video_core/vulkan: Added VkPipelineCache to store Vulkan pipelines

As an optional feature which can be enabled in the advanced graphics configuration, all pipelines that get built at the initial shader loading are stored in a VkPipelineCache object and are dumped to the disk.

These vendor specific pipeline cache files are located at `/shader/GAME_ID/vulkan_pipelines.bin`. This feature was mainly added because of an issue with the AMD driver (see yuzu-emu#8507) causing invalidation of the cache files the driver builds automatically.
This commit is contained in:
Wollnashorn 2022-12-30 14:50:07 +01:00
parent e82e3e06be
commit 16809c1fa7
15 changed files with 253 additions and 67 deletions

View file

@ -152,6 +152,7 @@ void Load(VkDevice device, DeviceDispatch& dld) noexcept {
X(vkCreateGraphicsPipelines);
X(vkCreateImage);
X(vkCreateImageView);
X(vkCreatePipelineCache);
X(vkCreatePipelineLayout);
X(vkCreateQueryPool);
X(vkCreateRenderPass);
@ -171,6 +172,7 @@ void Load(VkDevice device, DeviceDispatch& dld) noexcept {
X(vkDestroyImage);
X(vkDestroyImageView);
X(vkDestroyPipeline);
X(vkDestroyPipelineCache);
X(vkDestroyPipelineLayout);
X(vkDestroyQueryPool);
X(vkDestroyRenderPass);
@ -188,6 +190,7 @@ void Load(VkDevice device, DeviceDispatch& dld) noexcept {
X(vkGetEventStatus);
X(vkGetFenceStatus);
X(vkGetImageMemoryRequirements);
X(vkGetPipelineCacheData);
X(vkGetMemoryFdKHR);
#ifdef _WIN32
X(vkGetMemoryWin32HandleKHR);
@ -431,6 +434,10 @@ void Destroy(VkDevice device, VkPipeline handle, const DeviceDispatch& dld) noex
dld.vkDestroyPipeline(device, handle, nullptr);
}
void Destroy(VkDevice device, VkPipelineCache handle, const DeviceDispatch& dld) noexcept {
dld.vkDestroyPipelineCache(device, handle, nullptr);
}
void Destroy(VkDevice device, VkPipelineLayout handle, const DeviceDispatch& dld) noexcept {
dld.vkDestroyPipelineLayout(device, handle, nullptr);
}
@ -651,6 +658,10 @@ void ShaderModule::SetObjectNameEXT(const char* name) const {
SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_SHADER_MODULE, name);
}
void PipelineCache::SetObjectNameEXT(const char* name) const {
SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_PIPELINE_CACHE, name);
}
void Semaphore::SetObjectNameEXT(const char* name) const {
SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_SEMAPHORE, name);
}
@ -746,21 +757,29 @@ DescriptorSetLayout Device::CreateDescriptorSetLayout(
return DescriptorSetLayout(object, handle, *dld);
}
PipelineCache Device::CreatePipelineCache(const VkPipelineCacheCreateInfo& ci) const {
VkPipelineCache cache;
Check(dld->vkCreatePipelineCache(handle, &ci, nullptr, &cache));
return PipelineCache(cache, handle, *dld);
}
PipelineLayout Device::CreatePipelineLayout(const VkPipelineLayoutCreateInfo& ci) const {
VkPipelineLayout object;
Check(dld->vkCreatePipelineLayout(handle, &ci, nullptr, &object));
return PipelineLayout(object, handle, *dld);
}
Pipeline Device::CreateGraphicsPipeline(const VkGraphicsPipelineCreateInfo& ci) const {
Pipeline Device::CreateGraphicsPipeline(const VkGraphicsPipelineCreateInfo& ci,
VkPipelineCache cache) const {
VkPipeline object;
Check(dld->vkCreateGraphicsPipelines(handle, nullptr, 1, &ci, nullptr, &object));
Check(dld->vkCreateGraphicsPipelines(handle, cache, 1, &ci, nullptr, &object));
return Pipeline(object, handle, *dld);
}
Pipeline Device::CreateComputePipeline(const VkComputePipelineCreateInfo& ci) const {
Pipeline Device::CreateComputePipeline(const VkComputePipelineCreateInfo& ci,
VkPipelineCache cache) const {
VkPipeline object;
Check(dld->vkCreateComputePipelines(handle, nullptr, 1, &ci, nullptr, &object));
Check(dld->vkCreateComputePipelines(handle, cache, 1, &ci, nullptr, &object));
return Pipeline(object, handle, *dld);
}

View file

@ -270,6 +270,7 @@ struct DeviceDispatch : InstanceDispatch {
PFN_vkCreateGraphicsPipelines vkCreateGraphicsPipelines{};
PFN_vkCreateImage vkCreateImage{};
PFN_vkCreateImageView vkCreateImageView{};
PFN_vkCreatePipelineCache vkCreatePipelineCache{};
PFN_vkCreatePipelineLayout vkCreatePipelineLayout{};
PFN_vkCreateQueryPool vkCreateQueryPool{};
PFN_vkCreateRenderPass vkCreateRenderPass{};
@ -289,6 +290,7 @@ struct DeviceDispatch : InstanceDispatch {
PFN_vkDestroyImage vkDestroyImage{};
PFN_vkDestroyImageView vkDestroyImageView{};
PFN_vkDestroyPipeline vkDestroyPipeline{};
PFN_vkDestroyPipelineCache vkDestroyPipelineCache{};
PFN_vkDestroyPipelineLayout vkDestroyPipelineLayout{};
PFN_vkDestroyQueryPool vkDestroyQueryPool{};
PFN_vkDestroyRenderPass vkDestroyRenderPass{};
@ -306,6 +308,7 @@ struct DeviceDispatch : InstanceDispatch {
PFN_vkGetEventStatus vkGetEventStatus{};
PFN_vkGetFenceStatus vkGetFenceStatus{};
PFN_vkGetImageMemoryRequirements vkGetImageMemoryRequirements{};
PFN_vkGetPipelineCacheData vkGetPipelineCacheData{};
PFN_vkGetMemoryFdKHR vkGetMemoryFdKHR{};
#ifdef _WIN32
PFN_vkGetMemoryWin32HandleKHR vkGetMemoryWin32HandleKHR{};
@ -351,6 +354,7 @@ void Destroy(VkDevice, VkFramebuffer, const DeviceDispatch&) noexcept;
void Destroy(VkDevice, VkImage, const DeviceDispatch&) noexcept;
void Destroy(VkDevice, VkImageView, const DeviceDispatch&) noexcept;
void Destroy(VkDevice, VkPipeline, const DeviceDispatch&) noexcept;
void Destroy(VkDevice, VkPipelineCache, const DeviceDispatch&) noexcept;
void Destroy(VkDevice, VkPipelineLayout, const DeviceDispatch&) noexcept;
void Destroy(VkDevice, VkQueryPool, const DeviceDispatch&) noexcept;
void Destroy(VkDevice, VkRenderPass, const DeviceDispatch&) noexcept;
@ -773,6 +777,18 @@ public:
void SetObjectNameEXT(const char* name) const;
};
class PipelineCache : public Handle<VkPipelineCache, VkDevice, DeviceDispatch> {
using Handle<VkPipelineCache, VkDevice, DeviceDispatch>::Handle;
public:
/// Set object name.
void SetObjectNameEXT(const char* name) const;
VkResult Read(size_t* size, void* data) const noexcept {
return dld->vkGetPipelineCacheData(owner, handle, size, data);
}
};
class Semaphore : public Handle<VkSemaphore, VkDevice, DeviceDispatch> {
using Handle<VkSemaphore, VkDevice, DeviceDispatch>::Handle;
@ -844,11 +860,15 @@ public:
DescriptorSetLayout CreateDescriptorSetLayout(const VkDescriptorSetLayoutCreateInfo& ci) const;
PipelineCache CreatePipelineCache(const VkPipelineCacheCreateInfo& ci) const;
PipelineLayout CreatePipelineLayout(const VkPipelineLayoutCreateInfo& ci) const;
Pipeline CreateGraphicsPipeline(const VkGraphicsPipelineCreateInfo& ci) const;
Pipeline CreateGraphicsPipeline(const VkGraphicsPipelineCreateInfo& ci,
VkPipelineCache cache = nullptr) const;
Pipeline CreateComputePipeline(const VkComputePipelineCreateInfo& ci) const;
Pipeline CreateComputePipeline(const VkComputePipelineCreateInfo& ci,
VkPipelineCache cache = nullptr) const;
Sampler CreateSampler(const VkSamplerCreateInfo& ci) const;