mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2026-11-07 09:16:02 -10:00
video_core: Emulate zero/one MIN/MAX blend factors (#5197)
* Use equivalent add operations for UNORM & sRGB targets after blend factor substitutions
This commit is contained in:
1 parent
c679ce6092
commit
c5dd8b8b50
3 files changed
+50
-36
No files matched your search
@@ -262,6 +262,26 @@ vk::BlendOp BlendOp(AmdGpu::BlendControl::BlendFunc func) {
|
||||
}
|
||||
}
|
||||
|
||||
void NormalizeMinMaxBlend(vk::BlendOp& op, vk::BlendFactor& src, vk::BlendFactor& dst,
|
||||
AmdGpu::NumberFormat format) {
|
||||
if (format != AmdGpu::NumberFormat::Unorm && format != AmdGpu::NumberFormat::Srgb) {
|
||||
return;
|
||||
}
|
||||
if (op != vk::BlendOp::eMin && op != vk::BlendOp::eMax) {
|
||||
return;
|
||||
}
|
||||
if ((src != vk::BlendFactor::eZero && src != vk::BlendFactor::eOne) ||
|
||||
(dst != vk::BlendFactor::eZero && dst != vk::BlendFactor::eOne) ||
|
||||
(src != vk::BlendFactor::eZero && dst != vk::BlendFactor::eZero)) {
|
||||
return;
|
||||
}
|
||||
if (op == vk::BlendOp::eMin) {
|
||||
src = vk::BlendFactor::eZero;
|
||||
dst = vk::BlendFactor::eZero;
|
||||
}
|
||||
op = vk::BlendOp::eAdd;
|
||||
}
|
||||
|
||||
vk::LogicOp LogicOp(AmdGpu::ColorControl::LogicOp logic_op) {
|
||||
using LogicOp = AmdGpu::ColorControl::LogicOp;
|
||||
switch (logic_op) {
|
||||
|
||||
@@ -35,6 +35,9 @@ bool IsDualSourceBlendFactor(AmdGpu::BlendControl::BlendFactor factor);
|
||||
|
||||
vk::BlendOp BlendOp(AmdGpu::BlendControl::BlendFunc func);
|
||||
|
||||
void NormalizeMinMaxBlend(vk::BlendOp& op, vk::BlendFactor& src, vk::BlendFactor& dst,
|
||||
AmdGpu::NumberFormat format);
|
||||
|
||||
vk::LogicOp LogicOp(AmdGpu::ColorControl::LogicOp logic_op);
|
||||
|
||||
vk::SamplerAddressMode ClampMode(AmdGpu::ClampMode mode);
|
||||
|
||||
@@ -311,47 +311,14 @@ GraphicsPipeline::GraphicsPipeline(
|
||||
const auto alpha_blend =
|
||||
control.separate_alpha_blend ? LiverpoolToVK::BlendOp(control.alpha_func) : color_blend;
|
||||
|
||||
// Vulkan ignores blend factors for min/max, but a factor that zeroes one operand
|
||||
// makes the operation collapse to a plain selection: min(s, 0) is 0 and max(s, 0)
|
||||
// is s for normalized alpha. Rewrite those to the equivalent add so the result is
|
||||
// exact instead of leaving the other operand to survive.
|
||||
auto eff_src_alpha = src_alpha;
|
||||
auto eff_dst_alpha = dst_alpha;
|
||||
auto eff_alpha_blend = alpha_blend;
|
||||
if (alpha_blend == vk::BlendOp::eMin || alpha_blend == vk::BlendOp::eMax) {
|
||||
const bool takes_max = alpha_blend == vk::BlendOp::eMax;
|
||||
if (src_alpha == vk::BlendFactor::eOne && dst_alpha == vk::BlendFactor::eZero) {
|
||||
eff_alpha_blend = vk::BlendOp::eAdd;
|
||||
eff_src_alpha = takes_max ? vk::BlendFactor::eOne : vk::BlendFactor::eZero;
|
||||
eff_dst_alpha = vk::BlendFactor::eZero;
|
||||
} else if (src_alpha == vk::BlendFactor::eZero && dst_alpha == vk::BlendFactor::eOne) {
|
||||
eff_alpha_blend = vk::BlendOp::eAdd;
|
||||
eff_src_alpha = vk::BlendFactor::eZero;
|
||||
eff_dst_alpha = takes_max ? vk::BlendFactor::eOne : vk::BlendFactor::eZero;
|
||||
}
|
||||
}
|
||||
|
||||
const auto color_scaled_min_max =
|
||||
(color_blend == vk::BlendOp::eMin || color_blend == vk::BlendOp::eMax) &&
|
||||
(src_color != vk::BlendFactor::eOne || dst_color != vk::BlendFactor::eOne) &&
|
||||
!key.color_buffers[i].blend_self_scale;
|
||||
const auto alpha_scaled_min_max =
|
||||
(eff_alpha_blend == vk::BlendOp::eMin || eff_alpha_blend == vk::BlendOp::eMax) &&
|
||||
(eff_src_alpha != vk::BlendFactor::eOne || eff_dst_alpha != vk::BlendFactor::eOne);
|
||||
if (color_scaled_min_max || alpha_scaled_min_max) {
|
||||
LOG_WARNING(
|
||||
Render_Vulkan,
|
||||
"Unimplemented use of min/max blend op with blend factor not equal to one.");
|
||||
}
|
||||
|
||||
attachments[i] = vk::PipelineColorBlendAttachmentState{
|
||||
.blendEnable = control.enable,
|
||||
.srcColorBlendFactor = src_color,
|
||||
.dstColorBlendFactor = dst_color,
|
||||
.colorBlendOp = color_blend,
|
||||
.srcAlphaBlendFactor = eff_src_alpha,
|
||||
.dstAlphaBlendFactor = eff_dst_alpha,
|
||||
.alphaBlendOp = eff_alpha_blend,
|
||||
.srcAlphaBlendFactor = src_alpha,
|
||||
.dstAlphaBlendFactor = dst_alpha,
|
||||
.alphaBlendOp = alpha_blend,
|
||||
.colorWriteMask =
|
||||
instance.IsDynamicColorWriteMaskSupported()
|
||||
? vk::ColorComponentFlagBits::eR | vk::ColorComponentFlagBits::eG |
|
||||
@@ -391,6 +358,30 @@ GraphicsPipeline::GraphicsPipeline(
|
||||
? vk::BlendFactor::eOne
|
||||
: vk::BlendFactor::eZero; // 1-A
|
||||
}
|
||||
|
||||
auto& attachment = attachments[i];
|
||||
LiverpoolToVK::NormalizeMinMaxBlend(attachment.colorBlendOp, attachment.srcColorBlendFactor,
|
||||
attachment.dstColorBlendFactor,
|
||||
key.color_buffers[i].num_format);
|
||||
LiverpoolToVK::NormalizeMinMaxBlend(attachment.alphaBlendOp, attachment.srcAlphaBlendFactor,
|
||||
attachment.dstAlphaBlendFactor,
|
||||
key.color_buffers[i].num_format);
|
||||
|
||||
const auto color_scaled_min_max =
|
||||
(attachment.colorBlendOp == vk::BlendOp::eMin ||
|
||||
attachment.colorBlendOp == vk::BlendOp::eMax) &&
|
||||
(attachment.srcColorBlendFactor != vk::BlendFactor::eOne ||
|
||||
attachment.dstColorBlendFactor != vk::BlendFactor::eOne);
|
||||
const auto alpha_scaled_min_max =
|
||||
(attachment.alphaBlendOp == vk::BlendOp::eMin ||
|
||||
attachment.alphaBlendOp == vk::BlendOp::eMax) &&
|
||||
(attachment.srcAlphaBlendFactor != vk::BlendFactor::eOne ||
|
||||
attachment.dstAlphaBlendFactor != vk::BlendFactor::eOne);
|
||||
if (control.enable && (color_scaled_min_max || alpha_scaled_min_max)) {
|
||||
LOG_WARNING(
|
||||
Render_Vulkan,
|
||||
"Unimplemented use of min/max blend op with blend factor not equal to one.");
|
||||
}
|
||||
}
|
||||
|
||||
const vk::PipelineColorBlendStateCreateInfo color_blending = {
|
||||
|
||||
Reference in new issue
Block a user