-
-
Notifications
You must be signed in to change notification settings - Fork 21.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Use WorkerThreadPool for Server threads (enhanced) #90268
Conversation
0109e33
to
9a81679
Compare
#if defined(GLES3_ENABLED) | ||
if (gl_manager_angle) { | ||
gl_manager_angle->release_current(); | ||
} | ||
if (gl_manager_legacy) { | ||
gl_manager_legacy->release_current(); | ||
} | ||
#endif | ||
} | ||
|
||
void DisplayServerMacOS::make_rendering_thread() { | ||
#if defined(GLES3_ENABLED) | ||
if (gl_manager_angle) { | ||
gl_manager_angle->make_current(); | ||
} | ||
if (gl_manager_legacy) { | ||
gl_manager_legacy->make_current(); | ||
} | ||
#endif |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems to be called from the thread when it is started and set the current GL context (to the context of the active window), but GL context is already set from _draw_viewport()
at the start of each window drawing, so it's likely redundant (probably part of the old 3.x single windows code).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That seems to be the case indeed. However, I'm not clear on what the right API would be because we now have the concepts of windows and threads somewhat conflated. I'm wondering if the right call would be the following:
- Remove
DisplayServer::make
/release_rendering_thread()
. - Remove
make
/release_current()
from the various GL context classes. - Modify
window_make_current()
so that takingINVALID_WINDOW_ID
means releasing the context.
(When I say remove, it may be needed to be understood as deprecate until we can remove.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the next push, I'm replacing the commit where I added those by one that simplifies the APIs (without breaking compat, I think). DisplayServer
as well as the various GL managers can therefore now have a window-specific make current, a global release, and call it a day.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For the reference:
Multithreaded compatibility renderer was crashing (in the GLES3::Utilities::get_video_adapter_api_version()
) before this PR. With it, it's no longer crashing, but still displaying only black screen. Multithreaded Vulkan renderer also not rendering anything (both with and without this PR), might be macOS specific issue, I'll check it later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In both cases, it deadlocks inside blit_render_targets_to_screen
.
Main thread:
🔻 Waiting for CommandQueueMT mutex.
std::__1::recursive_mutex::lock() (@std::__1::recursive_mutex::lock():7)
CommandQueueMT::Command1<RendererCanvasCull, void (RendererCanvasCull::*)(RID), RID>* CommandQueueMT::allocate_and_lock<CommandQueueMT::Command1<RendererCanvasCull, void (RendererCanvasCull::*)(RID), RID>>() (core/templates/command_queue_mt.h:362)
void CommandQueueMT::push<RendererCanvasCull, void (RendererCanvasCull::*)(RID), RID>(RendererCanvasCull*, void (RendererCanvasCull::*)(RID), RID) (core/templates/command_queue_mt.h:407)
RenderingServerDefault::canvas_item_clear(RID) (servers/rendering/rendering_server_default.h:916)
CanvasItem::_redraw_callback() (scene/main/canvas_item.cpp:137)
CallQueue::_call_function(Callable const&, Variant const*, int, bool) (core/object/message_queue.cpp:221)
CallQueue::flush() (core/object/message_queue.cpp:326)
SceneTree::process(double) (scene/main/scene_tree.cpp:537)
🔻 Inside main evnet loop.
Main::iteration() (main/main.cpp:4013)
OS_MacOS::run() (platform/macos/os_macos.mm:778)
main (platform/macos/godot_main_macos.mm:84)
start (@start:593)
Rendering thread:
🔻 Since nothing seems directy holding it in the Engine code, I assue it's waiting for the next main event loop iteration, but main thread is locked.
_dlock_wait (@_dlock_wait:17)
_dispatch_thread_event_wait_slow (@_dispatch_thread_event_wait_slow:17)
-[CAMetalLayer(MoltenVK) screenMVK] (@-[CAMetalLayer(MoltenVK) screenMVK]:31)
MVKSwapchain::initSurfaceImages(VkSwapchainCreateInfoKHR const*, unsigned int) (@MVKSwapchain::initSurfaceImages(VkSwapchainCreateInfoKHR const*, unsigned int):153)
MVKSwapchain::MVKSwapchain(MVKDevice*, VkSwapchainCreateInfoKHR const*) (@MVKSwapchain::MVKSwapchain(MVKDevice*, VkSwapchainCreateInfoKHR const*):183)
MVKDevice::createSwapchain(VkSwapchainCreateInfoKHR const*, VkAllocationCallbacks const*) (@MVKDevice::createSwapchain(VkSwapchainCreateInfoKHR const*, VkAllocationCallbacks const*):15)
vkCreateSwapchainKHR (@vkCreateSwapchainKHR:31)
RenderingDeviceDriverVulkan::swap_chain_resize(RenderingDeviceDriver::CommandQueueID, RenderingDeviceDriver::SwapChainID, unsigned int) (drivers/vulkan/rendering_device_driver_vulkan.cpp:2663)
RenderingDevice::screen_prepare_for_drawing(int) (servers/rendering/rendering_device.cpp:3190)
RendererCompositorRD::blit_render_targets_to_screen(int, BlitToScreen const*, int) (servers/rendering/renderer_rd/renderer_compositor_rd.cpp:37)
RendererViewport::draw_viewports(bool) (servers/rendering/renderer_viewport.cpp:861)
RenderingServerDefault::_draw(bool, double) (servers/rendering/rendering_server_default.cpp:89)
🔻 This lock CommandQueueMT mutex.
CommandQueueMT::_flush() (core/templates/command_queue_mt.h:377)
CommandQueueMT::flush_all() (core/templates/command_queue_mt.h:423)
RenderingServerDefault::_thread_loop() (servers/rendering/rendering_server_default.cpp:347)
...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bisected it to #87340 - Finish splitting functionality of the RenderingDevice
backends into RenderingDeviceDriver
(it's big, so probably won't be easy to detect what exactly is causing the issue).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Neither is working.
Since it was originally broken by #87340, which is not changing CommandQueueMT
in any way, it's probably not directly related, and the issue is in RenderingDevice
.
In some cases (resizing window for example), it still lockups with the aforementioned patch (and lockups only involve RenderingDevice
not CommandQueueMT
).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Alright. Thanks for your help! I'll delve.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The more I look into this, the more issues with multi-threading rendering (physics seem OK) I'm seeing. My suggestion (CC @akien-mga) is that we merge this as it is, given it seems it doesn't break single-threading, and I'll make a subsequent PR fixing MT rendering.
fb6a641
to
13ed92c
Compare
4352c87
to
8e7a566
Compare
8e7a566
to
8ca91c5
Compare
8ca91c5
to
2dd1585
Compare
2dd1585
to
3884e7a
Compare
I'm about to push with a change: yielding functions in |
3884e7a
to
ebe731d
Compare
cf43f93
to
db15eab
Compare
- Adapt GL make/release API to the current architecture. - Fix DisplayServer being locked while dispatching input (prevent deadlocks).
* Servers now use WorkerThreadPool for background computation. * This helps keep the number of threads used fixed at all times. * It also ensures everything works on HTML5 with threads. * And makes it easier to support disabling threads for also HTML5. CommandQueueMT now syncs with the servers via the WorkerThreadPool yielding mechanism, which makes its classic main sync semaphore superfluous. Also, some warnings about calls that kill performance when using threaded rendering are removed because there's a mechanism that warns about that in a more general fashion. Co-authored-by: Pedro J. Estébanez <pedrojrulez@gmail.com>
db15eab
to
65686de
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can't vouch for the thread pool code but the rest looks clean to me
4d89aa6
to
65686de
Compare
Tested against the GDQuest TPS demo with multithreaded rendering and physics. Rendering seems to work ok, but physics gave me a crash. It worked fine initially but after breaking a few crates things got laggy and eventually segfaulted.
|
Trying to reproduce, to no avail, so far. Maybe it's one of those obscure and unpredictable platform-specific things. I'm wondering, could you try reproducing on |
It indeed seems to be reproducible on So I guess we can merge this PR now and get wider testing. |
Thanks! Great work 🎉 |
This PR is the version of #77004 where my collaboration on top of @reduz's work has been added.
This is kept from the description of the original PR:
This is new:
This is no longer true:
Supersedes #77004.
2024-04-09: A way of easily testing this being sure all the physics and rendering are threaded is to apply this patch:
all_servers_mt.txt