diff --git a/src/asahi/lib/agx_device.c b/src/asahi/lib/agx_device.c index 08f9d6fde9d..fa5fd91b6ce 100644 --- a/src/asahi/lib/agx_device.c +++ b/src/asahi/lib/agx_device.c @@ -9,6 +9,7 @@ #include #include "clc/asahi_clc.h" #include "drm-uapi/asahi_drm.h" +#include "util/bitscan.h" #include "util/macros.h" #include "util/ralloc.h" #include "util/timespec.h" @@ -33,6 +34,7 @@ #include "util/os_mman.h" #include "util/os_time.h" #include "util/simple_mtx.h" +#include "util/u_math.h" #include "util/u_printf.h" #include "git_sha1.h" #include "nir_serialize.h" @@ -614,6 +616,23 @@ agx_open_device(void *memctx, struct agx_device *dev) return false; } + /* Round the user VA window to powers-of-two... */ + user_start = util_next_power_of_two64(user_start); + user_size = util_next_power_of_two64(user_size + 1) >> 1; + + /* ...so when we cut user size in half to emulate sparse buffers... */ + user_size /= 2; + + /* ...or maybe in quarters if necessary to disambiguate */ + if (user_size == user_start) { + user_size /= 2; + } + + /* ...we can distinguish the top/bottom half by an address bit */ + dev->sparse_ro_offset = user_size; + assert((user_start & dev->sparse_ro_offset) == 0); + assert(((user_start + (user_size - 1)) & dev->sparse_ro_offset) == 0); + simple_mtx_init(&dev->vma_lock, mtx_plain); util_vma_heap_init(&dev->main_heap, user_start, user_size); util_vma_heap_init(&dev->usc_heap, dev->shader_base, shader_size); diff --git a/src/asahi/lib/agx_device.h b/src/asahi/lib/agx_device.h index 266cf17d3e9..0ab6ed6a4de 100644 --- a/src/asahi/lib/agx_device.h +++ b/src/asahi/lib/agx_device.h @@ -120,6 +120,19 @@ struct agx_device { struct util_vma_heap usc_heap; uint64_t guard_size; + /* To emulate sparse-resident buffers, we map buffers in both the bottom half + * and top half of the address space. sparse_ro_offset controls the + * partitioning. This is a power-of-two that &'s zero in bottom (read-write) + * buffers but non-zero in top (read-only) shadow mappings. + * + * In other words, given an address X, we can check if it is in the top half + * if (X & sparse_ro_offset) != 0. + * + * Given a bottom half address X, we can get the top half address + * equivalently as (X + sparse_ro_offset) or (X | sparse_ro_offset). + */ + uint64_t sparse_ro_offset; + struct renderonly *ro; pthread_mutex_t bo_map_lock;