brw: handle GLSL/GLSL tessellation parameters

Apparently various tessellation parameters come specified from
TESS_EVAL stage in GLSL while they come from the TESS_CTRL stage in
HLSL.

We switch to store the tesselation params more like shader_info with 0
values for unspecified fields. That let's us merge it with a simple OR
with values from from tcs/tes and the resulting merge can be used for
state programming.

Signed-off-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
Fixes: a91e0e0d61 ("brw: add support for separate tessellation shader compilation")
Fixes: 50fd669294 ("anv: prep work for separate tessellation shaders")
Reviewed-by: Ivan Briano <ivan.briano@intel.com>
(cherry picked from commit f3df267735)

Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/38167>
This commit is contained in:
Lionel Landwerlin 2025-10-21 16:41:41 +03:00 committed by Dylan Baker
parent 1648f759c1
commit dcecd8fd1e
9 changed files with 166 additions and 58 deletions

View file

@ -994,7 +994,7 @@
"description": "brw: handle GLSL/GLSL tessellation parameters", "description": "brw: handle GLSL/GLSL tessellation parameters",
"nominated": true, "nominated": true,
"nomination_type": 2, "nomination_type": 2,
"resolution": 0, "resolution": 1,
"main_sha": null, "main_sha": null,
"because_sha": "a91e0e0d616f857144c8cadfaed734ac5be8e729", "because_sha": "a91e0e0d616f857144c8cadfaed734ac5be8e729",
"notes": null "notes": null

View file

@ -223,9 +223,9 @@ iris_apply_brw_tes_prog_data(struct iris_compiled_shader *shader,
iris_apply_brw_vue_prog_data(&brw->base, &iris->base); iris_apply_brw_vue_prog_data(&brw->base, &iris->base);
iris->partitioning = brw->partitioning; iris->partitioning = brw_tess_info_partitioning(brw->tess_info);
iris->output_topology = brw->output_topology; iris->output_topology = brw_tess_info_output_topology(brw->tess_info);
iris->domain = brw->domain; iris->domain = brw_tess_info_domain(brw->tess_info);
iris->include_primitive_id = brw->include_primitive_id; iris->include_primitive_id = brw->include_primitive_id;
} }

View file

@ -196,6 +196,9 @@ brw_compile_tcs(const struct brw_compiler *compiler,
brw_prog_data_init(&prog_data->base.base, &params->base); brw_prog_data_init(&prog_data->base.base, &params->base);
brw_fill_tess_info_from_shader_info(&prog_data->tess_info,
&nir->info);
nir->info.outputs_written = key->outputs_written; nir->info.outputs_written = key->outputs_written;
nir->info.patch_outputs_written = key->patch_outputs_written; nir->info.patch_outputs_written = key->patch_outputs_written;

View file

@ -59,6 +59,22 @@ run_tes(brw_shader &s)
return !s.failed; return !s.failed;
} }
extern "C" void
brw_fill_tess_info_from_shader_info(struct brw_tess_info *brw_info,
const shader_info *shader_info)
{
STATIC_ASSERT(INTEL_TESS_PARTITIONING_INTEGER == TESS_SPACING_EQUAL - 1);
STATIC_ASSERT(INTEL_TESS_PARTITIONING_ODD_FRACTIONAL ==
TESS_SPACING_FRACTIONAL_ODD - 1);
STATIC_ASSERT(INTEL_TESS_PARTITIONING_EVEN_FRACTIONAL ==
TESS_SPACING_FRACTIONAL_EVEN - 1);
brw_info->primitive_mode = shader_info->tess._primitive_mode;
brw_info->spacing = shader_info->tess.spacing;
brw_info->ccw = shader_info->tess.ccw;
brw_info->point_mode = shader_info->tess.point_mode;
}
const unsigned * const unsigned *
brw_compile_tes(const struct brw_compiler *compiler, brw_compile_tes(const struct brw_compiler *compiler,
brw_compile_tes_params *params) brw_compile_tes_params *params)
@ -121,39 +137,8 @@ brw_compile_tes(const struct brw_compiler *compiler,
prog_data->base.urb_read_length = 0; prog_data->base.urb_read_length = 0;
STATIC_ASSERT(INTEL_TESS_PARTITIONING_INTEGER == TESS_SPACING_EQUAL - 1); brw_fill_tess_info_from_shader_info(&prog_data->tess_info,
STATIC_ASSERT(INTEL_TESS_PARTITIONING_ODD_FRACTIONAL == &nir->info);
TESS_SPACING_FRACTIONAL_ODD - 1);
STATIC_ASSERT(INTEL_TESS_PARTITIONING_EVEN_FRACTIONAL ==
TESS_SPACING_FRACTIONAL_EVEN - 1);
prog_data->partitioning =
(enum intel_tess_partitioning) (nir->info.tess.spacing - 1);
switch (nir->info.tess._primitive_mode) {
case TESS_PRIMITIVE_QUADS:
prog_data->domain = INTEL_TESS_DOMAIN_QUAD;
break;
case TESS_PRIMITIVE_TRIANGLES:
prog_data->domain = INTEL_TESS_DOMAIN_TRI;
break;
case TESS_PRIMITIVE_ISOLINES:
prog_data->domain = INTEL_TESS_DOMAIN_ISOLINE;
break;
default:
UNREACHABLE("invalid domain shader primitive mode");
}
if (nir->info.tess.point_mode) {
prog_data->output_topology = INTEL_TESS_OUTPUT_TOPOLOGY_POINT;
} else if (nir->info.tess._primitive_mode == TESS_PRIMITIVE_ISOLINES) {
prog_data->output_topology = INTEL_TESS_OUTPUT_TOPOLOGY_LINE;
} else {
/* Hardware winding order is backwards from OpenGL */
prog_data->output_topology =
nir->info.tess.ccw ? INTEL_TESS_OUTPUT_TOPOLOGY_TRI_CW
: INTEL_TESS_OUTPUT_TOPOLOGY_TRI_CCW;
}
if (unlikely(debug_enabled)) { if (unlikely(debug_enabled)) {
fprintf(stderr, "TES Input "); fprintf(stderr, "TES Input ");

View file

@ -1158,10 +1158,20 @@ struct brw_vs_prog_data {
uint32_t vf_component_packing[4]; uint32_t vf_component_packing[4];
}; };
struct brw_tess_info {
enum tess_primitive_mode primitive_mode:8;
uint8_t spacing:2;
bool ccw:1;
bool point_mode:1;
uint32_t pad:20;
};
struct brw_tcs_prog_data struct brw_tcs_prog_data
{ {
struct brw_vue_prog_data base; struct brw_vue_prog_data base;
struct brw_tess_info tess_info;
/** Number of input vertices, 0 means dynamic */ /** Number of input vertices, 0 means dynamic */
unsigned input_vertices; unsigned input_vertices;
@ -1187,14 +1197,12 @@ struct brw_tcs_prog_data
unsigned tess_config_param; unsigned tess_config_param;
}; };
struct brw_tes_prog_data struct brw_tes_prog_data
{ {
struct brw_vue_prog_data base; struct brw_vue_prog_data base;
enum intel_tess_partitioning partitioning; struct brw_tess_info tess_info;
enum intel_tess_output_topology output_topology;
enum intel_tess_domain domain;
bool include_primitive_id; bool include_primitive_id;
/** /**
@ -1367,6 +1375,64 @@ DEFINE_PROG_DATA_DOWNCAST(mesh, prog_data->stage == MESA_SHADER_MESH)
#undef DEFINE_PROG_DATA_DOWNCAST #undef DEFINE_PROG_DATA_DOWNCAST
static inline struct brw_tess_info
brw_merge_tess_info(struct brw_tess_info tcs_info,
struct brw_tess_info tes_info)
{
/* Just merge by OR'ing the raw bits */
uint32_t x, y;
assert(sizeof(x) == sizeof(tcs_info));
memcpy(&x, &tcs_info, sizeof(x));
memcpy(&y, &tes_info, sizeof(y));
x |= y;
struct brw_tess_info out;
memcpy(&out, &x, sizeof(out));
return out;
}
static inline enum intel_tess_partitioning
brw_tess_info_partitioning(struct brw_tess_info info)
{
return (enum intel_tess_partitioning)(info.spacing - 1);
}
static inline enum intel_tess_domain
brw_tess_info_domain(struct brw_tess_info info)
{
switch (info.primitive_mode) {
case TESS_PRIMITIVE_QUADS:
return INTEL_TESS_DOMAIN_QUAD;
break;
case TESS_PRIMITIVE_TRIANGLES:
return INTEL_TESS_DOMAIN_TRI;
break;
case TESS_PRIMITIVE_ISOLINES:
return INTEL_TESS_DOMAIN_ISOLINE;
break;
default:
UNREACHABLE("invalid primitive mode");
}
}
static inline enum intel_tess_output_topology
brw_tess_info_output_topology(struct brw_tess_info info)
{
if (info.point_mode) {
return INTEL_TESS_OUTPUT_TOPOLOGY_POINT;
} else if (info.primitive_mode == TESS_PRIMITIVE_ISOLINES) {
return INTEL_TESS_OUTPUT_TOPOLOGY_LINE;
} else {
/* Hardware winding order is backwards from OpenGL */
return info.ccw ?
INTEL_TESS_OUTPUT_TOPOLOGY_TRI_CW :
INTEL_TESS_OUTPUT_TOPOLOGY_TRI_CCW;
}
}
/** @} */ /** @} */
struct brw_compiler * struct brw_compiler *

View file

@ -36,6 +36,10 @@ extern "C" {
extern const struct nir_shader_compiler_options brw_scalar_nir_options; extern const struct nir_shader_compiler_options brw_scalar_nir_options;
void
brw_fill_tess_info_from_shader_info(struct brw_tess_info *brw_info,
const shader_info *shader_info);
int type_size_vec4(const struct glsl_type *type, bool bindless); int type_size_vec4(const struct glsl_type *type, bool bindless);
int type_size_dvec4(const struct glsl_type *type, bool bindless); int type_size_dvec4(const struct glsl_type *type, bool bindless);

View file

@ -2161,8 +2161,15 @@ struct anv_gfx_dynamic_state {
uint32_t SampleMask; uint32_t SampleMask;
} sm; } sm;
/* 3DSTATE_DS */
struct {
bool ComputeWCoordinateEnable;
} ds;
/* 3DSTATE_TE */ /* 3DSTATE_TE */
struct { struct {
uint32_t TEDomain;
uint32_t Partitioning;
uint32_t OutputTopology; uint32_t OutputTopology;
uint32_t TessellationDistributionMode; uint32_t TessellationDistributionMode;
} te; } te;

View file

@ -490,7 +490,12 @@ anv_raster_polygon_mode(const struct anv_cmd_graphics_state *gfx,
} }
UNREACHABLE("Unsupported GS output topology"); UNREACHABLE("Unsupported GS output topology");
} else if (gfx->shaders[MESA_SHADER_TESS_EVAL] != NULL) { } else if (gfx->shaders[MESA_SHADER_TESS_EVAL] != NULL) {
switch (get_gfx_tes_prog_data(gfx)->output_topology) { struct brw_tess_info tess_info =
brw_merge_tess_info(
get_gfx_tcs_prog_data(gfx)->tess_info,
get_gfx_tes_prog_data(gfx)->tess_info);
switch (brw_tess_info_output_topology(tess_info)) {
case INTEL_TESS_OUTPUT_TOPOLOGY_POINT: case INTEL_TESS_OUTPUT_TOPOLOGY_POINT:
return VK_POLYGON_MODE_POINT; return VK_POLYGON_MODE_POINT;
@ -500,8 +505,10 @@ anv_raster_polygon_mode(const struct anv_cmd_graphics_state *gfx,
case INTEL_TESS_OUTPUT_TOPOLOGY_TRI_CW: case INTEL_TESS_OUTPUT_TOPOLOGY_TRI_CW:
case INTEL_TESS_OUTPUT_TOPOLOGY_TRI_CCW: case INTEL_TESS_OUTPUT_TOPOLOGY_TRI_CCW:
return polygon_mode; return polygon_mode;
default:
UNREACHABLE("Unsupported TCS output topology");
} }
UNREACHABLE("Unsupported TCS output topology");
} else { } else {
switch (primitive_topology) { switch (primitive_topology) {
case VK_PRIMITIVE_TOPOLOGY_POINT_LIST: case VK_PRIMITIVE_TOPOLOGY_POINT_LIST:
@ -1317,6 +1324,22 @@ update_cps(struct anv_gfx_dynamic_state *hw_state,
} }
#endif #endif
ALWAYS_INLINE static void
update_ds(struct anv_gfx_dynamic_state *hw_state,
const struct anv_cmd_graphics_state *gfx)
{
const struct brw_tes_prog_data *tes_prog_data = get_gfx_tes_prog_data(gfx);
if (tes_prog_data) {
struct brw_tess_info tess_info =
brw_merge_tess_info(get_gfx_tcs_prog_data(gfx)->tess_info,
tes_prog_data->tess_info);
SET(DS, ds.ComputeWCoordinateEnable,
brw_tess_info_domain(tess_info) == INTEL_TESS_DOMAIN_TRI);
}
}
ALWAYS_INLINE static void ALWAYS_INLINE static void
update_te(struct anv_gfx_dynamic_state *hw_state, update_te(struct anv_gfx_dynamic_state *hw_state,
const struct anv_device *device, const struct anv_device *device,
@ -1326,16 +1349,28 @@ update_te(struct anv_gfx_dynamic_state *hw_state,
const struct brw_tes_prog_data *tes_prog_data = get_gfx_tes_prog_data(gfx); const struct brw_tes_prog_data *tes_prog_data = get_gfx_tes_prog_data(gfx);
if (tes_prog_data) { if (tes_prog_data) {
struct brw_tess_info tess_info =
brw_merge_tess_info(get_gfx_tcs_prog_data(gfx)->tess_info,
tes_prog_data->tess_info);
SET(TE, te.TEDomain, brw_tess_info_domain(tess_info));
SET(TE, te.Partitioning, brw_tess_info_partitioning(tess_info));
if (dyn->ts.domain_origin == VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT) { if (dyn->ts.domain_origin == VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT) {
SET(TE, te.OutputTopology, tes_prog_data->output_topology); SET(TE, te.OutputTopology, brw_tess_info_output_topology(tess_info));
} else { } else {
/* When the origin is upper-left, we have to flip the winding order */ /* When the origin is upper-left, we have to flip the winding order */
if (tes_prog_data->output_topology == OUTPUT_TRI_CCW) { enum intel_tess_output_topology output_topology =
brw_tess_info_output_topology(tess_info);
switch (output_topology) {
case OUTPUT_TRI_CCW:
SET(TE, te.OutputTopology, OUTPUT_TRI_CW); SET(TE, te.OutputTopology, OUTPUT_TRI_CW);
} else if (tes_prog_data->output_topology == OUTPUT_TRI_CW) { break;
case OUTPUT_TRI_CW:
SET(TE, te.OutputTopology, OUTPUT_TRI_CCW); SET(TE, te.OutputTopology, OUTPUT_TRI_CCW);
} else { break;
SET(TE, te.OutputTopology, tes_prog_data->output_topology); default:
SET(TE, te.OutputTopology, output_topology);
break;
} }
} }
@ -2335,11 +2370,14 @@ cmd_buffer_flush_gfx_runtime_state(struct anv_gfx_dynamic_state *hw_state,
update_cps(hw_state, device, dyn); update_cps(hw_state, device, dyn);
#endif /* GFX_VER >= 11 */ #endif /* GFX_VER >= 11 */
if (gfx->dirty & (ANV_CMD_DIRTY_HS | ANV_CMD_DIRTY_DS))
update_ds(hw_state, gfx);
if ( if (
#if GFX_VERx10 >= 125 #if GFX_VERx10 >= 125
(gfx->dirty & ANV_CMD_DIRTY_PRERASTER_SHADERS) || (gfx->dirty & ANV_CMD_DIRTY_PRERASTER_SHADERS) ||
#else #else
(gfx->dirty & ANV_CMD_DIRTY_DS) || (gfx->dirty & (ANV_CMD_DIRTY_HS | ANV_CMD_DIRTY_DS)) ||
#endif #endif
BITSET_TEST(dyn->dirty, MESA_VK_DYNAMIC_TS_DOMAIN_ORIGIN)) BITSET_TEST(dyn->dirty, MESA_VK_DYNAMIC_TS_DOMAIN_ORIGIN))
update_te(hw_state, device, dyn, gfx); update_te(hw_state, device, dyn, gfx);
@ -2506,10 +2544,14 @@ cmd_buffer_flush_gfx_runtime_state(struct anv_gfx_dynamic_state *hw_state,
((gfx->dirty & (ANV_CMD_DIRTY_HS | ANV_CMD_DIRTY_DS)) || ((gfx->dirty & (ANV_CMD_DIRTY_HS | ANV_CMD_DIRTY_DS)) ||
BITSET_TEST(dyn->dirty, MESA_VK_DYNAMIC_TS_PATCH_CONTROL_POINTS))) { BITSET_TEST(dyn->dirty, MESA_VK_DYNAMIC_TS_PATCH_CONTROL_POINTS))) {
assert(tcs_prog_data != NULL && tes_prog_data != NULL); assert(tcs_prog_data != NULL && tes_prog_data != NULL);
struct brw_tess_info tess_info =
brw_merge_tess_info(tcs_prog_data->tess_info,
tes_prog_data->tess_info);
SET(TESS_CONFIG, tess_config, SET(TESS_CONFIG, tess_config,
intel_tess_config(dyn->ts.patch_control_points, intel_tess_config(dyn->ts.patch_control_points,
tcs_prog_data->instances, tcs_prog_data->instances,
tes_prog_data->domain, brw_tess_info_domain(tess_info),
tcs_prog_data->base.vue_map.num_per_patch_slots, tcs_prog_data->base.vue_map.num_per_patch_slots,
tcs_prog_data->base.vue_map.num_per_vertex_slots, tcs_prog_data->base.vue_map.num_per_vertex_slots,
tcs_prog_data->base.vue_map.builtins_slot_offset)); tcs_prog_data->base.vue_map.builtins_slot_offset));
@ -2975,6 +3017,8 @@ cmd_buffer_repack_gfx_state(struct anv_gfx_dynamic_state *hw_state,
if (anv_gfx_has_stage(gfx, MESA_SHADER_TESS_EVAL)) { if (anv_gfx_has_stage(gfx, MESA_SHADER_TESS_EVAL)) {
anv_gfx_pack_merge(te, GENX(3DSTATE_TE), anv_gfx_pack_merge(te, GENX(3DSTATE_TE),
MESA_SHADER_TESS_EVAL, ds.te, te) { MESA_SHADER_TESS_EVAL, ds.te, te) {
SET(te, te, TEDomain);
SET(te, te, Partitioning);
SET(te, te, OutputTopology); SET(te, te, OutputTopology);
#if GFX_VERx10 >= 125 #if GFX_VERx10 >= 125
SET(te, te, TessellationDistributionMode); SET(te, te, TessellationDistributionMode);
@ -3230,8 +3274,12 @@ cmd_buffer_repack_gfx_state(struct anv_gfx_dynamic_state *hw_state,
if (IS_DIRTY(HS)) if (IS_DIRTY(HS))
anv_gfx_copy_protected(hs, GENX(3DSTATE_HS), MESA_SHADER_TESS_CTRL, hs.hs); anv_gfx_copy_protected(hs, GENX(3DSTATE_HS), MESA_SHADER_TESS_CTRL, hs.hs);
if (IS_DIRTY(DS)) if (IS_DIRTY(DS)) {
anv_gfx_copy_protected(ds, GENX(3DSTATE_DS), MESA_SHADER_TESS_EVAL, ds.ds); anv_gfx_pack_merge_protected(ds, GENX(3DSTATE_DS),
MESA_SHADER_TESS_EVAL, ds.ds, ds) {
SET(ds, ds, ComputeWCoordinateEnable);
}
}
if (IS_DIRTY(GS)) { if (IS_DIRTY(GS)) {
anv_gfx_pack_merge_protected(gs, GENX(3DSTATE_GS), anv_gfx_pack_merge_protected(gs, GENX(3DSTATE_GS),

View file

@ -695,8 +695,6 @@ emit_ds_shader(struct anv_batch *batch,
anv_shader_emit(batch, shader, ds.te, GENX(3DSTATE_TE), te) { anv_shader_emit(batch, shader, ds.te, GENX(3DSTATE_TE), te) {
te.TEEnable = true; te.TEEnable = true;
te.Partitioning = tes_prog_data->partitioning;
te.TEDomain = tes_prog_data->domain;
te.MaximumTessellationFactorOdd = 63.0; te.MaximumTessellationFactorOdd = 63.0;
te.MaximumTessellationFactorNotOdd = 64.0; te.MaximumTessellationFactorNotOdd = 64.0;
#if GFX_VERx10 >= 125 #if GFX_VERx10 >= 125
@ -731,9 +729,6 @@ emit_ds_shader(struct anv_batch *batch,
ds.BindingTableEntryCount = shader->bind_map.surface_count; ds.BindingTableEntryCount = shader->bind_map.surface_count;
ds.MaximumNumberofThreads = devinfo->max_tes_threads - 1; ds.MaximumNumberofThreads = devinfo->max_tes_threads - 1;
ds.ComputeWCoordinateEnable =
tes_prog_data->domain == INTEL_TESS_DOMAIN_TRI;
ds.PatchURBEntryReadLength = tes_prog_data->base.urb_read_length; ds.PatchURBEntryReadLength = tes_prog_data->base.urb_read_length;
ds.PatchURBEntryReadOffset = 0; ds.PatchURBEntryReadOffset = 0;
ds.DispatchGRFStartRegisterForURBData = ds.DispatchGRFStartRegisterForURBData =