1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2023 The Khronos Group Inc.
6  * Copyright (c) 2023 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 VK_EXT_dynamic_rendering_unused_attachments Tests
23  *//*--------------------------------------------------------------------*/
24 
25 #include "vktDynamicRenderingUnusedAttachmentsTests.hpp"
26 #include "vktTestCase.hpp"
27 
28 #include "vkImageUtil.hpp"
29 #include "vkQueryUtil.hpp"
30 #include "vkObjUtil.hpp"
31 #include "vkCmdUtil.hpp"
32 #include "vkBarrierUtil.hpp"
33 
34 #include "tcuStringTemplate.hpp"
35 #include "tcuImageCompare.hpp"
36 #include "tcuTextureUtil.hpp"
37 
38 #include <string>
39 #include <sstream>
40 #include <vector>
41 #include <memory>
42 #include <bitset>
43 #include <algorithm>
44 #include <iterator>
45 #include <iomanip>
46 
47 namespace vkt
48 {
49 namespace renderpass
50 {
51 
52 namespace
53 {
54 
55 using namespace vk;
56 
57 static constexpr VkFormat kColorFormat    = VK_FORMAT_R8G8B8A8_UINT;
58 static constexpr VkFormat kBadColorFormat = VK_FORMAT_R32G32B32A32_UINT;
59 
getDSFormatList(void)60 std::vector<VkFormat> getDSFormatList(void)
61 {
62     // The spec mandates support for one of these two formats.
63     static const VkFormat kDSFormatList[] = {VK_FORMAT_D32_SFLOAT_S8_UINT, VK_FORMAT_D24_UNORM_S8_UINT};
64     return std::vector<VkFormat>(kDSFormatList, kDSFormatList + de::arrayLength(kDSFormatList));
65 }
66 
67 // Find a suitable format for the depth/stencil buffer.
chooseDepthStencilFormat(const InstanceInterface & vki,VkPhysicalDevice physDev)68 VkFormat chooseDepthStencilFormat(const InstanceInterface &vki, VkPhysicalDevice physDev)
69 {
70     const auto candidates = getDSFormatList();
71 
72     for (const auto &format : candidates)
73     {
74         const auto properties = getPhysicalDeviceFormatProperties(vki, physDev, format);
75         if ((properties.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) != 0u)
76             return format;
77     }
78 
79     TCU_FAIL("No suitable depth/stencil format found");
80     return VK_FORMAT_UNDEFINED; // Unreachable.
81 }
82 
83 // Return a different depth/stencil format from the one chosen.
chooseAltDSFormat(VkFormat chosenFormat)84 VkFormat chooseAltDSFormat(VkFormat chosenFormat)
85 {
86     const auto candidates = getDSFormatList();
87 
88     for (const auto &format : candidates)
89     {
90         if (format != chosenFormat)
91             return format;
92     }
93 
94     DE_ASSERT(false);
95     return candidates.at(0u);
96 }
97 
98 struct TestParams
99 {
100     static constexpr uint32_t kMaxFragAttachments = 8u; // Based on real-world maxFragmentOutputAttachments values.
101     static constexpr uint32_t kMaxFramebufferAttachments =
102         2u * kMaxFragAttachments;                          // Slightly arbitrary, based on the previous number.
103     static constexpr uint32_t kExtraPipelineAttCount = 4u; // Used when largePipeAttCount is true.
104 
105     const uint32_t
106         pipeFBAttachmentCount; // Number of attachments specified in the pipeline and framebuffer (VUID-vkCmdDraw-colorAttachmentCount-06179).
107     const uint32_t fragAttachmentCount; // Frag shader outputs. Needs to be >= pipeFBAttachmentCount.
108 
109     const uint32_t layerCount; // Image layers.
110     const uint32_t layerMask;  // Which layers are going to be written to, either using viewMask or manual calls.
111     const bool multiView;      // Manual or "automatic" layer handling.
112 
113     const uint32_t
114         formatMask; // Which attachments will have VK_FORMAT_UNDEFINED in the pipeline (0 for undefined, 1 for defined).
115     const uint32_t
116         framebufferMask; // Which attachments will be VK_NULL_HANDLE in the framebuffer (0 for null, 1 for valid handle).
117 
118     const bool depthPresent;     // Create the pipeline with a depth attachment or not.
119     const bool depthDefined;     // Make the depth attachment have VK_FORMAT_UNDEFINED in the pipeline or not.
120     const bool depthValidHandle; // Make the depth attachment be VK_NULL_HANDLE in the framebuffer or not.
121 
122     const bool stencilPresent;     // Create the pipeline with a stencil attachment or not.
123     const bool stencilDefined;     // Make the stencil attachment have VK_FORMAT_UNDEFINED in the pipeline or not.
124     const bool stencilValidHandle; // Make the stencil attachment be VK_NULL_HANDLE in the framebuffer or not.
125 
126     const bool useSecondaries;           // Use secondary command buffers inside the render pass.
127     const bool wrongFormatWithNullViews; // Use the wrong format value if the image view handle is VK_NULL_HANDLE.
128     const bool
129         largePipeAttCount; // Ignore VUID-vkCmdDraw-colorAttachmentCount-06179 and make VkPipelineRenderingCreateInfo::colorAttachmentCount larger than VkRenderingInfo::colorAttachmentCount.
130 
TestParamsvkt::renderpass::__anonacb1cc960111::TestParams131     TestParams(uint32_t pipeFBAttachmentCount_, uint32_t fragAttachmentCount_, uint32_t layerCount_,
132                uint32_t layerMask_, bool multiView_, uint32_t formatMask_, uint32_t framebufferMask_,
133                bool depthPresent_, bool depthDefined_, bool depthValidHandle_, bool stencilPresent_,
134                bool stencilDefined_, bool stencilValidHandle_, bool useSecondaries_, bool wrongFormatWithNullViews_,
135                bool largePipeAttCount_)
136         : pipeFBAttachmentCount(pipeFBAttachmentCount_)
137         , fragAttachmentCount(fragAttachmentCount_)
138         , layerCount(layerCount_)
139         , layerMask(layerMask_)
140         , multiView(multiView_)
141         , formatMask(formatMask_)
142         , framebufferMask(framebufferMask_)
143         , depthPresent(depthPresent_)
144         , depthDefined(depthDefined_)
145         , depthValidHandle(depthValidHandle_)
146         , stencilPresent(stencilPresent_)
147         , stencilDefined(stencilDefined_)
148         , stencilValidHandle(stencilValidHandle_)
149         , useSecondaries(useSecondaries_)
150         , wrongFormatWithNullViews(wrongFormatWithNullViews_)
151         , largePipeAttCount(largePipeAttCount_)
152     {
153         DE_ASSERT(fragAttachmentCount <= kMaxFragAttachments);
154         DE_ASSERT(pipeFBAttachmentCount <= kMaxFramebufferAttachments);
155         DE_ASSERT(fragAttachmentCount >= pipeFBAttachmentCount);
156         DE_ASSERT(layerCount >= 1u);
157     }
158 
159 private:
getFlagTextvkt::renderpass::__anonacb1cc960111::TestParams160     inline const char *getFlagText(bool flag, const char *trueText, const char *falseText) const
161     {
162         return (flag ? trueText : falseText);
163     }
164 
getPresentvkt::renderpass::__anonacb1cc960111::TestParams165     inline const char *getPresent(bool flag) const
166     {
167         return getFlagText(flag, "yes", "no");
168     }
getDefinedvkt::renderpass::__anonacb1cc960111::TestParams169     inline const char *getDefined(bool flag) const
170     {
171         return getFlagText(flag, "def", "undef");
172     }
getValidvkt::renderpass::__anonacb1cc960111::TestParams173     inline const char *getValid(bool flag) const
174     {
175         return getFlagText(flag, "valid", "null");
176     }
177 
178 public:
getTestNamevkt::renderpass::__anonacb1cc960111::TestParams179     std::string getTestName(void) const
180     {
181         // Yes, this is an awfully long string.
182         std::ostringstream testName;
183         testName << "pipe_" << pipeFBAttachmentCount << "_frag_" << fragAttachmentCount << "_layers_" << layerCount
184                  << "_mask_0x" << std::hex << std::setfill('0') << std::setw(2) << layerMask << "_formats_0x"
185                  << std::hex << std::setfill('0') << std::setw(8) << formatMask << "_handles_0x" << std::hex
186                  << std::setfill('0') << std::setw(8) << framebufferMask << "_depth_" << getPresent(depthPresent) << "_"
187                  << getDefined(depthDefined) << "_" << getValid(depthValidHandle) << "_stencil_"
188                  << getPresent(stencilPresent) << "_" << getDefined(stencilDefined) << "_"
189                  << getValid(stencilValidHandle) << (multiView ? "_multiview" : "")
190             //<< (wrongFormatWithNullViews ? "_bad_formats" : "")
191             ;
192         return testName.str();
193     }
194 
depthStencilNeededvkt::renderpass::__anonacb1cc960111::TestParams195     bool depthStencilNeeded(void) const
196     {
197         return (depthPresent || stencilPresent);
198     }
199 
200     // Returns true if the vertex shader has to write to the Layer built-in.
vertExportsLayervkt::renderpass::__anonacb1cc960111::TestParams201     bool vertExportsLayer(void) const
202     {
203         return (!multiView && layerCount > 1u);
204     }
205 
206 protected:
getFormatVectorForMaskvkt::renderpass::__anonacb1cc960111::TestParams207     std::vector<VkFormat> getFormatVectorForMask(const VkFormat colorFormat, const uint32_t bitMask,
208                                                  const uint32_t attachmentCount) const
209     {
210         std::bitset<kMaxFragAttachments> mask(static_cast<unsigned long long>(bitMask));
211         std::vector<VkFormat> formats;
212 
213         formats.reserve(attachmentCount);
214         for (uint32_t attIdx = 0u; attIdx < attachmentCount; ++attIdx)
215             formats.push_back(mask[attIdx] ? colorFormat : VK_FORMAT_UNDEFINED);
216 
217         return formats;
218     }
219 
220 public:
getPipelineFormatVectorvkt::renderpass::__anonacb1cc960111::TestParams221     std::vector<VkFormat> getPipelineFormatVector(const VkFormat colorFormat) const
222     {
223         return getFormatVectorForMask(colorFormat, formatMask, pipeFBAttachmentCount);
224     }
225 
getInheritanceFormatVectorvkt::renderpass::__anonacb1cc960111::TestParams226     std::vector<VkFormat> getInheritanceFormatVector(const VkFormat colorFormat) const
227     {
228         return getFormatVectorForMask(colorFormat, framebufferMask, pipeFBAttachmentCount);
229     }
230 
getPipelineDepthFormatvkt::renderpass::__anonacb1cc960111::TestParams231     inline VkFormat getPipelineDepthFormat(VkFormat dsFormat) const
232     {
233         return ((depthPresent && depthDefined) ? dsFormat : VK_FORMAT_UNDEFINED);
234     }
235 
getInheritanceDepthFormatvkt::renderpass::__anonacb1cc960111::TestParams236     inline VkFormat getInheritanceDepthFormat(VkFormat dsFormat) const
237     {
238         return ((depthPresent && depthValidHandle) ? dsFormat : VK_FORMAT_UNDEFINED);
239     }
240 
getPipelineStencilFormatvkt::renderpass::__anonacb1cc960111::TestParams241     inline VkFormat getPipelineStencilFormat(VkFormat dsFormat) const
242     {
243         return ((stencilPresent && stencilDefined) ? dsFormat : VK_FORMAT_UNDEFINED);
244     }
245 
getInheritanceStencilFormatvkt::renderpass::__anonacb1cc960111::TestParams246     inline VkFormat getInheritanceStencilFormat(VkFormat dsFormat) const
247     {
248         return ((stencilPresent && stencilValidHandle) ? dsFormat : VK_FORMAT_UNDEFINED);
249     }
250 
getClearValuevkt::renderpass::__anonacb1cc960111::TestParams251     static VkClearValue getClearValue(void)
252     {
253         VkClearValue clearValue;
254         deMemset(&clearValue, 0, sizeof(clearValue));
255         return clearValue;
256     }
257 
getRenderingAttachmentInfosvkt::renderpass::__anonacb1cc960111::TestParams258     std::vector<VkRenderingAttachmentInfo> getRenderingAttachmentInfos(const std::vector<VkImageView> &imageViews) const
259     {
260         DE_ASSERT(imageViews.size() == static_cast<size_t>(pipeFBAttachmentCount));
261 
262         std::bitset<kMaxFramebufferAttachments> mask(static_cast<unsigned long long>(framebufferMask));
263         const auto clearValue = getClearValue();
264         std::vector<VkRenderingAttachmentInfo> infos;
265 
266         infos.reserve(pipeFBAttachmentCount);
267         for (uint32_t attIdx = 0u; attIdx < pipeFBAttachmentCount; ++attIdx)
268         {
269             const auto imgView = (mask[attIdx] ? imageViews.at(attIdx) : VK_NULL_HANDLE);
270 
271             infos.push_back(VkRenderingAttachmentInfo{
272                 VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO, // VkStructureType sType;
273                 nullptr,                                     // const void* pNext;
274                 imgView,                                     // VkImageView imageView;
275                 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,    // VkImageLayout imageLayout;
276                 VK_RESOLVE_MODE_NONE,                        // VkResolveModeFlagBits resolveMode;
277                 VK_NULL_HANDLE,                              // VkImageView resolveImageView;
278                 VK_IMAGE_LAYOUT_UNDEFINED,                   // VkImageLayout resolveImageLayout;
279                 VK_ATTACHMENT_LOAD_OP_LOAD,                  // VkAttachmentLoadOp loadOp;
280                 VK_ATTACHMENT_STORE_OP_STORE,                // VkAttachmentStoreOp storeOp;
281                 clearValue,                                  // VkClearValue clearValue;
282             });
283         }
284 
285         return infos;
286     }
287 
getDepthAttachmentInfovkt::renderpass::__anonacb1cc960111::TestParams288     VkRenderingAttachmentInfo getDepthAttachmentInfo(const VkImageView imageView) const
289     {
290         const auto clearValue = getClearValue();
291         const auto attView    = ((depthPresent && depthValidHandle) ? imageView : VK_NULL_HANDLE);
292 
293         return VkRenderingAttachmentInfo{
294             VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO,      // VkStructureType sType;
295             nullptr,                                          // const void* pNext;
296             attView,                                          // VkImageView imageView;
297             VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, // VkImageLayout imageLayout;
298             VK_RESOLVE_MODE_NONE,                             // VkResolveModeFlagBits resolveMode;
299             VK_NULL_HANDLE,                                   // VkImageView resolveImageView;
300             VK_IMAGE_LAYOUT_UNDEFINED,                        // VkImageLayout resolveImageLayout;
301             VK_ATTACHMENT_LOAD_OP_LOAD,                       // VkAttachmentLoadOp loadOp;
302             VK_ATTACHMENT_STORE_OP_STORE,                     // VkAttachmentStoreOp storeOp;
303             clearValue,                                       // VkClearValue clearValue;
304         };
305     }
306 
getStencilAttachmentInfovkt::renderpass::__anonacb1cc960111::TestParams307     VkRenderingAttachmentInfo getStencilAttachmentInfo(const VkImageView imageView) const
308     {
309         const auto clearValue = getClearValue();
310         const auto attView    = ((stencilPresent && stencilValidHandle) ? imageView : VK_NULL_HANDLE);
311 
312         return VkRenderingAttachmentInfo{
313             VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO,      // VkStructureType sType;
314             nullptr,                                          // const void* pNext;
315             attView,                                          // VkImageView imageView;
316             VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, // VkImageLayout imageLayout;
317             VK_RESOLVE_MODE_NONE,                             // VkResolveModeFlagBits resolveMode;
318             VK_NULL_HANDLE,                                   // VkImageView resolveImageView;
319             VK_IMAGE_LAYOUT_UNDEFINED,                        // VkImageLayout resolveImageLayout;
320             VK_ATTACHMENT_LOAD_OP_LOAD,                       // VkAttachmentLoadOp loadOp;
321             VK_ATTACHMENT_STORE_OP_STORE,                     // VkAttachmentStoreOp storeOp;
322             clearValue,                                       // VkClearValue clearValue;
323         };
324     }
325 };
326 
327 class DynamicUnusedAttachmentsInstance : public vkt::TestInstance
328 {
329 public:
DynamicUnusedAttachmentsInstance(Context & context,const TestParams & params)330     DynamicUnusedAttachmentsInstance(Context &context, const TestParams &params)
331         : vkt::TestInstance(context)
332         , m_params(params)
333     {
334     }
~DynamicUnusedAttachmentsInstance(void)335     virtual ~DynamicUnusedAttachmentsInstance(void)
336     {
337     }
338 
339     tcu::TestStatus iterate(void) override;
340 
341 protected:
342     const TestParams m_params;
343 };
344 
345 class DynamicUnusedAttachmentsCase : public vkt::TestCase
346 {
347 public:
DynamicUnusedAttachmentsCase(tcu::TestContext & testCtx,const std::string & name,const TestParams & params)348     DynamicUnusedAttachmentsCase(tcu::TestContext &testCtx, const std::string &name, const TestParams &params)
349         : vkt::TestCase(testCtx, name)
350         , m_params(params)
351     {
352     }
createInstance(Context & context) const353     TestInstance *createInstance(Context &context) const override
354     {
355         return new DynamicUnusedAttachmentsInstance(context, m_params);
356     }
357     void initPrograms(vk::SourceCollections &programCollection) const override;
358     void checkSupport(Context &context) const override;
359 
360 protected:
361     const TestParams m_params;
362 };
363 
initPrograms(vk::SourceCollections & programCollection) const364 void DynamicUnusedAttachmentsCase::initPrograms(vk::SourceCollections &programCollection) const
365 {
366     const bool vertExportsLayer = m_params.vertExportsLayer();
367 
368     std::ostringstream vert;
369     vert << "#version 460\n"
370          << "#extension GL_ARB_shader_viewport_layer_array : enable\n"
371          << "layout (push_constant, std430) uniform PushConstantBlock { int layerIndex; } pc;\n"
372          << "vec2 positions[3] = vec2[](\n"
373          << "    vec2(-1.0, -1.0),\n"
374          << "    vec2(-1.0,  3.0),\n"
375          << "    vec2( 3.0, -1.0)\n"
376          << ");\n"
377          << "void main() {\n"
378          << "    gl_Position = vec4(positions[gl_VertexIndex % 3], 1.0, 1.0);\n"
379          << (vertExportsLayer ? "    gl_Layer = pc.layerIndex;\n" : "") << "}\n";
380     {
381         // This is required by the validation layers for the program to be correct. A SPIR-V 1.0 module that exports the Layer
382         // built-in will use the ShaderViewportIndexLayerEXT capability, which is enabled by the VK_EXT_shader_viewport_index_layer
383         // extension.
384         //
385         // However, in Vulkan 1.2+ the extension was promoted to core and that capability was replaced by the ShaderLayer and
386         // ShaderViewportIndex capabilities, which are enabled by the shaderOutputViewportIndex and shaderOutputLayer features in
387         // VkPhysicalDeviceVulkan12Features. In a Vulkan 1.2+ context, CTS will not enable VK_EXT_shader_viewport_index_layer as
388         // that's part of the core extensions, and will enable the Vulkan 1.2 features instead. These will allow access to the
389         // ShaderLayer and ShaderViewportIndex capabilities, but not the ShaderViewportIndexLayerEXT capability.
390         //
391         // When building the vertex module, glslang will, by default, target SPIR-V 1.0 and create a module that uses the
392         // ShaderViewportIndexLayerEXT capability. When targetting SPIR-V 1.5 explicitly, glslang will generate a module that uses
393         // the ShaderLayer capability.
394         //
395         // We cannot use a SPIR-V 1.0 module in a Vulkan 1.2+ context, because it will use the ShaderViewportIndexLayerEXT
396         // capability, which will not be enabled. In that case, we must use a SPIR-V 1.5 module that depends on the ShaderLayer
397         // capability.
398         //
399         // We cannot use a SPIR-V 1.5 module in a Vulkan <1.2 context, because it will use the ShaderLayer capability, which will
400         // not be enabled. In these cases, we must use a SPIR-V 1.0 module that depends on the ShaderViewportIndexLayerEXT
401         // capability.
402         //
403         // So we need both versions of the vertex shader and we need to choose at runtime.
404         //
405         const auto src = vert.str();
406         const vk::ShaderBuildOptions spv15Opts(programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_5, 0u, false);
407 
408         programCollection.glslSources.add("vert-spv10") << glu::VertexSource(src);
409         programCollection.glslSources.add("vert-spv15") << glu::VertexSource(src) << spv15Opts;
410     }
411 
412     // Make sure the fragment shader does not write to any attachment which will have an undefined format in the pipeline.
413     std::vector<bool> fragAttachmentUsed(m_params.fragAttachmentCount, true);
414     const auto pipelineFormats = m_params.getPipelineFormatVector(kColorFormat);
415 
416     for (size_t i = 0; i < pipelineFormats.size(); ++i)
417     {
418         if (pipelineFormats[i] == VK_FORMAT_UNDEFINED)
419             fragAttachmentUsed.at(i) = false;
420     }
421 
422     std::ostringstream frag;
423 
424     frag << "#version 460\n"
425          << "#extension " << (m_params.multiView ? "GL_EXT_multiview" : "GL_ARB_shader_viewport_layer_array")
426          << " : enable\n";
427     ;
428 
429     // Color outputs.
430     for (uint32_t i = 0u; i < m_params.fragAttachmentCount; ++i)
431     {
432         if (fragAttachmentUsed.at(i))
433             frag << "layout (location=" << i << ") out uvec4 color" << i << ";\n";
434     }
435 
436     const char *layerIndexExpr;
437 
438     if (m_params.multiView)
439         layerIndexExpr = "uint(gl_ViewIndex)";
440     else if (vertExportsLayer)
441         layerIndexExpr = "uint(gl_Layer)";
442     else
443         layerIndexExpr = "0u";
444 
445     frag << "void main (void) {\n"
446          << "    const uint layerIndex = " << layerIndexExpr << ";\n";
447 
448     for (uint32_t i = 0u; i < m_params.fragAttachmentCount; ++i)
449     {
450         if (fragAttachmentUsed.at(i))
451             frag << "    color" << i << " = uvec4(layerIndex, 255, " << i << ", 255);\n";
452     }
453 
454     frag << "}\n";
455 
456     programCollection.glslSources.add("frag") << glu::FragmentSource(frag.str());
457 }
458 
checkSupport(Context & context) const459 void DynamicUnusedAttachmentsCase::checkSupport(Context &context) const
460 {
461     context.requireDeviceFunctionality("VK_KHR_dynamic_rendering");
462     context.requireDeviceFunctionality("VK_EXT_dynamic_rendering_unused_attachments");
463 
464     const auto &properties = context.getDeviceProperties();
465 
466     if (m_params.fragAttachmentCount > properties.limits.maxFragmentOutputAttachments)
467         TCU_THROW(NotSupportedError, "Unsupported number of fragment output attachments");
468 
469     if (m_params.pipeFBAttachmentCount > properties.limits.maxColorAttachments)
470         TCU_THROW(NotSupportedError, "Unsupported number of color attachments");
471 
472     if (m_params.largePipeAttCount)
473     {
474         // In theory, there's no limit to the amount of attachments in the pipeline.
475         // In practice, many implementations limit these to maxFragmentOutputAttachments, so we check the limit here.
476         const auto pipelineAttCount = m_params.pipeFBAttachmentCount + TestParams::kExtraPipelineAttCount;
477         if (pipelineAttCount > properties.limits.maxFragmentOutputAttachments)
478             TCU_THROW(NotSupportedError, "Unsupported number of extra attachments");
479     }
480 
481     if (m_params.vertExportsLayer())
482     {
483         // This will check the right extension or Vulkan 1.2 features automatically.
484         context.requireDeviceFunctionality("VK_EXT_shader_viewport_index_layer");
485 
486         // We also need geometry shader support to be able to use gl_Layer from frag shaders.
487         context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_GEOMETRY_SHADER);
488     }
489 
490     if (m_params.multiView)
491         context.requireDeviceFunctionality("VK_KHR_multiview");
492 }
493 
iterate(void)494 tcu::TestStatus DynamicUnusedAttachmentsInstance::iterate(void)
495 {
496     const auto ctx = m_context.getContextCommonData();
497     const tcu::IVec3 fbDim(1, 1, 1);
498     const auto fbExtent  = makeExtent3D(fbDim);
499     const auto fbSamples = VK_SAMPLE_COUNT_1_BIT;
500     const auto colorUsage =
501         (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT);
502     const auto dsUsage  = (VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
503                           VK_IMAGE_USAGE_TRANSFER_DST_BIT);
504     const auto colorSRR = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, m_params.layerCount);
505     const auto dsSRR = makeImageSubresourceRange((VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT), 0u, 1u, 0u,
506                                                  m_params.layerCount);
507     const auto colorSRL   = makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, m_params.layerCount);
508     const auto depthSRL   = makeImageSubresourceLayers(VK_IMAGE_ASPECT_DEPTH_BIT, 0u, 0u, m_params.layerCount);
509     const auto stencilSRL = makeImageSubresourceLayers(VK_IMAGE_ASPECT_STENCIL_BIT, 0u, 0u, m_params.layerCount);
510     const auto dsNeeded   = m_params.depthStencilNeeded();
511 
512     using ImageWithBufferPtr = std::unique_ptr<ImageWithBuffer>;
513 
514     // Allocate color attachments.
515     std::vector<ImageWithBufferPtr> colorImages(m_params.pipeFBAttachmentCount);
516     for (uint32_t i = 0; i < m_params.pipeFBAttachmentCount; ++i)
517         colorImages[i].reset(new ImageWithBuffer(ctx.vkd, ctx.device, ctx.allocator, fbExtent, kColorFormat, colorUsage,
518                                                  VK_IMAGE_TYPE_2D, colorSRR, m_params.layerCount));
519 
520     VkFormat dsFormat = VK_FORMAT_UNDEFINED;
521     std::unique_ptr<ImageWithMemory> dsImage;
522     Move<VkImageView> dsImageView;
523     tcu::TextureFormat depthCopyFormat;
524     tcu::TextureFormat stencilCopyFormat;
525     std::unique_ptr<BufferWithMemory> depthVerificationBuffer;
526     std::unique_ptr<BufferWithMemory> stencilVerificationBuffer;
527 
528     if (dsNeeded)
529         dsFormat = chooseDepthStencilFormat(ctx.vki, ctx.physicalDevice);
530 
531     if (dsNeeded)
532     {
533         const VkImageCreateInfo dsCreateInfo = {
534             VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
535             nullptr,                             // const void* pNext;
536             0u,                                  // VkImageCreateFlags flags;
537             VK_IMAGE_TYPE_2D,                    // VkImageType imageType;
538             dsFormat,                            // VkFormat format;
539             fbExtent,                            // VkExtent3D extent;
540             1u,                                  // uint32_t mipLevels;
541             m_params.layerCount,                 // uint32_t arrayLayers;
542             fbSamples,                           // VkSampleCountFlagBits samples;
543             VK_IMAGE_TILING_OPTIMAL,             // VkImageTiling tiling;
544             dsUsage,                             // VkImageUsageFlags usage;
545             VK_SHARING_MODE_EXCLUSIVE,           // VkSharingMode sharingMode;
546             0u,                                  // uint32_t queueFamilyIndexCount;
547             nullptr,                             // const uint32_t* pQueueFamilyIndices;
548             VK_IMAGE_LAYOUT_UNDEFINED,           // VkImageLayout initialLayout;
549         };
550         dsImage.reset(new ImageWithMemory(ctx.vkd, ctx.device, ctx.allocator, dsCreateInfo, MemoryRequirement::Any));
551 
552         const auto dsImageViewType = (m_params.layerCount > 1u ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D);
553         dsImageView       = makeImageView(ctx.vkd, ctx.device, dsImage->get(), dsImageViewType, dsFormat, dsSRR);
554         depthCopyFormat   = getDepthCopyFormat(dsFormat);
555         stencilCopyFormat = getStencilCopyFormat(dsFormat);
556 
557         const auto depthVerificationBufferSize =
558             static_cast<VkDeviceSize>(tcu::getPixelSize(depthCopyFormat) * fbExtent.width * fbExtent.height *
559                                       fbExtent.depth * m_params.layerCount);
560         const auto depthVerificationBufferInfo =
561             makeBufferCreateInfo(depthVerificationBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
562         depthVerificationBuffer.reset(new BufferWithMemory(
563             ctx.vkd, ctx.device, ctx.allocator, depthVerificationBufferInfo, MemoryRequirement::HostVisible));
564 
565         const auto stencilVerificationBufferSize =
566             static_cast<VkDeviceSize>(tcu::getPixelSize(stencilCopyFormat) * fbExtent.width * fbExtent.height *
567                                       fbExtent.depth * m_params.layerCount);
568         const auto stencilVerificationBufferInfo =
569             makeBufferCreateInfo(stencilVerificationBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
570         stencilVerificationBuffer.reset(new BufferWithMemory(
571             ctx.vkd, ctx.device, ctx.allocator, stencilVerificationBufferInfo, MemoryRequirement::HostVisible));
572     }
573 
574     const std::vector<VkViewport> viewports(1u, makeViewport(fbExtent));
575     const std::vector<VkRect2D> scissors(1u, makeRect2D(fbExtent));
576 
577     const auto &binaries   = m_context.getBinaryCollection();
578     const auto vk12Support = m_context.contextSupports(vk::ApiVersion(0u, 1u, 2u, 0u));
579     const auto vertModule =
580         createShaderModule(ctx.vkd, ctx.device, binaries.get(vk12Support ? "vert-spv15" : "vert-spv10"));
581     const auto fragModule = createShaderModule(ctx.vkd, ctx.device, binaries.get("frag"));
582 
583     const auto pcSize         = static_cast<uint32_t>(sizeof(int32_t));
584     const auto pcStages       = VK_SHADER_STAGE_VERTEX_BIT;
585     const auto pcRange        = makePushConstantRange(pcStages, 0u, pcSize);
586     const auto pipelineLayout = makePipelineLayout(ctx.vkd, ctx.device, VK_NULL_HANDLE, &pcRange);
587 
588     const VkPipelineVertexInputStateCreateInfo vertexInputStateCreateInfo = initVulkanStructure();
589     const auto stencilOpState = makeStencilOpState(VK_STENCIL_OP_KEEP, VK_STENCIL_OP_REPLACE, VK_STENCIL_OP_KEEP,
590                                                    VK_COMPARE_OP_GREATER_OR_EQUAL, 0xFFu, 0xFFu, 0xFFu);
591     // If the depth or stencil test is enabled and the image view is not VK_NULL_HANDLE, the format cannot be UNDEFINED.
592     const auto depthEnabled   = (m_params.depthPresent && !(!m_params.depthDefined && m_params.depthValidHandle));
593     const auto stencilEnabled = (m_params.stencilPresent && !(!m_params.stencilDefined && m_params.stencilValidHandle));
594     const VkPipelineDepthStencilStateCreateInfo depthStencilStateCreateInfo = {
595         VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, // VkStructureType sType;
596         nullptr,                                                    // const void* pNext;
597         0u,                                                         // VkPipelineDepthStencilStateCreateFlags flags;
598         depthEnabled,                                               // VkBool32 depthTestEnable;
599         depthEnabled,                                               // VkBool32 depthWriteEnable;
600         VK_COMPARE_OP_GREATER_OR_EQUAL,                             // VkCompareOp depthCompareOp;
601         VK_FALSE,                                                   // VkBool32 depthBoundsTestEnable;
602         stencilEnabled,                                             // VkBool32 stencilTestEnable;
603         stencilOpState,                                             // VkStencilOpState front;
604         stencilOpState,                                             // VkStencilOpState back;
605         0.0f,                                                       // float minDepthBounds;
606         1.0f,                                                       // float maxDepthBounds;
607     };
608 
609     auto colorPipelineFormats  = m_params.getPipelineFormatVector(kColorFormat);
610     auto depthPipelineFormat   = m_params.getPipelineDepthFormat(dsFormat);
611     auto stencilPipelineFormat = m_params.getPipelineStencilFormat(dsFormat);
612     const auto viewMask        = (m_params.multiView ? m_params.layerMask : 0u);
613 
614     std::vector<VkImageView> rawColorViews;
615     rawColorViews.reserve(colorImages.size());
616     std::transform(begin(colorImages), end(colorImages), std::back_inserter(rawColorViews),
617                    [](const ImageWithBufferPtr &ib) { return (ib.get() ? ib->getImageView() : VK_NULL_HANDLE); });
618 
619     const auto renderingAttInfos = m_params.getRenderingAttachmentInfos(rawColorViews);
620 
621     using RenderingAttachmentInfoPtr = std::unique_ptr<VkRenderingAttachmentInfo>;
622     RenderingAttachmentInfoPtr depthAttachmentPtr;
623     RenderingAttachmentInfoPtr stencilAttachmentPtr;
624 
625     if (dsNeeded)
626     {
627         const auto &imgView = dsImageView.get();
628         DE_ASSERT(imgView != VK_NULL_HANDLE);
629         depthAttachmentPtr.reset(new VkRenderingAttachmentInfo(m_params.getDepthAttachmentInfo(imgView)));
630         stencilAttachmentPtr.reset(new VkRenderingAttachmentInfo(m_params.getStencilAttachmentInfo(imgView)));
631     }
632 
633     if (m_params.wrongFormatWithNullViews)
634     {
635         DE_ASSERT(renderingAttInfos.size() == colorPipelineFormats.size());
636 
637         // Use wrong formats when the image view is VK_NULL_HANDLE.
638         for (size_t i = 0u; i < renderingAttInfos.size(); ++i)
639         {
640             if (renderingAttInfos[i].imageView == VK_NULL_HANDLE)
641                 colorPipelineFormats[i] = kBadColorFormat;
642         }
643 
644         const auto badDSFormat = chooseAltDSFormat(dsFormat);
645 
646         if (depthAttachmentPtr.get() && depthAttachmentPtr->imageView == VK_NULL_HANDLE)
647             depthPipelineFormat = badDSFormat;
648 
649         if (stencilAttachmentPtr.get() && stencilAttachmentPtr->imageView == VK_NULL_HANDLE)
650             stencilPipelineFormat = badDSFormat;
651     }
652 
653     if (m_params.largePipeAttCount)
654     {
655         // Make VkPipelineRenderingCreateInfo::colorAttachmentCount larger than VkRenderingInfo::colorAttachmentCount
656         colorPipelineFormats.reserve(colorPipelineFormats.size() + TestParams::kExtraPipelineAttCount);
657         for (uint32_t i = 0u; i < TestParams::kExtraPipelineAttCount; ++i)
658             colorPipelineFormats.push_back(kBadColorFormat);
659     }
660 
661     const VkPipelineRenderingCreateInfo pipelineRenderingCreateInfo = {
662         VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR, // VkStructureType sType;
663         nullptr,                                              // const void* pNext;
664         viewMask,                                             // uint32_t viewMask;
665         de::sizeU32(colorPipelineFormats),                    // uint32_t colorAttachmentCount;
666         de::dataOrNull(colorPipelineFormats),                 // const VkFormat* pColorAttachmentFormats;
667         depthPipelineFormat,                                  // VkFormat depthAttachmentFormat;
668         stencilPipelineFormat,                                // VkFormat stencilAttachmentFormat;
669     };
670 
671     const auto colorWriteMask =
672         (VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT);
673     const auto colorBlendAttState = makePipelineColorBlendAttachmentState(
674         VK_FALSE, VK_BLEND_FACTOR_ZERO, VK_BLEND_FACTOR_ZERO, VK_BLEND_OP_ADD, VK_BLEND_FACTOR_ZERO,
675         VK_BLEND_FACTOR_ZERO, VK_BLEND_OP_ADD, colorWriteMask);
676 
677     const std::vector<VkPipelineColorBlendAttachmentState> colorBlendStateVec(
678         pipelineRenderingCreateInfo.colorAttachmentCount, colorBlendAttState);
679 
680     const VkPipelineColorBlendStateCreateInfo colorBlendStateCreateInfo = {
681         VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, // VkStructureType sType;
682         nullptr,                                                  // const void* pNext;
683         0u,                                                       // VkPipelineColorBlendStateCreateFlags flags;
684         VK_FALSE,                                                 // VkBool32 logicOpEnable;
685         VK_LOGIC_OP_CLEAR,                                        // VkLogicOp logicOp;
686         de::sizeU32(colorBlendStateVec),                          // uint32_t attachmentCount;
687         de::dataOrNull(colorBlendStateVec), // const VkPipelineColorBlendAttachmentState* pAttachments;
688         {0.0f, 0.0f, 0.0f, 0.0f},           // float blendConstants[4];
689     };
690 
691     const auto pipeline = makeGraphicsPipeline(
692         ctx.vkd, ctx.device, pipelineLayout.get(), vertModule.get(), VK_NULL_HANDLE, VK_NULL_HANDLE, VK_NULL_HANDLE,
693         fragModule.get(), VK_NULL_HANDLE, viewports, scissors, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, 0u, 0u,
694         &vertexInputStateCreateInfo, nullptr, nullptr, &depthStencilStateCreateInfo, &colorBlendStateCreateInfo,
695         nullptr, &pipelineRenderingCreateInfo);
696 
697     CommandPoolWithBuffer cmd(ctx.vkd, ctx.device, ctx.qfIndex);
698     const auto cmdBuffer = cmd.cmdBuffer.get();
699     Move<VkCommandBuffer> secondaryCmdBuffer;
700 
701     if (m_params.useSecondaries)
702         secondaryCmdBuffer =
703             allocateCommandBuffer(ctx.vkd, ctx.device, cmd.cmdPool.get(), VK_COMMAND_BUFFER_LEVEL_SECONDARY);
704 
705     const auto rpCmdBuffer = (m_params.useSecondaries ? secondaryCmdBuffer.get() : cmdBuffer);
706 
707     const auto renderingFlags =
708         (m_params.useSecondaries ? static_cast<VkRenderingFlags>(VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT) :
709                                    0);
710 
711     const VkRenderingInfo renderingInfo = {
712         VK_STRUCTURE_TYPE_RENDERING_INFO_KHR,            // VkStructureType sType;
713         nullptr,                                         // const void* pNext;
714         renderingFlags,                                  // VkRenderingFlags flags;
715         scissors.at(0u),                                 // VkRect2D renderArea;
716         (m_params.multiView ? 1u : m_params.layerCount), // uint32_t layerCount;
717         viewMask,                                        // uint32_t viewMask;
718         de::sizeU32(renderingAttInfos),                  // uint32_t colorAttachmentCount;
719         de::dataOrNull(renderingAttInfos),               // const VkRenderingAttachmentInfo* pColorAttachments;
720         depthAttachmentPtr.get(),                        // const VkRenderingAttachmentInfo* pDepthAttachment;
721         stencilAttachmentPtr.get(),                      // const VkRenderingAttachmentInfo* pStencilAttachment;
722     };
723 
724     beginCommandBuffer(ctx.vkd, cmdBuffer);
725 
726     // Transition the layout of every image.
727     {
728         std::vector<VkImageMemoryBarrier> initialLayoutBarriers;
729 
730         for (const auto &img : colorImages)
731         {
732             const auto colorBarrier =
733                 makeImageMemoryBarrier(0u, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED,
734                                        VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, img->getImage(), colorSRR);
735             initialLayoutBarriers.push_back(colorBarrier);
736         }
737         if (dsNeeded)
738         {
739             const auto dsBarrier = makeImageMemoryBarrier(0u, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED,
740                                                           VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, dsImage->get(), dsSRR);
741             initialLayoutBarriers.push_back(dsBarrier);
742         }
743 
744         ctx.vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u,
745                                    nullptr, 0u, nullptr, de::sizeU32(initialLayoutBarriers),
746                                    de::dataOrNull(initialLayoutBarriers));
747     }
748 
749     // Clear images.
750     {
751         const auto clearValue = TestParams::getClearValue();
752 
753         for (const auto &img : colorImages)
754             ctx.vkd.cmdClearColorImage(cmdBuffer, img->getImage(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
755                                        &clearValue.color, 1u, &colorSRR);
756         if (dsNeeded)
757             ctx.vkd.cmdClearDepthStencilImage(cmdBuffer, dsImage->get(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
758                                               &clearValue.depthStencil, 1u, &dsSRR);
759     }
760 
761     // Transition the layout of every image.
762     {
763         std::vector<VkImageMemoryBarrier> initialLayoutBarriers;
764 
765         for (const auto &img : colorImages)
766         {
767             const auto colorBarrier =
768                 makeImageMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT,
769                                        (VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT),
770                                        VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
771                                        img->getImage(), colorSRR);
772             initialLayoutBarriers.push_back(colorBarrier);
773         }
774         if (dsNeeded)
775         {
776             const auto dsBarrier = makeImageMemoryBarrier(
777                 VK_ACCESS_TRANSFER_WRITE_BIT,
778                 (VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT),
779                 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, dsImage->get(),
780                 dsSRR);
781             initialLayoutBarriers.push_back(dsBarrier);
782         }
783 
784         ctx.vkd.cmdPipelineBarrier(
785             cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT,
786             (VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
787              VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT),
788             0u, 0u, nullptr, 0u, nullptr, de::sizeU32(initialLayoutBarriers), de::dataOrNull(initialLayoutBarriers));
789     }
790 
791     ctx.vkd.cmdBeginRendering(cmdBuffer, &renderingInfo);
792 
793     if (m_params.useSecondaries)
794     {
795         // The inheritance info and framebuffer attachments must match (null handle -> undefined format, non-null handle -> valid format).
796         // The pipeline rendering info will later be able to selectively disable an attachment.
797         const auto inheritanceColorFormats  = m_params.getInheritanceFormatVector(kColorFormat);
798         const auto inheritanceDepthFormat   = m_params.getInheritanceDepthFormat(dsFormat);
799         const auto inheritanceStencilFormat = m_params.getInheritanceStencilFormat(dsFormat);
800 
801         const VkCommandBufferInheritanceRenderingInfo inheritanceRenderingInfo = {
802             VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_RENDERING_INFO, // VkStructureType sType;
803             nullptr,                                                     // const void* pNext;
804             0u,                                                          // VkRenderingFlags flags;
805             viewMask,                                                    // uint32_t viewMask;
806             de::sizeU32(inheritanceColorFormats),                        // uint32_t colorAttachmentCount;
807             de::dataOrNull(inheritanceColorFormats),                     // const VkFormat* pColorAttachmentFormats;
808             inheritanceDepthFormat,                                      // VkFormat depthAttachmentFormat;
809             inheritanceStencilFormat,                                    // VkFormat stencilAttachmentFormat;
810             fbSamples,                                                   // VkSampleCountFlagBits rasterizationSamples;
811         };
812 
813         const VkCommandBufferInheritanceInfo inheritanceInfo = {
814             VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO, // VkStructureType sType;
815             &inheritanceRenderingInfo,                         // const void* pNext;
816             VK_NULL_HANDLE,                                    // VkRenderPass renderPass;
817             0u,                                                // uint32_t subpass;
818             VK_NULL_HANDLE,                                    // VkFramebuffer framebuffer;
819             VK_FALSE,                                          // VkBool32 occlusionQueryEnable;
820             0u,                                                // VkQueryControlFlags queryFlags;
821             0u,                                                // VkQueryPipelineStatisticFlags pipelineStatistics;
822         };
823 
824         const VkCommandBufferBeginInfo beginInfo = {
825             VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,      // VkStructureType sType;
826             nullptr,                                          // const void* pNext;
827             VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT, // VkCommandBufferUsageFlags flags;
828             &inheritanceInfo,                                 // const VkCommandBufferInheritanceInfo* pInheritanceInfo;
829         };
830 
831         ctx.vkd.beginCommandBuffer(secondaryCmdBuffer.get(), &beginInfo);
832     }
833 
834     ctx.vkd.cmdBindPipeline(rpCmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.get());
835     {
836         const auto iterCount = (m_params.multiView ? 1u : m_params.layerCount);
837         for (uint32_t i = 0; i < iterCount; ++i)
838         {
839             // In non-multiview mode, we have to skip some layers manually.
840             if (!m_params.multiView && ((m_params.layerMask & (1u << i)) == 0u))
841                 continue;
842 
843             ctx.vkd.cmdPushConstants(rpCmdBuffer, pipelineLayout.get(), pcStages, 0u, pcSize, &i);
844             ctx.vkd.cmdDraw(rpCmdBuffer, 3u, 1u, 0u, 0u);
845         }
846     }
847 
848     if (m_params.useSecondaries)
849     {
850         endCommandBuffer(ctx.vkd, secondaryCmdBuffer.get());
851         ctx.vkd.cmdExecuteCommands(cmdBuffer, 1u, &secondaryCmdBuffer.get());
852     }
853 
854     ctx.vkd.cmdEndRendering(cmdBuffer);
855 
856     // Transition the layout of all images again for verification.
857     {
858         std::vector<VkImageMemoryBarrier> preCopyLayoutBarriers;
859 
860         for (const auto &img : colorImages)
861         {
862             const auto colorBarrier =
863                 makeImageMemoryBarrier((VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT),
864                                        VK_ACCESS_TRANSFER_READ_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
865                                        VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, img->getImage(), colorSRR);
866             preCopyLayoutBarriers.push_back(colorBarrier);
867         }
868         if (dsNeeded)
869         {
870             const auto dsBarrier = makeImageMemoryBarrier(
871                 (VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT),
872                 VK_ACCESS_TRANSFER_READ_BIT, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
873                 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dsImage->get(), dsSRR);
874             preCopyLayoutBarriers.push_back(dsBarrier);
875         }
876 
877         ctx.vkd.cmdPipelineBarrier(cmdBuffer,
878                                    (VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
879                                     VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
880                                     VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT),
881                                    VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, nullptr, 0u, nullptr,
882                                    de::sizeU32(preCopyLayoutBarriers), de::dataOrNull(preCopyLayoutBarriers));
883     }
884 
885     // Copy all image contents to their verification buffers (note depth/stencil uses two buffers).
886     for (const auto &img : colorImages)
887     {
888         const auto copyRegion = makeBufferImageCopy(fbExtent, colorSRL);
889         ctx.vkd.cmdCopyImageToBuffer(cmdBuffer, img->getImage(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, img->getBuffer(),
890                                      1u, &copyRegion);
891     }
892     if (dsNeeded)
893     {
894         const auto depthCopyRegion   = makeBufferImageCopy(fbExtent, depthSRL);
895         const auto stencilCopyRegion = makeBufferImageCopy(fbExtent, stencilSRL);
896 
897         ctx.vkd.cmdCopyImageToBuffer(cmdBuffer, dsImage->get(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
898                                      depthVerificationBuffer->get(), 1u, &depthCopyRegion);
899         ctx.vkd.cmdCopyImageToBuffer(cmdBuffer, dsImage->get(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
900                                      stencilVerificationBuffer->get(), 1u, &stencilCopyRegion);
901     }
902 
903     // Global barrier to synchronize verification buffers to host reads.
904     {
905         const auto transfer2HostBarrier = makeMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT);
906         cmdPipelineMemoryBarrier(ctx.vkd, cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT,
907                                  &transfer2HostBarrier);
908     }
909 
910     endCommandBuffer(ctx.vkd, cmdBuffer);
911     submitCommandsAndWait(ctx.vkd, ctx.device, ctx.queue, cmdBuffer);
912 
913     // Invalidate all allocations.
914     for (uint32_t i = 0; i < m_params.pipeFBAttachmentCount; ++i)
915         invalidateAlloc(ctx.vkd, ctx.device, colorImages.at(i)->getBufferAllocation());
916     if (dsNeeded)
917     {
918         invalidateAlloc(ctx.vkd, ctx.device, depthVerificationBuffer->getAllocation());
919         invalidateAlloc(ctx.vkd, ctx.device, stencilVerificationBuffer->getAllocation());
920     }
921 
922     // Verify all layers in all images.
923     const auto colorTcuFormat = mapVkFormat(kColorFormat);
924     const auto colorPixelSize = tcu::getPixelSize(colorTcuFormat);
925     const auto colorLayerSize = static_cast<size_t>(fbDim.x() * fbDim.y() * fbDim.z() * colorPixelSize);
926 
927     const tcu::UVec4 threshold(0u, 0u, 0u, 0u); // We expect exact results.
928     auto &log    = m_context.getTestContext().getLog();
929     bool failure = false;
930 
931     for (size_t colorImgIdx = 0u; colorImgIdx < colorImages.size(); ++colorImgIdx)
932     {
933         const auto &colorImg = colorImages.at(colorImgIdx);
934         const auto dataPtr   = reinterpret_cast<const char *>(colorImg->getBufferAllocation().getHostPtr());
935         const bool imgWritten =
936             (colorImgIdx < colorPipelineFormats.size() && colorPipelineFormats.at(colorImgIdx) != VK_FORMAT_UNDEFINED &&
937              colorImgIdx < renderingAttInfos.size() && renderingAttInfos.at(colorImgIdx).imageView != VK_NULL_HANDLE);
938 
939         for (uint32_t layerIdx = 0u; layerIdx < m_params.layerCount; ++layerIdx)
940         {
941             const bool layerWritten = imgWritten && ((m_params.layerMask & (1 << layerIdx)) != 0u);
942             const auto layerDataPtr = dataPtr + colorLayerSize * layerIdx;
943             const tcu::ConstPixelBufferAccess layerAccess(colorTcuFormat, fbDim, layerDataPtr);
944             const tcu::UVec4 expectedColor =
945                 (layerWritten ?
946                      tcu::UVec4(layerIdx, 255u, static_cast<uint32_t>(colorImgIdx), 255u) // Needs to match frag shader.
947                      :
948                      tcu::UVec4(0u, 0u, 0u, 0u));
949             const std::string logImgName =
950                 "ColorAttachment" + std::to_string(colorImgIdx) + "-Layer" + std::to_string(layerIdx);
951             tcu::TextureLevel refLevel(colorTcuFormat, fbDim.x(), fbDim.y(), fbDim.z());
952             tcu::PixelBufferAccess refAccess = refLevel.getAccess();
953 
954             tcu::clear(refAccess, expectedColor);
955             if (!tcu::intThresholdCompare(log, logImgName.c_str(), "", refAccess, layerAccess, threshold,
956                                           tcu::COMPARE_LOG_EVERYTHING))
957                 failure = true;
958         }
959     }
960 
961     if (dsNeeded)
962     {
963         const bool depthWritten   = (m_params.depthPresent && m_params.depthDefined && m_params.depthValidHandle);
964         const bool stencilWritten = (m_params.stencilPresent && m_params.stencilDefined && m_params.stencilValidHandle);
965 
966         // Depth.
967         {
968             const auto dataPtr = reinterpret_cast<const char *>(depthVerificationBuffer->getAllocation().getHostPtr());
969             const auto depthPixelSize = tcu::getPixelSize(depthCopyFormat);
970             const auto depthLayerSize = static_cast<size_t>(fbDim.x() * fbDim.y() * fbDim.z() * depthPixelSize);
971             const auto depthThreshold = 0.0f; // We expect exact results.
972 
973             for (uint32_t layerIdx = 0u; layerIdx < m_params.layerCount; ++layerIdx)
974             {
975                 const bool layerWritten = depthWritten && ((m_params.layerMask & (1 << layerIdx)) != 0u);
976                 const auto layerDataPtr = dataPtr + depthLayerSize * layerIdx;
977                 const tcu::ConstPixelBufferAccess layerAccess(depthCopyFormat, fbDim, layerDataPtr);
978                 const float expectedDepth =
979                     (layerWritten ? 1.0f : 0.0f); // Needs to match the vertex shader and depth/stencil config.
980                 const std::string logImgName = "DepthAttachment-Layer" + std::to_string(layerIdx);
981                 tcu::TextureLevel refLevel(depthCopyFormat, fbDim.x(), fbDim.y(), fbDim.z());
982                 tcu::PixelBufferAccess refAccess = refLevel.getAccess();
983 
984                 tcu::clearDepth(refAccess, expectedDepth);
985                 if (!tcu::dsThresholdCompare(log, logImgName.c_str(), "", refAccess, layerAccess, depthThreshold,
986                                              tcu::COMPARE_LOG_ON_ERROR))
987                     failure = true;
988             }
989         }
990 
991         // Stencil.
992         {
993             const auto dataPtr =
994                 reinterpret_cast<const char *>(stencilVerificationBuffer->getAllocation().getHostPtr());
995             const auto stencilPixelSize = tcu::getPixelSize(stencilCopyFormat);
996             const auto stencilLayerSize = static_cast<size_t>(fbDim.x() * fbDim.y() * fbDim.z() * stencilPixelSize);
997             const auto stencilThreshold = 0.0f; // We expect exact results.
998 
999             for (uint32_t layerIdx = 0u; layerIdx < m_params.layerCount; ++layerIdx)
1000             {
1001                 const bool layerWritten = stencilWritten && ((m_params.layerMask & (1 << layerIdx)) != 0u);
1002                 const auto layerDataPtr = dataPtr + stencilLayerSize * layerIdx;
1003                 const tcu::ConstPixelBufferAccess layerAccess(stencilCopyFormat, fbDim, layerDataPtr);
1004                 const int expectedStencil    = (layerWritten ? 0xFF : 0); // Needs to match the stencil op config.
1005                 const std::string logImgName = "StencilAttachment-Layer" + std::to_string(layerIdx);
1006                 tcu::TextureLevel refLevel(stencilCopyFormat, fbDim.x(), fbDim.y(), fbDim.z());
1007                 tcu::PixelBufferAccess refAccess = refLevel.getAccess();
1008 
1009                 tcu::clearStencil(refAccess, expectedStencil);
1010                 if (!tcu::dsThresholdCompare(log, logImgName.c_str(), "", refAccess, layerAccess, stencilThreshold,
1011                                              tcu::COMPARE_LOG_ON_ERROR))
1012                     failure = true;
1013             }
1014         }
1015     }
1016 
1017     if (failure)
1018         return tcu::TestStatus::fail("Invalid value found in verification buffers; check log for details");
1019 
1020     return tcu::TestStatus::pass("Pass");
1021 }
1022 
1023 using GroupPtr = de::MovePtr<tcu::TestCaseGroup>;
1024 
1025 } // anonymous namespace
1026 
createDynamicRenderingUnusedAttachmentsTests(tcu::TestContext & testCtx,bool useSecondaries)1027 tcu::TestCaseGroup *createDynamicRenderingUnusedAttachmentsTests(tcu::TestContext &testCtx, bool useSecondaries)
1028 {
1029     // Tests for VK_EXT_dynamic_rendering_unused_attachments
1030     GroupPtr group(new tcu::TestCaseGroup(testCtx, "unused_attachments"));
1031 
1032     // Add a combination subgroup just in case we want to add more test cases later to another subgroup.
1033     // VK_EXT_dynamic_rendering_unused_attachments with different combinations
1034     GroupPtr combGroup(new tcu::TestCaseGroup(testCtx, "comb"));
1035     GroupPtr colorGroup(new tcu::TestCaseGroup(testCtx, "color"));
1036     GroupPtr dsGroup(new tcu::TestCaseGroup(testCtx, "depth_stencil"));
1037     GroupPtr badFmtGrp(new tcu::TestCaseGroup(testCtx, "bad_formats"));
1038     GroupPtr moreAttGrp(new tcu::TestCaseGroup(testCtx, "extra_att"));
1039 
1040     const uint32_t attachmentCounts[] = {
1041         1u,
1042         4u,
1043         8u,
1044     };
1045     const uint32_t layerCounts[] = {
1046         1u,
1047         4u,
1048     };
1049     const uint32_t masksToTest[] = {
1050         0xFFFFFFFFu,
1051         0x0u,
1052         0x55555555u,
1053         0xAAAAAAAAu,
1054     };
1055 
1056     {
1057         // Combinations of color attachment counts, no depth/stencil.
1058         for (const auto &pipeAtt : attachmentCounts)
1059             for (const auto &fragAtt : attachmentCounts)
1060             {
1061                 if (fragAtt < pipeAtt)
1062                     continue;
1063 
1064                 for (const auto &layerCount : layerCounts)
1065                     for (const auto &layerMask : masksToTest)
1066                     {
1067                         // Avoid duplicate cases.
1068                         if (layerCount == 1u && layerMask != masksToTest[0] && layerMask != masksToTest[1])
1069                             continue;
1070 
1071                         for (const auto &formatMask : masksToTest)
1072                             for (const auto &handleMask : masksToTest)
1073                             {
1074                                 for (const auto multiview : {false, true})
1075                                 {
1076                                     const auto viewMask = (((1u << layerCount) - 1u) & layerMask);
1077 
1078                                     if (multiview && viewMask == 0u)
1079                                         continue;
1080 
1081                                     const TestParams params(pipeAtt, fragAtt, layerCount, viewMask, multiview,
1082                                                             formatMask, handleMask, false, false, false, false, false,
1083                                                             false, useSecondaries, false, false);
1084                                     colorGroup->addChild(
1085                                         new DynamicUnusedAttachmentsCase(testCtx, params.getTestName(), params));
1086                                 }
1087                             }
1088                     }
1089             }
1090 
1091         // Combinations of depth/stencil parameters, single color attachment.
1092         for (const auto depthPresent : {false, true})
1093             for (const auto depthDefined : {false, true})
1094                 for (const auto depthValidHandle : {false, true})
1095                 {
1096                     if (!depthPresent && (depthDefined || depthValidHandle))
1097                         continue;
1098 
1099                     for (const auto stencilPresent : {false, true})
1100                         for (const auto stencilDefined : {false, true})
1101                             for (const auto stencilValidHandle : {false, true})
1102                             {
1103                                 if (!stencilPresent && (stencilDefined || stencilValidHandle))
1104                                     continue;
1105 
1106                                 // Either both or none according to VUID-VkRenderingInfo-pDepthAttachment-06085
1107                                 if (depthValidHandle != stencilValidHandle)
1108                                     continue;
1109 
1110                                 // So far there is no VU that prevents only one of the depth/stencil formats from being
1111                                 // VK_FORMAT_UNDEFINED while the other one is not. However, that would mean disabling the
1112                                 // depth/stencil test (or at least make that aspect read-only, it's not clear) through a second
1113                                 // mechanism in the pipeline configuration.
1114                                 //
1115                                 // We can still test the VK_NULL_HANDLE/VK_FORMAT_UNDEFINED inconsistency, just not separately for
1116                                 // depth and stencil, which is one of the focus of these tests.
1117                                 if (depthDefined != stencilDefined)
1118                                     continue;
1119 
1120                                 for (const auto &layerCount : layerCounts)
1121                                     for (const auto &layerMask : masksToTest)
1122                                     {
1123                                         // Avoid duplicate cases.
1124                                         if (layerCount == 1u && layerMask != masksToTest[0] &&
1125                                             layerMask != masksToTest[1])
1126                                             continue;
1127 
1128                                         for (const auto multiview : {false, true})
1129                                         {
1130                                             const auto viewMask = (((1u << layerCount) - 1u) & layerMask);
1131 
1132                                             if (multiview && viewMask == 0u)
1133                                                 continue;
1134 
1135                                             const TestParams params(
1136                                                 1u, 1u, layerCount, viewMask, multiview, 0xFFFFFFFFu, 0xFFFFFFFFu,
1137                                                 depthPresent, depthDefined, depthValidHandle, stencilPresent,
1138                                                 stencilDefined, stencilValidHandle, useSecondaries, false, false);
1139                                             dsGroup->addChild(new DynamicUnusedAttachmentsCase(
1140                                                 testCtx, params.getTestName(), params));
1141                                         }
1142                                     }
1143                             }
1144                 }
1145 
1146         combGroup->addChild(colorGroup.release());
1147         combGroup->addChild(dsGroup.release());
1148     }
1149     group->addChild(combGroup.release());
1150 
1151     // Bad format tests.
1152     {
1153         for (const auto &formatMask : masksToTest)
1154             for (const auto &handleMask : masksToTest)
1155             {
1156                 if (handleMask == 0xFFFFFFFFu || formatMask == handleMask)
1157                     continue;
1158 
1159                 const TestParams params(4u, 4u, 1u, 1u, false, formatMask, handleMask, true, true, false, true, true,
1160                                         false, useSecondaries, true, false);
1161                 badFmtGrp->addChild(new DynamicUnusedAttachmentsCase(testCtx, params.getTestName(), params));
1162             }
1163     }
1164     group->addChild(badFmtGrp.release());
1165 
1166     // Extra attachments tests.
1167     {
1168         for (const auto &attCount : attachmentCounts)
1169             for (const auto &formatMask : masksToTest)
1170                 for (const auto &handleMask : masksToTest)
1171                 {
1172                     if (handleMask == 0xFFFFFFFFu || formatMask == handleMask)
1173                         continue;
1174 
1175                     const TestParams params(attCount, attCount, 1u, 1u, false, formatMask, handleMask, false, false,
1176                                             false, false, false, false, useSecondaries, false, true);
1177                     moreAttGrp->addChild(new DynamicUnusedAttachmentsCase(testCtx, params.getTestName(), params));
1178                 }
1179     }
1180     group->addChild(moreAttGrp.release());
1181 
1182     return group.release();
1183 }
1184 
1185 } // namespace renderpass
1186 } // namespace vkt
1187