r600: fix alpha-to-coverage and alpha-to-one used together

This change is inspired by b56f47611a ("radeonsi: fix
alpha-to-coverage + alpha-to-one used together for
gfx6-10.3") and implements the same algorithm.

This change was tested on rv770, palm and cayman. Here are the tests fixed:
spec/arb_framebuffer_object/execution/msaa-alpha-to-coverage_alpha-to-one: fail pass
spec/arb_framebuffer_object/execution/msaa-alpha-to-coverage_alpha-to-one_write-z: fail pass

Cc: mesa-stable
Signed-off-by: Patrick Lerda <patrick9876@free.fr>
(cherry picked from commit 7513f48edf)

Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/41269>
This commit is contained in:
Patrick Lerda 2026-02-09 13:01:16 +01:00 committed by Eric Engestrom
parent ca1923a820
commit 5ec6772843
9 changed files with 59 additions and 5 deletions

View file

@ -4394,7 +4394,7 @@
"description": "r600: fix alpha-to-coverage and alpha-to-one used together",
"nominated": true,
"nomination_type": 1,
"resolution": 0,
"resolution": 1,
"main_sha": null,
"because_sha": null,
"notes": null

View file

@ -362,6 +362,7 @@ static void *evergreen_create_blend_state_mode(struct pipe_context *ctx,
blend->dual_src_blend = util_blend_state_is_dual(state, 0);
blend->cb_target_mask = target_mask;
blend->alpha_to_one = state->alpha_to_one;
blend->alpha_to_one_and_coverage = state->alpha_to_one && state->alpha_to_coverage;
if (target_mask)
color_control |= S_028808_MODE(mode);
@ -3837,6 +3838,10 @@ void evergreen_update_ps_state(struct pipe_context *ctx, struct r600_pipe_shader
break;
}
}
if (unlikely(rctx->alpha_to_one_and_coverage))
exports_ps |= 1;
if (rshader->uses_kill)
db_shader_control |= S_02880C_KILL_ENABLE(1);
@ -4137,14 +4142,17 @@ void evergreen_update_db_shader_control(struct r600_context * rctx)
return;
}
const bool alpha_to_one_and_coverage = rctx->ps_shader->current->key.ps.alpha_to_one_and_coverage;
dual_export = rctx->cb_state.export_16bpc &&
!rctx->ps_shader->current->ps_depth_export;
!rctx->ps_shader->current->ps_depth_export &&
!alpha_to_one_and_coverage;
db_shader_control = rctx->ps_shader->current->db_shader_control |
S_02880C_DUAL_EXPORT_ENABLE(dual_export) |
S_02880C_DB_SOURCE_FORMAT(dual_export ? V_02880C_EXPORT_DB_TWO :
V_02880C_EXPORT_DB_FULL) |
S_02880C_ALPHA_TO_MASK_DISABLE(rctx->cb_state.cb0_is_integer);
S_02880C_ALPHA_TO_MASK_DISABLE(rctx->cb_state.cb0_is_integer) |
S_02880C_COVERAGE_TO_MASK_ENABLE(alpha_to_one_and_coverage);
/* When alpha test is enabled we can't trust the hw to make the proper
* decision on the order in which ztest should be run related to fragment

View file

@ -964,6 +964,9 @@
#define S_02880C_KILL_ENABLE(x) (((unsigned)(x) & 0x1) << 6)
#define G_02880C_KILL_ENABLE(x) (((x) >> 6) & 0x1)
#define C_02880C_KILL_ENABLE 0xFFFFFFBF
#define S_02880C_COVERAGE_TO_MASK_ENABLE(x) (((unsigned)(x) & 0x1) << 7)
#define G_02880C_COVERAGE_TO_MASK_ENABLE(x) (((x) >> 7) & 0x1)
#define C_02880C_COVERAGE_TO_MASK_ENABLE 0xFFFFFF7F
#define S_02880C_MASK_EXPORT_ENABLE(x) (((unsigned)(x) & 0x1) << 8)
#define G_02880C_MASK_EXPORT_ENABLE(x) (((x) >> 8) & 0x1)
#define C_02880C_MASK_EXPORT_ENABLE 0XFFFFFEFF

View file

@ -301,6 +301,7 @@ struct r600_blend_state {
unsigned cb_color_control_no_blend;
bool dual_src_blend;
bool alpha_to_one;
bool alpha_to_one_and_coverage;
};
struct r600_dsa_state {
@ -582,6 +583,7 @@ struct r600_context {
struct r600_rasterizer_state *rasterizer;
bool alpha_to_one;
bool alpha_to_one_and_coverage;
bool force_blend_disable;
bool gs_tri_strip_adj_fix;
bool dual_src_blend;

View file

@ -126,6 +126,7 @@ union r600_shader_key {
unsigned image_size_const_offset:5;
unsigned color_two_side:1;
unsigned alpha_to_one:1;
unsigned alpha_to_one_and_coverage:1;
unsigned apply_sample_id_mask:1;
unsigned dual_source_blend:1;
} ps;

View file

@ -356,6 +356,7 @@ static void *r600_create_blend_state_mode(struct pipe_context *ctx,
blend->cb_color_control = color_control;
blend->cb_color_control_no_blend = color_control & C_028808_TARGET_BLEND_ENABLE;
blend->alpha_to_one = state->alpha_to_one;
blend->alpha_to_one_and_coverage = state->alpha_to_one && state->alpha_to_coverage;
r600_store_context_reg(&blend->buffer, R_028D44_DB_ALPHA_TO_MASK,
S_028D44_ALPHA_TO_MASK_ENABLE(state->alpha_to_coverage) |
@ -2530,6 +2531,10 @@ void r600_update_ps_state(struct pipe_context *ctx, struct r600_pipe_shader *sha
break;
}
}
if (unlikely(rctx->alpha_to_one_and_coverage))
exports_ps |= 1;
db_shader_control |= S_02880C_Z_EXPORT_ENABLE(z_export);
db_shader_control |= S_02880C_STENCIL_REF_EXPORT_ENABLE(stencil_export);
db_shader_control |= S_02880C_MASK_EXPORT_ENABLE(mask_export);
@ -2813,11 +2818,14 @@ void r600_update_db_shader_control(struct r600_context * rctx)
return;
}
const bool alpha_to_one_and_coverage = rctx->ps_shader->current->key.ps.alpha_to_one_and_coverage;
dual_export = rctx->cb_state.export_16bpc &&
!rctx->ps_shader->current->ps_depth_export;
!rctx->ps_shader->current->ps_depth_export &&
!alpha_to_one_and_coverage;
db_shader_control = rctx->ps_shader->current->db_shader_control |
S_02880C_DUAL_EXPORT_ENABLE(dual_export);
S_02880C_DUAL_EXPORT_ENABLE(dual_export) |
S_02880C_COVERAGE_TO_MASK_ENABLE(alpha_to_one_and_coverage);
ps_conservative_z = rctx->ps_shader->current->shader.ps_conservative_z;

View file

@ -174,6 +174,7 @@ static void r600_bind_blend_state_internal(struct r600_context *rctx,
bool update_cb = false;
rctx->alpha_to_one = blend->alpha_to_one;
rctx->alpha_to_one_and_coverage = blend->alpha_to_one_and_coverage;
rctx->dual_src_blend = blend->dual_src_blend;
if (!blend_disable) {
@ -823,6 +824,7 @@ static inline void r600_shader_selector_key(const struct pipe_context *ctx,
key->ps.alpha_to_one = rctx->alpha_to_one &&
rctx->rasterizer && rctx->rasterizer->multisample_enable &&
!rctx->cb_state.cb0_is_integer;
key->ps.alpha_to_one_and_coverage = key->ps.alpha_to_one && rctx->alpha_to_one_and_coverage;
key->ps.nr_cbufs = rctx->framebuffer.state.nr_cbufs;
key->ps.apply_sample_id_mask = (rctx->ps_iter_samples > 1) || !rctx->rasterizer->multisample_enable;
/* Dual-source blending only makes sense with nr_cbufs == 1. */

View file

@ -850,6 +850,9 @@
#define S_02880C_KILL_ENABLE(x) (((unsigned)(x) & 0x1) << 6)
#define G_02880C_KILL_ENABLE(x) (((x) >> 6) & 0x1)
#define C_02880C_KILL_ENABLE 0xFFFFFFBF
#define S_02880C_COVERAGE_TO_MASK_ENABLE(x) (((unsigned)(x) & 0x1) << 7)
#define G_02880C_COVERAGE_TO_MASK_ENABLE(x) (((x) >> 7) & 0x1)
#define C_02880C_COVERAGE_TO_MASK_ENABLE 0xFFFFFF7F
#define S_02880C_MASK_EXPORT_ENABLE(x) (((unsigned)(x) & 0x1) << 8)
#define G_02880C_MASK_EXPORT_ENABLE(x) (((x) >> 8) & 0x1)
#define C_02880C_MASK_EXPORT_ENABLE 0xFFFFFEFF

View file

@ -87,6 +87,7 @@ public:
ConditionalJumpTracker m_jump_tracker;
CallStack m_callstack;
bool ps_alpha_to_one;
bool ps_alpha_to_one_and_coverage;
/* End initialized in constructor */
std::set<uint32_t> m_nliterals_in_group;
@ -132,6 +133,7 @@ AssamblerVisitor::AssamblerVisitor(r600_shader *sh, const r600_shader_key& key,
m_bc(&sh->bc),
m_callstack(sh->bc),
ps_alpha_to_one(key.ps.alpha_to_one),
ps_alpha_to_one_and_coverage(key.ps.alpha_to_one_and_coverage),
m_legacy_math_rules(legacy_math_rules)
{
if (m_shader->processor_type == MESA_SHADER_FRAGMENT)
@ -532,6 +534,31 @@ AssamblerVisitor::visit(const ExportInstr& exi)
{
const auto& value = exi.value();
if (unlikely(ps_alpha_to_one_and_coverage && exi.export_type() == ExportInstr::pixel &&
exi.location() == 0)) {
r600_bytecode_output output;
memset(&output, 0, sizeof(output));
output.gpr = value.sel();
output.elem_size = 3;
output.swizzle_x = 7;
output.swizzle_y = 7;
output.swizzle_z = 7;
output.swizzle_w = value[3]->chan();
output.array_base = 61;
output.burst_count = 1;
output.op = CF_OP_EXPORT;
output.type = exi.export_type();
int r = 0;
if ((r = r600_bytecode_add_output(m_bc, &output))) {
R600_ASM_ERR("Error adding export at location %d : err: %d\n",
output.array_base,
r);
m_result = false;
}
}
r600_bytecode_output output;
memset(&output, 0, sizeof(output));