mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-20 10:56:58 +02:00
graphics: preserve logical alpha when blending reordered targets (PPSA02721)
Co-authored-by: EmK530 <admin@emk530.net>
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
#include "graphics/host_gpu/renderer/pipeline/blendMapping.h"
|
||||
|
||||
#include "graphics/guest_gpu/hardwareContext.h"
|
||||
|
||||
#include <initializer_list>
|
||||
|
||||
namespace Libs::Graphics {
|
||||
|
||||
bool BlendFactorIsDualSource(uint8_t factor) {
|
||||
return factor >= static_cast<uint8_t>(Prospero::BlendFactor::kSrc1Color) &&
|
||||
factor <= static_cast<uint8_t>(Prospero::BlendFactor::kOneMinusSrc1Alpha);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
bool BlendFactorIsConstantColor(uint8_t factor) {
|
||||
return factor == static_cast<uint8_t>(Prospero::BlendFactor::kConstantColor) ||
|
||||
factor == static_cast<uint8_t>(Prospero::BlendFactor::kOneMinusConstantColor);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
BlendMappingSupport ClassifyBlendMapping(const HW::BlendControl& blend,
|
||||
const Prospero::ColorComponentMapping& mapping) {
|
||||
// Color constants are not swizzled with the exports; scalar constant alpha is unaffected.
|
||||
if (!mapping.IsIdentity() && (BlendFactorIsConstantColor(blend.color_srcblend) ||
|
||||
BlendFactorIsConstantColor(blend.color_destblend))) {
|
||||
return BlendMappingSupport::Unsupported;
|
||||
}
|
||||
if (mapping.Map(3) == 3u) {
|
||||
return BlendMappingSupport::Direct;
|
||||
}
|
||||
// Moving alpha requires the same equation for all channels.
|
||||
if (blend.separate_alpha_blend && (blend.alpha_srcblend != blend.color_srcblend ||
|
||||
blend.alpha_destblend != blend.color_destblend ||
|
||||
blend.alpha_comb_fcn != blend.color_comb_fcn)) {
|
||||
return BlendMappingSupport::Unsupported;
|
||||
}
|
||||
auto support = BlendMappingSupport::Direct;
|
||||
for (const auto factor: {blend.color_srcblend, blend.color_destblend}) {
|
||||
if (BlendFactorIsDualSource(factor)) {
|
||||
return BlendMappingSupport::Unsupported;
|
||||
}
|
||||
switch (static_cast<Prospero::BlendFactor>(factor)) {
|
||||
case Prospero::BlendFactor::kSrcAlpha:
|
||||
case Prospero::BlendFactor::kOneMinusSrcAlpha:
|
||||
support = BlendMappingSupport::SourceAlpha;
|
||||
break;
|
||||
case Prospero::BlendFactor::kDstAlpha:
|
||||
case Prospero::BlendFactor::kOneMinusDstAlpha:
|
||||
case Prospero::BlendFactor::kSrcAlphaSaturate: return BlendMappingSupport::Unsupported;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
return support;
|
||||
}
|
||||
|
||||
} // namespace Libs::Graphics
|
||||
@@ -0,0 +1,27 @@
|
||||
#ifndef EMULATOR_SRC_GRAPHICS_HOST_GPU_RENDERER_PIPELINE_BLENDMAPPING_H_
|
||||
#define EMULATOR_SRC_GRAPHICS_HOST_GPU_RENDERER_PIPELINE_BLENDMAPPING_H_
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace Libs::Graphics {
|
||||
|
||||
namespace HW {
|
||||
struct BlendControl;
|
||||
}
|
||||
namespace Prospero {
|
||||
struct ColorComponentMapping;
|
||||
}
|
||||
|
||||
enum class BlendMappingSupport {
|
||||
Direct,
|
||||
SourceAlpha, // Requires logical alpha in the second blend source.
|
||||
Unsupported,
|
||||
};
|
||||
|
||||
bool BlendFactorIsDualSource(uint8_t factor);
|
||||
BlendMappingSupport ClassifyBlendMapping(const HW::BlendControl& blend,
|
||||
const Prospero::ColorComponentMapping& mapping);
|
||||
|
||||
} // namespace Libs::Graphics
|
||||
|
||||
#endif // EMULATOR_SRC_GRAPHICS_HOST_GPU_RENDERER_PIPELINE_BLENDMAPPING_H_
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "graphics/host_gpu/renderer/debug.h"
|
||||
#include "graphics/host_gpu/renderer/depthRenderTarget.h"
|
||||
#include "graphics/host_gpu/renderer/image/imageView.h"
|
||||
#include "graphics/host_gpu/renderer/pipeline/blendMapping.h"
|
||||
#include "graphics/host_gpu/renderer/render.h"
|
||||
#include "graphics/host_gpu/renderer/renderContext.h"
|
||||
#include "graphics/shader/recompiler/ShaderRecompiler.h"
|
||||
@@ -609,21 +610,30 @@ PipelineCache::GraphicsPrograms PipelineCache::GetGraphicsPrograms(
|
||||
}
|
||||
ShaderParams pixel_params;
|
||||
if (pixel_active) {
|
||||
pixel_params = PrepareProgram(pixel_regs, sh, target_export_mapping, pixel_info);
|
||||
const auto& blend = context.GetBlendControl(0);
|
||||
const auto is_dual_source = [](uint8_t factor) {
|
||||
return factor >= static_cast<uint8_t>(Prospero::BlendFactor::kSrc1Color) &&
|
||||
factor <= static_cast<uint8_t>(Prospero::BlendFactor::kOneMinusSrc1Alpha);
|
||||
};
|
||||
pixel_params = PrepareProgram(pixel_regs, sh, target_export_mapping, pixel_info);
|
||||
const auto& blend = context.GetBlendControl(0);
|
||||
pixel_info.dual_source_blending =
|
||||
blend.enable && !context.GetRenderTarget(0).info.blend_bypass &&
|
||||
(is_dual_source(blend.color_srcblend) || is_dual_source(blend.color_destblend) ||
|
||||
(blend.separate_alpha_blend &&
|
||||
(is_dual_source(blend.alpha_srcblend) || is_dual_source(blend.alpha_destblend))));
|
||||
(BlendFactorIsDualSource(blend.color_srcblend) ||
|
||||
BlendFactorIsDualSource(blend.color_destblend) ||
|
||||
(blend.separate_alpha_blend && (BlendFactorIsDualSource(blend.alpha_srcblend) ||
|
||||
BlendFactorIsDualSource(blend.alpha_destblend))));
|
||||
if (pixel_info.dual_source_blending) {
|
||||
// MRT1 supplies a second blend source for the same render target as MRT0.
|
||||
// MRT1 supplies the second blend source for target 0.
|
||||
pixel_info.target_output_mode[1] = pixel_info.target_output_mode[0];
|
||||
pixel_info.target_export_mapping[1] = pixel_info.target_export_mapping[0];
|
||||
} else if (blend.enable && !context.GetRenderTarget(0).info.blend_bypass &&
|
||||
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] = {};
|
||||
}
|
||||
}
|
||||
if (context.GetClipControl().clip_disable) {
|
||||
@@ -720,7 +730,24 @@ PipelineCache::Pipeline& PipelineCache::GetGraphicsPipeline(
|
||||
static_params.alpha_comb_fcn[slot] = bc.alpha_comb_fcn;
|
||||
static_params.alpha_destblend[slot] = bc.alpha_destblend;
|
||||
static_params.separate_alpha_blend[slot] = bc.separate_alpha_blend;
|
||||
static_params.blend_enable[slot] = bc.enable && !rt.info.blend_bypass;
|
||||
const bool alpha_remap =
|
||||
slot == 0 && ps_input_info != nullptr && ps_input_info->alpha_blend_source_remap;
|
||||
static_params.blend_enable[slot] = bc.enable && !rt.info.blend_bypass;
|
||||
if (static_params.blend_enable[slot] && !alpha_remap &&
|
||||
ClassifyBlendMapping(bc, colors[i].export_mapping) != BlendMappingSupport::Direct) {
|
||||
static_params.blend_enable[slot] = false;
|
||||
static std::atomic_bool warned = false;
|
||||
if (!warned.exchange(true, std::memory_order_relaxed)) {
|
||||
Log::WriteToConsoleAndLog(fmt::format(
|
||||
"Warning: blending disabled for unsupported color mapping "
|
||||
"(slot={} mapping=0x{:02x} color={}/{} alpha={}/{} separate={}).\n",
|
||||
slot, colors[i].export_mapping.packed, bc.color_srcblend, bc.color_destblend,
|
||||
bc.alpha_srcblend, bc.alpha_destblend, bc.separate_alpha_blend ? 1 : 0));
|
||||
}
|
||||
}
|
||||
if (alpha_remap) {
|
||||
static_params.blend_alpha_source_remap = true;
|
||||
}
|
||||
}
|
||||
const bool with_depth =
|
||||
depth.desc.view_info.format != vk::Format::eUndefined && static_cast<bool>(depth.image_id);
|
||||
|
||||
@@ -55,6 +55,7 @@ struct PipelineStaticParameters {
|
||||
uint8_t alpha_destblend[RENDER_COLOR_ATTACHMENTS_MAX] = {};
|
||||
bool separate_alpha_blend[RENDER_COLOR_ATTACHMENTS_MAX] = {};
|
||||
bool blend_enable[RENDER_COLOR_ATTACHMENTS_MAX] = {};
|
||||
bool blend_alpha_source_remap = false;
|
||||
|
||||
bool operator==(const PipelineStaticParameters& other) const noexcept;
|
||||
};
|
||||
@@ -64,7 +65,7 @@ struct PipelineStaticParameters {
|
||||
static_assert(std::is_trivially_copyable_v<PipelineStaticParameters>);
|
||||
static_assert(std::is_standard_layout_v<PipelineStaticParameters>);
|
||||
static_assert(alignof(PipelineStaticParameters) == 1);
|
||||
static_assert(sizeof(PipelineStaticParameters) == 125);
|
||||
static_assert(sizeof(PipelineStaticParameters) == 126);
|
||||
|
||||
struct PipelineRenderingState {
|
||||
std::array<vk::Format, RENDER_COLOR_ATTACHMENTS_MAX> color_formats {};
|
||||
|
||||
@@ -137,14 +137,17 @@ static void GetInputFormat(const ShaderBufferResource& res, vk::Format& format,
|
||||
}
|
||||
}
|
||||
|
||||
static vk::BlendFactor GetBlendFactor(uint32_t factor) {
|
||||
static vk::BlendFactor GetBlendFactor(uint32_t factor, bool remap_source_alpha) {
|
||||
switch (static_cast<Prospero::BlendFactor>(factor)) {
|
||||
case Prospero::BlendFactor::kZero: return vk::BlendFactor::eZero;
|
||||
case Prospero::BlendFactor::kOne: return vk::BlendFactor::eOne;
|
||||
case Prospero::BlendFactor::kSrcColor: return vk::BlendFactor::eSrcColor;
|
||||
case Prospero::BlendFactor::kOneMinusSrcColor: return vk::BlendFactor::eOneMinusSrcColor;
|
||||
case Prospero::BlendFactor::kSrcAlpha: return vk::BlendFactor::eSrcAlpha;
|
||||
case Prospero::BlendFactor::kOneMinusSrcAlpha: return vk::BlendFactor::eOneMinusSrcAlpha;
|
||||
case Prospero::BlendFactor::kSrcAlpha:
|
||||
return remap_source_alpha ? vk::BlendFactor::eSrc1Color : vk::BlendFactor::eSrcAlpha;
|
||||
case Prospero::BlendFactor::kOneMinusSrcAlpha:
|
||||
return remap_source_alpha ? vk::BlendFactor::eOneMinusSrc1Color
|
||||
: vk::BlendFactor::eOneMinusSrcAlpha;
|
||||
case Prospero::BlendFactor::kDstAlpha: return vk::BlendFactor::eDstAlpha;
|
||||
case Prospero::BlendFactor::kOneMinusDstAlpha: return vk::BlendFactor::eOneMinusDstAlpha;
|
||||
case Prospero::BlendFactor::kDstColor: return vk::BlendFactor::eDstColor;
|
||||
@@ -397,17 +400,20 @@ void CreatePipelineInternal(GraphicContext& graphics, PipelineCache::Pipeline& p
|
||||
color_blend_attachment[i].colorWriteMask =
|
||||
vk::ColorComponentFlags {static_params.color_mask[i]};
|
||||
color_blend_attachment[i].blendEnable = static_params.blend_enable[i] ? VK_TRUE : VK_FALSE;
|
||||
// Only target 0 can use the second blend source carrying logical alpha.
|
||||
const bool remap_source_alpha = i == 0 && static_params.blend_alpha_source_remap;
|
||||
color_blend_attachment[i].srcColorBlendFactor =
|
||||
GetBlendFactor(static_params.color_srcblend[i]);
|
||||
GetBlendFactor(static_params.color_srcblend[i], remap_source_alpha);
|
||||
color_blend_attachment[i].dstColorBlendFactor =
|
||||
GetBlendFactor(static_params.color_destblend[i]);
|
||||
GetBlendFactor(static_params.color_destblend[i], remap_source_alpha);
|
||||
color_blend_attachment[i].colorBlendOp = GetBlendOp(static_params.color_comb_fcn[i]);
|
||||
color_blend_attachment[i].srcAlphaBlendFactor =
|
||||
(static_params.separate_alpha_blend[i] ? GetBlendFactor(static_params.alpha_srcblend[i])
|
||||
: color_blend_attachment[i].srcColorBlendFactor);
|
||||
(static_params.separate_alpha_blend[i]
|
||||
? GetBlendFactor(static_params.alpha_srcblend[i], remap_source_alpha)
|
||||
: color_blend_attachment[i].srcColorBlendFactor);
|
||||
color_blend_attachment[i].dstAlphaBlendFactor =
|
||||
(static_params.separate_alpha_blend[i]
|
||||
? GetBlendFactor(static_params.alpha_destblend[i])
|
||||
? GetBlendFactor(static_params.alpha_destblend[i], remap_source_alpha)
|
||||
: color_blend_attachment[i].dstColorBlendFactor);
|
||||
color_blend_attachment[i].alphaBlendOp =
|
||||
(static_params.separate_alpha_blend[i] ? GetBlendOp(static_params.alpha_comb_fcn[i])
|
||||
|
||||
Reference in New Issue
Block a user