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