multiple windows and context sharing
underdoeg opened this issue · comments
do you have a few hints on how to setup a project with multiple windows? One or two for rendering some shared vertex buffers and another for an imgui context?
That would be a great feature! I think this could be particularly useful when using le_swapchain_direct
(which takes full control of a monitor) together with a windowed swapchain on a second monitor.
Some thoughts
I think this would need multiple swapchains, one for each window. There are multiple ways of doing this in terms of render surfaces:
- render into one big off-screen image, then blit parts of this image onto swapchain-provided image/surface
- render into per-swapchain image/surface, one renderpass per swapchain
- hybrids of 1. and 2.
This would need some changes in le_backend
, as the backend currently only assumes a single swapchain, similarly to LE_SWAPCHAIN_IMAGE_HANDLE
, we would need to declare resource names which correspond to additional swapchain images.
Something to consider in more detail is synchronisation:
Rendering is based on the concept of a Frame
. A frame is all the data (gpu, and cpu) which is needed to render a single frame. A lot of this data is dynamic, meaning it is only kept alive for the duration of that single frame. To make sure no data is freed before both the CPU and the GPU are finished using it, each Frame is protected by a vkFence
. The Fence signals that all rendering operations on the vkQueue
concerning this frame have been completed by the GPU. This means that the Frame can be freed / recycled.
So far so good. There are two more synchronisation primitives per-Frame:
semaphoreRenderComplete
semaphorePresentComplete
semaphoreRenderComplete
signals from the renderer to the swapchain that an image has been finished writing into, and can be displayed. semaphorePresentComplete
is used by the swapchain to signal to the renderer that an image has been taken off the screen and is ready to be written into again.
These two semaphores are currently assuming that there is but a single Swapchain.
I think that semaphoreRenderComplete
can be used by multiple swapchains. Each swapchain would need to have their own semaphorePresentComplete
, so that would need to be adapted.
Another point to think about is vsync: I'm curious what happens if two or more swapchains use FIFO (which is commonly tied to vsync), and whether this increases the risk of stuttering: so that the queue can progress, both swapchains must have flipped, and if two monitors run out of sync, so might the swapchains.
It's an interesting challenge: I'll look more into it - and keep me posted if you do some experiments of your own :)
Update: Multi-window is implemented now
I've implemented multi-window, and added an example to show how to set it up.
By the way: it's not just multi-window, but multi-swapchain, which means that instead of a windowed swapchain, you can add a direct-to-screen swapchain. For example, to set up a windowed, plus a direct swapchain:
app->renderer.setup(
le::RendererInfoBuilder()
.addSwapchain()
.asWindowSwapchain()
.setWindow( app->window_0 )
.end()
.end()
.addSwapchain()
.asDirectSwapchain()
.end()
.end()
.build()
);
Direct rendering bypasses the compositor, and renders straight to the second monitor, which is pretty neat... Note that for this to work, the second monitor must first be disabled using nvidia x server settings - the direct swapchain will then switch it on when taking control of the monitor.
awesome
[edit] nice cat...