gpu: fix zero-source alpha blending on swizzled targets

Co-authored-by: Çağatay Güçlü <33038942+defektu@users.noreply.github.com>
This commit is contained in:
nmzik
2026-10-04 23:22:54 +04:00
parent 8274e517b2
commit 94e7d239dd
7 changed files with 35 additions and 10 deletions
@@ -32,12 +32,15 @@ BlendMappingSupport ClassifyBlendMapping(const HW::BlendControl&
} }
if (blend.separate_alpha_blend && if (blend.separate_alpha_blend &&
blend.color_srcblend == static_cast<uint8_t>(Prospero::BlendFactor::kSrcAlpha) && blend.color_srcblend == static_cast<uint8_t>(Prospero::BlendFactor::kSrcAlpha) &&
blend.alpha_srcblend == static_cast<uint8_t>(Prospero::BlendFactor::kOne) &&
blend.color_destblend == static_cast<uint8_t>(Prospero::BlendFactor::kOneMinusSrcAlpha) && blend.color_destblend == static_cast<uint8_t>(Prospero::BlendFactor::kOneMinusSrcAlpha) &&
blend.alpha_destblend == blend.color_destblend && blend.alpha_destblend == blend.color_destblend &&
blend.color_comb_fcn == static_cast<uint8_t>(Prospero::BlendOp::kAdd) && blend.color_comb_fcn == static_cast<uint8_t>(Prospero::BlendOp::kAdd) &&
blend.alpha_comb_fcn == blend.color_comb_fcn) { blend.alpha_comb_fcn == blend.color_comb_fcn) {
return BlendMappingSupport::SourceAlphaOne; switch (static_cast<Prospero::BlendFactor>(blend.alpha_srcblend)) {
case Prospero::BlendFactor::kZero: return BlendMappingSupport::SourceAlphaZero;
case Prospero::BlendFactor::kOne: return BlendMappingSupport::SourceAlphaOne;
default: break;
}
} }
// Moving alpha requires the same equation for all channels. // Moving alpha requires the same equation for all channels.
if (blend.separate_alpha_blend && (blend.alpha_srcblend != blend.color_srcblend || if (blend.separate_alpha_blend && (blend.alpha_srcblend != blend.color_srcblend ||
@@ -16,6 +16,7 @@ enum class BlendMappingSupport {
Direct, Direct,
SourceAlpha, // Requires logical alpha in the second blend source. SourceAlpha, // Requires logical alpha in the second blend source.
SourceAlphaOne, // Source alpha for RGB, one for alpha, with a shared destination equation. SourceAlphaOne, // Source alpha for RGB, one for alpha, with a shared destination equation.
SourceAlphaZero, // Source alpha for RGB, zero for alpha, with a shared destination equation.
Unsupported, Unsupported,
}; };
@@ -640,6 +640,9 @@ PipelineCache::GraphicsPrograms PipelineCache::GetGraphicsPrograms(
case BlendMappingSupport::SourceAlphaOne: case BlendMappingSupport::SourceAlphaOne:
pixel_info.alpha_blend_source = ShaderAlphaBlendSource::SourceAlphaOne; pixel_info.alpha_blend_source = ShaderAlphaBlendSource::SourceAlphaOne;
break; break;
case BlendMappingSupport::SourceAlphaZero:
pixel_info.alpha_blend_source = ShaderAlphaBlendSource::SourceAlphaZero;
break;
default: break; default: break;
} }
if (pixel_info.alpha_blend_source != ShaderAlphaBlendSource::None) { if (pixel_info.alpha_blend_source != ShaderAlphaBlendSource::None) {
@@ -764,6 +767,7 @@ PipelineCache::Pipeline& PipelineCache::GetGraphicsPipeline(
blend.separate_alpha_blend = false; blend.separate_alpha_blend = false;
break; break;
case ShaderAlphaBlendSource::SourceAlphaOne: case ShaderAlphaBlendSource::SourceAlphaOne:
case ShaderAlphaBlendSource::SourceAlphaZero:
// The second source carries the mapped source factor; its alpha stays logical Sa. // 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_srcblend = static_cast<uint8_t>(Prospero::BlendFactor::kSrc1Color);
blend.color_destblend = blend.color_destblend =
@@ -512,14 +512,23 @@ void EmitSetAttribute(ValueEmitContext& ctx, const IR::Inst& inst) {
auto alpha = state.builder.AllocateId(); auto alpha = state.builder.AllocateId();
state.builder.AddFunction(spv::OpVectorShuffle, vector_type, alpha, value, value, state.builder.AddFunction(spv::OpVectorShuffle, vector_type, alpha, value, value,
3u, 3u, 3u, 3u); 3u, 3u, 3u, 3u);
if (state.input_info.pixel->alpha_blend_source == uint32_t alpha_factor = 0;
ShaderAlphaBlendSource::SourceAlphaOne) { switch (state.input_info.pixel->alpha_blend_source) {
case ShaderAlphaBlendSource::SourceAlphaOne:
alpha_factor = ConstantF32Value(state, 1.0f);
break;
case ShaderAlphaBlendSource::SourceAlphaZero:
alpha_factor = ConstantF32Value(state, 0.0f);
break;
default: break;
}
if (alpha_factor != 0) {
const auto mapping = state.input_info.pixel->target_export_mapping[0]; const auto mapping = state.input_info.pixel->target_export_mapping[0];
for (uint32_t component = 0; component < 4; component++) { for (uint32_t component = 0; component < 4; component++) {
if (mapping.Map(component) != 3u) continue; if (mapping.Map(component) != 3u) continue;
const auto factors = state.builder.AllocateId(); const auto factors = state.builder.AllocateId();
state.builder.AddFunction(spv::OpCompositeInsert, vector_type, factors, state.builder.AddFunction(spv::OpCompositeInsert, vector_type, factors,
ConstantF32Value(state, 1.0f), alpha, component); alpha_factor, alpha, component);
alpha = factors; alpha = factors;
break; break;
} }
+1 -1
View File
@@ -158,7 +158,7 @@ struct ShaderComputeInputInfo: ShaderWorkgroupInputInfo {
ShaderStageRuntime stage; ShaderStageRuntime stage;
}; };
enum class ShaderAlphaBlendSource : uint8_t { None, SourceAlpha, SourceAlphaOne }; enum class ShaderAlphaBlendSource : uint8_t { None, SourceAlpha, SourceAlphaOne, SourceAlphaZero };
struct ShaderPixelInputInfo { struct ShaderPixelInputInfo {
uint32_t interpolator_settings[32] = {0}; uint32_t interpolator_settings[32] = {0};
+3 -2
View File
@@ -15830,7 +15830,7 @@ public:
"wave32 and wave64 pixel programs shared a cache key"); "wave32 and wave64 pixel programs shared a cache key");
// Reversed RGBA targets must use logical Sa for RGB, with a separate // Reversed RGBA targets must use logical Sa for RGB, with a separate
// unit source factor when alpha accumulates as Sa + Da * (1 - Sa). // zero or unit source factor for separate alpha attenuation or accumulation.
static const auto blend_pixel = [] { static const auto blend_pixel = [] {
std::vector<u32> code; std::vector<u32> code;
constexpr std::array<float, 4> source{0.8f, 0.6f, 0.4f, 0.5f}; constexpr std::array<float, 4> source{0.8f, 0.6f, 0.4f, 0.5f};
@@ -15871,7 +15871,8 @@ public:
for (const auto test : { for (const auto test : {
AlphaBlendCase{false, Prospero::BlendFactor::kOne, ShaderAlphaBlendSource::SourceAlpha, 0.4f}, AlphaBlendCase{false, Prospero::BlendFactor::kOne, ShaderAlphaBlendSource::SourceAlpha, 0.4f},
AlphaBlendCase{true, Prospero::BlendFactor::kSrcAlpha, ShaderAlphaBlendSource::SourceAlpha, 0.4f}, AlphaBlendCase{true, Prospero::BlendFactor::kSrcAlpha, ShaderAlphaBlendSource::SourceAlpha, 0.4f},
AlphaBlendCase{true, Prospero::BlendFactor::kOne, ShaderAlphaBlendSource::SourceAlphaOne, 0.65f}}) { AlphaBlendCase{true, Prospero::BlendFactor::kOne, ShaderAlphaBlendSource::SourceAlphaOne, 0.65f},
AlphaBlendCase{true, Prospero::BlendFactor::kZero, ShaderAlphaBlendSource::SourceAlphaZero, 0.15f}}) {
alpha_blend.separate_alpha_blend = test.separate; alpha_blend.separate_alpha_blend = test.separate;
alpha_blend.alpha_srcblend = static_cast<uint8_t>(test.alpha_source); alpha_blend.alpha_srcblend = static_cast<uint8_t>(test.alpha_source);
registers.SetBlendControl(0, alpha_blend); registers.SetBlendControl(0, alpha_blend);
+9 -2
View File
@@ -12906,6 +12906,9 @@ void TestBlendMappingClassification() {
static_cast<uint8_t>(Factor::kOneMinusSrcAlpha); static_cast<uint8_t>(Factor::kOneMinusSrcAlpha);
Check(classify(Prospero::ColorMappingAbgr) == Support::SourceAlphaOne, Check(classify(Prospero::ColorMappingAbgr) == Support::SourceAlphaOne,
"separate alpha accumulation did not preserve its unit source factor"); "separate alpha accumulation did not preserve its unit source factor");
blend.alpha_srcblend = static_cast<uint8_t>(Factor::kZero);
Check(classify(Prospero::ColorMappingAbgr) == Support::SourceAlphaZero,
"separate alpha attenuation did not preserve its zero source factor");
blend.alpha_srcblend = blend.color_srcblend; blend.alpha_srcblend = blend.color_srcblend;
Check(classify(Prospero::ColorMappingAbgr) == Support::SourceAlpha, Check(classify(Prospero::ColorMappingAbgr) == Support::SourceAlpha,
"equal separate alpha equations did not reuse the broadcast alpha mode"); "equal separate alpha equations did not reuse the broadcast alpha mode");
@@ -12916,7 +12919,7 @@ void TestBlendMappingClassification() {
switch (changed) { switch (changed) {
case 0: blend.color_srcblend = static_cast<uint8_t>(Factor::kZero); break; case 0: blend.color_srcblend = static_cast<uint8_t>(Factor::kZero); break;
case 1: blend.color_destblend = static_cast<uint8_t>(Factor::kOne); break; case 1: blend.color_destblend = static_cast<uint8_t>(Factor::kOne); break;
case 2: blend.alpha_srcblend = static_cast<uint8_t>(Factor::kZero); break; case 2: blend.alpha_srcblend = static_cast<uint8_t>(Factor::kDstAlpha); break;
case 3: blend.alpha_destblend = static_cast<uint8_t>(Factor::kOne); break; case 3: blend.alpha_destblend = static_cast<uint8_t>(Factor::kOne); break;
case 4: blend.color_comb_fcn = static_cast<uint8_t>(Prospero::BlendOp::kSubtract); break; case 4: blend.color_comb_fcn = static_cast<uint8_t>(Prospero::BlendOp::kSubtract); break;
case 5: blend.alpha_comb_fcn = static_cast<uint8_t>(Prospero::BlendOp::kSubtract); break; case 5: blend.alpha_comb_fcn = static_cast<uint8_t>(Prospero::BlendOp::kSubtract); break;
@@ -12937,9 +12940,13 @@ void TestLogicalAlphaBlendExport() {
const auto remapped_key = MakeStageStaticKey(pixel); const auto remapped_key = MakeStageStaticKey(pixel);
pixel.alpha_blend_source = ShaderAlphaBlendSource::SourceAlphaOne; pixel.alpha_blend_source = ShaderAlphaBlendSource::SourceAlphaOne;
const auto separate_key = MakeStageStaticKey(pixel); const auto separate_key = MakeStageStaticKey(pixel);
pixel.alpha_blend_source = ShaderAlphaBlendSource::SourceAlphaZero;
const auto zero_key = MakeStageStaticKey(pixel);
Check(ordinary_key != guest_key && guest_key != remapped_key && Check(ordinary_key != guest_key && guest_key != remapped_key &&
ordinary_key != remapped_key && separate_key != ordinary_key && ordinary_key != remapped_key && separate_key != ordinary_key &&
separate_key != guest_key && separate_key != remapped_key, separate_key != guest_key && separate_key != remapped_key &&
zero_key != ordinary_key && zero_key != guest_key &&
zero_key != remapped_key && zero_key != separate_key,
"ordinary, guest dual-source, and logical-alpha modes share a cache key"); "ordinary, guest dual-source, and logical-alpha modes share a cache key");
auto options = MakeCompileOptions(ShaderType::Pixel); auto options = MakeCompileOptions(ShaderType::Pixel);