llvmpipe: implement alpha-to-coverage dithering

Reviewed-by: Konstantin Seurer <konstantin.seurer@gmail.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/31373>
This commit is contained in:
Aleksi Sapon 2024-09-25 14:49:05 -04:00 committed by Marge Bot
parent 6d6d5b869c
commit ad4635d6ef
3 changed files with 48 additions and 2 deletions

View file

@ -329,7 +329,7 @@ lp_build_alpha_to_coverage(struct gallivm_state *gallivm,
lp_build_context_init(&bld, gallivm, type);
alpha_ref_value = lp_build_const_vec(gallivm, type, 0.5);
alpha_ref_value = lp_build_const_vec(gallivm, type, 0);
test = lp_build_cmp(&bld, PIPE_FUNC_GREATER, alpha, alpha_ref_value);

View file

@ -390,6 +390,8 @@ llvmpipe_get_param(struct pipe_screen *screen, enum pipe_cap param)
return LLVM_VERSION_MAJOR >= 15;
case PIPE_CAP_NIR_IMAGES_AS_DEREF:
return 0;
case PIPE_CAP_ALPHA_TO_COVERAGE_DITHER_CONTROL:
return 1;
default:
return u_pipe_screen_get_param_defaults(screen, param);
}

View file

@ -403,6 +403,45 @@ lp_build_depth_clamp(struct gallivm_state *gallivm,
}
static LLVMValueRef
lp_build_alpha_to_coverage_dither(struct gallivm_state *gallivm,
struct lp_type type,
unsigned coverage_samples,
const LLVMValueRef* pos,
LLVMValueRef alpha)
{
LLVMBuilderRef builder = gallivm->builder;
/* Standard ordered dithering 2x2 threshold matrix. */
LLVMValueRef elems[] = {
lp_build_const_elem(gallivm, type, 0.125 / coverage_samples),
lp_build_const_elem(gallivm, type, 0.625 / coverage_samples),
lp_build_const_elem(gallivm, type, 0.875 / coverage_samples),
lp_build_const_elem(gallivm, type, 0.375 / coverage_samples),
};
LLVMValueRef dither_thresholds = LLVMConstVector(elems, ARRAY_SIZE(elems));
/* Get a two bit mask, where each bit is even/odd on X and Y. */
LLVMTypeRef int_vec_type = lp_build_int_vec_type(gallivm, type);
LLVMValueRef frag_int_pos_x = LLVMBuildFPToSI(builder, pos[0], int_vec_type, "frag_int_pos_x");
LLVMValueRef frag_int_pos_y = LLVMBuildFPToSI(builder, pos[1], int_vec_type, "frag_int_pos_y");
LLVMValueRef odd_bitmask = lp_build_const_int_vec(gallivm, type, 1);
LLVMValueRef dither_index = LLVMBuildOr(builder, LLVMBuildAnd(builder, frag_int_pos_x, odd_bitmask, ""),
LLVMBuildShl(builder, LLVMBuildAnd(builder, frag_int_pos_y, odd_bitmask, ""),
lp_build_const_int_vec(gallivm, type, 1), ""), "dither_index");
/* Use the bit mask as an index in the threshold matrix, subtract it from the alpha value. */
LLVMValueRef offsets = LLVMGetUndef(lp_build_vec_type(gallivm, type));
for (unsigned i = 0; i < type.length; i++) {
LLVMValueRef index = lp_build_const_int32(gallivm, i);
offsets = LLVMBuildInsertElement(builder, offsets,
LLVMBuildExtractElement(builder, dither_thresholds,
LLVMBuildExtractElement(builder, dither_index,
index, "threshold"),
""), index, "");
}
/* Alpha value is only used in a comparison, no need to clamp to [0, 1]. */
return LLVMBuildFSub(builder, alpha, offsets, "");
}
static void
lp_build_sample_alpha_to_coverage(struct gallivm_state *gallivm,
struct lp_type type,
@ -1100,13 +1139,18 @@ generate_fs_loop(struct gallivm_state *gallivm,
}
}
/* Emulate Alpha to Coverage with Alpha test */
/* Alpha to coverage */
if (key->blend.alpha_to_coverage) {
int color0 = find_output_by_frag_result(nir, FRAG_RESULT_DATA0);
if (color0 != -1 && outputs[color0][3]) {
LLVMValueRef alpha = LLVMBuildLoad2(builder, vec_type, outputs[color0][3], "alpha");
if (key->blend.alpha_to_coverage_dither) {
alpha = lp_build_alpha_to_coverage_dither(gallivm, type, key->coverage_samples,
interp->pos, alpha);
}
if (!key->multisample) {
lp_build_alpha_to_coverage(gallivm, type,
&mask, alpha,