From a39b3ec855af315ee3e553fcdce16cf8648eb21b Mon Sep 17 00:00:00 2001 From: Skyth <19259897+blueskythlikesclouds@users.noreply.github.com> Date: Fri, 10 Jan 2025 22:02:54 +0300 Subject: [PATCH] Implement the aspect ratio option. --- UnleashedRecomp/CMakeLists.txt | 2 +- .../gpu/shader/gamma_correction_ps.hlsl | 16 ++- UnleashedRecomp/gpu/video.cpp | 106 +++++++++++++++--- UnleashedRecomp/gpu/video.h | 4 + ...d_patches.cpp => aspect_ratio_patches.cpp} | 26 +---- .../patches/aspect_ratio_patches.h | 6 + UnleashedRecomp/patches/camera_patches.cpp | 3 +- UnleashedRecomp/ui/options_menu.cpp | 4 +- 8 files changed, 123 insertions(+), 44 deletions(-) rename UnleashedRecomp/patches/{csd_patches.cpp => aspect_ratio_patches.cpp} (98%) create mode 100644 UnleashedRecomp/patches/aspect_ratio_patches.h diff --git a/UnleashedRecomp/CMakeLists.txt b/UnleashedRecomp/CMakeLists.txt index baabe782..378297f4 100644 --- a/UnleashedRecomp/CMakeLists.txt +++ b/UnleashedRecomp/CMakeLists.txt @@ -152,9 +152,9 @@ set(SWA_PATCHES_CXX_SOURCES "patches/ui/CTitleStateIntro_patches.cpp" "patches/ui/CTitleStateMenu_patches.cpp" "patches/ui/frontend_listener.cpp" + "patches/aspect_ratio_patches.cpp" "patches/audio_patches.cpp" "patches/camera_patches.cpp" - "patches/csd_patches.cpp" "patches/fps_patches.cpp" "patches/inspire_patches.cpp" "patches/misc_patches.cpp" diff --git a/UnleashedRecomp/gpu/shader/gamma_correction_ps.hlsl b/UnleashedRecomp/gpu/shader/gamma_correction_ps.hlsl index 48f774fb..cf4be926 100644 --- a/UnleashedRecomp/gpu/shader/gamma_correction_ps.hlsl +++ b/UnleashedRecomp/gpu/shader/gamma_correction_ps.hlsl @@ -5,12 +5,17 @@ #define g_Gamma vk::RawBufferLoad(g_PushConstants.SharedConstants + 0) #define g_TextureDescriptorIndex vk::RawBufferLoad(g_PushConstants.SharedConstants + 12) +#define g_ViewportOffset vk::RawBufferLoad(g_PushConstants.SharedConstants + 16) +#define g_ViewportSize vk::RawBufferLoad(g_PushConstants.SharedConstants + 24) + #else cbuffer SharedConstants : register(b2, space4) { - float3 g_Gamma : packoffset(c0.x); - uint g_TextureDescriptorIndex : packoffset(c0.w); + float3 g_Gamma; + uint g_TextureDescriptorIndex; + int2 g_ViewportOffset; + int2 g_ViewportSize; }; #endif @@ -18,7 +23,12 @@ cbuffer SharedConstants : register(b2, space4) float4 main(in float4 position : SV_Position) : SV_Target { Texture2D texture = g_Texture2DDescriptorHeap[g_TextureDescriptorIndex]; - float4 color = texture.Load(int3(position.xy, 0)); + + int2 movedPosition = int2(position.xy) - g_ViewportOffset; + bool boxed = any(movedPosition < 0) || any(movedPosition >= g_ViewportSize); + if (boxed) movedPosition = 0; + + float4 color = boxed ? 0.0 : texture.Load(int3(movedPosition, 0)); color.rgb = pow(color.rgb, g_Gamma); return color; } diff --git a/UnleashedRecomp/gpu/video.cpp b/UnleashedRecomp/gpu/video.cpp index f73cc302..b1c10cc3 100644 --- a/UnleashedRecomp/gpu/video.cpp +++ b/UnleashedRecomp/gpu/video.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -1352,16 +1353,19 @@ static void CheckSwapChain() if (g_swapChainValid) g_swapChainValid = g_swapChain->acquireTexture(g_acquireSemaphores[g_frame].get(), &g_backBufferIndex); - float aspectRatio = float(GameWindow::s_width) / GameWindow::s_height; + if (g_needsResize) + Video::ComputeViewportDimensions(); + + float aspectRatio = float(Video::s_viewportWidth) / Video::s_viewportHeight; if (aspectRatio >= ORIGINAL_ASPECT_RATIO) { - g_backBuffer->width = GameWindow::s_width * 720 / GameWindow::s_height; + g_backBuffer->width = Video::s_viewportWidth * 720 / Video::s_viewportHeight; g_backBuffer->height = 720; } else { g_backBuffer->width = 960; - g_backBuffer->height = GameWindow::s_height * 960 / GameWindow::s_width; + g_backBuffer->height = Video::s_viewportHeight * 960 / Video::s_viewportWidth; } } @@ -1376,13 +1380,14 @@ static void BeginCommandList() if (g_swapChainValid) { - bool applyingGammaCorrection = Config::XboxColorCorrection || abs(Config::Brightness - 0.5f) > 0.001f; + uint32_t width = Video::s_viewportWidth; + uint32_t height = Video::s_viewportHeight; - if (applyingGammaCorrection) + bool usingIntermediaryTexture = (width != g_swapChain->getWidth()) || (height != g_swapChain->getHeight()) || + Config::XboxColorCorrection || (abs(Config::Brightness - 0.5f) > 0.001f); + + if (usingIntermediaryTexture) { - uint32_t width = g_swapChain->getWidth(); - uint32_t height = g_swapChain->getHeight(); - if (g_intermediaryBackBufferTextureWidth != width || g_intermediaryBackBufferTextureHeight != height) { @@ -1665,6 +1670,7 @@ void Video::CreateHostDevice(const char *sdlVideoDriver) g_backBuffer->format = BACKBUFFER_FORMAT; g_backBuffer->textureHolder = g_device->createTexture(RenderTextureDesc::Texture2D(1, 1, 1, BACKBUFFER_FORMAT, RenderTextureFlag::RENDER_TARGET)); + Video::ComputeViewportDimensions(); CheckSwapChain(); BeginCommandList(); @@ -2062,6 +2068,8 @@ static void DrawImGui() ImGui::End(); #endif + ImGui::GetIO().DisplaySize = { float(Video::s_viewportWidth), float(Video::s_viewportHeight) }; + AchievementMenu::Draw(); OptionsMenu::Draw(); AchievementOverlay::Draw(); @@ -2343,6 +2351,11 @@ static void ProcExecuteCommandList(const RenderCommand& cmd) float gammaG; float gammaB; uint32_t textureDescriptorIndex; + + int32_t viewportOffsetX; + int32_t viewportOffsetY; + int32_t viewportWidth; + int32_t viewportHeight; } constants; if (Config::XboxColorCorrection) @@ -2365,6 +2378,11 @@ static void ProcExecuteCommandList(const RenderCommand& cmd) constants.gammaB = 1.0f / std::clamp(constants.gammaB + offset, 0.1f, 4.0f); constants.textureDescriptorIndex = g_intermediaryBackBufferTextureDescriptorIndex; + constants.viewportOffsetX = (int32_t(g_swapChain->getWidth()) - int32_t(Video::s_viewportWidth)) / 2; + constants.viewportOffsetY = (int32_t(g_swapChain->getHeight()) - int32_t(Video::s_viewportHeight)) / 2; + constants.viewportWidth = Video::s_viewportWidth; + constants.viewportHeight = Video::s_viewportHeight; + auto &framebuffer = g_backBuffer->framebuffers[swapChainTexture]; if (!framebuffer) { @@ -2387,8 +2405,8 @@ static void ProcExecuteCommandList(const RenderCommand& cmd) commandList->setGraphicsDescriptorSet(g_textureDescriptorSet.get(), 0); SetRootDescriptor(g_uploadAllocators[g_frame].allocate(&constants, sizeof(constants), 0x100), 2); commandList->setFramebuffer(framebuffer.get()); - commandList->setViewports(RenderViewport(0.0f, 0.0f, g_intermediaryBackBufferTextureWidth, g_intermediaryBackBufferTextureHeight)); - commandList->setScissors(RenderRect(0, 0, g_intermediaryBackBufferTextureWidth, g_intermediaryBackBufferTextureHeight)); + commandList->setViewports(RenderViewport(0.0f, 0.0f, g_swapChain->getWidth(), g_swapChain->getHeight())); + commandList->setScissors(RenderRect(0, 0, g_swapChain->getWidth(), g_swapChain->getHeight())); commandList->drawInstanced(6, 1, 0, 0); commandList->barriers(RenderBarrierStage::GRAPHICS, RenderTextureBarrier(swapChainTexture, RenderTextureLayout::PRESENT)); } @@ -2442,6 +2460,56 @@ GuestSurface* Video::GetBackBuffer() return g_backBuffer; } +void Video::ComputeViewportDimensions() +{ + uint32_t width = g_swapChain->getWidth(); + uint32_t height = g_swapChain->getHeight(); + float aspectRatio = float(width) / float(height); + + switch (Config::AspectRatio) + { + case EAspectRatio::Wide: + { + if (aspectRatio > (16.0f / 9.0f)) + { + s_viewportWidth = height * 16 / 9; + s_viewportHeight = height; + } + else + { + s_viewportWidth = width; + s_viewportHeight = width * 9 / 16; + } + + break; + } + + case EAspectRatio::Narrow: + case EAspectRatio::OriginalNarrow: + { + if (aspectRatio > (4.0f / 3.0f)) + { + s_viewportWidth = height * 4 / 3; + s_viewportHeight = height; + } + else + { + s_viewportWidth = width; + s_viewportHeight = width * 3 / 4; + } + + break; + } + + default: + s_viewportWidth = width; + s_viewportHeight = height; + break; + } + + AspectRatioPatches::ComputeOffsets(); +} + static RenderFormat ConvertFormat(uint32_t format) { switch (format) @@ -2610,8 +2678,8 @@ static void FlushViewport() if (renderingToBackBuffer) { - float width = g_swapChain->getWidth(); - float height = g_swapChain->getHeight(); + float width = Video::s_viewportWidth; + float height = Video::s_viewportHeight; viewport.x *= width / g_backBuffer->width; viewport.y *= height / g_backBuffer->height; @@ -2637,8 +2705,8 @@ static void FlushViewport() if (renderingToBackBuffer) { - uint32_t width = g_swapChain->getWidth(); - uint32_t height = g_swapChain->getHeight(); + uint32_t width = Video::s_viewportWidth; + uint32_t height = Video::s_viewportHeight; scissorRect.left = scissorRect.left * width / g_backBuffer->width; scissorRect.top = scissorRect.top * height / g_backBuffer->height; @@ -4958,8 +5026,10 @@ void SetShadowResolutionMidAsmHook(PPCRegister& r11) static void SetResolution(be* device) { - uint32_t width = uint32_t(round(g_swapChain->getWidth() * Config::ResolutionScale)); - uint32_t height = uint32_t(round(g_swapChain->getHeight() * Config::ResolutionScale)); + Video::ComputeViewportDimensions(); + + uint32_t width = uint32_t(round(Video::s_viewportWidth * Config::ResolutionScale)); + uint32_t height = uint32_t(round(Video::s_viewportHeight * Config::ResolutionScale)); device[46] = width == 0 ? 880 : width; device[47] = height == 0 ? 720 : height; } @@ -6438,10 +6508,14 @@ void VideoConfigValueChangedCallback(IConfigDef* config) { // Config options that require internal resolution resize g_needsResize |= + config == &Config::AspectRatio || config == &Config::ResolutionScale || config == &Config::AntiAliasing || config == &Config::ShadowResolution; + if (g_needsResize) + Video::ComputeViewportDimensions(); + // Config options that require pipeline recompilation bool shouldRecompile = config == &Config::AntiAliasing || diff --git a/UnleashedRecomp/gpu/video.h b/UnleashedRecomp/gpu/video.h index 8143ab55..9c6a6bc3 100644 --- a/UnleashedRecomp/gpu/video.h +++ b/UnleashedRecomp/gpu/video.h @@ -15,12 +15,16 @@ using namespace plume; struct Video { + static inline uint32_t s_viewportWidth; + static inline uint32_t s_viewportHeight; + static void CreateHostDevice(const char *sdlVideoDriver); static void WaitOnSwapChain(); static void Present(); static void StartPipelinePrecompilation(); static void WaitForGPU(); static struct GuestSurface* GetBackBuffer(); + static void ComputeViewportDimensions(); }; struct GuestSamplerState diff --git a/UnleashedRecomp/patches/csd_patches.cpp b/UnleashedRecomp/patches/aspect_ratio_patches.cpp similarity index 98% rename from UnleashedRecomp/patches/csd_patches.cpp rename to UnleashedRecomp/patches/aspect_ratio_patches.cpp index d56d25b0..f6036a0b 100644 --- a/UnleashedRecomp/patches/csd_patches.cpp +++ b/UnleashedRecomp/patches/aspect_ratio_patches.cpp @@ -2,9 +2,9 @@ #include #include #include -#include #include +#include "aspect_ratio_patches.h" #include "camera_patches.h" // These are here for now to not recompile basically all of the project. @@ -191,8 +191,11 @@ static float ComputeScale(float aspectRatio) return ((aspectRatio * 720.0f) / 1280.0f) / sqrt((aspectRatio * 720.0f) / 1280.0f); } -static void ComputeOffsets(float width, float height) +void AspectRatioPatches::ComputeOffsets() { + float width = Video::s_viewportWidth; + float height = Video::s_viewportHeight; + g_aspectRatio = width / height; g_scale = 1.0f; @@ -224,25 +227,6 @@ static void ComputeOffsets(float width, float height) g_worldMapOffset = std::clamp((g_aspectRatio - NARROW_ASPECT_RATIO) / (WIDE_ASPECT_RATIO - NARROW_ASPECT_RATIO), 0.0f, 1.0f); } -static class SDLEventListenerForCSD : public SDLEventListener -{ -public: - void OnSDLEvent(SDL_Event* event) override - { - if (event->type == SDL_WINDOWEVENT && event->window.event == SDL_WINDOWEVENT_RESIZED) - ComputeOffsets(event->window.data1, event->window.data2); - } -} g_sdlEventListenerForCSD; - -// Chao::CSD::SetOffsets -PPC_FUNC_IMPL(__imp__sub_830C0A78); -PPC_FUNC(sub_830C0A78) -{ - __imp__sub_830C0A78(ctx, base); - - ComputeOffsets(GameWindow::s_width, GameWindow::s_height); -} - // SWA::CGameDocument::ComputeScreenPosition PPC_FUNC_IMPL(__imp__sub_8250FC70); PPC_FUNC(sub_8250FC70) diff --git a/UnleashedRecomp/patches/aspect_ratio_patches.h b/UnleashedRecomp/patches/aspect_ratio_patches.h new file mode 100644 index 00000000..443f13c6 --- /dev/null +++ b/UnleashedRecomp/patches/aspect_ratio_patches.h @@ -0,0 +1,6 @@ +#pragma once + +struct AspectRatioPatches +{ + static void ComputeOffsets(); +}; diff --git a/UnleashedRecomp/patches/camera_patches.cpp b/UnleashedRecomp/patches/camera_patches.cpp index 215f4227..5cdd72ff 100644 --- a/UnleashedRecomp/patches/camera_patches.cpp +++ b/UnleashedRecomp/patches/camera_patches.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include "camera_patches.h" static constexpr float ORIGINAL_ASPECT_RATIO = 4.0f / 3.0f; @@ -13,7 +14,7 @@ void CameraAspectRatioMidAsmHook(PPCRegister& r30, PPCRegister& r31) auto camera = (SWA::CCamera*)g_memory.Translate(r31.u32); // Dynamically adjust horizontal aspect ratio to window dimensions. - camera->m_HorzAspectRatio = float(GameWindow::s_width) / float(GameWindow::s_height); + camera->m_HorzAspectRatio = float(Video::s_viewportWidth) / float(Video::s_viewportHeight); } float AdjustFieldOfView(float fieldOfView, float aspectRatio) diff --git a/UnleashedRecomp/ui/options_menu.cpp b/UnleashedRecomp/ui/options_menu.cpp index eb8ac156..c1727b31 100644 --- a/UnleashedRecomp/ui/options_menu.cpp +++ b/UnleashedRecomp/ui/options_menu.cpp @@ -1057,8 +1057,8 @@ static void DrawInfoPanel() auto resScale = round(*(float*)g_selectedItem->GetValue() * 1000) / 1000; std::snprintf(buf, sizeof(buf), desc.c_str(), - (int)((float)GameWindow::s_width * resScale), - (int)((float)GameWindow::s_height * resScale)); + (int)((float)Video::s_viewportWidth * resScale), + (int)((float)Video::s_viewportHeight * resScale)); desc = buf; }