.lds_bytes_if_culling_off = lds_bytes_if_culling_off,
.can_cull = can_cull,
.passthrough = passthrough,
+ .early_prim_export = state.early_prim_export,
.nggc_inputs_read_by_pos = state.inputs_needed_by_pos,
.nggc_inputs_read_by_others = state.inputs_needed_by_others,
};
int16_t last_SMEM_stall;
int last_SMEM_dep_idx;
MoveState mv;
+ bool schedule_pos_exports = true;
+ unsigned schedule_pos_export_div = 1;
};
/* This scheduler is a simple bottom-up pass based on ideas from
Instruction* current, int idx)
{
assert(idx != 0);
- int window_size = POS_EXP_WINDOW_SIZE;
- int max_moves = POS_EXP_MAX_MOVES;
+ int window_size = POS_EXP_WINDOW_SIZE / ctx.schedule_pos_export_div;
+ int max_moves = POS_EXP_MAX_MOVES / ctx.schedule_pos_export_div;
int16_t k = 0;
DownwardsCursor cursor = ctx.mv.downwards_init(idx, true, false);
for (unsigned idx = 0; idx < block->instructions.size(); idx++) {
Instruction* current = block->instructions[idx].get();
- if (block->kind & block_kind_export_end && current->isEXP()) {
+ if (block->kind & block_kind_export_end && current->isEXP() && ctx.schedule_pos_exports) {
unsigned target = current->exp().dest;
if (target >= V_008DFC_SQ_EXP_POS && target < V_008DFC_SQ_EXP_PRIM) {
ctx.mv.current = current;
ctx.mv.max_registers = {int16_t(get_addr_vgpr_from_waves(program, ctx.num_waves * wave_fac) - 2),
int16_t(get_addr_sgpr_from_waves(program, ctx.num_waves * wave_fac))};
+ /* NGG culling shaders are very sensitive to position export scheduling.
+ * Schedule less aggressively when early primitive export is used, and
+ * keep the position export at the very bottom when late primitive export is used.
+ */
+ if (program->info->has_ngg_culling && program->stage.num_sw_stages() == 1) {
+ if (!program->info->has_ngg_early_prim_export)
+ ctx.schedule_pos_exports = false;
+ else
+ ctx.schedule_pos_export_div = 4;
+ }
+
for (Block& block : program->blocks)
schedule_block(ctx, program, &block, live_vars);
key->vs.provoking_vtx_last);
info->has_ngg_culling = out_conf.can_cull;
+ info->has_ngg_early_prim_export = out_conf.early_prim_export;
info->num_lds_blocks_when_not_culling = DIV_ROUND_UP(out_conf.lds_bytes_if_culling_off, device->physical_device->rad_info.lds_encode_granularity);
info->is_ngg_passthrough = out_conf.passthrough;
key->vs_common_out.as_ngg_passthrough = out_conf.passthrough;