From 4d49efc831015d6fdd9650a73ddb14b64f1577b2 Mon Sep 17 00:00:00 2001 From: Kenneth Graunke Date: Mon, 16 Mar 2026 15:13:32 -0700 Subject: [PATCH] jay: Add tessellation evaluation shader support Part-of: --- src/intel/compiler/jay/jay_from_nir.c | 68 +++++++++++++++++++++++++- src/intel/compiler/jay/jay_nir.c | 41 ++++++++++++++++ src/intel/compiler/jay/jay_partition.c | 4 ++ src/intel/dev/intel_debug.c | 7 +-- 4 files changed, 116 insertions(+), 4 deletions(-) diff --git a/src/intel/compiler/jay/jay_from_nir.c b/src/intel/compiler/jay/jay_from_nir.c index c4bdf34c1a4..936d10b8a30 100644 --- a/src/intel/compiler/jay/jay_from_nir.c +++ b/src/intel/compiler/jay/jay_from_nir.c @@ -54,6 +54,11 @@ typedef struct jay_vs_payload { jay_def attributes[30 * 4]; } jay_vs_payload; +typedef struct jay_tes_payload { + jay_def tess_coord; + jay_def patch_inputs[32 * 4]; +} jay_tes_payload; + typedef struct jay_cs_payload { jay_def local_invocation_ids; } jay_cs_payload; @@ -102,6 +107,7 @@ struct nir_to_jay_state { union { jay_vs_payload vs; + jay_tes_payload tes; jay_cs_payload cs; jay_fs_payload fs; }; @@ -1235,6 +1241,8 @@ jay_emit_intrinsic(struct nir_to_jay_state *nj, nir_intrinsic_instr *intr) mesa_shader_stage_is_compute(s->stage) ? &nj->payload.cs : NULL; jay_fs_payload *fs = s->stage == MESA_SHADER_FRAGMENT ? &nj->payload.fs : NULL; + jay_tes_payload *tes = + s->stage == MESA_SHADER_TESS_EVAL ? &nj->payload.tes : NULL; const bool has_dest = nir_intrinsic_infos[intr->intrinsic].has_dest; jay_def dst = has_dest ? nj_def(&intr->def) : jay_null(); @@ -1319,6 +1327,13 @@ jay_emit_intrinsic(struct nir_to_jay_state *nj, nir_intrinsic_instr *intr) nj->payload.push_data[s->prog_data->fs.fs_config_param / 4]); break; + case nir_intrinsic_load_tess_config_intel: { + const unsigned offs = tes ? s->prog_data->tes.tess_config_param : + s->prog_data->tcs.tess_config_param; + jay_MOV(b, dst, nj->payload.push_data[offs / 4]); + break; + } + case nir_intrinsic_barrier: { jay_SCHEDULE_BARRIER(b); @@ -1505,6 +1520,22 @@ jay_emit_intrinsic(struct nir_to_jay_state *nj, nir_intrinsic_instr *intr) } break; + case nir_intrinsic_load_tess_coord: + assert(tes); + jay_copy(b, dst, tes->tess_coord); + break; + + case nir_intrinsic_load_primitive_id: + assert(tes); + assert(nj->s->prog_data->tes.include_primitive_id); + jay_copy(b, dst, jay_extract(nj->payload.u0, 1)); + break; + + case nir_intrinsic_load_urb_input_handle_intel: + assert(tes); + jay_MOV(b, dst, jay_extract(nj->payload.u0, 0)); + break; + case nir_intrinsic_load_urb_output_handle_intel: jay_MOV(b, dst, nj->payload.urb_handle); break; @@ -1559,6 +1590,20 @@ jay_emit_intrinsic(struct nir_to_jay_state *nj, nir_intrinsic_instr *intr) break; } + case nir_intrinsic_load_attribute_payload_intel: + assert(intr->def.bit_size == 32); + + if (s->stage == MESA_SHADER_TESS_EVAL) { + assert(nir_src_is_const(intr->src[0])); + unsigned offs = nir_src_as_uint(intr->src[0]) / 4; + jay_copy(b, dst, + jay_collect_vectors(b, nj->payload.tes.patch_inputs + offs, + intr->def.num_components)); + } else { + UNREACHABLE("TODO: attribute payload data"); + } + break; + case nir_intrinsic_load_input: if (s->stage == MESA_SHADER_VERTEX) { unsigned offs = nir_intrinsic_base(intr) * 4; @@ -2517,7 +2562,8 @@ jay_emit_eot(struct nir_to_jay_state *nj) jay_SEND(b, .sfid = GEN_SFID_MESSAGE_GATEWAY, .eot = true, .msg_desc = 0, .srcs = ©, .nr_srcs = 1, .type = JAY_TYPE_U32, .uniform = true); - } else if (nj->nir->info.stage == MESA_SHADER_VERTEX) { + } else if (nj->nir->info.stage == MESA_SHADER_VERTEX || + nj->nir->info.stage == MESA_SHADER_TESS_EVAL) { jay_block *block = jay_last_block(nj->f); jay_inst *I = jay_last_inst(block); @@ -2609,6 +2655,23 @@ setup_vertex_payload(struct nir_to_jay_state *nj, struct payload_builder *p) } } +static void +setup_tess_eval_payload(struct nir_to_jay_state *nj, struct payload_builder *p) +{ + nj->payload.tes.tess_coord = read_vector_payload(p, GPR, 3); + nj->payload.urb_handle = read_payload(p, GPR); + + setup_payload_dispatch_start(nj, p); + setup_payload_push(nj, p); + + unsigned input_ugprs = 8 * nj->s->prog_data->vue.urb_read_length; + + for (unsigned i = 0; i < input_ugprs; ++i) { + assert(i < ARRAY_SIZE(nj->payload.tes.patch_inputs)); + nj->payload.tes.patch_inputs[i] = read_payload(p, UGPR); + } +} + static void setup_compute_payload(struct nir_to_jay_state *nj, struct payload_builder *p) { @@ -2818,6 +2881,9 @@ jay_setup_payload(struct nir_to_jay_state *nj) case MESA_SHADER_VERTEX: setup_vertex_payload(nj, &p); break; + case MESA_SHADER_TESS_EVAL: + setup_tess_eval_payload(nj, &p); + break; case MESA_SHADER_FRAGMENT: setup_fragment_payload(nj, &p); break; diff --git a/src/intel/compiler/jay/jay_nir.c b/src/intel/compiler/jay/jay_nir.c index 706e3cbebc6..99b63efd909 100644 --- a/src/intel/compiler/jay/jay_nir.c +++ b/src/intel/compiler/jay/jay_nir.c @@ -412,6 +412,47 @@ jay_process_nir(const struct intel_device_info *devinfo, JAY_NIR_PASS(nir_opt_constant_folding); JAY_NIR_PASS(brw_nir_lower_deferred_urb_writes, devinfo, &prog_data->vue.vue_map, 0, 0); + } else if (stage == MESA_SHADER_TESS_EVAL) { + const uint32_t pos_slots = + (nir->info.per_view_outputs & VARYING_BIT_POS) ? + MAX2(1, util_bitcount(key->base.view_mask)) : + 1; + + brw_compute_vue_map(devinfo, &prog_data->vue.vue_map, + nir->info.outputs_written, key->base.vue_layout, + pos_slots); + + struct intel_vue_map input_vue_map; + + brw_compute_tess_vue_map(&input_vue_map, nir->info.inputs_read, + nir->info.patch_inputs_read, + key->tes.separate_tess_vue_layout); + + brw_nir_apply_key(pt, &key->base, simd_width); + brw_nir_lower_tes_inputs(nir, devinfo, &input_vue_map, + &prog_data->vue.urb_read_length); + brw_nir_lower_vue_outputs(nir); + BRW_NIR_SNAPSHOT("after_lower_io"); + + brw_nir_opt_vectorize_urb(pt); + BRW_NIR_PASS(intel_nir_lower_patch_vertices_tes); + + BRW_NIR_PASS(brw_nir_lower_deferred_urb_writes, devinfo, + &prog_data->vue.vue_map, 0, 0); + + unsigned output_size_bytes = prog_data->vue.vue_map.num_slots * 4 * 4; + + assert(output_size_bytes >= 1); + assert(output_size_bytes <= GFX7_MAX_DS_URB_ENTRY_SIZE_BYTES); + + prog_data->tes.include_primitive_id = + BITSET_TEST(nir->info.system_values_read, SYSTEM_VALUE_PRIMITIVE_ID); + + /* URB entry sizes are stored as a multiple of 64 bytes. */ + prog_data->vue.urb_entry_size = align(output_size_bytes, 64) / 64; + + brw_fill_tess_info_from_shader_info(&prog_data->tes.tess_info, + &nir->info); } else if (stage == MESA_SHADER_FRAGMENT) { assert(key->fs.mesh_input == INTEL_NEVER && "todo"); brw_nir_apply_key(pt, &key->base, simd_width); diff --git a/src/intel/compiler/jay/jay_partition.c b/src/intel/compiler/jay/jay_partition.c index 1732706a6dd..3a4b2b85878 100644 --- a/src/intel/compiler/jay/jay_partition.c +++ b/src/intel/compiler/jay/jay_partition.c @@ -188,6 +188,10 @@ jay_partition_grf(jay_shader *shader) payload_4[1] = shader->prog_data->vue.urb_read_length * 8; payload_u[1] = shader->push_grfs; eot_4 = 16; + } else if (shader->stage == MESA_SHADER_TESS_EVAL) { + payload_4[0] = 4; /* tesscoord and URB output handles */ + /* inputs and push constants use the general UGPR section */ + eot_4 = 16; } else if (shader->stage == MESA_SHADER_FRAGMENT) { /* The SIMD32 fragment payload splits GPRs into low and high GRFs, with * UGPRs mixed in between. jay_insert_payload_swizzle deals with this and diff --git a/src/intel/dev/intel_debug.c b/src/intel/dev/intel_debug.c index 74c0990eb3d..5d8e8006b68 100644 --- a/src/intel/dev/intel_debug.c +++ b/src/intel/dev/intel_debug.c @@ -304,9 +304,10 @@ process_intel_debug_variable_once(void) } static const struct debug_named_value use_jay_options[] = { - { "vs", BITFIELD_BIT(MESA_SHADER_VERTEX), "Use jay for vertex shaders" }, - { "fs", BITFIELD_BIT(MESA_SHADER_FRAGMENT), "Use jay for fragment shaders" }, - { "cs", BITFIELD_BIT(MESA_SHADER_COMPUTE), "Use jay for compute shaders" }, + { "vs", BITFIELD_BIT(MESA_SHADER_VERTEX), "Use jay for vertex shaders" }, + { "tes", BITFIELD_BIT(MESA_SHADER_TESS_EVAL), "Use jay for tessellation evaluation shaders" }, + { "fs", BITFIELD_BIT(MESA_SHADER_FRAGMENT), "Use jay for fragment shaders" }, + { "cs", BITFIELD_BIT(MESA_SHADER_COMPUTE), "Use jay for compute shaders" }, DEBUG_NAMED_VALUE_END };