From ba6febece2fb701d99731ec76028efadc452fc57 Mon Sep 17 00:00:00 2001 From: Skyth <19259897+blueskythlikesclouds@users.noreply.github.com> Date: Sat, 7 Dec 2024 23:34:53 +0300 Subject: [PATCH] Implement proper DoF weighting & add quality options. Co-authored-by: Dario --- UnleashedRecomp/CMakeLists.txt | 5 +- ...ssian_blur_ps.hlsl => gaussian_blur.hlsli} | 51 ++++++----- .../gpu/shader/gaussian_blur_3x3.hlsl | 2 + .../gpu/shader/gaussian_blur_5x5.hlsl | 2 + .../gpu/shader/gaussian_blur_7x7.hlsl | 2 + .../gpu/shader/gaussian_blur_9x9.hlsl | 2 + UnleashedRecomp/gpu/video.cpp | 84 ++++++++++++++++--- UnleashedRecomp/locale/config_locale.h | 19 +++++ UnleashedRecomp/ui/options_menu.cpp | 1 + UnleashedRecomp/user/config.h | 1 + UnleashedRecomp/user/config_detail.h | 18 ++++ 11 files changed, 154 insertions(+), 33 deletions(-) rename UnleashedRecomp/gpu/shader/{gaussian_blur_ps.hlsl => gaussian_blur.hlsli} (59%) create mode 100644 UnleashedRecomp/gpu/shader/gaussian_blur_3x3.hlsl create mode 100644 UnleashedRecomp/gpu/shader/gaussian_blur_5x5.hlsl create mode 100644 UnleashedRecomp/gpu/shader/gaussian_blur_7x7.hlsl create mode 100644 UnleashedRecomp/gpu/shader/gaussian_blur_9x9.hlsl diff --git a/UnleashedRecomp/CMakeLists.txt b/UnleashedRecomp/CMakeLists.txt index c268677a..50459d3d 100644 --- a/UnleashedRecomp/CMakeLists.txt +++ b/UnleashedRecomp/CMakeLists.txt @@ -284,7 +284,10 @@ function(compile_pixel_shader FILE_PATH) endfunction() compile_vertex_shader(copy_vs) -compile_pixel_shader(gaussian_blur_ps) +compile_pixel_shader(gaussian_blur_3x3) +compile_pixel_shader(gaussian_blur_5x5) +compile_pixel_shader(gaussian_blur_7x7) +compile_pixel_shader(gaussian_blur_9x9) compile_pixel_shader(gamma_correction_ps) compile_pixel_shader(imgui_ps) compile_vertex_shader(imgui_vs) diff --git a/UnleashedRecomp/gpu/shader/gaussian_blur_ps.hlsl b/UnleashedRecomp/gpu/shader/gaussian_blur.hlsli similarity index 59% rename from UnleashedRecomp/gpu/shader/gaussian_blur_ps.hlsl rename to UnleashedRecomp/gpu/shader/gaussian_blur.hlsli index e9303a03..2e24dcda 100644 --- a/UnleashedRecomp/gpu/shader/gaussian_blur_ps.hlsl +++ b/UnleashedRecomp/gpu/shader/gaussian_blur.hlsli @@ -28,33 +28,44 @@ cbuffer SharedConstants : register(b2, space4) #endif +#ifdef __INTELLISENSE__ +#define KERNEL_SIZE 5 +#endif + +#define PI 3.14159265358979323846 + +float ComputeWeight(float x) +{ + float std = 0.952; + return exp(-(x * x) / (2.0 * std * std)) / (std * sqrt(2.0 * PI)); +} + float4 main(in float4 iPosition : SV_Position, in float4 iTexCoord0 : TEXCOORD0) : SV_Target { Texture2D texture = g_Texture2DDescriptorHeap[s0_Texture2DDescriptorIndex]; SamplerState samplerState = g_SamplerDescriptorHeap[s0_SamplerDescriptorIndex]; - float scaleFactor = g_ViewportSize.y / 360.0; + float scale = g_ViewportSize.y / 360.0; - float2 offsets[5]; - offsets[0] = g_offsets(0).xy * scaleFactor; - offsets[2] = g_offsets(0).zw * scaleFactor; - offsets[4] = g_offsets(1).xy * scaleFactor; + float2 offsets[3]; + offsets[0] = g_offsets(0).xy * scale; + offsets[1] = g_offsets(0).zw * scale; + offsets[2] = g_offsets(1).xy * scale; - offsets[1] = lerp(offsets[2], offsets[0], 0.5); - offsets[3] = lerp(offsets[2], offsets[4], 0.5); + float4 color = 0.0; + float weightSum = 0.0; - float weights[5]; - weights[0] = 0.1131226076; - weights[1] = 0.2360540033; - weights[2] = 0.3016467782; - weights[3] = 0.2360540033; - weights[4] = 0.1131226076; - - float4 c0 = texture.Sample(samplerState, iTexCoord0.xy + offsets[0]) * weights[0]; - float4 c1 = texture.Sample(samplerState, iTexCoord0.xy + offsets[1]) * weights[1]; - float4 c2 = texture.Sample(samplerState, iTexCoord0.xy + offsets[2]) * weights[2]; - float4 c3 = texture.Sample(samplerState, iTexCoord0.xy + offsets[3]) * weights[3]; - float4 c4 = texture.Sample(samplerState, iTexCoord0.xy + offsets[4]) * weights[4]; + [unroll] + for (int i = 0; i < KERNEL_SIZE; i++) + { + float step = i / float(KERNEL_SIZE - 1); + float scaled = step * 2; + float2 offset = lerp(offsets[int(scaled)], offsets[min(int(scaled) + 1, 2)], frac(scaled)); + float offsetScale = 1.0 / 0.75; + float weight = ComputeWeight(lerp(-offsetScale, offsetScale, step)); + color += texture.Sample(samplerState, iTexCoord0.xy + offset) * weight; + weightSum += weight; + } - return c0 + c1 + c2 + c3 + c4; + return color / weightSum; } diff --git a/UnleashedRecomp/gpu/shader/gaussian_blur_3x3.hlsl b/UnleashedRecomp/gpu/shader/gaussian_blur_3x3.hlsl new file mode 100644 index 00000000..9ad09068 --- /dev/null +++ b/UnleashedRecomp/gpu/shader/gaussian_blur_3x3.hlsl @@ -0,0 +1,2 @@ +#define KERNEL_SIZE 3 +#include "gaussian_blur.hlsli" diff --git a/UnleashedRecomp/gpu/shader/gaussian_blur_5x5.hlsl b/UnleashedRecomp/gpu/shader/gaussian_blur_5x5.hlsl new file mode 100644 index 00000000..727d2bf8 --- /dev/null +++ b/UnleashedRecomp/gpu/shader/gaussian_blur_5x5.hlsl @@ -0,0 +1,2 @@ +#define KERNEL_SIZE 5 +#include "gaussian_blur.hlsli" diff --git a/UnleashedRecomp/gpu/shader/gaussian_blur_7x7.hlsl b/UnleashedRecomp/gpu/shader/gaussian_blur_7x7.hlsl new file mode 100644 index 00000000..6aad31b1 --- /dev/null +++ b/UnleashedRecomp/gpu/shader/gaussian_blur_7x7.hlsl @@ -0,0 +1,2 @@ +#define KERNEL_SIZE 7 +#include "gaussian_blur.hlsli" diff --git a/UnleashedRecomp/gpu/shader/gaussian_blur_9x9.hlsl b/UnleashedRecomp/gpu/shader/gaussian_blur_9x9.hlsl new file mode 100644 index 00000000..98c9a847 --- /dev/null +++ b/UnleashedRecomp/gpu/shader/gaussian_blur_9x9.hlsl @@ -0,0 +1,2 @@ +#define KERNEL_SIZE 9 +#include "gaussian_blur.hlsli" diff --git a/UnleashedRecomp/gpu/video.cpp b/UnleashedRecomp/gpu/video.cpp index 31a8691b..73bd0b7b 100644 --- a/UnleashedRecomp/gpu/video.cpp +++ b/UnleashedRecomp/gpu/video.cpp @@ -34,8 +34,14 @@ #include "../../thirdparty/ShaderRecomp/ShaderRecomp/shader_common.h" #include "shader/copy_vs.hlsl.dxil.h" #include "shader/copy_vs.hlsl.spirv.h" -#include "shader/gaussian_blur_ps.hlsl.dxil.h" -#include "shader/gaussian_blur_ps.hlsl.spirv.h" +#include "shader/gaussian_blur_3x3.hlsl.dxil.h" +#include "shader/gaussian_blur_3x3.hlsl.spirv.h" +#include "shader/gaussian_blur_5x5.hlsl.dxil.h" +#include "shader/gaussian_blur_5x5.hlsl.spirv.h" +#include "shader/gaussian_blur_7x7.hlsl.dxil.h" +#include "shader/gaussian_blur_7x7.hlsl.spirv.h" +#include "shader/gaussian_blur_9x9.hlsl.dxil.h" +#include "shader/gaussian_blur_9x9.hlsl.spirv.h" #include "shader/gamma_correction_ps.hlsl.dxil.h" #include "shader/gamma_correction_ps.hlsl.spirv.h" #include "shader/imgui_ps.hlsl.dxil.h" @@ -1026,7 +1032,17 @@ static const std::pair g_setRenderStateFunctions[] = }; static std::unique_ptr g_resolveMsaaDepthPipelines[3]; -static std::unique_ptr g_gaussianBlurShader; + +enum +{ + GAUSSIAN_BLUR_3X3, + GAUSSIAN_BLUR_5X5, + GAUSSIAN_BLUR_7X7, + GAUSSIAN_BLUR_9X9, + GAUSSIAN_BLUR_COUNT +}; + +static std::unique_ptr g_gaussianBlurShaders[GAUSSIAN_BLUR_COUNT]; #define CREATE_SHADER(NAME) \ g_device->createShader( \ @@ -1419,8 +1435,13 @@ void Video::CreateHostDevice() g_resolveMsaaDepthPipelines[i] = g_device->createGraphicsPipeline(desc); } - g_gaussianBlurShader = std::make_unique(ResourceType::PixelShader); - g_gaussianBlurShader->shader = CREATE_SHADER(gaussian_blur_ps); + for (auto& shader : g_gaussianBlurShaders) + shader = std::make_unique(ResourceType::PixelShader); + + g_gaussianBlurShaders[GAUSSIAN_BLUR_3X3]->shader = CREATE_SHADER(gaussian_blur_3x3); + g_gaussianBlurShaders[GAUSSIAN_BLUR_5X5]->shader = CREATE_SHADER(gaussian_blur_5x5); + g_gaussianBlurShaders[GAUSSIAN_BLUR_7X7]->shader = CREATE_SHADER(gaussian_blur_7x7); + g_gaussianBlurShaders[GAUSSIAN_BLUR_9X9]->shader = CREATE_SHADER(gaussian_blur_9x9); CreateImGuiBackend(); @@ -3842,12 +3863,6 @@ static GuestShader* CreatePixelShader(const be* function) static void SetPixelShader(GuestDevice* device, GuestShader* shader) { - if (shader != nullptr && shader->shaderCacheEntry != nullptr && shader->shaderCacheEntry->hash == 0x4294510C775F4EE8) - { - if (!(GetAsyncKeyState(VK_F4) & 0x8000)) - shader = g_gaussianBlurShader.get(); - } - RenderCommand cmd; cmd.type = RenderCommandType::SetPixelShader; cmd.setPixelShader.shader = shader; @@ -3856,7 +3871,52 @@ static void SetPixelShader(GuestDevice* device, GuestShader* shader) static void ProcSetPixelShader(const RenderCommand& cmd) { - SetDirtyValue(g_dirtyStates.pipelineState, g_pipelineState.pixelShader, cmd.setPixelShader.shader); + GuestShader* shader = cmd.setPixelShader.shader; + if (shader != nullptr && + shader->shaderCacheEntry != nullptr && + shader->shaderCacheEntry->hash == 0x4294510C775F4EE8) + { + size_t shaderIndex = GAUSSIAN_BLUR_3X3; + + switch (Config::DepthOfFieldQuality) + { + case EDepthOfFieldQuality::Low: + shaderIndex = GAUSSIAN_BLUR_3X3; + break; + + case EDepthOfFieldQuality::Medium: + shaderIndex = GAUSSIAN_BLUR_5X5; + break; + + case EDepthOfFieldQuality::High: + shaderIndex = GAUSSIAN_BLUR_7X7; + break; + + case EDepthOfFieldQuality::Ultra: + shaderIndex = GAUSSIAN_BLUR_9X9; + break; + + default: + { + size_t height = round(g_swapChain->getHeight() * Config::ResolutionScale); + + if (height >= 2160) + shaderIndex = GAUSSIAN_BLUR_9X9; + else if (height >= 1440) + shaderIndex = GAUSSIAN_BLUR_7X7; + else if (height >= 1080) + shaderIndex = GAUSSIAN_BLUR_5X5; + else + shaderIndex = GAUSSIAN_BLUR_3X3; + + break; + } + } + + shader = g_gaussianBlurShaders[shaderIndex].get(); + } + + SetDirtyValue(g_dirtyStates.pipelineState, g_pipelineState.pixelShader, shader); } static std::thread g_renderThread([] diff --git a/UnleashedRecomp/locale/config_locale.h b/UnleashedRecomp/locale/config_locale.h index 86fced1b..0c8382d8 100644 --- a/UnleashedRecomp/locale/config_locale.h +++ b/UnleashedRecomp/locale/config_locale.h @@ -309,6 +309,25 @@ CONFIG_DEFINE_ENUM_LOCALE(EGITextureFiltering) } }; +CONFIG_DEFINE_LOCALE(DepthOfFieldQuality) +{ + { ELanguage::English, { "Depth of Field Quality", "[PLACEHOLDER]" } } +}; + +CONFIG_DEFINE_ENUM_LOCALE(EDepthOfFieldQuality) +{ + { + ELanguage::English, + { + { EDepthOfFieldQuality::Auto, { "AUTO", "" } }, + { EDepthOfFieldQuality::Low, { "LOW", "" } }, + { EDepthOfFieldQuality::Medium, { "MEDIUM", "" } }, + { EDepthOfFieldQuality::High, { "HIGH", "" } }, + { EDepthOfFieldQuality::Ultra, { "ULTRA", "" } }, + } + } +}; + CONFIG_DEFINE_LOCALE(MotionBlur) { { ELanguage::English, { "Motion Blur", "Use per-object motion blur and radial blur." } } diff --git a/UnleashedRecomp/ui/options_menu.cpp b/UnleashedRecomp/ui/options_menu.cpp index 86c43291..4dd1ecf2 100644 --- a/UnleashedRecomp/ui/options_menu.cpp +++ b/UnleashedRecomp/ui/options_menu.cpp @@ -813,6 +813,7 @@ static void DrawConfigOptions() DrawConfigOption(rowCount++, yOffset, &Config::TransparencyAntiAliasing, Config::AntiAliasing != EAntiAliasing::None, &Localise("Options_Desc_NotAvailableMSAA")); DrawConfigOption(rowCount++, yOffset, &Config::ShadowResolution, true); DrawConfigOption(rowCount++, yOffset, &Config::GITextureFiltering, true); + DrawConfigOption(rowCount++, yOffset, &Config::DepthOfFieldQuality, true); DrawConfigOption(rowCount++, yOffset, &Config::MotionBlur, true); DrawConfigOption(rowCount++, yOffset, &Config::XboxColourCorrection, true); DrawConfigOption(rowCount++, yOffset, &Config::MovieScaleMode, true); diff --git a/UnleashedRecomp/user/config.h b/UnleashedRecomp/user/config.h index 44a14e62..d3e82412 100644 --- a/UnleashedRecomp/user/config.h +++ b/UnleashedRecomp/user/config.h @@ -63,6 +63,7 @@ public: CONFIG_DEFINE("Video", size_t, AnisotropicFiltering, 16); CONFIG_DEFINE_ENUM_LOCALISED("Video", EShadowResolution, ShadowResolution, EShadowResolution::x4096); CONFIG_DEFINE_ENUM_LOCALISED("Video", EGITextureFiltering, GITextureFiltering, EGITextureFiltering::Bicubic); + CONFIG_DEFINE_ENUM_LOCALISED("Video", EDepthOfFieldQuality, DepthOfFieldQuality, EDepthOfFieldQuality::Auto); CONFIG_DEFINE_LOCALISED("Video", bool, MotionBlur, true); CONFIG_DEFINE_LOCALISED("Video", bool, XboxColourCorrection, false); CONFIG_DEFINE_ENUM_LOCALISED("Video", EMovieScaleMode, MovieScaleMode, EMovieScaleMode::Fit); diff --git a/UnleashedRecomp/user/config_detail.h b/UnleashedRecomp/user/config_detail.h index 4966f687..9b52aa8d 100644 --- a/UnleashedRecomp/user/config_detail.h +++ b/UnleashedRecomp/user/config_detail.h @@ -192,6 +192,24 @@ CONFIG_DEFINE_ENUM_TEMPLATE(EGITextureFiltering) { "Bicubic", EGITextureFiltering::Bicubic } }; +enum class EDepthOfFieldQuality : uint32_t +{ + Auto, + Low, + Medium, + High, + Ultra +}; + +CONFIG_DEFINE_ENUM_TEMPLATE(EDepthOfFieldQuality) +{ + { "Auto", EDepthOfFieldQuality::Auto }, + { "Low", EDepthOfFieldQuality::Low }, + { "Medium", EDepthOfFieldQuality::Medium }, + { "High", EDepthOfFieldQuality::High }, + { "Ultra", EDepthOfFieldQuality::Ultra } +}; + enum class EMovieScaleMode : uint32_t { Stretch,