D3D12: Use waitable swap chain
This commit is contained in:
parent
3e0c10d393
commit
83df6ce27c
|
@ -32,6 +32,7 @@
|
|||
|
||||
#include "core/config/project_settings.h"
|
||||
#include "core/io/marshalls.h"
|
||||
#include "main/main.h"
|
||||
#include "servers/rendering/rendering_device.h"
|
||||
#include "thirdparty/zlib/zlib.h"
|
||||
|
||||
|
@ -2294,11 +2295,32 @@ Error RenderingDeviceDriverD3D12::command_queue_execute_and_present(CommandQueue
|
|||
bool any_present_failed = false;
|
||||
for (uint32_t i = 0; i < p_swap_chains.size(); i++) {
|
||||
SwapChain *swap_chain = (SwapChain *)(p_swap_chains[i].id);
|
||||
bool skip_present = false;
|
||||
if (swap_chain->needs_wait) {
|
||||
DWORD wait = WaitForSingleObject(swap_chain->frame_latency_waitable_obj, 0);
|
||||
if (wait != WAIT_OBJECT_0) {
|
||||
skip_present = true;
|
||||
if (wait == WAIT_TIMEOUT) {
|
||||
// Force a redraw so that we can present the latest frame
|
||||
// for this swap chain on the next redraw.
|
||||
Main::force_redraw();
|
||||
} else if (wait == WAIT_FAILED) {
|
||||
DWORD error = GetLastError();
|
||||
ERR_PRINT(vformat("Wait for frame latency waitable failed with error: 0x%08X", (unsigned)error));
|
||||
} else {
|
||||
ERR_PRINT(vformat("Wait for frame latency waitable failed, WaitForSingleObject returned 0x%08X", (unsigned)wait));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (skip_present) {
|
||||
continue;
|
||||
}
|
||||
res = swap_chain->d3d_swap_chain->Present(swap_chain->sync_interval, swap_chain->present_flags);
|
||||
if (!SUCCEEDED(res)) {
|
||||
print_verbose(vformat("D3D12: Presenting swapchain failed with error 0x%08ux.", (uint64_t)res));
|
||||
any_present_failed = true;
|
||||
}
|
||||
swap_chain->needs_wait = true;
|
||||
}
|
||||
|
||||
return any_present_failed ? FAILED : OK;
|
||||
|
@ -2412,6 +2434,10 @@ void RenderingDeviceDriverD3D12::command_buffer_execute_secondary(CommandBufferI
|
|||
void RenderingDeviceDriverD3D12::_swap_chain_release(SwapChain *p_swap_chain) {
|
||||
_swap_chain_release_buffers(p_swap_chain);
|
||||
|
||||
CloseHandle(p_swap_chain->frame_latency_waitable_obj);
|
||||
p_swap_chain->frame_latency_waitable_obj = nullptr;
|
||||
p_swap_chain->needs_wait = false;
|
||||
|
||||
p_swap_chain->d3d_swap_chain.Reset();
|
||||
}
|
||||
|
||||
|
@ -2493,6 +2519,8 @@ Error RenderingDeviceDriverD3D12::swap_chain_resize(CommandQueueID p_cmd_queue,
|
|||
break;
|
||||
}
|
||||
|
||||
creation_flags |= DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT;
|
||||
|
||||
print_verbose("Using swap chain flags: " + itos(creation_flags) + ", sync interval: " + itos(sync_interval) + ", present flags: " + itos(present_flags));
|
||||
|
||||
if (swap_chain->d3d_swap_chain != nullptr && creation_flags != swap_chain->creation_flags) {
|
||||
|
@ -2535,6 +2563,9 @@ Error RenderingDeviceDriverD3D12::swap_chain_resize(CommandQueueID p_cmd_queue,
|
|||
|
||||
res = context_driver->dxgi_factory_get()->MakeWindowAssociation(surface->hwnd, DXGI_MWA_NO_ALT_ENTER | DXGI_MWA_NO_WINDOW_CHANGES);
|
||||
ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);
|
||||
|
||||
swap_chain->frame_latency_waitable_obj = swap_chain->d3d_swap_chain->GetFrameLatencyWaitableObject();
|
||||
swap_chain->needs_wait = true;
|
||||
}
|
||||
|
||||
res = swap_chain->d3d_swap_chain->GetDesc1(&swap_chain_desc);
|
||||
|
@ -2555,6 +2586,8 @@ Error RenderingDeviceDriverD3D12::swap_chain_resize(CommandQueueID p_cmd_queue,
|
|||
swap_chain->render_targets_info.reserve(swap_chain_desc.BufferCount);
|
||||
swap_chain->framebuffers.reserve(swap_chain_desc.BufferCount);
|
||||
|
||||
swap_chain->d3d_swap_chain->SetMaximumFrameLatency(swap_chain_desc.BufferCount - 1);
|
||||
|
||||
for (uint32_t i = 0; i < swap_chain_desc.BufferCount; i++) {
|
||||
// Retrieve the resource corresponding to the swap chain's buffer.
|
||||
ID3D12Resource *render_target = nullptr;
|
||||
|
@ -2623,6 +2656,24 @@ void RenderingDeviceDriverD3D12::swap_chain_free(SwapChainID p_swap_chain) {
|
|||
memdelete(swap_chain);
|
||||
}
|
||||
|
||||
void RenderingDeviceDriverD3D12::wait_for_present(SwapChainID p_swap_chain) {
|
||||
SwapChain *swap_chain = (SwapChain *)(p_swap_chain.id);
|
||||
|
||||
if (swap_chain->needs_wait) {
|
||||
DWORD wait = WaitForSingleObject(swap_chain->frame_latency_waitable_obj, 1000);
|
||||
if (wait != WAIT_OBJECT_0) {
|
||||
if (wait == WAIT_FAILED) {
|
||||
DWORD error = GetLastError();
|
||||
ERR_PRINT(vformat("Wait for frame latency waitable failed with error: 0x%08X", (unsigned)error));
|
||||
} else {
|
||||
ERR_PRINT(vformat("Wait for frame latency waitable failed, WaitForSingleObject returned 0x%08X", (unsigned)wait));
|
||||
}
|
||||
} else {
|
||||
swap_chain->needs_wait = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*********************/
|
||||
/**** FRAMEBUFFER ****/
|
||||
/*********************/
|
||||
|
|
|
@ -512,6 +512,8 @@ private:
|
|||
TightLocalVector<TextureInfo> render_targets_info;
|
||||
TightLocalVector<FramebufferID> framebuffers;
|
||||
RDD::DataFormat data_format = DATA_FORMAT_MAX;
|
||||
HANDLE frame_latency_waitable_obj = nullptr;
|
||||
bool needs_wait = false;
|
||||
};
|
||||
|
||||
void _swap_chain_release(SwapChain *p_swap_chain);
|
||||
|
@ -524,6 +526,7 @@ public:
|
|||
virtual RenderPassID swap_chain_get_render_pass(SwapChainID p_swap_chain) override;
|
||||
virtual DataFormat swap_chain_get_format(SwapChainID p_swap_chain) override;
|
||||
virtual void swap_chain_free(SwapChainID p_swap_chain) override;
|
||||
virtual void wait_for_present(SwapChainID p_swap_chain) override;
|
||||
|
||||
/*********************/
|
||||
/**** FRAMEBUFFER ****/
|
||||
|
|
|
@ -3003,6 +3003,12 @@ String DisplayServerWindows::keyboard_get_layout_name(int p_index) const {
|
|||
void DisplayServerWindows::process_events() {
|
||||
ERR_FAIL_COND(!Thread::is_main_thread());
|
||||
|
||||
#ifdef RD_ENABLED
|
||||
if (rendering_device) {
|
||||
rendering_device->screen_wait_for_present(get_focused_window() == INVALID_WINDOW_ID ? MAIN_WINDOW_ID : get_focused_window());
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!drop_events) {
|
||||
joypad->process_joypads();
|
||||
}
|
||||
|
|
|
@ -3544,6 +3544,15 @@ Error RenderingDevice::screen_free(DisplayServer::WindowID p_screen) {
|
|||
return OK;
|
||||
}
|
||||
|
||||
void RenderingDevice::screen_wait_for_present(DisplayServer::WindowID p_screen) {
|
||||
_THREAD_SAFE_METHOD_
|
||||
|
||||
HashMap<DisplayServer::WindowID, RDD::SwapChainID>::ConstIterator it = screen_swap_chains.find(p_screen);
|
||||
ERR_FAIL_COND_MSG(it == screen_swap_chains.end(), "A swap chain was not created for the screen.");
|
||||
|
||||
driver->wait_for_present(it->value);
|
||||
}
|
||||
|
||||
/*******************/
|
||||
/**** DRAW LIST ****/
|
||||
/*******************/
|
||||
|
|
|
@ -1054,6 +1054,7 @@ public:
|
|||
int screen_get_height(DisplayServer::WindowID p_screen = DisplayServer::MAIN_WINDOW_ID) const;
|
||||
FramebufferFormatID screen_get_framebuffer_format(DisplayServer::WindowID p_screen = DisplayServer::MAIN_WINDOW_ID) const;
|
||||
Error screen_free(DisplayServer::WindowID p_screen = DisplayServer::MAIN_WINDOW_ID);
|
||||
void screen_wait_for_present(DisplayServer::WindowID p_screen);
|
||||
|
||||
/*************************/
|
||||
/**** DRAW LISTS (II) ****/
|
||||
|
|
|
@ -459,6 +459,9 @@ public:
|
|||
// Wait until all rendering associated to the swap chain is finished before deleting it.
|
||||
virtual void swap_chain_free(SwapChainID p_swap_chain) = 0;
|
||||
|
||||
// Wait for the swap chain to be presented on the screen.
|
||||
virtual void wait_for_present(SwapChainID p_swap_chain){};
|
||||
|
||||
/*********************/
|
||||
/**** FRAMEBUFFER ****/
|
||||
/*********************/
|
||||
|
|
Loading…
Reference in New Issue