aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorkraibse <33869366+kraibse@users.noreply.github.com>2026-10-31 15:53:50 +0100
committerkraibse <33869366+kraibse@users.noreply.github.com>2026-11-01 17:29:56 +0100
commita855e8373f5575fddd172ec7ffc56a8c3904c3fb (patch)
treef486d7e29a6d72b16af773bafdf7c38394ed8047 /src
parent139b7e5efb7c4181f14e987706eef26ca1f327c0 (diff)
vulkan: back large sparse images normally on AMD
Lazy Switch 2 sparse regions made the texture cache create large images with no memory bound and sample them. AMD's drivers crash shortly after the first such draw (builds 49+). Skip the unbacked-image paths on AMD drivers; images get regular backing as in build 47.
Diffstat (limited to 'src')
-rw-r--r--src/video_core/renderer_vulkan/vk_texture_cache.cpp10
-rw-r--r--src/video_core/vulkan_common/vulkan_device.h8
2 files changed, 15 insertions, 3 deletions
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
index 5ba36feee9..3294af9c22 100644
--- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
@@ -172,7 +172,10 @@ constexpr VkBorderColor ConvertBorderColor(const std::array<float, 4>& color) {
// A large image over Switch 2 sparse blocks nobody has written (title 1's terrain layer pools, 2.9
// GB of R8/RG16/R16 that stay empty in the attract demo) is all zeros: it gets no device memory
// until a write makes the texture cache replace it.
-[[nodiscard]] bool IsUnwrittenSparse(const ImageInfo& info, GPUVAddr gpu_addr) {
+[[nodiscard]] bool IsUnwrittenSparse(const Device& device, const ImageInfo& info, GPUVAddr gpu_addr) {
+ if (!device.CanUseUnbackedSparseImages()) {
+ return false;
+ }
constexpr u32 MinSize = 32U << 20;
const u32 size = VideoCommon::CalculateGuestSizeInBytes(info);
return size >= MinSize && info.type != ImageType::e1D && info.type != ImageType::Buffer &&
@@ -184,7 +187,8 @@ constexpr VkBorderColor ConvertBorderColor(const std::array<float, 4>& color) {
// Image::BindLayers. Only formats uploaded layer by layer: huge ASTC arrays (GPU decode) and
// formats the host samples as they are.
[[nodiscard]] bool UsesSparseLayers(const Device& device, const ImageInfo& info, GPUVAddr gpu_addr) {
- if (!device.IsSparseResidencyImage2DSupported() || info.type != ImageType::e2D ||
+ if (!device.CanUseUnbackedSparseImages() || !device.IsSparseResidencyImage2DSupported() ||
+ info.type != ImageType::e2D ||
info.resources.layers <= 1 || info.num_samples != 1 ||
VideoCore::Surface::GetFormatType(info.format) != VideoCore::Surface::SurfaceType::ColorTexture) {
return false;
@@ -2089,7 +2093,7 @@ Image::Image(TextureCacheRuntime& runtime_, const ImageInfo& info_, GPUVAddr gpu
: runtime->ViewFormats(info.format),
AstcHostFormat(runtime_.device, info),
UsesSparseLayers(runtime_.device, info, gpu_addr_) ||
- IsUnwrittenSparse(info, gpu_addr_))),
+ IsUnwrittenSparse(runtime_.device, info, gpu_addr_))),
aspect_mask(ImageAspectMask(info.format)) {
if (original_image.IsUnbacked()) {
flags |= VideoCommon::ImageFlagBits::Unbacked;
diff --git a/src/video_core/vulkan_common/vulkan_device.h b/src/video_core/vulkan_common/vulkan_device.h
index d8524f6575..abd31ad904 100644
--- a/src/video_core/vulkan_common/vulkan_device.h
+++ b/src/video_core/vulkan_common/vulkan_device.h
@@ -326,6 +326,14 @@ public:
return IsSparseBindingSupported() && features.features.sparseResidencyImage2D;
}
+ /// Whether images with no memory bound may be sampled and used as attachments. AMD's drivers
+ /// fault on it (the GPU hangs shortly after the first such draw), so large images there are
+ /// backed normally.
+ bool CanUseUnbackedSparseImages() const {
+ const VkDriverIdKHR id = GetDriverID();
+ return id != VK_DRIVER_ID_AMD_PROPRIETARY && id != VK_DRIVER_ID_AMD_OPEN_SOURCE;
+ }
+
/// Returns true for tile-based deferred renderers.
bool IsTiler() const {
switch (GetDriverID()) {