Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions MarathonRecomp/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ set(MARATHON_RECOMP_CPU_CXX_SOURCES
)

set(MARATHON_RECOMP_GPU_CXX_SOURCES
"gpu/render_resolution.cpp"
"gpu/video.cpp"
"gpu/resources.cpp"
"gpu/guest_convert.cpp"
Expand Down Expand Up @@ -491,6 +492,7 @@ compile_pixel_shader(conditional_survey_ps)
compile_vertex_shader(copy_vs)
compile_pixel_shader(copy_color_ps)
compile_pixel_shader(copy_depth_ps)
compile_pixel_shader(downsample_ps)
compile_vertex_shader(enhanced_burnout_blur_vs)
compile_pixel_shader(enhanced_burnout_blur_ps)
compile_pixel_shader(movie_ps)
Expand Down
6 changes: 6 additions & 0 deletions MarathonRecomp/gpu/guest_shader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ static std::unique_ptr<RenderShader> g_enhancedBurnoutBlurPSShader;

static std::unique_ptr<RenderShader> g_MoviePSShader;

static std::unique_ptr<RenderShader> g_downsamplePSShader;

std::unique_ptr<GuestShader> g_conditionalSurveyPSShader;

void LoadEmbeddedResources()
Expand Down Expand Up @@ -47,6 +49,8 @@ void CreateReplacementShaders()
g_enhancedBurnoutBlurPSShader = CREATE_SHADER(enhanced_burnout_blur_ps);
g_MoviePSShader = CREATE_SHADER(movie_ps);

g_downsamplePSShader = CREATE_SHADER(downsample_ps);

g_conditionalSurveyPSShader = std::make_unique<GuestShader>();
g_conditionalSurveyPSShader->type = ResourceType::PixelShader;
g_conditionalSurveyPSShader->shader = CREATE_SHADER(conditional_survey_ps);
Expand All @@ -73,6 +77,8 @@ RenderShader* GetReplacementShader(const GuestShader* guestShader)
break;
case 0x88EB0AA82E4257B0:
return g_MoviePSShader.get();
case 0x62573AB4C9EC44EE:
return g_downsamplePSShader.get();
default:
break;
}
Expand Down
72 changes: 72 additions & 0 deletions MarathonRecomp/gpu/render_resolution.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
#include "render_resolution.h"
#include <gpu/video.h>
#include <patches/aspect_ratio_patches.h>
#include <user/config.h>

static uint32_t ScaleDimension(uint32_t value, float scale)
{
return uint32_t(float(value) * scale);
}

static float GetReflectionScale()
{
switch (Config::ReflectionResolution)
{
case EReflectionResolution::Eighth:
return 0.5f;
case EReflectionResolution::Half:
return 2.0f;
case EReflectionResolution::Full:
return 4.0f;
default:
return 1.0f;
}
}

BufferSize RenderResolution::GetInternalSize()
{
return { ScaleDimension(Video::s_viewportWidth, Config::ResolutionScale), ScaleDimension(Video::s_viewportHeight, Config::ResolutionScale) };
}

std::optional<BufferSize> RenderResolution::FindBufferSize(std::string_view name, const char* pBlockName)
{
const auto internalSize = GetInternalSize();
const auto blockName = std::string_view(pBlockName != nullptr ? pBlockName : "");

if (name == "framebuffer0" || name == "framebuffer1" || name == "framebuffer_hdr")
return internalSize;

if (name.starts_with("coframebuffer") || name == "codepthstencil")
return BufferSize { internalSize.Width / 2, internalSize.Height };

// Downsampled chain, e.g. "framebuffer_1_4_0" is a quarter of the internal resolution.
if (name.starts_with("framebuffer_1_"))
{
uint32_t divisor = 0;
std::from_chars(name.data() + 14, name.data() + name.size(), divisor);

if (divisor != 0)
return BufferSize { internalSize.Width / divisor, internalSize.Height / divisor };
}

// Reflections are an eighth of the internal resolution at the default setting.
if (name == "reflection0" || name == "depthstencil_1_4")
return BufferSize { ScaleDimension(internalSize.Width >> 3, GetReflectionScale()), ScaleDimension(internalSize.Height >> 3, GetReflectionScale()) };

if (name == "radermap" || blockName == "radermap0")
return BufferSize { uint32_t(g_radarMapScale), uint32_t(g_radarMapScale) };

const auto shadowResolution = uint32_t(Config::ShadowResolution.Value);

if (shadowResolution > 0)
{
// RenderMefiress
if (name == "user0" || (blockName == "user0" && name == "depthstencil_256"))
return BufferSize { shadowResolution, shadowResolution };

if (name == "csm")
return BufferSize { shadowResolution, shadowResolution };
}

return {};
}
13 changes: 13 additions & 0 deletions MarathonRecomp/gpu/render_resolution.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#pragma once

struct BufferSize
{
uint32_t Width{};
uint32_t Height{};
};

namespace RenderResolution
{
BufferSize GetInternalSize();
std::optional<BufferSize> FindBufferSize(std::string_view name, const char* pBlockName);
}
35 changes: 35 additions & 0 deletions MarathonRecomp/gpu/shader/hlsl/downsample_ps.hlsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#include "../../../../tools/XenosRecomp/XenosRecomp/shader_common.h"

#ifdef __spirv__

#define s0_Texture2DDescriptorIndex vk::RawBufferLoad<uint>(g_PushConstants.SharedConstants + 0)

#else

cbuffer SharedConstants : register(b2, space4)
{
uint s0_Texture2DDescriptorIndex : packoffset(c0.x);
DEFINE_SHARED_CONSTANTS();
};

#endif

float4 shaderMain(
in float4 oPos : SV_Position,
in float4 oTexCoord0 : TEXCOORD0) : SV_Target
{
Texture2D<float4> texture = g_Texture2DDescriptorHeap[s0_Texture2DDescriptorIndex];

float2 pixelCoord = oTexCoord0.xy * float2(getTexture2DDimensions(texture));
float2 step = float2(ddx(pixelCoord.x), ddy(pixelCoord.y)) / 4.0;

float4 color = 0.0;

for (int y = 0; y < 4; y++)
{
for (int x = 0; x < 4; x++)
color += texture.Load(int3(int2(pixelCoord + (float2(x, y) - 1.5) * step), 0));
}

return color / 16.0;
}
30 changes: 30 additions & 0 deletions MarathonRecomp/gpu/shader/msl/downsample_ps.metal
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#include "../../../../tools/XenosRecomp/XenosRecomp/shader_common.h"

#define s0_TextureDescriptorIndex (*(reinterpret_cast<device int*>(g_PushConstants.SharedConstants + 0)))

struct Interpolators
{
float4 oPos [[position]];
float4 oTexCoord0 [[user(TEXCOORD0)]];
};

[[fragment]]
float4 shaderMain(Interpolators input [[stage_in]],
constant Texture2DDescriptorHeap* g_Texture2DDescriptorHeap [[buffer(0)]],
constant PushConstants& g_PushConstants [[buffer(8)]])
{
texture2d<float> texture = g_Texture2DDescriptorHeap[s0_TextureDescriptorIndex].tex;

float2 pixelCoord = input.oTexCoord0.xy * float2(getTexture2DDimensions(texture));
float2 step = float2(dfdx(pixelCoord.x), dfdy(pixelCoord.y)) / 4.0;

float4 color = 0.0;

for (int y = 0; y < 4; y++)
{
for (int x = 0; x < 4; x++)
color += texture.read(uint2(pixelCoord + (float2(x, y) - 1.5) * step));
}

return color / 16.0;
}
67 changes: 23 additions & 44 deletions MarathonRecomp/gpu/video.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@
#include "guest_convert.h"
#include "guest_device.h"
#include "guest_shader.h"
#include "surface_variant.h"
#include "video_internal.h"
#include "pipeline.h"
#include "imgui/imgui_common.h"
#include "imgui/imgui_snapshot.h"
#include "pipeline.h"
#include "render_command.h"
#include "render_resolution.h"
#include "resources.h"
#include "surface_variant.h"
#include "video_internal.h"

#include <Marathon.h>
#include <app.h>
Expand Down Expand Up @@ -2472,38 +2473,14 @@ void Video::Resize(uint32_t width, uint32_t height)
if (!pRenderTargetContainer || !pMyGraphicsDevice)
return;

width *= Config::ResolutionScale;
height *= Config::ResolutionScale;
const auto internalSize = RenderResolution::GetInternalSize();

if (!width || !height)
if (!internalSize.Width || !internalSize.Height)
{
LOGN_ERROR("Attempting to resize buffers to 0x0.");
return;
}

struct BufferInfo
{
uint32_t Width;
uint32_t Height;
uint32_t Index;
uint32_t Flags;
};

static std::map<std::string, BufferInfo> buffers{};

// Update buffer dimensions.
buffers["framebuffer0"] = { width, height, 0, 4 };
buffers["framebuffer1"] = { width, height, 0, 0 };
buffers["framebuffer_1_4_0"] = { width >> 2, height >> 2, 3, 2 };
buffers["framebuffer_1_4_1"] = { width >> 2, height >> 2, 0, 2 };
buffers["framebuffer_1_8_0"] = { width >> 3, height >> 3, 3, 2 };
buffers["framebuffer_1_8_1"] = { width >> 3, height >> 3, 0, 2 };
buffers["framebuffer_1_16_0"] = { width >> 4, height >> 4, 3, 2 };
buffers["framebuffer_1_16_1"] = { width >> 4, height >> 4, 0, 2 };
buffers["framebuffer_1_32_0"] = { width >> 5, height >> 5, 3, 2 };
buffers["framebuffer_1_32_1"] = { width >> 5, height >> 5, 0, 2 };
buffers["depthstencil_1_4"] = { width, height, 6, 0 };

if (g_backBuffer && g_backBuffer != pApp->m_pBackBufferSurface.get())
g_backBuffer->Release();

Expand All @@ -2513,7 +2490,7 @@ void Video::Resize(uint32_t width, uint32_t height)
auto& rDeviceInfo = pApp->m_DeviceInfo;

auto surfaceParams = D3DXBSURFACE_PARAMETERS(0, 0, 0);
const auto surfaceBase = static_cast<uint32_t>(height * 1.155555555555556); // 720p: 0x340
const auto surfaceBase = static_cast<uint32_t>(internalSize.Height * 1.155555555555556); // 720p: 0x340

// Recreate main buffers.
ReleaseResource(static_cast<GuestTexture*>(pApp->m_pFrontBufferTexture.get()));
Expand All @@ -2525,21 +2502,21 @@ void Video::Resize(uint32_t width, uint32_t height)
surfaceParams.Base = surfaceParams.Base + surfaceBase;

ReleaseResource(static_cast<GuestSurface*>(pApp->m_pDepthStencilSurface.get()));
pApp->m_pDepthStencilSurface = CreateSurface(width, height, D3DFMT_D24FS8, 0, reinterpret_cast<GuestSurfaceCreateParams*>(&surfaceParams));
pApp->m_pDepthStencilSurface = CreateSurface(internalSize.Width, internalSize.Height, D3DFMT_D24FS8, 0, reinterpret_cast<GuestSurfaceCreateParams*>(&surfaceParams));

rDeviceInfo.SurfaceParamsB = surfaceParams;
rDeviceInfo.SurfaceParamsC = rDeviceInfo.SurfaceParamsB;
rDeviceInfo.SurfaceParamsC.Base = rDeviceInfo.SurfaceParamsB.Base + surfaceBase;

ReleaseResource(static_cast<GuestSurface*>(pApp->m_pColorTile2x.get()));
pApp->m_pColorTile2x = CreateSurface(width, height, D3DFMT_A16B16G16R16F_2, 1, reinterpret_cast<GuestSurfaceCreateParams*>(&surfaceParams));
pApp->m_pColorTile2x = CreateSurface(internalSize.Width, internalSize.Height, D3DFMT_A16B16G16R16F_2, 1, reinterpret_cast<GuestSurfaceCreateParams*>(&surfaceParams));
ReleaseResource(static_cast<GuestSurface*>(pApp->m_pDepthTile2x.get()));
pApp->m_pDepthTile2x = CreateSurface(width, height, D3DFMT_D24FS8, 1, reinterpret_cast<GuestSurfaceCreateParams*>(&surfaceParams));
pApp->m_pDepthTile2x = CreateSurface(internalSize.Width, internalSize.Height, D3DFMT_D24FS8, 1, reinterpret_cast<GuestSurfaceCreateParams*>(&surfaceParams));

ReleaseResource(static_cast<GuestSurface*>(pApp->m_pColorTile4x.get()));
pApp->m_pColorTile4x = CreateSurface(width, height, D3DFMT_A16B16G16R16F_2, 2, reinterpret_cast<GuestSurfaceCreateParams*>(&surfaceParams));
pApp->m_pColorTile4x = CreateSurface(internalSize.Width, internalSize.Height, D3DFMT_A16B16G16R16F_2, 2, reinterpret_cast<GuestSurfaceCreateParams*>(&surfaceParams));
ReleaseResource(static_cast<GuestSurface*>(pApp->m_pDepthTile4x.get()));
pApp->m_pDepthTile4x = CreateSurface(width, height, D3DFMT_D24FS8, 2, reinterpret_cast<GuestSurfaceCreateParams*>(&surfaceParams));
pApp->m_pDepthTile4x = CreateSurface(internalSize.Width, internalSize.Height, D3DFMT_D24FS8, 2, reinterpret_cast<GuestSurfaceCreateParams*>(&surfaceParams));

// Viewport is reset here because we're using the game's backbuffer directly.
SetRenderTarget(static_cast<GuestDevice*>(pApp->m_pDevice.get()), 0, static_cast<GuestSurface*>(pApp->m_pBackBufferSurface.get()));
Expand Down Expand Up @@ -2605,37 +2582,39 @@ void Video::Resize(uint32_t width, uint32_t height)
{
const auto pSurfaceName = rSurface.first.c_str();

if (!buffers.contains(pSurfaceName))
if (!g_BufferInfo.contains(pSurfaceName))
continue;

const auto& rBufferInfo = buffers[pSurfaceName];
const auto& rBufferInfo = g_BufferInfo.at(pSurfaceName);
const auto size = *RenderResolution::FindBufferSize(pSurfaceName, nullptr);

auto pSurfaceParams = getSurfaceParams(rBufferInfo.Index, rBufferInfo.Flags);
auto pNewSurface = CreateSurface(rBufferInfo.Width, rBufferInfo.Height, pFormatConfigs[rBufferInfo.Index].SurfaceFormat, 0, reinterpret_cast<GuestSurfaceCreateParams*>(pSurfaceParams));
auto pNewSurface = CreateSurface(size.Width, size.Height, pFormatConfigs[rBufferInfo.Index].SurfaceFormat, 0, reinterpret_cast<GuestSurfaceCreateParams*>(pSurfaceParams));

GuestToHostFunction<void>(sub_82592E98, rSurface.second.get(), pNewSurface, rBufferInfo.Width, rBufferInfo.Height);
GuestToHostFunction<void>(sub_82592E98, rSurface.second.get(), pNewSurface, size.Width, size.Height);
}

// Update frame buffer textures.
for (auto& rTexture : pRenderTargetContainer->m_FrameBufferTextures)
{
const auto pTextureName = rTexture.first.c_str();

if (!buffers.contains(pTextureName))
if (!g_BufferInfo.contains(pTextureName))
continue;

const auto& rBufferInfo = buffers[pTextureName];
const auto& rBufferInfo = g_BufferInfo.at(pTextureName);
const auto size = *RenderResolution::FindBufferSize(pTextureName, nullptr);

CreateTextureLocal(rTexture.second.get(), rBufferInfo.Width, rBufferInfo.Height, 1, 1, pFormatConfigs[rBufferInfo.Index].Usage, pFormatConfigs[rBufferInfo.Index].TextureFormat, 0, 3);
CreateTextureLocal(rTexture.second.get(), size.Width, size.Height, 1, 1, pFormatConfigs[rBufferInfo.Index].Usage, pFormatConfigs[rBufferInfo.Index].TextureFormat, 0, 3);

const auto surfaceFormatIndex = (rBufferInfo.Flags & 4) == 0
? rBufferInfo.Index
: 3;

auto pSurfaceParams = getSurfaceParams(surfaceFormatIndex, rBufferInfo.Flags);
auto pNewSurface = CreateSurface(rBufferInfo.Width, rBufferInfo.Height, pFormatConfigs[surfaceFormatIndex].SurfaceFormat, 0, reinterpret_cast<GuestSurfaceCreateParams*>(pSurfaceParams));
auto pNewSurface = CreateSurface(size.Width, size.Height, pFormatConfigs[surfaceFormatIndex].SurfaceFormat, 0, reinterpret_cast<GuestSurfaceCreateParams*>(pSurfaceParams));

GuestToHostFunction<void>(sub_82592E98, rTexture.second->m_Surfaces[0].get(), pNewSurface, rBufferInfo.Width, rBufferInfo.Height);
GuestToHostFunction<void>(sub_82592E98, rTexture.second->m_Surfaces[0].get(), pNewSurface, size.Width, size.Height);
}

// Clear post-process buffers.
Expand Down
21 changes: 21 additions & 0 deletions MarathonRecomp/gpu/video.h
Original file line number Diff line number Diff line change
Expand Up @@ -518,6 +518,27 @@ enum GuestTextureAddress
D3DTADDRESS_BORDER = 6
};

struct BufferInfo
{
uint32_t Index;
uint32_t Flags;
};

static const std::map<std::string, BufferInfo> g_BufferInfo
{
{ "framebuffer0", { 0, 4 } },
{ "framebuffer1", { 0, 0 } },
{ "framebuffer_1_4_0", { 3, 2 } },
{ "framebuffer_1_4_1", { 0, 2 } },
{ "framebuffer_1_8_0", { 3, 2 } },
{ "framebuffer_1_8_1", { 0, 2 } },
{ "framebuffer_1_16_0", { 3, 2 } },
{ "framebuffer_1_16_1", { 0, 2 } },
{ "framebuffer_1_32_0", { 3, 2 } },
{ "framebuffer_1_32_1", { 0, 2 } },
{ "depthstencil_1_4", { 6, 0 } },
};

extern std::unique_ptr<GuestTexture> LoadTexture(const uint8_t* data, size_t dataSize, RenderComponentMapping componentMapping = RenderComponentMapping());

extern void VideoConfigValueChangedCallback(const class IConfigDef* config);
Loading
Loading