From 6793c8d25b43432cc16f527895bc4e68bfa78ca5 Mon Sep 17 00:00:00 2001 From: Nikolay Nadorichev Date: Thu, 29 Oct 2026 21:58:12 +0300 Subject: [PATCH] Keep descriptor sets aligned after vkResetDescriptorPool The pool sub-allocator heap was initialized with an end address where a size was expected, making it TU_POOL_HEAP_OFFSET bytes larger than the BO, and vkResetDescriptorPool re-initialized it without restoring alloc_high = false. After a reset, sets were handed out from the top: offsets were 32 mod 64 and the topmost set ran 32 bytes past the BO. Turnip masks the low 6 bits of set_iova, so descriptors and inline uniforms of such sets were read 32 bytes off. Seen as invisible Scaleform UI in Detroit: Become Human on Adreno 840. --- README.md | 1 + ...07-tu-descriptor-pool-heap-alignment.patch | 61 +++++++++++++++++++ patches/series.json | 7 +++ 3 files changed, 69 insertions(+) create mode 100644 patches/linux/0007-tu-descriptor-pool-heap-alignment.patch diff --git a/README.md b/README.md index d609dfa..f9f0731 100644 --- a/README.md +++ b/README.md @@ -72,6 +72,7 @@ build and the release notes. | `scripts/process_heap_usage.py` | ✓ | ✓ | | `linux/0001` … `linux/0005` (mesh shaders, half-wave subgroups, A8XX cube, bindless and IB fixes) | | ✓ | | `lrz/0001` (A8XX LRZ flush before the next render pass) | ✓ | ✓ | +| `linux/0007` (descriptor sets stay aligned after a pool reset) | | ✓ | A script whose anchor no longer matches Mesa main exits non-zero and a `.patch` that no longer applies fails `git apply`, so upstream drift fails the build instead of shipping a driver without the fix. The `Check` diff --git a/patches/linux/0007-tu-descriptor-pool-heap-alignment.patch b/patches/linux/0007-tu-descriptor-pool-heap-alignment.patch new file mode 100644 index 0000000..cdf9fc5 --- /dev/null +++ b/patches/linux/0007-tu-descriptor-pool-heap-alignment.patch @@ -0,0 +1,61 @@ +diff --git a/src/freedreno/vulkan/tu_descriptor_set.cc b/src/freedreno/vulkan/tu_descriptor_set.cc +index 18b9299..34bf3ee 100644 +--- a/src/freedreno/vulkan/tu_descriptor_set.cc ++++ b/src/freedreno/vulkan/tu_descriptor_set.cc +@@ -670,7 +670,8 @@ tu_descriptor_set_create(struct tu_device *device, + + if (!pool->host_memory_base) { + uint64_t pool_vma_offset = +- util_vma_heap_alloc(&pool->bo_heap, set->size, 1); ++ util_vma_heap_alloc(&pool->bo_heap, set->size, ++ TU_DESCRIPTOR_SET_ALIGNMENT); + if (!pool_vma_offset) { + vk_object_free(&device->vk, NULL, set); + if (pool->bo_heap.free_size >= set->size) +@@ -821,8 +822,7 @@ tu_CreateDescriptorPool(VkDevice _device, + pool->host_memory_end = reinterpret_cast(pool) + size; + } else { + if (bo_size) { +- util_vma_heap_init(&pool->bo_heap, TU_POOL_HEAP_OFFSET, +- bo_size + TU_POOL_HEAP_OFFSET); ++ util_vma_heap_init(&pool->bo_heap, TU_POOL_HEAP_OFFSET, bo_size); + pool->bo_heap.alloc_high = false; + } + } +@@ -918,8 +918,8 @@ tu_ResetDescriptorPool(VkDevice _device, + + if (!pool->host_memory_base && pool->size) { + util_vma_heap_finish(&pool->bo_heap); +- util_vma_heap_init(&pool->bo_heap, TU_POOL_HEAP_OFFSET, +- pool->size + TU_POOL_HEAP_OFFSET); ++ util_vma_heap_init(&pool->bo_heap, TU_POOL_HEAP_OFFSET, pool->size); ++ pool->bo_heap.alloc_high = false; + } + + pool->entry_count = 0; +diff --git a/src/freedreno/vulkan/tu_descriptor_set.h b/src/freedreno/vulkan/tu_descriptor_set.h +index 74b36ec..b763d10 100644 +--- a/src/freedreno/vulkan/tu_descriptor_set.h ++++ b/src/freedreno/vulkan/tu_descriptor_set.h +@@ -28,11 +28,18 @@ + */ + #define MAX_SET_SIZE ((1 << 28) * 4) + ++/* Descriptor sets have to start on a 64-byte boundary: the low 6 bits of ++ * set_iova hold the bindless descriptor size and are masked off when the ++ * address is used. ++ */ ++#define TU_DESCRIPTOR_SET_ALIGNMENT (4 * FDL6_TEX_CONST_DWORDS) ++ + /* The vma heap reserves 0 to mean NULL; we have to offset by some amount to +- * ensure we can allocate the entire BO without hitting zero. The actual +- * amount doesn't matter. ++ * ensure we can allocate the entire BO without hitting zero. The heap aligns ++ * heap addresses, not BO offsets, so the offset has to be a multiple of ++ * TU_DESCRIPTOR_SET_ALIGNMENT. + */ +-#define TU_POOL_HEAP_OFFSET 32 ++#define TU_POOL_HEAP_OFFSET 64 + + struct tu_descriptor_set_binding_layout + { diff --git a/patches/series.json b/patches/series.json index 4047232..777735d 100644 --- a/patches/series.json +++ b/patches/series.json @@ -156,5 +156,12 @@ "linux" ], "summary": "Reset the LRZ controls after the end-of-pass LRZ flush on A8XX, as freedreno does, so a large fast-cleared LRZ buffer no longer hangs the GPU" + }, + { + "file": "linux/0007-tu-descriptor-pool-heap-alignment.patch", + "targets": [ + "linux" + ], + "summary": "Keep descriptor sets 64-byte aligned and inside the pool BO after vkResetDescriptorPool" } ]