mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2026-01-06 06:40:08 +01:00
radeonsi: implement shader culling in GS
It already does compaction, so we just need to load vertex positions and cull. This was easier than expected. Reviewed-by: Pierre-Eric Pelloux-Prayer <pierre-eric.pelloux-prayer@amd.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/13829>
This commit is contained in:
parent
492a61fe72
commit
9d7ac70ffb
6 changed files with 98 additions and 18 deletions
|
|
@ -78,7 +78,10 @@ static LLVMValueRef ngg_get_vertices_per_prim(struct si_shader_context *ctx, uns
|
|||
{
|
||||
const struct si_shader_info *info = &ctx->shader->selector->info;
|
||||
|
||||
if (ctx->stage == MESA_SHADER_VERTEX) {
|
||||
if (ctx->stage == MESA_SHADER_GEOMETRY) {
|
||||
*num_vertices = u_vertices_per_prim(info->base.gs.output_primitive);
|
||||
return LLVMConstInt(ctx->ac.i32, *num_vertices, false);
|
||||
} else if (ctx->stage == MESA_SHADER_VERTEX) {
|
||||
if (info->base.vs.blit_sgprs_amd) {
|
||||
/* Blits always use axis-aligned rectangles with 3 vertices. */
|
||||
*num_vertices = 3;
|
||||
|
|
@ -1954,6 +1957,79 @@ void gfx10_ngg_gs_emit_epilogue(struct si_shader_context *ctx)
|
|||
ac_build_endif(&ctx->ac, 5109);
|
||||
}
|
||||
|
||||
/* Cull primitives. */
|
||||
if (ctx->shader->key.ge.opt.ngg_culling) {
|
||||
assert(info->num_stream_output_components[0]);
|
||||
|
||||
LLVMValueRef gs_vtxptr = ngg_gs_vertex_ptr(ctx, tid);
|
||||
LLVMValueRef live = LLVMBuildLoad(builder, ngg_gs_get_emit_primflag_ptr(ctx, gs_vtxptr, 0), "");
|
||||
live = LLVMBuildTrunc(builder, live, ctx->ac.i1, "");
|
||||
LLVMValueRef is_emit = LLVMBuildICmp(builder, LLVMIntULT, tid, num_emit_threads, "");
|
||||
LLVMValueRef prim_enable = LLVMBuildAnd(builder, live, is_emit, "");
|
||||
|
||||
/* Wait for streamout to finish before we kill primitives. */
|
||||
if (sel->so.num_outputs)
|
||||
ac_build_s_barrier(&ctx->ac);
|
||||
|
||||
ac_build_ifcc(&ctx->ac, prim_enable, 0);
|
||||
{
|
||||
LLVMValueRef vtxptr[3] = {};
|
||||
LLVMValueRef pos[3][4] = {};
|
||||
|
||||
for (unsigned i = 0; i < verts_per_prim; i++) {
|
||||
tmp = LLVMBuildSub(builder, tid, LLVMConstInt(ctx->ac.i32, verts_per_prim - i - 1, false), "");
|
||||
vtxptr[i] = ac_build_gep0(&ctx->ac, ngg_gs_vertex_ptr(ctx, tmp), ctx->ac.i32_0);
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < info->num_outputs; i++) {
|
||||
/* If the stream index is non-zero for all channels, skip the output. */
|
||||
if (info->output_streams[i] & 0x3 &&
|
||||
(info->output_streams[i] >> 2) & 0x3 &&
|
||||
(info->output_streams[i] >> 4) & 0x3 &&
|
||||
(info->output_streams[i] >> 6) & 0x3)
|
||||
continue;
|
||||
|
||||
switch (info->output_semantic[i]) {
|
||||
case VARYING_SLOT_POS:
|
||||
/* Load the positions from LDS. */
|
||||
for (unsigned vert = 0; vert < verts_per_prim; vert++) {
|
||||
for (unsigned comp = 0; comp < 4; comp++) {
|
||||
/* Z is not needed. */
|
||||
if (comp == 2)
|
||||
continue;
|
||||
|
||||
tmp = ac_build_gep0(&ctx->ac, vtxptr[vert],
|
||||
LLVMConstInt(ctx->ac.i32, 4 * i + comp, false));
|
||||
pos[vert][comp] = LLVMBuildLoad(builder, tmp, "");
|
||||
pos[vert][comp] = ac_to_float(&ctx->ac, pos[vert][comp]);
|
||||
}
|
||||
}
|
||||
|
||||
/* Divide XY by W. */
|
||||
for (unsigned vert = 0; vert < verts_per_prim; vert++) {
|
||||
for (unsigned comp = 0; comp < 2; comp++)
|
||||
pos[vert][comp] = ac_build_fdiv(&ctx->ac, pos[vert][comp], pos[vert][3]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
LLVMValueRef clipdist_accepted = ctx->ac.i1true; /* TODO */
|
||||
LLVMValueRef accepted = ac_build_alloca(&ctx->ac, ctx->ac.i32, "");
|
||||
|
||||
cull_primitive(ctx, pos, clipdist_accepted, accepted, NULL);
|
||||
|
||||
accepted = LLVMBuildLoad(builder, accepted, "");
|
||||
LLVMValueRef rejected = LLVMBuildNot(builder, LLVMBuildTrunc(builder, accepted, ctx->ac.i1, ""), "");
|
||||
|
||||
ac_build_ifcc(&ctx->ac, rejected, 0);
|
||||
LLVMBuildStore(builder, ctx->ac.i8_0, ngg_gs_get_emit_primflag_ptr(ctx, gs_vtxptr, 0));
|
||||
ac_build_endif(&ctx->ac, 0);
|
||||
}
|
||||
ac_build_endif(&ctx->ac, 0);
|
||||
ac_build_s_barrier(&ctx->ac);
|
||||
}
|
||||
|
||||
/* Determine vertex liveness. */
|
||||
LLVMValueRef vertliveptr = ac_build_alloca(&ctx->ac, ctx->ac.i1, "vertexlive");
|
||||
|
||||
|
|
|
|||
|
|
@ -546,10 +546,14 @@ void si_init_shader_args(struct si_shader_context *ctx, bool ngg_cull_shader)
|
|||
ac_add_arg(&ctx->args, AC_ARG_SGPR, 1, AC_ARG_INT, &ctx->tcs_offchip_layout);
|
||||
ac_add_arg(&ctx->args, AC_ARG_SGPR, 1, AC_ARG_INT, &ctx->tes_offchip_addr);
|
||||
ac_add_arg(&ctx->args, AC_ARG_SGPR, 1, AC_ARG_INT, NULL); /* unused */
|
||||
} else {
|
||||
/* GS */
|
||||
ac_add_arg(&ctx->args, AC_ARG_SGPR, 1, AC_ARG_INT, NULL); /* unused */
|
||||
ac_add_arg(&ctx->args, AC_ARG_SGPR, 1, AC_ARG_INT, NULL); /* unused */
|
||||
ac_add_arg(&ctx->args, AC_ARG_SGPR, 1, AC_ARG_INT, NULL); /* unused */
|
||||
}
|
||||
|
||||
if (ctx->stage != MESA_SHADER_GEOMETRY)
|
||||
ac_add_arg(&ctx->args, AC_ARG_SGPR, 1, AC_ARG_CONST_DESC_PTR, &ctx->small_prim_cull_info);
|
||||
ac_add_arg(&ctx->args, AC_ARG_SGPR, 1, AC_ARG_CONST_DESC_PTR, &ctx->small_prim_cull_info);
|
||||
|
||||
if (ctx->stage == MESA_SHADER_VERTEX)
|
||||
declare_vb_descriptor_input_sgprs(ctx);
|
||||
|
|
@ -583,10 +587,8 @@ void si_init_shader_args(struct si_shader_context *ctx, bool ngg_cull_shader)
|
|||
num_user_sgprs =
|
||||
SI_SGPR_VS_VB_DESCRIPTOR_FIRST + shader->selector->num_vbos_in_user_sgprs * 4;
|
||||
}
|
||||
} else if (ctx->stage == MESA_SHADER_TESS_EVAL && ngg_cull_shader) {
|
||||
num_user_sgprs = GFX9_GS_NUM_USER_SGPR;
|
||||
} else {
|
||||
num_user_sgprs = SI_NUM_VS_STATE_RESOURCE_SGPRS;
|
||||
num_user_sgprs = GFX9_GS_NUM_USER_SGPR;
|
||||
}
|
||||
|
||||
/* The NGG cull shader has to return all 9 VGPRs.
|
||||
|
|
@ -1264,8 +1266,7 @@ static void si_dump_shader_key(const struct si_shader *shader, FILE *f)
|
|||
fprintf(f, " opt.kill_outputs = 0x%" PRIx64 "\n", key->ge.opt.kill_outputs);
|
||||
fprintf(f, " opt.kill_pointsize = 0x%x\n", key->ge.opt.kill_pointsize);
|
||||
fprintf(f, " opt.kill_clip_distances = 0x%x\n", key->ge.opt.kill_clip_distances);
|
||||
if (stage != MESA_SHADER_GEOMETRY)
|
||||
fprintf(f, " opt.ngg_culling = 0x%x\n", key->ge.opt.ngg_culling);
|
||||
fprintf(f, " opt.ngg_culling = 0x%x\n", key->ge.opt.ngg_culling);
|
||||
}
|
||||
|
||||
if (stage <= MESA_SHADER_GEOMETRY) {
|
||||
|
|
|
|||
|
|
@ -1093,7 +1093,7 @@ bool si_llvm_compile_shader(struct si_screen *sscreen, struct ac_llvm_compiler *
|
|||
si_llvm_context_init(&ctx, sscreen, compiler, si_get_shader_wave_size(shader));
|
||||
|
||||
LLVMValueRef ngg_cull_main_fn = NULL;
|
||||
if (sel->info.stage <= MESA_SHADER_GEOMETRY && shader->key.ge.opt.ngg_culling) {
|
||||
if (sel->info.stage <= MESA_SHADER_TESS_EVAL && shader->key.ge.opt.ngg_culling) {
|
||||
if (!si_llvm_translate_nir(&ctx, shader, nir, false, true)) {
|
||||
si_llvm_dispose(&ctx);
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -116,9 +116,10 @@ static void si_set_es_return_value_for_gs(struct si_shader_context *ctx)
|
|||
8 + SI_SGPR_BINDLESS_SAMPLERS_AND_IMAGES);
|
||||
if (ctx->screen->use_ngg) {
|
||||
ret = si_insert_input_ptr(ctx, ret, ctx->vs_state_bits, 8 + SI_SGPR_VS_STATE_BITS);
|
||||
ret = si_insert_input_ptr(ctx, ret, ctx->small_prim_cull_info, 8 + GFX9_SGPR_SMALL_PRIM_CULL_INFO);
|
||||
}
|
||||
|
||||
unsigned vgpr = 8 + SI_NUM_VS_STATE_RESOURCE_SGPRS;
|
||||
unsigned vgpr = 8 + GFX9_GS_NUM_USER_SGPR;
|
||||
|
||||
ret = si_insert_input_ret_float(ctx, ret, ctx->args.gs_vtx_offset[0], vgpr++);
|
||||
ret = si_insert_input_ret_float(ctx, ret, ctx->args.gs_vtx_offset[1], vgpr++);
|
||||
|
|
|
|||
|
|
@ -2267,10 +2267,10 @@ static void si_draw(struct pipe_context *ctx,
|
|||
if (GFX_VERSION >= GFX10) {
|
||||
struct si_shader_selector *hw_vs = si_get_vs_inline(sctx, HAS_TESS, HAS_GS)->cso;
|
||||
|
||||
if (NGG && !HAS_GS &&
|
||||
/* Tessellation sets ngg_cull_vert_threshold to UINT_MAX if the prim type
|
||||
* is not points, so this check is only needed without tessellation. */
|
||||
(HAS_TESS || util_rast_prim_is_lines_or_triangles(sctx->current_rast_prim)) &&
|
||||
if (NGG &&
|
||||
/* Tessellation and GS set ngg_cull_vert_threshold to UINT_MAX if the prim type
|
||||
* is not points, so this check is only needed for VS. */
|
||||
(HAS_TESS || HAS_GS || util_rast_prim_is_lines_or_triangles(sctx->current_rast_prim)) &&
|
||||
/* Only the first draw for a shader starts with culling disabled and it's disabled
|
||||
* until we pass the total_direct_count check and then it stays enabled until
|
||||
* the shader is changed. This eliminates most culling on/off state changes. */
|
||||
|
|
|
|||
|
|
@ -3017,11 +3017,12 @@ static void *si_create_shader_selector(struct pipe_context *ctx,
|
|||
bool ngg_culling_allowed =
|
||||
sscreen->info.chip_class >= GFX10 &&
|
||||
sscreen->use_ngg_culling &&
|
||||
(sel->info.stage == MESA_SHADER_VERTEX ||
|
||||
sel->info.stage == MESA_SHADER_TESS_EVAL) &&
|
||||
sel->info.writes_position &&
|
||||
!sel->info.writes_viewport_index && /* cull only against viewport 0 */
|
||||
!sel->info.base.writes_memory && !sel->so.num_outputs &&
|
||||
!sel->info.base.writes_memory &&
|
||||
/* NGG GS supports culling with streamout because it culls after streamout. */
|
||||
(sel->info.stage == MESA_SHADER_GEOMETRY || !sel->so.num_outputs) &&
|
||||
(sel->info.stage != MESA_SHADER_GEOMETRY || sel->info.num_stream_output_components[0]) &&
|
||||
(sel->info.stage != MESA_SHADER_VERTEX ||
|
||||
(!sel->info.base.vs.blit_sgprs_amd &&
|
||||
!sel->info.base.vs.window_space_position));
|
||||
|
|
@ -3034,7 +3035,8 @@ static void *si_create_shader_selector(struct pipe_context *ctx,
|
|||
sel->ngg_cull_vert_threshold = 0; /* always enabled */
|
||||
else
|
||||
sel->ngg_cull_vert_threshold = 128;
|
||||
} else if (sel->info.stage == MESA_SHADER_TESS_EVAL) {
|
||||
} else if (sel->info.stage == MESA_SHADER_TESS_EVAL ||
|
||||
sel->info.stage == MESA_SHADER_GEOMETRY) {
|
||||
if (sel->rast_prim != PIPE_PRIM_POINTS)
|
||||
sel->ngg_cull_vert_threshold = 0; /* always enabled */
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue