diff options
| -rw-r--r-- | src/common/settings.h | 2 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_compute_pipeline.cpp | 42 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_compute_pipeline.h | 4 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp | 51 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_graphics_pipeline.h | 19 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_pipeline_cache.cpp | 117 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_pipeline_cache.h | 9 | ||||
| -rw-r--r-- | src/video_core/vulkan_common/vulkan_wrapper.cpp | 27 | ||||
| -rw-r--r-- | src/video_core/vulkan_common/vulkan_wrapper.h | 24 | ||||
| -rw-r--r-- | src/yuzu/configuration/config.cpp | 2 | ||||
| -rw-r--r-- | src/yuzu/configuration/configure_graphics_advanced.cpp | 7 | ||||
| -rw-r--r-- | src/yuzu/configuration/configure_graphics_advanced.h | 1 | ||||
| -rw-r--r-- | src/yuzu/configuration/configure_graphics_advanced.ui | 10 | ||||
| -rw-r--r-- | src/yuzu_cmd/config.cpp | 1 | ||||
| -rw-r--r-- | src/yuzu_cmd/default_ini.h | 4 | 
15 files changed, 253 insertions, 67 deletions
| diff --git a/src/common/settings.h b/src/common/settings.h index 5017951c5..0d58d6171 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -451,6 +451,8 @@ struct Values {      SwitchableSetting<bool> use_asynchronous_shaders{false, "use_asynchronous_shaders"};      SwitchableSetting<bool> use_fast_gpu_time{true, "use_fast_gpu_time"};      SwitchableSetting<bool> use_pessimistic_flushes{false, "use_pessimistic_flushes"}; +    SwitchableSetting<bool> use_vulkan_driver_pipeline_cache{false, +                                                             "use_vulkan_driver_pipeline_cache"};      SwitchableSetting<u8> bg_red{0, "bg_red"};      SwitchableSetting<u8> bg_green{0, "bg_green"}; 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;  using Shader::Backend::SPIRV::RESCALING_LAYOUT_WORDS_OFFSET;  using Tegra::Texture::TexturePair; -ComputePipeline::ComputePipeline(const Device& device_, DescriptorPool& descriptor_pool, +ComputePipeline::ComputePipeline(const Device& device_, vk::PipelineCache& pipeline_cache_, +                                 DescriptorPool& descriptor_pool,                                   UpdateDescriptorQueue& update_descriptor_queue_,                                   Common::ThreadWorker* thread_worker,                                   PipelineStatistics* pipeline_statistics,                                   VideoCore::ShaderNotify* shader_notify, const Shader::Info& info_,                                   vk::ShaderModule spv_module_) -    : device{device_}, update_descriptor_queue{update_descriptor_queue_}, info{info_}, +    : device{device_}, pipeline_cache(pipeline_cache_), +      update_descriptor_queue{update_descriptor_queue_}, info{info_},        spv_module(std::move(spv_module_)) {      if (shader_notify) {          shader_notify->MarkShaderBuilding(); @@ -56,23 +58,27 @@ ComputePipeline::ComputePipeline(const Device& device_, DescriptorPool& descript          if (device.IsKhrPipelineExecutablePropertiesEnabled()) {              flags |= VK_PIPELINE_CREATE_CAPTURE_STATISTICS_BIT_KHR;          } -        pipeline = device.GetLogical().CreateComputePipeline({ -            .sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO, -            .pNext = nullptr, -            .flags = flags, -            .stage{ -                .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, -                .pNext = device.IsExtSubgroupSizeControlSupported() ? &subgroup_size_ci : nullptr, -                .flags = 0, -                .stage = VK_SHADER_STAGE_COMPUTE_BIT, -                .module = *spv_module, -                .pName = "main", -                .pSpecializationInfo = nullptr, +        pipeline = device.GetLogical().CreateComputePipeline( +            { +                .sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO, +                .pNext = nullptr, +                .flags = flags, +                .stage{ +                    .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, +                    .pNext = +                        device.IsExtSubgroupSizeControlSupported() ? &subgroup_size_ci : nullptr, +                    .flags = 0, +                    .stage = VK_SHADER_STAGE_COMPUTE_BIT, +                    .module = *spv_module, +                    .pName = "main", +                    .pSpecializationInfo = nullptr, +                }, +                .layout = *pipeline_layout, +                .basePipelineHandle = 0, +                .basePipelineIndex = 0,              }, -            .layout = *pipeline_layout, -            .basePipelineHandle = 0, -            .basePipelineIndex = 0, -        }); +            *pipeline_cache); +          if (pipeline_statistics) {              pipeline_statistics->Collect(*pipeline);          } 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;  class ComputePipeline {  public: -    explicit ComputePipeline(const Device& device, DescriptorPool& descriptor_pool, +    explicit ComputePipeline(const Device& device, vk::PipelineCache& pipeline_cache, +                             DescriptorPool& descriptor_pool,                               UpdateDescriptorQueue& update_descriptor_queue,                               Common::ThreadWorker* thread_worker,                               PipelineStatistics* pipeline_statistics, @@ -46,6 +47,7 @@ public:  private:      const Device& device; +    vk::PipelineCache& pipeline_cache;      UpdateDescriptorQueue& update_descriptor_queue;      Shader::Info info; 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  GraphicsPipeline::GraphicsPipeline(      Scheduler& scheduler_, BufferCache& buffer_cache_, TextureCache& texture_cache_, -    VideoCore::ShaderNotify* shader_notify, const Device& device_, DescriptorPool& descriptor_pool, +    vk::PipelineCache& pipeline_cache_, VideoCore::ShaderNotify* shader_notify, +    const Device& device_, DescriptorPool& descriptor_pool,      UpdateDescriptorQueue& update_descriptor_queue_, Common::ThreadWorker* worker_thread,      PipelineStatistics* pipeline_statistics, RenderPassCache& render_pass_cache,      const GraphicsPipelineCacheKey& key_, std::array<vk::ShaderModule, NUM_STAGES> stages,      const std::array<const Shader::Info*, NUM_STAGES>& infos) -    : key{key_}, device{device_}, texture_cache{texture_cache_}, -      buffer_cache{buffer_cache_}, scheduler{scheduler_}, +    : key{key_}, device{device_}, texture_cache{texture_cache_}, buffer_cache{buffer_cache_}, +      pipeline_cache(pipeline_cache_), scheduler{scheduler_},        update_descriptor_queue{update_descriptor_queue_}, spv_modules{std::move(stages)} {      if (shader_notify) {          shader_notify->MarkShaderBuilding(); @@ -897,27 +898,29 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) {      if (device.IsKhrPipelineExecutablePropertiesEnabled()) {          flags |= VK_PIPELINE_CREATE_CAPTURE_STATISTICS_BIT_KHR;      } -    pipeline = device.GetLogical().CreateGraphicsPipeline({ -        .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, -        .pNext = nullptr, -        .flags = flags, -        .stageCount = static_cast<u32>(shader_stages.size()), -        .pStages = shader_stages.data(), -        .pVertexInputState = &vertex_input_ci, -        .pInputAssemblyState = &input_assembly_ci, -        .pTessellationState = &tessellation_ci, -        .pViewportState = &viewport_ci, -        .pRasterizationState = &rasterization_ci, -        .pMultisampleState = &multisample_ci, -        .pDepthStencilState = &depth_stencil_ci, -        .pColorBlendState = &color_blend_ci, -        .pDynamicState = &dynamic_state_ci, -        .layout = *pipeline_layout, -        .renderPass = render_pass, -        .subpass = 0, -        .basePipelineHandle = nullptr, -        .basePipelineIndex = 0, -    }); +    pipeline = device.GetLogical().CreateGraphicsPipeline( +        { +            .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, +            .pNext = nullptr, +            .flags = flags, +            .stageCount = static_cast<u32>(shader_stages.size()), +            .pStages = shader_stages.data(), +            .pVertexInputState = &vertex_input_ci, +            .pInputAssemblyState = &input_assembly_ci, +            .pTessellationState = &tessellation_ci, +            .pViewportState = &viewport_ci, +            .pRasterizationState = &rasterization_ci, +            .pMultisampleState = &multisample_ci, +            .pDepthStencilState = &depth_stencil_ci, +            .pColorBlendState = &color_blend_ci, +            .pDynamicState = &dynamic_state_ci, +            .layout = *pipeline_layout, +            .renderPass = render_pass, +            .subpass = 0, +            .basePipelineHandle = nullptr, +            .basePipelineIndex = 0, +        }, +        *pipeline_cache);  }  void 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 {      static constexpr size_t NUM_STAGES = Tegra::Engines::Maxwell3D::Regs::MaxShaderStage;  public: -    explicit GraphicsPipeline(Scheduler& scheduler, BufferCache& buffer_cache, -                              TextureCache& texture_cache, VideoCore::ShaderNotify* shader_notify, -                              const Device& device, DescriptorPool& descriptor_pool, -                              UpdateDescriptorQueue& update_descriptor_queue, -                              Common::ThreadWorker* worker_thread, -                              PipelineStatistics* pipeline_statistics, -                              RenderPassCache& render_pass_cache, -                              const GraphicsPipelineCacheKey& key, -                              std::array<vk::ShaderModule, NUM_STAGES> stages, -                              const std::array<const Shader::Info*, NUM_STAGES>& infos); +    explicit GraphicsPipeline( +        Scheduler& scheduler, BufferCache& buffer_cache, TextureCache& texture_cache, +        vk::PipelineCache& pipeline_cache, VideoCore::ShaderNotify* shader_notify, +        const Device& device, DescriptorPool& descriptor_pool, +        UpdateDescriptorQueue& update_descriptor_queue, Common::ThreadWorker* worker_thread, +        PipelineStatistics* pipeline_statistics, RenderPassCache& render_pass_cache, +        const GraphicsPipelineCacheKey& key, std::array<vk::ShaderModule, NUM_STAGES> stages, +        const std::array<const Shader::Info*, NUM_STAGES>& infos);      GraphicsPipeline& operator=(GraphicsPipeline&&) noexcept = delete;      GraphicsPipeline(GraphicsPipeline&&) noexcept = delete; @@ -133,6 +131,7 @@ private:      const Device& device;      TextureCache& texture_cache;      BufferCache& buffer_cache; +    vk::PipelineCache& pipeline_cache;      Scheduler& scheduler;      UpdateDescriptorQueue& update_descriptor_queue; diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index 3046b72ab..e0e2be90c 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;  using VideoCommon::GraphicsEnvironment;  constexpr u32 CACHE_VERSION = 10; +constexpr std::array<char, 8> VULKAN_CACHE_MAGIC_NUMBER{'y', 'u', 'z', 'u', 'v', 'k', 'c', 'h'};  template <typename Container>  auto MakeSpan(Container& container) { @@ -284,6 +285,7 @@ PipelineCache::PipelineCache(RasterizerVulkan& rasterizer_, const Device& device        render_pass_cache{render_pass_cache_}, buffer_cache{buffer_cache_},        texture_cache{texture_cache_}, shader_notify{shader_notify_},        use_asynchronous_shaders{Settings::values.use_asynchronous_shaders.GetValue()}, +      use_vulkan_pipeline_cache{Settings::values.use_vulkan_driver_pipeline_cache.GetValue()},        workers(std::max(std::thread::hardware_concurrency(), 2U) - 1, "VkPipelineBuilder"),        serialization_thread(1, "VkPipelineSerialization") {      const auto& float_control{device.FloatControlProperties()}; @@ -362,7 +364,11 @@ PipelineCache::PipelineCache(RasterizerVulkan& rasterizer_, const Device& device      };  } -PipelineCache::~PipelineCache() = default; +PipelineCache::~PipelineCache() { +    if (use_vulkan_pipeline_cache) { +        SerializeVulkanPipelineCache(vulkan_pipeline_cache_filename, vulkan_pipeline_cache); +    } +}  GraphicsPipeline* PipelineCache::CurrentGraphicsPipeline() {      MICROPROFILE_SCOPE(Vulkan_PipelineCache); @@ -418,6 +424,11 @@ void PipelineCache::LoadDiskResources(u64 title_id, std::stop_token stop_loading      }      pipeline_cache_filename = base_dir / "vulkan.bin"; +    if (use_vulkan_pipeline_cache) { +        vulkan_pipeline_cache_filename = base_dir / "vulkan_pipelines.bin"; +        vulkan_pipeline_cache = LoadVulkanPipelineCache(vulkan_pipeline_cache_filename); +    } +      struct {          std::mutex mutex;          size_t total{}; @@ -496,6 +507,10 @@ void PipelineCache::LoadDiskResources(u64 title_id, std::stop_token stop_loading      workers.WaitForRequests(stop_loading); +    if (use_vulkan_pipeline_cache) { +        SerializeVulkanPipelineCache(vulkan_pipeline_cache_filename, vulkan_pipeline_cache); +    } +      if (state.statistics) {          state.statistics->Report();      } @@ -616,10 +631,10 @@ std::unique_ptr<GraphicsPipeline> PipelineCache::CreateGraphicsPipeline(          previous_stage = &program;      }      Common::ThreadWorker* const thread_worker{build_in_parallel ? &workers : nullptr}; -    return std::make_unique<GraphicsPipeline>(scheduler, buffer_cache, texture_cache, -                                              &shader_notify, device, descriptor_pool, -                                              update_descriptor_queue, thread_worker, statistics, -                                              render_pass_cache, key, std::move(modules), infos); +    return std::make_unique<GraphicsPipeline>( +        scheduler, buffer_cache, texture_cache, vulkan_pipeline_cache, &shader_notify, device, +        descriptor_pool, update_descriptor_queue, thread_worker, statistics, render_pass_cache, key, +        std::move(modules), infos);  } catch (const Shader::Exception& exception) {      LOG_ERROR(Render_Vulkan, "{}", exception.what()); @@ -689,13 +704,99 @@ std::unique_ptr<ComputePipeline> PipelineCache::CreateComputePipeline(          spv_module.SetObjectNameEXT(name.c_str());      }      Common::ThreadWorker* const thread_worker{build_in_parallel ? &workers : nullptr}; -    return std::make_unique<ComputePipeline>(device, descriptor_pool, update_descriptor_queue, -                                             thread_worker, statistics, &shader_notify, -                                             program.info, std::move(spv_module)); +    return std::make_unique<ComputePipeline>(device, vulkan_pipeline_cache, descriptor_pool, +                                             update_descriptor_queue, thread_worker, statistics, +                                             &shader_notify, program.info, std::move(spv_module));  } catch (const Shader::Exception& exception) {      LOG_ERROR(Render_Vulkan, "{}", exception.what());      return nullptr;  } +void PipelineCache::SerializeVulkanPipelineCache(const std::filesystem::path& filename, +                                                 const vk::PipelineCache& pipeline_cache) try { +    std::ofstream file(filename, std::ios::binary); +    file.exceptions(std::ifstream::failbit); +    if (!file.is_open()) { +        LOG_ERROR(Common_Filesystem, "Failed to open Vulkan pipeline cache file {}", +                  Common::FS::PathToUTF8String(filename)); +        return; +    } +    file.write(VULKAN_CACHE_MAGIC_NUMBER.data(), VULKAN_CACHE_MAGIC_NUMBER.size()); + +    size_t cache_size = 0; +    std::vector<char> cache_data; +    if (pipeline_cache) { +        pipeline_cache.Read(&cache_size, nullptr); +        cache_data.resize(cache_size); +        pipeline_cache.Read(&cache_size, cache_data.data()); +    } +    file.write(cache_data.data(), cache_size); + +    LOG_INFO(Render_Vulkan, "Vulkan pipelines cached at: {}", +             Common::FS::PathToUTF8String(filename)); + +} catch (const std::ios_base::failure& e) { +    LOG_ERROR(Common_Filesystem, "{}", e.what()); +    if (!Common::FS::RemoveFile(filename)) { +        LOG_ERROR(Common_Filesystem, "Failed to delete Vulkan pipeline cache file {}", +                  Common::FS::PathToUTF8String(filename)); +    } +} + +vk::PipelineCache PipelineCache::LoadVulkanPipelineCache(const std::filesystem::path& filename) { +    const auto create_pipeline_cache = [this](size_t data_size, const void* data) { +        VkPipelineCacheCreateInfo pipeline_cache_ci = { +            .sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO, +            .pNext = nullptr, +            .flags = 0, +            .initialDataSize = data_size, +            .pInitialData = data}; +        return device.GetLogical().CreatePipelineCache(pipeline_cache_ci); +    }; +    try { +        std::ifstream file(filename, std::ios::binary | std::ios::ate); +        if (!file.is_open()) { +            return create_pipeline_cache(0, nullptr); +        } +        file.exceptions(std::ifstream::failbit); +        const auto end{file.tellg()}; +        file.seekg(0, std::ios::beg); + +        std::array<char, 8> magic_number; +        file.read(magic_number.data(), magic_number.size()); +        if (magic_number != VULKAN_CACHE_MAGIC_NUMBER) { +            file.close(); +            if (Common::FS::RemoveFile(filename)) { +                if (magic_number != VULKAN_CACHE_MAGIC_NUMBER) { +                    LOG_ERROR(Common_Filesystem, "Invalid Vulkan pipeline cache file"); +                } +            } else { +                LOG_ERROR(Common_Filesystem, +                          "Invalid Vulkan pipeline cache file and failed to delete it in \"{}\"", +                          Common::FS::PathToUTF8String(filename)); +            } +            return create_pipeline_cache(0, nullptr); +        } + +        const size_t cache_size = static_cast<size_t>(end) - magic_number.size(); +        std::vector<char> cache_data(cache_size); +        file.read(cache_data.data(), cache_size); + +        LOG_INFO(Render_Vulkan, +                 "Loaded Vulkan pipeline cache: ", Common::FS::PathToUTF8String(filename)); + +        return create_pipeline_cache(cache_size, cache_data.data()); + +    } catch (const std::ios_base::failure& e) { +        LOG_ERROR(Common_Filesystem, "{}", e.what()); +        if (!Common::FS::RemoveFile(filename)) { +            LOG_ERROR(Common_Filesystem, "Failed to delete Vulkan pipeline cache file {}", +                      Common::FS::PathToUTF8String(filename)); +        } + +        return create_pipeline_cache(0, nullptr); +    } +} +  } // 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..cf3bd6b85 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.h +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.h @@ -135,6 +135,11 @@ private:                                                             PipelineStatistics* statistics,                                                             bool build_in_parallel); +    void SerializeVulkanPipelineCache(const std::filesystem::path& filename, +                                      const vk::PipelineCache& pipeline_cache); + +    vk::PipelineCache LoadVulkanPipelineCache(const std::filesystem::path& filename); +      const Device& device;      Scheduler& scheduler;      DescriptorPool& descriptor_pool; @@ -144,6 +149,7 @@ private:      TextureCache& texture_cache;      VideoCore::ShaderNotify& shader_notify;      bool use_asynchronous_shaders{}; +    bool use_vulkan_pipeline_cache{};      GraphicsPipelineCacheKey graphics_key{};      GraphicsPipeline* current_pipeline{}; @@ -158,6 +164,9 @@ private:      std::filesystem::path pipeline_cache_filename; +    std::filesystem::path vulkan_pipeline_cache_filename; +    vk::PipelineCache vulkan_pipeline_cache; +      Common::ThreadWorker workers;      Common::ThreadWorker serialization_thread;      DynamicFeatures dynamic_features; diff --git a/src/video_core/vulkan_common/vulkan_wrapper.cpp b/src/video_core/vulkan_common/vulkan_wrapper.cpp index 861767c13..61be1fce1 100644 --- a/src/video_core/vulkan_common/vulkan_wrapper.cpp +++ b/src/video_core/vulkan_common/vulkan_wrapper.cpp @@ -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);  } diff --git a/src/video_core/vulkan_common/vulkan_wrapper.h b/src/video_core/vulkan_common/vulkan_wrapper.h index accfad8c1..412779b51 100644 --- a/src/video_core/vulkan_common/vulkan_wrapper.h +++ b/src/video_core/vulkan_common/vulkan_wrapper.h @@ -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; diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index e9425b5bd..fbfa3ba35 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp @@ -709,6 +709,7 @@ void Config::ReadRendererValues() {      ReadGlobalSetting(Settings::values.use_asynchronous_shaders);      ReadGlobalSetting(Settings::values.use_fast_gpu_time);      ReadGlobalSetting(Settings::values.use_pessimistic_flushes); +    ReadGlobalSetting(Settings::values.use_vulkan_driver_pipeline_cache);      ReadGlobalSetting(Settings::values.bg_red);      ReadGlobalSetting(Settings::values.bg_green);      ReadGlobalSetting(Settings::values.bg_blue); @@ -1348,6 +1349,7 @@ void Config::SaveRendererValues() {      WriteGlobalSetting(Settings::values.use_asynchronous_shaders);      WriteGlobalSetting(Settings::values.use_fast_gpu_time);      WriteGlobalSetting(Settings::values.use_pessimistic_flushes); +    WriteGlobalSetting(Settings::values.use_vulkan_driver_pipeline_cache);      WriteGlobalSetting(Settings::values.bg_red);      WriteGlobalSetting(Settings::values.bg_green);      WriteGlobalSetting(Settings::values.bg_blue); diff --git a/src/yuzu/configuration/configure_graphics_advanced.cpp b/src/yuzu/configuration/configure_graphics_advanced.cpp index 01f074699..b3862e707 100644 --- a/src/yuzu/configuration/configure_graphics_advanced.cpp +++ b/src/yuzu/configuration/configure_graphics_advanced.cpp @@ -29,6 +29,8 @@ void ConfigureGraphicsAdvanced::SetConfiguration() {      ui->use_asynchronous_shaders->setChecked(Settings::values.use_asynchronous_shaders.GetValue());      ui->use_fast_gpu_time->setChecked(Settings::values.use_fast_gpu_time.GetValue());      ui->use_pessimistic_flushes->setChecked(Settings::values.use_pessimistic_flushes.GetValue()); +    ui->use_vulkan_driver_pipeline_cache->setChecked( +        Settings::values.use_vulkan_driver_pipeline_cache.GetValue());      if (Settings::IsConfiguringGlobal()) {          ui->gpu_accuracy->setCurrentIndex( @@ -58,6 +60,9 @@ void ConfigureGraphicsAdvanced::ApplyConfiguration() {                                               ui->use_fast_gpu_time, use_fast_gpu_time);      ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_pessimistic_flushes,                                               ui->use_pessimistic_flushes, use_pessimistic_flushes); +    ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_vulkan_driver_pipeline_cache, +                                             ui->use_vulkan_driver_pipeline_cache, +                                             use_vulkan_driver_pipeline_cache);  }  void ConfigureGraphicsAdvanced::changeEvent(QEvent* event) { @@ -82,6 +87,8 @@ void ConfigureGraphicsAdvanced::SetupPerGameUI() {          ui->use_fast_gpu_time->setEnabled(Settings::values.use_fast_gpu_time.UsingGlobal());          ui->use_pessimistic_flushes->setEnabled(              Settings::values.use_pessimistic_flushes.UsingGlobal()); +        ui->use_vulkan_driver_pipeline_cache->setEnabled( +            Settings::values.use_vulkan_driver_pipeline_cache.UsingGlobal());          ui->anisotropic_filtering_combobox->setEnabled(              Settings::values.max_anisotropy.UsingGlobal()); diff --git a/src/yuzu/configuration/configure_graphics_advanced.h b/src/yuzu/configuration/configure_graphics_advanced.h index 12e816905..891efc068 100644 --- a/src/yuzu/configuration/configure_graphics_advanced.h +++ b/src/yuzu/configuration/configure_graphics_advanced.h @@ -40,6 +40,7 @@ private:      ConfigurationShared::CheckState use_asynchronous_shaders;      ConfigurationShared::CheckState use_fast_gpu_time;      ConfigurationShared::CheckState use_pessimistic_flushes; +    ConfigurationShared::CheckState use_vulkan_driver_pipeline_cache;      const Core::System& system;  }; diff --git a/src/yuzu/configuration/configure_graphics_advanced.ui b/src/yuzu/configuration/configure_graphics_advanced.ui index 87a121471..67878b057 100644 --- a/src/yuzu/configuration/configure_graphics_advanced.ui +++ b/src/yuzu/configuration/configure_graphics_advanced.ui @@ -110,6 +110,16 @@           </widget>          </item>          <item> +         <widget class="QCheckBox" name="use_vulkan_driver_pipeline_cache"> +          <property name="toolTip"> +            <string>Enables GPU vendor-specific pipeline cache. This option can improve shader loading time significantly in cases where the Vulkan driver does not store pipeline cache files automatically.</string> +          </property> +          <property name="text"> +           <string>Use Vulkan pipeline cache (Hack)</string> +          </property> +         </widget> +        </item> +        <item>           <widget class="QWidget" name="af_layout" native="true">            <layout class="QHBoxLayout" name="horizontalLayout_1">             <property name="leftMargin"> diff --git a/src/yuzu_cmd/config.cpp b/src/yuzu_cmd/config.cpp index 1e45e57bc..b2d690bb6 100644 --- a/src/yuzu_cmd/config.cpp +++ b/src/yuzu_cmd/config.cpp @@ -321,6 +321,7 @@ void Config::ReadValues() {      ReadSetting("Renderer", Settings::values.accelerate_astc);      ReadSetting("Renderer", Settings::values.use_fast_gpu_time);      ReadSetting("Renderer", Settings::values.use_pessimistic_flushes); +    ReadSetting("Renderer", Settings::values.use_vulkan_driver_pipeline_cache);      ReadSetting("Renderer", Settings::values.bg_red);      ReadSetting("Renderer", Settings::values.bg_green); diff --git a/src/yuzu_cmd/default_ini.h b/src/yuzu_cmd/default_ini.h index 6fcf04e1b..7f8c8af0c 100644 --- a/src/yuzu_cmd/default_ini.h +++ b/src/yuzu_cmd/default_ini.h @@ -350,6 +350,10 @@ use_fast_gpu_time =  # 0: Off (default), 1: On  use_pessimistic_flushes = +# Enables storing a cache file for Vulkan pipelines, which can significantly improve shader load time. +# 0: Off (default), 1: On +use_vulkan_driver_pipeline_cache = +  # Whether to use garbage collection or not for GPU caches.  # 0 (default): Off, 1: On  use_caches_gc = | 
