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
@@ -459,7 +459,7 @@ void EmitSetAttribute(ValueEmitContext& ctx, const IR::Inst& inst) {
}
// Skip dormant color exports after their valid mask; MRT1 is reserved for logical alpha.
if (state.program.stage == ShaderType::Pixel && exp.kind == IR::ExportTargetKind::Mrt &&
exp.index != 0 && state.input_info.pixel->alpha_blend_source_remap) {
exp.index != 0 && state.input_info.pixel->alpha_blend_source != ShaderAlphaBlendSource::None) {
return;
}
EmitIfCondition(state, exec, [&]() {
@@ -503,14 +503,27 @@ void EmitSetAttribute(ValueEmitContext& ctx, const IR::Inst& inst) {
const auto vector_type = uint_output ? TypeU32Vector(state, 4) : TypeF32Vector(state, 4);
auto value = ExportVector(ctx, data, exp, uint_output);
if (state.program.stage == ShaderType::Pixel && exp.kind == IR::ExportTargetKind::Mrt &&
exp.index == 0 && !uint_output && state.input_info.pixel->alpha_blend_source_remap) {
exp.index == 0 && !uint_output &&
state.input_info.pixel->alpha_blend_source != ShaderAlphaBlendSource::None) {
// Broadcast logical alpha before swizzling the primary output.
const auto blend_output =
OutputVariableForExport(state, {.kind = IR::ExportTargetKind::Mrt, .index = 1});
if (blend_output != 0) {
const auto alpha = state.builder.AllocateId();
auto alpha = state.builder.AllocateId();
state.builder.AddFunction(spv::OpVectorShuffle, vector_type, alpha, value, value,
3u, 3u, 3u, 3u);
if (state.input_info.pixel->alpha_blend_source ==
ShaderAlphaBlendSource::SourceAlphaOne) {
const auto mapping = state.input_info.pixel->target_export_mapping[0];
for (uint32_t component = 0; component < 4; component++) {
if (mapping.Map(component) != 3u) continue;
const auto factors = state.builder.AllocateId();
state.builder.AddFunction(spv::OpCompositeInsert, vector_type, factors,
ConstantF32Value(state, 1.0f), alpha, component);
alpha = factors;
break;
}
}
state.builder.AddFunction(spv::OpStore, blend_output, alpha);
}
}
@@ -327,7 +327,7 @@ void CollectBuiltinInputs(const Program& program, ShaderInfo& info) {
void CollectOutputs(const Program& program, ShaderStageInputInfo input_info, ShaderInfo& info) {
const bool alpha_remap = program.stage == ShaderType::Pixel && input_info.pixel != nullptr &&
input_info.pixel->alpha_blend_source_remap;
input_info.pixel->alpha_blend_source != ShaderAlphaBlendSource::None;
for (const auto* block: program.blocks) {
for (const auto& inst: *block) {
if (inst.GetOpcode() != ValueOpcode::SetAttribute) {
+1 -1
View File
@@ -660,7 +660,7 @@ void BuildStageStaticKey(const ShaderPixelInputInfo& info, std::vector<uint32_t>
key.push_back(static_cast<uint32_t>(info.ps_sample_mask_export_enable));
key.push_back(static_cast<uint32_t>(info.ps_early_z));
key.push_back(static_cast<uint32_t>(info.dual_source_blending));
key.push_back(static_cast<uint32_t>(info.alpha_blend_source_remap));
key.push_back(static_cast<uint32_t>(info.alpha_blend_source));
key.insert(key.end(), std::begin(info.target_output_mode), std::end(info.target_output_mode));
for (uint32_t base = 0; base < info.target_export_mapping.size(); base += 4u) {
uint32_t packed = 0;
+4 -2
View File
@@ -156,6 +156,8 @@ struct ShaderComputeInputInfo: ShaderWorkgroupInputInfo {
ShaderStageRuntime stage;
};
enum class ShaderAlphaBlendSource : uint8_t { None, SourceAlpha, SourceAlphaOne };
struct ShaderPixelInputInfo {
uint32_t interpolator_settings[32] = {0};
uint32_t input_num = 0;
@@ -179,8 +181,8 @@ struct ShaderPixelInputInfo {
bool ps_sample_mask_export_enable = false;
bool ps_sample_shading = false;
bool dual_source_blending = false;
// Export logical alpha through MRT1 for blending after channel swizzling.
bool alpha_blend_source_remap = false;
// Export logical alpha or per-channel source factors through MRT1 after channel swizzling.
ShaderAlphaBlendSource alpha_blend_source = ShaderAlphaBlendSource::None;
bool ps_early_z = false;
bool ps_execute_on_noop = false;
ShaderStageRuntime stage;