aboutsummaryrefslogtreecommitdiff
path: root/src/video_core/renderer_vulkan
diff options
context:
space:
mode:
authorTakoroka <137927095+Takoroka@users.noreply.github.com>2026-10-30 13:48:24 -0400
committerTakoroka <137927095+Takoroka@users.noreply.github.com>2026-10-30 13:48:24 -0400
commit01effa81ab0e151f8cfd674bf4da952d24645943 (patch)
treedf3037540d582c4119acef689d4531976cac7f32 /src/video_core/renderer_vulkan
parentdfe734dce6aed88038d2fd8f54b06c6b0304cf36 (diff)
parentea33ad1865970ee731e5f74dbcc26ca472798afe (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.cpp25
-rw-r--r--src/video_core/renderer_vulkan/vk_texture_cache.cpp22
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();