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 ¶ms)
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 ¶ms)
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, ©Region);
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