diff --git a/src/video_core/shader/generator/glsl_fs_shader_gen.cpp b/src/video_core/shader/generator/glsl_fs_shader_gen.cpp index 7d7ae63bb..8ff5ac9d4 100644 --- a/src/video_core/shader/generator/glsl_fs_shader_gen.cpp +++ b/src/video_core/shader/generator/glsl_fs_shader_gen.cpp @@ -895,7 +895,11 @@ void FragmentModule::WriteLogicOp() { } void FragmentModule::WriteBlending() { - if (!config.EmulateBlend() || profile.is_vulkan) [[likely]] { + bool requires_rgb_minmax_emulation = + config.framebuffer.requested_rgb_blend.RequiresMinMaxEmulation(); + bool requires_alpha_minmax_emulation = + config.framebuffer.requested_alpha_blend.RequiresMinMaxEmulation(); + if (!requires_rgb_minmax_emulation && !requires_alpha_minmax_emulation) [[likely]] { return; } @@ -937,23 +941,25 @@ void FragmentModule::WriteBlending() { return "vec4(1.f)"; } }; + + // At this point, the blend equation can only be min or max. const auto get_func = [](Pica::FramebufferRegs::BlendEquation eq) { return eq == Pica::FramebufferRegs::BlendEquation::Min ? "min" : "max"; }; - if (config.framebuffer.rgb_blend.eq != Pica::FramebufferRegs::BlendEquation::Add) { + if (requires_rgb_minmax_emulation) { out += fmt::format( "combiner_output.rgb = {}(source_color.rgb * ({}).rgb, dest_color.rgb * ({}).rgb);\n", - get_func(config.framebuffer.rgb_blend.eq), - get_factor(config.framebuffer.rgb_blend.src_factor), - get_factor(config.framebuffer.rgb_blend.dst_factor)); + get_func(config.framebuffer.requested_rgb_blend.eq), + get_factor(config.framebuffer.requested_rgb_blend.src_factor), + get_factor(config.framebuffer.requested_rgb_blend.dst_factor)); } - if (config.framebuffer.alpha_blend.eq != Pica::FramebufferRegs::BlendEquation::Add) { + if (requires_alpha_minmax_emulation) { out += fmt::format("combiner_output.a = {}(source_color.a * ({}).a, dest_color.a * ({}).a);\n", - get_func(config.framebuffer.alpha_blend.eq), - get_factor(config.framebuffer.alpha_blend.src_factor), - get_factor(config.framebuffer.alpha_blend.dst_factor)); + get_func(config.framebuffer.requested_alpha_blend.eq), + get_factor(config.framebuffer.requested_alpha_blend.src_factor), + get_factor(config.framebuffer.requested_alpha_blend.dst_factor)); } } @@ -1239,7 +1245,8 @@ void FragmentModule::DefineExtensions() { use_fragment_shader_barycentric = false; } } - if (config.EmulateBlend() && !profile.is_vulkan) { + if (config.framebuffer.requested_rgb_blend.RequiresMinMaxEmulation() || + config.framebuffer.requested_alpha_blend.RequiresMinMaxEmulation()) [[unlikely]] { if (profile.has_gl_ext_framebuffer_fetch) { out += "#extension GL_EXT_shader_framebuffer_fetch : enable\n"; out += "#define destFactor color\n"; @@ -1338,7 +1345,7 @@ void FragmentModule::DefineBindingsGL() { out += "layout(binding = 6) uniform sampler2D tex_normal;\n"; } if (use_blend_fallback) { - out += "layout(location = 7) uniform sampler2D tex_color;\n"; + out += "layout(binding = 7) uniform sampler2D tex_color;\n"; } // Shadow textures diff --git a/src/video_core/shader/generator/pica_fs_config.cpp b/src/video_core/shader/generator/pica_fs_config.cpp index 0f3854ce8..c584b99a0 100644 --- a/src/video_core/shader/generator/pica_fs_config.cpp +++ b/src/video_core/shader/generator/pica_fs_config.cpp @@ -21,13 +21,13 @@ FramebufferConfig::FramebufferConfig(const Pica::RegsInternal& regs) { logic_op.Assign(Pica::FramebufferRegs::LogicOp::Copy); if (alphablend_enable) { - rgb_blend.eq = output_merger.alpha_blending.blend_equation_rgb.Value(); - rgb_blend.src_factor = output_merger.alpha_blending.factor_source_rgb; - rgb_blend.dst_factor = output_merger.alpha_blending.factor_dest_rgb; + requested_rgb_blend.eq = output_merger.alpha_blending.blend_equation_rgb.Value(); + requested_rgb_blend.src_factor = output_merger.alpha_blending.factor_source_rgb; + requested_rgb_blend.dst_factor = output_merger.alpha_blending.factor_dest_rgb; - alpha_blend.eq = output_merger.alpha_blending.blend_equation_a.Value(); - alpha_blend.src_factor = output_merger.alpha_blending.factor_source_a; - alpha_blend.dst_factor = output_merger.alpha_blending.factor_dest_a; + requested_alpha_blend.eq = output_merger.alpha_blending.blend_equation_a.Value(); + requested_alpha_blend.src_factor = output_merger.alpha_blending.factor_source_a; + requested_alpha_blend.dst_factor = output_merger.alpha_blending.factor_dest_a; } } @@ -37,17 +37,10 @@ void FramebufferConfig::ApplyProfile(const Profile& profile) { logic_op.Assign(requested_logic_op); } - // Min/max blend emulation - if (!profile.has_blend_minmax_factor && alphablend_enable) { - if (rgb_blend.eq != Pica::FramebufferRegs::BlendEquation::Min && - rgb_blend.eq != Pica::FramebufferRegs::BlendEquation::Max) { - rgb_blend = {}; - } - - if (alpha_blend.eq != Pica::FramebufferRegs::BlendEquation::Min && - alpha_blend.eq != Pica::FramebufferRegs::BlendEquation::Max) { - alpha_blend = {}; - } + // Check if we don't need blend min/max emulation. + if ((profile.has_blend_minmax_factor || profile.is_vulkan) && alphablend_enable) { + requested_rgb_blend.SetMinMaxEmulationDisabled(); + requested_alpha_blend.SetMinMaxEmulationDisabled(); } } diff --git a/src/video_core/shader/generator/pica_fs_config.h b/src/video_core/shader/generator/pica_fs_config.h index 736880a5b..f0e2fe718 100644 --- a/src/video_core/shader/generator/pica_fs_config.h +++ b/src/video_core/shader/generator/pica_fs_config.h @@ -43,6 +43,17 @@ struct BlendConfig { // fields FIELD_HASH(eq), FIELD_HASH(src_factor), FIELD_HASH(dst_factor)); } + + void SetMinMaxEmulationDisabled() { + // If we don't need min/max emulation, set the blend equation + // to "-1" as a clear marker that this config is disabled. + eq = static_cast(UINT32_MAX); + } + + bool RequiresMinMaxEmulation() { + return eq == Pica::FramebufferRegs::BlendEquation::Min || + eq == Pica::FramebufferRegs::BlendEquation::Max; + } }; static_assert(std::has_unique_object_representations_v); @@ -58,8 +69,8 @@ struct FramebufferConfig { BitField<10, 1, u32> shadow_rendering; BitField<11, 1, u32> alphablend_enable; }; - BlendConfig rgb_blend{}; - BlendConfig alpha_blend{}; + BlendConfig requested_rgb_blend{}; + BlendConfig requested_alpha_blend{}; Pica::FramebufferRegs::LogicOp requested_logic_op{}; @@ -78,7 +89,8 @@ struct FramebufferConfig { // fields FIELD_HASH(alpha_test_func), FIELD_HASH(scissor_test_mode), FIELD_HASH(depthmap_enable), FIELD_HASH(logic_op), FIELD_HASH(shadow_rendering), FIELD_HASH(alphablend_enable), - FIELD_HASH(rgb_blend), FIELD_HASH(alpha_blend), FIELD_HASH(requested_logic_op), + FIELD_HASH(requested_rgb_blend), FIELD_HASH(requested_alpha_blend), + FIELD_HASH(requested_logic_op), // nested layout BlendConfig::StructHash()); @@ -387,11 +399,6 @@ struct FSConfig { return (stage_index < 4) && ((texture.combiner_buffer_input >> 4) & (1 << stage_index)); } - [[nodiscard]] bool EmulateBlend() const { - return framebuffer.rgb_blend.eq != Pica::FramebufferRegs::BlendEquation::Add || - framebuffer.alpha_blend.eq != Pica::FramebufferRegs::BlendEquation::Add; - } - [[nodiscard]] bool UsesSpirvIncompatibleConfig() const { const auto texture0_type = texture.texture0_type.Value(); return texture0_type == Pica::TexturingRegs::TextureConfig::ShadowCube ||