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