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