[D3D12] Fix constant-alpha blending in the RTV path

This commit is contained in:
Clippy95
2026-08-15 10:32:54 +03:00
committed by Radosław Gliński
parent 7cd47947b0
commit 4cc584f47d
6 changed files with 92 additions and 16 deletions

View File

@@ -2831,7 +2831,8 @@ bool D3D12CommandProcessor::IssueDraw(xenos::PrimitiveType primitive_type,
#endif
// Update viewport, scissor, blend factor and stencil reference.
UpdateFixedFunctionState(viewport_info, scissor, primitive_polygonal,
normalized_depth_control);
normalized_depth_control, normalized_color_mask,
bound_depth_and_color_render_target_bits);
// Update system constants before uploading them.
// TODO(Triang3l): With ROV, pass the disabled render target mask for safety.
@@ -3902,7 +3903,9 @@ void D3D12CommandProcessor::ClearCommandAllocatorCache() {
void D3D12CommandProcessor::UpdateFixedFunctionState(
const draw_util::ViewportInfo& viewport_info,
const draw_util::Scissor& scissor, bool primitive_polygonal,
reg::RB_DEPTHCONTROL normalized_depth_control) {
reg::RB_DEPTHCONTROL normalized_depth_control,
uint32_t normalized_color_mask,
uint32_t bound_depth_and_color_render_target_bits) {
#if XE_GPU_FINE_GRAINED_DRAW_SCOPES
SCOPE_profile_cpu_f("gpu");
#endif // XE_GPU_FINE_GRAINED_DRAW_SCOPES
@@ -3936,6 +3939,51 @@ void D3D12CommandProcessor::UpdateFixedFunctionState(
regs.Get<float>(XE_GPU_REG_RB_BLEND_BLUE),
regs.Get<float>(XE_GPU_REG_RB_BLEND_ALPHA),
};
if (!GetD3D12Provider().IsAlphaBlendFactorSupported()) {
bool color_uses_constant_color = false;
bool color_uses_constant_alpha = false;
for (uint32_t i = 0; i < xenos::kMaxColorRenderTargets; ++i) {
// Ignore unbound targets and targets that don't write RGB, since their
// color blend factors don't affect the host output merger.
if (!(bound_depth_and_color_render_target_bits &
(uint32_t(1) << (1 + i))) ||
!((normalized_color_mask >> (i * 4)) & 0b0111)) {
continue;
}
auto blend_control = regs.Get<reg::RB_BLENDCONTROL>(
reg::RB_BLENDCONTROL::rt_register_indices[i]);
// Direct3D 12 ignores blend factors for MIN and MAX.
if (blend_control.color_comb_fcn == xenos::BlendOp::kMin ||
blend_control.color_comb_fcn == xenos::BlendOp::kMax) {
continue;
}
const xenos::BlendFactor color_blend_factors[] = {
blend_control.color_srcblend, blend_control.color_destblend};
for (xenos::BlendFactor color_blend_factor : color_blend_factors) {
switch (color_blend_factor) {
case xenos::BlendFactor::kConstantColor:
case xenos::BlendFactor::kOneMinusConstantColor:
color_uses_constant_color = true;
break;
case xenos::BlendFactor::kConstantAlpha:
case xenos::BlendFactor::kOneMinusConstantAlpha:
color_uses_constant_alpha = true;
break;
default:
break;
}
}
}
// Legacy D3D12 has only a four-component constant-color factor. If the
// draw needs only the scalar constant-alpha factor, emulate it by
// replicating A. Mixed constant-color and constant-alpha use can't be
// represented exactly, so preserve the color factor in that case.
if (color_uses_constant_alpha && !color_uses_constant_color) {
blend_factor[0] = blend_factor[3];
blend_factor[1] = blend_factor[3];
blend_factor[2] = blend_factor[3];
}
}
// std::memcmp instead of != so in case of NaN, every draw won't be
// invalidating it.
ff_blend_factor_update_needed_ |=

View File

@@ -452,10 +452,12 @@ class D3D12CommandProcessor final : public CommandProcessor {
D3D12_CPU_DESCRIPTOR_HANDLE& cpu_handle_out,
D3D12_GPU_DESCRIPTOR_HANDLE& gpu_handle_out);
void UpdateFixedFunctionState(const draw_util::ViewportInfo& viewport_info,
const draw_util::Scissor& scissor,
bool primitive_polygonal,
reg::RB_DEPTHCONTROL normalized_depth_control);
void UpdateFixedFunctionState(
const draw_util::ViewportInfo& viewport_info,
const draw_util::Scissor& scissor, bool primitive_polygonal,
reg::RB_DEPTHCONTROL normalized_depth_control,
uint32_t normalized_color_mask,
uint32_t bound_depth_and_color_render_target_bits);
template <bool primitive_polygonal, bool edram_rov_used>
XE_NOINLINE void UpdateSystemConstantValues_Impl(

View File

@@ -1544,9 +1544,9 @@ bool PipelineCache::GetCurrentStateDescription(
// ONE_MINUS_CONSTANT_COLOR
/* 13 */ PipelineBlendFactor::kInvBlendFactor,
// CONSTANT_ALPHA
/* 14 */ PipelineBlendFactor::kBlendFactor,
/* 14 */ PipelineBlendFactor::kAlphaFactor,
// ONE_MINUS_CONSTANT_ALPHA
/* 15 */ PipelineBlendFactor::kInvBlendFactor,
/* 15 */ PipelineBlendFactor::kInvAlphaFactor,
/* 16 */ PipelineBlendFactor::kSrcAlphaSat,
};
// Like kBlendFactorMap, but with color modes changed to alpha. Some
@@ -3156,14 +3156,26 @@ ID3D12PipelineState* PipelineCache::CreateD3D12Pipeline(
// Render targets and blending.
state_desc.BlendState.IndependentBlendEnable = true;
static constexpr D3D12_BLEND kBlendFactorMap[] = {
D3D12_BLEND_ZERO, D3D12_BLEND_ONE,
D3D12_BLEND_SRC_COLOR, D3D12_BLEND_INV_SRC_COLOR,
D3D12_BLEND_SRC_ALPHA, D3D12_BLEND_INV_SRC_ALPHA,
D3D12_BLEND_DEST_COLOR, D3D12_BLEND_INV_DEST_COLOR,
D3D12_BLEND_DEST_ALPHA, D3D12_BLEND_INV_DEST_ALPHA,
D3D12_BLEND_BLEND_FACTOR, D3D12_BLEND_INV_BLEND_FACTOR,
const bool alpha_blend_factor_supported =
command_processor_.GetD3D12Provider().IsAlphaBlendFactorSupported();
const D3D12_BLEND kBlendFactorMap[] = {
D3D12_BLEND_ZERO,
D3D12_BLEND_ONE,
D3D12_BLEND_SRC_COLOR,
D3D12_BLEND_INV_SRC_COLOR,
D3D12_BLEND_SRC_ALPHA,
D3D12_BLEND_INV_SRC_ALPHA,
D3D12_BLEND_DEST_COLOR,
D3D12_BLEND_INV_DEST_COLOR,
D3D12_BLEND_DEST_ALPHA,
D3D12_BLEND_INV_DEST_ALPHA,
D3D12_BLEND_BLEND_FACTOR,
D3D12_BLEND_INV_BLEND_FACTOR,
D3D12_BLEND_SRC_ALPHA_SAT,
alpha_blend_factor_supported ? D3D12_BLEND_ALPHA_FACTOR
: D3D12_BLEND_BLEND_FACTOR,
alpha_blend_factor_supported ? D3D12_BLEND_INV_ALPHA_FACTOR
: D3D12_BLEND_INV_BLEND_FACTOR,
};
// 8 entries for safety since 3 bits from the guest are passed directly.
static constexpr D3D12_BLEND_OP kBlendOpMap[] = {

View File

@@ -180,6 +180,8 @@ class PipelineCache {
kBlendFactor,
kInvBlendFactor,
kSrcAlphaSat,
kAlphaFactor,
kInvAlphaFactor,
};
// Update PipelineDescription::kVersion if anything is changed!
@@ -237,7 +239,7 @@ class PipelineCache {
PipelineRenderTarget render_targets[xenos::kMaxColorRenderTargets];
inline bool operator==(const PipelineDescription& other) const;
static constexpr uint32_t kVersion = 0x20260716;
static constexpr uint32_t kVersion = 0x20260815;
});
XEPACKEDSTRUCT(PipelineStoredDescription, {

View File

@@ -463,6 +463,12 @@ bool D3D12Provider::Initialize() {
unaligned_block_textures_supported_ =
bool(options8.UnalignedBlockTexturesSupported);
}
alpha_blend_factor_supported_ = false;
D3D12_FEATURE_DATA_D3D12_OPTIONS13 options13 = {};
if (SUCCEEDED(device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS13,
&options13, sizeof(options13)))) {
alpha_blend_factor_supported_ = bool(options13.AlphaBlendFactorSupported);
}
virtual_address_bits_per_resource_ = 0;
D3D12_FEATURE_DATA_GPU_VIRTUAL_ADDRESS_SUPPORT virtual_address_support;
if (SUCCEEDED(device->CheckFeatureSupport(
@@ -478,6 +484,7 @@ bool D3D12Provider::Initialize() {
"* Pixel-shader-specified stencil reference: {}\n"
"* Programmable sample positions: tier {}\n"
"* Rasterizer-ordered views: {}\n"
"* Scalar alpha blend factor: {}\n"
"* Resource binding: tier {}\n"
"* Tiled resources: tier {}\n"
"* Unaligned block-compressed textures: {}",
@@ -487,6 +494,7 @@ bool D3D12Provider::Initialize() {
ps_specified_stencil_reference_supported_ ? "yes" : "no",
uint32_t(programmable_sample_positions_tier_),
rasterizer_ordered_views_supported_ ? "yes" : "no",
alpha_blend_factor_supported_ ? "yes" : "no",
uint32_t(resource_binding_tier_), uint32_t(tiled_resources_tier_),
unaligned_block_textures_supported_ ? "yes" : "no");

View File

@@ -114,6 +114,9 @@ class D3D12Provider : public GraphicsProvider {
bool AreRasterizerOrderedViewsSupported() const {
return rasterizer_ordered_views_supported_;
}
bool IsAlphaBlendFactorSupported() const {
return alpha_blend_factor_supported_;
}
D3D12_RESOURCE_BINDING_TIER GetResourceBindingTier() const {
return resource_binding_tier_;
}
@@ -210,6 +213,7 @@ class D3D12Provider : public GraphicsProvider {
uint32_t virtual_address_bits_per_resource_;
bool ps_specified_stencil_reference_supported_;
bool rasterizer_ordered_views_supported_;
bool alpha_blend_factor_supported_;
bool unaligned_block_textures_supported_;
};