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