• 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 identifier tests
22 *//*--------------------------------------------------------------------*/
23 
24 #include "vktPipelineIdentifierTests.hpp"
25 
26 #include <set>
27 #include <vector>
28 #include <string>
29 
30 #include "vktTestCaseUtil.hpp"
31 #include "vkDefs.hpp"
32 #include "vkSafetyCriticalUtil.hpp"
33 #include "vkQueryUtil.hpp"
34 #include "vkRefUtil.hpp"
35 #include "tcuTestLog.hpp"
36 
37 namespace vkt
38 {
39 namespace sc
40 {
41 
42 using namespace vk;
43 
44 namespace
45 {
46 
47 enum PIPipeline
48 {
49 	PIP_UNUSED = 0,
50 	PIP_GRAPHICS,
51 	PIP_COMPUTE
52 };
53 
54 enum PITTestType
55 {
56 	PITT_UNUSED = 0,
57 	PITT_MISSING_ID,
58 	PITT_NONEXISTING_ID,
59 	PITT_MATCHCONTROL
60 };
61 
62 enum PITMatchControl
63 {
64 	PIMC_UNUSED = 0,
65 	PIMC_UUID_EXACT_MATCH
66 };
67 
68 struct TestParams
69 {
70 	PITTestType				type;
71 	PITMatchControl			matchControl;
72 	bool					single;
73 };
74 
createGraphicsShaders(SourceCollections & dst,TestParams testParams)75 void createGraphicsShaders (SourceCollections& dst, TestParams testParams)
76 {
77 	deUint32	pipelineCount = testParams.single ? 1 : 3;
78 
79 	for (deUint32 i = 0; i < pipelineCount; ++i)
80 	{
81 		std::ostringstream name, code;
82 		name << "vertex_" << i;
83 		code <<
84 			"#version 450\n"
85 			"\n"
86 			"void main (void)\n"
87 			"{\n"
88 			"   gl_Position = vec4( "<< i <<");\n"
89 			"}\n";
90 		dst.glslSources.add(name.str()) << glu::VertexSource(code.str());
91 	}
92 
93 	for (deUint32 i = 0; i < pipelineCount; ++i)
94 	{
95 		std::ostringstream name, code;
96 		name << "fragment_" << i;
97 		code <<
98 			"#version 450\n"
99 			"\n"
100 			"layout(location=0) out vec4 x;\n"
101 			"void main (void)\n"
102 			"{\n"
103 			"   x = vec4(" << i <<");\n"
104 			"}\n";
105 			dst.glslSources.add(name.str()) << glu::FragmentSource(code.str());
106 	}
107 }
108 
createComputeShaders(SourceCollections & dst,TestParams testParams)109 void createComputeShaders (SourceCollections& dst, TestParams testParams)
110 {
111 	deUint32	pipelineCount = testParams.single ? 1 : 3;
112 
113 	for (deUint32 i = 0; i < pipelineCount; ++i)
114 	{
115 		std::ostringstream name, code;
116 		name << "compute_" << i;
117 		code <<
118 			"#version 450\n"
119 			"layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
120 			"void main (void)\n"
121 			"{\n"
122 			"	uvec4 x = uvec4(" << i <<");\n"
123 			"}\n";
124 
125 		dst.glslSources.add(name.str()) << glu::ComputeSource(code.str());
126 	}
127 }
128 
testGraphicsPipelineIdentifier(Context & context,TestParams testParams)129 tcu::TestStatus testGraphicsPipelineIdentifier (Context& context, TestParams testParams)
130 {
131 	const vk::PlatformInterface&							vkp								= context.getPlatformInterface();
132 	const InstanceInterface&								vki								= context.getInstanceInterface();
133 	const VkInstance										instance						= context.getInstance();
134 	const DeviceInterface&									vk								= context.getDeviceInterface();
135 	const VkDevice											device							= context.getDevice();
136 	const VkPhysicalDevice									physicalDevice					= context.getPhysicalDevice();
137 
138 	deUint32												pipelineCount					= testParams.single ? 1 : 3;
139 
140 	std::vector<Move<VkShaderModule>>						shaders;
141 	for (deUint32 i = 0; i < pipelineCount; ++i)
142 	{
143 		{
144 			std::ostringstream name;
145 			name << "vertex_" << i;
146 			shaders.emplace_back(createShaderModule(vk, device, context.getBinaryCollection().get(name.str()), 0));
147 		}
148 		{
149 			std::ostringstream name;
150 			name << "fragment_" << i;
151 			shaders.emplace_back(createShaderModule(vk, device, context.getBinaryCollection().get(name.str()), 0));
152 		}
153 	}
154 
155 	std::vector<std::vector<VkPipelineShaderStageCreateInfo>>	shaderStageCreateInfos	(pipelineCount);
156 	for (deUint32 i = 0; i < pipelineCount; ++i)
157 	{
158 		shaderStageCreateInfos[i].push_back
159 		(
160 			{
161 				VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,						// VkStructureType                     sType;
162 				DE_NULL,																	// const void*                         pNext;
163 				(VkPipelineShaderStageCreateFlags)0,										// VkPipelineShaderStageCreateFlags    flags;
164 				VK_SHADER_STAGE_VERTEX_BIT,													// VkShaderStageFlagBits               stage;
165 				*shaders[2*i],																// VkShaderModule                      shader;
166 				"main",																		// const char*                         pName;
167 				DE_NULL,																	// const VkSpecializationInfo*         pSpecializationInfo;
168 			}
169 		);
170 		shaderStageCreateInfos[i].push_back
171 		(
172 			{
173 				VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,						// VkStructureType                     sType;
174 				DE_NULL,																	// const void*                         pNext;
175 				(VkPipelineShaderStageCreateFlags)0,										// VkPipelineShaderStageCreateFlags    flags;
176 				VK_SHADER_STAGE_FRAGMENT_BIT,												// VkShaderStageFlagBits               stage;
177 				*shaders[2*i+1],															// VkShaderModule                      shader;
178 				"main",																		// const char*                         pName;
179 				DE_NULL,																	// const VkSpecializationInfo*         pSpecializationInfo;
180 			}
181 		);
182 	}
183 
184 	std::vector<VkPipelineVertexInputStateCreateInfo>		vertexInputStateCreateInfo		(pipelineCount);
185 	std::vector<VkPipelineInputAssemblyStateCreateInfo>		inputAssemblyStateCreateInfo	(pipelineCount);
186 	std::vector<VkPipelineViewportStateCreateInfo>			viewPortStateCreateInfo			(pipelineCount);
187 	std::vector<VkPipelineRasterizationStateCreateInfo>		rasterizationStateCreateInfo	(pipelineCount);
188 	std::vector<VkPipelineMultisampleStateCreateInfo>		multisampleStateCreateInfo		(pipelineCount);
189 	std::vector<VkPipelineColorBlendAttachmentState>		colorBlendAttachmentState		(pipelineCount);
190 	std::vector<VkPipelineColorBlendStateCreateInfo>		colorBlendStateCreateInfo		(pipelineCount);
191 	std::vector<VkPipelineDynamicStateCreateInfo>			dynamicStateCreateInfo			(pipelineCount);
192 	std::vector<std::vector<VkDynamicState>>				dynamicStates
193 	{
194 		{ VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR },
195 		{ VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR },
196 		{ VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR },
197 	};
198 
199 	const VkPipelineLayoutCreateInfo						pipelineLayoutCreateInfo		=
200 	{
201 		VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,										// VkStructureType                     sType;
202 		DE_NULL,																			// const void*                         pNext;
203 		(VkPipelineLayoutCreateFlags)0u,													// VkPipelineLayoutCreateFlags         flags;
204 		0u,																					// deUint32                            setLayoutCount;
205 		DE_NULL,																			// const VkDescriptorSetLayout*        pSetLayouts;
206 		0u,																					// deUint32                            pushConstantRangeCount;
207 		DE_NULL																				// const VkPushConstantRange*          pPushConstantRanges;
208 	};
209 	Move<VkPipelineLayout>									pipelineLayout					= createPipelineLayout(vk, device, &pipelineLayoutCreateInfo);
210 
211 	const VkFormat											format							= getRenderTargetFormat(vki, physicalDevice);
212 
213 	VkAttachmentDescription									attachmentDescription;
214 	VkAttachmentReference									attachmentReference;
215 	VkSubpassDescription									subpassDescription;
216 	VkRenderPassCreateInfo									renderPassCreateInfo			= prepareSimpleRenderPassCI(format, attachmentDescription, attachmentReference, subpassDescription);
217 	Move<VkRenderPass>										renderPass						= createRenderPass(vk, device, &renderPassCreateInfo);
218 
219 	std::vector<VkGraphicsPipelineCreateInfo>				graphicsPipelineCreateInfos		(pipelineCount);
220 	for (deUint32 i = 0; i < pipelineCount; ++i)
221 		graphicsPipelineCreateInfos[i] = prepareSimpleGraphicsPipelineCI(vertexInputStateCreateInfo[i], shaderStageCreateInfos[i], inputAssemblyStateCreateInfo[i], viewPortStateCreateInfo[i],
222 			rasterizationStateCreateInfo[i], multisampleStateCreateInfo[i], colorBlendAttachmentState[i], colorBlendStateCreateInfo[i], dynamicStateCreateInfo[i], dynamicStates[i], *pipelineLayout, *renderPass);
223 
224 	std::vector<std::string>								sourcePID						{ "IDG_0000", "IDG_1111", "IDG_2222" };
225 	std::vector<std::string>								destPID;
226 
227 	switch (testParams.type)
228 	{
229 	case PITT_MISSING_ID:
230 	case PITT_NONEXISTING_ID:
231 		destPID = { "IDG_XXXX", "IDG_1111", "IDG_2222" };
232 		break;
233 	case PITT_MATCHCONTROL:
234 		switch (testParams.matchControl)
235 		{
236 		case PIMC_UUID_EXACT_MATCH:
237 			destPID = { "IDG_0000", "IDG_1111", "IDG_2222" };
238 			break;
239 		default:
240 			TCU_THROW(InternalError, "Unrecognized match control");
241 		}
242 		break;
243 	default:
244 		TCU_THROW(InternalError, "Unrecognized test type");
245 	}
246 
247 	// fill pipeline identifiers with initial values, apply pipeline names from sourcePID
248 	std::vector<VkPipelineOfflineCreateInfo>				pipelineIDs;
249 	for (deUint32 i = 0; i < pipelineCount; ++i)
250 	{
251 		pipelineIDs.emplace_back(resetPipelineOfflineCreateInfo());
252 		applyPipelineIdentifier(pipelineIDs[i], sourcePID[i]);
253 	}
254 
255 	switch (testParams.matchControl)
256 	{
257 	case PIMC_UUID_EXACT_MATCH:
258 		for (deUint32 i = 0; i < pipelineCount; ++i)
259 			pipelineIDs[i].matchControl = VK_PIPELINE_MATCH_CONTROL_APPLICATION_UUID_EXACT_MATCH;
260 		break;
261 	default:
262 		TCU_THROW(InternalError, "Unrecognized match control");
263 	}
264 
265 	if (!context.getTestContext().getCommandLine().isSubProcess())
266 	{
267 		// If it's a main process - we create graphics pipelines only to increase VkDeviceObjectReservationCreateInfo::computePipelineRequestCount.
268 		// We also fill all pipeline identifiers with distinct values ( otherwise the framework will create pipeline identifiers itself )
269 		for (deUint32 i = 0; i < pipelineCount; ++i)
270 		{
271 			pipelineIDs[i].pNext					= graphicsPipelineCreateInfos[i].pNext;
272 			graphicsPipelineCreateInfos[i].pNext	= &pipelineIDs[i];
273 		}
274 
275 		std::vector<Move<VkPipeline>> pipelines;
276 		for (deUint32 i = 0; i < pipelineCount; ++i)
277 			pipelines.emplace_back(createGraphicsPipeline(vk, device, DE_NULL, &graphicsPipelineCreateInfos[i]));
278 		return tcu::TestStatus::pass("Pass");
279 	}
280 
281 	for (deUint32 i = 0; i < pipelineCount; ++i)
282 		context.getResourceInterface()->fillPoolEntrySize(pipelineIDs[i]);
283 
284 	// subprocess - we create the same pipeline, but we use vkCreateGraphicsPipelines directly to skip the framework
285 	GetDeviceProcAddrFunc									getDeviceProcAddrFunc			= (GetDeviceProcAddrFunc)vkp.getInstanceProcAddr(instance, "vkGetDeviceProcAddr");
286 	CreateGraphicsPipelinesFunc								createGraphicsPipelinesFunc		= (CreateGraphicsPipelinesFunc)getDeviceProcAddrFunc(device, "vkCreateGraphicsPipelines");
287 	DestroyPipelineFunc										destroyPipelineFunc				= (DestroyPipelineFunc)getDeviceProcAddrFunc(device, "vkDestroyPipeline");
288 	VkPipelineCache											pipelineCache					= context.getResourceInterface()->getPipelineCache(device);
289 	std::vector<VkPipeline>									pipelines						(pipelineCount);
290 
291 	VkResult												expectedResult;
292 	std::vector<deUint8>									expectedNullHandle				(pipelineCount);
293 	switch (testParams.type)
294 	{
295 	case PITT_MISSING_ID:
296 		expectedResult = VK_ERROR_NO_PIPELINE_MATCH;
297 		expectedNullHandle[0] = 1;
298 		for (deUint32 i = 1; i < pipelineCount; ++i)
299 		{
300 			// we are skipping pipeline identifier at index 0
301 			applyPipelineIdentifier(pipelineIDs[i], destPID[i]);
302 			pipelineIDs[i].pNext					= graphicsPipelineCreateInfos[i].pNext;
303 			graphicsPipelineCreateInfos[i].pNext	= &pipelineIDs[i];
304 			expectedNullHandle[i] = 0;
305 		}
306 		break;
307 	case PITT_NONEXISTING_ID:
308 		expectedResult = VK_ERROR_NO_PIPELINE_MATCH;
309 		for (deUint32 i = 0; i < pipelineCount; ++i)
310 		{
311 			// Pipeline identifier at index 0 uses wrong ID for PITT_NONEXISTING_ID test
312 			// or a proper one for PITT_MATCHCONTROL test
313 			applyPipelineIdentifier(pipelineIDs[i], destPID[i]);
314 			pipelineIDs[i].pNext					= graphicsPipelineCreateInfos[i].pNext;
315 			graphicsPipelineCreateInfos[i].pNext	= &pipelineIDs[i];
316 			expectedNullHandle[i] = (i == 0);
317 		}
318 		break;
319 	case PITT_MATCHCONTROL:
320 		expectedResult = VK_SUCCESS;
321 		for (deUint32 i = 0; i < pipelineCount; ++i)
322 		{
323 			// Pipeline identifier at index 0 uses wrong ID for PITT_NONEXISTING_ID test
324 			// or a proper one for PITT_MATCHCONTROL test
325 			applyPipelineIdentifier(pipelineIDs[i], destPID[i]);
326 			pipelineIDs[i].pNext					= graphicsPipelineCreateInfos[i].pNext;
327 			graphicsPipelineCreateInfos[i].pNext	= &pipelineIDs[i];
328 			expectedNullHandle[i] = 0;
329 		}
330 		break;
331 	default:
332 		TCU_THROW(InternalError, "Unrecognized match control");
333 	}
334 
335 	VkResult												result						= createGraphicsPipelinesFunc(device, pipelineCache, pipelineCount, graphicsPipelineCreateInfos.data(), DE_NULL, pipelines.data());
336 	bool													isOK						= true;
337 	for (deUint32 i = 0; i < pipelineCount; ++i)
338 	{
339 		if (expectedNullHandle[i] == 0 && pipelines[i] == DE_NULL)
340 		{
341 			context.getTestContext().getLog() << tcu::TestLog::Message << "Pipeline "<< i << " should be created" << tcu::TestLog::EndMessage;
342 			isOK = false;
343 		}
344 		if (expectedNullHandle[i] != 0 && pipelines[i] != DE_NULL)
345 		{
346 			context.getTestContext().getLog() << tcu::TestLog::Message << "Pipeline " << i << " should not be created" << tcu::TestLog::EndMessage;
347 			isOK = false;
348 		}
349 	}
350 
351 	if (result != expectedResult)
352 	{
353 		context.getTestContext().getLog() << tcu::TestLog::Message << "vkCreateGraphicsPipelines returned wrong VkResult" << tcu::TestLog::EndMessage;
354 		isOK = false;
355 	}
356 
357 	for (deUint32 i = 0; i < pipelineCount; ++i)
358 		destroyPipelineFunc(device, pipelines[i], DE_NULL);
359 
360 	return isOK ? tcu::TestStatus::pass("Pass") : tcu::TestStatus::fail("Fail");
361 }
362 
testComputePipelineIdentifier(Context & context,TestParams testParams)363 tcu::TestStatus testComputePipelineIdentifier (Context& context, TestParams testParams)
364 {
365 	const vk::PlatformInterface&					vkp							= context.getPlatformInterface();
366 	const VkInstance								instance					= context.getInstance();
367 	const DeviceInterface&							vk							= context.getDeviceInterface();
368 	const VkDevice									device						= context.getDevice();
369 
370 	deUint32										pipelineCount				= testParams.single ? 1 : 3;
371 
372 	std::vector<Move<VkShaderModule>>				computeShaders;
373 	for (deUint32 i = 0; i < pipelineCount; ++i)
374 	{
375 		std::ostringstream name;
376 		name << "compute_" << i;
377 		computeShaders.emplace_back(createShaderModule(vk, device, context.getBinaryCollection().get(name.str()), 0));
378 	}
379 
380 	std::vector<VkPipelineShaderStageCreateInfo>	shaderStageCreateInfos		(pipelineCount);
381 	for (deUint32 i = 0; i < pipelineCount; ++i)
382 	{
383 		shaderStageCreateInfos[i] =
384 		{
385 			VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,				// VkStructureType                     sType;
386 			DE_NULL,															// const void*                         pNext;
387 			(VkPipelineShaderStageCreateFlags)0,								// VkPipelineShaderStageCreateFlags    flags;
388 			VK_SHADER_STAGE_COMPUTE_BIT,										// VkShaderStageFlagBits               stage;
389 			*computeShaders[i],													// VkShaderModule                      shader;
390 			"main",																// const char*                         pName;
391 			DE_NULL,															// const VkSpecializationInfo*         pSpecializationInfo;
392 		};
393 	}
394 
395 	const VkPipelineLayoutCreateInfo				pipelineLayoutCreateInfo	=
396 	{
397 		VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,							// VkStructureType                     sType;
398 		DE_NULL,																// const void*                         pNext;
399 		(VkPipelineLayoutCreateFlags)0u,										// VkPipelineLayoutCreateFlags         flags;
400 		0u,																		// deUint32                            setLayoutCount;
401 		DE_NULL,																// const VkDescriptorSetLayout*        pSetLayouts;
402 		0u,																		// deUint32                            pushConstantRangeCount;
403 		DE_NULL																	// const VkPushConstantRange*          pPushConstantRanges;
404 	};
405 	Move<VkPipelineLayout>							pipelineLayout				= createPipelineLayout(vk, device, &pipelineLayoutCreateInfo);
406 
407 	std::vector<VkComputePipelineCreateInfo>		computePipelineCreateInfos	(pipelineCount);
408 	for (deUint32 i = 0; i < pipelineCount; ++i)
409 		computePipelineCreateInfos[i] = prepareSimpleComputePipelineCI(shaderStageCreateInfos[i], *pipelineLayout);
410 
411 	std::vector<std::string>						sourcePID					{ "IDC_0000", "IDC_1111", "IDC_2222" };
412 	std::vector<std::string>						destPID;
413 
414 	switch (testParams.type)
415 	{
416 	case PITT_MISSING_ID:
417 	case PITT_NONEXISTING_ID:
418 		destPID = { "IDC_XXXX", "IDC_1111", "IDC_2222" };
419 		break;
420 	case PITT_MATCHCONTROL:
421 		switch (testParams.matchControl)
422 		{
423 		case PIMC_UUID_EXACT_MATCH:
424 			destPID = { "IDC_0000", "IDC_1111", "IDC_2222" };
425 			break;
426 		default:
427 			TCU_THROW(InternalError, "Unrecognized match control");
428 		}
429 		break;
430 	default:
431 		TCU_THROW(InternalError, "Unrecognized test type");
432 	}
433 
434 	// fill pipeline identifiers with initial values, apply pipeline names from sourcePID
435 	std::vector<VkPipelineOfflineCreateInfo>		pipelineIDs;
436 	for (deUint32 i = 0; i < pipelineCount; ++i)
437 	{
438 		pipelineIDs.emplace_back(resetPipelineOfflineCreateInfo());
439 		applyPipelineIdentifier(pipelineIDs[i], sourcePID[i]);
440 	}
441 
442 	switch (testParams.matchControl)
443 	{
444 	case PIMC_UUID_EXACT_MATCH:
445 		for (deUint32 i = 0; i < pipelineCount; ++i)
446 			pipelineIDs[i].matchControl = VK_PIPELINE_MATCH_CONTROL_APPLICATION_UUID_EXACT_MATCH;
447 		break;
448 	default:
449 		TCU_THROW(InternalError, "Unrecognized match control");
450 	}
451 
452 	if (!context.getTestContext().getCommandLine().isSubProcess())
453 	{
454 		// If it's a main process - we create compute pipelines only to increase VkDeviceObjectReservationCreateInfo::computePipelineRequestCount.
455 		// We also fill all pipeline identifiers with distinct values ( otherwise the framework will create pipeline identifiers itself )
456 		for (deUint32 i = 0; i < pipelineCount; ++i)
457 		{
458 			pipelineIDs[i].pNext					= computePipelineCreateInfos[i].pNext;
459 			computePipelineCreateInfos[i].pNext		= &pipelineIDs[i];
460 		}
461 
462 		std::vector<Move<VkPipeline>> pipelines;
463 		for (deUint32 i = 0; i < pipelineCount; ++i)
464 			pipelines.emplace_back(createComputePipeline(vk, device, DE_NULL, &computePipelineCreateInfos[i]));
465 		return tcu::TestStatus::pass("Pass");
466 	}
467 
468 	for (deUint32 i = 0; i < pipelineCount; ++i)
469 		context.getResourceInterface()->fillPoolEntrySize(pipelineIDs[i]);
470 
471 	// In subprocess we create the same pipelines, but we use vkCreateGraphicsPipelines directly to skip the framework
472 	GetDeviceProcAddrFunc							getDeviceProcAddrFunc		= (GetDeviceProcAddrFunc)vkp.getInstanceProcAddr(instance, "vkGetDeviceProcAddr");
473 	CreateComputePipelinesFunc						createComputePipelinesFunc	= (CreateComputePipelinesFunc)getDeviceProcAddrFunc(device, "vkCreateComputePipelines");
474 	DestroyPipelineFunc								destroyPipelineFunc			= (DestroyPipelineFunc)getDeviceProcAddrFunc(device, "vkDestroyPipeline");
475 	VkPipelineCache									pipelineCache				= context.getResourceInterface()->getPipelineCache(device);
476 	std::vector<VkPipeline>							pipelines					(pipelineCount);
477 
478 	VkResult										expectedResult;
479 	std::vector<deUint8>							expectedNullHandle			(pipelineCount);
480 	switch (testParams.type)
481 	{
482 	case PITT_MISSING_ID:
483 		expectedResult = VK_ERROR_NO_PIPELINE_MATCH;
484 		expectedNullHandle[0] = 1;
485 		for (deUint32 i = 1; i < pipelineCount; ++i)
486 		{
487 			// we are skipping pipeline identifier at index 0
488 			applyPipelineIdentifier(pipelineIDs[i], destPID[i]);
489 			pipelineIDs[i].pNext					= computePipelineCreateInfos[i].pNext;
490 			computePipelineCreateInfos[i].pNext		= &pipelineIDs[i];
491 			expectedNullHandle[i]					= 0;
492 		}
493 		break;
494 	case PITT_NONEXISTING_ID:
495 		expectedResult = VK_ERROR_NO_PIPELINE_MATCH;
496 		for (deUint32 i = 0; i < pipelineCount; ++i)
497 		{
498 			// Pipeline identifier at index 0 uses wrong ID for PITT_NONEXISTING_ID test
499 			// or a proper one for PITT_MATCHCONTROL test
500 			applyPipelineIdentifier(pipelineIDs[i], destPID[i]);
501 			pipelineIDs[i].pNext					= computePipelineCreateInfos[i].pNext;
502 			computePipelineCreateInfos[i].pNext		= &pipelineIDs[i];
503 			expectedNullHandle[i]					= (i == 0);
504 		}
505 		break;
506 	case PITT_MATCHCONTROL:
507 		expectedResult = VK_SUCCESS;
508 		for (deUint32 i = 0; i < pipelineCount; ++i)
509 		{
510 			// Pipeline identifier at index 0 uses wrong ID for PITT_NONEXISTING_ID test
511 			// or a proper one for PITT_MATCHCONTROL test
512 			applyPipelineIdentifier(pipelineIDs[i], destPID[i]);
513 			pipelineIDs[i].pNext					= computePipelineCreateInfos[i].pNext;
514 			computePipelineCreateInfos[i].pNext		= &pipelineIDs[i];
515 			expectedNullHandle[i]					= 0;
516 		}
517 		break;
518 	default:
519 		TCU_THROW(InternalError, "Unrecognized match control");
520 	}
521 
522 	VkResult										result						= createComputePipelinesFunc(device, pipelineCache, pipelineCount, computePipelineCreateInfos.data(), DE_NULL, pipelines.data());
523 
524 	bool isOK = true;
525 	for (deUint32 i = 0; i < pipelineCount; ++i)
526 	{
527 		if (expectedNullHandle[i] == 0 && pipelines[i] == DE_NULL)
528 		{
529 			context.getTestContext().getLog() << tcu::TestLog::Message << "Pipeline "<< i << " should be created" << tcu::TestLog::EndMessage;
530 			isOK = false;
531 		}
532 		if (expectedNullHandle[i] != 0 && pipelines[i] != DE_NULL)
533 		{
534 			context.getTestContext().getLog() << tcu::TestLog::Message << "Pipeline " << i << " should not be created" << tcu::TestLog::EndMessage;
535 			isOK = false;
536 		}
537 	}
538 
539 	if (result != expectedResult)
540 	{
541 		context.getTestContext().getLog() << tcu::TestLog::Message << "vkCreateComputePipelines returned wrong VkResult" << tcu::TestLog::EndMessage;
542 		isOK = false;
543 	}
544 
545 	for (deUint32 i = 0; i < pipelineCount; ++i)
546 		destroyPipelineFunc(device, pipelines[i], DE_NULL);
547 
548 
549 	return isOK ? tcu::TestStatus::pass("Pass") : tcu::TestStatus::fail("Fail");
550 }
551 
552 } // anonymous
553 
createPipelineIdentifierTests(tcu::TestContext & testCtx)554 tcu::TestCaseGroup*	createPipelineIdentifierTests (tcu::TestContext& testCtx)
555 {
556 	de::MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(testCtx, "pipeline_identifier", "Tests verifying Vulkan SC pipeline identifier structure"));
557 
558 	const struct
559 	{
560 		PIPipeline									pipeline;
561 		const char*									name;
562 		FunctionPrograms1<TestParams>::Function		initPrograms;
563 		FunctionInstance1<TestParams>::Function		testFunction;
564 	} pipelineTypes[] =
565 	{
566 		{ PIP_GRAPHICS,				"graphics",	createGraphicsShaders,	testGraphicsPipelineIdentifier	},
567 		{ PIP_COMPUTE,				"compute",	createComputeShaders,	testComputePipelineIdentifier	},
568 	};
569 
570 	const struct
571 	{
572 		PITTestType									type;
573 		const char*									name;
574 	} testTypes[] =
575 	{
576 		{ PITT_MISSING_ID,			"missing_pid"		},
577 		{ PITT_NONEXISTING_ID,		"nonexisting_pid"	},
578 		{ PITT_MATCHCONTROL,		"match_control"		},
579 	};
580 
581 	const struct
582 	{
583 		PITMatchControl								control;
584 		const char*									name;
585 	} matchControls[] =
586 	{
587 		{ PIMC_UUID_EXACT_MATCH,	"exact_match"		},
588 	};
589 
590 	const struct
591 	{
592 		bool										single;
593 		const char*									name;
594 	} cardinalities[] =
595 	{
596 		{ true,						"single"	},
597 		{ false,					"multiple"	},
598 	};
599 
600 	for (int pipelineIdx = 0; pipelineIdx < DE_LENGTH_OF_ARRAY(pipelineTypes); ++pipelineIdx)
601 	{
602 		de::MovePtr<tcu::TestCaseGroup> pipelineGroup(new tcu::TestCaseGroup(testCtx, pipelineTypes[pipelineIdx].name, ""));
603 
604 		for (int typeIdx = 0; typeIdx < DE_LENGTH_OF_ARRAY(testTypes); ++typeIdx)
605 		{
606 			de::MovePtr<tcu::TestCaseGroup> typeGroup(new tcu::TestCaseGroup(testCtx, testTypes[typeIdx].name, ""));
607 
608 			for (int matchIdx = 0; matchIdx < DE_LENGTH_OF_ARRAY(matchControls); ++matchIdx)
609 			{
610 				de::MovePtr<tcu::TestCaseGroup> matchGroup(new tcu::TestCaseGroup(testCtx, matchControls[matchIdx].name, ""));
611 
612 				for (int cardIdx = 0; cardIdx < DE_LENGTH_OF_ARRAY(cardinalities); ++cardIdx)
613 				{
614 					TestParams testParams{ testTypes[typeIdx].type, matchControls[matchIdx].control, cardinalities[cardIdx].single };
615 
616 					addFunctionCaseWithPrograms(matchGroup.get(), cardinalities[cardIdx].name, "", pipelineTypes[pipelineIdx].initPrograms, pipelineTypes[pipelineIdx].testFunction, testParams);
617 				}
618 				typeGroup->addChild(matchGroup.release());
619 			}
620 			pipelineGroup->addChild(typeGroup.release());
621 		}
622 		group->addChild(pipelineGroup.release());
623 	}
624 	return group.release();
625 }
626 
627 }	// sc
628 
629 }	// vkt
630