blob: 83f4a015ec6dc5b402da536ec5a0d02d15cfb4a9 [file] [log] [blame]
/*-------------------------------------------------------------------------
* Vulkan CTS Framework
* --------------------
*
* Copyright (c) 2021 The Khronos Group Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*-------------------------------------------------------------------------*/
#include "vksCacheBuilder.hpp"
#include "pcreader.hpp"
#include "vksJson.hpp"
#include <fstream>
// Currently CTS does not use C++17, so universal method of deleting files from directory has been commented out
//#include <filesystem>
#include "vkRefUtil.hpp"
#include "vkQueryUtil.hpp"
#include "deDirectoryIterator.hpp"
#include "deFile.h"
#include "vkSafetyCriticalUtil.hpp"
namespace vk
{
typedef VKAPI_ATTR VkResult(VKAPI_CALL *CreateSamplerYcbcrConversionFunc)(
VkDevice device, const VkSamplerYcbcrConversionCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator,
VkSamplerYcbcrConversion *pYcbcrConversion);
typedef VKAPI_ATTR void(VKAPI_CALL *DestroySamplerYcbcrConversionFunc)(VkDevice device,
VkSamplerYcbcrConversion ycbcrConversion,
const VkAllocationCallbacks *pAllocator);
typedef VKAPI_ATTR VkResult(VKAPI_CALL *CreateSamplerFunc)(VkDevice device, const VkSamplerCreateInfo *pCreateInfo,
const VkAllocationCallbacks *pAllocator,
VkSampler *pSampler);
typedef VKAPI_ATTR void(VKAPI_CALL *DestroySamplerFunc)(VkDevice device, VkSampler sampler,
const VkAllocationCallbacks *pAllocator);
typedef VKAPI_ATTR VkResult(VKAPI_CALL *CreateShaderModuleFunc)(VkDevice device,
const VkShaderModuleCreateInfo *pCreateInfo,
const VkAllocationCallbacks *pAllocator,
VkShaderModule *pShaderModule);
typedef VKAPI_ATTR void(VKAPI_CALL *DestroyShaderModuleFunc)(VkDevice device, VkShaderModule shaderModule,
const VkAllocationCallbacks *pAllocator);
typedef VKAPI_ATTR VkResult(VKAPI_CALL *CreateRenderPassFunc)(VkDevice device,
const VkRenderPassCreateInfo *pCreateInfo,
const VkAllocationCallbacks *pAllocator,
VkRenderPass *pRenderPass);
typedef VKAPI_ATTR VkResult(VKAPI_CALL *CreateRenderPass2Func)(VkDevice device,
const VkRenderPassCreateInfo2 *pCreateInfo,
const VkAllocationCallbacks *pAllocator,
VkRenderPass *pRenderPass);
typedef VKAPI_ATTR void(VKAPI_CALL *DestroyRenderPassFunc)(VkDevice device, VkRenderPass renderPass,
const VkAllocationCallbacks *pAllocator);
typedef VKAPI_ATTR VkResult(VKAPI_CALL *CreateDescriptorSetLayoutFunc)(
VkDevice device, const VkDescriptorSetLayoutCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator,
VkDescriptorSetLayout *pSetLayout);
typedef VKAPI_ATTR void(VKAPI_CALL *DestroyDescriptorSetLayoutFunc)(VkDevice device,
VkDescriptorSetLayout descriptorSetLayout,
const VkAllocationCallbacks *pAllocator);
typedef VKAPI_ATTR VkResult(VKAPI_CALL *CreatePipelineLayoutFunc)(VkDevice device,
const VkPipelineLayoutCreateInfo *pCreateInfo,
const VkAllocationCallbacks *pAllocator,
VkPipelineLayout *pPipelineLayout);
typedef VKAPI_ATTR void(VKAPI_CALL *DestroyPipelineLayoutFunc)(VkDevice device, VkPipelineLayout pipelineLayout,
const VkAllocationCallbacks *pAllocator);
typedef VKAPI_ATTR VkResult(VKAPI_CALL *CreateGraphicsPipelinesFunc)(VkDevice device, VkPipelineCache pipelineCache,
uint32_t createInfoCount,
const VkGraphicsPipelineCreateInfo *pCreateInfos,
const VkAllocationCallbacks *pAllocator,
VkPipeline *pPipelines);
typedef VKAPI_ATTR VkResult(VKAPI_CALL *CreateComputePipelinesFunc)(VkDevice device, VkPipelineCache pipelineCache,
uint32_t createInfoCount,
const VkComputePipelineCreateInfo *pCreateInfos,
const VkAllocationCallbacks *pAllocator,
VkPipeline *pPipelines);
typedef VKAPI_ATTR void(VKAPI_CALL *DestroyPipelineFunc)(VkDevice device, VkPipeline pipeline,
const VkAllocationCallbacks *pAllocator);
typedef VKAPI_ATTR VkResult(VKAPI_CALL *CreatePipelineCacheFunc)(VkDevice device,
const VkPipelineCacheCreateInfo *pCreateInfo,
const VkAllocationCallbacks *pAllocator,
VkPipelineCache *pPipelineCache);
typedef VKAPI_ATTR void(VKAPI_CALL *DestroyPipelineCacheFunc)(VkDevice device, VkPipelineCache pipelineCache,
const VkAllocationCallbacks *pAllocator);
typedef VKAPI_ATTR VkResult(VKAPI_CALL *GetPipelineCacheDataFunc)(VkDevice device, VkPipelineCache pipelineCache,
uintptr_t *pDataSize, void *pData);
} // namespace vk
namespace vksc_server
{
const VkDeviceSize VKSC_DEFAULT_PIPELINE_POOL_SIZE = 2u * 1024u * 1024u;
void exportFilesForExternalCompiler(const VulkanPipelineCacheInput &input, const std::string &path,
const std::string &filePrefix)
{
// unpack JSON data to track relations between objects
using namespace vk;
using namespace json;
Context jsonReader;
std::map<VkSamplerYcbcrConversion, VkSamplerYcbcrConversionCreateInfo> allSamplerYcbcrConversions;
for (auto &&samplerYcbcr : input.samplerYcbcrConversions)
{
VkSamplerYcbcrConversionCreateInfo sycCI{};
readJSON_VkSamplerYcbcrConversionCreateInfo(jsonReader, samplerYcbcr.second, sycCI);
allSamplerYcbcrConversions.insert({samplerYcbcr.first, sycCI});
}
std::map<VkSampler, VkSamplerCreateInfo> allSamplers;
for (auto &&sampler : input.samplers)
{
VkSamplerCreateInfo sCI{};
readJSON_VkSamplerCreateInfo(jsonReader, sampler.second, sCI);
allSamplers.insert({sampler.first, sCI});
}
std::map<VkShaderModule, VkShaderModuleCreateInfo> allShaderModules;
std::map<VkShaderModule, std::vector<uint8_t>> allSpirvShaders;
for (auto &&shader : input.shaderModules)
{
VkShaderModuleCreateInfo smCI{};
std::vector<uint8_t> spirvShader;
readJSON_VkShaderModuleCreateInfo(jsonReader, shader.second, smCI, spirvShader);
allShaderModules.insert({shader.first, smCI});
allSpirvShaders.insert({shader.first, spirvShader});
}
std::map<VkRenderPass, VkRenderPassCreateInfo> allRenderPasses;
std::map<VkRenderPass, VkRenderPassCreateInfo2> allRenderPasses2;
for (auto &&renderPass : input.renderPasses)
{
if (renderPass.second.find("VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2") != std::string::npos)
{
VkRenderPassCreateInfo2 rpCI{};
readJSON_VkRenderPassCreateInfo2(jsonReader, renderPass.second, rpCI);
allRenderPasses2.insert({renderPass.first, rpCI});
}
else if (renderPass.second.find("VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO") != std::string::npos)
{
VkRenderPassCreateInfo rpCI{};
readJSON_VkRenderPassCreateInfo(jsonReader, renderPass.second, rpCI);
allRenderPasses.insert({renderPass.first, rpCI});
}
else
TCU_THROW(InternalError, "Could not recognize render pass type");
}
std::map<VkDescriptorSetLayout, VkDescriptorSetLayoutCreateInfo> allDescriptorSetLayouts;
for (auto &&descriptorSetLayout : input.descriptorSetLayouts)
{
VkDescriptorSetLayoutCreateInfo dsCI{};
readJSON_VkDescriptorSetLayoutCreateInfo(jsonReader, descriptorSetLayout.second, dsCI);
allDescriptorSetLayouts.insert({descriptorSetLayout.first, dsCI});
}
std::map<VkPipelineLayout, VkPipelineLayoutCreateInfo> allPipelineLayouts;
for (auto &&pipelineLayout : input.pipelineLayouts)
{
VkPipelineLayoutCreateInfo plCI{};
readJSON_VkPipelineLayoutCreateInfo(jsonReader, pipelineLayout.second, plCI);
allPipelineLayouts.insert({pipelineLayout.first, plCI});
}
uint32_t exportedPipelines = 0;
for (auto &&pipeline : input.pipelines)
{
// filter objects used for this specific pipeline ( graphics or compute )
std::map<VkSamplerYcbcrConversion, VkSamplerYcbcrConversionCreateInfo> samplerYcbcrConversions;
std::map<VkSampler, VkSamplerCreateInfo> samplers;
std::map<VkShaderModule, VkShaderModuleCreateInfo> shaderModules;
std::map<VkShaderModule, std::vector<uint8_t>> spirvShaders;
std::map<VkRenderPass, VkRenderPassCreateInfo> renderPasses;
std::map<VkRenderPass, VkRenderPassCreateInfo2> renderPasses2;
std::map<VkDescriptorSetLayout, VkDescriptorSetLayoutCreateInfo> descriptorSetLayouts;
std::map<VkPipelineLayout, VkPipelineLayoutCreateInfo> pipelineLayouts;
if (pipeline.pipelineContents.find("VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO") != std::string::npos)
{
VkGraphicsPipelineCreateInfo gpCI{};
readJSON_VkGraphicsPipelineCreateInfo(jsonReader, pipeline.pipelineContents, gpCI);
// copy all used shaders
for (uint32_t i = 0; i < gpCI.stageCount; ++i)
{
auto it = allShaderModules.find(gpCI.pStages[i].module);
if (it == end(allShaderModules))
TCU_THROW(InternalError, "Could not find shader module");
shaderModules.insert(*it);
auto it2 = allSpirvShaders.find(gpCI.pStages[i].module);
if (it2 == end(allSpirvShaders))
TCU_THROW(InternalError, "Could not find shader");
spirvShaders.insert(*it2);
}
// copy render pass
{
auto it = allRenderPasses.find(gpCI.renderPass);
if (it == end(allRenderPasses))
{
auto it2 = allRenderPasses2.find(gpCI.renderPass);
if (it2 == end(allRenderPasses2))
TCU_THROW(InternalError, "Could not find render pass");
else
renderPasses2.insert(*it2);
}
else
renderPasses.insert(*it);
}
// copy pipeline layout
{
auto it = allPipelineLayouts.find(gpCI.layout);
if (it == end(allPipelineLayouts))
TCU_THROW(InternalError, "Could not find pipeline layout");
pipelineLayouts.insert(*it);
// copy descriptor set layouts
for (uint32_t i = 0; i < it->second.setLayoutCount; ++i)
{
auto it2 = allDescriptorSetLayouts.find(it->second.pSetLayouts[i]);
if (it2 == end(allDescriptorSetLayouts))
TCU_THROW(InternalError, "Could not find descriptor set layout");
descriptorSetLayouts.insert({it2->first, it2->second});
// copy samplers
for (uint32_t j = 0; j < it2->second.bindingCount; ++j)
{
if (it2->second.pBindings[j].pImmutableSamplers != DE_NULL)
{
for (uint32_t k = 0; k < it2->second.pBindings[j].descriptorCount; ++k)
{
auto it3 = allSamplers.find(it2->second.pBindings[j].pImmutableSamplers[k]);
if (it3 == end(allSamplers))
TCU_THROW(InternalError, "Could not find sampler");
samplers.insert({it3->first, it3->second});
// copy sampler YcbcrConversion
if (it3->second.pNext != DE_NULL)
{
VkSamplerYcbcrConversionInfo *info =
(VkSamplerYcbcrConversionInfo *)findStructureInChain(
it3->second.pNext, VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO);
if (info->sType == VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO)
{
auto it4 = allSamplerYcbcrConversions.find(info->conversion);
if (it4 == end(allSamplerYcbcrConversions))
TCU_THROW(InternalError, "Could not find VkSamplerYcbcrConversion");
samplerYcbcrConversions.insert({it4->first, it4->second});
}
}
}
}
}
}
}
vk::VkPhysicalDeviceFeatures2 deviceFeatures2;
readJSON_VkPhysicalDeviceFeatures2(jsonReader, pipeline.deviceFeatures, deviceFeatures2);
// export shaders and objects to JSON compatible with https://schema.khronos.org/vulkan/vkpcc.json
std::string gpTxt = writeJSON_GraphicsPipeline_vkpccjson(
filePrefix, exportedPipelines, pipeline.id, gpCI, deviceFeatures2, pipeline.deviceExtensions,
samplerYcbcrConversions, samplers, descriptorSetLayouts, renderPasses, renderPasses2, pipelineLayouts);
std::stringstream fileName;
#ifdef _WIN32
fileName << path << "\\" << filePrefix << "graphics_pipeline_" << exportedPipelines << ".json";
#else
fileName << path << "/" << filePrefix << "graphics_pipeline_" << exportedPipelines << ".json";
#endif
{
std::ofstream oFile(fileName.str().c_str(), std::ios::out);
oFile << gpTxt;
}
for (uint32_t j = 0; j < gpCI.stageCount; ++j)
{
std::stringstream shaderName;
#ifdef _WIN32
shaderName << path << "\\" << filePrefix << "shader_" << exportedPipelines << "_"
<< gpCI.pStages[j].module.getInternal() << ".";
#else
shaderName << path << "/" << filePrefix << "shader_" << exportedPipelines << "_"
<< gpCI.pStages[j].module.getInternal() << ".";
#endif
switch (gpCI.pStages[j].stage)
{
case VK_SHADER_STAGE_VERTEX_BIT:
shaderName << "vert";
break;
case VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT:
shaderName << "tesc";
break;
case VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT:
shaderName << "tese";
break;
case VK_SHADER_STAGE_GEOMETRY_BIT:
shaderName << "geom";
break;
case VK_SHADER_STAGE_FRAGMENT_BIT:
shaderName << "frag";
break;
default:
TCU_THROW(InternalError, "Unrecognized shader stage");
}
shaderName << ".spv";
auto sit = spirvShaders.find(gpCI.pStages[j].module);
if (sit == end(spirvShaders))
TCU_THROW(InternalError, "SPIR-V shader not found");
std::ofstream oFile(shaderName.str().c_str(), std::ios::out | std::ios::binary);
oFile.write((const char *)sit->second.data(), sit->second.size());
}
exportedPipelines++;
}
else if (pipeline.pipelineContents.find("VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO") != std::string::npos)
{
VkComputePipelineCreateInfo cpCI{};
readJSON_VkComputePipelineCreateInfo(jsonReader, pipeline.pipelineContents, cpCI);
// copy shader
{
auto it = allShaderModules.find(cpCI.stage.module);
if (it == end(allShaderModules))
TCU_THROW(InternalError, "Could not find shader module");
shaderModules.insert(*it);
auto it2 = allSpirvShaders.find(cpCI.stage.module);
if (it2 == end(allSpirvShaders))
TCU_THROW(InternalError, "Could not find shader");
spirvShaders.insert(*it2);
}
// copy pipeline layout
{
auto it = allPipelineLayouts.find(cpCI.layout);
if (it == end(allPipelineLayouts))
TCU_THROW(InternalError, "Could not find pipeline layout");
pipelineLayouts.insert(*it);
// copy descriptor set layouts
for (uint32_t i = 0; i < it->second.setLayoutCount; ++i)
{
auto it2 = allDescriptorSetLayouts.find(it->second.pSetLayouts[i]);
if (it2 == end(allDescriptorSetLayouts))
TCU_THROW(InternalError, "Could not find descriptor set layout");
descriptorSetLayouts.insert({it2->first, it2->second});
// copy samplers
for (uint32_t j = 0; j < it2->second.bindingCount; ++j)
{
if (it2->second.pBindings[j].pImmutableSamplers != DE_NULL)
{
for (uint32_t k = 0; k < it2->second.pBindings[j].descriptorCount; ++k)
{
auto it3 = allSamplers.find(it2->second.pBindings[j].pImmutableSamplers[k]);
if (it3 == end(allSamplers))
TCU_THROW(InternalError, "Could not find sampler");
samplers.insert({it3->first, it3->second});
// copy sampler YcbcrConversion
if (it3->second.pNext != DE_NULL)
{
VkSamplerYcbcrConversionInfo *info =
(VkSamplerYcbcrConversionInfo *)(it3->second.pNext);
if (info->sType == VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO)
{
auto it4 = allSamplerYcbcrConversions.find(info->conversion);
if (it4 == end(allSamplerYcbcrConversions))
TCU_THROW(InternalError, "Could not find VkSamplerYcbcrConversion");
samplerYcbcrConversions.insert({it4->first, it4->second});
}
}
}
}
}
}
}
vk::VkPhysicalDeviceFeatures2 deviceFeatures2;
readJSON_VkPhysicalDeviceFeatures2(jsonReader, pipeline.deviceFeatures, deviceFeatures2);
// export shaders and objects to JSON compatible with https://schema.khronos.org/vulkan/vkpcc.json
std::string cpTxt = writeJSON_ComputePipeline_vkpccjson(
filePrefix, exportedPipelines, pipeline.id, cpCI, deviceFeatures2, pipeline.deviceExtensions,
samplerYcbcrConversions, samplers, descriptorSetLayouts, pipelineLayouts);
std::stringstream fileName;
#ifdef _WIN32
fileName << path << "\\" << filePrefix << "compute_pipeline_" << exportedPipelines << ".json";
#else
fileName << path << "/" << filePrefix << "compute_pipeline_" << exportedPipelines << ".json";
#endif
{
std::ofstream oFile(fileName.str().c_str(), std::ios::out);
oFile << cpTxt;
}
{
std::stringstream shaderName;
#ifdef _WIN32
shaderName << path << "\\" << filePrefix << "shader_" << exportedPipelines << "_"
<< cpCI.stage.module.getInternal() << ".";
#else
shaderName << path << "/" << filePrefix << "shader_" << exportedPipelines << "_"
<< cpCI.stage.module.getInternal() << ".";
#endif
switch (cpCI.stage.stage)
{
case VK_SHADER_STAGE_COMPUTE_BIT:
shaderName << "comp";
break;
default:
TCU_THROW(InternalError, "Unrecognized shader stage");
}
shaderName << ".spv";
auto sit = spirvShaders.find(cpCI.stage.module);
if (sit == end(spirvShaders))
TCU_THROW(InternalError, "SPIR-V shader not found");
std::ofstream oFile(shaderName.str().c_str(), std::ios::out | std::ios::binary);
oFile.write((const char *)sit->second.data(), sit->second.size());
}
exportedPipelines++;
}
}
}
// This is function prototype for creating pipeline cache using offline pipeline compiler
vector<u8> 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)
{
if (!deFileExists(pipelineCompilerPath.c_str()))
TCU_THROW(InternalError, std::string("Can't find pipeline compiler") + pipelineCompilerPath);
// Remove all files from output directory
for (de::DirectoryIterator iter(pipelineCompilerDataDir); iter.hasItem(); iter.next())
{
const de::FilePath filePath = iter.getItem();
if (filePath.getType() != de::FilePath::TYPE_FILE)
continue;
if (!pipelineCompilerFilePrefix.empty() && filePath.getBaseName().find(pipelineCompilerFilePrefix) != 0)
continue;
deDeleteFile(filePath.getPath());
}
// export new files
exportFilesForExternalCompiler(input, pipelineCompilerDataDir, pipelineCompilerFilePrefix);
if (input.pipelines.size() == 0)
return vector<u8>();
// run offline pipeline compiler
{
std::stringstream compilerCommand;
compilerCommand << pipelineCompilerPath << " --path " << pipelineCompilerDataDir << " --out "
<< pipelineCompilerOutputFile;
if (!pipelineCompilerLogFile.empty())
compilerCommand << " --log " << pipelineCompilerLogFile;
if (!pipelineCompilerFilePrefix.empty())
compilerCommand << " --prefix " << pipelineCompilerFilePrefix;
if (!pipelineCompilerArgs.empty())
compilerCommand << " " << pipelineCompilerArgs;
std::string command = compilerCommand.str();
int returnValue = system(command.c_str());
// offline pipeline compiler returns EXIT_SUCCESS on success
if (returnValue != EXIT_SUCCESS)
{
TCU_THROW(InternalError, "offline pipeline compilation failed");
}
}
// read created pipeline cache into result vector
vector<u8> result;
{
std::ifstream iFile(pipelineCompilerOutputFile.c_str(), std::ios::in | std::ios::binary);
if (!iFile)
TCU_THROW(InternalError, (std::string("Cannot open file ") + pipelineCompilerOutputFile).c_str());
auto fileBegin = iFile.tellg();
iFile.seekg(0, std::ios::end);
auto fileEnd = iFile.tellg();
iFile.seekg(0, std::ios::beg);
std::size_t fileSize = static_cast<std::size_t>(fileEnd - fileBegin);
if (fileSize > 0)
{
result.resize(fileSize);
iFile.read(reinterpret_cast<char *>(result.data()), fileSize);
if (iFile.fail())
TCU_THROW(InternalError, (std::string("Cannot load file ") + pipelineCompilerOutputFile).c_str());
}
}
return result;
}
vector<u8> buildPipelineCache(const VulkanPipelineCacheInput &input, const vk::PlatformInterface &vkp,
vk::VkInstance instance, const vk::InstanceInterface &vki,
vk::VkPhysicalDevice physicalDevice, uint32_t queueIndex)
{
using namespace vk;
using namespace json;
Context jsonReader;
// sort pipelines by device features and extensions
std::vector<VulkanJsonPipelineDescription> pipelines = input.pipelines;
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;
});
std::string deviceFeatures = "<empty>";
std::vector<std::string> deviceExtensions = {"<empty>"};
Move<VkDevice> pcDevice;
VkPipelineCache pipelineCache;
vector<u8> resultCacheData;
GetDeviceProcAddrFunc getDeviceProcAddrFunc = DE_NULL;
CreateSamplerYcbcrConversionFunc createSamplerYcbcrConversionFunc = DE_NULL;
DestroySamplerYcbcrConversionFunc destroySamplerYcbcrConversionFunc = DE_NULL;
CreateSamplerFunc createSamplerFunc = DE_NULL;
DestroySamplerFunc destroySamplerFunc = DE_NULL;
CreateShaderModuleFunc createShaderModuleFunc = DE_NULL;
DestroyShaderModuleFunc destroyShaderModuleFunc = DE_NULL;
CreateRenderPassFunc createRenderPassFunc = DE_NULL;
CreateRenderPass2Func createRenderPass2Func = DE_NULL;
DestroyRenderPassFunc destroyRenderPassFunc = DE_NULL;
CreateDescriptorSetLayoutFunc createDescriptorSetLayoutFunc = DE_NULL;
DestroyDescriptorSetLayoutFunc destroyDescriptorSetLayoutFunc = DE_NULL;
CreatePipelineLayoutFunc createPipelineLayoutFunc = DE_NULL;
DestroyPipelineLayoutFunc destroyPipelineLayoutFunc = DE_NULL;
CreateGraphicsPipelinesFunc createGraphicsPipelinesFunc = DE_NULL;
CreateComputePipelinesFunc createComputePipelinesFunc = DE_NULL;
CreatePipelineCacheFunc createPipelineCacheFunc = DE_NULL;
DestroyPipelineCacheFunc destroyPipelineCacheFunc = DE_NULL;
DestroyPipelineFunc destroyPipelineFunc = DE_NULL;
GetPipelineCacheDataFunc getPipelineCacheDataFunc = DE_NULL;
std::map<VkSamplerYcbcrConversion, VkSamplerYcbcrConversion> falseToRealSamplerYcbcrConversions;
std::map<VkSampler, VkSampler> falseToRealSamplers;
std::map<VkShaderModule, VkShaderModule> falseToRealShaderModules;
std::map<VkRenderPass, VkRenderPass> falseToRealRenderPasses;
std::map<VkDescriptorSetLayout, VkDescriptorSetLayout> falseToRealDescriptorSetLayouts;
std::map<VkPipelineLayout, VkPipelineLayout> falseToRealPipelineLayouts;
// decode VkGraphicsPipelineCreateInfo and VkComputePipelineCreateInfo structs and create VkPipelines with a given pipeline cache
for (auto &&pipeline : pipelines)
{
// check if we need to create new device
if (pcDevice.get() == DE_NULL || deviceFeatures != pipeline.deviceFeatures ||
deviceExtensions != pipeline.deviceExtensions)
{
// remove old device
if (pcDevice.get() != DE_NULL)
{
// collect cache data
std::size_t cacheSize;
VK_CHECK(getPipelineCacheDataFunc(*pcDevice, pipelineCache, &cacheSize, DE_NULL));
resultCacheData.resize(cacheSize);
VK_CHECK(getPipelineCacheDataFunc(*pcDevice, pipelineCache, &cacheSize, resultCacheData.data()));
// clean up resources - in ResourceInterfaceStandard we just simulate Vulkan SC driver after all...
for (auto &&it : falseToRealPipelineLayouts)
destroyPipelineLayoutFunc(*pcDevice, it.second, DE_NULL);
for (auto &&it : falseToRealDescriptorSetLayouts)
destroyDescriptorSetLayoutFunc(*pcDevice, it.second, DE_NULL);
for (auto &&it : falseToRealRenderPasses)
destroyRenderPassFunc(*pcDevice, it.second, DE_NULL);
for (auto &&it : falseToRealShaderModules)
destroyShaderModuleFunc(*pcDevice, it.second, DE_NULL);
for (auto &&it : falseToRealSamplers)
destroySamplerFunc(*pcDevice, it.second, DE_NULL);
for (auto &&it : falseToRealSamplerYcbcrConversions)
destroySamplerYcbcrConversionFunc(*pcDevice, it.second, DE_NULL);
destroyPipelineCacheFunc(*pcDevice, pipelineCache, DE_NULL);
// clear maps
falseToRealSamplerYcbcrConversions.clear();
falseToRealSamplers.clear();
falseToRealShaderModules.clear();
falseToRealRenderPasses.clear();
falseToRealDescriptorSetLayouts.clear();
falseToRealPipelineLayouts.clear();
// remove device
pcDevice = Move<VkDevice>();
}
// create new device with proper features and extensions
const float queuePriority = 1.0f;
const VkDeviceQueueCreateInfo deviceQueueCreateInfo = {
VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
DE_NULL,
(VkDeviceQueueCreateFlags)0u,
queueIndex, //queueFamilyIndex;
1, //queueCount;
&queuePriority, //pQueuePriorities;
};
// recreate pNext chain. Add required Vulkan SC objects if they're missing
void *pNextChain = readJSON_pNextChain(jsonReader, pipeline.deviceFeatures);
VkPhysicalDeviceFeatures2 *chainedFeatures = (VkPhysicalDeviceFeatures2 *)findStructureInChain(
pNextChain, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2);
VkPhysicalDeviceFeatures2 localFeatures = initVulkanStructure();
VkDeviceObjectReservationCreateInfo *chainedObjReservation =
(VkDeviceObjectReservationCreateInfo *)findStructureInChain(
pNextChain, VK_STRUCTURE_TYPE_DEVICE_OBJECT_RESERVATION_CREATE_INFO);
VkDeviceObjectReservationCreateInfo localObjReservation = resetDeviceObjectReservationCreateInfo();
VkPhysicalDeviceVulkanSC10Features *chainedSC10Features =
(VkPhysicalDeviceVulkanSC10Features *)findStructureInChain(
pNextChain, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_SC_1_0_FEATURES);
VkPhysicalDeviceVulkanSC10Features localSC10Features = createDefaultSC10Features();
void *pNext = pNextChain;
if (chainedFeatures == DE_NULL)
{
chainedFeatures = &localFeatures;
localFeatures.pNext = pNext;
pNext = &localFeatures;
}
if (chainedObjReservation == DE_NULL)
{
chainedObjReservation = &localObjReservation;
localObjReservation.pNext = pNext;
pNext = &localObjReservation;
}
if (chainedSC10Features == DE_NULL)
{
chainedSC10Features = &localSC10Features;
localSC10Features.pNext = pNext;
pNext = &localSC10Features;
}
uint32_t gPipelineCount = 0U;
uint32_t cPipelineCount = 0U;
for (auto &&pipeline2 : pipelines)
{
if (pipeline2.deviceFeatures != pipeline.deviceFeatures ||
pipeline2.deviceExtensions != pipeline.deviceExtensions)
continue;
if (pipeline2.pipelineContents.find("VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO") !=
std::string::npos)
gPipelineCount++;
else if (pipeline2.pipelineContents.find("VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO") !=
std::string::npos)
cPipelineCount++;
}
// declare pipeline pool size
VkPipelinePoolSize poolSize = {
VK_STRUCTURE_TYPE_PIPELINE_POOL_SIZE, // VkStructureType sType;
DE_NULL, // const void* pNext;
VKSC_DEFAULT_PIPELINE_POOL_SIZE, // VkDeviceSize poolEntrySize;
gPipelineCount + cPipelineCount // uint32_t poolEntryCount;
};
chainedObjReservation->pipelinePoolSizeCount = 1u;
chainedObjReservation->pPipelinePoolSizes = &poolSize;
// declare pipeline cache
VkPipelineCacheCreateInfo pcCI = {
VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
(VkPipelineCacheCreateFlags)0u, // VkPipelineCacheCreateFlags flags;
resultCacheData.size(), // size_t initialDataSize;
resultCacheData.empty() ? DE_NULL : resultCacheData.data() // const void* pInitialData;
};
chainedObjReservation->pipelineCacheCreateInfoCount = 1u;
chainedObjReservation->pPipelineCacheCreateInfos = &pcCI;
chainedObjReservation->pipelineLayoutRequestCount =
de::max(chainedObjReservation->pipelineLayoutRequestCount, uint32_t(input.pipelineLayouts.size()));
chainedObjReservation->renderPassRequestCount =
de::max(chainedObjReservation->renderPassRequestCount, uint32_t(input.renderPasses.size()));
chainedObjReservation->graphicsPipelineRequestCount =
de::max(chainedObjReservation->graphicsPipelineRequestCount, gPipelineCount);
chainedObjReservation->computePipelineRequestCount =
de::max(chainedObjReservation->computePipelineRequestCount, cPipelineCount);
chainedObjReservation->descriptorSetLayoutRequestCount = de::max(
chainedObjReservation->descriptorSetLayoutRequestCount, uint32_t(input.descriptorSetLayouts.size()));
chainedObjReservation->samplerRequestCount =
de::max(chainedObjReservation->samplerRequestCount, uint32_t(input.samplers.size()));
chainedObjReservation->samplerYcbcrConversionRequestCount =
de::max(chainedObjReservation->samplerYcbcrConversionRequestCount,
uint32_t(input.samplerYcbcrConversions.size()));
chainedObjReservation->pipelineCacheRequestCount =
de::max(chainedObjReservation->pipelineCacheRequestCount, 1u);
// decode all VkDescriptorSetLayoutCreateInfo
std::map<VkDescriptorSetLayout, VkDescriptorSetLayoutCreateInfo> descriptorSetLayoutCreateInfos;
for (auto &&descriptorSetLayout : input.descriptorSetLayouts)
{
VkDescriptorSetLayoutCreateInfo dsCI{};
readJSON_VkDescriptorSetLayoutCreateInfo(jsonReader, descriptorSetLayout.second, dsCI);
descriptorSetLayoutCreateInfos.insert({descriptorSetLayout.first, dsCI});
}
chainedObjReservation->descriptorSetLayoutBindingLimit = 1u;
for (auto &&dsCI : descriptorSetLayoutCreateInfos)
for (uint32_t i = 0; i < dsCI.second.bindingCount; ++i)
chainedObjReservation->descriptorSetLayoutBindingLimit = de::max(
chainedObjReservation->descriptorSetLayoutBindingLimit, dsCI.second.pBindings[i].binding + 1u);
// recreate device extensions
vector<const char *> deviceExts;
for (auto &&ext : pipeline.deviceExtensions)
deviceExts.push_back(ext.data());
const VkDeviceCreateInfo deviceCreateInfo = {
VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, // sType
pNext, // pNext
(VkDeviceCreateFlags)0u, // flags
1, // queueRecordCount
&deviceQueueCreateInfo, // pRequestedQueues
0, // layerCount
DE_NULL, // ppEnabledLayerNames
(uint32_t)deviceExts.size(), // extensionCount
deviceExts.empty() ? DE_NULL : deviceExts.data(), // ppEnabledExtensionNames
&(chainedFeatures->features) // pEnabledFeatures
};
// create new device
pcDevice = createDevice(vkp, instance, vki, physicalDevice, &deviceCreateInfo);
deviceFeatures = pipeline.deviceFeatures;
deviceExtensions = pipeline.deviceExtensions;
// create local function pointers required to perform pipeline cache creation
getDeviceProcAddrFunc = (GetDeviceProcAddrFunc)vkp.getInstanceProcAddr(instance, "vkGetDeviceProcAddr");
createSamplerYcbcrConversionFunc =
(CreateSamplerYcbcrConversionFunc)getDeviceProcAddrFunc(*pcDevice, "vkCreateSamplerYcbcrConversion");
destroySamplerYcbcrConversionFunc =
(DestroySamplerYcbcrConversionFunc)getDeviceProcAddrFunc(*pcDevice, "vkDestroySamplerYcbcrConversion");
createSamplerFunc = (CreateSamplerFunc)getDeviceProcAddrFunc(*pcDevice, "vkCreateSampler");
destroySamplerFunc = (DestroySamplerFunc)getDeviceProcAddrFunc(*pcDevice, "vkDestroySampler");
createShaderModuleFunc = (CreateShaderModuleFunc)getDeviceProcAddrFunc(*pcDevice, "vkCreateShaderModule");
destroyShaderModuleFunc =
(DestroyShaderModuleFunc)getDeviceProcAddrFunc(*pcDevice, "vkDestroyShaderModule");
createRenderPassFunc = (CreateRenderPassFunc)getDeviceProcAddrFunc(*pcDevice, "vkCreateRenderPass");
createRenderPass2Func = (CreateRenderPass2Func)getDeviceProcAddrFunc(*pcDevice, "vkCreateRenderPass2");
destroyRenderPassFunc = (DestroyRenderPassFunc)getDeviceProcAddrFunc(*pcDevice, "vkDestroyRenderPass");
createDescriptorSetLayoutFunc =
(CreateDescriptorSetLayoutFunc)getDeviceProcAddrFunc(*pcDevice, "vkCreateDescriptorSetLayout");
destroyDescriptorSetLayoutFunc =
(DestroyDescriptorSetLayoutFunc)getDeviceProcAddrFunc(*pcDevice, "vkDestroyDescriptorSetLayout");
createPipelineLayoutFunc =
(CreatePipelineLayoutFunc)getDeviceProcAddrFunc(*pcDevice, "vkCreatePipelineLayout");
destroyPipelineLayoutFunc =
(DestroyPipelineLayoutFunc)getDeviceProcAddrFunc(*pcDevice, "vkDestroyPipelineLayout");
createGraphicsPipelinesFunc =
(CreateGraphicsPipelinesFunc)getDeviceProcAddrFunc(*pcDevice, "vkCreateGraphicsPipelines");
createComputePipelinesFunc =
(CreateComputePipelinesFunc)getDeviceProcAddrFunc(*pcDevice, "vkCreateComputePipelines");
createPipelineCacheFunc =
(CreatePipelineCacheFunc)getDeviceProcAddrFunc(*pcDevice, "vkCreatePipelineCache");
destroyPipelineCacheFunc =
(DestroyPipelineCacheFunc)getDeviceProcAddrFunc(*pcDevice, "vkDestroyPipelineCache");
destroyPipelineFunc = (DestroyPipelineFunc)getDeviceProcAddrFunc(*pcDevice, "vkDestroyPipeline");
getPipelineCacheDataFunc =
(GetPipelineCacheDataFunc)getDeviceProcAddrFunc(*pcDevice, "vkGetPipelineCacheData");
VK_CHECK(createPipelineCacheFunc(*pcDevice, &pcCI, DE_NULL, &pipelineCache));
// decode VkSamplerYcbcrConversionCreateInfo structs and create VkSamplerYcbcrConversions
for (auto &&samplerYcbcr : input.samplerYcbcrConversions)
{
VkSamplerYcbcrConversionCreateInfo sycCI{};
readJSON_VkSamplerYcbcrConversionCreateInfo(jsonReader, samplerYcbcr.second, sycCI);
VkSamplerYcbcrConversion realConversion;
VK_CHECK(createSamplerYcbcrConversionFunc(*pcDevice, &sycCI, DE_NULL, &realConversion));
falseToRealSamplerYcbcrConversions.insert({samplerYcbcr.first, realConversion});
}
// decode VkSamplerCreateInfo structs and create VkSamplers
for (auto &&sampler : input.samplers)
{
VkSamplerCreateInfo sCI{};
readJSON_VkSamplerCreateInfo(jsonReader, sampler.second, sCI);
// replace ycbcr conversions if required
if (sCI.pNext != NULL)
{
if (sCI.pNext != DE_NULL)
{
VkSamplerYcbcrConversionInfo *info = (VkSamplerYcbcrConversionInfo *)(sCI.pNext);
if (info->sType == VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO)
{
auto jt = falseToRealSamplerYcbcrConversions.find(info->conversion);
if (jt == end(falseToRealSamplerYcbcrConversions))
TCU_THROW(InternalError, "VkSamplerYcbcrConversion not found");
info->conversion = jt->second;
}
}
}
VkSampler realSampler;
VK_CHECK(createSamplerFunc(*pcDevice, &sCI, DE_NULL, &realSampler));
falseToRealSamplers.insert({sampler.first, realSampler});
}
// decode VkShaderModuleCreateInfo structs and create VkShaderModules
for (auto &&shader : input.shaderModules)
{
VkShaderModuleCreateInfo smCI{};
std::vector<uint8_t> spirvShader;
readJSON_VkShaderModuleCreateInfo(jsonReader, shader.second, smCI, spirvShader);
VkShaderModule realShaderModule;
VK_CHECK(createShaderModuleFunc(*pcDevice, &smCI, DE_NULL, &realShaderModule));
falseToRealShaderModules.insert({shader.first, realShaderModule});
}
// decode renderPass structs and create VkRenderPasses
for (auto &&renderPass : input.renderPasses)
{
if (renderPass.second.find("VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2") != std::string::npos)
{
VkRenderPassCreateInfo2 rpCI{};
readJSON_VkRenderPassCreateInfo2(jsonReader, renderPass.second, rpCI);
VkRenderPass realRenderPass;
VK_CHECK(createRenderPass2Func(*pcDevice, &rpCI, DE_NULL, &realRenderPass));
falseToRealRenderPasses.insert({renderPass.first, realRenderPass});
}
else if (renderPass.second.find("VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO") != std::string::npos)
{
VkRenderPassCreateInfo rpCI{};
readJSON_VkRenderPassCreateInfo(jsonReader, renderPass.second, rpCI);
VkRenderPass realRenderPass;
VK_CHECK(createRenderPassFunc(*pcDevice, &rpCI, DE_NULL, &realRenderPass));
falseToRealRenderPasses.insert({renderPass.first, realRenderPass});
}
else
TCU_THROW(InternalError, "Could not recognize render pass type");
}
// create VkDescriptorSetLayouts
for (auto &&dsCI : descriptorSetLayoutCreateInfos)
{
std::vector<VkDescriptorSetLayoutBinding> newDescriptorBindings;
std::vector<std::vector<VkSampler>> realSamplers;
// we have to replace all bindings if there is any immutable sampler defined
bool needReplaceSamplers = false;
for (uint32_t i = 0; i < dsCI.second.bindingCount; ++i)
{
if (dsCI.second.pBindings[i].pImmutableSamplers != DE_NULL)
needReplaceSamplers = true;
}
if (needReplaceSamplers)
{
for (uint32_t i = 0; i < dsCI.second.bindingCount; ++i)
{
if (dsCI.second.pBindings[i].pImmutableSamplers == DE_NULL)
{
newDescriptorBindings.push_back(dsCI.second.pBindings[i]);
continue;
}
realSamplers.push_back(std::vector<VkSampler>(dsCI.second.pBindings[i].descriptorCount));
for (uint32_t j = 0; j < dsCI.second.pBindings[i].descriptorCount; ++j)
{
if (dsCI.second.pBindings[i].pImmutableSamplers[j] == VK_NULL_HANDLE)
{
realSamplers.back()[j] = VK_NULL_HANDLE;
continue;
}
else
{
auto jt = falseToRealSamplers.find(dsCI.second.pBindings[i].pImmutableSamplers[j]);
if (jt == end(falseToRealSamplers))
TCU_THROW(InternalError, "VkSampler not found");
realSamplers.back()[j] = jt->second;
}
}
VkDescriptorSetLayoutBinding bCopy = {
dsCI.second.pBindings[i].binding, // uint32_t binding;
dsCI.second.pBindings[i].descriptorType, // VkDescriptorType descriptorType;
dsCI.second.pBindings[i].descriptorCount, // uint32_t descriptorCount;
dsCI.second.pBindings[i].stageFlags, // VkShaderStageFlags stageFlags;
realSamplers.back().data() // const VkSampler* pImmutableSamplers;
};
newDescriptorBindings.push_back(bCopy);
}
dsCI.second.pBindings = newDescriptorBindings.data();
}
VkDescriptorSetLayout realDescriptorSetLayout;
VK_CHECK(createDescriptorSetLayoutFunc(*pcDevice, &dsCI.second, DE_NULL, &realDescriptorSetLayout));
falseToRealDescriptorSetLayouts.insert({dsCI.first, realDescriptorSetLayout});
}
// decode pipeline layout structs and create VkPipelineLayouts. Requires creation of new pSetLayouts to bypass constness
for (auto &&pipelineLayout : input.pipelineLayouts)
{
VkPipelineLayoutCreateInfo plCI{};
readJSON_VkPipelineLayoutCreateInfo(jsonReader, pipelineLayout.second, plCI);
// replace descriptor set layouts with real ones
std::vector<VkDescriptorSetLayout> newSetLayouts;
for (uint32_t i = 0; i < plCI.setLayoutCount; ++i)
{
auto jt = falseToRealDescriptorSetLayouts.find(plCI.pSetLayouts[i]);
if (jt == end(falseToRealDescriptorSetLayouts))
TCU_THROW(InternalError, "VkDescriptorSetLayout not found");
newSetLayouts.push_back(jt->second);
}
plCI.pSetLayouts = newSetLayouts.data();
VkPipelineLayout realPipelineLayout;
VK_CHECK(createPipelineLayoutFunc(*pcDevice, &plCI, DE_NULL, &realPipelineLayout));
falseToRealPipelineLayouts.insert({pipelineLayout.first, realPipelineLayout});
}
}
// after device creation - start creating pipelines
if (pipeline.pipelineContents.find("VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO") != std::string::npos)
{
VkGraphicsPipelineCreateInfo gpCI{};
gpCI.basePipelineHandle = VK_NULL_HANDLE;
readJSON_VkGraphicsPipelineCreateInfo(jsonReader, pipeline.pipelineContents, gpCI);
// set poolEntrySize for pipeline
VkPipelineOfflineCreateInfo *offlineCreateInfo = (VkPipelineOfflineCreateInfo *)findStructureInChain(
gpCI.pNext, VK_STRUCTURE_TYPE_PIPELINE_OFFLINE_CREATE_INFO);
if (offlineCreateInfo != DE_NULL)
offlineCreateInfo->poolEntrySize = VKSC_DEFAULT_PIPELINE_POOL_SIZE;
// replace VkShaderModules with real ones. Requires creation of new pStages to bypass constness
std::vector<VkPipelineShaderStageCreateInfo> newStages;
for (uint32_t i = 0; i < gpCI.stageCount; ++i)
{
VkPipelineShaderStageCreateInfo newStage = gpCI.pStages[i];
auto jt = falseToRealShaderModules.find(gpCI.pStages[i].module);
if (jt == end(falseToRealShaderModules))
TCU_THROW(InternalError, "VkShaderModule not found");
newStage.module = jt->second;
newStages.push_back(newStage);
}
gpCI.pStages = newStages.data();
// replace render pass with a real one
{
auto jt = falseToRealRenderPasses.find(gpCI.renderPass);
if (jt == end(falseToRealRenderPasses))
TCU_THROW(InternalError, "VkRenderPass not found");
gpCI.renderPass = jt->second;
}
// replace pipeline layout with a real one
{
auto jt = falseToRealPipelineLayouts.find(gpCI.layout);
if (jt == end(falseToRealPipelineLayouts))
TCU_THROW(InternalError, "VkPipelineLayout not found");
gpCI.layout = jt->second;
}
VkPipeline gPipeline = VK_NULL_HANDLE;
VK_CHECK(createGraphicsPipelinesFunc(*pcDevice, pipelineCache, 1, &gpCI, DE_NULL, &gPipeline));
// pipeline was added to cache. We may remove it immediately
destroyPipelineFunc(*pcDevice, gPipeline, DE_NULL);
}
else if (pipeline.pipelineContents.find("VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO") != std::string::npos)
{
VkComputePipelineCreateInfo cpCI{};
cpCI.basePipelineHandle = VK_NULL_HANDLE;
readJSON_VkComputePipelineCreateInfo(jsonReader, pipeline.pipelineContents, cpCI);
// set poolEntrySize for pipeline
VkPipelineOfflineCreateInfo *offlineCreateInfo = (VkPipelineOfflineCreateInfo *)findStructureInChain(
cpCI.pNext, VK_STRUCTURE_TYPE_PIPELINE_OFFLINE_CREATE_INFO);
if (offlineCreateInfo != DE_NULL)
offlineCreateInfo->poolEntrySize = VKSC_DEFAULT_PIPELINE_POOL_SIZE;
// replace VkShaderModule with real one
{
auto jt = falseToRealShaderModules.find(cpCI.stage.module);
if (jt == end(falseToRealShaderModules))
TCU_THROW(InternalError, "VkShaderModule not found");
cpCI.stage.module = jt->second;
}
// replace pipeline layout with a real one
{
auto jt = falseToRealPipelineLayouts.find(cpCI.layout);
if (jt == end(falseToRealPipelineLayouts))
TCU_THROW(InternalError, "VkPipelineLayout not found");
cpCI.layout = jt->second;
}
VkPipeline cPipeline = VK_NULL_HANDLE;
VK_CHECK(createComputePipelinesFunc(*pcDevice, pipelineCache, 1, &cpCI, DE_NULL, &cPipeline));
// pipeline was added to cache. We may remove it immediately
destroyPipelineFunc(*pcDevice, cPipeline, DE_NULL);
}
else
TCU_THROW(InternalError, "Could not recognize pipeline type");
}
if (pcDevice.get() != DE_NULL)
{
// getPipelineCacheData() binary data, store it in m_cacheData
std::size_t cacheSize;
VK_CHECK(getPipelineCacheDataFunc(*pcDevice, pipelineCache, &cacheSize, DE_NULL));
resultCacheData.resize(cacheSize);
VK_CHECK(getPipelineCacheDataFunc(*pcDevice, pipelineCache, &cacheSize, resultCacheData.data()));
// clean up resources - in ResourceInterfaceStandard we just simulate Vulkan SC driver after all...
for (auto &&it : falseToRealPipelineLayouts)
destroyPipelineLayoutFunc(*pcDevice, it.second, DE_NULL);
for (auto &&it : falseToRealDescriptorSetLayouts)
destroyDescriptorSetLayoutFunc(*pcDevice, it.second, DE_NULL);
for (auto &&it : falseToRealRenderPasses)
destroyRenderPassFunc(*pcDevice, it.second, DE_NULL);
for (auto &&it : falseToRealShaderModules)
destroyShaderModuleFunc(*pcDevice, it.second, DE_NULL);
for (auto &&it : falseToRealSamplers)
destroySamplerFunc(*pcDevice, it.second, DE_NULL);
for (auto &&it : falseToRealSamplerYcbcrConversions)
destroySamplerYcbcrConversionFunc(*pcDevice, it.second, DE_NULL);
destroyPipelineCacheFunc(*pcDevice, pipelineCache, DE_NULL);
}
return resultCacheData;
}
std::vector<VulkanPipelineSize> extractSizesFromPipelineCache(const VulkanPipelineCacheInput &input,
const vector<u8> &pipelineCache,
uint32_t pipelineDefaultSize, bool recyclePipelineMemory)
{
std::vector<VulkanPipelineSize> result;
if (input.pipelines.empty())
return result;
VKSCPipelineCacheHeaderReader pcr(pipelineCache.size(), pipelineCache.data());
if (pcr.isValid())
{
for (uint32_t p = 0; p < pcr.getPipelineIndexCount(); ++p)
{
const VkPipelineCacheSafetyCriticalIndexEntry *pie = pcr.getPipelineIndexEntry(p);
if (nullptr != pie)
{
VulkanPipelineSize pipelineSize;
pipelineSize.id = resetPipelineOfflineCreateInfo();
for (uint32_t i = 0; i < VK_UUID_SIZE; ++i)
pipelineSize.id.pipelineIdentifier[i] = pie->pipelineIdentifier[i];
pipelineSize.size = uint32_t(pie->pipelineMemorySize);
pipelineSize.count = 0u;
auto it = std::find_if(begin(input.pipelines), end(input.pipelines),
vksc_server::PipelineIdentifierEqual(pipelineSize.id));
if (it != end(input.pipelines))
{
if (recyclePipelineMemory)
pipelineSize.count = it->maxCount;
else // you'd better have enough memory...
pipelineSize.count = it->allCount;
}
result.emplace_back(pipelineSize);
}
}
}
else // ordinary Vulkan pipeline. Declare all pipeline sizes as equal to pipelineDefaultSize
{
for (uint32_t p = 0; p < input.pipelines.size(); ++p)
{
VulkanPipelineSize pipelineSize;
pipelineSize.id = resetPipelineOfflineCreateInfo();
for (uint32_t i = 0; i < VK_UUID_SIZE; ++i)
pipelineSize.id.pipelineIdentifier[i] = input.pipelines[p].id.pipelineIdentifier[i];
pipelineSize.size = pipelineDefaultSize;
if (recyclePipelineMemory)
pipelineSize.count = input.pipelines[p].maxCount;
else // you'd better have enough memory...
pipelineSize.count = input.pipelines[p].allCount;
result.emplace_back(pipelineSize);
}
}
return result;
}
} // namespace vksc_server