summaryrefslogtreecommitdiff
path: root/src/video_core/renderer_vulkan
diff options
context:
space:
mode:
authorGravatar Fernando S2023-01-05 16:38:07 -0500
committerGravatar GitHub2023-01-05 16:38:07 -0500
commit1428451722718d7af450f67d7ec823b155b128d2 (patch)
treed498f1f26f66edcb3e2517cd83d1fd8f6d8f015f /src/video_core/renderer_vulkan
parentMerge pull request #9557 from FernandoS27/ooops-i-killed-the-shitty-drivers (diff)
parentvideo_core/vulkan: Vulkan driver pipelines now contain cache version (diff)
downloadyuzu-1428451722718d7af450f67d7ec823b155b128d2.tar.gz
yuzu-1428451722718d7af450f67d7ec823b155b128d2.tar.xz
yuzu-1428451722718d7af450f67d7ec823b155b128d2.zip
Merge pull request #9527 from Wollnashorn/amd-cache-fix
video_core/vulkan: Implemented `VkPipelineCache` to store Vulkan pipelines
Diffstat (limited to 'src/video_core/renderer_vulkan')
-rw-r--r--src/video_core/renderer_vulkan/vk_compute_pipeline.cpp42
-rw-r--r--src/video_core/renderer_vulkan/vk_compute_pipeline.h4
-rw-r--r--src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp51
-rw-r--r--src/video_core/renderer_vulkan/vk_graphics_pipeline.h19
-rw-r--r--src/video_core/renderer_vulkan/vk_pipeline_cache.cpp128
-rw-r--r--src/video_core/renderer_vulkan/vk_pipeline_cache.h10
6 files changed, 193 insertions, 61 deletions
diff --git a/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp b/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp
index 04a3a861e..2a0f0dbf0 100644
--- a/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp
+++ b/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp
@@ -24,13 +24,15 @@ using Shader::ImageBufferDescriptor;
24using Shader::Backend::SPIRV::RESCALING_LAYOUT_WORDS_OFFSET; 24using Shader::Backend::SPIRV::RESCALING_LAYOUT_WORDS_OFFSET;
25using Tegra::Texture::TexturePair; 25using Tegra::Texture::TexturePair;
26 26
27ComputePipeline::ComputePipeline(const Device& device_, DescriptorPool& descriptor_pool, 27ComputePipeline::ComputePipeline(const Device& device_, vk::PipelineCache& pipeline_cache_,
28 DescriptorPool& descriptor_pool,
28 UpdateDescriptorQueue& update_descriptor_queue_, 29 UpdateDescriptorQueue& update_descriptor_queue_,
29 Common::ThreadWorker* thread_worker, 30 Common::ThreadWorker* thread_worker,
30 PipelineStatistics* pipeline_statistics, 31 PipelineStatistics* pipeline_statistics,
31 VideoCore::ShaderNotify* shader_notify, const Shader::Info& info_, 32 VideoCore::ShaderNotify* shader_notify, const Shader::Info& info_,
32 vk::ShaderModule spv_module_) 33 vk::ShaderModule spv_module_)
33 : device{device_}, update_descriptor_queue{update_descriptor_queue_}, info{info_}, 34 : device{device_}, pipeline_cache(pipeline_cache_),
35 update_descriptor_queue{update_descriptor_queue_}, info{info_},
34 spv_module(std::move(spv_module_)) { 36 spv_module(std::move(spv_module_)) {
35 if (shader_notify) { 37 if (shader_notify) {
36 shader_notify->MarkShaderBuilding(); 38 shader_notify->MarkShaderBuilding();
@@ -56,23 +58,27 @@ ComputePipeline::ComputePipeline(const Device& device_, DescriptorPool& descript
56 if (device.IsKhrPipelineExecutablePropertiesEnabled()) { 58 if (device.IsKhrPipelineExecutablePropertiesEnabled()) {
57 flags |= VK_PIPELINE_CREATE_CAPTURE_STATISTICS_BIT_KHR; 59 flags |= VK_PIPELINE_CREATE_CAPTURE_STATISTICS_BIT_KHR;
58 } 60 }
59 pipeline = device.GetLogical().CreateComputePipeline({ 61 pipeline = device.GetLogical().CreateComputePipeline(
60 .sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO, 62 {
61 .pNext = nullptr, 63 .sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO,
62 .flags = flags, 64 .pNext = nullptr,
63 .stage{ 65 .flags = flags,
64 .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, 66 .stage{
65 .pNext = device.IsExtSubgroupSizeControlSupported() ? &subgroup_size_ci : nullptr, 67 .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
66 .flags = 0, 68 .pNext =
67 .stage = VK_SHADER_STAGE_COMPUTE_BIT, 69 device.IsExtSubgroupSizeControlSupported() ? &subgroup_size_ci : nullptr,
68 .module = *spv_module, 70 .flags = 0,
69 .pName = "main", 71 .stage = VK_SHADER_STAGE_COMPUTE_BIT,
70 .pSpecializationInfo = nullptr, 72 .module = *spv_module,
73 .pName = "main",
74 .pSpecializationInfo = nullptr,
75 },
76 .layout = *pipeline_layout,
77 .basePipelineHandle = 0,
78 .basePipelineIndex = 0,
71 }, 79 },
72 .layout = *pipeline_layout, 80 *pipeline_cache);
73 .basePipelineHandle = 0, 81
74 .basePipelineIndex = 0,
75 });
76 if (pipeline_statistics) { 82 if (pipeline_statistics) {
77 pipeline_statistics->Collect(*pipeline); 83 pipeline_statistics->Collect(*pipeline);
78 } 84 }
diff --git a/src/video_core/renderer_vulkan/vk_compute_pipeline.h b/src/video_core/renderer_vulkan/vk_compute_pipeline.h
index d70837fc5..78d77027f 100644
--- a/src/video_core/renderer_vulkan/vk_compute_pipeline.h
+++ b/src/video_core/renderer_vulkan/vk_compute_pipeline.h
@@ -28,7 +28,8 @@ class Scheduler;
28 28
29class ComputePipeline { 29class ComputePipeline {
30public: 30public:
31 explicit ComputePipeline(const Device& device, DescriptorPool& descriptor_pool, 31 explicit ComputePipeline(const Device& device, vk::PipelineCache& pipeline_cache,
32 DescriptorPool& descriptor_pool,
32 UpdateDescriptorQueue& update_descriptor_queue, 33 UpdateDescriptorQueue& update_descriptor_queue,
33 Common::ThreadWorker* thread_worker, 34 Common::ThreadWorker* thread_worker,
34 PipelineStatistics* pipeline_statistics, 35 PipelineStatistics* pipeline_statistics,
@@ -46,6 +47,7 @@ public:
46 47
47private: 48private:
48 const Device& device; 49 const Device& device;
50 vk::PipelineCache& pipeline_cache;
49 UpdateDescriptorQueue& update_descriptor_queue; 51 UpdateDescriptorQueue& update_descriptor_queue;
50 Shader::Info info; 52 Shader::Info info;
51 53
diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp
index 734c379b9..f91bb5a1d 100644
--- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp
+++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp
@@ -234,13 +234,14 @@ ConfigureFuncPtr ConfigureFunc(const std::array<vk::ShaderModule, NUM_STAGES>& m
234 234
235GraphicsPipeline::GraphicsPipeline( 235GraphicsPipeline::GraphicsPipeline(
236 Scheduler& scheduler_, BufferCache& buffer_cache_, TextureCache& texture_cache_, 236 Scheduler& scheduler_, BufferCache& buffer_cache_, TextureCache& texture_cache_,
237 VideoCore::ShaderNotify* shader_notify, const Device& device_, DescriptorPool& descriptor_pool, 237 vk::PipelineCache& pipeline_cache_, VideoCore::ShaderNotify* shader_notify,
238 const Device& device_, DescriptorPool& descriptor_pool,
238 UpdateDescriptorQueue& update_descriptor_queue_, Common::ThreadWorker* worker_thread, 239 UpdateDescriptorQueue& update_descriptor_queue_, Common::ThreadWorker* worker_thread,
239 PipelineStatistics* pipeline_statistics, RenderPassCache& render_pass_cache, 240 PipelineStatistics* pipeline_statistics, RenderPassCache& render_pass_cache,
240 const GraphicsPipelineCacheKey& key_, std::array<vk::ShaderModule, NUM_STAGES> stages, 241 const GraphicsPipelineCacheKey& key_, std::array<vk::ShaderModule, NUM_STAGES> stages,
241 const std::array<const Shader::Info*, NUM_STAGES>& infos) 242 const std::array<const Shader::Info*, NUM_STAGES>& infos)
242 : key{key_}, device{device_}, texture_cache{texture_cache_}, 243 : key{key_}, device{device_}, texture_cache{texture_cache_}, buffer_cache{buffer_cache_},
243 buffer_cache{buffer_cache_}, scheduler{scheduler_}, 244 pipeline_cache(pipeline_cache_), scheduler{scheduler_},
244 update_descriptor_queue{update_descriptor_queue_}, spv_modules{std::move(stages)} { 245 update_descriptor_queue{update_descriptor_queue_}, spv_modules{std::move(stages)} {
245 if (shader_notify) { 246 if (shader_notify) {
246 shader_notify->MarkShaderBuilding(); 247 shader_notify->MarkShaderBuilding();
@@ -897,27 +898,29 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) {
897 if (device.IsKhrPipelineExecutablePropertiesEnabled()) { 898 if (device.IsKhrPipelineExecutablePropertiesEnabled()) {
898 flags |= VK_PIPELINE_CREATE_CAPTURE_STATISTICS_BIT_KHR; 899 flags |= VK_PIPELINE_CREATE_CAPTURE_STATISTICS_BIT_KHR;
899 } 900 }
900 pipeline = device.GetLogical().CreateGraphicsPipeline({ 901 pipeline = device.GetLogical().CreateGraphicsPipeline(
901 .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, 902 {
902 .pNext = nullptr, 903 .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
903 .flags = flags, 904 .pNext = nullptr,
904 .stageCount = static_cast<u32>(shader_stages.size()), 905 .flags = flags,
905 .pStages = shader_stages.data(), 906 .stageCount = static_cast<u32>(shader_stages.size()),
906 .pVertexInputState = &vertex_input_ci, 907 .pStages = shader_stages.data(),
907 .pInputAssemblyState = &input_assembly_ci, 908 .pVertexInputState = &vertex_input_ci,
908 .pTessellationState = &tessellation_ci, 909 .pInputAssemblyState = &input_assembly_ci,
909 .pViewportState = &viewport_ci, 910 .pTessellationState = &tessellation_ci,
910 .pRasterizationState = &rasterization_ci, 911 .pViewportState = &viewport_ci,
911 .pMultisampleState = &multisample_ci, 912 .pRasterizationState = &rasterization_ci,
912 .pDepthStencilState = &depth_stencil_ci, 913 .pMultisampleState = &multisample_ci,
913 .pColorBlendState = &color_blend_ci, 914 .pDepthStencilState = &depth_stencil_ci,
914 .pDynamicState = &dynamic_state_ci, 915 .pColorBlendState = &color_blend_ci,
915 .layout = *pipeline_layout, 916 .pDynamicState = &dynamic_state_ci,
916 .renderPass = render_pass, 917 .layout = *pipeline_layout,
917 .subpass = 0, 918 .renderPass = render_pass,
918 .basePipelineHandle = nullptr, 919 .subpass = 0,
919 .basePipelineIndex = 0, 920 .basePipelineHandle = nullptr,
920 }); 921 .basePipelineIndex = 0,
922 },
923 *pipeline_cache);
921} 924}
922 925
923void GraphicsPipeline::Validate() { 926void GraphicsPipeline::Validate() {
diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.h b/src/video_core/renderer_vulkan/vk_graphics_pipeline.h
index 1ed2967be..67c657d0e 100644
--- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.h
+++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.h
@@ -70,16 +70,14 @@ class GraphicsPipeline {
70 static constexpr size_t NUM_STAGES = Tegra::Engines::Maxwell3D::Regs::MaxShaderStage; 70 static constexpr size_t NUM_STAGES = Tegra::Engines::Maxwell3D::Regs::MaxShaderStage;
71 71
72public: 72public:
73 explicit GraphicsPipeline(Scheduler& scheduler, BufferCache& buffer_cache, 73 explicit GraphicsPipeline(
74 TextureCache& texture_cache, VideoCore::ShaderNotify* shader_notify, 74 Scheduler& scheduler, BufferCache& buffer_cache, TextureCache& texture_cache,
75 const Device& device, DescriptorPool& descriptor_pool, 75 vk::PipelineCache& pipeline_cache, VideoCore::ShaderNotify* shader_notify,
76 UpdateDescriptorQueue& update_descriptor_queue, 76 const Device& device, DescriptorPool& descriptor_pool,
77 Common::ThreadWorker* worker_thread, 77 UpdateDescriptorQueue& update_descriptor_queue, Common::ThreadWorker* worker_thread,
78 PipelineStatistics* pipeline_statistics, 78 PipelineStatistics* pipeline_statistics, RenderPassCache& render_pass_cache,
79 RenderPassCache& render_pass_cache, 79 const GraphicsPipelineCacheKey& key, std::array<vk::ShaderModule, NUM_STAGES> stages,
80 const GraphicsPipelineCacheKey& key, 80 const std::array<const Shader::Info*, NUM_STAGES>& infos);
81 std::array<vk::ShaderModule, NUM_STAGES> stages,
82 const std::array<const Shader::Info*, NUM_STAGES>& infos);
83 81
84 GraphicsPipeline& operator=(GraphicsPipeline&&) noexcept = delete; 82 GraphicsPipeline& operator=(GraphicsPipeline&&) noexcept = delete;
85 GraphicsPipeline(GraphicsPipeline&&) noexcept = delete; 83 GraphicsPipeline(GraphicsPipeline&&) noexcept = delete;
@@ -133,6 +131,7 @@ private:
133 const Device& device; 131 const Device& device;
134 TextureCache& texture_cache; 132 TextureCache& texture_cache;
135 BufferCache& buffer_cache; 133 BufferCache& buffer_cache;
134 vk::PipelineCache& pipeline_cache;
136 Scheduler& scheduler; 135 Scheduler& scheduler;
137 UpdateDescriptorQueue& update_descriptor_queue; 136 UpdateDescriptorQueue& update_descriptor_queue;
138 137
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
index 3046b72ab..67e5bc648 100644
--- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
@@ -55,6 +55,7 @@ using VideoCommon::GenericEnvironment;
55using VideoCommon::GraphicsEnvironment; 55using VideoCommon::GraphicsEnvironment;
56 56
57constexpr u32 CACHE_VERSION = 10; 57constexpr u32 CACHE_VERSION = 10;
58constexpr std::array<char, 8> VULKAN_CACHE_MAGIC_NUMBER{'y', 'u', 'z', 'u', 'v', 'k', 'c', 'h'};
58 59
59template <typename Container> 60template <typename Container>
60auto MakeSpan(Container& container) { 61auto MakeSpan(Container& container) {
@@ -284,6 +285,7 @@ PipelineCache::PipelineCache(RasterizerVulkan& rasterizer_, const Device& device
284 render_pass_cache{render_pass_cache_}, buffer_cache{buffer_cache_}, 285 render_pass_cache{render_pass_cache_}, buffer_cache{buffer_cache_},
285 texture_cache{texture_cache_}, shader_notify{shader_notify_}, 286 texture_cache{texture_cache_}, shader_notify{shader_notify_},
286 use_asynchronous_shaders{Settings::values.use_asynchronous_shaders.GetValue()}, 287 use_asynchronous_shaders{Settings::values.use_asynchronous_shaders.GetValue()},
288 use_vulkan_pipeline_cache{Settings::values.use_vulkan_driver_pipeline_cache.GetValue()},
287 workers(std::max(std::thread::hardware_concurrency(), 2U) - 1, "VkPipelineBuilder"), 289 workers(std::max(std::thread::hardware_concurrency(), 2U) - 1, "VkPipelineBuilder"),
288 serialization_thread(1, "VkPipelineSerialization") { 290 serialization_thread(1, "VkPipelineSerialization") {
289 const auto& float_control{device.FloatControlProperties()}; 291 const auto& float_control{device.FloatControlProperties()};
@@ -362,7 +364,12 @@ PipelineCache::PipelineCache(RasterizerVulkan& rasterizer_, const Device& device
362 }; 364 };
363} 365}
364 366
365PipelineCache::~PipelineCache() = default; 367PipelineCache::~PipelineCache() {
368 if (use_vulkan_pipeline_cache && !vulkan_pipeline_cache_filename.empty()) {
369 SerializeVulkanPipelineCache(vulkan_pipeline_cache_filename, vulkan_pipeline_cache,
370 CACHE_VERSION);
371 }
372}
366 373
367GraphicsPipeline* PipelineCache::CurrentGraphicsPipeline() { 374GraphicsPipeline* PipelineCache::CurrentGraphicsPipeline() {
368 MICROPROFILE_SCOPE(Vulkan_PipelineCache); 375 MICROPROFILE_SCOPE(Vulkan_PipelineCache);
@@ -418,6 +425,12 @@ void PipelineCache::LoadDiskResources(u64 title_id, std::stop_token stop_loading
418 } 425 }
419 pipeline_cache_filename = base_dir / "vulkan.bin"; 426 pipeline_cache_filename = base_dir / "vulkan.bin";
420 427
428 if (use_vulkan_pipeline_cache) {
429 vulkan_pipeline_cache_filename = base_dir / "vulkan_pipelines.bin";
430 vulkan_pipeline_cache =
431 LoadVulkanPipelineCache(vulkan_pipeline_cache_filename, CACHE_VERSION);
432 }
433
421 struct { 434 struct {
422 std::mutex mutex; 435 std::mutex mutex;
423 size_t total{}; 436 size_t total{};
@@ -496,6 +509,11 @@ void PipelineCache::LoadDiskResources(u64 title_id, std::stop_token stop_loading
496 509
497 workers.WaitForRequests(stop_loading); 510 workers.WaitForRequests(stop_loading);
498 511
512 if (use_vulkan_pipeline_cache) {
513 SerializeVulkanPipelineCache(vulkan_pipeline_cache_filename, vulkan_pipeline_cache,
514 CACHE_VERSION);
515 }
516
499 if (state.statistics) { 517 if (state.statistics) {
500 state.statistics->Report(); 518 state.statistics->Report();
501 } 519 }
@@ -616,10 +634,10 @@ std::unique_ptr<GraphicsPipeline> PipelineCache::CreateGraphicsPipeline(
616 previous_stage = &program; 634 previous_stage = &program;
617 } 635 }
618 Common::ThreadWorker* const thread_worker{build_in_parallel ? &workers : nullptr}; 636 Common::ThreadWorker* const thread_worker{build_in_parallel ? &workers : nullptr};
619 return std::make_unique<GraphicsPipeline>(scheduler, buffer_cache, texture_cache, 637 return std::make_unique<GraphicsPipeline>(
620 &shader_notify, device, descriptor_pool, 638 scheduler, buffer_cache, texture_cache, vulkan_pipeline_cache, &shader_notify, device,
621 update_descriptor_queue, thread_worker, statistics, 639 descriptor_pool, update_descriptor_queue, thread_worker, statistics, render_pass_cache, key,
622 render_pass_cache, key, std::move(modules), infos); 640 std::move(modules), infos);
623 641
624} catch (const Shader::Exception& exception) { 642} catch (const Shader::Exception& exception) {
625 LOG_ERROR(Render_Vulkan, "{}", exception.what()); 643 LOG_ERROR(Render_Vulkan, "{}", exception.what());
@@ -689,13 +707,107 @@ std::unique_ptr<ComputePipeline> PipelineCache::CreateComputePipeline(
689 spv_module.SetObjectNameEXT(name.c_str()); 707 spv_module.SetObjectNameEXT(name.c_str());
690 } 708 }
691 Common::ThreadWorker* const thread_worker{build_in_parallel ? &workers : nullptr}; 709 Common::ThreadWorker* const thread_worker{build_in_parallel ? &workers : nullptr};
692 return std::make_unique<ComputePipeline>(device, descriptor_pool, update_descriptor_queue, 710 return std::make_unique<ComputePipeline>(device, vulkan_pipeline_cache, descriptor_pool,
693 thread_worker, statistics, &shader_notify, 711 update_descriptor_queue, thread_worker, statistics,
694 program.info, std::move(spv_module)); 712 &shader_notify, program.info, std::move(spv_module));
695 713
696} catch (const Shader::Exception& exception) { 714} catch (const Shader::Exception& exception) {
697 LOG_ERROR(Render_Vulkan, "{}", exception.what()); 715 LOG_ERROR(Render_Vulkan, "{}", exception.what());
698 return nullptr; 716 return nullptr;
699} 717}
700 718
719void PipelineCache::SerializeVulkanPipelineCache(const std::filesystem::path& filename,
720 const vk::PipelineCache& pipeline_cache,
721 u32 cache_version) try {
722 std::ofstream file(filename, std::ios::binary);
723 file.exceptions(std::ifstream::failbit);
724 if (!file.is_open()) {
725 LOG_ERROR(Common_Filesystem, "Failed to open Vulkan driver pipeline cache file {}",
726 Common::FS::PathToUTF8String(filename));
727 return;
728 }
729 file.write(VULKAN_CACHE_MAGIC_NUMBER.data(), VULKAN_CACHE_MAGIC_NUMBER.size())
730 .write(reinterpret_cast<const char*>(&cache_version), sizeof(cache_version));
731
732 size_t cache_size = 0;
733 std::vector<char> cache_data;
734 if (pipeline_cache) {
735 pipeline_cache.Read(&cache_size, nullptr);
736 cache_data.resize(cache_size);
737 pipeline_cache.Read(&cache_size, cache_data.data());
738 }
739 file.write(cache_data.data(), cache_size);
740
741 LOG_INFO(Render_Vulkan, "Vulkan driver pipelines cached at: {}",
742 Common::FS::PathToUTF8String(filename));
743
744} catch (const std::ios_base::failure& e) {
745 LOG_ERROR(Common_Filesystem, "{}", e.what());
746 if (!Common::FS::RemoveFile(filename)) {
747 LOG_ERROR(Common_Filesystem, "Failed to delete Vulkan driver pipeline cache file {}",
748 Common::FS::PathToUTF8String(filename));
749 }
750}
751
752vk::PipelineCache PipelineCache::LoadVulkanPipelineCache(const std::filesystem::path& filename,
753 u32 expected_cache_version) {
754 const auto create_pipeline_cache = [this](size_t data_size, const void* data) {
755 VkPipelineCacheCreateInfo pipeline_cache_ci = {
756 .sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO,
757 .pNext = nullptr,
758 .flags = 0,
759 .initialDataSize = data_size,
760 .pInitialData = data};
761 return device.GetLogical().CreatePipelineCache(pipeline_cache_ci);
762 };
763 try {
764 std::ifstream file(filename, std::ios::binary | std::ios::ate);
765 if (!file.is_open()) {
766 return create_pipeline_cache(0, nullptr);
767 }
768 file.exceptions(std::ifstream::failbit);
769 const auto end{file.tellg()};
770 file.seekg(0, std::ios::beg);
771
772 std::array<char, 8> magic_number;
773 u32 cache_version;
774 file.read(magic_number.data(), magic_number.size())
775 .read(reinterpret_cast<char*>(&cache_version), sizeof(cache_version));
776 if (magic_number != VULKAN_CACHE_MAGIC_NUMBER || cache_version != expected_cache_version) {
777 file.close();
778 if (Common::FS::RemoveFile(filename)) {
779 if (magic_number != VULKAN_CACHE_MAGIC_NUMBER) {
780 LOG_ERROR(Common_Filesystem, "Invalid Vulkan driver pipeline cache file");
781 }
782 if (cache_version != expected_cache_version) {
783 LOG_INFO(Common_Filesystem, "Deleting old Vulkan driver pipeline cache");
784 }
785 } else {
786 LOG_ERROR(Common_Filesystem,
787 "Invalid Vulkan pipeline cache file and failed to delete it in \"{}\"",
788 Common::FS::PathToUTF8String(filename));
789 }
790 return create_pipeline_cache(0, nullptr);
791 }
792
793 const size_t cache_size = static_cast<size_t>(end) - magic_number.size();
794 std::vector<char> cache_data(cache_size);
795 file.read(cache_data.data(), cache_size);
796
797 LOG_INFO(Render_Vulkan,
798 "Loaded Vulkan driver pipeline cache: ", Common::FS::PathToUTF8String(filename));
799
800 return create_pipeline_cache(cache_size, cache_data.data());
801
802 } catch (const std::ios_base::failure& e) {
803 LOG_ERROR(Common_Filesystem, "{}", e.what());
804 if (!Common::FS::RemoveFile(filename)) {
805 LOG_ERROR(Common_Filesystem, "Failed to delete Vulkan driver pipeline cache file {}",
806 Common::FS::PathToUTF8String(filename));
807 }
808
809 return create_pipeline_cache(0, nullptr);
810 }
811}
812
701} // namespace Vulkan 813} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.h b/src/video_core/renderer_vulkan/vk_pipeline_cache.h
index b4f593ef5..5171912d7 100644
--- a/src/video_core/renderer_vulkan/vk_pipeline_cache.h
+++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.h
@@ -135,6 +135,12 @@ private:
135 PipelineStatistics* statistics, 135 PipelineStatistics* statistics,
136 bool build_in_parallel); 136 bool build_in_parallel);
137 137
138 void SerializeVulkanPipelineCache(const std::filesystem::path& filename,
139 const vk::PipelineCache& pipeline_cache, u32 cache_version);
140
141 vk::PipelineCache LoadVulkanPipelineCache(const std::filesystem::path& filename,
142 u32 expected_cache_version);
143
138 const Device& device; 144 const Device& device;
139 Scheduler& scheduler; 145 Scheduler& scheduler;
140 DescriptorPool& descriptor_pool; 146 DescriptorPool& descriptor_pool;
@@ -144,6 +150,7 @@ private:
144 TextureCache& texture_cache; 150 TextureCache& texture_cache;
145 VideoCore::ShaderNotify& shader_notify; 151 VideoCore::ShaderNotify& shader_notify;
146 bool use_asynchronous_shaders{}; 152 bool use_asynchronous_shaders{};
153 bool use_vulkan_pipeline_cache{};
147 154
148 GraphicsPipelineCacheKey graphics_key{}; 155 GraphicsPipelineCacheKey graphics_key{};
149 GraphicsPipeline* current_pipeline{}; 156 GraphicsPipeline* current_pipeline{};
@@ -158,6 +165,9 @@ private:
158 165
159 std::filesystem::path pipeline_cache_filename; 166 std::filesystem::path pipeline_cache_filename;
160 167
168 std::filesystem::path vulkan_pipeline_cache_filename;
169 vk::PipelineCache vulkan_pipeline_cache;
170
161 Common::ThreadWorker workers; 171 Common::ThreadWorker workers;
162 Common::ThreadWorker serialization_thread; 172 Common::ThreadWorker serialization_thread;
163 DynamicFeatures dynamic_features; 173 DynamicFeatures dynamic_features;