Implement the aspect ratio option.

This commit is contained in:
Skyth 2025-01-10 22:02:54 +03:00
parent 3647261f2b
commit a39b3ec855
8 changed files with 123 additions and 44 deletions

View file

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

View file

@ -5,12 +5,17 @@
#define g_Gamma vk::RawBufferLoad<float3>(g_PushConstants.SharedConstants + 0)
#define g_TextureDescriptorIndex vk::RawBufferLoad<uint>(g_PushConstants.SharedConstants + 12)
#define g_ViewportOffset vk::RawBufferLoad<int2>(g_PushConstants.SharedConstants + 16)
#define g_ViewportSize vk::RawBufferLoad<int2>(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<float4> 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;
}

View file

@ -26,6 +26,7 @@
#include <ui/options_menu.h>
#include <ui/sdl_listener.h>
#include <ui/game_window.h>
#include <patches/aspect_ratio_patches.h>
#include <user/config.h>
#include <xxHashMap.h>
@ -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<false>(&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<uint32_t>* 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 ||

View file

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

View file

@ -2,9 +2,9 @@
#include <api/SWA.h>
#include <app.h>
#include <ui/game_window.h>
#include <ui/sdl_listener.h>
#include <gpu/video.h>
#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)

View file

@ -0,0 +1,6 @@
#pragma once
struct AspectRatioPatches
{
static void ComputeOffsets();
};

View file

@ -1,6 +1,7 @@
#include <api/SWA.h>
#include <ui/game_window.h>
#include <user/config.h>
#include <gpu/video.h>
#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)

View file

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