diff --git a/include/rt64_layer.h b/include/rt64_layer.h index a138785..9944669 100644 --- a/include/rt64_layer.h +++ b/include/rt64_layer.h @@ -40,6 +40,7 @@ namespace ultramodern { RT64::UserConfiguration::Antialiasing RT64MaxMSAA(); bool RT64SamplePositionsSupported(); + bool RT64HighPrecisionFBEnabled(); } void set_rt64_hooks(); diff --git a/patches/effect_patches.c b/patches/effect_patches.c index 79ba7d9..5fff08a 100644 --- a/patches/effect_patches.c +++ b/patches/effect_patches.c @@ -98,9 +98,12 @@ void Play_DrawMotionBlur(PlayState* this) { f32 exponent = 20.0f / recomp_get_target_framerate(gFramerateDivisor); f32 alpha_float = recomp_powf(alpha / 255.0f, exponent); // Clamp the blur alpha, which ensures that the output color converges to within a reasonable delta of the target color - // when using an R8G8B8A8 framebuffer as RT64 currently does. Although this makes the effect less noticeable at high framerates, + // when using an R8G8B8A8 framebuffer. Although this makes the effect less noticeable at high framerates, // not clamping leads to noticeable image retention. - //alpha_float = MIN(alpha_float, 0.825f); + // Skip clamping if high precision framebuffers are in use, as there's no risk of ghosting with those. + if (!recomp_high_precision_fb_enabled()) { + alpha_float = MIN(alpha_float, 0.825f); + } alpha = (s32)(alpha_float * 255.0f); if (sMotionBlurStatus == MOTION_BLUR_PROCESS) { diff --git a/patches/graphics.h b/patches/graphics.h index 88ccb77..94ff609 100644 --- a/patches/graphics.h +++ b/patches/graphics.h @@ -5,5 +5,6 @@ DECLARE_FUNC(float, recomp_get_aspect_ratio, float); DECLARE_FUNC(s32, recomp_get_target_framerate, s32); +DECLARE_FUNC(s32, recomp_high_precision_fb_enabled); #endif diff --git a/patches/syms.ld b/patches/syms.ld index 22e16ae..aa92a7f 100644 --- a/patches/syms.ld +++ b/patches/syms.ld @@ -52,3 +52,4 @@ osGetTime_recomp = 0x8F000088; recomp_autosave_enabled = 0x8F00008C; recomp_load_overlays = 0x8F000090; osInvalICache_recomp = 0x8F000094; +recomp_high_precision_fb_enabled = 0x8F0000A8; diff --git a/src/game/config.cpp b/src/game/config.cpp index 7c37d2a..af7c48f 100644 --- a/src/game/config.cpp +++ b/src/game/config.cpp @@ -24,6 +24,7 @@ constexpr auto api_default = ultramodern::GraphicsApi::Auto; constexpr auto ar_default = RT64::UserConfiguration::AspectRatio::Expand; constexpr auto msaa_default = RT64::UserConfiguration::Antialiasing::MSAA2X; constexpr auto rr_default = RT64::UserConfiguration::RefreshRate::Display; +constexpr auto hpfb_default = ultramodern::HighPrecisionFramebuffer::Auto; constexpr int ds_default = 1; constexpr int rr_manual_default = 60; constexpr bool developer_mode_default = false; @@ -93,6 +94,7 @@ namespace ultramodern { {"ar_option", config.ar_option}, {"msaa_option", config.msaa_option}, {"rr_option", config.rr_option}, + {"hpfb_option", config.hpfb_option}, {"rr_manual_value", config.rr_manual_value}, {"developer_mode", config.developer_mode}, }; @@ -107,6 +109,7 @@ namespace ultramodern { config.ar_option = from_or_default(j, "ar_option", ar_default); config.msaa_option = from_or_default(j, "msaa_option", msaa_default); config.rr_option = from_or_default(j, "rr_option", rr_default); + config.hpfb_option = from_or_default(j, "hpfb_option", hpfb_default); config.rr_manual_value = from_or_default(j, "rr_manual_value", rr_manual_default); config.developer_mode = from_or_default(j, "developer_mode", developer_mode_default); } @@ -245,6 +248,7 @@ void reset_graphics_options() { new_config.ar_option = ar_default; new_config.msaa_option = msaa_default; new_config.rr_option = rr_default; + new_config.hpfb_option = hpfb_default; new_config.rr_manual_value = rr_manual_default; new_config.developer_mode = developer_mode_default; ultramodern::set_graphics_config(new_config); diff --git a/src/game/recomp_api.cpp b/src/game/recomp_api.cpp index 84d7000..ef654b6 100644 --- a/src/game/recomp_api.cpp +++ b/src/game/recomp_api.cpp @@ -7,6 +7,7 @@ #include "recomp_ui.h" #include "recomp_sound.h" #include "recomp_helpers.h" +#include "rt64_layer.h" #include "../patches/input.h" #include "../patches/graphics.h" #include "../patches/sound.h" @@ -102,3 +103,7 @@ extern "C" void recomp_load_overlays(uint8_t * rdram, recomp_context * ctx) { load_overlays(rom, ram, size); } + +extern "C" void recomp_high_precision_fb_enabled(uint8_t * rdram, recomp_context * ctx) { + _return(ctx, static_cast(ultramodern::RT64HighPrecisionFBEnabled())); +} diff --git a/ultramodern/config.hpp b/ultramodern/config.hpp index 7d35eb3..2cd9ea3 100644 --- a/ultramodern/config.hpp +++ b/ultramodern/config.hpp @@ -27,6 +27,12 @@ namespace ultramodern { Vulkan, OptionCount }; + enum class HighPrecisionFramebuffer { + Auto, + On, + Off, + OptionCount + }; struct GraphicsConfig { Resolution res_option; @@ -36,6 +42,7 @@ namespace ultramodern { RT64::UserConfiguration::AspectRatio ar_option; RT64::UserConfiguration::Antialiasing msaa_option; RT64::UserConfiguration::RefreshRate rr_option; + HighPrecisionFramebuffer hpfb_option; int rr_manual_value; int ds_option; bool developer_mode; @@ -68,6 +75,12 @@ namespace ultramodern { {ultramodern::GraphicsApi::D3D12, "D3D12"}, {ultramodern::GraphicsApi::Vulkan, "Vulkan"}, }); + + NLOHMANN_JSON_SERIALIZE_ENUM(ultramodern::HighPrecisionFramebuffer, { + {ultramodern::HighPrecisionFramebuffer::Auto, "Auto"}, + {ultramodern::HighPrecisionFramebuffer::On, "On"}, + {ultramodern::HighPrecisionFramebuffer::Off, "Off"}, + }); }; #endif diff --git a/ultramodern/rt64_layer.cpp b/ultramodern/rt64_layer.cpp index 611e1eb..a1faa4e 100644 --- a/ultramodern/rt64_layer.cpp +++ b/ultramodern/rt64_layer.cpp @@ -11,6 +11,7 @@ ultramodern::RT64Context::~RT64Context() = default; static RT64::UserConfiguration::Antialiasing device_max_msaa = RT64::UserConfiguration::Antialiasing::None; static bool sample_positions_supported = false; +static bool high_precision_fb_enabled = false; static uint8_t DMEM[0x1000]; static uint8_t IMEM[0x1000]; @@ -58,6 +59,19 @@ RT64::UserConfiguration::Antialiasing compute_max_supported_aa(RT64::RenderSampl return RT64::UserConfiguration::Antialiasing::None; } +RT64::UserConfiguration::InternalColorFormat to_rt64(ultramodern::HighPrecisionFramebuffer option) { + switch (option) { + case ultramodern::HighPrecisionFramebuffer::Off: + return RT64::UserConfiguration::InternalColorFormat::Standard; + case ultramodern::HighPrecisionFramebuffer::On: + return RT64::UserConfiguration::InternalColorFormat::High; + case ultramodern::HighPrecisionFramebuffer::Auto: + return RT64::UserConfiguration::InternalColorFormat::Automatic; + default: + return RT64::UserConfiguration::InternalColorFormat::OptionCount; + } +} + void set_application_user_config(RT64::Application* application, const ultramodern::GraphicsConfig& config) { switch (config.res_option) { default: @@ -95,6 +109,7 @@ void set_application_user_config(RT64::Application* application, const ultramode application->userConfig.antialiasing = config.msaa_option; application->userConfig.refreshRate = config.rr_option; application->userConfig.refreshRateTarget = config.rr_manual_value; + application->userConfig.internalColorFormat = to_rt64(config.hpfb_option); } ultramodern::RT64SetupResult map_setup_result(RT64::Application::SetupResult rt64_result) { @@ -216,6 +231,8 @@ ultramodern::RT64Context::RT64Context(uint8_t* rdram, ultramodern::WindowHandle device_max_msaa = RT64::UserConfiguration::Antialiasing::None; sample_positions_supported = false; } + + high_precision_fb_enabled = app->shaderLibrary->usesHDR; } void ultramodern::RT64Context::send_dl(const OSTask* task) { @@ -278,3 +295,7 @@ RT64::UserConfiguration::Antialiasing ultramodern::RT64MaxMSAA() { bool ultramodern::RT64SamplePositionsSupported() { return sample_positions_supported; } + +bool ultramodern::RT64HighPrecisionFBEnabled() { + return high_precision_fb_enabled; +}