Implement proper DoF weighting & add quality options.

Co-authored-by: Dario <dariosamo@gmail.com>
This commit is contained in:
Skyth 2024-12-07 23:34:53 +03:00
parent 27b7812215
commit ba6febece2
11 changed files with 154 additions and 33 deletions

View file

@ -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)

View file

@ -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<float4> 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;
}

View file

@ -0,0 +1,2 @@
#define KERNEL_SIZE 3
#include "gaussian_blur.hlsli"

View file

@ -0,0 +1,2 @@
#define KERNEL_SIZE 5
#include "gaussian_blur.hlsli"

View file

@ -0,0 +1,2 @@
#define KERNEL_SIZE 7
#include "gaussian_blur.hlsli"

View file

@ -0,0 +1,2 @@
#define KERNEL_SIZE 9
#include "gaussian_blur.hlsli"

View file

@ -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<GuestRenderState, void*> g_setRenderStateFunctions[] =
};
static std::unique_ptr<RenderPipeline> g_resolveMsaaDepthPipelines[3];
static std::unique_ptr<GuestShader> g_gaussianBlurShader;
enum
{
GAUSSIAN_BLUR_3X3,
GAUSSIAN_BLUR_5X5,
GAUSSIAN_BLUR_7X7,
GAUSSIAN_BLUR_9X9,
GAUSSIAN_BLUR_COUNT
};
static std::unique_ptr<GuestShader> 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<GuestShader>(ResourceType::PixelShader);
g_gaussianBlurShader->shader = CREATE_SHADER(gaussian_blur_ps);
for (auto& shader : g_gaussianBlurShaders)
shader = std::make_unique<GuestShader>(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<uint32_t>* 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([]

View file

@ -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." } }

View file

@ -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);

View file

@ -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);

View file

@ -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,