• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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