1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2018 The Khronos Group Inc.
6  * Copyright (c) 2018 Google Inc.
7  * Copyright (c) 2023 LunarG, Inc.
8  * Copyright (c) 2023 Nintendo
9  *
10  * Licensed under the Apache License, Version 2.0 (the "License");
11  * you may not use this file except in compliance with the License.
12  * You may obtain a copy of the License at
13  *
14  *      http://www.apache.org/licenses/LICENSE-2.0
15  *
16  * Unless required by applicable law or agreed to in writing, software
17  * distributed under the License is distributed on an "AS IS" BASIS,
18  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19  * See the License for the specific language governing permissions and
20  * limitations under the License.
21  *
22  *//*!
23  * \file
24  * \brief Early pipeline destroying tests
25  *//*--------------------------------------------------------------------*/
26 
27 #include "vktPipelineEarlyDestroyTests.hpp"
28 #include "vktTestCase.hpp"
29 #include "vktTestCaseUtil.hpp"
30 #include "vktTestGroupUtil.hpp"
31 #include "vkMemUtil.hpp"
32 #include "vkPrograms.hpp"
33 #include "vkRefUtil.hpp"
34 #include "vkObjUtil.hpp"
35 #include "deUniquePtr.hpp"
36 #include "tcuTexture.hpp"
37 #include "vkImageUtil.hpp"
38 #include "vkImageWithMemory.hpp"
39 #include "vkBufferWithMemory.hpp"
40 #include "vkCmdUtil.hpp"
41 
42 namespace vkt
43 {
44 namespace pipeline
45 {
46 
47 using namespace vk;
48 
49 namespace
50 {
51 
52 struct TestParams
53 {
54 	PipelineConstructionType	pipelineConstructionType;
55 	bool						usePipelineCache;
56 	bool						useMaintenance5;
57 };
58 
checkSupport(Context& context, TestParams testParams)59 void checkSupport(Context& context, TestParams testParams)
60 {
61 	if (testParams.useMaintenance5)
62 		context.requireDeviceFunctionality("VK_KHR_maintenance5");
63 
64 	checkPipelineConstructionRequirements(context.getInstanceInterface(), context.getPhysicalDevice(), testParams.pipelineConstructionType);
65 }
66 
initPrograms(SourceCollections& programCollection, TestParams testParams)67 void initPrograms (SourceCollections& programCollection, TestParams testParams)
68 {
69 	DE_UNREF(testParams.usePipelineCache);
70 
71 	programCollection.glslSources.add("color_vert") << glu::VertexSource(
72 		"#version 450\n"
73 		"vec2 vertices[3];\n"
74 		"\n"
75 		"void main()\n"
76 		"{\n"
77 		"   vertices[0] = vec2(-1.0, -1.0);\n"
78 		"   vertices[1] = vec2( 1.0, -1.0);\n"
79 		"   vertices[2] = vec2( 0.0,  1.0);\n"
80 		"   gl_Position = vec4(vertices[gl_VertexIndex % 3], 0.0, 1.0);\n"
81 		"}\n");
82 
83 	programCollection.glslSources.add("color_frag") << glu::FragmentSource(
84 		"#version 450\n"
85 		"\n"
86 		"layout(location = 0) out vec4 uFragColor;\n"
87 		"\n"
88 		"void main()\n"
89 		"{\n"
90 		"   uFragColor = vec4(0,1,0,1);\n"
91 		"}\n");
92 }
93 
testEarlyDestroy(Context& context, const TestParams& params, bool destroyLayout)94 tcu::TestStatus testEarlyDestroy (Context& context, const TestParams& params, bool destroyLayout)
95 {
96 	const InstanceInterface&							vki								= context.getInstanceInterface();
97 	const DeviceInterface&								vk								= context.getDeviceInterface();
98 	const VkPhysicalDevice								physicalDevice					= context.getPhysicalDevice();
99 	const VkDevice										vkDevice						= context.getDevice();
100 	const ShaderWrapper									vertexShaderModule				(ShaderWrapper(vk, vkDevice, context.getBinaryCollection().get("color_vert"), 0));
101 
102 	const Unique<VkCommandPool>							cmdPool							(createCommandPool(vk, vkDevice, VK_COMMAND_POOL_CREATE_TRANSIENT_BIT | VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, context.getUniversalQueueFamilyIndex()));
103 	const Unique<VkCommandBuffer>						cmdBuffer						(allocateCommandBuffer(vk, vkDevice, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
104 
105 	const VkPipelineLayoutCreateInfo					pipelineLayoutCreateInfo		=
106 	{
107 		VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,									// VkStructureType					sType;
108 		DE_NULL,																		// const void*						pNext;
109 		0u,																				// VkPipelineLayoutCreateFlags		flags;
110 		0u,																				// deUint32							setLayoutCount;
111 		DE_NULL,																		// const VkDescriptorSetLayout*		pSetLayouts;
112 		0u,																				// deUint32							pushConstantRangeCount;
113 		DE_NULL																			// const VkPushConstantRange*		pPushConstantRanges;
114 	};
115 
116 	// Multiple passes for destroy layout in order to increase the chance of crashing if some resource/state gets carried over from previous iterations.
117 	int numTests = destroyLayout ? 3 : 1;
118 	for(int i = 0; i < numTests; ++i)
119 	{
120 		PipelineLayoutWrapper							pipelineLayout					(params.pipelineConstructionType, vk, vkDevice, &pipelineLayoutCreateInfo, DE_NULL);
121 		RenderPassWrapper								renderPass						(params.pipelineConstructionType, vk, vkDevice, VK_FORMAT_R8G8B8A8_UNORM);
122 		const VkPipelineVertexInputStateCreateInfo		vertexInputStateCreateInfo		=
123 		{
124 			VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,					// VkStructureType							sType;
125 			DE_NULL,																	// const void*								pNext;
126 			0u,																			// VkPipelineVertexInputStateCreateFlags	flags;
127 			0u,																			// deUint32									vertexBindingDescriptionCount;
128 			DE_NULL,																	// const VkVertexInputBindingDescription*	pVertexBindingDescriptions;
129 			0u,																			// deUint32									vertexAttributeDescriptionCount;
130 			DE_NULL																		// const VkVertexInputAttributeDescription*	pVertexAttributeDescriptions;
131 		};
132 		const VkPipelineInputAssemblyStateCreateInfo	inputAssemblyStateCreateInfo	=
133 		{
134 			VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,				// VkStructureType							sType;
135 			DE_NULL,																	// const void*								pNext;
136 			0u,																			// VkPipelineInputAssemblyStateCreateFlags	flags;
137 			VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP,										// VkPrimitiveTopology						topology;
138 			VK_FALSE																	// VkBool32									primitiveRestartEnable;
139 		};
140 		const VkPipelineRasterizationStateCreateInfo	rasterizationStateCreateInfo	=
141 		{
142 			VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,					// VkStructureType							sType;
143 			DE_NULL,																	// const void*								pNext;
144 			0u,																			// VkPipelineRasterizationStateCreateFlags	flags;
145 			VK_FALSE,																	// VkBool32									depthClampEnable;
146 			VK_TRUE,																	// VkBool32									rasterizerDiscardEnable;
147 			VK_POLYGON_MODE_FILL,														// VkPolygonMode							polygonMode;
148 			VK_CULL_MODE_BACK_BIT,														// VkCullModeFlags							cullMode;
149 			VK_FRONT_FACE_CLOCKWISE,													// VkFrontFace								frontFace;
150 			VK_FALSE,																	// VkBool32									depthBiasEnable;
151 			0.0f,																		// float									depthBiasConstantFactor;
152 			0.0f,																		// float									depthBiasClamp;
153 			0.0f,																		// float									depthBiasSlopeFactor;
154 			1.0f																		// float									lineWidth;
155 		};
156 		const VkPipelineColorBlendAttachmentState		colorBlendAttachmentState		=
157 		{
158 			VK_FALSE,																	// VkBool32					blendEnable;
159 			VK_BLEND_FACTOR_ZERO,														// VkBlendFactor			srcColorBlendFactor;
160 			VK_BLEND_FACTOR_ZERO,														// VkBlendFactor			dstColorBlendFactor;
161 			VK_BLEND_OP_ADD,															// VkBlendOp				colorBlendOp;
162 			VK_BLEND_FACTOR_ZERO,														// VkBlendFactor			srcAlphaBlendFactor;
163 			VK_BLEND_FACTOR_ZERO,														// VkBlendFactor			dstAlphaBlendFactor;
164 			VK_BLEND_OP_ADD,															// VkBlendOp				alphaBlendOp;
165 			0xf																			// VkColorComponentFlags	colorWriteMask;
166 		};
167 		const VkPipelineColorBlendStateCreateInfo		colorBlendStateCreateInfo		=
168 		{
169 			VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,					// VkStructureType								sType;
170 			DE_NULL,																	// const void*									pNext;
171 			0u,																			// VkPipelineColorBlendStateCreateFlags			flags;
172 			VK_FALSE,																	// VkBool32										logicOpEnable;
173 			VK_LOGIC_OP_CLEAR,															// VkLogicOp									logicOp;
174 			1u,																			// deUint32										attachmentCount;
175 			&colorBlendAttachmentState,													// const VkPipelineColorBlendAttachmentState*	pAttachments;
176 			{ 0.0f, 0.0f, 0.0f, 0.0f }													// float										blendConstants[4];
177 		};
178 		const VkPipelineCacheCreateInfo					pipelineCacheCreateInfo			=
179 		{
180 			VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO,								// VkStructureType				sType;
181 			DE_NULL,																	// const void*					pNext;
182 #ifndef CTS_USES_VULKANSC
183 			(VkPipelineCacheCreateFlags)0u,												// VkPipelineCacheCreateFlags	flags;
184 			0u,																			// size_t						initialDataSize;
185 			DE_NULL																		// const void*					pInitialData;
186 #else
187 			VK_PIPELINE_CACHE_CREATE_READ_ONLY_BIT |
188 				VK_PIPELINE_CACHE_CREATE_USE_APPLICATION_STORAGE_BIT,					// VkPipelineCacheCreateFlags	flags;
189 			context.getResourceInterface()->getCacheDataSize(),							// deUintptr					initialDataSize;
190 			context.getResourceInterface()->getCacheData()								// const void*					pInitialData;
191 #endif // CTS_USES_VULKANSC
192 		};
193 		const Unique<VkPipelineCache>					pipelineCache					(createPipelineCache(vk, vkDevice, &pipelineCacheCreateInfo));
194 
195 		const std::vector<VkViewport>					viewports						{};
196 		const std::vector<VkRect2D>						scissors						{};
197 		GraphicsPipelineWrapper							graphicsPipeline				(vki, vk, physicalDevice, vkDevice, context.getDeviceExtensions(), params.pipelineConstructionType, VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT);
198 
199 #ifndef CTS_USES_VULKANSC
200 		if (params.useMaintenance5)
201 			graphicsPipeline.setPipelineCreateFlags2(VK_PIPELINE_CREATE_2_DISABLE_OPTIMIZATION_BIT_KHR);
202 #endif // CTS_USES_VULKANSC
203 
204 		graphicsPipeline.disableViewportState()
205 						.setDefaultMultisampleState()
206 						.setDefaultDepthStencilState()
207 						.setupVertexInputState(&vertexInputStateCreateInfo, &inputAssemblyStateCreateInfo)
208 						.setupPreRasterizationShaderState(viewports,
209 														  scissors,
210 														  pipelineLayout,
211 														  *renderPass,
212 														  0u,
213 														  vertexShaderModule,
214 														  &rasterizationStateCreateInfo)
215 						// Uninitialized so the pipeline wrapper does not add fragment stage.
216 						// This avoids running into VUID-VkGraphicsPipelineCreateInfo-pStages-06894 due to enabled rasterizerDiscard
217 						.setupFragmentShaderState(pipelineLayout, *renderPass, 0u, vk::ShaderWrapper())
218 						.setupFragmentOutputState(*renderPass, 0u, &colorBlendStateCreateInfo)
219 						.setMonolithicPipelineLayout(pipelineLayout)
220 						.buildPipeline(params.usePipelineCache ? *pipelineCache : DE_NULL);
221 
222 		const deUint32 framebufferWidth													= 32;
223 		const deUint32 framebufferHeight												= 32;
224 		if (destroyLayout)
225 		{
226 			// This will destroy the pipelineLayout when going out of enclosing scope
227 			pipelineLayout.destroy();
228 		}
229 		const VkCommandBufferBeginInfo					cmdBufferBeginInfo				=
230 		{
231 			VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,								// VkStructureType							sType;
232 			DE_NULL,																	// const void*								pNext;
233 			0u,																			// VkCommandBufferUsageFlags				flags;
234 			(const VkCommandBufferInheritanceInfo*)DE_NULL								// const VkCommandBufferInheritanceInfo*	pInheritanceInfo;
235 		};
236 		if (!destroyLayout) {
237 			VK_CHECK(vk.beginCommandBuffer(*cmdBuffer, &cmdBufferBeginInfo));
238 			VK_CHECK(vk.endCommandBuffer(*cmdBuffer));
239 		} else {
240 			auto&										allocator						= context.getDefaultAllocator();
241 			const auto									queue							= context.getUniversalQueue();
242 			const VkFormat								attachmentFormat				= VK_FORMAT_R8G8B8A8_UNORM;
243 			const tcu::TextureFormat					textureFormat					= mapVkFormat(attachmentFormat);
244 			const VkDeviceSize							imageSize						= framebufferWidth * framebufferHeight * textureFormat.getPixelSize();
245 			const VkImageCreateInfo						imageCreateInfo					=
246 			{
247 				VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,									// VkStructureType			sType;
248 				DE_NULL,																// const void*				pNext;
249 				(VkImageCreateFlags)0,													// VkImageCreateFlags		flags;
250 				VK_IMAGE_TYPE_2D,														// VkImageType				imageType;
251 				attachmentFormat,														// VkFormat					format;
252 				{ framebufferWidth, framebufferHeight, 1u },							// VkExtent3D				extent;
253 				1u,																		// deUint32					mipLevels;
254 				1u,																		// deUint32					arrayLayers;
255 				VK_SAMPLE_COUNT_1_BIT,													// VkSampleCountFlagBits	samples;
256 				VK_IMAGE_TILING_OPTIMAL,												// VkImageTiling			tiling;
257 				VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
258 				VK_IMAGE_USAGE_TRANSFER_DST_BIT |
259 				VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,									// VkImageUsageFlags		usage;
260 				VK_SHARING_MODE_EXCLUSIVE,												// VkSharingMode			sharingMode;
261 				0u,																		// deUint32					queueFamilyIndexCount;
262 				DE_NULL,																// const deUint32*			pQueueFamilyIndices;
263 				VK_IMAGE_LAYOUT_UNDEFINED												// VkImageLayout			initialLayout;
264 			};
265 			const ImageWithMemory						attachmentImage					(vk, vkDevice, context.getDefaultAllocator(), imageCreateInfo, MemoryRequirement::Any);
266 			const VkImageSubresourceRange				colorSubresourceRange			= { VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u };
267 			const Unique<VkImageView>					attachmentImageView				(vk::makeImageView(vk, vkDevice, *attachmentImage, VK_IMAGE_VIEW_TYPE_2D, attachmentFormat, colorSubresourceRange));
268 			const VkBufferCreateInfo					imageBufferCreateInfo			= vk::makeBufferCreateInfo(imageSize, vk::VK_BUFFER_USAGE_TRANSFER_DST_BIT);
269 			const BufferWithMemory						imageBuffer						(vk, vkDevice, allocator, imageBufferCreateInfo, vk::MemoryRequirement::HostVisible);
270 			renderPass.createFramebuffer(vk, vkDevice, *attachmentImage, *attachmentImageView, framebufferWidth, framebufferHeight, 1u);
271 
272 			VK_CHECK(vk.beginCommandBuffer(*cmdBuffer, &cmdBufferBeginInfo));
273 			const tcu::Vec4								clearColor						= { 0.2f, 0.6f, 0.8f, 1.0f };
274 			VkClearValue								clearValue						=
275 			{
276 				{ { clearColor.x(), clearColor.y(),
277 					clearColor.z(), clearColor.w() } }									// float						float32[4];
278 			};
279 			VkClearAttachment								attachment						=
280 			{
281 				VK_IMAGE_ASPECT_COLOR_BIT,												// VkImageAspectFlags			aspectMask;
282 				0u,																		// deUint32						colorAttachment;
283 				clearValue																// VkClearValue					clearValue;
284 			};
285 			const VkRect2D								renderArea						= { { 0, 0 }, { framebufferWidth, framebufferHeight } };
286 			const VkClearRect								rect							=
287 			{
288 				renderArea,																// VkRect2D						rect
289 				0u,																		// uint32_t						baseArrayLayer
290 				1u																		// uint32_t						layerCount
291 			};
292 			renderPass.begin(vk, *cmdBuffer, renderArea, clearValue);
293 			vk.cmdClearAttachments(*cmdBuffer, 1, &attachment, 1, &rect);
294 			renderPass.end(vk, *cmdBuffer);
295 			vk::copyImageToBuffer(vk, *cmdBuffer, *attachmentImage, *imageBuffer, tcu::IVec2(framebufferWidth, framebufferHeight));
296 			VK_CHECK(vk.endCommandBuffer(*cmdBuffer));
297 
298 			vk::submitCommandsAndWait(vk, vkDevice, queue, *cmdBuffer);
299 			VK_CHECK(vk.resetCommandBuffer(*cmdBuffer, VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT));
300 			const auto&									imageBufferAlloc				= imageBuffer.getAllocation();
301 			vk::invalidateAlloc(vk, vkDevice, imageBufferAlloc);
302 
303 			const auto									imageBufferPtr					= reinterpret_cast<const char*>(imageBufferAlloc.getHostPtr()) + imageBufferAlloc.getOffset();
304 			const tcu::ConstPixelBufferAccess			imagePixels						(textureFormat, framebufferWidth, framebufferHeight, 1u, imageBufferPtr);
305 
306 #ifdef CTS_USES_VULKANSC
307 			if (context.getTestContext().getCommandLine().isSubProcess())
308 #endif // CTS_USES_VULKANSC
309 			{
310 				for (int z = 0; z < imagePixels.getDepth(); ++z)
311 				for (int y = 0; y < imagePixels.getHeight(); ++y)
312 				for (int x = 0; x < imagePixels.getWidth(); ++x)
313 				{
314 					const auto pixel = imagePixels.getPixel(x, y, z);
315 					if (pixel != clearColor) {
316 										std::ostringstream msg; msg << "Pixel value mismatch after framebuffer clear." << " diff: " << pixel << " vs " << clearColor;
317 
318 						return tcu::TestStatus::fail(msg.str()/*"Pixel value mismatch after framebuffer clear."*/);
319 					}
320 				}
321 			}
322 		}
323 	}
324 	// Passes as long as no crash occurred.
325 	return tcu::TestStatus::pass("Pass");
326 }
327 
testEarlyDestroyKeepLayout(Context& context, TestParams params)328 tcu::TestStatus testEarlyDestroyKeepLayout (Context& context, TestParams params)
329 {
330 	return testEarlyDestroy (context, params, false);
331 }
332 
testEarlyDestroyDestroyLayout(Context& context, TestParams params)333 tcu::TestStatus testEarlyDestroyDestroyLayout (Context& context, TestParams params)
334 {
335 	return testEarlyDestroy (context, params, true);
336 }
337 
addEarlyDestroyTestCasesWithFunctions(tcu::TestCaseGroup* group, PipelineConstructionType pipelineConstructionType)338 void addEarlyDestroyTestCasesWithFunctions (tcu::TestCaseGroup* group, PipelineConstructionType pipelineConstructionType)
339 {
340 	TestParams params
341 	{
342 		pipelineConstructionType,
343 		true,
344 		false,
345 	};
346 
347 	addFunctionCaseWithPrograms(group, "cache", checkSupport, initPrograms, testEarlyDestroyKeepLayout, params);
348 	params.usePipelineCache = false;
349 	addFunctionCaseWithPrograms(group, "no_cache", checkSupport, initPrograms, testEarlyDestroyKeepLayout, params);
350 	params.usePipelineCache = true;
351 	addFunctionCaseWithPrograms(group, "cache_destroy_layout", checkSupport, initPrograms, testEarlyDestroyDestroyLayout, params);
352 	params.usePipelineCache = false;
353 	addFunctionCaseWithPrograms(group, "no_cache_destroy_layout", checkSupport, initPrograms, testEarlyDestroyDestroyLayout, params);
354 	params.useMaintenance5 = true;
355 	addFunctionCaseWithPrograms(group, "no_cache_destroy_layout_maintenance5", checkSupport, initPrograms, testEarlyDestroyDestroyLayout, params);
356 }
357 
358 } // anonymous
359 
createEarlyDestroyTests(tcu::TestContext& testCtx, PipelineConstructionType pipelineConstructionType)360 tcu::TestCaseGroup* createEarlyDestroyTests (tcu::TestContext& testCtx, PipelineConstructionType pipelineConstructionType)
361 {
362 	return createTestGroup(testCtx, "early_destroy", addEarlyDestroyTestCasesWithFunctions, pipelineConstructionType);
363 }
364 
365 } // pipeline
366 } // vkt
367