diff options
| author | Takoroka <137927095+Takoroka@users.noreply.github.com> | 2026-10-30 13:48:24 -0400 |
|---|---|---|
| committer | Takoroka <137927095+Takoroka@users.noreply.github.com> | 2026-10-30 13:48:24 -0400 |
| commit | 01effa81ab0e151f8cfd674bf4da952d24645943 (patch) | |
| tree | df3037540d582c4119acef689d4531976cac7f32 /src/video_core/renderer_vulkan | |
| parent | dfe734dce6aed88038d2fd8f54b06c6b0304cf36 (diff) | |
| parent | ea33ad1865970ee731e5f74dbcc26ca472798afe (diff) | |
Merge branch 'nx2' into nx2-experimental
# Conflicts:
# src/video_core/nx2.h
# src/video_core/renderer_vulkan/vk_texture_cache.cpp
# src/video_core/texture_cache/texture_cache.h
Diffstat (limited to 'src/video_core/renderer_vulkan')
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_pipeline_cache.cpp | 25 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_texture_cache.cpp | 22 |
2 files changed, 45 insertions, 2 deletions
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index 17f57983e3..2c64f3375b 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp @@ -1089,7 +1089,7 @@ std::unique_ptr<ComputePipeline> PipelineCache::CreateComputePipeline( const VkDriverIdKHR driver_id = device.GetDriverID(); const bool needs_shared_mem_clamp = driver_id == VK_DRIVER_ID_QUALCOMM_PROPRIETARY || - driver_id == VK_DRIVER_ID_ARM_PROPRIETARY; + driver_id == VK_DRIVER_ID_ARM_PROPRIETARY || driver_id == VK_DRIVER_ID_MOLTENVK; const u32 max_shared_memory = device.GetMaxComputeSharedMemorySize(); if (needs_shared_mem_clamp && program.shared_memory_size > max_shared_memory) { LOG_WARNING(Render_Vulkan, @@ -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) { diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp index e192d8d7b1..d5136a2abe 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp @@ -2635,6 +2635,20 @@ std::vector<u32> Image::BindLayers(std::span<const u32> layers) { const VkDeviceSize cap = SparseLayersCap(device); std::vector<VkSparseImageMemoryBind> image_binds; std::vector<VkSparseMemoryBind> opaque_binds; + const bool tail_was_bound = s.tail_memory != VK_NULL_HANDLE; + std::vector<u32> fresh; // Layers given memory by this call + // A failed bind leaves the layers as they were, so the next call tries them again. + const auto roll_back = [&] { + for (const u32 layer : fresh) { + s.allocator->FreeSparseMemory(s.layer_memory[layer]); + s.layer_memory[layer] = VK_NULL_HANDLE; + s.bound_bytes -= s.layer_bytes; + } + if (s.tail_memory != VK_NULL_HANDLE && !tail_was_bound) { + s.allocator->FreeSparseMemory(s.tail_memory); + s.tail_memory = VK_NULL_HANDLE; + } + }; for (const u32 layer : layers) { if (s.layer_memory[layer] != VK_NULL_HANDLE) { bound.push_back(layer); @@ -2662,6 +2676,7 @@ std::vector<u32> Image::BindLayers(std::span<const u32> layers) { } s.layer_memory[layer] = allocation; s.bound_bytes += s.layer_bytes; + fresh.push_back(layer); for (u32 level = 0; level < tail_lod; ++level) { const u32 width = (std::max)(s.width >> level, 1U); const u32 height = (std::max)(s.height >> level, 1U); @@ -2708,6 +2723,12 @@ std::vector<u32> Image::BindLayers(std::span<const u32> layers) { .memoryOffset = offset, .flags = 0, }); + } else { + LOG_WARNING(Render_Vulkan, "Sparse layered image {:#x}: out of device memory for the " + "mip tail", + gpu_addr); + roll_back(); + return {}; } } if (image_binds.empty() && opaque_binds.empty()) { @@ -2752,6 +2773,7 @@ std::vector<u32> Image::BindLayers(std::span<const u32> layers) { if (result != VK_SUCCESS) { LOG_ERROR(Render_Vulkan, "Sparse layered image {:#x}: binding failed ({})", gpu_addr, static_cast<int>(result)); + roll_back(); return {}; } fence.Wait(); |
