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 uint32_t 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, const std::string &name, const TestParams &testParams);
77 virtual ~SubpassMergeFeedbackTest(void);
78 virtual TestInstance *createInstance(Context &context) const;
79
80 private:
81 const TestParams m_testParams;
82 };
83
84 class SubpassMergeFeedbackTestInstance : public vkt::TestInstance
85 {
86 public:
87 SubpassMergeFeedbackTestInstance(Context &context, const TestParams &testParams);
88 virtual ~SubpassMergeFeedbackTestInstance(void);
89 virtual tcu::TestStatus iterate(void);
90
91 private:
92 tcu::TestStatus createRenderPassAndVerify(const DeviceInterface &vk, VkDevice vkDevice);
93
94 const TestParams m_testParams;
95 };
96
SubpassMergeFeedbackTest(tcu::TestContext & testContext,const std::string & name,const TestParams & testParams)97 SubpassMergeFeedbackTest::SubpassMergeFeedbackTest(tcu::TestContext &testContext, const std::string &name,
98 const TestParams &testParams)
99 : vkt::TestCase(testContext, name)
100 , m_testParams(testParams)
101 {
102 }
103
~SubpassMergeFeedbackTest(void)104 SubpassMergeFeedbackTest::~SubpassMergeFeedbackTest(void)
105 {
106 }
107
createInstance(Context & context) const108 TestInstance *SubpassMergeFeedbackTest::createInstance(Context &context) const
109 {
110 return new SubpassMergeFeedbackTestInstance(context, m_testParams);
111 }
112
SubpassMergeFeedbackTestInstance(Context & context,const TestParams & testParams)113 SubpassMergeFeedbackTestInstance::SubpassMergeFeedbackTestInstance(Context &context, const TestParams &testParams)
114 : vkt::TestInstance(context)
115 , m_testParams(testParams)
116 {
117 // Check for renderpass2 extension
118 context.requireDeviceFunctionality("VK_KHR_create_renderpass2");
119
120 // Check for subpass merge feedback extension
121 context.requireDeviceFunctionality("VK_EXT_subpass_merge_feedback");
122 }
123
~SubpassMergeFeedbackTestInstance(void)124 SubpassMergeFeedbackTestInstance::~SubpassMergeFeedbackTestInstance(void)
125 {
126 }
127
createRenderPassAndVerify(const DeviceInterface & vk,VkDevice vkDevice)128 tcu::TestStatus SubpassMergeFeedbackTestInstance::createRenderPassAndVerify(const DeviceInterface &vk,
129 VkDevice vkDevice)
130 {
131 const VkImageAspectFlags aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
132
133 std::vector<AttachmentDescription2> attachmentDescriptions;
134 std::vector<AttachmentReference2> resultAttachments;
135 std::vector<AttachmentReference2> inputAttachments;
136 std::vector<VkRenderPassCreationControlEXT> subpassMergeControls;
137 std::vector<VkRenderPassSubpassFeedbackCreateInfoEXT> subpassFeedbackCreateInfos;
138 std::vector<VkRenderPassSubpassFeedbackInfoEXT> subpassFeedbackInfos;
139 std::vector<SubpassDescription2> subpassDescriptions;
140
141 for (uint32_t i = 0; i < m_testParams.subpassCount; ++i)
142 {
143 attachmentDescriptions.emplace_back(
144 nullptr, // const void* pNext
145 (VkAttachmentDescriptionFlags)0, // VkAttachmentDescriptionFlags flags
146 VK_FORMAT_R8G8B8A8_UNORM, // VkFormat format
147 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples
148 VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp
149 VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp
150 VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp
151 VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp
152 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout
153 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout finalLayout
154 );
155
156 resultAttachments.emplace_back(nullptr, // const void* pNext
157 i, // uint32_t attachment
158 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout layout
159 aspectMask // VkImageAspectFlags aspectMask
160 );
161
162 inputAttachments.emplace_back(nullptr, // const void* pNext
163 i, // uint32_t attachment
164 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, // VkImageLayout layout
165 aspectMask // VkImageAspectFlags aspectMask
166 );
167
168 VkBool32 disallowSubpassMerge = VK_FALSE;
169 if (i == 1 && m_testParams.disallowMergeSubPass1)
170 {
171 disallowSubpassMerge = VK_TRUE;
172 }
173
174 const VkRenderPassCreationControlEXT mergeControl = {
175 VK_STRUCTURE_TYPE_RENDER_PASS_CREATION_CONTROL_EXT, // VkStructureType sType;
176 nullptr, // const void* pNext;
177 disallowSubpassMerge, // VkBool32 disallowMerging;
178 };
179 subpassMergeControls.push_back(mergeControl);
180
181 VkRenderPassSubpassFeedbackInfoEXT feedbackInfo = {
182 VK_SUBPASS_MERGE_STATUS_MERGED_EXT, // VkSubpassMergeStatusEXT subpassMergeStatus;
183 "", // description[VK_MAX_DESCRIPTION_SIZE];
184 0 // uint32_t postMergeIndex;
185 };
186 subpassFeedbackInfos.push_back(feedbackInfo);
187 }
188
189 for (uint32_t i = 0; i < m_testParams.subpassCount; ++i)
190 {
191 const VkRenderPassSubpassFeedbackCreateInfoEXT feedbackCreateInfo = {
192 VK_STRUCTURE_TYPE_RENDER_PASS_SUBPASS_FEEDBACK_CREATE_INFO_EXT, // VkStructureType sType;
193 &subpassMergeControls[i], // const void* pNext;
194 &subpassFeedbackInfos[i]};
195 subpassFeedbackCreateInfos.push_back(feedbackCreateInfo);
196 }
197
198 for (uint32_t i = 0; i < m_testParams.subpassCount; ++i)
199 {
200 subpassDescriptions.emplace_back(
201 &subpassFeedbackCreateInfos[i],
202 (VkSubpassDescriptionFlags)0, // VkSubpassDescriptionFlags flags
203 VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint pipelineBindPoint
204 0u, // uint32_t viewMask
205 (i > 0) ? 1u : 0u, // uint32_t inputAttachmentCount
206 (i > 0) ? &inputAttachments[i - 1] : nullptr, // const VkAttachmentReference* pInputAttachments
207 1u, // uint32_t colorAttachmentCount
208 &resultAttachments[i], // const VkAttachmentReference* pColorAttachments
209 nullptr, // const VkAttachmentReference* pResolveAttachments
210 nullptr, // const VkAttachmentReference* pDepthStencilAttachment
211 0u, // uint32_t preserveAttachmentCount
212 nullptr // const uint32_t* pPreserveAttachments
213 );
214 }
215
216 std::vector<SubpassDependency2> subpassDependencies;
217 for (uint32_t i = 1; i < m_testParams.subpassCount; ++i)
218 {
219
220 subpassDependencies.emplace_back(
221 nullptr, // const void* pNext
222 i - 1, // uint32_t srcSubpass
223 i, // uint32_t dstSubpass
224 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, // VkPipelineStageFlags srcStageMask
225 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, // VkPipelineStageFlags dstStageMask
226 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, // VkAccessFlags srcAccessMask
227 VK_ACCESS_INPUT_ATTACHMENT_READ_BIT, // VkAccessFlags dstAccessMask
228 VK_DEPENDENCY_BY_REGION_BIT, // VkDependencyFlags dependencyFlags
229 0u // int32_t viewOffset
230 );
231 }
232
233 VkBool32 disallowMerging = VK_FALSE;
234 if (m_testParams.disallowMergeRenderpass)
235 {
236 disallowMerging = VK_TRUE;
237 }
238
239 const VkRenderPassCreationControlEXT renderpassControl = {
240 VK_STRUCTURE_TYPE_RENDER_PASS_CREATION_CONTROL_EXT, // VkStructureType sType;
241 DE_NULL, // const void* pNext;
242 disallowMerging // VkBool32 disallowMerging;
243 };
244
245 VkRenderPassCreationFeedbackInfoEXT renderpassFeedbackInfo = {
246 0 // uint32_t postMergeSubpassCount;
247 };
248
249 VkRenderPassCreationFeedbackCreateInfoEXT renderpassFeedbackCreateInfo = {
250 VK_STRUCTURE_TYPE_RENDER_PASS_CREATION_FEEDBACK_CREATE_INFO_EXT, // VkStructureType sType;
251 &renderpassControl, // const void* pNext;
252 &renderpassFeedbackInfo};
253
254 const RenderPassCreateInfo2 renderPassInfo(
255 &renderpassFeedbackCreateInfo, // const void* pNext
256 (VkRenderPassCreateFlags)0, // VkRenderPassCreateFlags flags
257 static_cast<uint32_t>(attachmentDescriptions.size()), // uint32_t attachmentCount
258 attachmentDescriptions.data(), // const VkAttachmentDescription* pAttachments
259 static_cast<uint32_t>(subpassDescriptions.size()), // uint32_t subpassCount
260 subpassDescriptions.data(), // const VkSubpassDescription* pSubpasses
261 static_cast<uint32_t>(subpassDependencies.size()), // uint32_t dependencyCount
262 subpassDependencies.data(), // const VkSubpassDependency* pDependencies
263 0u, // uint32_t correlatedViewMaskCount
264 nullptr // const uint32_t* pCorrelatedViewMasks
265 );
266
267 Move<VkRenderPass> renderPass = renderPassInfo.createRenderPass(vk, vkDevice);
268
269 // Verify merge status flags
270 if (m_testParams.disallowMergeRenderpass)
271 {
272 if (renderpassFeedbackInfo.postMergeSubpassCount != m_testParams.subpassCount)
273 {
274 return tcu::TestStatus::fail("Fail");
275 }
276
277 for (uint32_t i = 0; i < m_testParams.subpassCount; ++i)
278 {
279 if (subpassFeedbackCreateInfos[i].pSubpassFeedback->subpassMergeStatus !=
280 VK_SUBPASS_MERGE_STATUS_DISALLOWED_EXT)
281 {
282 return tcu::TestStatus::fail("Fail");
283 }
284
285 if (i > 0 && subpassFeedbackCreateInfos[i].pSubpassFeedback->postMergeIndex ==
286 subpassFeedbackCreateInfos[i - 1].pSubpassFeedback->postMergeIndex)
287 {
288 return tcu::TestStatus::fail("Fail");
289 }
290 }
291 }
292 else
293 {
294 if (renderpassFeedbackInfo.postMergeSubpassCount > m_testParams.subpassCount)
295 {
296 return tcu::TestStatus::fail("Fail");
297 }
298
299 if (m_testParams.subpassCount == 1 && subpassFeedbackCreateInfos[0].pSubpassFeedback->subpassMergeStatus !=
300 VK_SUBPASS_MERGE_STATUS_NOT_MERGED_SINGLE_SUBPASS_EXT)
301 {
302 return tcu::TestStatus::fail("Fail");
303 }
304
305 for (uint32_t i = 1; i < m_testParams.subpassCount; ++i)
306 {
307 if (i == 1 && m_testParams.disallowMergeSubPass1 &&
308 subpassFeedbackCreateInfos[i].pSubpassFeedback->subpassMergeStatus !=
309 VK_SUBPASS_MERGE_STATUS_DISALLOWED_EXT)
310 {
311 return tcu::TestStatus::fail("Fail");
312 }
313
314 if (subpassFeedbackCreateInfos[i].pSubpassFeedback->subpassMergeStatus ==
315 VK_SUBPASS_MERGE_STATUS_MERGED_EXT &&
316 subpassFeedbackCreateInfos[i].pSubpassFeedback->postMergeIndex !=
317 subpassFeedbackCreateInfos[i - 1].pSubpassFeedback->postMergeIndex)
318 {
319 return tcu::TestStatus::fail("Fail");
320 }
321
322 if (subpassFeedbackCreateInfos[i].pSubpassFeedback->subpassMergeStatus !=
323 VK_SUBPASS_MERGE_STATUS_MERGED_EXT &&
324 subpassFeedbackCreateInfos[i].pSubpassFeedback->postMergeIndex ==
325 subpassFeedbackCreateInfos[i - 1].pSubpassFeedback->postMergeIndex)
326 {
327 return tcu::TestStatus::fail("Fail");
328 }
329 }
330 }
331
332 return tcu::TestStatus::pass("Pass");
333 }
334
iterate(void)335 tcu::TestStatus SubpassMergeFeedbackTestInstance::iterate(void)
336 {
337 const DeviceInterface &vk = m_context.getDeviceInterface();
338 const VkDevice vkDevice = m_context.getDevice();
339
340 // Create render pass
341 return createRenderPassAndVerify(vk, vkDevice);
342 }
343
344 } // namespace
345
createRenderPassSubpassMergeFeedbackTests(tcu::TestContext & testCtx,const RenderingType renderingType)346 tcu::TestCaseGroup *createRenderPassSubpassMergeFeedbackTests(tcu::TestContext &testCtx,
347 const RenderingType renderingType)
348 {
349 if (renderingType != RENDERING_TYPE_RENDERPASS2)
350 {
351 return nullptr;
352 }
353
354 de::MovePtr<tcu::TestCaseGroup> subpassMergeFeedbackTests(
355 new tcu::TestCaseGroup(testCtx, "subpass_merge_feedback"));
356
357 {
358 TestParams params;
359 const std::string testName = std::string("single_subpass");
360
361 params.subpassCount = 1;
362 params.disallowMergeRenderpass = false;
363 params.disallowMergeSubPass1 = false;
364
365 subpassMergeFeedbackTests->addChild(new SubpassMergeFeedbackTest(testCtx, testName, params));
366 }
367 {
368 TestParams params;
369 const std::string testName = std::string("single_subpass_disallow_renderpass_merge");
370
371 params.subpassCount = 1;
372 params.disallowMergeRenderpass = true;
373 params.disallowMergeSubPass1 = false;
374
375 subpassMergeFeedbackTests->addChild(new SubpassMergeFeedbackTest(testCtx, testName, params));
376 }
377 {
378 TestParams params;
379 const std::string testName = std::string("three_subpasses");
380
381 params.subpassCount = 3;
382 params.disallowMergeRenderpass = false;
383 params.disallowMergeSubPass1 = false;
384
385 subpassMergeFeedbackTests->addChild(new SubpassMergeFeedbackTest(testCtx, testName, params));
386 }
387 {
388 TestParams params;
389 const std::string testName = std::string("three_subpasses_disallow_renderpass_merge");
390
391 params.subpassCount = 3;
392 params.disallowMergeRenderpass = true;
393 params.disallowMergeSubPass1 = false;
394
395 subpassMergeFeedbackTests->addChild(new SubpassMergeFeedbackTest(testCtx, testName, params));
396 }
397 {
398 TestParams params;
399 const std::string testName = std::string("three_subpasses_disallow_subpass_merge");
400
401 params.subpassCount = 3;
402 params.disallowMergeRenderpass = false;
403 params.disallowMergeSubPass1 = true;
404
405 subpassMergeFeedbackTests->addChild(new SubpassMergeFeedbackTest(testCtx, testName, params));
406 }
407 {
408 TestParams params;
409 const std::string testName = std::string("many_subpasses");
410
411 params.subpassCount = 32;
412 params.disallowMergeRenderpass = false;
413 params.disallowMergeSubPass1 = false;
414
415 subpassMergeFeedbackTests->addChild(new SubpassMergeFeedbackTest(testCtx, testName, params));
416 }
417
418 return subpassMergeFeedbackTests.release();
419 }
420
421 } // namespace renderpass
422 } // namespace vkt
423