diff --git a/src/broadcom/compiler/nir_to_vir.c b/src/broadcom/compiler/nir_to_vir.c index 9e7d308745b..dc83c015821 100644 --- a/src/broadcom/compiler/nir_to_vir.c +++ b/src/broadcom/compiler/nir_to_vir.c @@ -932,10 +932,8 @@ ldvary_sequence_inst(struct v3d_compile *c, struct qreg result) return result; } -static struct qreg -emit_smooth_varying(struct v3d_compile *c, - struct qinst *ldvary, - struct qreg vary, struct qreg w, struct qreg r5) +static void +track_ldvary_pipelining(struct v3d_compile *c, struct qinst *ldvary) { if (ldvary) { c->ldvary_sequence_length++; @@ -945,10 +943,38 @@ emit_smooth_varying(struct v3d_compile *c, c->ldvary_sequence_start_inst = ldvary; } } +} + +static struct qreg +emit_smooth_varying(struct v3d_compile *c, + struct qinst *ldvary, + struct qreg vary, struct qreg w, struct qreg r5) +{ + track_ldvary_pipelining(c, ldvary); return ldvary_sequence_inst(c, vir_FADD(c, ldvary_sequence_inst(c, vir_FMUL(c, vary, w)), r5)); } +static struct qreg +emit_noperspective_varying(struct v3d_compile *c, + struct qinst *ldvary, + struct qreg vary, struct qreg r5) +{ + track_ldvary_pipelining(c, ldvary); + return ldvary_sequence_inst(c, vir_FADD(c, + ldvary_sequence_inst(c, vir_MOV(c, vary)), r5)); +} + +static struct qreg +emit_flat_varying(struct v3d_compile *c, + struct qinst *ldvary, + struct qreg vary, struct qreg r5) +{ + track_ldvary_pipelining(c, ldvary); + vir_MOV_dest(c, c->undef, vary); + return ldvary_sequence_inst(c, vir_MOV(c, r5)); +} + static void break_smooth_varying_sequence(struct v3d_compile *c) { @@ -1032,16 +1058,13 @@ emit_fragment_varying(struct v3d_compile *c, nir_variable *var, break; case INTERP_MODE_NOPERSPECTIVE: - break_smooth_varying_sequence(c); BITSET_SET(c->noperspective_flags, i); - result = vir_FADD(c, vir_MOV(c, vary), r5); + result = emit_noperspective_varying(c, ldvary, vary, r5); break; case INTERP_MODE_FLAT: - break_smooth_varying_sequence(c); BITSET_SET(c->flat_shade_flags, i); - vir_MOV_dest(c, c->undef, vary); - result = vir_MOV(c, r5); + result = emit_flat_varying(c, ldvary, vary, r5); break; default: diff --git a/src/broadcom/compiler/qpu_schedule.c b/src/broadcom/compiler/qpu_schedule.c index 571a89fb7be..f4b0d5a86e5 100644 --- a/src/broadcom/compiler/qpu_schedule.c +++ b/src/broadcom/compiler/qpu_schedule.c @@ -1050,10 +1050,27 @@ choose_instruction_to_schedule(const struct v3d_device_info *devinfo, * them, however, if we failed to find anything to schedule then we * can't possibly continue the sequence and we need to stop the * pipelining process and try again. + * + * There is one exception to the above: noperspective or flat + * varyings can cause us to not be able to pick an instruction + * because they need a nop between the ldvary and the next instruction + * to account for the ldvary r5 write latency. We can try to detect this + * by checking if we are also unable to schedule an instruction after + * disabling pipelining. + * + * FIXME: dropping pipelining and picking up another instruction could + * break the sequence for flat/noperspective varyings we could've been + * able to continue if we returned NULL here and scheduled a NOP as a + * result, but detecting this case would require us to know in advance + * that emitting the next NOP will guarantee that we will be able to + * continue the sequence. */ if (scoreboard->ldvary_pipelining && !prev_inst && !chosen) { + bool prev_ldvary_pipelining = scoreboard->ldvary_pipelining; scoreboard->ldvary_pipelining = false; chosen = choose_instruction_to_schedule(devinfo, scoreboard, prev_inst); + if (!chosen) + scoreboard->ldvary_pipelining = prev_ldvary_pipelining; } else if (chosen) { if (scoreboard->ldvary_pipelining) { assert(chosen->inst->ldvary_pipelining);