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
65 namespace vkt
66 {
67 namespace conditional
68 {
69 namespace
70 {
71
72 using namespace vk;
73
74 class ConditionalIgnoreClearTestCase : public vkt::TestCase
75 {
76 public:
77 ConditionalIgnoreClearTestCase(tcu::TestContext& context, const std::string& name, const ConditionalData& data);
initPrograms(SourceCollections &) const78 void initPrograms (SourceCollections&) const override { }
79 TestInstance* createInstance (Context& context) const override;
checkSupport(Context & context) const80 void checkSupport (Context& context) const override
81 {
82 context.requireDeviceFunctionality("VK_EXT_conditional_rendering");
83 if (m_data.conditionInherited && !context.getConditionalRenderingFeaturesEXT().inheritedConditionalRendering)
84 TCU_THROW(NotSupportedError, "Device does not support inherited conditional rendering");
85 }
86 private:
87 const ConditionalData m_data;
88 };
89
90
91 class ConditionalIgnoreClearTestInstance : public vkt::TestInstance
92 {
93 public:
ConditionalIgnoreClearTestInstance(Context & context,const ConditionalData & data)94 ConditionalIgnoreClearTestInstance(Context& context, const ConditionalData& data)
95 : vkt::TestInstance (context)
96 , m_data(data)
97 { };
98 virtual tcu::TestStatus iterate (void);
99 private:
100 const ConditionalData m_data;
101 };
102
103
ConditionalIgnoreClearTestCase(tcu::TestContext & context,const std::string & name,const ConditionalData & data)104 ConditionalIgnoreClearTestCase::ConditionalIgnoreClearTestCase(tcu::TestContext& context, const std::string& name, const ConditionalData& data)
105 : vkt::TestCase (context, name)
106 , m_data(data)
107 { }
108
createInstance(Context & context) const109 TestInstance* ConditionalIgnoreClearTestCase::createInstance(Context& context) const
110 {
111 return new ConditionalIgnoreClearTestInstance(context, m_data);
112 }
113
114 //make a buffer to read an image back after rendering
makeBufferForImage(const DeviceInterface & vkd,const VkDevice device,Allocator & allocator,VkFormat imageFormat,VkExtent3D imageExtent)115 std::unique_ptr<BufferWithMemory> makeBufferForImage(const DeviceInterface& vkd, const VkDevice device, Allocator& allocator, VkFormat imageFormat, VkExtent3D imageExtent)
116 {
117 const auto tcuFormat = mapVkFormat(imageFormat);
118 const auto outBufferSize = static_cast<VkDeviceSize>(static_cast<uint32_t>(tcu::getPixelSize(tcuFormat)) * imageExtent.width * imageExtent.height);
119 const auto outBufferUsage = VK_BUFFER_USAGE_TRANSFER_DST_BIT;
120 const auto outBufferInfo = makeBufferCreateInfo(outBufferSize, outBufferUsage);
121
122 auto outBuffer = std::unique_ptr<BufferWithMemory>(new BufferWithMemory(vkd, device, allocator, outBufferInfo, MemoryRequirement::HostVisible));
123
124 return outBuffer;
125 }
126
iterate(void)127 tcu::TestStatus ConditionalIgnoreClearTestInstance::iterate(void)
128 {
129 const auto& vkd = m_context.getDeviceInterface();
130 const auto device = m_context.getDevice();
131 auto& alloc = m_context.getDefaultAllocator();
132 const auto imageFormat = VK_FORMAT_R8G8B8A8_UNORM;
133 const auto depthFormat = VK_FORMAT_D16_UNORM;
134 const auto imageExtent = makeExtent3D(2, 2, 1u);
135 const auto qIndex = m_context.getUniversalQueueFamilyIndex();
136
137 const auto expected = tcu::Vec4(0.0, 0.0, 0.0, 1.0);
138
139 const VkClearColorValue clearColor = { { 0.0, 0.0, 0.0, 1.0 } };
140 const VkClearColorValue clearColorWrong = { { 1.0, 0.0, 0.0, 1.0 } };
141
142 const VkClearDepthStencilValue depthClear = {0.0, 0};
143 const VkClearDepthStencilValue depthClearWrong = {1.0, 0};
144
145 const tcu::IVec3 imageDim (static_cast<int>(imageExtent.width), static_cast<int>(imageExtent.height), static_cast<int>(imageExtent.depth));
146 const tcu::IVec2 imageSize (imageDim.x(), imageDim.y());
147
148 de::MovePtr<ImageWithMemory> colorAttachment;
149 de::MovePtr<ImageWithMemory> depthAttachment;
150
151 //create color image
152 const auto imageUsage = static_cast<VkImageUsageFlags>(VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT);
153 const VkImageCreateInfo imageCreateInfo =
154 {
155 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
156 nullptr, // const void* pNext;
157 0u, // VkImageCreateFlags flags;
158 VK_IMAGE_TYPE_2D, // VkImageType imageType;
159 imageFormat, // VkFormat format;
160 imageExtent, // VkExtent3D extent;
161 1u, // deUint32 mipLevels;
162 1u, // deUint32 arrayLayers;
163 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
164 VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
165 imageUsage, // VkImageUsageFlags usage;
166 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
167 0, // deUint32 queueFamilyIndexCount;
168 nullptr, // const deUint32* pQueueFamilyIndices;
169 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
170 };
171
172 const auto colorSubresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
173 colorAttachment = de::MovePtr<ImageWithMemory>(new ImageWithMemory(vkd, device, alloc, imageCreateInfo, MemoryRequirement::Any));
174 auto colorAttachmentView = makeImageView(vkd, device, colorAttachment->get(), VK_IMAGE_VIEW_TYPE_2D, imageFormat, colorSubresourceRange);
175
176 //create depth image
177 const auto depthImageUsage =
178 static_cast<VkImageUsageFlags>(VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT);
179 const VkImageCreateInfo depthImageCreateInfo =
180 {
181 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
182 nullptr, // const void* pNext;
183 0u, // VkImageCreateFlags flags;
184 VK_IMAGE_TYPE_2D, // VkImageType imageType;
185 depthFormat, // VkFormat format;
186 imageExtent, // VkExtent3D extent;
187 1u, // deUint32 mipLevels;
188 1u, // deUint32 arrayLayers;
189 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
190 VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
191 depthImageUsage, // VkImageUsageFlags usage;
192 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
193 0u, // deUint32 queueFamilyIndexCount;
194 nullptr, // const deUint32* pQueueFamilyIndices;
195 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
196 };
197
198 const auto depthSubresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_DEPTH_BIT, 0u, 1u, 0u, 1u);
199 depthAttachment = de::MovePtr<ImageWithMemory>(new ImageWithMemory(vkd, device, alloc, depthImageCreateInfo, MemoryRequirement::Any));
200 auto depthAttachmentView = makeImageView(vkd, device, depthAttachment->get(), VK_IMAGE_VIEW_TYPE_2D, depthFormat, depthSubresourceRange);
201
202 //buffers to read the outputs
203 const auto outBuffer = makeBufferForImage(vkd, device, alloc, imageFormat, imageExtent);
204 const auto& outBufferAlloc = outBuffer->getAllocation();
205 const void* outBufferData = outBufferAlloc.getHostPtr();
206
207 const auto outDepthBuffer = makeBufferForImage(vkd, device, alloc, depthFormat, imageExtent);
208 const auto& outDepthBufferAlloc = outDepthBuffer->getAllocation();
209 const void* outDepthBufferData = outDepthBufferAlloc.getHostPtr();
210
211 const auto commandPool = createCommandPool(vkd, device, VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, qIndex);
212 auto commandBuffer = allocateCommandBuffer(vkd, device, commandPool.get(), VK_COMMAND_BUFFER_LEVEL_PRIMARY);
213 auto commandBuffer2 = allocateCommandBuffer(vkd, device, commandPool.get(), VK_COMMAND_BUFFER_LEVEL_SECONDARY);
214
215 auto conditionalBuffer = createConditionalRenderingBuffer(m_context, m_data);
216 //prepare command buffers
217 const bool useSecondaryCmdBuffer = m_data.conditionInherited || m_data.conditionInSecondaryCommandBuffer;
218
219 VkCommandBufferInheritanceConditionalRenderingInfoEXT conditionalRenderingInheritanceInfo = initVulkanStructure();
220 conditionalRenderingInheritanceInfo.conditionalRenderingEnable = m_data.conditionInherited ? VK_TRUE : VK_FALSE;
221
222 const VkCommandBufferInheritanceInfo inheritanceInfo =
223 {
224 VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO,
225 &conditionalRenderingInheritanceInfo,
226 VK_NULL_HANDLE, // renderPass
227 0u, // subpass
228 VK_NULL_HANDLE, // framebuffer
229 VK_FALSE, // occlusionQueryEnable
230 (VkQueryControlFlags)0u, // queryFlags
231 (VkQueryPipelineStatisticFlags)0u, // pipelineStatistics
232 };
233
234 const VkCommandBufferBeginInfo commandBufferBeginInfo =
235 {
236 VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
237 nullptr,
238 VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
239 &inheritanceInfo
240 };
241
242 beginCommandBuffer(vkd, commandBuffer.get());
243 //transition color and depth images
244 VkImageMemoryBarrier colorTransition = makeImageMemoryBarrier(0, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED,
245 VK_IMAGE_LAYOUT_GENERAL, colorAttachment.get()->get(), colorSubresourceRange);
246 VkImageMemoryBarrier depthTransition = makeImageMemoryBarrier(0, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED,
247 VK_IMAGE_LAYOUT_GENERAL, depthAttachment.get()->get(), depthSubresourceRange);
248 VkImageMemoryBarrier barriers[] = {colorTransition, depthTransition};
249 cmdPipelineImageMemoryBarrier(vkd, commandBuffer.get(), VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
250 barriers, DE_LENGTH_OF_ARRAY(barriers));
251
252 //clear to the incorrect color
253 vkd.cmdClearColorImage(commandBuffer.get(), colorAttachment.get()->get(), VK_IMAGE_LAYOUT_GENERAL, &clearColorWrong, 1, &colorSubresourceRange);
254 vkd.cmdClearDepthStencilImage(commandBuffer.get(), depthAttachment.get()->get(), VK_IMAGE_LAYOUT_GENERAL, &depthClearWrong, 1, &depthSubresourceRange);
255
256 const auto barrier = makeMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_TRANSFER_WRITE_BIT);
257 cmdPipelineMemoryBarrier(vkd, commandBuffer.get(), VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, &barrier);
258
259 //do all combinations of clears
260 if (useSecondaryCmdBuffer)
261 {
262 vkd.beginCommandBuffer(*commandBuffer2, &commandBufferBeginInfo);
263 if (m_data.conditionInSecondaryCommandBuffer)
264 {
265 beginConditionalRendering(vkd, commandBuffer2.get(), *conditionalBuffer, m_data);
266 }
267 else
268 {
269 beginConditionalRendering(vkd, commandBuffer.get(), *conditionalBuffer, m_data);
270 }
271
272 //clear to the correct colors
273 vkd.cmdClearColorImage(commandBuffer2.get(), colorAttachment.get()->get(), VK_IMAGE_LAYOUT_GENERAL, &clearColor, 1, &colorSubresourceRange);
274 vkd.cmdClearDepthStencilImage(commandBuffer2.get(), depthAttachment.get()->get(), VK_IMAGE_LAYOUT_GENERAL, &depthClear, 1, &depthSubresourceRange);
275
276 if (m_data.conditionInSecondaryCommandBuffer)
277 {
278 vkd.cmdEndConditionalRenderingEXT(commandBuffer2.get());
279 }
280 else
281 {
282 vkd.cmdEndConditionalRenderingEXT(commandBuffer.get());
283 }
284
285 vkd.endCommandBuffer(*commandBuffer2);
286 vkd.cmdExecuteCommands(commandBuffer.get(), 1, &commandBuffer2.get());
287 }
288 else
289 {
290 beginConditionalRendering(vkd, commandBuffer.get(), *conditionalBuffer, m_data);
291
292 //clear to the correct colors
293 vkd.cmdClearColorImage(commandBuffer.get(), colorAttachment.get()->get(), VK_IMAGE_LAYOUT_GENERAL, &clearColor, 1, &colorSubresourceRange);
294 vkd.cmdClearDepthStencilImage(commandBuffer.get(), depthAttachment.get()->get(), VK_IMAGE_LAYOUT_GENERAL, &depthClear, 1, &depthSubresourceRange);
295
296 vkd.cmdEndConditionalRenderingEXT(commandBuffer.get());
297 }
298 copyImageToBuffer(vkd, commandBuffer.get(), colorAttachment.get()->get(), (*outBuffer).get(), imageSize,
299 VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_GENERAL);
300 copyImageToBuffer(vkd, commandBuffer.get(), depthAttachment.get()->get(), (*outDepthBuffer).get(), imageSize,
301 VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_GENERAL, 1, VK_IMAGE_ASPECT_DEPTH_BIT, VK_IMAGE_ASPECT_DEPTH_BIT);
302
303 endCommandBuffer(vkd, commandBuffer.get());
304 submitCommandsAndWait(vkd, device, m_context.getUniversalQueue(), commandBuffer.get());
305
306 invalidateAlloc(vkd, device, outBufferAlloc);
307 invalidateAlloc(vkd, device, outDepthBufferAlloc);
308 tcu::ConstPixelBufferAccess outPixels(mapVkFormat(imageFormat), imageDim, outBufferData);
309 tcu::ConstPixelBufferAccess outDepth(mapVkFormat(depthFormat), imageDim, outDepthBufferData);
310
311 //the clears should happen in every case
312 if (!tcu::floatThresholdCompare(m_context.getTestContext().getLog(), "Compare color", "color image comparison", expected, outPixels, tcu::Vec4(0.0), tcu::COMPARE_LOG_ON_ERROR))
313 return tcu::TestStatus::fail("Color image verification failed, check log for details");
314 if (!tcu::floatThresholdCompare(m_context.getTestContext().getLog(), "Compare depth", "depth image comparison", expected, outDepth, tcu::Vec4(0.0), tcu::COMPARE_LOG_ON_ERROR))
315 return tcu::TestStatus::fail("Depth image verification failed, check log for details");
316
317 return tcu::TestStatus::pass("Pass");
318 }
319
320 } // anonymous
321
322 // operations that ignore conditions
ConditionalIgnoreTests(tcu::TestContext & testCtx)323 ConditionalIgnoreTests::ConditionalIgnoreTests(tcu::TestContext &testCtx)
324 : TestCaseGroup (testCtx, "conditional_ignore")
325 { }
326
~ConditionalIgnoreTests(void)327 ConditionalIgnoreTests::~ConditionalIgnoreTests(void)
328 {}
329
init(void)330 void ConditionalIgnoreTests::init (void)
331 {
332 for (int conditionNdx = 0; conditionNdx < DE_LENGTH_OF_ARRAY(conditional::s_testsData); conditionNdx++)
333 {
334 const ConditionalData& conditionData = conditional::s_testsData[conditionNdx];
335
336 if (conditionData.clearInRenderPass)
337 continue;
338
339 // tests that some clear operations always happen
340 addChild(new ConditionalIgnoreClearTestCase(m_testCtx, std::string("clear_") + de::toString(conditionData).c_str(), conditionData));
341 }
342 }
343
344 } // conditional
345 } // vkt
346