radv/llvm: implement a workaround for gl_FragCoord.z with VRS on GFX10.3

Without it, FragCoord.z will have the value of one of the fine pixels
instead of the center of the coarse pixel.

It's only enabled for RADV.

Signed-off-by: Samuel Pitoiset <samuel.pitoiset@gmail.com>
Reviewed-by: Bas Nieuwenhuizen <bas@basnieuwenhuizen.nl>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/7837>
This commit is contained in:
Samuel Pitoiset 2020-12-11 08:46:19 +01:00 committed by Marge Bot
parent 7a464f4296
commit 45524afe95
4 changed files with 40 additions and 7 deletions

View file

@ -3328,6 +3328,37 @@ emit_load_frag_shading_rate(struct ac_nir_context *ctx)
return LLVMBuildOr(ctx->ac.builder, x_rate, y_rate, "");
}
static LLVMValueRef
emit_load_frag_coord(struct ac_nir_context *ctx)
{
LLVMValueRef values[4] = {
ac_get_arg(&ctx->ac, ctx->args->frag_pos[0]), ac_get_arg(&ctx->ac, ctx->args->frag_pos[1]),
ac_get_arg(&ctx->ac, ctx->args->frag_pos[2]),
ac_build_fdiv(&ctx->ac, ctx->ac.f32_1, ac_get_arg(&ctx->ac, ctx->args->frag_pos[3]))};
if (ctx->abi->adjust_frag_coord_z) {
/* Adjust gl_FragCoord.z for VRS due to a hw bug on some GFX10.3 chips. */
LLVMValueRef frag_z = values[2];
/* dFdx fine */
LLVMValueRef adjusted_frag_z = emit_ddxy(ctx, nir_op_fddx_fine, frag_z);
/* adjusted_frag_z * 0.0625 + frag_z */
adjusted_frag_z = LLVMBuildFAdd(ctx->ac.builder, frag_z,
LLVMBuildFMul(ctx->ac.builder, adjusted_frag_z,
LLVMConstReal(ctx->ac.f32, 0.0625), ""), "");
/* VRS Rate X = Ancillary[2:3] */
LLVMValueRef x_rate = ac_unpack_param(&ctx->ac, ac_get_arg(&ctx->ac, ctx->args->ancillary), 2, 2);
/* xRate = xRate == 0x1 ? adjusted_frag_z : frag_z. */
LLVMValueRef cond = LLVMBuildICmp(ctx->ac.builder, LLVMIntEQ, x_rate, ctx->ac.i32_1, "");
values[2] = LLVMBuildSelect(ctx->ac.builder, cond, adjusted_frag_z, frag_z, "");
}
return ac_to_integer(&ctx->ac, ac_build_gather_values(&ctx->ac, values, 4));
}
static void visit_intrinsic(struct ac_nir_context *ctx, nir_intrinsic_instr *instr)
{
LLVMValueRef result = NULL;
@ -3421,14 +3452,9 @@ static void visit_intrinsic(struct ac_nir_context *ctx, nir_intrinsic_instr *ins
case nir_intrinsic_load_sample_mask_in:
result = ctx->abi->load_sample_mask_in(ctx->abi);
break;
case nir_intrinsic_load_frag_coord: {
LLVMValueRef values[4] = {
ac_get_arg(&ctx->ac, ctx->args->frag_pos[0]), ac_get_arg(&ctx->ac, ctx->args->frag_pos[1]),
ac_get_arg(&ctx->ac, ctx->args->frag_pos[2]),
ac_build_fdiv(&ctx->ac, ctx->ac.f32_1, ac_get_arg(&ctx->ac, ctx->args->frag_pos[3]))};
result = ac_to_integer(&ctx->ac, ac_build_gather_values(&ctx->ac, values, 4));
case nir_intrinsic_load_frag_coord:
result = emit_load_frag_coord(ctx);
break;
}
case nir_intrinsic_load_frag_shading_rate:
result = emit_load_frag_shading_rate(ctx);
break;

View file

@ -165,6 +165,11 @@ struct ac_shader_abi {
/* Clamp div by 0 (so it won't produce NaN) */
bool clamp_div_by_zero;
/* Whether gl_FragCoord.z should be adjusted for VRS due to a hw bug on
* some GFX10.3 chips.
*/
bool adjust_frag_coord_z;
};
#endif /* AC_SHADER_ABI_H */

View file

@ -3896,6 +3896,7 @@ LLVMModuleRef ac_translate_nir_to_llvm(struct ac_llvm_compiler *ac_llvm,
ctx.abi.load_sampler_desc = radv_get_sampler_desc;
ctx.abi.load_resource = radv_load_resource;
ctx.abi.clamp_shadow_reference = false;
ctx.abi.adjust_frag_coord_z = args->options->adjust_frag_coord_z;
ctx.abi.robust_buffer_access = args->options->robust_buffer_access;
bool is_ngg = is_pre_gs_stage(shaders[0]->info.stage) && args->options->key.vs_common_out.as_ngg;

View file

@ -487,6 +487,7 @@ static bool si_nir_build_llvm(struct si_shader_context *ctx, struct nir_shader *
ctx->abi.robust_buffer_access = true;
ctx->abi.convert_undef_to_zero = true;
ctx->abi.clamp_div_by_zero = ctx->screen->options.clamp_div_by_zero;
ctx->abi.adjust_frag_coord_z = false;
const struct si_shader_info *info = &ctx->shader->selector->info;
for (unsigned i = 0; i < info->num_outputs; i++) {