asahi: make point size replacement dynamic

I'm not measuring a significant perf difference in
-bshading:shading=phong:model=bunny -bideas -brefract so this seems Good Enough
For Me.

Signed-off-by: Alyssa Rosenzweig <alyssa@rosenzweig.io>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/28483>
This commit is contained in:
Alyssa Rosenzweig 2024-03-05 10:46:54 -04:00 committed by Marge Bot
parent 7595dc9036
commit 5c7ce24896
4 changed files with 49 additions and 66 deletions

View file

@ -1936,7 +1936,8 @@ system_value("api_sample_mask_agx", 1, bit_sizes=[16])
# Loads the sample position array as fixed point packed into a 32-bit word
system_value("sample_positions_agx", 1, bit_sizes=[32])
# Loads the fixed-function glPointSize() value
# Loads the fixed-function glPointSize() value, or zero if the
# shader-supplied value should be used.
system_value("fixed_point_size_agx", 1, bit_sizes=[32])
# Bit mask of TEX locations that are replaced with point sprites

View file

@ -5,60 +5,62 @@
#include "agx_state.h"
#include "nir.h"
#include "nir_builder.h"
#include "nir_builder_opcodes.h"
/*
* gl_PointSize lowering. This runs late on a vertex shader (epilogue). By this
* time, I/O has been lowered, and transform feedback has been written. Point
* size will thus only get consumed by the rasterizer, so we can clamp/replace.
* We do this instead of the mesa/st lowerings for better behaviour with lowered
* I/O and vertex epilogues.
* gl_PointSize lowering. This runs late on a vertex shader. By this time, I/O
* has been lowered, and transform feedback has been written. Point size will
* thus only get consumed by the rasterizer, so we can clamp/replace. We do
* this instead of the mesa/st lowerings to avoid the variant. I wouldn't mind
* ripping this out some day...
*/
static bool
pass(nir_builder *b, nir_intrinsic_instr *intr, void *data)
{
bool *fixed_point_size = data;
b->cursor = nir_before_instr(&intr->instr);
if ((intr->intrinsic != nir_intrinsic_store_output) ||
(nir_intrinsic_io_semantics(intr).location != VARYING_SLOT_PSIZ))
return false;
if (*fixed_point_size) {
/* We want to override point size. Remove this store. */
nir_instr_remove(&intr->instr);
} else {
/* We want to use this point size. Clamp it. */
nir_src_rewrite(&intr->src[0],
nir_fmax(b, intr->src[0].ssa, nir_imm_float(b, 1.0f)));
}
/* The size we write must be clamped */
nir_def *size = nir_fmax(b, intr->src[0].ssa, nir_imm_float(b, 1.0f));
/* Override it if the API requires */
nir_def *fixed_size = nir_load_fixed_point_size_agx(b);
size = nir_bcsel(b, nir_fgt_imm(b, fixed_size, 0.0), fixed_size, size);
nir_src_rewrite(&intr->src[0], size);
return true;
}
bool
agx_nir_lower_point_size(nir_shader *nir, bool fixed_point_size)
agx_nir_lower_point_size(nir_shader *nir, bool insert_write)
{
/* Handle existing point size write */
bool progress = nir_shader_intrinsics_pass(
nir, pass, nir_metadata_block_index | nir_metadata_dominance,
&fixed_point_size);
/* Lower existing point size write */
if (nir_shader_intrinsics_pass(
nir, pass, nir_metadata_block_index | nir_metadata_dominance, NULL))
return true;
/* Write the fixed-function point size if we have one */
if (fixed_point_size) {
nir_builder b =
nir_builder_at(nir_after_impl(nir_shader_get_entrypoint(nir)));
if (!insert_write)
return false;
nir_store_output(
&b, nir_load_fixed_point_size_agx(&b), nir_imm_int(&b, 0),
.io_semantics.location = VARYING_SLOT_PSIZ,
.io_semantics.num_slots = 1, .write_mask = nir_component_mask(1));
/* If there's no existing point size write, insert one. This assumes there
* was a fixed point size set in the API. If not, GL allows undefined
* behaviour, which we implement by writing garbage.
*/
nir_builder b =
nir_builder_at(nir_after_impl(nir_shader_get_entrypoint(nir)));
nir->info.outputs_written |= VARYING_BIT_PSIZ;
progress = true;
nir_metadata_preserve(b.impl,
nir_metadata_dominance | nir_metadata_block_index);
}
nir_store_output(&b, nir_load_fixed_point_size_agx(&b), nir_imm_int(&b, 0),
.io_semantics.location = VARYING_SLOT_PSIZ,
.io_semantics.num_slots = 1,
.write_mask = nir_component_mask(1));
return progress;
nir->info.outputs_written |= VARYING_BIT_PSIZ;
nir_metadata_preserve(b.impl,
nir_metadata_dominance | nir_metadata_block_index);
return true;
}

View file

@ -1823,8 +1823,8 @@ agx_compile_variant(struct agx_device *dev, struct pipe_context *pctx,
NIR_PASS(_, nir, lower_vbo, key->attribs);
if (key->hw) {
NIR_PASS(_, nir, agx_nir_lower_point_size,
key->next.hw.fixed_point_size);
NIR_PASS(_, nir, agx_nir_lower_point_size, true);
NIR_PASS(_, nir, nir_shader_intrinsics_pass, agx_nir_lower_clip_m1_1,
nir_metadata_block_index | nir_metadata_dominance, NULL);
NIR_PASS(_, nir, agx_nir_lower_uvs, &uvs);
@ -1976,10 +1976,11 @@ agx_compile_variant(struct agx_device *dev, struct pipe_context *pctx,
}
if (gs_copy) {
struct asahi_gs_shader_key *key = &key_->gs;
/* Replace the point size write if present, but do not insert a write:
* the GS rast program writes point size iff we have points.
*/
NIR_PASS(_, gs_copy, agx_nir_lower_point_size, false);
/* TODO: deduplicate */
NIR_PASS(_, gs_copy, agx_nir_lower_point_size, key->fixed_point_size);
NIR_PASS(_, gs_copy, nir_shader_intrinsics_pass, agx_nir_lower_clip_m1_1,
nir_metadata_block_index | nir_metadata_dominance, NULL);
@ -2381,21 +2382,12 @@ agx_update_vs(struct agx_context *ctx, unsigned index_size_B)
ctx->stage[PIPE_SHADER_GEOMETRY].shader || ctx->in_tess))
return false;
enum mesa_prim rasterized_prim =
rast_prim(ctx->batch->reduced_prim, ctx->rast->base.fill_front);
struct asahi_vs_shader_key key = {
.hw = !((ctx->stage[PIPE_SHADER_TESS_EVAL].shader && !ctx->in_tess) ||
ctx->stage[PIPE_SHADER_GEOMETRY].shader),
};
if (key.hw) {
/* If we are not rasterizing points, don't set fixed_point_size to
* eliminate the useless point size write.
*/
key.next.hw.fixed_point_size = !ctx->rast->base.point_size_per_vertex &&
rasterized_prim == MESA_PRIM_POINTS;
} else {
if (!key.hw) {
key.next.sw.index_size_B = index_size_B;
}
@ -2441,15 +2433,8 @@ agx_update_gs(struct agx_context *ctx, const struct pipe_draw_info *info,
tgt->stride = gs->xfb_strides[i];
}
enum mesa_prim rasterized_prim =
rast_prim(gs->gs_mode, ctx->rast->base.fill_front);
struct asahi_gs_shader_key key = {
.rasterizer_discard = ctx->rast->base.rasterizer_discard,
/* TODO: Deduplicate */
.fixed_point_size = !ctx->rast->base.point_size_per_vertex &&
rasterized_prim == MESA_PRIM_POINTS,
};
return agx_update_shader(ctx, &ctx->gs, PIPE_SHADER_GEOMETRY,
@ -5044,7 +5029,9 @@ agx_draw_vbo(struct pipe_context *pctx, const struct pipe_draw_info *info,
}
if (IS_DIRTY(RS)) {
batch->uniforms.fixed_point_size = ctx->rast->base.point_size;
batch->uniforms.fixed_point_size =
ctx->rast->base.point_size_per_vertex ? 0.0
: ctx->rast->base.point_size;
}
if (IS_DIRTY(QUERY)) {

View file

@ -486,10 +486,6 @@ struct asahi_vs_shader_key {
struct {
uint8_t index_size_B;
} sw;
struct {
bool fixed_point_size;
} hw;
} next;
};
@ -520,12 +516,9 @@ struct asahi_fs_shader_key {
};
struct asahi_gs_shader_key {
/* Rasterizer shader key */
bool fixed_point_size;
/* If true, this GS is run only for its side effects (including XFB) */
bool rasterizer_discard;
bool padding[6];
bool padding[7];
};
static_assert(sizeof(struct asahi_gs_shader_key) == 8, "no holes");
@ -980,7 +973,7 @@ void agx_set_cbuf_uniforms(struct agx_batch *batch,
void agx_set_ssbo_uniforms(struct agx_batch *batch,
enum pipe_shader_type stage);
bool agx_nir_lower_point_size(nir_shader *nir, bool fixed_point_size);
bool agx_nir_lower_point_size(nir_shader *nir, bool insert_write);
bool agx_nir_lower_sysvals(nir_shader *shader, enum pipe_shader_type desc_stage,
bool lower_draw_params);