From c5e195fef336037b5ec3bf098b2830440f48706a Mon Sep 17 00:00:00 2001 From: Skyth <19259897+blueskythlikesclouds@users.noreply.github.com> Date: Tue, 8 Oct 2024 12:24:37 +0300 Subject: [PATCH] Recreate internal framebuffers when swap chain gets resized. --- UnleashedRecomp/gpu/rhi/rt64_d3d12.cpp | 4 ++ UnleashedRecomp/gpu/rhi/rt64_d3d12.h | 1 + .../gpu/rhi/rt64_render_interface.h | 3 +- UnleashedRecomp/gpu/rhi/rt64_vulkan.cpp | 4 ++ UnleashedRecomp/gpu/rhi/rt64_vulkan.h | 1 + UnleashedRecomp/gpu/video.cpp | 65 +++++++++++++++---- 6 files changed, 63 insertions(+), 15 deletions(-) diff --git a/UnleashedRecomp/gpu/rhi/rt64_d3d12.cpp b/UnleashedRecomp/gpu/rhi/rt64_d3d12.cpp index 421a8fa..0a7b1e2 100644 --- a/UnleashedRecomp/gpu/rhi/rt64_d3d12.cpp +++ b/UnleashedRecomp/gpu/rhi/rt64_d3d12.cpp @@ -3630,6 +3630,10 @@ namespace RT64 { return countsSupported; } + void D3D12Device::waitIdle() const { + assert(false && "Use fences to replicate wait idle behavior on D3D12."); + } + void D3D12Device::release() { if (d3d != nullptr) { d3d->Release(); diff --git a/UnleashedRecomp/gpu/rhi/rt64_d3d12.h b/UnleashedRecomp/gpu/rhi/rt64_d3d12.h index 5c14cf3..0efa0e1 100644 --- a/UnleashedRecomp/gpu/rhi/rt64_d3d12.h +++ b/UnleashedRecomp/gpu/rhi/rt64_d3d12.h @@ -433,6 +433,7 @@ namespace RT64 { const RenderDeviceCapabilities &getCapabilities() const override; const RenderDeviceDescription &getDescription() const override; RenderSampleCounts getSampleCountsSupported(RenderFormat format) const override; + void waitIdle() const override; void release(); bool isValid() const; }; diff --git a/UnleashedRecomp/gpu/rhi/rt64_render_interface.h b/UnleashedRecomp/gpu/rhi/rt64_render_interface.h index 3b6ff7c..b57cc34 100644 --- a/UnleashedRecomp/gpu/rhi/rt64_render_interface.h +++ b/UnleashedRecomp/gpu/rhi/rt64_render_interface.h @@ -189,7 +189,7 @@ namespace RT64 { // Concrete implementation shortcuts. inline void executeCommandLists(const RenderCommandList *commandList, RenderCommandFence *signalFence = nullptr) { - executeCommandLists(&commandList, 1, nullptr, 0, nullptr, 0, signalFence); + executeCommandLists(commandList != nullptr ? &commandList : nullptr, commandList != nullptr ? 1 : 0, nullptr, 0, nullptr, 0, signalFence); } }; @@ -223,6 +223,7 @@ namespace RT64 { virtual const RenderDeviceCapabilities &getCapabilities() const = 0; virtual const RenderDeviceDescription &getDescription() const = 0; virtual RenderSampleCounts getSampleCountsSupported(RenderFormat format) const = 0; + virtual void waitIdle() const = 0; }; struct RenderInterface { diff --git a/UnleashedRecomp/gpu/rhi/rt64_vulkan.cpp b/UnleashedRecomp/gpu/rhi/rt64_vulkan.cpp index ff0127b..79a1d82 100644 --- a/UnleashedRecomp/gpu/rhi/rt64_vulkan.cpp +++ b/UnleashedRecomp/gpu/rhi/rt64_vulkan.cpp @@ -3966,6 +3966,10 @@ namespace RT64 { } } + void VulkanDevice::waitIdle() const { + vkDeviceWaitIdle(vk); + } + void VulkanDevice::release() { if (allocator != VK_NULL_HANDLE) { vmaDestroyAllocator(allocator); diff --git a/UnleashedRecomp/gpu/rhi/rt64_vulkan.h b/UnleashedRecomp/gpu/rhi/rt64_vulkan.h index 481611d..52f5aaa 100644 --- a/UnleashedRecomp/gpu/rhi/rt64_vulkan.h +++ b/UnleashedRecomp/gpu/rhi/rt64_vulkan.h @@ -391,6 +391,7 @@ namespace RT64 { const RenderDeviceCapabilities &getCapabilities() const override; const RenderDeviceDescription &getDescription() const override; RenderSampleCounts getSampleCountsSupported(RenderFormat format) const override; + void waitIdle() const override; void release(); bool isValid() const; }; diff --git a/UnleashedRecomp/gpu/video.cpp b/UnleashedRecomp/gpu/video.cpp index d6e1198..75a1111 100644 --- a/UnleashedRecomp/gpu/video.cpp +++ b/UnleashedRecomp/gpu/video.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -562,13 +563,50 @@ static void CreateHostDevice() static void WaitForGPU() { - for (size_t i = 0; i < NUM_FRAMES; i++) + if (g_vulkan) { - if (g_commandListStates[i]) + g_device->waitIdle(); + } + else + { + for (size_t i = 0; i < NUM_FRAMES; i++) { - g_queue->waitForCommandFence(g_commandFences[i].get()); - g_commandListStates[i] = false; + if (g_commandListStates[i]) + { + g_queue->waitForCommandFence(g_commandFences[i].get()); + g_commandListStates[i] = false; + } } + g_queue->executeCommandLists(nullptr, g_commandFences[0].get()); + g_queue->waitForCommandFence(g_commandFences[0].get()); + } +} + +static PPCRegister g_r3; +static PPCRegister g_r4; +static PPCRegister g_r5; + +PPC_FUNC_IMPL(__imp__sub_8258C8A0); +PPC_FUNC(sub_8258C8A0) +{ + g_r3 = ctx.r3; + g_r4 = ctx.r4; + g_r5 = ctx.r5; + __imp__sub_8258C8A0(ctx, base); +} + +static void ResizeSwapChain() +{ + WaitForGPU(); + g_backBuffer->framebuffers.clear(); + + if (g_swapChain->resize() && g_r3.u32 != NULL) + { + auto ctx = GetPPCContext(); + ctx->r3 = g_r3; + ctx->r4 = g_r4; + ctx->r5 = g_r5; + GuestCode::Run(__imp__sub_8258C8A0, ctx); } } @@ -585,21 +623,18 @@ static void BeginCommandList() { g_swapChainValid = g_swapChain->acquireTexture(g_acquireSemaphores[g_frame].get(), &g_backBufferIndex); if (g_swapChainValid) - { g_backBuffer->texture = g_swapChain->getTexture(g_backBufferIndex); - g_backBuffer->pendingBarrier = true; - } } else { - WaitForGPU(); - g_backBuffer->framebuffers.clear(); - g_swapChain->resize(); + ResizeSwapChain(); } if (!g_swapChainValid) g_backBuffer->texture = g_backBuffer->textureHolder.get(); + g_backBuffer->pendingBarrier = true; + auto& commandList = g_commandLists[g_frame]; commandList->begin(); @@ -1052,6 +1087,8 @@ static void FlushFramebuffer() g_depthStencil->pendingBarrier = false; } + FlushBarriers(); + if (g_dirtyStates.renderTargetAndDepthStencil) { GuestSurface* framebufferContainer = nullptr; @@ -1102,8 +1139,6 @@ static void FlushFramebuffer() g_dirtyStates.renderTargetAndDepthStencil = false; } - - FlushBarriers(); } static void Clear(GuestDevice* device, uint32_t flags, uint32_t, be* color, double z) @@ -2338,8 +2373,10 @@ void SetShadowResolutionMidAsmHook(PPCRegister& r11) static void SetResolution(be* device) { - device[46] = 1920; - device[47] = 1080; + uint32_t width = g_swapChain->getWidth(); + uint32_t height = g_swapChain->getHeight(); + device[46] = width == 0 ? 880 : width; + device[47] = height == 0 ? 720 : height; } static uint32_t StubFunction()