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