• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2021 The Khronos Group Inc.
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *	  http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief  Vulkan SC pipeline cache tests
22 *//*--------------------------------------------------------------------*/
23 
24 #include "vktPipelineCacheSCTests.hpp"
25 
26 #include <set>
27 #include <vector>
28 #include <string>
29 
30 #include "vktTestCaseUtil.hpp"
31 #include "vktCustomInstancesDevices.hpp"
32 #include "vkDefs.hpp"
33 #include "vkDeviceUtil.hpp"
34 #include "vkQueryUtil.hpp"
35 #include "vkRefUtil.hpp"
36 #include "vkSafetyCriticalUtil.hpp"
37 #include "tcuTestLog.hpp"
38 
39 namespace vkt
40 {
41 namespace sc
42 {
43 
44 using namespace vk;
45 
46 namespace
47 {
48 
49 enum PipelineCacheTestType
50 {
51 	PCTT_UNUSED = 0,
52 	PCTT_WRONG_VENDOR_ID,
53 	PCTT_WRONG_DEVICE_ID
54 };
55 
56 struct TestParams
57 {
58 	PipelineCacheTestType	type;
59 };
60 
createShaders(SourceCollections & dst,TestParams params)61 void createShaders (SourceCollections& dst, TestParams params)
62 {
63 	DE_UNREF(params);
64 
65 	{
66 		std::ostringstream name, code;
67 		name << "vertex";
68 		code <<
69 			"#version 450\n"
70 			"\n"
71 			"void main (void)\n"
72 			"{\n"
73 			"   gl_Position = vec4( 1.0 );\n"
74 			"}\n";
75 		dst.glslSources.add(name.str()) << glu::VertexSource(code.str());
76 	}
77 
78 	{
79 		std::ostringstream name, code;
80 		name << "fragment";
81 		code <<
82 			"#version 450\n"
83 			"\n"
84 			"layout(location=0) out vec4 x;\n"
85 			"void main (void)\n"
86 			"{\n"
87 			"   x = vec4( 1.0 );\n"
88 			"}\n";
89 		dst.glslSources.add(name.str()) << glu::FragmentSource(code.str());
90 	}
91 
92 	{
93 		std::ostringstream name, code;
94 		name << "compute";
95 		code <<
96 			"#version 450\n"
97 			"layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
98 			"void main (void)\n"
99 			"{\n"
100 			"	uvec4 x = uvec4( 1 );\n"
101 			"}\n";
102 		dst.glslSources.add(name.str()) << glu::ComputeSource(code.str());
103 	}
104 }
105 
createPipelineCacheTest(Context & context,TestParams testParams)106 tcu::TestStatus createPipelineCacheTest (Context& context, TestParams testParams)
107 {
108 	const vk::PlatformInterface&							vkp							= context.getPlatformInterface();
109 	const CustomInstance									instance					(createCustomInstanceFromContext(context));
110 	const InstanceDriver&									instanceDriver				(instance.getDriver());
111 	const VkPhysicalDevice									physicalDevice				= chooseDevice(instanceDriver, instance, context.getTestContext().getCommandLine());
112 
113 	std::string												graphicsPID					= "PCST_GRAPHICS";
114 	std::string												computePID					= "PCST_COMPUTE";
115 
116 	// In main process : prepare one graphics pipeline and one compute pipeline
117 	// Actually these pipelines are here only to ensure that pipeline cache is not empty. We don't use them in subprocess
118 	if (!context.getTestContext().getCommandLine().isSubProcess())
119 	{
120 		const DeviceInterface&								vk							= context.getDeviceInterface();
121 		const VkDevice										device						= context.getDevice();
122 
123 		// graphics pipeline
124 		{
125 			Move<VkShaderModule>							vertexShader				= createShaderModule(vk, device, context.getBinaryCollection().get("vertex"), 0);
126 			Move<VkShaderModule>							fragmentShader				= createShaderModule(vk, device, context.getBinaryCollection().get("fragment"), 0);
127 
128 			std::vector<VkPipelineShaderStageCreateInfo>	shaderStageCreateInfos;
129 			shaderStageCreateInfos.push_back
130 			(
131 				{
132 					VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,				// VkStructureType                     sType;
133 					DE_NULL,															// const void*                         pNext;
134 					(VkPipelineShaderStageCreateFlags)0,								// VkPipelineShaderStageCreateFlags    flags;
135 					VK_SHADER_STAGE_VERTEX_BIT,											// VkShaderStageFlagBits               stage;
136 					*vertexShader,														// VkShaderModule                      shader;
137 					"main",																// const char*                         pName;
138 					DE_NULL,															// const VkSpecializationInfo*         pSpecializationInfo;
139 				}
140 			);
141 			shaderStageCreateInfos.push_back
142 			(
143 				{
144 					VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,				// VkStructureType                     sType;
145 					DE_NULL,															// const void*                         pNext;
146 					(VkPipelineShaderStageCreateFlags)0,								// VkPipelineShaderStageCreateFlags    flags;
147 					VK_SHADER_STAGE_FRAGMENT_BIT,										// VkShaderStageFlagBits               stage;
148 					*fragmentShader,													// VkShaderModule                      shader;
149 					"main",																// const char*                         pName;
150 					DE_NULL,															// const VkSpecializationInfo*         pSpecializationInfo;
151 				}
152 			);
153 
154 			VkPipelineVertexInputStateCreateInfo			vertexInputStateCreateInfo;
155 			VkPipelineInputAssemblyStateCreateInfo			inputAssemblyStateCreateInfo;
156 			VkPipelineViewportStateCreateInfo				viewPortStateCreateInfo;
157 			VkPipelineRasterizationStateCreateInfo			rasterizationStateCreateInfo;
158 			VkPipelineMultisampleStateCreateInfo			multisampleStateCreateInfo;
159 			VkPipelineColorBlendAttachmentState				colorBlendAttachmentState;
160 			VkPipelineColorBlendStateCreateInfo				colorBlendStateCreateInfo;
161 			VkPipelineDynamicStateCreateInfo				dynamicStateCreateInfo;
162 			std::vector<VkDynamicState>						dynamicStates{ VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR };
163 
164 			const VkPipelineLayoutCreateInfo				pipelineLayoutCreateInfo	=
165 			{
166 				VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,							// VkStructureType                     sType;
167 				DE_NULL,																// const void*                         pNext;
168 				(VkPipelineLayoutCreateFlags)0u,										// VkPipelineLayoutCreateFlags         flags;
169 				0u,																		// deUint32                            setLayoutCount;
170 				DE_NULL,																// const VkDescriptorSetLayout*        pSetLayouts;
171 				0u,																		// deUint32                            pushConstantRangeCount;
172 				DE_NULL																	// const VkPushConstantRange*          pPushConstantRanges;
173 			};
174 			Move<VkPipelineLayout>							pipelineLayout				= createPipelineLayout(vk, device, &pipelineLayoutCreateInfo);
175 
176 			const VkFormat									format						= getRenderTargetFormat(instanceDriver, physicalDevice);
177 
178 			VkAttachmentDescription							attachmentDescription;
179 			VkAttachmentReference							attachmentReference;
180 			VkSubpassDescription							subpassDescription;
181 			VkRenderPassCreateInfo							renderPassCreateInfo		= prepareSimpleRenderPassCI(format, attachmentDescription, attachmentReference, subpassDescription);
182 			Move<VkRenderPass>								renderPass					= createRenderPass(vk, device, &renderPassCreateInfo);
183 
184 			VkGraphicsPipelineCreateInfo					graphicsPipelineCreateInfo	= prepareSimpleGraphicsPipelineCI(vertexInputStateCreateInfo, shaderStageCreateInfos, inputAssemblyStateCreateInfo, viewPortStateCreateInfo,
185 					rasterizationStateCreateInfo, multisampleStateCreateInfo, colorBlendAttachmentState, colorBlendStateCreateInfo, dynamicStateCreateInfo, dynamicStates, *pipelineLayout, *renderPass);
186 
187 			// connect pipeline identifier
188 			VkPipelineOfflineCreateInfo						pipelineID					= resetPipelineOfflineCreateInfo();
189 			applyPipelineIdentifier(pipelineID, graphicsPID);
190 			pipelineID.pNext															= graphicsPipelineCreateInfo.pNext;
191 			graphicsPipelineCreateInfo.pNext											= &pipelineID;
192 
193 			// creation of a pipeline in main process registers it in pipeline cache
194 			Move<VkPipeline>								graphicsPipeline			= createGraphicsPipeline(vk, device, DE_NULL, &graphicsPipelineCreateInfo);
195 		}
196 
197 		// compute pipeline
198 		{
199 			Move<VkShaderModule>							computeShader				= createShaderModule(vk, device, context.getBinaryCollection().get("compute"), 0);
200 			VkPipelineShaderStageCreateInfo					shaderStageCreateInfo		=
201 			{
202 				VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,					// VkStructureType                     sType;
203 				DE_NULL,																// const void*                         pNext;
204 				(VkPipelineShaderStageCreateFlags)0,									// VkPipelineShaderStageCreateFlags    flags;
205 				VK_SHADER_STAGE_COMPUTE_BIT,											// VkShaderStageFlagBits               stage;
206 				*computeShader,															// VkShaderModule                      shader;
207 				"main",																	// const char*                         pName;
208 				DE_NULL,																// const VkSpecializationInfo*         pSpecializationInfo;
209 			};
210 
211 			const VkPipelineLayoutCreateInfo				pipelineLayoutCreateInfo	=
212 			{
213 				VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,							// VkStructureType                     sType;
214 				DE_NULL,																// const void*                         pNext;
215 				(VkPipelineLayoutCreateFlags)0u,										// VkPipelineLayoutCreateFlags         flags;
216 				0u,																		// deUint32                            setLayoutCount;
217 				DE_NULL,																// const VkDescriptorSetLayout*        pSetLayouts;
218 				0u,																		// deUint32                            pushConstantRangeCount;
219 				DE_NULL																	// const VkPushConstantRange*          pPushConstantRanges;
220 			};
221 			Move<VkPipelineLayout>							pipelineLayout				= createPipelineLayout(vk, device, &pipelineLayoutCreateInfo);
222 
223 			VkComputePipelineCreateInfo						computePipelineCreateInfo	= prepareSimpleComputePipelineCI(shaderStageCreateInfo, *pipelineLayout);
224 
225 			// connect pipeline identifier
226 			VkPipelineOfflineCreateInfo						pipelineID					= resetPipelineOfflineCreateInfo();
227 			applyPipelineIdentifier(pipelineID, computePID);
228 			pipelineID.pNext															= computePipelineCreateInfo.pNext;
229 			computePipelineCreateInfo.pNext												= &pipelineID;
230 
231 			// creation of a pipeline in main process registers it in pipeline cache
232 			Move<VkPipeline>								computePipeline				= createComputePipeline(vk, device, DE_NULL, &computePipelineCreateInfo);
233 		}
234 		return tcu::TestStatus::pass("Pass");
235 	}
236 
237 	// Subprocess : prepare pipeline cache data according to test type
238 	// Copy data from ResourceInterface
239 	std::vector<deUint8>									customCacheData				(context.getResourceInterface()->getCacheDataSize());
240 	deMemcpy(customCacheData.data(), context.getResourceInterface()->getCacheData(), context.getResourceInterface()->getCacheDataSize());
241 	deUintptr												initialDataSize				= customCacheData.size();
242 	VkPipelineCacheHeaderVersionSafetyCriticalOne*			pcHeader					= (VkPipelineCacheHeaderVersionSafetyCriticalOne*)customCacheData.data();
243 
244 	switch (testParams.type)
245 	{
246 		case PCTT_WRONG_VENDOR_ID:
247 		{
248 			pcHeader->headerVersionOne.vendorID = deUint32(VK_VENDOR_ID_MAX_ENUM);
249 			break;
250 		}
251 		case PCTT_WRONG_DEVICE_ID:
252 		{
253 			pcHeader->headerVersionOne.deviceID = 0xFFFFFFFF;
254 			break;
255 		}
256 		default:
257 			TCU_THROW(InternalError, "Unrecognized test type");
258 	}
259 
260 	// Now, create custom device
261 	const float												queuePriority				= 1.0f;
262 
263 	const VkDeviceQueueCreateInfo							deviceQueueCI				=
264 	{
265 		VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,										// sType
266 		DE_NULL,																		// pNext
267 		(VkDeviceQueueCreateFlags)0u,													// flags
268 		0,																				//queueFamilyIndex;
269 		1,																				//queueCount;
270 		&queuePriority,																	//pQueuePriorities;
271 	};
272 
273 	VkDeviceCreateInfo										deviceCreateInfo			=
274 	{
275 		VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,											// sType;
276 		DE_NULL,																		// pNext;
277 		(VkDeviceCreateFlags)0u,														// flags
278 		1,																				// queueRecordCount;
279 		&deviceQueueCI,																	// pRequestedQueues;
280 		0,																				// layerCount;
281 		DE_NULL,																		// ppEnabledLayerNames;
282 		0,																				// extensionCount;
283 		DE_NULL,																		// ppEnabledExtensionNames;
284 		DE_NULL,																		// pEnabledFeatures;
285 	};
286 
287 	VkDeviceObjectReservationCreateInfo						objectInfo					= resetDeviceObjectReservationCreateInfo();
288 	objectInfo.pNext																	= DE_NULL;
289 	objectInfo.pipelineLayoutRequestCount												= 2u;
290 	objectInfo.renderPassRequestCount													= 1u;
291 	objectInfo.subpassDescriptionRequestCount											= 1u;
292 	objectInfo.attachmentDescriptionRequestCount										= 1u;
293 	objectInfo.graphicsPipelineRequestCount												= 1u;
294 	objectInfo.computePipelineRequestCount												= 1u;
295 	objectInfo.pipelineCacheRequestCount												= 2u;
296 
297 	VkPipelineCacheCreateInfo								pipelineCacheCreateInfo		=
298 	{
299 		VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO,									// VkStructureType				sType;
300 		DE_NULL,																		// const void*					pNext;
301 		VK_PIPELINE_CACHE_CREATE_READ_ONLY_BIT |
302 			VK_PIPELINE_CACHE_CREATE_USE_APPLICATION_STORAGE_BIT,						// VkPipelineCacheCreateFlags	flags;
303 		initialDataSize,																// deUintptr					initialDataSize;
304 		customCacheData.data()															// const void*					pInitialData;
305 	};
306 	objectInfo.pipelineCacheCreateInfoCount												= 1u;
307 	objectInfo.pPipelineCacheCreateInfos												= &pipelineCacheCreateInfo;
308 
309 	std::vector<VkPipelinePoolSize>							poolSizes					= context.getResourceInterface()->getPipelinePoolSizes();
310 	if (!poolSizes.empty())
311 	{
312 		objectInfo.pipelinePoolSizeCount												= deUint32(poolSizes.size());
313 		objectInfo.pPipelinePoolSizes													= poolSizes.data();
314 	}
315 	void* pNext																			= &objectInfo;
316 
317 	VkPhysicalDeviceVulkanSC10Features						sc10Features				= createDefaultSC10Features();
318 	sc10Features.pNext																	= pNext;
319 	pNext																				= &sc10Features;
320 
321 	deviceCreateInfo.pNext																= pNext;
322 
323 	tcu::TestStatus											testStatus					= tcu::TestStatus::pass("Pass");
324 	Move<VkDevice>											device;
325 	{
326 		std::vector<const char*>								enabledLayers;
327 
328 		if (deviceCreateInfo.enabledLayerCount == 0u && context.getTestContext().getCommandLine().isValidationEnabled())
329 		{
330 			enabledLayers							= getValidationLayers(instanceDriver, physicalDevice);
331 			deviceCreateInfo.enabledLayerCount		= static_cast<deUint32>(enabledLayers.size());
332 			deviceCreateInfo.ppEnabledLayerNames	= (enabledLayers.empty() ? DE_NULL : enabledLayers.data());
333 		}
334 		VkDevice		object	= 0;
335 		VkResult		result	= instanceDriver.createDevice(physicalDevice, &deviceCreateInfo, DE_NULL, &object);
336 		switch (testParams.type)
337 		{
338 			case PCTT_WRONG_VENDOR_ID:
339 			case PCTT_WRONG_DEVICE_ID:
340 				if (result != VK_ERROR_INVALID_PIPELINE_CACHE_DATA)
341 					testStatus = tcu::TestStatus::fail("Fail");
342 				break;
343 			default:
344 				TCU_THROW(InternalError, "Unrecognized test type");
345 		}
346 		if (result != VK_SUCCESS)
347 			return testStatus;
348 		device					=  Move<VkDevice>(check<VkDevice>(object), Deleter<VkDevice>(vkp, instance, object, DE_NULL));
349 	}
350 
351 	// create our own pipeline cache in subprocess. Use VK functions directly
352 	GetDeviceProcAddrFunc									getDeviceProcAddrFunc		= (GetDeviceProcAddrFunc)vkp.getInstanceProcAddr(instance, "vkGetDeviceProcAddr");
353 	CreatePipelineCacheFunc									createPipelineCacheFunc		= (CreatePipelineCacheFunc)getDeviceProcAddrFunc(*device, "vkCreatePipelineCache");
354 	DestroyPipelineCacheFunc								destroyPipelineCacheFunc	= (DestroyPipelineCacheFunc)getDeviceProcAddrFunc(*device, "vkDestroyPipelineCache");
355 
356 	VkPipelineCache											pipelineCache;
357 	VkResult												result						= createPipelineCacheFunc(*device, &pipelineCacheCreateInfo, DE_NULL, &pipelineCache);
358 
359 	switch (testParams.type)
360 	{
361 		case PCTT_WRONG_VENDOR_ID:
362 		case PCTT_WRONG_DEVICE_ID:
363 			if (result != VK_ERROR_INVALID_PIPELINE_CACHE_DATA)
364 				testStatus = tcu::TestStatus::fail("Fail");
365 			break;
366 		default:
367 			TCU_THROW(InternalError, "Unrecognized test type");
368 	}
369 
370 	if (result == VK_SUCCESS)
371 		destroyPipelineCacheFunc(*device, pipelineCache, DE_NULL);
372 
373 	return testStatus;
374 }
375 
376 } // anonymous
377 
createPipelineCacheTests(tcu::TestContext & testCtx)378 tcu::TestCaseGroup*	createPipelineCacheTests (tcu::TestContext& testCtx)
379 {
380 	de::MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(testCtx, "pipeline_cache", "Tests verifying Vulkan SC pipeline cache"));
381 
382 	const struct
383 	{
384 		PipelineCacheTestType						testType;
385 		const char*									name;
386 	} tests[] =
387 	{
388 		{ PCTT_WRONG_VENDOR_ID,	"incorrect_vendor_id"		},
389 		{ PCTT_WRONG_DEVICE_ID,	"incorrect_device_id"		},
390 	};
391 
392 	for (int testIdx = 0; testIdx < DE_LENGTH_OF_ARRAY(tests); ++testIdx)
393 	{
394 		TestParams params{ tests[testIdx].testType };
395 		addFunctionCaseWithPrograms(group.get(), tests[testIdx].name, "", createShaders, createPipelineCacheTest, params);
396 	}
397 
398 	return group.release();
399 }
400 
401 }	// sc
402 
403 }	// vkt
404