diff --git a/MarathonRecomp/CMakeLists.txt b/MarathonRecomp/CMakeLists.txt index 341971e35..500513415 100644 --- a/MarathonRecomp/CMakeLists.txt +++ b/MarathonRecomp/CMakeLists.txt @@ -483,7 +483,8 @@ compile_pixel_shader(copy_depth_ps) compile_pixel_shader(csd_filter_ps) compile_vertex_shader(csd_no_tex_vs) compile_vertex_shader(csd_vs) -compile_pixel_shader(enhanced_motion_blur_ps) +compile_vertex_shader(enhanced_burnout_blur_vs) +compile_pixel_shader(enhanced_burnout_blur_ps) compile_pixel_shader(gaussian_blur_3x3) compile_pixel_shader(gaussian_blur_5x5) compile_pixel_shader(gaussian_blur_7x7) diff --git a/MarathonRecomp/gpu/shader/hlsl/enhanced_burnout_blur_ps.hlsl b/MarathonRecomp/gpu/shader/hlsl/enhanced_burnout_blur_ps.hlsl new file mode 100644 index 000000000..c752487ff --- /dev/null +++ b/MarathonRecomp/gpu/shader/hlsl/enhanced_burnout_blur_ps.hlsl @@ -0,0 +1,51 @@ +#include "../../../../tools/XenosRecomp/XenosRecomp/shader_common.h" + +#ifdef __spirv__ + +#define s0_Texture2DDescriptorIndex vk::RawBufferLoad(g_PushConstants.SharedConstants + 0) +#define s0_SamplerDescriptorIndex vk::RawBufferLoad(g_PushConstants.SharedConstants + 192) + +#else + +cbuffer SharedConstants : register(b2, space4) +{ + uint s0_Texture2DDescriptorIndex : packoffset(c0.x); + uint s0_SamplerDescriptorIndex : packoffset(c12.x); + DEFINE_SHARED_CONSTANTS(); +}; + +#endif + +float4 shaderMain( + in float4 oPos : SV_Position, + in float2 oTexCoord0 : TEXCOORD0, + in float2 oVelocity : TEXCOORD1, + in float2 oVelScale : TEXCOORD2) : SV_Target +{ + Texture2D texture = g_Texture2DDescriptorHeap[s0_Texture2DDescriptorIndex]; + SamplerState samplerState = g_SamplerDescriptorHeap[s0_SamplerDescriptorIndex]; + + float velocityMag = sqrt(dot(oVelocity, oVelocity)); + float blurAmount = saturate(velocityMag - 0.25); + + if (blurAmount == 0.0) + return texture.SampleLevel(samplerState, oTexCoord0, 0); + + blurAmount = min(blurAmount * blurAmount, 0.25); + + float blurStrength = blurAmount * velocityMag; + int g_SampleCount = clamp((int)(blurStrength * 256.0), 4, 64); + float2 scaledVelStep = oVelScale / (float)g_SampleCount; + + float4 result = float4(0.0, 0.0, 0.0, 0.0); + + for (int i = 0; i < g_SampleCount; i++) + { + float2 offset = blurAmount * scaledVelStep * (float)i; + float2 samplePos = oTexCoord0 + offset; + + result += texture.SampleLevel(samplerState, samplePos, 0); + } + + return result * (1.0 / (float)g_SampleCount); +} diff --git a/MarathonRecomp/gpu/shader/hlsl/enhanced_burnout_blur_vs.hlsl b/MarathonRecomp/gpu/shader/hlsl/enhanced_burnout_blur_vs.hlsl new file mode 100644 index 000000000..d16091fa2 --- /dev/null +++ b/MarathonRecomp/gpu/shader/hlsl/enhanced_burnout_blur_vs.hlsl @@ -0,0 +1,37 @@ +#include "../../../../tools/XenosRecomp/XenosRecomp/shader_common.h" + +#ifdef __spirv__ + +#define g_Velocity vk::RawBufferLoad(g_PushConstants.VertexShaderConstants + 3360, 0x10) + +#else + +cbuffer VertexShaderConstants : register(b1, space4) +{ + float4 g_Velocity : packoffset(c210); +}; + +#endif + +void shaderMain( + [[vk::location(0)]] in float4 iPosition0 : POSITION0, + [[vk::location(13)]] in float2 iTexCoord0 : TEXCOORD0, + out float4 oPos : SV_Position, + out float2 oTexCoord0 : TEXCOORD0, + out float2 oVelocity : TEXCOORD1, + out float2 oVelScale : TEXCOORD2) +{ + oPos = iPosition0; + oTexCoord0 = iTexCoord0; + + float2 centeredUV; + centeredUV.x = iTexCoord0.y * 2.0 - 1.0; + centeredUV.y = iTexCoord0.x * 2.0 - 1.0; + + oVelocity.x = -g_Velocity.x - centeredUV.y; + oVelocity.y = centeredUV.x - g_Velocity.y; + + float2 scaledVec = oVelocity * g_Velocity.w; + oVelScale.x = scaledVec.x * 0.00002; + oVelScale.y = -scaledVec.y * 0.00001; +} diff --git a/MarathonRecomp/gpu/shader/hlsl/enhanced_motion_blur_ps.hlsl b/MarathonRecomp/gpu/shader/hlsl/enhanced_motion_blur_ps.hlsl deleted file mode 100644 index 3535b696b..000000000 --- a/MarathonRecomp/gpu/shader/hlsl/enhanced_motion_blur_ps.hlsl +++ /dev/null @@ -1,75 +0,0 @@ -#include "../../../../tools/XenosRecomp/XenosRecomp/shader_common.h" - -#ifdef __spirv__ - -#define g_BlurRate vk::RawBufferLoad(g_PushConstants.PixelShaderConstants + 2400, 0x10) -#define g_ViewportSize vk::RawBufferLoad(g_PushConstants.PixelShaderConstants + 384, 0x10) - -#define sampColor_Texture2DDescriptorIndex vk::RawBufferLoad(g_PushConstants.SharedConstants + 0) -#define sampColor_SamplerDescriptorIndex vk::RawBufferLoad(g_PushConstants.SharedConstants + 192) - -#define sampVelocityMap_Texture2DDescriptorIndex vk::RawBufferLoad(g_PushConstants.SharedConstants + 4) -#define sampVelocityMap_SamplerDescriptorIndex vk::RawBufferLoad(g_PushConstants.SharedConstants + 196) - -#define sampZBuffer_Texture2DDescriptorIndex vk::RawBufferLoad(g_PushConstants.SharedConstants + 8) -#define sampZBuffer_SamplerDescriptorIndex vk::RawBufferLoad(g_PushConstants.SharedConstants + 200) - -#else - -cbuffer PixelShaderConstants : register(b1, space4) -{ - float4 g_BlurRate : packoffset(c150); - float4 g_ViewportSize : packoffset(c24); -}; - -cbuffer SharedConstants : register(b2, space4) -{ - uint sampColor_Texture2DDescriptorIndex : packoffset(c0.x); - uint sampColor_SamplerDescriptorIndex : packoffset(c12.x); - - uint sampVelocityMap_Texture2DDescriptorIndex : packoffset(c0.y); - uint sampVelocityMap_SamplerDescriptorIndex : packoffset(c12.y); - - uint sampZBuffer_Texture2DDescriptorIndex : packoffset(c0.z); - uint sampZBuffer_SamplerDescriptorIndex : packoffset(c12.z); - - DEFINE_SHARED_CONSTANTS(); -}; - -#endif - -float4 shaderMain(in float4 position : SV_Position, in float4 texCoord : TEXCOORD0) : SV_Target -{ - Texture2D sampColor = g_Texture2DDescriptorHeap[sampColor_Texture2DDescriptorIndex]; - Texture2D sampVelocityMap = g_Texture2DDescriptorHeap[sampVelocityMap_Texture2DDescriptorIndex]; - Texture2D sampZBuffer = g_Texture2DDescriptorHeap[sampZBuffer_Texture2DDescriptorIndex]; - - SamplerState sampColor_s = g_SamplerDescriptorHeap[sampColor_SamplerDescriptorIndex]; - SamplerState sampVelocityMap_s = g_SamplerDescriptorHeap[sampVelocityMap_SamplerDescriptorIndex]; - SamplerState sampZBuffer_s = g_SamplerDescriptorHeap[sampZBuffer_SamplerDescriptorIndex]; - - float depth = sampZBuffer.SampleLevel(sampZBuffer_s, texCoord.xy, 0).x; - float4 velocityMap = sampVelocityMap.SampleLevel(sampVelocityMap_s, texCoord.xy, 0); - float2 velocity = (velocityMap.xz + velocityMap.yw / 255.0) * 2.0 - 1.0; - - int sampleCount = min(64, round(length(velocity * g_ViewportSize.xy))); - float2 sampleOffset = velocity / (float) sampleCount; - - float3 color = sampColor.SampleLevel(sampColor_s, texCoord.xy, 0).rgb; - int count = 1; - - for (int i = 1; i <= sampleCount; i++) - { - float2 sampleCoord = texCoord.xy + sampleOffset * i; - float3 sampleColor = sampColor.SampleLevel(sampColor_s, sampleCoord, 0).rgb; - float sampleDepth = sampZBuffer.SampleLevel(sampZBuffer_s, sampleCoord, 0).x; - - if (sampleDepth - depth < 0.01) - { - color += sampleColor; - count += 1; - } - } - - return float4(color / count, g_BlurRate.x * saturate(dot(abs(velocity), g_ViewportSize.xy) / 8.0) * saturate(count - 1)); -} diff --git a/MarathonRecomp/gpu/shader/msl/enhanced_burnout_blur_ps.metal b/MarathonRecomp/gpu/shader/msl/enhanced_burnout_blur_ps.metal new file mode 100644 index 000000000..a7e1e007a --- /dev/null +++ b/MarathonRecomp/gpu/shader/msl/enhanced_burnout_blur_ps.metal @@ -0,0 +1,46 @@ +#include "../../../../tools/XenosRecomp/XenosRecomp/shader_common.h" + +#define s0_TextureDescriptorIndex (*(reinterpret_cast(g_PushConstants.SharedConstants + 0))) +#define s0_SamplerDescriptorIndex (*(reinterpret_cast(g_PushConstants.SharedConstants + 192))) + +struct Interpolators +{ + float4 oPos [[position]]; + float2 oTexCoord0 [[user(TEXCOORD0)]]; + float2 oVelocity [[user(TEXCOORD1)]]; + float2 oVelScale [[user(TEXCOORD2)]]; +}; + +[[fragment]] +float4 shaderMain(Interpolators input [[stage_in]], + constant Texture2DDescriptorHeap* g_Texture2DDescriptorHeap [[buffer(0)]], + constant SamplerDescriptorHeap* g_SamplerDescriptorHeap [[buffer(3)]], + constant PushConstants& g_PushConstants [[buffer(8)]]) +{ + texture2d texture = g_Texture2DDescriptorHeap[s0_TextureDescriptorIndex].tex; + sampler samp = g_SamplerDescriptorHeap[s0_SamplerDescriptorIndex].samp; + + float velocityMag = sqrt(dot(input.oVelocity, input.oVelocity)); + float blurAmount = saturate(velocityMag - 0.25); + + if (blurAmount == 0.0) + return texture.sample(samp, input.oTexCoord0, level(0)); + + blurAmount = min(blurAmount * blurAmount, 0.25); + + float blurStrength = blurAmount * velocityMag; + int g_SampleCount = clamp((int)(blurStrength * 256.0), 4, 64); + float2 scaledVelStep = input.oVelScale / (float)g_SampleCount; + + float4 result = float4(0.0); + + for (int i = 0; i < g_SampleCount; i++) + { + float2 offset = blurAmount * scaledVelStep * (float)i; + float2 samplePos = input.oTexCoord0 + offset; + + result += texture.sample(samp, samplePos, level(0)); + } + + return result * (1.0 / (float)g_SampleCount); +} diff --git a/MarathonRecomp/gpu/shader/msl/enhanced_burnout_blur_vs.metal b/MarathonRecomp/gpu/shader/msl/enhanced_burnout_blur_vs.metal new file mode 100644 index 000000000..632d9ce33 --- /dev/null +++ b/MarathonRecomp/gpu/shader/msl/enhanced_burnout_blur_vs.metal @@ -0,0 +1,41 @@ +#include "../../../../tools/XenosRecomp/XenosRecomp/shader_common.h" + +// #define g_SampleCount (*(reinterpret_cast(g_PushConstants.VertexShaderConstants + 0))) +#define g_Velocity (*(reinterpret_cast(g_PushConstants.VertexShaderConstants + 3360))) + +struct VertexShaderInput +{ + float4 iPosition0 [[attribute(0)]]; + float2 iTexCoord0 [[attribute(13)]]; +}; + +struct Interpolators +{ + float4 oPos [[position]]; + float2 oTexCoord0 [[user(TEXCOORD0)]]; + float2 oVelocity [[user(TEXCOORD1)]]; + float2 oVelScale [[user(TEXCOORD2)]]; +}; + +[[vertex]] +Interpolators shaderMain(VertexShaderInput input [[stage_in]], + constant PushConstants& g_PushConstants [[buffer(8)]]) +{ + Interpolators output; + + output.oPos = input.iPosition0; + output.oTexCoord0 = input.iTexCoord0; + + float2 centeredUV; + centeredUV.x = input.iTexCoord0.y * 2.0 - 1.0; + centeredUV.y = input.iTexCoord0.x * 2.0 - 1.0; + + output.oVelocity.x = -g_Velocity.x - centeredUV.y; + output.oVelocity.y = centeredUV.x - g_Velocity.y; + + float2 scaledVec = output.oVelocity * g_Velocity.w; + output.oVelScale.x = scaledVec.x * 0.00002; + output.oVelScale.y = -scaledVec.y * 0.00001; + + return output; +} diff --git a/MarathonRecomp/gpu/shader/msl/enhanced_motion_blur_ps.metal b/MarathonRecomp/gpu/shader/msl/enhanced_motion_blur_ps.metal deleted file mode 100644 index a5205321a..000000000 --- a/MarathonRecomp/gpu/shader/msl/enhanced_motion_blur_ps.metal +++ /dev/null @@ -1,59 +0,0 @@ -#include "../../../../tools/XenosRecomp/XenosRecomp/shader_common.h" - -#define g_BlurRate (*(reinterpret_cast(g_PushConstants.PixelShaderConstants + 2400))) -#define g_ViewportSize (*(reinterpret_cast(g_PushConstants.PixelShaderConstants + 384))) - -#define sampColor_Texture2DDescriptorIndex (*(reinterpret_cast(g_PushConstants.SharedConstants + 0))) -#define sampColor_SamplerDescriptorIndex (*(reinterpret_cast(g_PushConstants.SharedConstants + 192))) - -#define sampVelocityMap_Texture2DDescriptorIndex (*(reinterpret_cast(g_PushConstants.SharedConstants + 4))) -#define sampVelocityMap_SamplerDescriptorIndex (*(reinterpret_cast(g_PushConstants.SharedConstants + 196))) - -#define sampZBuffer_Texture2DDescriptorIndex (*(reinterpret_cast(g_PushConstants.SharedConstants + 8))) -#define sampZBuffer_SamplerDescriptorIndex (*(reinterpret_cast(g_PushConstants.SharedConstants + 200))) - -struct Interpolators -{ - float4 texCoord [[user(TEXCOORD0)]]; -}; - -[[fragment]] -float4 shaderMain(float4 position [[position]], - Interpolators input [[stage_in]], - constant Texture2DDescriptorHeap* g_Texture2DDescriptorHeap [[buffer(0)]], - constant SamplerDescriptorHeap* g_SamplerDescriptorHeap [[buffer(3)]], - constant PushConstants& g_PushConstants [[buffer(8)]]) -{ - texture2d sampColor = g_Texture2DDescriptorHeap[sampColor_Texture2DDescriptorIndex].tex; - texture2d sampVelocityMap = g_Texture2DDescriptorHeap[sampVelocityMap_Texture2DDescriptorIndex].tex; - texture2d sampZBuffer = g_Texture2DDescriptorHeap[sampZBuffer_Texture2DDescriptorIndex].tex; - - sampler sampColor_s = g_SamplerDescriptorHeap[sampColor_SamplerDescriptorIndex].samp; - sampler sampVelocityMap_s = g_SamplerDescriptorHeap[sampVelocityMap_SamplerDescriptorIndex].samp; - sampler sampZBuffer_s = g_SamplerDescriptorHeap[sampZBuffer_SamplerDescriptorIndex].samp; - - float depth = sampZBuffer.sample(sampZBuffer_s, input.texCoord.xy, level(0)).x; - float4 velocityMap = sampVelocityMap.sample(sampVelocityMap_s, input.texCoord.xy, level(0)); - float2 velocity = (velocityMap.xz + velocityMap.yw / 255.0) * 2.0 - 1.0; - - int sampleCount = min(64, int(round(length(velocity * g_ViewportSize.xy)))); - float2 sampleOffset = velocity / (float) sampleCount; - - float3 color = sampColor.sample(sampColor_s, input.texCoord.xy, level(0)).rgb; - int count = 1; - - for (int i = 1; i <= sampleCount; i++) - { - float2 sampleCoord = input.texCoord.xy + sampleOffset * i; - float3 sampleColor = sampColor.sample(sampColor_s, sampleCoord, level(0)).rgb; - float sampleDepth = sampZBuffer.sample(sampZBuffer_s, sampleCoord, 0).x; - - if (sampleDepth - depth < 0.01) - { - color += sampleColor; - count += 1; - } - } - - return float4(color / count, g_BlurRate.x * saturate(dot(abs(velocity), g_ViewportSize.xy) / 8.0) * saturate(float(count - 1))); -} diff --git a/MarathonRecomp/gpu/video.cpp b/MarathonRecomp/gpu/video.cpp index ea6545835..8829d9e6a 100644 --- a/MarathonRecomp/gpu/video.cpp +++ b/MarathonRecomp/gpu/video.cpp @@ -50,7 +50,8 @@ #include "shader/hlsl/csd_filter_ps.hlsl.dxil.h" #include "shader/hlsl/csd_no_tex_vs.hlsl.dxil.h" #include "shader/hlsl/csd_vs.hlsl.dxil.h" -#include "shader/hlsl/enhanced_motion_blur_ps.hlsl.dxil.h" +#include "shader/hlsl/enhanced_burnout_blur_vs.hlsl.dxil.h" +#include "shader/hlsl/enhanced_burnout_blur_ps.hlsl.dxil.h" #include "shader/hlsl/gamma_correction_ps.hlsl.dxil.h" #include "shader/hlsl/gaussian_blur_3x3.hlsl.dxil.h" #include "shader/hlsl/gaussian_blur_5x5.hlsl.dxil.h" @@ -76,7 +77,8 @@ #include "shader/msl/csd_filter_ps.metal.metallib.h" #include "shader/msl/csd_no_tex_vs.metal.metallib.h" #include "shader/msl/csd_vs.metal.metallib.h" -#include "shader/msl/enhanced_motion_blur_ps.metal.metallib.h" +#include "shader/msl/enhanced_burnout_blur_vs.metal.metallib.h" +#include "shader/msl/enhanced_burnout_blur_ps.metal.metallib.h" #include "shader/msl/gamma_correction_ps.metal.metallib.h" #include "shader/msl/gaussian_blur_3x3.metal.metallib.h" #include "shader/msl/gaussian_blur_5x5.metal.metallib.h" @@ -101,7 +103,8 @@ #include "shader/hlsl/csd_filter_ps.hlsl.spirv.h" #include "shader/hlsl/csd_no_tex_vs.hlsl.spirv.h" #include "shader/hlsl/csd_vs.hlsl.spirv.h" -#include "shader/hlsl/enhanced_motion_blur_ps.hlsl.spirv.h" +#include "shader/hlsl/enhanced_burnout_blur_vs.hlsl.spirv.h" +#include "shader/hlsl/enhanced_burnout_blur_ps.hlsl.spirv.h" #include "shader/hlsl/gamma_correction_ps.hlsl.spirv.h" #include "shader/hlsl/gaussian_blur_3x3.hlsl.spirv.h" #include "shader/hlsl/gaussian_blur_5x5.hlsl.spirv.h" @@ -1466,7 +1469,8 @@ static std::unique_ptr g_gaussianBlurShaders[GAUSSIAN_BLUR_COUNT]; static std::unique_ptr g_csdFilterShader; static GuestShader* g_csdShader; -static std::unique_ptr g_enhancedMotionBlurShader; +static std::unique_ptr g_enhancedBurnoutBlurVSShader; +static std::unique_ptr g_enhancedBurnoutBlurPSShader; #if defined(MARATHON_RECOMP_D3D12) @@ -2205,8 +2209,11 @@ bool Video::CreateHostDevice(const char *sdlVideoDriver, bool graphicsApiRetry) g_csdFilterShader = std::make_unique(ResourceType::PixelShader); g_csdFilterShader->shader = CREATE_SHADER(csd_filter_ps); - g_enhancedMotionBlurShader = std::make_unique(ResourceType::PixelShader); - g_enhancedMotionBlurShader->shader = CREATE_SHADER(enhanced_motion_blur_ps); + g_enhancedBurnoutBlurVSShader = std::make_unique(ResourceType::VertexShader); + g_enhancedBurnoutBlurVSShader->shader = CREATE_SHADER(enhanced_burnout_blur_vs); + + g_enhancedBurnoutBlurPSShader = std::make_unique(ResourceType::PixelShader); + g_enhancedBurnoutBlurPSShader->shader = CREATE_SHADER(enhanced_burnout_blur_ps); CreateImGuiBackend(); @@ -5483,7 +5490,19 @@ static void SetVertexShader(GuestDevice* device, GuestShader* shader) static void ProcSetVertexShader(const RenderCommand& cmd) { - SetDirtyValue(g_dirtyStates.pipelineState, g_pipelineState.vertexShader, cmd.setVertexShader.shader); + GuestShader* shader = cmd.setVertexShader.shader; + + if (shader != nullptr && + shader->shaderCacheEntry != nullptr) + { + if (shader->shaderCacheEntry->hash == 0x3687D038CE7D0BEA || shader->shaderCacheEntry->hash == 0xB4DA7A442DBB16CC) + { + if (Config::RadialBlur == ERadialBlur::Enhanced) + shader = g_enhancedBurnoutBlurVSShader.get(); + } + } + + SetDirtyValue(g_dirtyStates.pipelineState, g_pipelineState.vertexShader, shader); } static void SetStreamSource(GuestDevice* device, uint32_t index, GuestBuffer* buffer, uint32_t offset, uint32_t stride) @@ -5549,6 +5568,17 @@ static void SetPixelShader(GuestDevice* device, GuestShader* shader) static void ProcSetPixelShader(const RenderCommand& cmd) { GuestShader* shader = cmd.setPixelShader.shader; + + if (shader != nullptr && + shader->shaderCacheEntry != nullptr) + { + if (shader->shaderCacheEntry->hash == 0xDA58F0110A8595D9 || shader->shaderCacheEntry->hash == 0x845A4EF989446C01) + { + if (Config::RadialBlur == ERadialBlur::Enhanced) + shader = g_enhancedBurnoutBlurPSShader.get(); + } + } + SetDirtyValue(g_dirtyStates.pipelineState, g_pipelineState.pixelShader, shader); } diff --git a/MarathonRecomp/user/config.cpp b/MarathonRecomp/user/config.cpp index 24b59bab1..12ad2b138 100644 --- a/MarathonRecomp/user/config.cpp +++ b/MarathonRecomp/user/config.cpp @@ -315,8 +315,9 @@ CONFIG_DEFINE_ENUM_TEMPLATE(EWindowState) CONFIG_DEFINE_ENUM_TEMPLATE(ERadialBlur) { - { "Off", ERadialBlur::Off }, + { "Off", ERadialBlur::Off }, { "Original", ERadialBlur::Original }, + { "Enhanced", ERadialBlur::Enhanced } }; CONFIG_DEFINE_ENUM_TEMPLATE(EAspectRatio) diff --git a/MarathonRecomp/user/config.h b/MarathonRecomp/user/config.h index a46463b59..4ce766119 100644 --- a/MarathonRecomp/user/config.h +++ b/MarathonRecomp/user/config.h @@ -123,7 +123,8 @@ enum class EReflectionResolution : int32_t enum class ERadialBlur : uint32_t { Off, - Original + Original, + Enhanced }; enum class ECutsceneAspectRatio : uint32_t