From 6f73533094188d7b5ebb8a7149f902969ba4d673 Mon Sep 17 00:00:00 2001 From: Mary Guillemard Date: Wed, 8 Oct 2025 12:22:46 +0200 Subject: [PATCH] asahi,nir: Stop relying on zero and scratch page in GS/TESS code Introduce new NIR intrinsics to handle getting a "sink" read-only address and another intrinsic to handle conversion of address to read-write (allowing implementation to replace the "sink" read-only with another address like required for Asahi) Signed-off-by: Mary Guillemard Reviewed-by: Alyssa Rosenzweig Part-of: --- src/asahi/compiler/agx_compile.c | 27 +++++++++++++++++++++++++++ src/asahi/libagx/geometry.cl | 7 +++---- src/asahi/libagx/geometry.h | 22 ++++++++++++---------- src/asahi/vulkan/hk_cmd_draw.c | 14 ++++++++++++-- src/compiler/nir/nir_intrinsics.py | 7 +++++++ 5 files changed, 61 insertions(+), 16 deletions(-) diff --git a/src/asahi/compiler/agx_compile.c b/src/asahi/compiler/agx_compile.c index 3e039d2c73f..6868ff7508e 100644 --- a/src/asahi/compiler/agx_compile.c +++ b/src/asahi/compiler/agx_compile.c @@ -3301,6 +3301,30 @@ lower_load_from_texture_handle(nir_builder *b, nir_intrinsic_instr *intr, return true; } +static bool +lower_sink_address(nir_builder *b, nir_intrinsic_instr *intr, UNUSED void *data) +{ + switch (intr->intrinsic) { + case nir_intrinsic_load_ro_sink_address_poly: + b->cursor = nir_before_instr(&intr->instr); + nir_def_replace(&intr->def, nir_imm_int64(b, AGX_ZERO_PAGE_ADDRESS)); + return true; + case nir_intrinsic_ro_to_rw_poly: { + b->cursor = nir_before_instr(&intr->instr); + nir_def_replace( + &intr->def, + nir_bcsel(b, nir_ieq_imm(b, intr->src[0].ssa, AGX_ZERO_PAGE_ADDRESS), + nir_imm_int64(b, AGX_SCRATCH_PAGE_ADDRESS), + intr->src[0].ssa)); + return true; + } + default: + break; + } + + return false; +} + static void agx_remove_unreachable_block(agx_block *block) { @@ -3823,6 +3847,9 @@ agx_compile_shader_nir(nir_shader *nir, struct agx_shader_key *key, NIR_PASS(_, nir, nir_shader_intrinsics_pass, lower_load_from_texture_handle, nir_metadata_control_flow, NULL); + NIR_PASS(_, nir, nir_shader_intrinsics_pass, lower_sink_address, + nir_metadata_control_flow, NULL); + info->push_count = key->reserved_preamble; agx_optimize_nir( nir, key->dev.soft_fault, key->secondary ? NULL : &info->push_count, diff --git a/src/asahi/libagx/geometry.cl b/src/asahi/libagx/geometry.cl index 795d255140b..bc72b487f5c 100644 --- a/src/asahi/libagx/geometry.cl +++ b/src/asahi/libagx/geometry.cl @@ -9,10 +9,11 @@ #include "util/macros.h" #include "util/u_math.h" #include "geometry.h" -#include "libagx_intrinsics.h" #include "query.h" #include "tessellator.h" +uint64_t nir_ro_to_rw_poly(uint64_t address); + /* Swap the two non-provoking vertices in odd triangles. This generates a vertex * ID list with a consistent winding order. * @@ -941,10 +942,8 @@ libagx_pre_gs(global struct agx_geometry_params *p, uint streams, unsigned stream = buffer_to_stream[i]; global uint *ptr = p->xfb_offs_ptrs[i]; - if ((uintptr_t)ptr == AGX_ZERO_PAGE_ADDRESS) { - ptr = (global uint *)AGX_SCRATCH_PAGE_ADDRESS; - } + ptr = (global uint *)nir_ro_to_rw_poly((uint64_t)ptr); *ptr += prims[stream] * prim_stride_B; } } diff --git a/src/asahi/libagx/geometry.h b/src/asahi/libagx/geometry.h index 547e2367e9f..870f6489ca4 100644 --- a/src/asahi/libagx/geometry.h +++ b/src/asahi/libagx/geometry.h @@ -154,6 +154,18 @@ agx_heap_alloc_nonatomic(global struct agx_heap *heap, uint size_B) { return heap->base + agx_heap_alloc_nonatomic_offs(heap, size_B); } + +uint64_t nir_load_ro_sink_address_poly(void); + +static inline uint64_t +libagx_index_buffer(uint64_t index_buffer, uint size_el, uint offset_el, + uint elsize_B) +{ + if (offset_el < size_el) + return index_buffer + (offset_el * elsize_B); + else + return nir_load_ro_sink_address_poly(); +} #endif struct agx_ia_state { @@ -170,16 +182,6 @@ struct agx_ia_state { } PACKED; static_assert(sizeof(struct agx_ia_state) == 4 * 4); -static inline uint64_t -libagx_index_buffer(uint64_t index_buffer, uint size_el, uint offset_el, - uint elsize_B) -{ - if (offset_el < size_el) - return index_buffer + (offset_el * elsize_B); - else - return AGX_ZERO_PAGE_ADDRESS; -} - static inline uint libagx_index_buffer_range_el(uint size_el, uint offset_el) { diff --git a/src/asahi/vulkan/hk_cmd_draw.c b/src/asahi/vulkan/hk_cmd_draw.c index 34f5bec771a..2c07b0fa168 100644 --- a/src/asahi/vulkan/hk_cmd_draw.c +++ b/src/asahi/vulkan/hk_cmd_draw.c @@ -1030,6 +1030,16 @@ hk_heap(struct hk_cmd_buffer *cmd) return dev->rodata.heap; } +static uint64_t +hk_index_buffer(uint64_t index_buffer, uint size_el, uint offset_el, + uint elsize_B) +{ + if (offset_el < size_el) + return index_buffer + (offset_el * elsize_B); + else + return AGX_ZERO_PAGE_ADDRESS; +} + static uint64_t hk_upload_ia_params(struct hk_cmd_buffer *cmd, struct agx_draw draw) { @@ -1041,8 +1051,8 @@ hk_upload_ia_params(struct hk_cmd_buffer *cmd, struct agx_draw draw) unsigned index_size_B = agx_index_size_to_B(draw.index_size); unsigned range_el = agx_draw_index_range_el(draw); - ia.index_buffer = libagx_index_buffer(agx_draw_index_buffer(draw), - range_el, 0, index_size_B); + ia.index_buffer = hk_index_buffer(agx_draw_index_buffer(draw), range_el, + 0, index_size_B); ia.index_buffer_range_el = range_el; } diff --git a/src/compiler/nir/nir_intrinsics.py b/src/compiler/nir/nir_intrinsics.py index 47fc1f02906..668bb2007ea 100644 --- a/src/compiler/nir/nir_intrinsics.py +++ b/src/compiler/nir/nir_intrinsics.py @@ -1407,6 +1407,13 @@ intrinsic("select_vertex_poly", src_comp=[1], indices=[STREAM_ID]) # Sources: (index offset, first vertex, number of vertices, # of XFB primitives before). intrinsic("emit_primitive_poly", src_comp=[1, 1, 1, 1], indices=[STREAM_ID]) +# Transform a given address to be used as read-write, +# allowing to transition a "sink" read-only address to the read-write address. +intrinsic("ro_to_rw_poly", src_comp=[1], dest_comp=1, flags=[CAN_ELIMINATE, CAN_REORDER], bit_sizes=[64]) + +# Get the address representing the read-only "sink" address (always read 0) +system_value("ro_sink_address_poly", 1, bit_sizes=[64]) + # mesa_prim for the input topology (in a geometry shader) system_value("input_topology_poly", 1)