aboutsummaryrefslogtreecommitdiff
path: root/src/video_core
diff options
context:
space:
mode:
authorkraibse <33869366+kraibse@users.noreply.github.com>2026-11-01 03:20:42 +0100
committerkraibse <33869366+kraibse@users.noreply.github.com>2026-11-02 00:11:25 +0100
commit803ece5f90bbdc5ef9751f559cbe8b2ecbdb2aac (patch)
tree80a1c821dad9d5bdb564d587f4d8c217c5a1e0e3 /src/video_core
parent8eaea9d3769fecff3dd7202884f66423ed2c83b1 (diff)
vulkan: don't divide by a zero sparse block size (AMD)
Image::InitSparseLayers divided by the imageGranularity the driver returns, which AMD's driver reports as 0 and crashed. Use Vulkan's standard 2D block shape when the device reports residencyStandard2DBlockShape, otherwise don't use sparse layers. Ported from Wael3rd/Eglantine-MKW (7a77946af3). Assisted-by: Claude Sonnet 5.5 (porting the fix) (cherry picked from commit eadb9fc0f06f32ff1684fe202519c0505669095d)
Diffstat (limited to 'src/video_core')
-rw-r--r--src/video_core/renderer_vulkan/vk_texture_cache.cpp48
1 files changed, 47 insertions, 1 deletions
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
index a95b4636f7..09e7961ff9 100644
--- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
@@ -244,6 +244,35 @@ enum class SparseTilesMode {
return size >= (32U << 20) && Tegra::Nx2InSparseRegion(gpu_addr, size);
}
+// Vulkan's standard sparse block shape for single-sampled 2D images (64 KiB blocks), in texel
+// blocks, for a texel block of `block_bytes`. Only valid when the device reports
+// residencyStandard2DBlockShape.
+[[nodiscard]] bool StandardSparseBlockShape(const Device& device, u64 block_bytes,
+ VkExtent3D& shape) {
+ if (!device.GetPhysical().GetProperties().sparseProperties.residencyStandard2DBlockShape) {
+ return false;
+ }
+ switch (block_bytes) {
+ case 1:
+ shape = {256, 256, 1};
+ return true;
+ case 2:
+ shape = {256, 128, 1};
+ return true;
+ case 4:
+ shape = {128, 128, 1};
+ return true;
+ case 8:
+ shape = {128, 64, 1};
+ return true;
+ case 16:
+ shape = {64, 64, 1};
+ return true;
+ default:
+ return false;
+ }
+}
+
// The most device memory one SparseLayers image binds: 768 MiB, 384 MiB on GPUs with less than
// 7 GiB (title 1's BC6H arrays are 85 MB a layer).
[[nodiscard]] VkDeviceSize SparseLayersCap(const Device& device) {
@@ -2696,7 +2725,24 @@ bool Image::InitSparseLayers() {
const u32 block_width = huge_astc ? 1 : VideoCore::Surface::DefaultBlockWidth(info.format);
const u32 block_height = huge_astc ? 1 : VideoCore::Surface::DefaultBlockHeight(info.format);
const u64 block_bytes = huge_astc ? 4 : VideoCore::Surface::BytesPerBlock(info.format);
- const VkExtent3D granularity = it->formatProperties.imageGranularity;
+ VkExtent3D granularity = it->formatProperties.imageGranularity;
+ if (granularity.width == 0 || granularity.height == 0) {
+ // Seen with AMD's driver: the sparse block size comes back as 0, and the size computation
+ // below divided by it. Use the standard 2D block shape when the device promises it.
+ if (!StandardSparseBlockShape(device, block_bytes, granularity)) {
+ LOG_WARNING(Render_Vulkan,
+ "Sparse layered image {:#x}: the driver reports no sparse block size and "
+ "no standard block shape; not using sparse layers",
+ gpu_addr);
+ return false;
+ }
+ granularity.width *= block_width;
+ granularity.height *= block_height;
+ LOG_INFO(Render_Vulkan,
+ "Sparse layered image {:#x}: no block size from the driver, using the standard "
+ "{}x{} texel block",
+ gpu_addr, granularity.width, granularity.height);
+ }
s.tile_width = granularity.width;
s.tile_height = granularity.height;
const u64 tile = s.requirements.alignment;