From 97d042a2e604cb40e408e8bbd806ecad2b86c1ef Mon Sep 17 00:00:00 2001 From: Musa Haji Date: Wed, 14 Aug 2024 01:44:16 -0400 Subject: [PATCH] darksouls: add tonemap blending, fix color grade not respecting peak by using upgradetonemap(), fix ui blending, remove film grain slider as game already has noise, use new hue correction code --- src/games/darksouls/addon.cpp | 50 +++--- .../darksouls/gamma_0xAB7CF260.ps_5_0.hlsl | 11 ++ src/games/darksouls/shared.h | 3 +- .../darksouls/tonemap_0xF87B3349.ps_5_0.hlsl | 149 +++++++++++------- src/games/darksouls/ui_0x64F62639.ps_5_0.hlsl | 12 +- src/games/darksouls/ui_0x809881A3.ps_5_0.hlsl | 12 +- src/games/darksouls/ui_0xB0850BF3.ps_5_0.hlsl | 12 +- .../darksouls/ui_text_0x6024AB96.ps_5_0.hlsl | 16 +- 8 files changed, 161 insertions(+), 104 deletions(-) diff --git a/src/games/darksouls/addon.cpp b/src/games/darksouls/addon.cpp index 592b26fe..b3c03a21 100644 --- a/src/games/darksouls/addon.cpp +++ b/src/games/darksouls/addon.cpp @@ -103,12 +103,25 @@ renodx::utils::settings::Settings settings = { new renodx::utils::settings::Setting{ .key = "toneMapHueCorrection", .binding = &shader_injection.toneMapHueCorrection, - .value_type = renodx::utils::settings::SettingValueType::BOOLEAN, - .default_value = 1, + .default_value = 100.f, .can_reset = false, .label = "Hue Correction", .section = "Tone Mapping", .tooltip = "Emulates hue shifting from the vanilla tonemapper", + .max = 100.f, + .is_enabled = []() { return shader_injection.toneMapType != 0; }, + .parse = [](float value) { return value * 0.01f; }, + }, + new renodx::utils::settings::Setting{ + .key = "toneMapBlend", + .binding = &shader_injection.toneMapBlend, + .value_type = renodx::utils::settings::SettingValueType::BOOLEAN, + .default_value = 1, + .can_reset = false, + .label = "Blend with Vanilla", + .section = "Tone Mapping", + .tooltip = "Blends the user selected tonemapper with vanilla", + .is_enabled = []() { return shader_injection.toneMapType != 0; }, }, new renodx::utils::settings::Setting{ .key = "colorGradeExposure", @@ -118,6 +131,7 @@ renodx::utils::settings::Settings settings = { .section = "Color Grading", .max = 20.f, .format = "%.2f", + .is_enabled = []() { return shader_injection.toneMapType != 0; }, }, new renodx::utils::settings::Setting{ .key = "colorGradeHighlights", @@ -126,6 +140,7 @@ renodx::utils::settings::Settings settings = { .label = "Highlights", .section = "Color Grading", .max = 100.f, + .is_enabled = []() { return shader_injection.toneMapType != 0; }, .parse = [](float value) { return value * 0.02f; }, }, new renodx::utils::settings::Setting{ @@ -135,6 +150,7 @@ renodx::utils::settings::Settings settings = { .label = "Shadows", .section = "Color Grading", .max = 100.f, + .is_enabled = []() { return shader_injection.toneMapType != 0; }, .parse = [](float value) { return value * 0.02f; }, }, new renodx::utils::settings::Setting{ @@ -144,6 +160,7 @@ renodx::utils::settings::Settings settings = { .label = "Contrast", .section = "Color Grading", .max = 100.f, + .is_enabled = []() { return shader_injection.toneMapType != 0; }, .parse = [](float value) { return value * 0.02f; }, }, new renodx::utils::settings::Setting{ @@ -153,16 +170,18 @@ renodx::utils::settings::Settings settings = { .label = "Saturation", .section = "Color Grading", .max = 100.f, + .is_enabled = []() { return shader_injection.toneMapType != 0; }, .parse = [](float value) { return value * 0.02f; }, }, new renodx::utils::settings::Setting{ .key = "colorGradeBlowout", .binding = &shader_injection.colorGradeBlowout, - .default_value = 70.f, + .default_value = 65.f, .label = "Blowout", .section = "Color Grading", .tooltip = "Controls highlight desaturation due to overexposure.", .max = 100.f, + .is_enabled = []() { return shader_injection.toneMapType == 3; }, .parse = [](float value) { return value * 0.01f; }, }, new renodx::utils::settings::Setting{ @@ -192,15 +211,6 @@ renodx::utils::settings::Settings settings = { .max = 100.f, .parse = [](float value) { return value * 0.02f; }, }, - new renodx::utils::settings::Setting{ - .key = "fxFilmGrain", - .binding = &shader_injection.fxFilmGrain, - .default_value = 0.f, - .label = "Film Grain", - .section = "Effects", - .max = 100.f, - .parse = [](float value) { return value * 0.02f; }, - }, }; void OnPresetOff() { @@ -222,19 +232,6 @@ void OnPresetOff() { renodx::utils::settings::UpdateSetting("fxFilmGrain", 0.f); } -auto start = std::chrono::steady_clock::now(); - -void OnPresent( - reshade::api::command_queue* queue, - reshade::api::swapchain* swapchain, - const reshade::api::rect* source_rect, - const reshade::api::rect* dest_rect, - uint32_t dirty_rect_count, - const reshade::api::rect* dirty_rects) { - auto end = std::chrono::steady_clock::now(); - shader_injection.elapsedTime = std::chrono::duration_cast(end - start).count(); -} - } // namespace // NOLINTBEGIN(readability-identifier-naming) @@ -274,12 +271,9 @@ BOOL APIENTRY DllMain(HMODULE h_module, DWORD fdw_reason, LPVOID lpv_reserved) { if (!reshade::register_addon(h_module)) return FALSE; - reshade::register_event(OnPresent); - break; case DLL_PROCESS_DETACH: reshade::unregister_addon(h_module); - reshade::unregister_event(OnPresent); break; } diff --git a/src/games/darksouls/gamma_0xAB7CF260.ps_5_0.hlsl b/src/games/darksouls/gamma_0xAB7CF260.ps_5_0.hlsl index b07f1e37..bac74db2 100644 --- a/src/games/darksouls/gamma_0xAB7CF260.ps_5_0.hlsl +++ b/src/games/darksouls/gamma_0xAB7CF260.ps_5_0.hlsl @@ -23,6 +23,17 @@ void main(float4 v0 o0.w = 1; o0.xyz = g_Texture.Sample(g_TextureSampler_s, v1.xy).xyz; + // linearize and scale paper white + float3 signs = sign(o0.rgb); + o0.rgb = abs(o0.rgb); + o0.rgb = (injectedData.toneMapGammaCorrection + ? pow(o0.rgb, 2.2f) + : renodx::color::bt709::from::SRGB(o0.rgb)); + o0.rgb *= signs; + o0.rgb *= injectedData.toneMapGameNits / 80.f; + + + // Removed gamma slider as it capped brightness // Image is unchanged when set to default 5 diff --git a/src/games/darksouls/shared.h b/src/games/darksouls/shared.h index 7623a041..363af6c8 100644 --- a/src/games/darksouls/shared.h +++ b/src/games/darksouls/shared.h @@ -14,6 +14,7 @@ struct ShaderInjectData { float toneMapUINits; float toneMapGammaCorrection; float toneMapHueCorrection; + float toneMapBlend; float colorGradeExposure; float colorGradeHighlights; float colorGradeShadows; @@ -23,8 +24,6 @@ struct ShaderInjectData { float colorGradeLUTStrength; float fxBloom; float fxDoF; - float fxFilmGrain; - float elapsedTime; }; #ifndef __cplusplus diff --git a/src/games/darksouls/tonemap_0xF87B3349.ps_5_0.hlsl b/src/games/darksouls/tonemap_0xF87B3349.ps_5_0.hlsl index d53fd499..65cb6b7a 100644 --- a/src/games/darksouls/tonemap_0xF87B3349.ps_5_0.hlsl +++ b/src/games/darksouls/tonemap_0xF87B3349.ps_5_0.hlsl @@ -96,12 +96,12 @@ void main(float4 v0 // Initial tonemapper settings, used in case 0 float vanillaMidGray = DL_FREG_054.z / DL_FREG_054.w; - float renoDRTContrast = 1.16f; + float renoDRTContrast = 1.2f; float renoDRTFlare = 0.f; float renoDRTShadows = 1.f; - float renoDRTDechroma = injectedData.colorGradeBlowout; float renoDRTSaturation = 1.3f; - float renoDRTHighlights = 1.04f; + float renoDRTHighlights = 1.f; + float3 vanillaColor; r0.xyz = gSMP_0.Sample(gSMP_0Sampler_s, v1.xy).xyz; r1.xyzw = gSMP_1.Sample(gSMP_1Sampler_s, v1.xy).wxyz; @@ -119,6 +119,7 @@ void main(float4 v0 float3 untonemapped = r0.xyz; + // switch case with multiple tonemappers, not sure when alternative tonemappers enable switch (r0.w) { case 0: // Vanilla tonemapper 0 r0.w = gSMP_5.Sample(gSMP_5Sampler_s, float2(0.5, 0.5)).x; @@ -126,8 +127,8 @@ void main(float4 v0 r0.w = min(DL_FREG_056.w, r0.w); r0.w = 9.99999975e-005 + r0.w; r0.w = DL_FREG_054.x / r0.w; - r2.xyz = r0.xyz * r0.www; - if (injectedData.toneMapType != 0) { // Custom tonemappers + r2.xyz = r0.xyz * r0.www; // exposure adjustment + if (injectedData.toneMapType != 0) { // untonemapped untonemapped = r2.xyz; } r0.w = DL_FREG_055.z * DL_FREG_055.y; // Start of tonemap 0 @@ -154,13 +155,12 @@ void main(float4 v0 r0.w = min(DL_FREG_056.w, r0.w); r0.w = 9.99999975e-005 + r0.w; r0.w = DL_FREG_054.x / r0.w; - r2.xyz = r0.xyz * r0.www; - if (injectedData.toneMapType != 0) { // Custom tonemappers + r2.xyz = r0.xyz * r0.www; // exposure adjustment + if (injectedData.toneMapType != 0) { // RenoDRT parameters + untonemapped vanillaMidGray = .15f; renoDRTContrast = 0.92f; renoDRTFlare = 0.f; renoDRTShadows = 1.f; - // renoDRTDechroma = 0.7f; renoDRTSaturation = 1.3f; renoDRTHighlights = 1.f; untonemapped = r2.xyz; @@ -180,13 +180,12 @@ void main(float4 v0 r0.w = min(DL_FREG_056.w, r0.w); r0.w = 9.99999975e-005 + r0.w; r0.w = DL_FREG_054.x / r0.w; - r0.xyz = r0.xyz * r0.www; - if (injectedData.toneMapType != 0) { // Custom tonemappers + r0.xyz = r0.xyz * r0.www; // exposure adjustment + if (injectedData.toneMapType != 0) { // RenoDRT parameters + untonemapped vanillaMidGray = .151f; renoDRTContrast = 0.94f; renoDRTFlare = 0.f; renoDRTShadows = 1.f; - // renoDRTDechroma = 0.7f; renoDRTSaturation = 1.3f; renoDRTHighlights = 1.f; untonemapped = r0.xyz; @@ -209,40 +208,84 @@ void main(float4 v0 break; } + float3 hdrColor; + float3 sdrColor; if (injectedData.toneMapType != 0) { - float3 tonemapped = renodx::tonemap::config::Apply( - untonemapped, - renodx::tonemap::config::Create( - injectedData.toneMapType, - injectedData.toneMapPeakNits, - injectedData.toneMapGameNits, - injectedData.toneMapGammaCorrection, - injectedData.colorGradeExposure, - injectedData.colorGradeHighlights, - injectedData.colorGradeShadows, - injectedData.colorGradeContrast, - injectedData.colorGradeSaturation, - vanillaMidGray, - vanillaMidGray * 100.f, - renoDRTHighlights, - renoDRTShadows, - renoDRTContrast, - renoDRTSaturation, - renoDRTDechroma, - renoDRTFlare)); - if (injectedData.toneMapHueCorrection) { - r1.xyz = renodx::color::correct::Hue(tonemapped, r1.xyz); - } else { - r1.xyz = tonemapped; + vanillaColor = r1.xyz; // vanilla tonemap, used for hue correction + + renodx::tonemap::Config hdrConfig = renodx::tonemap::config::Create(); + hdrConfig.type = injectedData.toneMapType; + hdrConfig.peak_nits = injectedData.toneMapPeakNits; + hdrConfig.game_nits = injectedData.toneMapGameNits; + hdrConfig.gamma_correction = injectedData.toneMapGammaCorrection - 1; + hdrConfig.exposure = injectedData.colorGradeExposure; + hdrConfig.highlights = injectedData.colorGradeHighlights; + hdrConfig.shadows = injectedData.colorGradeShadows; + hdrConfig.contrast = injectedData.colorGradeContrast; + hdrConfig.saturation = injectedData.colorGradeSaturation; + hdrConfig.hue_correction_type = renodx::tonemap::config::hue_correction_type::CUSTOM; + hdrConfig.hue_correction_color = vanillaColor, + hdrConfig.hue_correction_strength = injectedData.toneMapHueCorrection; + hdrConfig.reno_drt_highlights = renoDRTHighlights; + hdrConfig.reno_drt_shadows = renoDRTShadows; + hdrConfig.reno_drt_contrast = renoDRTContrast; + hdrConfig.reno_drt_saturation = renoDRTSaturation; + hdrConfig.reno_drt_dechroma = injectedData.colorGradeBlowout; + hdrConfig.mid_gray_value = vanillaMidGray; + hdrConfig.mid_gray_nits = vanillaMidGray * 100.f; + hdrConfig.reno_drt_flare = renoDRTFlare; + + // don't allow for double adjustment of color grading when blending is on + if (injectedData.toneMapBlend) { + hdrConfig.exposure = 1.f; + hdrConfig.shadows = 1.f; + hdrConfig.contrast = 1.f; + hdrConfig.saturation = 1.f; } - } else { // Clamp vanilla tonemapper to BT709 - r0.xyz = max(0, r1.xyz); + + renodx::tonemap::Config sdrConfig = hdrConfig; + sdrConfig.peak_nits = injectedData.toneMapGameNits; + + hdrColor = renodx::tonemap::config::Apply(untonemapped, hdrConfig); + sdrColor = renodx::tonemap::config::Apply(untonemapped, sdrConfig); + + // blend custom tonemapper with vanilla by channel + if (injectedData.toneMapBlend) { + float3 negHDR = min(0, hdrColor); + sdrColor = lerp(saturate(vanillaColor), max(0, sdrColor), saturate(vanillaColor)); + hdrColor += negHDR; + + negHDR = min(0, hdrColor); + hdrColor = lerp(saturate(vanillaColor), max(0, hdrColor), saturate(vanillaColor)); + hdrColor += negHDR; + + // apply color grading post-blend + sdrColor = renodx::color::grade::UserColorGrading( + sdrColor, + injectedData.colorGradeExposure, + 1.f, + injectedData.colorGradeShadows, + injectedData.colorGradeContrast, + injectedData.colorGradeSaturation); + hdrColor = renodx::color::grade::UserColorGrading( + hdrColor, + injectedData.colorGradeExposure, + 1.f, + injectedData.colorGradeShadows, + injectedData.colorGradeContrast, + injectedData.colorGradeSaturation); + + } + r1.xyz = sdrColor; + + sdrColor = sign(sdrColor) * pow(abs(sdrColor), 1.f / 2.2f); + hdrColor = sign(hdrColor) * pow(abs(hdrColor), 1.f / 2.2f); } - r0.xyz = sign(r1.xyz) * pow(abs(r1.xyz), 1.f / 2.2f); // Linearize before color grade + r0.xyz = sign(r1.xyz) * pow(abs(r1.xyz), 1.f / 2.2f); // color grade in gamma space - const float3 preLUT = r0.xyz; + const float3 colorGradeInput = r0.xyz; r0.w = 1; r1.x = dot(r0.xyzw, DL_FREG_062._m00_m10_m20_m30); @@ -261,31 +304,17 @@ void main(float4 v0 r0.xyz = r2.xyz * r0.xyz; r0.xyz = r3.xyz * r4.xyz + r0.xyz; r0.xyz = r0.xyz + -r1.xyz; - // r0.xyz = DL_FREG_068.xxx * r0.xyz + r1.xyz; - // DL_FREG_068.xxx = noise - r0.xyz = - lerp(preLUT + DL_FREG_068.xxx * r0.xyz, DL_FREG_068.xxx * r0.xyz + r1.xyz, - injectedData.colorGradeLUTStrength); - - if (injectedData.fxFilmGrain) { - float3 grainedColor = renodx::effects::ApplyFilmGrain( - r0.rgb, v1.xy, frac(injectedData.elapsedTime / 1000.f), - injectedData.fxFilmGrain * 0.03f, 1.f); - r0.xyz = grainedColor; - } + r0.xyz = DL_FREG_068.xxx * r0.xyz + r1.xyz; - if (injectedData.toneMapType == 0) { // Cap vanilla tonemapper + if (injectedData.toneMapType == 0) { + r0.xyz = lerp(colorGradeInput, r0.xyz, injectedData.colorGradeLUTStrength); r0.xyz = clamp(r0.xyz, 0, injectedData.toneMapPeakNits / injectedData.toneMapGameNits); + } else { + // apply color grade to SDR tonemapped image and apply difference to HDR + // color filter will now respect peak brightness + r0.xyz = renodx::tonemap::UpgradeToneMap(hdrColor, sdrColor, r0.xyz, injectedData.colorGradeLUTStrength); } - r0.rgb = injectedData.toneMapGammaCorrection - ? sign(r0.rgb) * pow(abs(r0.rgb), 2.2f) - : renodx::color::bt709::from::SRGB(r0.rgb); - - r0.rgb *= injectedData.toneMapGameNits / 80.f; - - r0.rgb = renodx::color::bt709::clamp::BT2020(r0.rgb); - o0.w = dot(r0.xyz, float3(0.298999995, 0.587000012, 0.114)); o0.xyz = r0.xyz; return; diff --git a/src/games/darksouls/ui_0x64F62639.ps_5_0.hlsl b/src/games/darksouls/ui_0x64F62639.ps_5_0.hlsl index 9af5f238..281e3d9b 100644 --- a/src/games/darksouls/ui_0x64F62639.ps_5_0.hlsl +++ b/src/games/darksouls/ui_0x64F62639.ps_5_0.hlsl @@ -12,9 +12,15 @@ void main(float4 v0 : SV_Target0) { o0.xyzw = v1.xyzw; - o0.rgb = injectedData.toneMapGammaCorrection ? pow(o0.rgb, 2.2f) - : renodx::color::bt709::from::SRGB(o0.rgb); - o0.rgb *= injectedData.toneMapUINits / 80.f; + o0.xyz = saturate(o0.xyz); + // allow for brightness adjustment while preserving UI blending in gamma space + if (injectedData.toneMapUINits != injectedData.toneMapGameNits) { + o0.rgb = injectedData.toneMapGammaCorrection ? pow(o0.rgb, 2.2f) + : renodx::color::bt709::from::SRGB(o0.rgb); + o0.rgb *= injectedData.toneMapUINits / injectedData.toneMapGameNits; + o0.rgb = injectedData.toneMapGammaCorrection ? pow(o0.rgb, 1.f / 2.2f) + : renodx::color::srgb::from::BT709(o0.rgb); + } return; } \ No newline at end of file diff --git a/src/games/darksouls/ui_0x809881A3.ps_5_0.hlsl b/src/games/darksouls/ui_0x809881A3.ps_5_0.hlsl index 1ac64bf3..351a030b 100644 --- a/src/games/darksouls/ui_0x809881A3.ps_5_0.hlsl +++ b/src/games/darksouls/ui_0x809881A3.ps_5_0.hlsl @@ -20,9 +20,15 @@ void main(float4 v0 r0.xyzw = g_Texture.Sample(g_TextureSampler_s, v2.xy).xyzw; o0.xyzw = v1.xyzw * r0.xyzw; - o0.rgb = injectedData.toneMapGammaCorrection ? pow(o0.rgb, 2.2f) - : renodx::color::bt709::from::SRGB(o0.rgb); - o0.rgb *= injectedData.toneMapUINits / 80.f; + o0.xyz = saturate(o0.xyz); + // allow for brightness adjustment while preserving UI blending in gamma space + if (injectedData.toneMapUINits != injectedData.toneMapGameNits) { + o0.rgb = injectedData.toneMapGammaCorrection ? pow(o0.rgb, 2.2f) + : renodx::color::bt709::from::SRGB(o0.rgb); + o0.rgb *= injectedData.toneMapUINits / injectedData.toneMapGameNits; + o0.rgb = injectedData.toneMapGammaCorrection ? pow(o0.rgb, 1.f / 2.2f) + : renodx::color::srgb::from::BT709(o0.rgb); + } return; } \ No newline at end of file diff --git a/src/games/darksouls/ui_0xB0850BF3.ps_5_0.hlsl b/src/games/darksouls/ui_0xB0850BF3.ps_5_0.hlsl index 11811db7..937206ba 100644 --- a/src/games/darksouls/ui_0xB0850BF3.ps_5_0.hlsl +++ b/src/games/darksouls/ui_0xB0850BF3.ps_5_0.hlsl @@ -12,9 +12,15 @@ void main(float4 v0 : SV_Target0) { o0.xyzw = v1.xyzw; - o0.rgb = injectedData.toneMapGammaCorrection ? pow(o0.rgb, 2.2f) - : renodx::color::bt709::from::SRGB(o0.rgb); - o0.rgb *= injectedData.toneMapUINits / 80.f; + o0.xyz = saturate(o0.xyz); + // allow for brightness adjustment while preserving UI blending in gamma space + if (injectedData.toneMapUINits != injectedData.toneMapGameNits) { + o0.rgb = injectedData.toneMapGammaCorrection ? pow(o0.rgb, 2.2f) + : renodx::color::bt709::from::SRGB(o0.rgb); + o0.rgb *= injectedData.toneMapUINits / injectedData.toneMapGameNits; + o0.rgb = injectedData.toneMapGammaCorrection ? pow(o0.rgb, 1.f / 2.2f) + : renodx::color::srgb::from::BT709(o0.rgb); + } // TODO: figure out what this shader does // o0.rgb = (1, 0, 1); diff --git a/src/games/darksouls/ui_text_0x6024AB96.ps_5_0.hlsl b/src/games/darksouls/ui_text_0x6024AB96.ps_5_0.hlsl index 75027498..54463d63 100644 --- a/src/games/darksouls/ui_text_0x6024AB96.ps_5_0.hlsl +++ b/src/games/darksouls/ui_text_0x6024AB96.ps_5_0.hlsl @@ -36,11 +36,17 @@ void main(float4 v0 r2.xyzw = g_Texture.Sample(g_TextureSampler_s, v4.zw).xyzw; r0.xyzw = -r2.xyzw + r0.xyzw; r0.xyzw = r0.xyzw * gFC_FontSharpParam.xxxx + r1.xyzw; - o0.xyzw = saturate(v1.xyzw * r0.xyzw); // Added saturate() to cap text brightness - - o0.rgb = injectedData.toneMapGammaCorrection ? pow(o0.rgb, 2.2f) - : renodx::color::bt709::from::SRGB(o0.rgb); - o0.rgb *= injectedData.toneMapUINits / 80.f; + o0.xyzw = v1.xyzw * r0.xyzw; + + o0.xyzw = saturate(o0.xyzw); // clamping text requires clamping alpha for some reason + // allow for brightness adjustment while preserving UI blending in gamma space + if (injectedData.toneMapUINits != injectedData.toneMapGameNits) { + o0.rgb = injectedData.toneMapGammaCorrection ? pow(o0.rgb, 2.2f) + : renodx::color::bt709::from::SRGB(o0.rgb); + o0.rgb *= injectedData.toneMapUINits / injectedData.toneMapGameNits; + o0.rgb = injectedData.toneMapGammaCorrection ? pow(o0.rgb, 1.f / 2.2f) + : renodx::color::srgb::from::BT709(o0.rgb); + } return; } \ No newline at end of file