Make max frame latency configurable.

This commit is contained in:
Skyth 2024-12-25 13:06:08 +03:00
parent 5c3d98a4e3
commit 27427f7950
7 changed files with 21 additions and 17 deletions

View file

@ -1191,7 +1191,7 @@ namespace plume {
// D3D12SwapChain // D3D12SwapChain
D3D12SwapChain::D3D12SwapChain(D3D12CommandQueue *commandQueue, RenderWindow renderWindow, uint32_t textureCount, RenderFormat format) { D3D12SwapChain::D3D12SwapChain(D3D12CommandQueue *commandQueue, RenderWindow renderWindow, uint32_t textureCount, RenderFormat format, uint32_t maxFrameLatency) {
assert(commandQueue != nullptr); assert(commandQueue != nullptr);
assert(renderWindow != 0); assert(renderWindow != 0);
@ -1199,6 +1199,7 @@ namespace plume {
this->renderWindow = renderWindow; this->renderWindow = renderWindow;
this->textureCount = textureCount; this->textureCount = textureCount;
this->format = format; this->format = format;
this->maxFrameLatency = maxFrameLatency;
// Store the native format representation. // Store the native format representation.
nativeFormat = toDXGI(format); nativeFormat = toDXGI(format);
@ -1230,7 +1231,7 @@ namespace plume {
} }
d3d = static_cast<IDXGISwapChain3 *>(swapChain1); d3d = static_cast<IDXGISwapChain3 *>(swapChain1);
d3d->SetMaximumFrameLatency(2); d3d->SetMaximumFrameLatency(maxFrameLatency);
waitableObject = d3d->GetFrameLatencyWaitableObject(); waitableObject = d3d->GetFrameLatencyWaitableObject();
textures.resize(textureCount); textures.resize(textureCount);
@ -2199,8 +2200,8 @@ namespace plume {
} }
} }
std::unique_ptr<RenderSwapChain> D3D12CommandQueue::createSwapChain(RenderWindow renderWindow, uint32_t bufferCount, RenderFormat format) { std::unique_ptr<RenderSwapChain> D3D12CommandQueue::createSwapChain(RenderWindow renderWindow, uint32_t bufferCount, RenderFormat format, uint32_t maxFrameLatency) {
return std::make_unique<D3D12SwapChain>(this, renderWindow, bufferCount, format); return std::make_unique<D3D12SwapChain>(this, renderWindow, bufferCount, format, maxFrameLatency);
} }
void D3D12CommandQueue::executeCommandLists(const RenderCommandList **commandLists, uint32_t commandListCount, RenderCommandSemaphore **waitSemaphores, uint32_t waitSemaphoreCount, RenderCommandSemaphore **signalSemaphores, uint32_t signalSemaphoreCount, RenderCommandFence *signalFence) { void D3D12CommandQueue::executeCommandLists(const RenderCommandList **commandLists, uint32_t commandListCount, RenderCommandSemaphore **waitSemaphores, uint32_t waitSemaphoreCount, RenderCommandSemaphore **signalSemaphores, uint32_t signalSemaphoreCount, RenderCommandFence *signalFence) {

View file

@ -107,8 +107,9 @@ namespace plume {
uint32_t height = 0; uint32_t height = 0;
uint32_t refreshRate = 0; uint32_t refreshRate = 0;
bool vsyncEnabled = true; bool vsyncEnabled = true;
uint32_t maxFrameLatency = 0;
D3D12SwapChain(D3D12CommandQueue *commandQueue, RenderWindow renderWindow, uint32_t textureCount, RenderFormat format); D3D12SwapChain(D3D12CommandQueue *commandQueue, RenderWindow renderWindow, uint32_t textureCount, RenderFormat format, uint32_t maxFrameLatency);
~D3D12SwapChain() override; ~D3D12SwapChain() override;
bool present(uint32_t textureIndex, RenderCommandSemaphore **waitSemaphores, uint32_t waitSemaphoreCount) override; bool present(uint32_t textureIndex, RenderCommandSemaphore **waitSemaphores, uint32_t waitSemaphoreCount) override;
void wait() override; void wait() override;
@ -231,7 +232,7 @@ namespace plume {
D3D12CommandQueue(D3D12Device *device, RenderCommandListType type); D3D12CommandQueue(D3D12Device *device, RenderCommandListType type);
~D3D12CommandQueue() override; ~D3D12CommandQueue() override;
std::unique_ptr<RenderSwapChain> createSwapChain(RenderWindow renderWindow, uint32_t textureCount, RenderFormat format) override; std::unique_ptr<RenderSwapChain> createSwapChain(RenderWindow renderWindow, uint32_t textureCount, RenderFormat format, uint32_t newFrameLatency) override;
void executeCommandLists(const RenderCommandList **commandLists, uint32_t commandListCount, RenderCommandSemaphore **waitSemaphores, uint32_t waitSemaphoreCount, RenderCommandSemaphore **signalSemaphores, uint32_t signalSemaphoreCount, RenderCommandFence *signalFence) override; void executeCommandLists(const RenderCommandList **commandLists, uint32_t commandListCount, RenderCommandSemaphore **waitSemaphores, uint32_t waitSemaphoreCount, RenderCommandSemaphore **signalSemaphores, uint32_t signalSemaphoreCount, RenderCommandFence *signalFence) override;
void waitForCommandFence(RenderCommandFence *fence) override; void waitForCommandFence(RenderCommandFence *fence) override;
}; };

View file

@ -191,7 +191,7 @@ namespace plume {
struct RenderCommandQueue { struct RenderCommandQueue {
virtual ~RenderCommandQueue() { } virtual ~RenderCommandQueue() { }
virtual std::unique_ptr<RenderSwapChain> createSwapChain(RenderWindow renderWindow, uint32_t textureCount, RenderFormat format) = 0; virtual std::unique_ptr<RenderSwapChain> createSwapChain(RenderWindow renderWindow, uint32_t textureCount, RenderFormat format, uint32_t maxFrameLatency) = 0;
virtual void executeCommandLists(const RenderCommandList **commandLists, uint32_t commandListCount, RenderCommandSemaphore **waitSemaphores = nullptr, uint32_t waitSemaphoreCount = 0, RenderCommandSemaphore **signalSemaphores = nullptr, uint32_t signalSemaphoreCount = 0, RenderCommandFence *signalFence = nullptr) = 0; virtual void executeCommandLists(const RenderCommandList **commandLists, uint32_t commandListCount, RenderCommandSemaphore **waitSemaphores = nullptr, uint32_t waitSemaphoreCount = 0, RenderCommandSemaphore **signalSemaphores = nullptr, uint32_t signalSemaphoreCount = 0, RenderCommandFence *signalFence = nullptr) = 0;
virtual void waitForCommandFence(RenderCommandFence *fence) = 0; virtual void waitForCommandFence(RenderCommandFence *fence) = 0;

View file

@ -1966,13 +1966,14 @@ namespace plume {
// VulkanSwapChain // VulkanSwapChain
VulkanSwapChain::VulkanSwapChain(VulkanCommandQueue *commandQueue, RenderWindow renderWindow, uint32_t textureCount, RenderFormat format) { VulkanSwapChain::VulkanSwapChain(VulkanCommandQueue *commandQueue, RenderWindow renderWindow, uint32_t textureCount, RenderFormat format, uint32_t maxFrameLatency) {
assert(commandQueue != nullptr); assert(commandQueue != nullptr);
assert(textureCount > 0); assert(textureCount > 0);
this->commandQueue = commandQueue; this->commandQueue = commandQueue;
this->renderWindow = renderWindow; this->renderWindow = renderWindow;
this->format = format; this->format = format;
this->maxFrameLatency = maxFrameLatency;
VkResult res; VkResult res;
@ -2170,10 +2171,9 @@ namespace plume {
} }
void VulkanSwapChain::wait() { void VulkanSwapChain::wait() {
constexpr uint64_t MaxFrameDelay = 1; if (commandQueue->device->capabilities.presentWait && (currentPresentId >= maxFrameLatency)) {
if (commandQueue->device->capabilities.presentWait && (currentPresentId > MaxFrameDelay)) {
constexpr uint64_t waitTimeout = 100000000; constexpr uint64_t waitTimeout = 100000000;
vkWaitForPresentKHR(commandQueue->device->vk, vk, currentPresentId - MaxFrameDelay, waitTimeout); vkWaitForPresentKHR(commandQueue->device->vk, vk, currentPresentId - (maxFrameLatency - 1), waitTimeout);
} }
} }
@ -3276,8 +3276,8 @@ namespace plume {
device->queueFamilies[familyIndex].remove(this); device->queueFamilies[familyIndex].remove(this);
} }
std::unique_ptr<RenderSwapChain> VulkanCommandQueue::createSwapChain(RenderWindow renderWindow, uint32_t bufferCount, RenderFormat format) { std::unique_ptr<RenderSwapChain> VulkanCommandQueue::createSwapChain(RenderWindow renderWindow, uint32_t bufferCount, RenderFormat format, uint32_t maxFrameLatency) {
return std::make_unique<VulkanSwapChain>(this, renderWindow, bufferCount, format); return std::make_unique<VulkanSwapChain>(this, renderWindow, bufferCount, format, maxFrameLatency);
} }
void VulkanCommandQueue::executeCommandLists(const RenderCommandList **commandLists, uint32_t commandListCount, RenderCommandSemaphore **waitSemaphores, uint32_t waitSemaphoreCount, RenderCommandSemaphore **signalSemaphores, uint32_t signalSemaphoreCount, RenderCommandFence *signalFence) { void VulkanCommandQueue::executeCommandLists(const RenderCommandList **commandLists, uint32_t commandListCount, RenderCommandSemaphore **waitSemaphores, uint32_t waitSemaphoreCount, RenderCommandSemaphore **signalSemaphores, uint32_t signalSemaphoreCount, RenderCommandFence *signalFence) {

View file

@ -231,8 +231,9 @@ namespace plume {
std::vector<VulkanTexture> textures; std::vector<VulkanTexture> textures;
uint64_t currentPresentId = 0; uint64_t currentPresentId = 0;
bool immediatePresentModeSupported = false; bool immediatePresentModeSupported = false;
uint32_t maxFrameLatency = 0;
VulkanSwapChain(VulkanCommandQueue *commandQueue, RenderWindow renderWindow, uint32_t textureCount, RenderFormat format); VulkanSwapChain(VulkanCommandQueue *commandQueue, RenderWindow renderWindow, uint32_t textureCount, RenderFormat format, uint32_t maxFrameLatency);
~VulkanSwapChain() override; ~VulkanSwapChain() override;
bool present(uint32_t textureIndex, RenderCommandSemaphore **waitSemaphores, uint32_t waitSemaphoreCount) override; bool present(uint32_t textureIndex, RenderCommandSemaphore **waitSemaphores, uint32_t waitSemaphoreCount) override;
void wait() override; void wait() override;
@ -347,7 +348,7 @@ namespace plume {
VulkanCommandQueue(VulkanDevice *device, RenderCommandListType commandListType); VulkanCommandQueue(VulkanDevice *device, RenderCommandListType commandListType);
~VulkanCommandQueue() override; ~VulkanCommandQueue() override;
std::unique_ptr<RenderSwapChain> createSwapChain(RenderWindow renderWindow, uint32_t bufferCount, RenderFormat format) override; std::unique_ptr<RenderSwapChain> createSwapChain(RenderWindow renderWindow, uint32_t bufferCount, RenderFormat format, uint32_t maxFrameLatency) override;
void executeCommandLists(const RenderCommandList **commandLists, uint32_t commandListCount, RenderCommandSemaphore **waitSemaphores, uint32_t waitSemaphoreCount, RenderCommandSemaphore **signalSemaphores, uint32_t signalSemaphoreCount, RenderCommandFence *signalFence) override; void executeCommandLists(const RenderCommandList **commandLists, uint32_t commandListCount, RenderCommandSemaphore **waitSemaphores, uint32_t waitSemaphoreCount, RenderCommandSemaphore **signalSemaphores, uint32_t signalSemaphoreCount, RenderCommandFence *signalFence) override;
void waitForCommandFence(RenderCommandFence *fence) override; void waitForCommandFence(RenderCommandFence *fence) override;
}; };

View file

@ -1464,7 +1464,7 @@ void Video::CreateHostDevice(const char *sdlVideoDriver)
break; break;
} }
g_swapChain = g_queue->createSwapChain(GameWindow::s_renderWindow, bufferCount, BACKBUFFER_FORMAT); g_swapChain = g_queue->createSwapChain(GameWindow::s_renderWindow, bufferCount, BACKBUFFER_FORMAT, Config::MaxFrameLatency);
g_swapChain->setVsyncEnabled(Config::VSync); g_swapChain->setVsyncEnabled(Config::VSync);
g_swapChainValid = !g_swapChain->needsResize(); g_swapChainValid = !g_swapChain->needsResize();

View file

@ -647,10 +647,11 @@ public:
CONFIG_DEFINE_LOCALISED("Video", bool, VSync, true); CONFIG_DEFINE_LOCALISED("Video", bool, VSync, true);
CONFIG_DEFINE_ENUM("Video", ETripleBuffering, TripleBuffering, ETripleBuffering::Auto); CONFIG_DEFINE_ENUM("Video", ETripleBuffering, TripleBuffering, ETripleBuffering::Auto);
CONFIG_DEFINE_LOCALISED("Video", int32_t, FPS, 60); CONFIG_DEFINE_LOCALISED("Video", int32_t, FPS, 60);
CONFIG_DEFINE("Video", uint32_t, MaxFrameLatency, 2);
CONFIG_DEFINE_LOCALISED("Video", float, Brightness, 0.5f); CONFIG_DEFINE_LOCALISED("Video", float, Brightness, 0.5f);
CONFIG_DEFINE_ENUM_LOCALISED("Video", EAntiAliasing, AntiAliasing, EAntiAliasing::MSAA4x); CONFIG_DEFINE_ENUM_LOCALISED("Video", EAntiAliasing, AntiAliasing, EAntiAliasing::MSAA4x);
CONFIG_DEFINE_LOCALISED("Video", bool, TransparencyAntiAliasing, true); CONFIG_DEFINE_LOCALISED("Video", bool, TransparencyAntiAliasing, true);
CONFIG_DEFINE("Video", size_t, AnisotropicFiltering, 16); CONFIG_DEFINE("Video", uint32_t, AnisotropicFiltering, 16);
CONFIG_DEFINE_ENUM_LOCALISED("Video", EShadowResolution, ShadowResolution, EShadowResolution::x4096); CONFIG_DEFINE_ENUM_LOCALISED("Video", EShadowResolution, ShadowResolution, EShadowResolution::x4096);
CONFIG_DEFINE_ENUM_LOCALISED("Video", EGITextureFiltering, GITextureFiltering, EGITextureFiltering::Bicubic); CONFIG_DEFINE_ENUM_LOCALISED("Video", EGITextureFiltering, GITextureFiltering, EGITextureFiltering::Bicubic);
CONFIG_DEFINE_ENUM("Video", EDepthOfFieldQuality, DepthOfFieldQuality, EDepthOfFieldQuality::Auto); CONFIG_DEFINE_ENUM("Video", EDepthOfFieldQuality, DepthOfFieldQuality, EDepthOfFieldQuality::Auto);