From 2a35b19166ab577674339a514bb7eb1657409443 Mon Sep 17 00:00:00 2001 From: Takoroka <137927095+Takoroka@users.noreply.github.com> Date: Wed, 28 Oct 2026 13:55:29 -0400 Subject: Vulkan: unbacked sparse images for textures too large to back Title 1 samples an 8192x8192, 12-level, 68-layer array (a sparse virtual texture, ~23 GB): vkCreateImage failed and Eden aborted, or VMA put it in system memory and staged a full upload (34 GB private). Images over 2^28 texels are now created sparse-resident with no memory bound; the texture cache neither uploads nor downloads them. Images merely over the VRAM budget are allocated without the budget limit instead of failing. --- src/video_core/texture_cache/texture_cache.h | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'src/video_core/texture_cache/texture_cache.h') diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h index cd4ef82dbe..f3da5684a5 100644 --- a/src/video_core/texture_cache/texture_cache.h +++ b/src/video_core/texture_cache/texture_cache.h @@ -597,7 +597,7 @@ void TextureCache

::WriteMemory(DAddr cpu_addr, size_t size) { template bool TextureCache

::IsDownloadable(const ImageBase& image) const noexcept { - if (!image.IsSafeGpuCopy()) { + if (!image.IsSafeGpuCopy() || True(image.flags & ImageFlagBits::Unbacked)) { return false; } if (image.info.num_samples == 1) { @@ -1146,6 +1146,12 @@ void TextureCache

::RefreshContents(Image& image, ImageId image_id) { TrackImage(image, image_id); + if (True(image.flags & ImageFlagBits::Unbacked)) { + // Nothing to upload into (and staging it could take tens of GB). + runtime.TransitionImageLayout(image); + return; + } + if (image.info.num_samples > 1 && !runtime.CanUploadMSAA()) { LOG_WARNING(HW_GPU, "MSAA image uploads are not implemented"); runtime.TransitionImageLayout(image); @@ -2669,7 +2675,8 @@ void TextureCache

::BindRenderTarget(ImageViewId* old_id, ImageViewId new_id) } if (new_id) { const ImageViewBase& old_view = slot_image_views[new_id]; - if (True(old_view.flags & ImageViewFlagBits::PreemtiveDownload)) { + if (True(old_view.flags & ImageViewFlagBits::PreemtiveDownload) && + False(slot_images[old_view.image_id].flags & ImageFlagBits::Unbacked)) { const PendingDownload new_download{true, 0, old_view.image_id}; uncommitted_downloads.emplace_back(new_download); } -- cgit v1.2.3