xref: /aosp_15_r20/external/deqp/external/vulkancts/vkscserver/vksCacheBuilder.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
1 /*-------------------------------------------------------------------------
2  * Vulkan CTS Framework
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 
21 #include "vksCacheBuilder.hpp"
22 #include "pcreader.hpp"
23 #include "vksJson.hpp"
24 
25 #include <fstream>
26 //    Currently CTS does not use C++17, so universal method of deleting files from directory has been commented out
27 //#include <filesystem>
28 #include "vkRefUtil.hpp"
29 #include "vkQueryUtil.hpp"
30 #include "deDirectoryIterator.hpp"
31 #include "deFile.h"
32 #include "vkSafetyCriticalUtil.hpp"
33 
34 namespace vk
35 {
36 
37 typedef VKAPI_ATTR VkResult(VKAPI_CALL *CreateSamplerYcbcrConversionFunc)(
38     VkDevice device, const VkSamplerYcbcrConversionCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator,
39     VkSamplerYcbcrConversion *pYcbcrConversion);
40 typedef VKAPI_ATTR void(VKAPI_CALL *DestroySamplerYcbcrConversionFunc)(VkDevice device,
41                                                                        VkSamplerYcbcrConversion ycbcrConversion,
42                                                                        const VkAllocationCallbacks *pAllocator);
43 typedef VKAPI_ATTR VkResult(VKAPI_CALL *CreateSamplerFunc)(VkDevice device, const VkSamplerCreateInfo *pCreateInfo,
44                                                            const VkAllocationCallbacks *pAllocator,
45                                                            VkSampler *pSampler);
46 typedef VKAPI_ATTR void(VKAPI_CALL *DestroySamplerFunc)(VkDevice device, VkSampler sampler,
47                                                         const VkAllocationCallbacks *pAllocator);
48 typedef VKAPI_ATTR VkResult(VKAPI_CALL *CreateShaderModuleFunc)(VkDevice device,
49                                                                 const VkShaderModuleCreateInfo *pCreateInfo,
50                                                                 const VkAllocationCallbacks *pAllocator,
51                                                                 VkShaderModule *pShaderModule);
52 typedef VKAPI_ATTR void(VKAPI_CALL *DestroyShaderModuleFunc)(VkDevice device, VkShaderModule shaderModule,
53                                                              const VkAllocationCallbacks *pAllocator);
54 typedef VKAPI_ATTR VkResult(VKAPI_CALL *CreateRenderPassFunc)(VkDevice device,
55                                                               const VkRenderPassCreateInfo *pCreateInfo,
56                                                               const VkAllocationCallbacks *pAllocator,
57                                                               VkRenderPass *pRenderPass);
58 typedef VKAPI_ATTR VkResult(VKAPI_CALL *CreateRenderPass2Func)(VkDevice device,
59                                                                const VkRenderPassCreateInfo2 *pCreateInfo,
60                                                                const VkAllocationCallbacks *pAllocator,
61                                                                VkRenderPass *pRenderPass);
62 typedef VKAPI_ATTR void(VKAPI_CALL *DestroyRenderPassFunc)(VkDevice device, VkRenderPass renderPass,
63                                                            const VkAllocationCallbacks *pAllocator);
64 typedef VKAPI_ATTR VkResult(VKAPI_CALL *CreateDescriptorSetLayoutFunc)(
65     VkDevice device, const VkDescriptorSetLayoutCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator,
66     VkDescriptorSetLayout *pSetLayout);
67 typedef VKAPI_ATTR void(VKAPI_CALL *DestroyDescriptorSetLayoutFunc)(VkDevice device,
68                                                                     VkDescriptorSetLayout descriptorSetLayout,
69                                                                     const VkAllocationCallbacks *pAllocator);
70 typedef VKAPI_ATTR VkResult(VKAPI_CALL *CreatePipelineLayoutFunc)(VkDevice device,
71                                                                   const VkPipelineLayoutCreateInfo *pCreateInfo,
72                                                                   const VkAllocationCallbacks *pAllocator,
73                                                                   VkPipelineLayout *pPipelineLayout);
74 typedef VKAPI_ATTR void(VKAPI_CALL *DestroyPipelineLayoutFunc)(VkDevice device, VkPipelineLayout pipelineLayout,
75                                                                const VkAllocationCallbacks *pAllocator);
76 typedef VKAPI_ATTR VkResult(VKAPI_CALL *CreateGraphicsPipelinesFunc)(VkDevice device, VkPipelineCache pipelineCache,
77                                                                      uint32_t createInfoCount,
78                                                                      const VkGraphicsPipelineCreateInfo *pCreateInfos,
79                                                                      const VkAllocationCallbacks *pAllocator,
80                                                                      VkPipeline *pPipelines);
81 typedef VKAPI_ATTR VkResult(VKAPI_CALL *CreateComputePipelinesFunc)(VkDevice device, VkPipelineCache pipelineCache,
82                                                                     uint32_t createInfoCount,
83                                                                     const VkComputePipelineCreateInfo *pCreateInfos,
84                                                                     const VkAllocationCallbacks *pAllocator,
85                                                                     VkPipeline *pPipelines);
86 typedef VKAPI_ATTR void(VKAPI_CALL *DestroyPipelineFunc)(VkDevice device, VkPipeline pipeline,
87                                                          const VkAllocationCallbacks *pAllocator);
88 typedef VKAPI_ATTR VkResult(VKAPI_CALL *CreatePipelineCacheFunc)(VkDevice device,
89                                                                  const VkPipelineCacheCreateInfo *pCreateInfo,
90                                                                  const VkAllocationCallbacks *pAllocator,
91                                                                  VkPipelineCache *pPipelineCache);
92 typedef VKAPI_ATTR void(VKAPI_CALL *DestroyPipelineCacheFunc)(VkDevice device, VkPipelineCache pipelineCache,
93                                                               const VkAllocationCallbacks *pAllocator);
94 typedef VKAPI_ATTR VkResult(VKAPI_CALL *GetPipelineCacheDataFunc)(VkDevice device, VkPipelineCache pipelineCache,
95                                                                   uintptr_t *pDataSize, void *pData);
96 
97 } // namespace vk
98 
99 namespace vksc_server
100 {
101 
102 const VkDeviceSize VKSC_DEFAULT_PIPELINE_POOL_SIZE = 2u * 1024u * 1024u;
103 
exportFilesForExternalCompiler(const VulkanPipelineCacheInput & input,const std::string & path,const std::string & filePrefix)104 void exportFilesForExternalCompiler(const VulkanPipelineCacheInput &input, const std::string &path,
105                                     const std::string &filePrefix)
106 {
107     // unpack JSON data to track relations between objects
108     using namespace vk;
109     using namespace json;
110     Context jsonReader;
111 
112     std::map<VkSamplerYcbcrConversion, VkSamplerYcbcrConversionCreateInfo> allSamplerYcbcrConversions;
113     for (auto &&samplerYcbcr : input.samplerYcbcrConversions)
114     {
115         VkSamplerYcbcrConversionCreateInfo sycCI{};
116         readJSON_VkSamplerYcbcrConversionCreateInfo(jsonReader, samplerYcbcr.second, sycCI);
117         allSamplerYcbcrConversions.insert({samplerYcbcr.first, sycCI});
118     }
119 
120     std::map<VkSampler, VkSamplerCreateInfo> allSamplers;
121     for (auto &&sampler : input.samplers)
122     {
123         VkSamplerCreateInfo sCI{};
124         readJSON_VkSamplerCreateInfo(jsonReader, sampler.second, sCI);
125         allSamplers.insert({sampler.first, sCI});
126     }
127 
128     std::map<VkShaderModule, VkShaderModuleCreateInfo> allShaderModules;
129     std::map<VkShaderModule, std::vector<uint8_t>> allSpirvShaders;
130     for (auto &&shader : input.shaderModules)
131     {
132         VkShaderModuleCreateInfo smCI{};
133         std::vector<uint8_t> spirvShader;
134         readJSON_VkShaderModuleCreateInfo(jsonReader, shader.second, smCI, spirvShader);
135         allShaderModules.insert({shader.first, smCI});
136         allSpirvShaders.insert({shader.first, spirvShader});
137     }
138 
139     std::map<VkRenderPass, VkRenderPassCreateInfo> allRenderPasses;
140     std::map<VkRenderPass, VkRenderPassCreateInfo2> allRenderPasses2;
141     for (auto &&renderPass : input.renderPasses)
142     {
143         if (renderPass.second.find("VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2") != std::string::npos)
144         {
145             VkRenderPassCreateInfo2 rpCI{};
146             readJSON_VkRenderPassCreateInfo2(jsonReader, renderPass.second, rpCI);
147             allRenderPasses2.insert({renderPass.first, rpCI});
148         }
149         else if (renderPass.second.find("VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO") != std::string::npos)
150         {
151             VkRenderPassCreateInfo rpCI{};
152             readJSON_VkRenderPassCreateInfo(jsonReader, renderPass.second, rpCI);
153             allRenderPasses.insert({renderPass.first, rpCI});
154         }
155         else
156             TCU_THROW(InternalError, "Could not recognize render pass type");
157     }
158 
159     std::map<VkDescriptorSetLayout, VkDescriptorSetLayoutCreateInfo> allDescriptorSetLayouts;
160     for (auto &&descriptorSetLayout : input.descriptorSetLayouts)
161     {
162         VkDescriptorSetLayoutCreateInfo dsCI{};
163         readJSON_VkDescriptorSetLayoutCreateInfo(jsonReader, descriptorSetLayout.second, dsCI);
164         allDescriptorSetLayouts.insert({descriptorSetLayout.first, dsCI});
165     }
166 
167     std::map<VkPipelineLayout, VkPipelineLayoutCreateInfo> allPipelineLayouts;
168     for (auto &&pipelineLayout : input.pipelineLayouts)
169     {
170         VkPipelineLayoutCreateInfo plCI{};
171         readJSON_VkPipelineLayoutCreateInfo(jsonReader, pipelineLayout.second, plCI);
172         allPipelineLayouts.insert({pipelineLayout.first, plCI});
173     }
174 
175     uint32_t exportedPipelines = 0;
176 
177     for (auto &&pipeline : input.pipelines)
178     {
179         // filter objects used for this specific pipeline ( graphics or compute )
180         std::map<VkSamplerYcbcrConversion, VkSamplerYcbcrConversionCreateInfo> samplerYcbcrConversions;
181         std::map<VkSampler, VkSamplerCreateInfo> samplers;
182         std::map<VkShaderModule, VkShaderModuleCreateInfo> shaderModules;
183         std::map<VkShaderModule, std::vector<uint8_t>> spirvShaders;
184         std::map<VkRenderPass, VkRenderPassCreateInfo> renderPasses;
185         std::map<VkRenderPass, VkRenderPassCreateInfo2> renderPasses2;
186         std::map<VkDescriptorSetLayout, VkDescriptorSetLayoutCreateInfo> descriptorSetLayouts;
187         std::map<VkPipelineLayout, VkPipelineLayoutCreateInfo> pipelineLayouts;
188 
189         if (pipeline.pipelineContents.find("VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO") != std::string::npos)
190         {
191             VkGraphicsPipelineCreateInfo gpCI{};
192             readJSON_VkGraphicsPipelineCreateInfo(jsonReader, pipeline.pipelineContents, gpCI);
193 
194             // copy all used shaders
195             for (uint32_t i = 0; i < gpCI.stageCount; ++i)
196             {
197                 auto it = allShaderModules.find(gpCI.pStages[i].module);
198                 if (it == end(allShaderModules))
199                     TCU_THROW(InternalError, "Could not find shader module");
200                 shaderModules.insert(*it);
201 
202                 auto it2 = allSpirvShaders.find(gpCI.pStages[i].module);
203                 if (it2 == end(allSpirvShaders))
204                     TCU_THROW(InternalError, "Could not find shader");
205                 spirvShaders.insert(*it2);
206             }
207 
208             // copy render pass
209             {
210                 auto it = allRenderPasses.find(gpCI.renderPass);
211                 if (it == end(allRenderPasses))
212                 {
213                     auto it2 = allRenderPasses2.find(gpCI.renderPass);
214                     if (it2 == end(allRenderPasses2))
215                         TCU_THROW(InternalError, "Could not find render pass");
216                     else
217                         renderPasses2.insert(*it2);
218                 }
219                 else
220                     renderPasses.insert(*it);
221             }
222 
223             // copy pipeline layout
224             {
225                 auto it = allPipelineLayouts.find(gpCI.layout);
226                 if (it == end(allPipelineLayouts))
227                     TCU_THROW(InternalError, "Could not find pipeline layout");
228                 pipelineLayouts.insert(*it);
229 
230                 // copy descriptor set layouts
231                 for (uint32_t i = 0; i < it->second.setLayoutCount; ++i)
232                 {
233                     auto it2 = allDescriptorSetLayouts.find(it->second.pSetLayouts[i]);
234                     if (it2 == end(allDescriptorSetLayouts))
235                         TCU_THROW(InternalError, "Could not find descriptor set layout");
236                     descriptorSetLayouts.insert({it2->first, it2->second});
237 
238                     // copy samplers
239                     for (uint32_t j = 0; j < it2->second.bindingCount; ++j)
240                     {
241                         if (it2->second.pBindings[j].pImmutableSamplers != DE_NULL)
242                         {
243                             for (uint32_t k = 0; k < it2->second.pBindings[j].descriptorCount; ++k)
244                             {
245                                 auto it3 = allSamplers.find(it2->second.pBindings[j].pImmutableSamplers[k]);
246                                 if (it3 == end(allSamplers))
247                                     TCU_THROW(InternalError, "Could not find sampler");
248                                 samplers.insert({it3->first, it3->second});
249 
250                                 // copy sampler YcbcrConversion
251                                 if (it3->second.pNext != DE_NULL)
252                                 {
253                                     VkSamplerYcbcrConversionInfo *info =
254                                         (VkSamplerYcbcrConversionInfo *)findStructureInChain(
255                                             it3->second.pNext, VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO);
256                                     if (info->sType == VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO)
257                                     {
258                                         auto it4 = allSamplerYcbcrConversions.find(info->conversion);
259                                         if (it4 == end(allSamplerYcbcrConversions))
260                                             TCU_THROW(InternalError, "Could not find VkSamplerYcbcrConversion");
261                                         samplerYcbcrConversions.insert({it4->first, it4->second});
262                                     }
263                                 }
264                             }
265                         }
266                     }
267                 }
268             }
269 
270             vk::VkPhysicalDeviceFeatures2 deviceFeatures2;
271             readJSON_VkPhysicalDeviceFeatures2(jsonReader, pipeline.deviceFeatures, deviceFeatures2);
272 
273             // export shaders and objects to JSON compatible with https://schema.khronos.org/vulkan/vkpcc.json
274             std::string gpTxt = writeJSON_GraphicsPipeline_vkpccjson(
275                 filePrefix, exportedPipelines, pipeline.id, gpCI, deviceFeatures2, pipeline.deviceExtensions,
276                 samplerYcbcrConversions, samplers, descriptorSetLayouts, renderPasses, renderPasses2, pipelineLayouts);
277             std::stringstream fileName;
278 #ifdef _WIN32
279             fileName << path << "\\" << filePrefix << "graphics_pipeline_" << exportedPipelines << ".json";
280 #else
281             fileName << path << "/" << filePrefix << "graphics_pipeline_" << exportedPipelines << ".json";
282 #endif
283             {
284                 std::ofstream oFile(fileName.str().c_str(), std::ios::out);
285                 oFile << gpTxt;
286             }
287 
288             for (uint32_t j = 0; j < gpCI.stageCount; ++j)
289             {
290                 std::stringstream shaderName;
291 #ifdef _WIN32
292                 shaderName << path << "\\" << filePrefix << "shader_" << exportedPipelines << "_"
293                            << gpCI.pStages[j].module.getInternal() << ".";
294 #else
295                 shaderName << path << "/" << filePrefix << "shader_" << exportedPipelines << "_"
296                            << gpCI.pStages[j].module.getInternal() << ".";
297 #endif
298                 switch (gpCI.pStages[j].stage)
299                 {
300                 case VK_SHADER_STAGE_VERTEX_BIT:
301                     shaderName << "vert";
302                     break;
303                 case VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT:
304                     shaderName << "tesc";
305                     break;
306                 case VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT:
307                     shaderName << "tese";
308                     break;
309                 case VK_SHADER_STAGE_GEOMETRY_BIT:
310                     shaderName << "geom";
311                     break;
312                 case VK_SHADER_STAGE_FRAGMENT_BIT:
313                     shaderName << "frag";
314                     break;
315                 default:
316                     TCU_THROW(InternalError, "Unrecognized shader stage");
317                 }
318                 shaderName << ".spv";
319 
320                 auto sit = spirvShaders.find(gpCI.pStages[j].module);
321                 if (sit == end(spirvShaders))
322                     TCU_THROW(InternalError, "SPIR-V shader not found");
323 
324                 std::ofstream oFile(shaderName.str().c_str(), std::ios::out | std::ios::binary);
325                 oFile.write((const char *)sit->second.data(), sit->second.size());
326             }
327 
328             exportedPipelines++;
329         }
330         else if (pipeline.pipelineContents.find("VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO") != std::string::npos)
331         {
332             VkComputePipelineCreateInfo cpCI{};
333             readJSON_VkComputePipelineCreateInfo(jsonReader, pipeline.pipelineContents, cpCI);
334 
335             // copy shader
336             {
337                 auto it = allShaderModules.find(cpCI.stage.module);
338                 if (it == end(allShaderModules))
339                     TCU_THROW(InternalError, "Could not find shader module");
340                 shaderModules.insert(*it);
341 
342                 auto it2 = allSpirvShaders.find(cpCI.stage.module);
343                 if (it2 == end(allSpirvShaders))
344                     TCU_THROW(InternalError, "Could not find shader");
345                 spirvShaders.insert(*it2);
346             }
347 
348             // copy pipeline layout
349             {
350                 auto it = allPipelineLayouts.find(cpCI.layout);
351                 if (it == end(allPipelineLayouts))
352                     TCU_THROW(InternalError, "Could not find pipeline layout");
353                 pipelineLayouts.insert(*it);
354 
355                 // copy descriptor set layouts
356                 for (uint32_t i = 0; i < it->second.setLayoutCount; ++i)
357                 {
358                     auto it2 = allDescriptorSetLayouts.find(it->second.pSetLayouts[i]);
359                     if (it2 == end(allDescriptorSetLayouts))
360                         TCU_THROW(InternalError, "Could not find descriptor set layout");
361                     descriptorSetLayouts.insert({it2->first, it2->second});
362 
363                     // copy samplers
364                     for (uint32_t j = 0; j < it2->second.bindingCount; ++j)
365                     {
366                         if (it2->second.pBindings[j].pImmutableSamplers != DE_NULL)
367                         {
368                             for (uint32_t k = 0; k < it2->second.pBindings[j].descriptorCount; ++k)
369                             {
370                                 auto it3 = allSamplers.find(it2->second.pBindings[j].pImmutableSamplers[k]);
371                                 if (it3 == end(allSamplers))
372                                     TCU_THROW(InternalError, "Could not find sampler");
373                                 samplers.insert({it3->first, it3->second});
374 
375                                 // copy sampler YcbcrConversion
376                                 if (it3->second.pNext != DE_NULL)
377                                 {
378                                     VkSamplerYcbcrConversionInfo *info =
379                                         (VkSamplerYcbcrConversionInfo *)(it3->second.pNext);
380                                     if (info->sType == VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO)
381                                     {
382                                         auto it4 = allSamplerYcbcrConversions.find(info->conversion);
383                                         if (it4 == end(allSamplerYcbcrConversions))
384                                             TCU_THROW(InternalError, "Could not find VkSamplerYcbcrConversion");
385                                         samplerYcbcrConversions.insert({it4->first, it4->second});
386                                     }
387                                 }
388                             }
389                         }
390                     }
391                 }
392             }
393             vk::VkPhysicalDeviceFeatures2 deviceFeatures2;
394             readJSON_VkPhysicalDeviceFeatures2(jsonReader, pipeline.deviceFeatures, deviceFeatures2);
395 
396             // export shaders and objects to JSON compatible with https://schema.khronos.org/vulkan/vkpcc.json
397             std::string cpTxt = writeJSON_ComputePipeline_vkpccjson(
398                 filePrefix, exportedPipelines, pipeline.id, cpCI, deviceFeatures2, pipeline.deviceExtensions,
399                 samplerYcbcrConversions, samplers, descriptorSetLayouts, pipelineLayouts);
400             std::stringstream fileName;
401 #ifdef _WIN32
402             fileName << path << "\\" << filePrefix << "compute_pipeline_" << exportedPipelines << ".json";
403 #else
404             fileName << path << "/" << filePrefix << "compute_pipeline_" << exportedPipelines << ".json";
405 #endif
406             {
407                 std::ofstream oFile(fileName.str().c_str(), std::ios::out);
408                 oFile << cpTxt;
409             }
410 
411             {
412                 std::stringstream shaderName;
413 #ifdef _WIN32
414                 shaderName << path << "\\" << filePrefix << "shader_" << exportedPipelines << "_"
415                            << cpCI.stage.module.getInternal() << ".";
416 #else
417                 shaderName << path << "/" << filePrefix << "shader_" << exportedPipelines << "_"
418                            << cpCI.stage.module.getInternal() << ".";
419 #endif
420                 switch (cpCI.stage.stage)
421                 {
422                 case VK_SHADER_STAGE_COMPUTE_BIT:
423                     shaderName << "comp";
424                     break;
425                 default:
426                     TCU_THROW(InternalError, "Unrecognized shader stage");
427                 }
428                 shaderName << ".spv";
429 
430                 auto sit = spirvShaders.find(cpCI.stage.module);
431                 if (sit == end(spirvShaders))
432                     TCU_THROW(InternalError, "SPIR-V shader not found");
433 
434                 std::ofstream oFile(shaderName.str().c_str(), std::ios::out | std::ios::binary);
435                 oFile.write((const char *)sit->second.data(), sit->second.size());
436             }
437 
438             exportedPipelines++;
439         }
440     }
441 }
442 
443 // This is function prototype for creating pipeline cache using offline pipeline compiler
444 
buildOfflinePipelineCache(const VulkanPipelineCacheInput & input,const std::string & pipelineCompilerPath,const std::string & pipelineCompilerDataDir,const std::string & pipelineCompilerArgs,const std::string & pipelineCompilerOutputFile,const std::string & pipelineCompilerLogFile,const std::string & pipelineCompilerFilePrefix)445 vector<u8> buildOfflinePipelineCache(const VulkanPipelineCacheInput &input, const std::string &pipelineCompilerPath,
446                                      const std::string &pipelineCompilerDataDir,
447                                      const std::string &pipelineCompilerArgs,
448                                      const std::string &pipelineCompilerOutputFile,
449                                      const std::string &pipelineCompilerLogFile,
450                                      const std::string &pipelineCompilerFilePrefix)
451 {
452     if (!deFileExists(pipelineCompilerPath.c_str()))
453         TCU_THROW(InternalError, std::string("Can't find pipeline compiler") + pipelineCompilerPath);
454     // Remove all files from output directory
455     for (de::DirectoryIterator iter(pipelineCompilerDataDir); iter.hasItem(); iter.next())
456     {
457         const de::FilePath filePath = iter.getItem();
458         if (filePath.getType() != de::FilePath::TYPE_FILE)
459             continue;
460         if (!pipelineCompilerFilePrefix.empty() && filePath.getBaseName().find(pipelineCompilerFilePrefix) != 0)
461             continue;
462         deDeleteFile(filePath.getPath());
463     }
464 
465     // export new files
466     exportFilesForExternalCompiler(input, pipelineCompilerDataDir, pipelineCompilerFilePrefix);
467     if (input.pipelines.size() == 0)
468         return vector<u8>();
469 
470     // run offline pipeline compiler
471     {
472         std::stringstream compilerCommand;
473         compilerCommand << pipelineCompilerPath << " --path " << pipelineCompilerDataDir << " --out "
474                         << pipelineCompilerOutputFile;
475         if (!pipelineCompilerLogFile.empty())
476             compilerCommand << " --log " << pipelineCompilerLogFile;
477         if (!pipelineCompilerFilePrefix.empty())
478             compilerCommand << " --prefix " << pipelineCompilerFilePrefix;
479         if (!pipelineCompilerArgs.empty())
480             compilerCommand << " " << pipelineCompilerArgs;
481 
482         std::string command = compilerCommand.str();
483         int returnValue     = system(command.c_str());
484         // offline pipeline compiler returns EXIT_SUCCESS on success
485         if (returnValue != EXIT_SUCCESS)
486         {
487             TCU_THROW(InternalError, "offline pipeline compilation failed");
488         }
489     }
490 
491     // read created pipeline cache into result vector
492     vector<u8> result;
493     {
494         std::ifstream iFile(pipelineCompilerOutputFile.c_str(), std::ios::in | std::ios::binary);
495         if (!iFile)
496             TCU_THROW(InternalError, (std::string("Cannot open file ") + pipelineCompilerOutputFile).c_str());
497 
498         auto fileBegin = iFile.tellg();
499         iFile.seekg(0, std::ios::end);
500         auto fileEnd = iFile.tellg();
501         iFile.seekg(0, std::ios::beg);
502         std::size_t fileSize = static_cast<std::size_t>(fileEnd - fileBegin);
503         if (fileSize > 0)
504         {
505             result.resize(fileSize);
506             iFile.read(reinterpret_cast<char *>(result.data()), fileSize);
507             if (iFile.fail())
508                 TCU_THROW(InternalError, (std::string("Cannot load file ") + pipelineCompilerOutputFile).c_str());
509         }
510     }
511     return result;
512 }
513 
buildPipelineCache(const VulkanPipelineCacheInput & input,const vk::PlatformInterface & vkp,vk::VkInstance instance,const vk::InstanceInterface & vki,vk::VkPhysicalDevice physicalDevice,uint32_t queueIndex)514 vector<u8> buildPipelineCache(const VulkanPipelineCacheInput &input, const vk::PlatformInterface &vkp,
515                               vk::VkInstance instance, const vk::InstanceInterface &vki,
516                               vk::VkPhysicalDevice physicalDevice, uint32_t queueIndex)
517 {
518     using namespace vk;
519     using namespace json;
520 
521     Context jsonReader;
522 
523     // sort pipelines by device features and extensions
524     std::vector<VulkanJsonPipelineDescription> pipelines = input.pipelines;
525     std::sort(begin(pipelines), end(pipelines),
526               [](const VulkanJsonPipelineDescription &lhs, const VulkanJsonPipelineDescription &rhs)
527               {
528                   if (lhs.deviceExtensions != rhs.deviceExtensions)
529                       return lhs.deviceExtensions < rhs.deviceExtensions;
530                   return lhs.deviceFeatures < rhs.deviceFeatures;
531               });
532 
533     std::string deviceFeatures                = "<empty>";
534     std::vector<std::string> deviceExtensions = {"<empty>"};
535 
536     Move<VkDevice> pcDevice;
537     VkPipelineCache pipelineCache;
538     vector<u8> resultCacheData;
539 
540     GetDeviceProcAddrFunc getDeviceProcAddrFunc                         = DE_NULL;
541     CreateSamplerYcbcrConversionFunc createSamplerYcbcrConversionFunc   = DE_NULL;
542     DestroySamplerYcbcrConversionFunc destroySamplerYcbcrConversionFunc = DE_NULL;
543     CreateSamplerFunc createSamplerFunc                                 = DE_NULL;
544     DestroySamplerFunc destroySamplerFunc                               = DE_NULL;
545     CreateShaderModuleFunc createShaderModuleFunc                       = DE_NULL;
546     DestroyShaderModuleFunc destroyShaderModuleFunc                     = DE_NULL;
547     CreateRenderPassFunc createRenderPassFunc                           = DE_NULL;
548     CreateRenderPass2Func createRenderPass2Func                         = DE_NULL;
549     DestroyRenderPassFunc destroyRenderPassFunc                         = DE_NULL;
550     CreateDescriptorSetLayoutFunc createDescriptorSetLayoutFunc         = DE_NULL;
551     DestroyDescriptorSetLayoutFunc destroyDescriptorSetLayoutFunc       = DE_NULL;
552     CreatePipelineLayoutFunc createPipelineLayoutFunc                   = DE_NULL;
553     DestroyPipelineLayoutFunc destroyPipelineLayoutFunc                 = DE_NULL;
554     CreateGraphicsPipelinesFunc createGraphicsPipelinesFunc             = DE_NULL;
555     CreateComputePipelinesFunc createComputePipelinesFunc               = DE_NULL;
556     CreatePipelineCacheFunc createPipelineCacheFunc                     = DE_NULL;
557     DestroyPipelineCacheFunc destroyPipelineCacheFunc                   = DE_NULL;
558     DestroyPipelineFunc destroyPipelineFunc                             = DE_NULL;
559     GetPipelineCacheDataFunc getPipelineCacheDataFunc                   = DE_NULL;
560 
561     std::map<VkSamplerYcbcrConversion, VkSamplerYcbcrConversion> falseToRealSamplerYcbcrConversions;
562     std::map<VkSampler, VkSampler> falseToRealSamplers;
563     std::map<VkShaderModule, VkShaderModule> falseToRealShaderModules;
564     std::map<VkRenderPass, VkRenderPass> falseToRealRenderPasses;
565     std::map<VkDescriptorSetLayout, VkDescriptorSetLayout> falseToRealDescriptorSetLayouts;
566     std::map<VkPipelineLayout, VkPipelineLayout> falseToRealPipelineLayouts;
567 
568     // decode VkGraphicsPipelineCreateInfo and VkComputePipelineCreateInfo structs and create VkPipelines with a given pipeline cache
569     for (auto &&pipeline : pipelines)
570     {
571         // check if we need to create new device
572         if (pcDevice.get() == DE_NULL || deviceFeatures != pipeline.deviceFeatures ||
573             deviceExtensions != pipeline.deviceExtensions)
574         {
575             // remove old device
576             if (pcDevice.get() != DE_NULL)
577             {
578                 // collect cache data
579                 std::size_t cacheSize;
580                 VK_CHECK(getPipelineCacheDataFunc(*pcDevice, pipelineCache, &cacheSize, DE_NULL));
581                 resultCacheData.resize(cacheSize);
582                 VK_CHECK(getPipelineCacheDataFunc(*pcDevice, pipelineCache, &cacheSize, resultCacheData.data()));
583 
584                 // clean up resources - in ResourceInterfaceStandard we just simulate Vulkan SC driver after all...
585                 for (auto &&it : falseToRealPipelineLayouts)
586                     destroyPipelineLayoutFunc(*pcDevice, it.second, DE_NULL);
587                 for (auto &&it : falseToRealDescriptorSetLayouts)
588                     destroyDescriptorSetLayoutFunc(*pcDevice, it.second, DE_NULL);
589                 for (auto &&it : falseToRealRenderPasses)
590                     destroyRenderPassFunc(*pcDevice, it.second, DE_NULL);
591                 for (auto &&it : falseToRealShaderModules)
592                     destroyShaderModuleFunc(*pcDevice, it.second, DE_NULL);
593                 for (auto &&it : falseToRealSamplers)
594                     destroySamplerFunc(*pcDevice, it.second, DE_NULL);
595                 for (auto &&it : falseToRealSamplerYcbcrConversions)
596                     destroySamplerYcbcrConversionFunc(*pcDevice, it.second, DE_NULL);
597                 destroyPipelineCacheFunc(*pcDevice, pipelineCache, DE_NULL);
598 
599                 // clear maps
600                 falseToRealSamplerYcbcrConversions.clear();
601                 falseToRealSamplers.clear();
602                 falseToRealShaderModules.clear();
603                 falseToRealRenderPasses.clear();
604                 falseToRealDescriptorSetLayouts.clear();
605                 falseToRealPipelineLayouts.clear();
606 
607                 // remove device
608                 pcDevice = Move<VkDevice>();
609             }
610 
611             // create new device with proper features and extensions
612             const float queuePriority                           = 1.0f;
613             const VkDeviceQueueCreateInfo deviceQueueCreateInfo = {
614                 VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
615                 DE_NULL,
616                 (VkDeviceQueueCreateFlags)0u,
617                 queueIndex,     //queueFamilyIndex;
618                 1,              //queueCount;
619                 &queuePriority, //pQueuePriorities;
620             };
621 
622             // recreate pNext chain. Add required Vulkan SC objects if they're missing
623             void *pNextChain                           = readJSON_pNextChain(jsonReader, pipeline.deviceFeatures);
624             VkPhysicalDeviceFeatures2 *chainedFeatures = (VkPhysicalDeviceFeatures2 *)findStructureInChain(
625                 pNextChain, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2);
626             VkPhysicalDeviceFeatures2 localFeatures = initVulkanStructure();
627             VkDeviceObjectReservationCreateInfo *chainedObjReservation =
628                 (VkDeviceObjectReservationCreateInfo *)findStructureInChain(
629                     pNextChain, VK_STRUCTURE_TYPE_DEVICE_OBJECT_RESERVATION_CREATE_INFO);
630             VkDeviceObjectReservationCreateInfo localObjReservation = resetDeviceObjectReservationCreateInfo();
631             VkPhysicalDeviceVulkanSC10Features *chainedSC10Features =
632                 (VkPhysicalDeviceVulkanSC10Features *)findStructureInChain(
633                     pNextChain, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_SC_1_0_FEATURES);
634             VkPhysicalDeviceVulkanSC10Features localSC10Features = createDefaultSC10Features();
635 
636             void *pNext = pNextChain;
637             if (chainedFeatures == DE_NULL)
638             {
639                 chainedFeatures     = &localFeatures;
640                 localFeatures.pNext = pNext;
641                 pNext               = &localFeatures;
642             }
643             if (chainedObjReservation == DE_NULL)
644             {
645                 chainedObjReservation     = &localObjReservation;
646                 localObjReservation.pNext = pNext;
647                 pNext                     = &localObjReservation;
648             }
649             if (chainedSC10Features == DE_NULL)
650             {
651                 chainedSC10Features     = &localSC10Features;
652                 localSC10Features.pNext = pNext;
653                 pNext                   = &localSC10Features;
654             }
655 
656             uint32_t gPipelineCount = 0U;
657             uint32_t cPipelineCount = 0U;
658             for (auto &&pipeline2 : pipelines)
659             {
660                 if (pipeline2.deviceFeatures != pipeline.deviceFeatures ||
661                     pipeline2.deviceExtensions != pipeline.deviceExtensions)
662                     continue;
663                 if (pipeline2.pipelineContents.find("VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO") !=
664                     std::string::npos)
665                     gPipelineCount++;
666                 else if (pipeline2.pipelineContents.find("VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO") !=
667                          std::string::npos)
668                     cPipelineCount++;
669             }
670 
671             // declare pipeline pool size
672             VkPipelinePoolSize poolSize = {
673                 VK_STRUCTURE_TYPE_PIPELINE_POOL_SIZE, // VkStructureType sType;
674                 DE_NULL,                              // const void* pNext;
675                 VKSC_DEFAULT_PIPELINE_POOL_SIZE,      // VkDeviceSize poolEntrySize;
676                 gPipelineCount + cPipelineCount       // uint32_t poolEntryCount;
677             };
678             chainedObjReservation->pipelinePoolSizeCount = 1u;
679             chainedObjReservation->pPipelinePoolSizes    = &poolSize;
680 
681             // declare pipeline cache
682             VkPipelineCacheCreateInfo pcCI = {
683                 VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO,              // VkStructureType sType;
684                 DE_NULL,                                                   // const void* pNext;
685                 (VkPipelineCacheCreateFlags)0u,                            // VkPipelineCacheCreateFlags flags;
686                 resultCacheData.size(),                                    // size_t initialDataSize;
687                 resultCacheData.empty() ? DE_NULL : resultCacheData.data() // const void* pInitialData;
688             };
689             chainedObjReservation->pipelineCacheCreateInfoCount = 1u;
690             chainedObjReservation->pPipelineCacheCreateInfos    = &pcCI;
691 
692             chainedObjReservation->pipelineLayoutRequestCount =
693                 de::max(chainedObjReservation->pipelineLayoutRequestCount, uint32_t(input.pipelineLayouts.size()));
694             chainedObjReservation->renderPassRequestCount =
695                 de::max(chainedObjReservation->renderPassRequestCount, uint32_t(input.renderPasses.size()));
696             chainedObjReservation->graphicsPipelineRequestCount =
697                 de::max(chainedObjReservation->graphicsPipelineRequestCount, gPipelineCount);
698             chainedObjReservation->computePipelineRequestCount =
699                 de::max(chainedObjReservation->computePipelineRequestCount, cPipelineCount);
700             chainedObjReservation->descriptorSetLayoutRequestCount = de::max(
701                 chainedObjReservation->descriptorSetLayoutRequestCount, uint32_t(input.descriptorSetLayouts.size()));
702             chainedObjReservation->samplerRequestCount =
703                 de::max(chainedObjReservation->samplerRequestCount, uint32_t(input.samplers.size()));
704             chainedObjReservation->samplerYcbcrConversionRequestCount =
705                 de::max(chainedObjReservation->samplerYcbcrConversionRequestCount,
706                         uint32_t(input.samplerYcbcrConversions.size()));
707             chainedObjReservation->pipelineCacheRequestCount =
708                 de::max(chainedObjReservation->pipelineCacheRequestCount, 1u);
709 
710             // decode all VkDescriptorSetLayoutCreateInfo
711             std::map<VkDescriptorSetLayout, VkDescriptorSetLayoutCreateInfo> descriptorSetLayoutCreateInfos;
712             for (auto &&descriptorSetLayout : input.descriptorSetLayouts)
713             {
714                 VkDescriptorSetLayoutCreateInfo dsCI{};
715                 readJSON_VkDescriptorSetLayoutCreateInfo(jsonReader, descriptorSetLayout.second, dsCI);
716                 descriptorSetLayoutCreateInfos.insert({descriptorSetLayout.first, dsCI});
717             }
718 
719             chainedObjReservation->descriptorSetLayoutBindingLimit = 1u;
720             for (auto &&dsCI : descriptorSetLayoutCreateInfos)
721                 for (uint32_t i = 0; i < dsCI.second.bindingCount; ++i)
722                     chainedObjReservation->descriptorSetLayoutBindingLimit = de::max(
723                         chainedObjReservation->descriptorSetLayoutBindingLimit, dsCI.second.pBindings[i].binding + 1u);
724 
725             // recreate device extensions
726             vector<const char *> deviceExts;
727             for (auto &&ext : pipeline.deviceExtensions)
728                 deviceExts.push_back(ext.data());
729 
730             const VkDeviceCreateInfo deviceCreateInfo = {
731                 VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,             // sType
732                 pNext,                                            // pNext
733                 (VkDeviceCreateFlags)0u,                          // flags
734                 1,                                                // queueRecordCount
735                 &deviceQueueCreateInfo,                           // pRequestedQueues
736                 0,                                                // layerCount
737                 DE_NULL,                                          // ppEnabledLayerNames
738                 (uint32_t)deviceExts.size(),                      // extensionCount
739                 deviceExts.empty() ? DE_NULL : deviceExts.data(), // ppEnabledExtensionNames
740                 &(chainedFeatures->features)                      // pEnabledFeatures
741             };
742 
743             // create new device
744             pcDevice         = createDevice(vkp, instance, vki, physicalDevice, &deviceCreateInfo);
745             deviceFeatures   = pipeline.deviceFeatures;
746             deviceExtensions = pipeline.deviceExtensions;
747 
748             // create local function pointers required to perform pipeline cache creation
749             getDeviceProcAddrFunc = (GetDeviceProcAddrFunc)vkp.getInstanceProcAddr(instance, "vkGetDeviceProcAddr");
750             createSamplerYcbcrConversionFunc =
751                 (CreateSamplerYcbcrConversionFunc)getDeviceProcAddrFunc(*pcDevice, "vkCreateSamplerYcbcrConversion");
752             destroySamplerYcbcrConversionFunc =
753                 (DestroySamplerYcbcrConversionFunc)getDeviceProcAddrFunc(*pcDevice, "vkDestroySamplerYcbcrConversion");
754             createSamplerFunc      = (CreateSamplerFunc)getDeviceProcAddrFunc(*pcDevice, "vkCreateSampler");
755             destroySamplerFunc     = (DestroySamplerFunc)getDeviceProcAddrFunc(*pcDevice, "vkDestroySampler");
756             createShaderModuleFunc = (CreateShaderModuleFunc)getDeviceProcAddrFunc(*pcDevice, "vkCreateShaderModule");
757             destroyShaderModuleFunc =
758                 (DestroyShaderModuleFunc)getDeviceProcAddrFunc(*pcDevice, "vkDestroyShaderModule");
759             createRenderPassFunc  = (CreateRenderPassFunc)getDeviceProcAddrFunc(*pcDevice, "vkCreateRenderPass");
760             createRenderPass2Func = (CreateRenderPass2Func)getDeviceProcAddrFunc(*pcDevice, "vkCreateRenderPass2");
761             destroyRenderPassFunc = (DestroyRenderPassFunc)getDeviceProcAddrFunc(*pcDevice, "vkDestroyRenderPass");
762             createDescriptorSetLayoutFunc =
763                 (CreateDescriptorSetLayoutFunc)getDeviceProcAddrFunc(*pcDevice, "vkCreateDescriptorSetLayout");
764             destroyDescriptorSetLayoutFunc =
765                 (DestroyDescriptorSetLayoutFunc)getDeviceProcAddrFunc(*pcDevice, "vkDestroyDescriptorSetLayout");
766             createPipelineLayoutFunc =
767                 (CreatePipelineLayoutFunc)getDeviceProcAddrFunc(*pcDevice, "vkCreatePipelineLayout");
768             destroyPipelineLayoutFunc =
769                 (DestroyPipelineLayoutFunc)getDeviceProcAddrFunc(*pcDevice, "vkDestroyPipelineLayout");
770             createGraphicsPipelinesFunc =
771                 (CreateGraphicsPipelinesFunc)getDeviceProcAddrFunc(*pcDevice, "vkCreateGraphicsPipelines");
772             createComputePipelinesFunc =
773                 (CreateComputePipelinesFunc)getDeviceProcAddrFunc(*pcDevice, "vkCreateComputePipelines");
774             createPipelineCacheFunc =
775                 (CreatePipelineCacheFunc)getDeviceProcAddrFunc(*pcDevice, "vkCreatePipelineCache");
776             destroyPipelineCacheFunc =
777                 (DestroyPipelineCacheFunc)getDeviceProcAddrFunc(*pcDevice, "vkDestroyPipelineCache");
778             destroyPipelineFunc = (DestroyPipelineFunc)getDeviceProcAddrFunc(*pcDevice, "vkDestroyPipeline");
779             getPipelineCacheDataFunc =
780                 (GetPipelineCacheDataFunc)getDeviceProcAddrFunc(*pcDevice, "vkGetPipelineCacheData");
781 
782             VK_CHECK(createPipelineCacheFunc(*pcDevice, &pcCI, DE_NULL, &pipelineCache));
783 
784             // decode VkSamplerYcbcrConversionCreateInfo structs and create VkSamplerYcbcrConversions
785             for (auto &&samplerYcbcr : input.samplerYcbcrConversions)
786             {
787                 VkSamplerYcbcrConversionCreateInfo sycCI{};
788                 readJSON_VkSamplerYcbcrConversionCreateInfo(jsonReader, samplerYcbcr.second, sycCI);
789                 VkSamplerYcbcrConversion realConversion;
790                 VK_CHECK(createSamplerYcbcrConversionFunc(*pcDevice, &sycCI, DE_NULL, &realConversion));
791                 falseToRealSamplerYcbcrConversions.insert({samplerYcbcr.first, realConversion});
792             }
793 
794             // decode VkSamplerCreateInfo structs and create VkSamplers
795             for (auto &&sampler : input.samplers)
796             {
797                 VkSamplerCreateInfo sCI{};
798                 readJSON_VkSamplerCreateInfo(jsonReader, sampler.second, sCI);
799 
800                 // replace ycbcr conversions if required
801                 if (sCI.pNext != NULL)
802                 {
803                     if (sCI.pNext != DE_NULL)
804                     {
805                         VkSamplerYcbcrConversionInfo *info = (VkSamplerYcbcrConversionInfo *)(sCI.pNext);
806                         if (info->sType == VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO)
807                         {
808                             auto jt = falseToRealSamplerYcbcrConversions.find(info->conversion);
809                             if (jt == end(falseToRealSamplerYcbcrConversions))
810                                 TCU_THROW(InternalError, "VkSamplerYcbcrConversion not found");
811                             info->conversion = jt->second;
812                         }
813                     }
814                 }
815 
816                 VkSampler realSampler;
817                 VK_CHECK(createSamplerFunc(*pcDevice, &sCI, DE_NULL, &realSampler));
818                 falseToRealSamplers.insert({sampler.first, realSampler});
819             }
820 
821             // decode VkShaderModuleCreateInfo structs and create VkShaderModules
822             for (auto &&shader : input.shaderModules)
823             {
824                 VkShaderModuleCreateInfo smCI{};
825                 std::vector<uint8_t> spirvShader;
826                 readJSON_VkShaderModuleCreateInfo(jsonReader, shader.second, smCI, spirvShader);
827                 VkShaderModule realShaderModule;
828                 VK_CHECK(createShaderModuleFunc(*pcDevice, &smCI, DE_NULL, &realShaderModule));
829                 falseToRealShaderModules.insert({shader.first, realShaderModule});
830             }
831 
832             // decode renderPass structs and create VkRenderPasses
833             for (auto &&renderPass : input.renderPasses)
834             {
835                 if (renderPass.second.find("VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2") != std::string::npos)
836                 {
837                     VkRenderPassCreateInfo2 rpCI{};
838                     readJSON_VkRenderPassCreateInfo2(jsonReader, renderPass.second, rpCI);
839                     VkRenderPass realRenderPass;
840                     VK_CHECK(createRenderPass2Func(*pcDevice, &rpCI, DE_NULL, &realRenderPass));
841                     falseToRealRenderPasses.insert({renderPass.first, realRenderPass});
842                 }
843                 else if (renderPass.second.find("VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO") != std::string::npos)
844                 {
845                     VkRenderPassCreateInfo rpCI{};
846                     readJSON_VkRenderPassCreateInfo(jsonReader, renderPass.second, rpCI);
847                     VkRenderPass realRenderPass;
848                     VK_CHECK(createRenderPassFunc(*pcDevice, &rpCI, DE_NULL, &realRenderPass));
849                     falseToRealRenderPasses.insert({renderPass.first, realRenderPass});
850                 }
851                 else
852                     TCU_THROW(InternalError, "Could not recognize render pass type");
853             }
854 
855             // create VkDescriptorSetLayouts
856             for (auto &&dsCI : descriptorSetLayoutCreateInfos)
857             {
858                 std::vector<VkDescriptorSetLayoutBinding> newDescriptorBindings;
859                 std::vector<std::vector<VkSampler>> realSamplers;
860 
861                 // we have to replace all bindings if there is any immutable sampler defined
862                 bool needReplaceSamplers = false;
863                 for (uint32_t i = 0; i < dsCI.second.bindingCount; ++i)
864                 {
865                     if (dsCI.second.pBindings[i].pImmutableSamplers != DE_NULL)
866                         needReplaceSamplers = true;
867                 }
868 
869                 if (needReplaceSamplers)
870                 {
871                     for (uint32_t i = 0; i < dsCI.second.bindingCount; ++i)
872                     {
873                         if (dsCI.second.pBindings[i].pImmutableSamplers == DE_NULL)
874                         {
875                             newDescriptorBindings.push_back(dsCI.second.pBindings[i]);
876                             continue;
877                         }
878 
879                         realSamplers.push_back(std::vector<VkSampler>(dsCI.second.pBindings[i].descriptorCount));
880                         for (uint32_t j = 0; j < dsCI.second.pBindings[i].descriptorCount; ++j)
881                         {
882                             if (dsCI.second.pBindings[i].pImmutableSamplers[j] == DE_NULL)
883                             {
884                                 realSamplers.back()[j] = DE_NULL;
885                                 continue;
886                             }
887                             else
888                             {
889                                 auto jt = falseToRealSamplers.find(dsCI.second.pBindings[i].pImmutableSamplers[j]);
890                                 if (jt == end(falseToRealSamplers))
891                                     TCU_THROW(InternalError, "VkSampler not found");
892                                 realSamplers.back()[j] = jt->second;
893                             }
894                         }
895                         VkDescriptorSetLayoutBinding bCopy = {
896                             dsCI.second.pBindings[i].binding,         // uint32_t binding;
897                             dsCI.second.pBindings[i].descriptorType,  // VkDescriptorType descriptorType;
898                             dsCI.second.pBindings[i].descriptorCount, // uint32_t descriptorCount;
899                             dsCI.second.pBindings[i].stageFlags,      // VkShaderStageFlags stageFlags;
900                             realSamplers.back().data()                // const VkSampler* pImmutableSamplers;
901                         };
902                         newDescriptorBindings.push_back(bCopy);
903                     }
904                     dsCI.second.pBindings = newDescriptorBindings.data();
905                 }
906 
907                 VkDescriptorSetLayout realDescriptorSetLayout;
908                 VK_CHECK(createDescriptorSetLayoutFunc(*pcDevice, &dsCI.second, DE_NULL, &realDescriptorSetLayout));
909                 falseToRealDescriptorSetLayouts.insert({dsCI.first, realDescriptorSetLayout});
910             }
911 
912             // decode pipeline layout structs and create VkPipelineLayouts. Requires creation of new pSetLayouts to bypass constness
913             for (auto &&pipelineLayout : input.pipelineLayouts)
914             {
915                 VkPipelineLayoutCreateInfo plCI{};
916                 readJSON_VkPipelineLayoutCreateInfo(jsonReader, pipelineLayout.second, plCI);
917                 // replace descriptor set layouts with real ones
918                 std::vector<VkDescriptorSetLayout> newSetLayouts;
919                 for (uint32_t i = 0; i < plCI.setLayoutCount; ++i)
920                 {
921                     auto jt = falseToRealDescriptorSetLayouts.find(plCI.pSetLayouts[i]);
922                     if (jt == end(falseToRealDescriptorSetLayouts))
923                         TCU_THROW(InternalError, "VkDescriptorSetLayout not found");
924                     newSetLayouts.push_back(jt->second);
925                 }
926                 plCI.pSetLayouts = newSetLayouts.data();
927 
928                 VkPipelineLayout realPipelineLayout;
929                 VK_CHECK(createPipelineLayoutFunc(*pcDevice, &plCI, DE_NULL, &realPipelineLayout));
930                 falseToRealPipelineLayouts.insert({pipelineLayout.first, realPipelineLayout});
931             }
932         }
933 
934         // after device creation - start creating pipelines
935         if (pipeline.pipelineContents.find("VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO") != std::string::npos)
936         {
937             VkGraphicsPipelineCreateInfo gpCI{};
938             gpCI.basePipelineHandle = VkPipeline(0);
939             readJSON_VkGraphicsPipelineCreateInfo(jsonReader, pipeline.pipelineContents, gpCI);
940 
941             // set poolEntrySize for pipeline
942             VkPipelineOfflineCreateInfo *offlineCreateInfo = (VkPipelineOfflineCreateInfo *)findStructureInChain(
943                 gpCI.pNext, VK_STRUCTURE_TYPE_PIPELINE_OFFLINE_CREATE_INFO);
944             if (offlineCreateInfo != DE_NULL)
945                 offlineCreateInfo->poolEntrySize = VKSC_DEFAULT_PIPELINE_POOL_SIZE;
946 
947             // replace VkShaderModules with real ones. Requires creation of new pStages to bypass constness
948             std::vector<VkPipelineShaderStageCreateInfo> newStages;
949             for (uint32_t i = 0; i < gpCI.stageCount; ++i)
950             {
951                 VkPipelineShaderStageCreateInfo newStage = gpCI.pStages[i];
952                 auto jt                                  = falseToRealShaderModules.find(gpCI.pStages[i].module);
953                 if (jt == end(falseToRealShaderModules))
954                     TCU_THROW(InternalError, "VkShaderModule not found");
955                 newStage.module = jt->second;
956                 newStages.push_back(newStage);
957             }
958             gpCI.pStages = newStages.data();
959 
960             // replace render pass with a real one
961             {
962                 auto jt = falseToRealRenderPasses.find(gpCI.renderPass);
963                 if (jt == end(falseToRealRenderPasses))
964                     TCU_THROW(InternalError, "VkRenderPass not found");
965                 gpCI.renderPass = jt->second;
966             }
967 
968             // replace pipeline layout with a real one
969             {
970                 auto jt = falseToRealPipelineLayouts.find(gpCI.layout);
971                 if (jt == end(falseToRealPipelineLayouts))
972                     TCU_THROW(InternalError, "VkPipelineLayout not found");
973                 gpCI.layout = jt->second;
974             }
975 
976             VkPipeline gPipeline(0u);
977             VK_CHECK(createGraphicsPipelinesFunc(*pcDevice, pipelineCache, 1, &gpCI, DE_NULL, &gPipeline));
978             // pipeline was added to cache. We may remove it immediately
979             destroyPipelineFunc(*pcDevice, gPipeline, DE_NULL);
980         }
981         else if (pipeline.pipelineContents.find("VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO") != std::string::npos)
982         {
983             VkComputePipelineCreateInfo cpCI{};
984             cpCI.basePipelineHandle = VkPipeline(0);
985             readJSON_VkComputePipelineCreateInfo(jsonReader, pipeline.pipelineContents, cpCI);
986 
987             // set poolEntrySize for pipeline
988             VkPipelineOfflineCreateInfo *offlineCreateInfo = (VkPipelineOfflineCreateInfo *)findStructureInChain(
989                 cpCI.pNext, VK_STRUCTURE_TYPE_PIPELINE_OFFLINE_CREATE_INFO);
990             if (offlineCreateInfo != DE_NULL)
991                 offlineCreateInfo->poolEntrySize = VKSC_DEFAULT_PIPELINE_POOL_SIZE;
992 
993             // replace VkShaderModule with real one
994             {
995                 auto jt = falseToRealShaderModules.find(cpCI.stage.module);
996                 if (jt == end(falseToRealShaderModules))
997                     TCU_THROW(InternalError, "VkShaderModule not found");
998                 cpCI.stage.module = jt->second;
999             }
1000 
1001             // replace pipeline layout with a real one
1002             {
1003                 auto jt = falseToRealPipelineLayouts.find(cpCI.layout);
1004                 if (jt == end(falseToRealPipelineLayouts))
1005                     TCU_THROW(InternalError, "VkPipelineLayout not found");
1006                 cpCI.layout = jt->second;
1007             }
1008 
1009             VkPipeline cPipeline(0u);
1010             VK_CHECK(createComputePipelinesFunc(*pcDevice, pipelineCache, 1, &cpCI, DE_NULL, &cPipeline));
1011             // pipeline was added to cache. We may remove it immediately
1012             destroyPipelineFunc(*pcDevice, cPipeline, DE_NULL);
1013         }
1014         else
1015             TCU_THROW(InternalError, "Could not recognize pipeline type");
1016     }
1017 
1018     if (pcDevice.get() != DE_NULL)
1019     {
1020         // getPipelineCacheData() binary data, store it in m_cacheData
1021         std::size_t cacheSize;
1022         VK_CHECK(getPipelineCacheDataFunc(*pcDevice, pipelineCache, &cacheSize, DE_NULL));
1023         resultCacheData.resize(cacheSize);
1024         VK_CHECK(getPipelineCacheDataFunc(*pcDevice, pipelineCache, &cacheSize, resultCacheData.data()));
1025 
1026         // clean up resources - in ResourceInterfaceStandard we just simulate Vulkan SC driver after all...
1027         for (auto &&it : falseToRealPipelineLayouts)
1028             destroyPipelineLayoutFunc(*pcDevice, it.second, DE_NULL);
1029         for (auto &&it : falseToRealDescriptorSetLayouts)
1030             destroyDescriptorSetLayoutFunc(*pcDevice, it.second, DE_NULL);
1031         for (auto &&it : falseToRealRenderPasses)
1032             destroyRenderPassFunc(*pcDevice, it.second, DE_NULL);
1033         for (auto &&it : falseToRealShaderModules)
1034             destroyShaderModuleFunc(*pcDevice, it.second, DE_NULL);
1035         for (auto &&it : falseToRealSamplers)
1036             destroySamplerFunc(*pcDevice, it.second, DE_NULL);
1037         for (auto &&it : falseToRealSamplerYcbcrConversions)
1038             destroySamplerYcbcrConversionFunc(*pcDevice, it.second, DE_NULL);
1039 
1040         destroyPipelineCacheFunc(*pcDevice, pipelineCache, DE_NULL);
1041     }
1042 
1043     return resultCacheData;
1044 }
1045 
extractSizesFromPipelineCache(const VulkanPipelineCacheInput & input,const vector<u8> & pipelineCache,uint32_t pipelineDefaultSize,bool recyclePipelineMemory)1046 std::vector<VulkanPipelineSize> extractSizesFromPipelineCache(const VulkanPipelineCacheInput &input,
1047                                                               const vector<u8> &pipelineCache,
1048                                                               uint32_t pipelineDefaultSize, bool recyclePipelineMemory)
1049 {
1050     std::vector<VulkanPipelineSize> result;
1051     if (input.pipelines.empty())
1052         return result;
1053     VKSCPipelineCacheHeaderReader pcr(pipelineCache.size(), pipelineCache.data());
1054     if (pcr.isValid())
1055     {
1056         for (uint32_t p = 0; p < pcr.getPipelineIndexCount(); ++p)
1057         {
1058             const VkPipelineCacheSafetyCriticalIndexEntry *pie = pcr.getPipelineIndexEntry(p);
1059             if (nullptr != pie)
1060             {
1061                 VulkanPipelineSize pipelineSize;
1062                 pipelineSize.id = resetPipelineOfflineCreateInfo();
1063                 for (uint32_t i = 0; i < VK_UUID_SIZE; ++i)
1064                     pipelineSize.id.pipelineIdentifier[i] = pie->pipelineIdentifier[i];
1065                 pipelineSize.size  = uint32_t(pie->pipelineMemorySize);
1066                 pipelineSize.count = 0u;
1067                 auto it            = std::find_if(begin(input.pipelines), end(input.pipelines),
1068                                                   vksc_server::PipelineIdentifierEqual(pipelineSize.id));
1069                 if (it != end(input.pipelines))
1070                 {
1071                     if (recyclePipelineMemory)
1072                         pipelineSize.count = it->maxCount;
1073                     else // you'd better have enough memory...
1074                         pipelineSize.count = it->allCount;
1075                 }
1076                 result.emplace_back(pipelineSize);
1077             }
1078         }
1079     }
1080     else // ordinary Vulkan pipeline. Declare all pipeline sizes as equal to pipelineDefaultSize
1081     {
1082         for (uint32_t p = 0; p < input.pipelines.size(); ++p)
1083         {
1084             VulkanPipelineSize pipelineSize;
1085             pipelineSize.id = resetPipelineOfflineCreateInfo();
1086             for (uint32_t i = 0; i < VK_UUID_SIZE; ++i)
1087                 pipelineSize.id.pipelineIdentifier[i] = input.pipelines[p].id.pipelineIdentifier[i];
1088             pipelineSize.size = pipelineDefaultSize;
1089             if (recyclePipelineMemory)
1090                 pipelineSize.count = input.pipelines[p].maxCount;
1091             else // you'd better have enough memory...
1092                 pipelineSize.count = input.pipelines[p].allCount;
1093             result.emplace_back(pipelineSize);
1094         }
1095     }
1096 
1097     return result;
1098 }
1099 
1100 } // namespace vksc_server
1101