pvr, pco: basic depth feedback/discard/terminate support

Signed-off-by: Simon Perretta <simon.perretta@imgtec.com>
Acked-by: Erik Faye-Lund <erik.faye-lund@collabora.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/36412>
This commit is contained in:
Simon Perretta 2025-02-02 01:05:21 +00:00 committed by Marge Bot
parent 7a5511d592
commit 486ca8bbc1
9 changed files with 179 additions and 4 deletions

View file

@ -2724,3 +2724,7 @@ index("unsigned", "mutex_op_pco")
# Perform a mutex operation (slot granularity).
intrinsic("mutex_pco", indices=[MUTEX_ID_PCO, MUTEX_OP_PCO])
# depthf_pco(depth value)
# Perform an ISP depth feedback operation.
intrinsic("depthf_pco", src_comp=[1], bit_sizes=[32])

View file

@ -78,6 +78,8 @@ typedef struct _pco_fs_data {
bool pntc; /** Whether the shader uses point coord. */
bool phase_change; /** Whether the shader does a phase change. */
bool fbfetch; /** Whether the shader fetches from the framebuffer. */
bool depth_feedback;
bool discard;
} uses;
} pco_fs_data;

View file

@ -2921,6 +2921,12 @@ static inline bool pco_should_skip_pass(const char *pass)
/** Integer one. */
#define pco_one pco_ref_hwreg(1, PCO_REG_CLASS_CONST)
/** Integer 2. */
#define pco_2 pco_ref_hwreg(2, PCO_REG_CLASS_CONST)
/** Integer 5. */
#define pco_5 pco_ref_hwreg(5, PCO_REG_CLASS_CONST)
/** Integer 31. */
#define pco_31 pco_ref_hwreg(31, PCO_REG_CLASS_CONST)

View file

@ -1424,6 +1424,21 @@ encode_map(O_ALPHATST,
op_ref_maps=[('backend', [['p0', '_']], ['drc', 's0', 's1', 's2'])]
)
encode_map(O_ALPHAF,
encodings=[
(I_VISTEST_ATST, [
('pwen', ('!pco_ref_is_null', DEST(0))),
('ifb', False)
])
],
op_ref_maps=[('backend', [['p0', '_']], ['drc', 's0', 's1', 's2'])]
)
encode_map(O_DEPTHF,
encodings=[(I_VISTEST_DEPTHF, [])],
op_ref_maps=[('backend', [], ['drc', 'w0'])]
)
encode_map(O_BBYP0BM,
encodings=[
(I_PHASE0_SRC, [
@ -2814,6 +2829,44 @@ group_map(O_ALPHATST,
]
)
group_map(O_ALPHAF,
hdr=(I_IGRP_HDR_MAIN, [
('oporg', 'be'),
('olchk', OM_OLCHK),
('w1p', False),
('w0p', False),
('cc', OM_EXEC_CND),
('end', OM_END),
('atom', OM_ATOM),
('rpt', 1)
]),
enc_ops=[('backend', O_ALPHAF)],
srcs=[
('s[0]', ('backend', SRC(1)), 's0'),
('s[1]', ('backend', SRC(2)), 's1'),
('s[2]', ('backend', SRC(3)), 's2'),
]
)
group_map(O_DEPTHF,
hdr=(I_IGRP_HDR_MAIN, [
('oporg', 'be'),
('olchk', OM_OLCHK),
('w1p', False),
('w0p', False),
('cc', OM_EXEC_CND),
('end', OM_END),
('atom', OM_ATOM),
('rpt', 1)
]),
enc_ops=[('backend', O_DEPTHF)],
srcs=[('s[0]', ('backend', SRC(1)), 'w0')],
iss=[
('is[0]', 's0'),
('is[4]', 'fte')
]
)
group_map(O_MOVI32,
hdr=(I_IGRP_HDR_BITWISE, [
('opcnt', 'p0'),

View file

@ -720,6 +720,11 @@ void pco_lower_nir(pco_ctx *ctx, nir_shader *nir, pco_data *data)
NIR_PASS(_, nir, nir_lower_blend, &data->fs.blend_opts);
nir->info.fs.uses_sample_shading = backup;
nir_opt_peephole_select_options peep_opts = {
.limit = 0,
.discard_ok = true,
};
NIR_PASS(_, nir, nir_opt_peephole_select, &peep_opts);
NIR_PASS(_, nir, pco_nir_pfo, &data->fs);
} else if (nir->info.stage == MESA_SHADER_VERTEX) {
NIR_PASS(_,

View file

@ -29,6 +29,15 @@
struct pfo_state {
struct util_dynarray loads; /** List of fragment loads. */
struct util_dynarray stores; /** List of fragment stores. */
/* Src for depth feedback (NULL if unused). */
nir_def *depth_feedback_src;
nir_def *discard_cond_reg;
bool has_discards;
/* nir_instr *terminate; */
pco_fs_data *fs; /** Fragment-specific data. */
};
@ -858,6 +867,8 @@ static bool is_pfo(const nir_instr *instr, UNUSED const void *cb_data)
switch (intr->intrinsic) {
case nir_intrinsic_store_output:
case nir_intrinsic_load_output:
case nir_intrinsic_terminate:
case nir_intrinsic_terminate_if:
return true;
default:
@ -881,12 +892,37 @@ static nir_def *lower_pfo(nir_builder *b, nir_instr *instr, void *cb_data)
nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr);
switch (intr->intrinsic) {
case nir_intrinsic_store_output:
return lower_pfo_store(b, intr, state);
case nir_intrinsic_store_output: {
nir_io_semantics sem = nir_intrinsic_io_semantics(intr);
if (sem.location >= FRAG_RESULT_DATA0)
return lower_pfo_store(b, intr, state);
if (sem.location == FRAG_RESULT_DEPTH) {
assert(!state->depth_feedback_src);
state->depth_feedback_src = nir_mov(b, intr->src[0].ssa);
return NIR_LOWER_INSTR_PROGRESS_REPLACE;
}
UNREACHABLE("");
}
case nir_intrinsic_load_output:
return lower_pfo_load(b, intr, state);
case nir_intrinsic_terminate:
state->has_discards = true;
nir_store_reg(b, nir_imm_true(b), state->discard_cond_reg);
return NIR_LOWER_INSTR_PROGRESS_REPLACE;
case nir_intrinsic_terminate_if: {
state->has_discards = true;
nir_def *val = nir_load_reg(b, state->discard_cond_reg);
val = nir_ior(b, val, intr->src[0].ssa);
nir_store_reg(b, val, state->discard_cond_reg);
return NIR_LOWER_INSTR_PROGRESS_REPLACE;
}
default:
break;
}
@ -894,6 +930,34 @@ static nir_def *lower_pfo(nir_builder *b, nir_instr *instr, void *cb_data)
return false;
}
static bool lower_isp_fb(nir_builder *b, struct pfo_state *state)
{
bool has_depth_feedback = !!state->depth_feedback_src;
assert(!(has_depth_feedback && state->has_discards));
/* Insert isp feedback instruction before the first store,
* or if there are no stores, at the end.
*/
if (state->stores.size > 0)
b->cursor = nir_before_instr(
&(*(nir_intrinsic_instr **)util_dynarray_begin(&state->stores))->instr);
else
b->cursor = nir_after_block(
nir_impl_last_block(nir_shader_get_entrypoint(b->shader)));
if (has_depth_feedback) {
nir_depthf_pco(b, state->depth_feedback_src);
state->fs->uses.depth_feedback = true;
} else if (state->has_discards) {
nir_def *val = nir_load_reg(b, state->discard_cond_reg);
nir_terminate_if(b, val);
state->fs->uses.discard = true;
}
return true;
}
static bool sink_outputs(nir_shader *shader, struct pfo_state *state)
{
bool progress = false;
@ -922,13 +986,24 @@ bool pco_nir_pfo(nir_shader *shader, pco_fs_data *fs)
{
assert(shader->info.stage == MESA_SHADER_FRAGMENT);
struct pfo_state state = { .fs = fs };
nir_builder b = nir_builder_create(nir_shader_get_entrypoint(shader));
b.cursor =
nir_before_block(nir_start_block(nir_shader_get_entrypoint(shader)));
struct pfo_state state = {
.fs = fs,
.discard_cond_reg = nir_decl_reg(&b, 1, 1, 0),
};
nir_store_reg(&b, nir_imm_false(&b), state.discard_cond_reg);
util_dynarray_init(&state.loads, NULL);
util_dynarray_init(&state.stores, NULL);
bool progress =
nir_shader_lower_instructions(shader, is_pfo, lower_pfo, &state);
progress |= lower_isp_fb(&b, &state);
progress |= sink_outputs(shader, &state);
util_dynarray_fini(&state.stores);

View file

@ -390,6 +390,9 @@ O_SMP = hw_op('smp', OM_ALU_RPT1 + [OM_DIM, OM_PROJ, OM_FCNORM, OM_NNCOORDS,
O_ALPHATST = hw_op('alphatst', OM_ALU_RPT1, 1, 4)
O_ALPHAF = hw_op('alphaf', OM_ALU_RPT1, 1, 4)
O_DEPTHF = hw_op('depthf', OM_ALU_RPT1, 0, 2)
## Bitwise.
O_MOVI32 = hw_op('movi32', OM_ALU, 1, 1)

View file

@ -1300,6 +1300,28 @@ static pco_instr *trans_intr(trans_ctx *tctx, nir_intrinsic_instr *intr)
instr = lower_alphatst(tctx, dest, src[0], src[1], src[2]);
break;
case nir_intrinsic_depthf_pco:
instr = pco_depthf(&tctx->b, pco_ref_drc(PCO_DRC_0), src[0]);
break;
case nir_intrinsic_terminate:
instr = pco_alphaf(&tctx->b,
pco_ref_null(),
pco_ref_drc(PCO_DRC_0),
pco_zero,
pco_zero,
pco_zero);
break;
case nir_intrinsic_terminate_if:
instr = pco_alphaf(&tctx->b,
pco_ref_null(),
pco_ref_drc(PCO_DRC_0),
pco_zero,
src[0],
pco_2);
break;
case nir_intrinsic_mutex_pco:
instr = pco_mutex(&tctx->b,
pco_ref_imm8(nir_intrinsic_mutex_id_pco(intr)),

View file

@ -1223,7 +1223,12 @@ static void pvr_fragment_state_save(struct pvr_graphics_pipeline *gfx_pipeline,
memcpy(&gfx_pipeline->fs_data, shader_data, sizeof(*shader_data));
/* TODO: add selection for other values of pass type and sample rate. */
if (shader_data->fs.uses.fbfetch)
if (shader_data->fs.uses.depth_feedback)
fragment_state->pass_type = ROGUE_TA_PASSTYPE_DEPTH_FEEDBACK;
else if (shader_data->fs.uses.discard)
fragment_state->pass_type = ROGUE_TA_PASSTYPE_PUNCH_THROUGH;
else if (shader_data->fs.uses.fbfetch)
fragment_state->pass_type = ROGUE_TA_PASSTYPE_TRANSLUCENT;
else
fragment_state->pass_type = ROGUE_TA_PASSTYPE_OPAQUE;