diff options
| author | givethesourceplox <272928635+givethesourceplox@users.noreply.github.com> | 2026-10-30 09:45:53 -0300 |
|---|---|---|
| committer | kraibse <33869366+kraibse@users.noreply.github.com> | 2026-10-30 17:48:04 +0100 |
| commit | ea33ad1865970ee731e5f74dbcc26ca472798afe (patch) | |
| tree | f73345d1d273bcbab8dfbd708a459b8ba6afee0b | |
| parent | 6f5e137ec4eb83bbff9ea15f1ad1a8407cfc0cba (diff) | |
vulkan: write the driver pipeline cache atomically; reject truncated ones
The emulator stopped while saving vulkan_pipelines.bin left it empty, and
every later boot terminated: the header read throws ios_base::failure,
and macOS's libc++ throws one the handler's type doesn't match. Write the
cache to a temporary file and rename it over the old one, and treat a
file shorter than its header as invalid without reading it.
Assisted-by: Claude (Anthropic)
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_pipeline_cache.cpp | 23 |
1 files changed, 22 insertions, 1 deletions
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index ac878ddfef..2c64f3375b 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp @@ -1138,7 +1138,11 @@ std::unique_ptr<ComputePipeline> PipelineCache::CreateComputePipeline( void PipelineCache::SerializeVulkanPipelineCache(const std::filesystem::path& filename, const vk::PipelineCache& pipeline_cache, u32 cache_version) try { - std::ofstream file(filename, std::ios::binary); + // Written beside the cache and renamed over it: the emulator stopped mid-write left the cache + // empty, and every later boot failed to read it. + auto temporary = filename; + temporary += ".tmp"; + std::ofstream file(temporary, std::ios::binary); file.exceptions(std::ifstream::failbit); if (!file.is_open()) { LOG_ERROR(Common_Filesystem, "Failed to open Vulkan driver pipeline cache file {}", @@ -1156,6 +1160,15 @@ void PipelineCache::SerializeVulkanPipelineCache(const std::filesystem::path& fi pipeline_cache.Read(&cache_size, cache_data.data()); } file.write(cache_data.data(), cache_size); + file.close(); + std::error_code error; + std::filesystem::rename(temporary, filename, error); + if (error) { + LOG_ERROR(Common_Filesystem, "Failed to replace Vulkan driver pipeline cache file {}: {}", + Common::FS::PathToUTF8String(filename), error.message()); + std::filesystem::remove(temporary, error); + return; + } LOG_INFO(Render_Vulkan, "Vulkan driver pipelines cached at: {}", Common::FS::PathToUTF8String(filename)); @@ -1190,6 +1203,14 @@ vk::PipelineCache PipelineCache::LoadVulkanPipelineCache(const std::filesystem:: std::array<char, 8> magic_number; u32 cache_version; + // A file cut short (the emulator stopped while writing it) would throw from the reads + // below, and macOS's libc++ throws an ios_base::failure the handler doesn't match. + if (static_cast<size_t>(end) < magic_number.size() + sizeof(cache_version)) { + file.close(); + LOG_ERROR(Common_Filesystem, "Truncated Vulkan driver pipeline cache file, deleting it"); + Common::FS::RemoveFile(filename); + return create_pipeline_cache(0, nullptr); + } file.read(magic_number.data(), magic_number.size()) .read(reinterpret_cast<char*>(&cache_version), sizeof(cache_version)); if (magic_number != VULKAN_CACHE_MAGIC_NUMBER || cache_version != expected_cache_version) { |
