From e6d53fc1d866386b5af71772b110fe2e6dabfbdb Mon Sep 17 00:00:00 2001 From: Lars-Ivar Hesselberg Simonsen Date: Mon, 2 Jun 2025 16:57:52 +0200 Subject: [PATCH] panvk: Add FS read support for PrimitiveID Adds support for reading PrimitiveID in a fragment shader assuming the previous shader was vertex. If support for shaders that can modify PrimitiveID is added, additional changes will be required. Reviewed-by: Boris Brezillon Part-of: --- src/panfrost/compiler/bifrost_compile.c | 4 +++ src/panfrost/lib/pan_shader.c | 3 +++ src/panfrost/util/pan_ir.h | 1 + src/panfrost/vulkan/csf/panvk_vX_cmd_draw.c | 2 ++ src/panfrost/vulkan/jm/panvk_vX_cmd_draw.c | 29 +++++++++++++++++++++ src/panfrost/vulkan/panvk_vX_shader.c | 23 ++++++++++++++++ 6 files changed, 62 insertions(+) diff --git a/src/panfrost/compiler/bifrost_compile.c b/src/panfrost/compiler/bifrost_compile.c index 7971ee40542..bfb69ed8cbc 100644 --- a/src/panfrost/compiler/bifrost_compile.c +++ b/src/panfrost/compiler/bifrost_compile.c @@ -2231,6 +2231,10 @@ bi_emit_intrinsic(bi_builder *b, nir_intrinsic_instr *instr) bi_load_sample_id_to(b, dst); break; + case nir_intrinsic_load_primitive_id: + bi_mov_i32_to(b, dst, bi_preload(b, 57)); + break; + case nir_intrinsic_load_front_face: { /* (r58 & 1) == 0 means primitive is front facing */ bi_index primitive_facing = bi_preload(b, 58); diff --git a/src/panfrost/lib/pan_shader.c b/src/panfrost/lib/pan_shader.c index ff7ce28b8fe..c179df6dc57 100644 --- a/src/panfrost/lib/pan_shader.c +++ b/src/panfrost/lib/pan_shader.c @@ -143,6 +143,9 @@ pan_shader_compile(nir_shader *s, struct pan_compile_inputs *inputs, info->fs.reads_frag_coord = (s->info.inputs_read & (1 << VARYING_SLOT_POS)) || BITSET_TEST(s->info.system_values_read, SYSTEM_VALUE_FRAG_COORD); + info->fs.reads_primitive_id = + (s->info.inputs_read & (1 << VARYING_SLOT_PRIMITIVE_ID)) || + BITSET_TEST(s->info.system_values_read, SYSTEM_VALUE_PRIMITIVE_ID); info->fs.reads_point_coord = s->info.inputs_read & (1 << VARYING_SLOT_PNTC); info->fs.reads_face = diff --git a/src/panfrost/util/pan_ir.h b/src/panfrost/util/pan_ir.h index 3214fb89595..c44fadb620d 100644 --- a/src/panfrost/util/pan_ir.h +++ b/src/panfrost/util/pan_ir.h @@ -206,6 +206,7 @@ struct pan_shader_info { struct { bool reads_frag_coord; bool reads_point_coord; + bool reads_primitive_id; bool reads_face; bool can_discard; bool writes_depth; diff --git a/src/panfrost/vulkan/csf/panvk_vX_cmd_draw.c b/src/panfrost/vulkan/csf/panvk_vX_cmd_draw.c index d0db8ab76df..bbc4930c827 100644 --- a/src/panfrost/vulkan/csf/panvk_vX_cmd_draw.c +++ b/src/panfrost/vulkan/csf/panvk_vX_cmd_draw.c @@ -2085,6 +2085,8 @@ set_tiler_idvs_flags(struct cs_builder *b, struct panvk_cmd_buffer *cmdbuf, if (dirty) { pan_pack(&tiler_idvs_flags, PRIMITIVE_FLAGS, cfg) { cfg.draw_mode = translate_prim_topology(ia->primitive_topology); + cfg.primitive_index_enable = + fs ? fs->info.fs.reads_primitive_id : false; #if PAN_ARCH < 13 cfg.point_size_array_format = writes_point_size diff --git a/src/panfrost/vulkan/jm/panvk_vX_cmd_draw.c b/src/panfrost/vulkan/jm/panvk_vX_cmd_draw.c index 1e6cac28249..cd500288218 100644 --- a/src/panfrost/vulkan/jm/panvk_vX_cmd_draw.c +++ b/src/panfrost/vulkan/jm/panvk_vX_cmd_draw.c @@ -835,11 +835,14 @@ panvk_emit_tiler_primitive(struct panvk_cmd_buffer *cmdbuf, vs->info.vs.writes_point_size && ia->primitive_topology == VK_PRIMITIVE_TOPOLOGY_POINT_LIST; bool secondary_shader = vs->info.vs.secondary_enable && fs != NULL; + bool fs_reads_primitive_id = fs ? fs->info.fs.reads_primitive_id : false; pan_pack(prim, PRIMITIVE, cfg) { cfg.draw_mode = translate_prim_topology(ia->primitive_topology); if (writes_point_size) cfg.point_size_array_format = MALI_POINT_SIZE_ARRAY_FORMAT_FP16; + cfg.primitive_index_enable = fs_reads_primitive_id; + cfg.primitive_index_writeback = fs_reads_primitive_id; cfg.first_provoking_vertex = cmdbuf->state.gfx.render.first_provoking_vertex != U_TRISTATE_NO; @@ -900,6 +903,24 @@ panvk_emit_tiler_primitive_size(struct panvk_cmd_buffer *cmdbuf, } } +static uint32_t +primitive_vertex_count(enum mali_draw_mode in) +{ + switch (in) { + case MALI_DRAW_MODE_POINTS: + return 1; + case MALI_DRAW_MODE_LINES: + case MALI_DRAW_MODE_LINE_STRIP: + return 2; + case MALI_DRAW_MODE_TRIANGLES: + case MALI_DRAW_MODE_TRIANGLE_STRIP: + case MALI_DRAW_MODE_TRIANGLE_FAN: + return 3; + default: + unreachable("Invalid draw mode"); + } +} + static void panvk_emit_tiler_dcd(struct panvk_cmd_buffer *cmdbuf, const struct panvk_draw_data *draw, @@ -936,6 +957,14 @@ panvk_emit_tiler_dcd(struct panvk_cmd_buffer *cmdbuf, cfg.offset_start = draw->info.vertex.raw_offset; cfg.instance_size = draw->info.instance.count > 1 ? draw->padded_vertex_count : 1; + uint32_t primitives_per_instance = + DIV_ROUND_UP(draw->padded_vertex_count, + primitive_vertex_count( + translate_prim_topology(ia->primitive_topology))); + /* instance_primitive_size has the same restrictions as + * padded_vertex_count, so we can use pan_padded_vertex_count here. */ + cfg.instance_primitive_size = + pan_padded_vertex_count(primitives_per_instance); cfg.uniform_buffers = fs_desc_state->tables[PANVK_BIFROST_DESC_TABLE_UBO]; cfg.push_uniforms = cmdbuf->state.gfx.fs.push_uniforms; cfg.textures = fs_desc_state->tables[PANVK_BIFROST_DESC_TABLE_TEXTURE]; diff --git a/src/panfrost/vulkan/panvk_vX_shader.c b/src/panfrost/vulkan/panvk_vX_shader.c index 845b4c6296b..ea9bff5031b 100644 --- a/src/panfrost/vulkan/panvk_vX_shader.c +++ b/src/panfrost/vulkan/panvk_vX_shader.c @@ -224,6 +224,26 @@ panvk_lower_load_vs_input(nir_builder *b, nir_intrinsic_instr *intrin, return true; } +static bool +panvk_lower_load_fs_input(nir_builder *b, nir_intrinsic_instr *intrin, + UNUSED void *data) +{ + if (intrin->intrinsic != nir_intrinsic_load_input) + return false; + + /* Lower PrimitiveID varying loads to the equivalent intrinsic. This only + * works since v6 and will require additional changes if PrimitiveID is + * explicitly written to (for example by a geometry shader). */ + if (nir_intrinsic_io_semantics(intrin).location == + VARYING_SLOT_PRIMITIVE_ID) { + b->cursor = nir_before_instr(&intrin->instr); + nir_def_replace(&intrin->def, nir_load_primitive_id(b)); + return true; + } + + return false; +} + #if PAN_ARCH <= 7 static bool lower_gl_pos_layer_writes(nir_builder *b, nir_instr *instr, void *data) @@ -867,6 +887,9 @@ panvk_lower_nir(struct panvk_device *dev, nir_shader *nir, if (stage == MESA_SHADER_VERTEX) NIR_PASS(_, nir, nir_shader_intrinsics_pass, panvk_lower_load_vs_input, nir_metadata_control_flow, NULL); + else if (stage == MESA_SHADER_FRAGMENT) + NIR_PASS(_, nir, nir_shader_intrinsics_pass, panvk_lower_load_fs_input, + nir_metadata_control_flow, NULL); /* since valhall, panvk_per_arch(nir_lower_descriptors) separates the * driver set and the user sets, and does not need pan_lower_image_index