aboutsummaryrefslogtreecommitdiff
path: root/src/video_core/vulkan_common/vulkan_device.cpp
diff options
context:
space:
mode:
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)) {