1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2022 The Khronos Group Inc.
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 *//*!
20 * \file
21 * \brief Tests subpass merge feedback extension
22 *//*--------------------------------------------------------------------*/
23
24 #include "vktRenderPassSubpassMergeFeedbackTests.hpp"
25 #include "pipeline/vktPipelineImageUtil.hpp"
26 #include "vktTestCase.hpp"
27 #include "vkImageUtil.hpp"
28 #include "vkMemUtil.hpp"
29 #include "vkPlatform.hpp"
30 #include "vkPrograms.hpp"
31 #include "vkQueryUtil.hpp"
32 #include "vkCmdUtil.hpp"
33 #include "vkRef.hpp"
34 #include "vkRefUtil.hpp"
35 #include "vkTypeUtil.hpp"
36 #include "vkCmdUtil.hpp"
37 #include "vkObjUtil.hpp"
38 #include "tcuImageCompare.hpp"
39 #include "tcuPlatform.hpp"
40 #include "tcuTextureUtil.hpp"
41 #include "tcuTestLog.hpp"
42 #include "deStringUtil.hpp"
43 #include "deUniquePtr.hpp"
44 #include "deRandom.hpp"
45 #include <cstring>
46 #include <set>
47 #include <sstream>
48 #include <vector>
49
50 namespace vkt
51 {
52 namespace renderpass
53 {
54
55 using namespace vk;
56
57 namespace
58 {
59
60 struct TestParams
61 {
62 deUint32 subpassCount;
63 bool disallowMergeRenderpass;
64 bool disallowMergeSubPass1;
65 };
66
67 struct Vertex4RGBA
68 {
69 tcu::Vec4 position;
70 tcu::Vec4 color;
71 };
72
73 class SubpassMergeFeedbackTest : public vkt::TestCase
74 {
75 public:
76 SubpassMergeFeedbackTest (tcu::TestContext& testContext,
77 const std::string& name,
78 const std::string& description,
79 const TestParams& testParams);
80 virtual ~SubpassMergeFeedbackTest (void);
81 virtual TestInstance* createInstance (Context& context) const;
82 private:
83 const TestParams m_testParams;
84 };
85
86 class SubpassMergeFeedbackTestInstance : public vkt::TestInstance
87 {
88 public:
89 SubpassMergeFeedbackTestInstance (Context& context,
90 const TestParams& testParams);
91 virtual ~SubpassMergeFeedbackTestInstance (void);
92 virtual tcu::TestStatus iterate (void);
93 private:
94
95 tcu::TestStatus createRenderPassAndVerify (const DeviceInterface& vk,
96 VkDevice vkDevice);
97
98 const TestParams m_testParams;
99 };
100
SubpassMergeFeedbackTest(tcu::TestContext & testContext,const std::string & name,const std::string & description,const TestParams & testParams)101 SubpassMergeFeedbackTest::SubpassMergeFeedbackTest (tcu::TestContext& testContext,
102 const std::string& name,
103 const std::string& description,
104 const TestParams& testParams)
105 : vkt::TestCase (testContext, name, description)
106 , m_testParams (testParams)
107 {
108 }
109
~SubpassMergeFeedbackTest(void)110 SubpassMergeFeedbackTest::~SubpassMergeFeedbackTest (void)
111 {
112 }
113
createInstance(Context & context) const114 TestInstance* SubpassMergeFeedbackTest::createInstance (Context& context) const
115 {
116 return new SubpassMergeFeedbackTestInstance(context, m_testParams);
117 }
118
SubpassMergeFeedbackTestInstance(Context & context,const TestParams & testParams)119 SubpassMergeFeedbackTestInstance::SubpassMergeFeedbackTestInstance (Context& context,
120 const TestParams& testParams)
121 : vkt::TestInstance (context)
122 , m_testParams (testParams)
123 {
124 // Check for renderpass2 extension
125 context.requireDeviceFunctionality("VK_KHR_create_renderpass2");
126
127 // Check for subpass merge feedback extension
128 context.requireDeviceFunctionality("VK_EXT_subpass_merge_feedback");
129 }
130
131
~SubpassMergeFeedbackTestInstance(void)132 SubpassMergeFeedbackTestInstance::~SubpassMergeFeedbackTestInstance (void)
133 {
134 }
135
createRenderPassAndVerify(const DeviceInterface & vk,VkDevice vkDevice)136 tcu::TestStatus SubpassMergeFeedbackTestInstance::createRenderPassAndVerify (const DeviceInterface& vk,
137 VkDevice vkDevice)
138 {
139 const VkImageAspectFlags aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
140
141 std::vector<AttachmentDescription2> attachmentDescriptions;
142 std::vector<AttachmentReference2> resultAttachments;
143 std::vector<AttachmentReference2> inputAttachments;
144 std::vector<VkRenderPassCreationControlEXT> subpassMergeControls;
145 std::vector<VkRenderPassSubpassFeedbackCreateInfoEXT> subpassFeedbackCreateInfos;
146 std::vector<VkRenderPassSubpassFeedbackInfoEXT> subpassFeedbackInfos;
147 std::vector<SubpassDescription2> subpassDescriptions;
148
149 for (deUint32 i = 0; i < m_testParams.subpassCount; ++i)
150 {
151 attachmentDescriptions.emplace_back(
152 nullptr, // const void* pNext
153 (VkAttachmentDescriptionFlags)0, // VkAttachmentDescriptionFlags flags
154 VK_FORMAT_R8G8B8A8_UNORM, // VkFormat format
155 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples
156 VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp
157 VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp
158 VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp
159 VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp
160 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout
161 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout finalLayout
162 );
163
164 resultAttachments.emplace_back(
165 nullptr, // const void* pNext
166 i, // deUint32 attachment
167 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout layout
168 aspectMask // VkImageAspectFlags aspectMask
169 );
170
171 inputAttachments.emplace_back(
172 nullptr, // const void* pNext
173 i, // deUint32 attachment
174 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, // VkImageLayout layout
175 aspectMask // VkImageAspectFlags aspectMask
176 );
177
178 VkBool32 disallowSubpassMerge = VK_FALSE;
179 if (i == 1 && m_testParams.disallowMergeSubPass1)
180 {
181 disallowSubpassMerge = VK_TRUE;
182 }
183
184 const VkRenderPassCreationControlEXT mergeControl = {
185 VK_STRUCTURE_TYPE_RENDER_PASS_CREATION_CONTROL_EXT, // VkStructureType sType;
186 nullptr, // const void* pNext;
187 disallowSubpassMerge, // VkBool32 disallowMerging;
188 };
189 subpassMergeControls.push_back( mergeControl );
190
191 VkRenderPassSubpassFeedbackInfoEXT feedbackInfo = {
192 VK_SUBPASS_MERGE_STATUS_MERGED_EXT, // VkSubpassMergeStatusEXT subpassMergeStatus;
193 "", // description[VK_MAX_DESCRIPTION_SIZE];
194 0 // uint32_t postMergeIndex;
195 };
196 subpassFeedbackInfos.push_back( feedbackInfo );
197 }
198
199 for (deUint32 i = 0; i < m_testParams.subpassCount; ++i)
200 {
201 const VkRenderPassSubpassFeedbackCreateInfoEXT feedbackCreateInfo = {
202 VK_STRUCTURE_TYPE_RENDER_PASS_SUBPASS_FEEDBACK_CREATE_INFO_EXT, // VkStructureType sType;
203 &subpassMergeControls[i], // const void* pNext;
204 &subpassFeedbackInfos[i]
205 };
206 subpassFeedbackCreateInfos.push_back( feedbackCreateInfo );
207 }
208
209 for (deUint32 i = 0; i < m_testParams.subpassCount; ++i)
210 {
211 subpassDescriptions.emplace_back (
212 &subpassFeedbackCreateInfos[i],
213 (VkSubpassDescriptionFlags)0, // VkSubpassDescriptionFlags flags
214 VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint pipelineBindPoint
215 0u, // deUint32 viewMask
216 (i>0) ? 1u : 0u, // deUint32 inputAttachmentCount
217 (i>0) ? &inputAttachments[i-1] : nullptr, // const VkAttachmentReference* pInputAttachments
218 1u, // deUint32 colorAttachmentCount
219 &resultAttachments[i], // const VkAttachmentReference* pColorAttachments
220 nullptr, // const VkAttachmentReference* pResolveAttachments
221 nullptr, // const VkAttachmentReference* pDepthStencilAttachment
222 0u, // deUint32 preserveAttachmentCount
223 nullptr // const deUint32* pPreserveAttachments
224 );
225 }
226
227 std::vector<SubpassDependency2> subpassDependencies;
228 for (deUint32 i = 1; i < m_testParams.subpassCount; ++i)
229 {
230
231 subpassDependencies.emplace_back(
232 nullptr, // const void* pNext
233 i-1, // uint32_t srcSubpass
234 i, // uint32_t dstSubpass
235 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, // VkPipelineStageFlags srcStageMask
236 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, // VkPipelineStageFlags dstStageMask
237 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, // VkAccessFlags srcAccessMask
238 VK_ACCESS_INPUT_ATTACHMENT_READ_BIT, // VkAccessFlags dstAccessMask
239 VK_DEPENDENCY_BY_REGION_BIT, // VkDependencyFlags dependencyFlags
240 0u // deInt32 viewOffset
241 );
242 }
243
244
245 VkBool32 disallowMerging = VK_FALSE;
246 if (m_testParams.disallowMergeRenderpass)
247 {
248 disallowMerging = VK_TRUE;
249 }
250
251 const VkRenderPassCreationControlEXT renderpassControl =
252 {
253 VK_STRUCTURE_TYPE_RENDER_PASS_CREATION_CONTROL_EXT, // VkStructureType sType;
254 DE_NULL, // const void* pNext;
255 disallowMerging // VkBool32 disallowMerging;
256 };
257
258 VkRenderPassCreationFeedbackInfoEXT renderpassFeedbackInfo =
259 {
260 0 // uint32_t postMergeSubpassCount;
261 };
262
263 VkRenderPassCreationFeedbackCreateInfoEXT renderpassFeedbackCreateInfo =
264 {
265 VK_STRUCTURE_TYPE_RENDER_PASS_CREATION_FEEDBACK_CREATE_INFO_EXT, // VkStructureType sType;
266 &renderpassControl, // const void* pNext;
267 &renderpassFeedbackInfo
268 };
269
270 const RenderPassCreateInfo2 renderPassInfo (
271 &renderpassFeedbackCreateInfo, // const void* pNext
272 (VkRenderPassCreateFlags)0, // VkRenderPassCreateFlags flags
273 static_cast<deUint32>(attachmentDescriptions.size()), // deUint32 attachmentCount
274 attachmentDescriptions.data(), // const VkAttachmentDescription* pAttachments
275 static_cast<deUint32>(subpassDescriptions.size()), // deUint32 subpassCount
276 subpassDescriptions.data(), // const VkSubpassDescription* pSubpasses
277 static_cast<deUint32>(subpassDependencies.size()), // deUint32 dependencyCount
278 subpassDependencies.data(), // const VkSubpassDependency* pDependencies
279 0u, // deUint32 correlatedViewMaskCount
280 nullptr // const deUint32* pCorrelatedViewMasks
281 );
282
283 Move<VkRenderPass> renderPass = renderPassInfo.createRenderPass(vk, vkDevice);
284
285 // Verify merge status flags
286 if (m_testParams.disallowMergeRenderpass)
287 {
288 if (renderpassFeedbackInfo.postMergeSubpassCount != m_testParams.subpassCount)
289 {
290 return tcu::TestStatus::fail("Fail");
291 }
292
293 for (deUint32 i = 0; i < m_testParams.subpassCount; ++i)
294 {
295 if (subpassFeedbackCreateInfos[i].pSubpassFeedback->subpassMergeStatus != VK_SUBPASS_MERGE_STATUS_DISALLOWED_EXT)
296 {
297 return tcu::TestStatus::fail("Fail");
298 }
299
300 if (i > 0 &&
301 subpassFeedbackCreateInfos[i].pSubpassFeedback->postMergeIndex == subpassFeedbackCreateInfos[i-1].pSubpassFeedback->postMergeIndex)
302 {
303 return tcu::TestStatus::fail("Fail");
304 }
305 }
306 }
307 else
308 {
309 if (renderpassFeedbackInfo.postMergeSubpassCount > m_testParams.subpassCount)
310 {
311 return tcu::TestStatus::fail("Fail");
312 }
313
314 if (m_testParams.subpassCount == 1 &&
315 subpassFeedbackCreateInfos[0].pSubpassFeedback->subpassMergeStatus != VK_SUBPASS_MERGE_STATUS_NOT_MERGED_SINGLE_SUBPASS_EXT)
316 {
317 return tcu::TestStatus::fail("Fail");
318 }
319
320 for (deUint32 i = 1; i < m_testParams.subpassCount; ++i)
321 {
322 if (i == 1 && m_testParams.disallowMergeSubPass1 &&
323 subpassFeedbackCreateInfos[i].pSubpassFeedback->subpassMergeStatus != VK_SUBPASS_MERGE_STATUS_DISALLOWED_EXT)
324 {
325 return tcu::TestStatus::fail("Fail");
326 }
327
328 if (subpassFeedbackCreateInfos[i].pSubpassFeedback->subpassMergeStatus == VK_SUBPASS_MERGE_STATUS_MERGED_EXT &&
329 subpassFeedbackCreateInfos[i].pSubpassFeedback->postMergeIndex != subpassFeedbackCreateInfos[i-1].pSubpassFeedback->postMergeIndex)
330 {
331 return tcu::TestStatus::fail("Fail");
332 }
333
334 if (subpassFeedbackCreateInfos[i].pSubpassFeedback->subpassMergeStatus != VK_SUBPASS_MERGE_STATUS_MERGED_EXT &&
335 subpassFeedbackCreateInfos[i].pSubpassFeedback->postMergeIndex == subpassFeedbackCreateInfos[i-1].pSubpassFeedback->postMergeIndex)
336 {
337 return tcu::TestStatus::fail("Fail");
338 }
339 }
340 }
341
342 return tcu::TestStatus::pass("Pass");
343 }
344
iterate(void)345 tcu::TestStatus SubpassMergeFeedbackTestInstance::iterate (void)
346 {
347 const DeviceInterface& vk = m_context.getDeviceInterface();
348 const VkDevice vkDevice = m_context.getDevice();
349
350 // Create render pass
351 return createRenderPassAndVerify(vk, vkDevice);
352 }
353
354 } // anonymous
355
createRenderPassSubpassMergeFeedbackTests(tcu::TestContext & testCtx,const RenderingType renderingType)356 tcu::TestCaseGroup* createRenderPassSubpassMergeFeedbackTests (tcu::TestContext& testCtx, const RenderingType renderingType)
357 {
358 if (renderingType != RENDERING_TYPE_RENDERPASS2)
359 {
360 return nullptr;
361 }
362
363 de::MovePtr<tcu::TestCaseGroup> subpassMergeFeedbackTests (new tcu::TestCaseGroup(testCtx, "subpass_merge_feedback", "Subpass merge feedback tests"));
364
365 {
366 TestParams params;
367 const std::string testName = std::string("single_subpass");
368
369 params.subpassCount = 1;
370 params.disallowMergeRenderpass = false;
371 params.disallowMergeSubPass1 = false;
372
373 subpassMergeFeedbackTests->addChild(new SubpassMergeFeedbackTest(testCtx, testName, "", params));
374 }
375 {
376 TestParams params;
377 const std::string testName = std::string("single_subpass_disallow_renderpass_merge");
378
379 params.subpassCount = 1;
380 params.disallowMergeRenderpass = true;
381 params.disallowMergeSubPass1 = false;
382
383 subpassMergeFeedbackTests->addChild(new SubpassMergeFeedbackTest(testCtx, testName, "", params));
384 }
385 {
386 TestParams params;
387 const std::string testName = std::string("three_subpasses");
388
389 params.subpassCount = 3;
390 params.disallowMergeRenderpass = false;
391 params.disallowMergeSubPass1 = false;
392
393 subpassMergeFeedbackTests->addChild(new SubpassMergeFeedbackTest(testCtx, testName, "", params));
394 }
395 {
396 TestParams params;
397 const std::string testName = std::string("three_subpasses_disallow_renderpass_merge");
398
399 params.subpassCount = 3;
400 params.disallowMergeRenderpass = true;
401 params.disallowMergeSubPass1 = false;
402
403 subpassMergeFeedbackTests->addChild(new SubpassMergeFeedbackTest(testCtx, testName, "", params));
404 }
405 {
406 TestParams params;
407 const std::string testName = std::string("three_subpasses_disallow_subpass_merge");
408
409 params.subpassCount = 3;
410 params.disallowMergeRenderpass = false;
411 params.disallowMergeSubPass1 = true;
412
413 subpassMergeFeedbackTests->addChild(new SubpassMergeFeedbackTest(testCtx, testName, "", params));
414 }
415 {
416 TestParams params;
417 const std::string testName = std::string("many_subpasses");
418
419 params.subpassCount = 32;
420 params.disallowMergeRenderpass = false;
421 params.disallowMergeSubPass1 = false;
422
423 subpassMergeFeedbackTests->addChild(new SubpassMergeFeedbackTest(testCtx, testName, "", params));
424 }
425
426 return subpassMergeFeedbackTests.release();
427 }
428
429 } // renderpass
430 } // vkt
431