From eb8706e3669ebd6c8710af03739c60bcee9bfcbb Mon Sep 17 00:00:00 2001 From: CamilleLaVey Date: Thu, 30 Jul 2026 19:53:34 -0400 Subject: [PATCH] Funny experiment for pipelines --- src/video_core/renderer_vulkan/blit_image.cpp | 18 +-- .../renderer_vulkan/present/util.cpp | 2 +- .../renderer_vulkan/vk_compute_pass.cpp | 2 +- .../vulkan_common/vulkan_device.cpp | 104 ++++++++++++++++++ src/video_core/vulkan_common/vulkan_device.h | 9 ++ 5 files changed, 124 insertions(+), 11 deletions(-) diff --git a/src/video_core/renderer_vulkan/blit_image.cpp b/src/video_core/renderer_vulkan/blit_image.cpp index e1c33e27ae..f4af87fb00 100644 --- a/src/video_core/renderer_vulkan/blit_image.cpp +++ b/src/video_core/renderer_vulkan/blit_image.cpp @@ -1270,7 +1270,7 @@ VkPipeline BlitImageHelper::FindOrEmplaceColorPipeline(const BlitImagePipelineKe .subpass = 0, .basePipelineHandle = VK_NULL_HANDLE, .basePipelineIndex = 0, - })); + }, device.StaticPipelineCache())); return *blit_color_pipelines.back(); } @@ -1304,7 +1304,7 @@ VkPipeline BlitImageHelper::FindOrEmplaceDepthStencilPipeline(const BlitImagePip .subpass = 0, .basePipelineHandle = VK_NULL_HANDLE, .basePipelineIndex = 0, - })); + }, device.StaticPipelineCache())); return *blit_depth_stencil_pipelines.back(); } @@ -1365,7 +1365,7 @@ VkPipeline BlitImageHelper::FindOrEmplaceClearColorPipeline(const BlitImagePipel .subpass = 0, .basePipelineHandle = VK_NULL_HANDLE, .basePipelineIndex = 0, - })); + }, device.StaticPipelineCache())); return *clear_color_pipelines.back(); } @@ -1434,7 +1434,7 @@ VkPipeline BlitImageHelper::FindOrEmplaceClearStencilPipeline( .subpass = 0, .basePipelineHandle = VK_NULL_HANDLE, .basePipelineIndex = 0, - })); + }, device.StaticPipelineCache())); return *clear_stencil_pipelines.back(); } @@ -1479,7 +1479,7 @@ VkPipeline BlitImageHelper::FindOrEmplaceBlitColorMSAAPipeline(const BlitMSAAPip .subpass = 0, .basePipelineHandle = VK_NULL_HANDLE, .basePipelineIndex = 0, - })); + }, device.StaticPipelineCache())); return *blit_msaa_color_pipelines.back(); } @@ -1523,7 +1523,7 @@ VkPipeline BlitImageHelper::FindOrEmplaceResolveDepthStencilPipeline( .subpass = 0, .basePipelineHandle = VK_NULL_HANDLE, .basePipelineIndex = 0, - })); + }, device.StaticPipelineCache())); return *pipelines.back(); } @@ -1596,7 +1596,7 @@ VkPipeline BlitImageHelper::FindOrEmplaceMSAACopyPipeline(const MSAACopyPipeline .subpass = 0, .basePipelineHandle = VK_NULL_HANDLE, .basePipelineIndex = 0, - })); + }, device.StaticPipelineCache())); return *msaa_copy_pipelines.back(); } @@ -1641,7 +1641,7 @@ void BlitImageHelper::ConvertPipelineEx(vk::Pipeline& pipeline, const Framebuffe .subpass = 0, .basePipelineHandle = VK_NULL_HANDLE, .basePipelineIndex = 0, - }); + }, device.StaticPipelineCache()); } void BlitImageHelper::ConvertPipelineColorTargetEx(vk::Pipeline& pipeline, @@ -1688,7 +1688,7 @@ void BlitImageHelper::ConvertPipeline(vk::Pipeline& pipeline, const Framebuffer* .subpass = 0, .basePipelineHandle = VK_NULL_HANDLE, .basePipelineIndex = 0, - }); + }, device.StaticPipelineCache()); } } // namespace Vulkan diff --git a/src/video_core/renderer_vulkan/present/util.cpp b/src/video_core/renderer_vulkan/present/util.cpp index 2b83902bc0..33b69c06d4 100644 --- a/src/video_core/renderer_vulkan/present/util.cpp +++ b/src/video_core/renderer_vulkan/present/util.cpp @@ -491,7 +491,7 @@ static vk::Pipeline CreateWrappedPipelineImpl( .subpass = 0, .basePipelineHandle = 0, .basePipelineIndex = 0, - }); + }, device.StaticPipelineCache()); } vk::Pipeline CreateWrappedPipeline(const Device& device, vk::RenderPass& renderpass, diff --git a/src/video_core/renderer_vulkan/vk_compute_pass.cpp b/src/video_core/renderer_vulkan/vk_compute_pass.cpp index 80c434dc8f..ab58560170 100644 --- a/src/video_core/renderer_vulkan/vk_compute_pass.cpp +++ b/src/video_core/renderer_vulkan/vk_compute_pass.cpp @@ -268,7 +268,7 @@ ComputePass::ComputePass(const Device& device_, Scheduler& scheduler, Descriptor .layout = *layout, .basePipelineHandle = {}, .basePipelineIndex = 0, - }); + }, device.StaticPipelineCache()); } ComputePass::~ComputePass() = default; diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp index 15ec5ba8fc..f33505f4f5 100644 --- a/src/video_core/vulkan_common/vulkan_device.cpp +++ b/src/video_core/vulkan_common/vulkan_device.cpp @@ -8,6 +8,8 @@ #include #include #include +#include +#include #include #include #include @@ -17,6 +19,8 @@ #include #include "common/assert.h" +#include "common/fs/fs.h" +#include "common/fs/path_util.h" #include "common/literals.h" #include #include "common/settings.h" @@ -394,6 +398,17 @@ std::vector ExtensionListForVulkan( return output; } +constexpr std::array STATIC_CACHE_MAGIC_NUMBER{'e', 'd', 'e', 'n', 's', 't', 'p', 'c'}; +constexpr u32 STATIC_CACHE_VERSION = 1; + +std::filesystem::path StaticPipelineCacheFilename() { + const auto shader_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::ShaderDir); + if (!Common::FS::CreateDir(shader_dir)) { + return {}; + } + return shader_dir / "vulkan_static_pipelines.bin"; +} + } // Anonymous namespace void Device::RemoveExtension(bool& extension, const std::string& extension_name) { @@ -778,16 +793,105 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR limits.storageImageSampleCounts); } + owns_static_pipeline_cache = surface != VkSurfaceKHR{}; + LoadStaticPipelineCache(); + // Initialize GPU logging if enabled InitializeGPULogging(); } Device::~Device() { + SaveStaticPipelineCache(); ShutdownGPULogging(); vk::FlushDeletionQueue(); vmaDestroyAllocator(allocator); } +void Device::LoadStaticPipelineCache() { + const auto create = [this](size_t size, const void* data) { + static_pipeline_cache = logical.CreatePipelineCache({ + .sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .initialDataSize = size, + .pInitialData = data, + }); + }; + if (!owns_static_pipeline_cache) { + create(0, nullptr); + return; + } + const auto filename = StaticPipelineCacheFilename(); + if (filename.empty()) { + create(0, nullptr); + return; + } + std::vector data; + try { + std::ifstream file(filename, std::ios::binary | std::ios::ate); + if (!file.is_open()) { + create(0, nullptr); + return; + } + file.exceptions(std::ifstream::failbit | std::ifstream::badbit); + const size_t total = static_cast(file.tellg()); + file.seekg(0, std::ios::beg); + std::array magic{}; + u32 version{}; + if (total < magic.size() + sizeof(version)) { + create(0, nullptr); + return; + } + file.read(magic.data(), magic.size()) + .read(reinterpret_cast(&version), sizeof(version)); + if (magic != STATIC_CACHE_MAGIC_NUMBER || version != STATIC_CACHE_VERSION) { + LOG_INFO(Render_Vulkan, "Discarding stale static pipeline cache"); + create(0, nullptr); + return; + } + data.resize(total - magic.size() - sizeof(version)); + file.read(data.data(), static_cast(data.size())); + } catch (const std::ios_base::failure& e) { + LOG_WARNING(Render_Vulkan, "Failed to read static pipeline cache: {}", e.what()); + create(0, nullptr); + return; + } + create(data.size(), data.empty() ? nullptr : data.data()); + LOG_INFO(Render_Vulkan, "Loaded {} bytes of static pipeline cache", data.size()); +} + +void Device::SaveStaticPipelineCache() const { + if (!owns_static_pipeline_cache || !static_pipeline_cache) { + return; + } + const auto filename = StaticPipelineCacheFilename(); + if (filename.empty()) { + return; + } + size_t size = 0; + std::vector data; + static_pipeline_cache.Read(&size, nullptr); + if (size == 0) { + return; + } + data.resize(size); + static_pipeline_cache.Read(&size, data.data()); + try { + std::ofstream file(filename, std::ios::binary | std::ios::trunc); + file.exceptions(std::ofstream::failbit); + if (!file.is_open()) { + return; + } + file.write(STATIC_CACHE_MAGIC_NUMBER.data(), STATIC_CACHE_MAGIC_NUMBER.size()) + .write(reinterpret_cast(&STATIC_CACHE_VERSION), + sizeof(STATIC_CACHE_VERSION)) + .write(data.data(), static_cast(size)); + } catch (const std::ios_base::failure& e) { + LOG_WARNING(Render_Vulkan, "Failed to write static pipeline cache: {}", e.what()); + Common::FS::RemoveFile(filename); + } +} + VkFormat Device::GetSupportedFormat(VkFormat wanted_format, VkFormatFeatureFlags wanted_usage, FormatType format_type) const { if (IsFormatSupported(wanted_format, wanted_usage, format_type)) { diff --git a/src/video_core/vulkan_common/vulkan_device.h b/src/video_core/vulkan_common/vulkan_device.h index d78b81df95..98234b0991 100644 --- a/src/video_core/vulkan_common/vulkan_device.h +++ b/src/video_core/vulkan_common/vulkan_device.h @@ -282,6 +282,10 @@ public: return physical; } + VkPipelineCache StaticPipelineCache() const noexcept { + return *static_pipeline_cache; + } + /// Returns the main graphics queue. vk::Queue GetGraphicsQueue() const { return graphics_queue; @@ -1184,6 +1188,9 @@ private: /// Returns true if the device natively supports blitting depth stencil images. bool TestDepthStencilBlits(VkFormat format) const; + void LoadStaticPipelineCache(); + void SaveStaticPipelineCache() const; + private: VkInstance instance; ///< Vulkan instance. VmaAllocator allocator; ///< VMA allocator. @@ -1193,6 +1200,8 @@ private: vk::Device logical; ///< Logical device. vk::Queue graphics_queue; ///< Main graphics queue. vk::Queue present_queue; ///< Main present queue. + vk::PipelineCache static_pipeline_cache; + bool owns_static_pipeline_cache{}; u32 instance_version{}; ///< Vulkan instance version. u32 graphics_family{}; ///< Main graphics queue family index. u32 present_family{}; ///< Main present queue family index.