gpu: fix separate alpha blending on swizzled render targets

Co-authored-by: Çağatay Güçlü <33038942+defektu@users.noreply.github.com>
This commit is contained in:
nmzik
2026-10-04 21:46:38 +04:00
parent 45fab265d5
commit 0bef3fc0d3
11 changed files with 246 additions and 83 deletions
@@ -39,6 +39,16 @@ namespace Libs::Graphics {
namespace {
uint8_t RemapSourceAlphaFactor(uint8_t factor) {
switch (static_cast<Prospero::BlendFactor>(factor)) {
case Prospero::BlendFactor::kSrcAlpha:
return static_cast<uint8_t>(Prospero::BlendFactor::kSrc1Alpha);
case Prospero::BlendFactor::kOneMinusSrcAlpha:
return static_cast<uint8_t>(Prospero::BlendFactor::kOneMinusSrc1Alpha);
default: return factor;
}
}
vk::PolygonMode ResolvePolygonMode(const HW::ModeControl& mode, bool cull_front, bool cull_back) {
// CxPrimitiveSetup::PolygonMode disables both per-face modes when it is zero.
if (mode.poly_mode == 0) {
@@ -619,14 +629,21 @@ PipelineCache::GraphicsPrograms PipelineCache::GetGraphicsPrograms(
pixel_info.target_output_mode[0] != 0 && pixel_info.target_output_mode[0] != 7 &&
std::all_of(std::begin(pixel_info.target_output_mode) + 1,
std::end(pixel_info.target_output_mode),
[](uint8_t mode) { return mode == 0; }) &&
ClassifyBlendMapping(blend, pixel_info.target_export_mapping[0]) ==
BlendMappingSupport::SourceAlpha) {
// Preserve logical alpha when the export mapping moves it.
pixel_info.alpha_blend_source_remap = true;
pixel_info.dual_source_blending = true;
pixel_info.target_output_mode[1] = pixel_info.target_output_mode[0];
pixel_info.target_export_mapping[1] = {};
[](uint8_t mode) { return mode == 0; })) {
switch (ClassifyBlendMapping(blend, pixel_info.target_export_mapping[0])) {
case BlendMappingSupport::SourceAlpha:
pixel_info.alpha_blend_source = ShaderAlphaBlendSource::SourceAlpha;
break;
case BlendMappingSupport::SourceAlphaOne:
pixel_info.alpha_blend_source = ShaderAlphaBlendSource::SourceAlphaOne;
break;
default: break;
}
if (pixel_info.alpha_blend_source != ShaderAlphaBlendSource::None) {
pixel_info.dual_source_blending = true;
pixel_info.target_output_mode[1] = pixel_info.target_output_mode[0];
pixel_info.target_export_mapping[1] = {};
}
}
}
if (context.GetClipControl().clip_disable) {
@@ -729,10 +746,12 @@ PipelineCache::Pipeline& PipelineCache::GetGraphicsPipeline(
}
const auto& rt = ctx.GetRenderTarget(colors[i].target_slot);
const auto& bc = ctx.GetBlendControl(colors[i].target_slot);
const bool alpha_remap =
slot == 0 && ps_input_info != nullptr && ps_input_info->alpha_blend_source_remap;
auto alpha_source = ShaderAlphaBlendSource::None;
if (slot == 0 && ps_input_info != nullptr) {
alpha_source = ps_input_info->alpha_blend_source;
}
static_params.blend_enable[slot] = bc.enable && !rt.info.blend_bypass;
if (static_params.blend_enable[slot] && !alpha_remap &&
if (static_params.blend_enable[slot] && alpha_source == ShaderAlphaBlendSource::None &&
ClassifyBlendMapping(bc, colors[i].export_mapping) != BlendMappingSupport::Direct) {
static_params.blend_enable[slot] = false;
static std::atomic_bool warned = false;
@@ -744,18 +763,34 @@ PipelineCache::Pipeline& PipelineCache::GetGraphicsPipeline(
bc.alpha_srcblend, bc.alpha_destblend, bc.separate_alpha_blend ? 1 : 0));
}
}
if (alpha_remap) {
static_params.blend_alpha_source_remap = true;
}
if (static_params.blend_enable[slot]) {
static_params.color_srcblend[slot] = bc.color_srcblend;
static_params.color_comb_fcn[slot] = bc.color_comb_fcn;
static_params.color_destblend[slot] = bc.color_destblend;
static_params.separate_alpha_blend[slot] = bc.separate_alpha_blend;
if (bc.separate_alpha_blend) {
static_params.alpha_srcblend[slot] = bc.alpha_srcblend;
static_params.alpha_comb_fcn[slot] = bc.alpha_comb_fcn;
static_params.alpha_destblend[slot] = bc.alpha_destblend;
auto blend = bc;
switch (alpha_source) {
case ShaderAlphaBlendSource::SourceAlpha:
blend.color_srcblend = RemapSourceAlphaFactor(blend.color_srcblend);
blend.color_destblend = RemapSourceAlphaFactor(blend.color_destblend);
if (blend.separate_alpha_blend) {
blend.alpha_srcblend = RemapSourceAlphaFactor(blend.alpha_srcblend);
blend.alpha_destblend = RemapSourceAlphaFactor(blend.alpha_destblend);
}
break;
case ShaderAlphaBlendSource::SourceAlphaOne:
// The second source carries the mapped source factor; its alpha stays logical Sa.
blend.color_srcblend = static_cast<uint8_t>(Prospero::BlendFactor::kSrc1Color);
blend.color_destblend =
static_cast<uint8_t>(Prospero::BlendFactor::kOneMinusSrc1Alpha);
blend.separate_alpha_blend = false;
break;
case ShaderAlphaBlendSource::None: break;
}
static_params.color_srcblend[slot] = blend.color_srcblend;
static_params.color_comb_fcn[slot] = blend.color_comb_fcn;
static_params.color_destblend[slot] = blend.color_destblend;
static_params.separate_alpha_blend[slot] = blend.separate_alpha_blend;
if (blend.separate_alpha_blend) {
static_params.alpha_srcblend[slot] = blend.alpha_srcblend;
static_params.alpha_comb_fcn[slot] = blend.alpha_comb_fcn;
static_params.alpha_destblend[slot] = blend.alpha_destblend;
}
}
}