aboutsummaryrefslogtreecommitdiff
path: root/src/video_core/vulkan_common/vulkan_device.cpp
diff options
context:
space:
mode:
authorLizzie and Samuel <lizzie@eden-emu.dev>2026-08-30 08:15:29 +0200
committercrueter <crueter@eden-emu.dev>2026-08-30 08:15:29 +0200
commit45b6ecff055cc6de6e7b9edc2239e0c6636de573 (patch)
tree6222194b48a56847d592ef46fba5378289c4ff28 /src/video_core/vulkan_common/vulkan_device.cpp
parent672bcbae012164ec59ef26ff79995c4585bd0e97 (diff)
[vulkan, vk_pipeline_cache] PSO Optimizations (#4294)
PR/Commit Owner: CamilleLaVey This PR prevents the recompilation of shaders when a new session has been started, based on data found on the recompiler, each new session does still recompile already cached shader cache, reducing the reaction and speed of games by at certain level, this prevent the warm-up with post sessions, only needed the initial warm-up and works globally for all games. Co-authored-by: CamilleLaVey <camillelavey99@gmail.com> Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4294 Reviewed-by: CamilleLaVey <camillelavey99@gmail.com> Reviewed-by: Maufeat <sahyno1996@gmail.com>
Diffstat (limited to 'src/video_core/vulkan_common/vulkan_device.cpp')
-rw-r--r--src/video_core/vulkan_common/vulkan_device.cpp100
1 files changed, 100 insertions, 0 deletions
diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp
index 9c0bc56a8b..b2cfd2c01d 100644
--- a/src/video_core/vulkan_common/vulkan_device.cpp
+++ b/src/video_core/vulkan_common/vulkan_device.cpp
@@ -7,6 +7,8 @@
#include <algorithm>
#include <bitset>
#include <chrono>
+#include <filesystem>
+#include <fstream>
#include <optional>
#include <thread>
#include <ankerl/unordered_dense.h>
@@ -16,6 +18,8 @@
#include <fmt/format.h>
#include "common/assert.h"
+#include "common/fs/fs.h"
+#include "common/fs/path_util.h"
#include "common/literals.h"
#include <ranges>
#include "common/settings.h"
@@ -393,6 +397,17 @@ std::vector<const char*> ExtensionListForVulkan(
return output;
}
+constexpr std::array<char, 8> 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) {
@@ -750,15 +765,100 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
vk::Check(vmaCreateAllocator(&allocator_info, &allocator));
+ owns_static_pipeline_cache = surface != VkSurfaceKHR{};
+ LoadStaticPipelineCache();
+
// Initialize GPU logging if enabled
InitializeGPULogging();
}
Device::~Device() {
+ SaveStaticPipelineCache();
ShutdownGPULogging();
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<char> 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<size_t>(file.tellg());
+ file.seekg(0, std::ios::beg);
+ std::array<char, 8> magic{};
+ u32 version{};
+ if (total < magic.size() + sizeof(version)) {
+ create(0, nullptr);
+ return;
+ }
+ file.read(magic.data(), magic.size())
+ .read(reinterpret_cast<char*>(&version), sizeof(version));
+ if (magic != STATIC_CACHE_MAGIC_NUMBER || version != STATIC_CACHE_VERSION) {
+ create(0, nullptr);
+ return;
+ }
+ data.resize(total - magic.size() - sizeof(version));
+ file.read(data.data(), static_cast<std::streamsize>(data.size()));
+ } catch (const std::ios_base::failure& e) {
+ create(0, nullptr);
+ return;
+ }
+ create(data.size(), data.empty() ? nullptr : data.data());
+}
+
+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<char> 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<const char*>(&STATIC_CACHE_VERSION),
+ sizeof(STATIC_CACHE_VERSION))
+ .write(data.data(), static_cast<std::streamsize>(size));
+ } catch (const std::ios_base::failure& e) {
+ 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)) {