From ad4635d6ef05ce6c825c4457a5cba1dd645348d4 Mon Sep 17 00:00:00 2001 From: Aleksi Sapon Date: Wed, 25 Sep 2024 14:49:05 -0400 Subject: [PATCH] llvmpipe: implement alpha-to-coverage dithering Reviewed-by: Konstantin Seurer Part-of: --- src/gallium/drivers/llvmpipe/lp_bld_blend.c | 2 +- src/gallium/drivers/llvmpipe/lp_screen.c | 2 + src/gallium/drivers/llvmpipe/lp_state_fs.c | 46 ++++++++++++++++++++- 3 files changed, 48 insertions(+), 2 deletions(-) diff --git a/src/gallium/drivers/llvmpipe/lp_bld_blend.c b/src/gallium/drivers/llvmpipe/lp_bld_blend.c index 3481721a571..e59c18c4725 100644 --- a/src/gallium/drivers/llvmpipe/lp_bld_blend.c +++ b/src/gallium/drivers/llvmpipe/lp_bld_blend.c @@ -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); diff --git a/src/gallium/drivers/llvmpipe/lp_screen.c b/src/gallium/drivers/llvmpipe/lp_screen.c index 458279d0c02..8486de93ca1 100644 --- a/src/gallium/drivers/llvmpipe/lp_screen.c +++ b/src/gallium/drivers/llvmpipe/lp_screen.c @@ -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); } diff --git a/src/gallium/drivers/llvmpipe/lp_state_fs.c b/src/gallium/drivers/llvmpipe/lp_state_fs.c index 9013a7ff115..ac2cd933cf3 100644 --- a/src/gallium/drivers/llvmpipe/lp_state_fs.c +++ b/src/gallium/drivers/llvmpipe/lp_state_fs.c @@ -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,