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