Closed olegded closed 4 years ago
Thanks all the details. I tried to recreate under Linux and unfortunatly minimizing doesn't recreate it, so will likely need to iterate on a solution between us. Looking at the docs for VkCreateSwapchain :
https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkSwapchainCreateInfoKHR.html
In one section is says:
On some platforms, it is normal that maxImageExtent may become (0, 0), for example when the window is minimized. In such a case, it is not possible to create a swapchain due to the Valid Usage requirements.
It will be easy for us to start adding in checks for non zero extents before the problem calls, but we'll also need to handle what happens on codes that depends upon those data structures so they handle the case in a coherent way. It may be most productive to catch this type of supported extents issue high up in the viewer/window class to avoid any rendering to minimized windows.
I will reflect on this issue and figure out what would be the most robust way to handle the minimization case. I will need to try and catch the case under Linux in a way that is also mirrors what is happening under Windows so any changes I make have a good chance of addressing the problem under Windows as well.
As a quick way of investigating what is going on I enabled the print out of Swapchain::create(..) settings via the change:
$ git diff
diff --git a/src/vsg/vk/Swapchain.cpp b/src/vsg/vk/Swapchain.cpp
index 0e74c1a..aa2ba5f 100644
--- a/src/vsg/vk/Swapchain.cpp
+++ b/src/vsg/vk/Swapchain.cpp
@@ -185,7 +185,7 @@ Swapchain::Result Swapchain::create(PhysicalDevice* physicalDevice, Device* devi
preferences.presentMode = presentMode;
preferences.surfaceFormat = surfaceFormat;
-#if 0
+#if 1
std::cout << "Swapchain::create(...., width = " << width << ", height = " << height << ")" << std::endl;
std::cout << " details.capabilities.minImageCount=" << details.capabilities.minImageCount << std::endl;
std::cout << " details.capabilities.maxImageCount=" << details.capabilities.maxImageCount << std::endl;
Note it's just changing the #if 0 to #if 1.
If I then rebuild VSG and vsgExamples, then run vsgdraw, minimize the window, the open it again the only console output I get is:
$ vsgdraw Swapchain::create(...., width = 800, height = 600) details.capabilities.minImageCount=2 details.capabilities.maxImageCount=8 imageCount = 3
So under Linux/Xcb the window is never being resized on minimization or maximization. This means that nothing needs to be recreated. If I resize the window then I see lots of calls to the Swapchain::create(..) function with the altering window sizes.
I presume under Windows the window itself is being resized along with all the Vulkan structures that the VSG maintains. It could be that our src/vsg/platform/win32/Win32_Window.cpp implementation isn't handling window minimization optimally, or perhaps it's just the way Windows works and we have to add some mechanism to handle this case correctly.
I don't have any Windows expertise so can't provide guidance on this. @tomhog any suggestions?
I have had a bash at forcing a resize to 0,0 under Linux but the window manager keeps fixing it for me so I end up with a non zero window width/height. I guess I might be able to disable the redirect to the the window manage but this will get rid of the window decoration so then I wouldn't be able to minimize... All this is a roundabout way of saying I'm struggling to forceably recreate the {0,0} swapchain etc. size under Linux.
This means we'll need to work between us to come up with a solution, while I can make some code changes to support this I can't directly test it. It probably makes sense for me to create a branch for the testing of changes/experiments.
Right now under Linux when I minimize the application main loop is oblivious of the window minimization and keeps running doing the record to command buffer, submit command buffer to queue, submitting the presentation just as it would any other frame. It's just the window manager is not showing the window so can't see the results. This is clearly inefficient.
Now if we have multiple windows open or even a simulation running we'd still want the main loop to run and to handle all the scene graph updates and rendering to renaming open windows. So I'm thinking that the right way to handle this would be to switch off the work for the minimized windows then reenable it when the window is opened. This would address the inefficiency of rendering things we don't see.
The next step, specific to Windows, would be how to handle the attempt to rebuild the Vulkan objects such as a the swap chain to a {0,0} size as is happening right now. My guess is if we had an open window size of {1920 1080} that gets minimized it asks for a {0,0} window, then when it's opened again the window size should return to {1920,1080}. The way I'm guessing is happening on Windows right now we get a Window::resize() call, looking at the code I'm guessing it's form within the bool Viewer::acquireNextFrame() code for handling an failure to acquire the next image.
So I'm now thinking that we might be able to detect a close window and not bother calling the resize, disable the rendering to the window till it's been opened again.
My hope is that we can avoid the rebuilding of the Vulkan objects - the swapchain and framebuffer and images on close and re-opening of the window, just rebuild these when required such as a window changing size.
I will ponder on this a little more. Most likely I'll create a branch for this work and initially just add extra debug messages in so we can see what is happening under Windows.
The
I will be happy to help with debugging and testing, can only do that in my spare time :-)
Thanks. I have created window_minimized branch for this work. I haven't checked in anything yet.
My current plan is to implement handling of window mapping/unmapping so that rendering and presentation isn't attempted for windows that aren't visible. I will be able to get this working under Linux but will need others to implement the window visibility code on the Windows side and then to test it out.
I have checked in following:
https://github.com/vsg-dev/VulkanSceneGraph/commit/599815974ef36ee47501b827bf69368efbd35b09
To the new window_minimized branch: https://github.com/vsg-dev/VulkanSceneGraph/tree/window_minimized
The key functionality is a new virtual bool Window::visible() method that needs to be implemented for each platform so that the window returns true when the window is valid and visible on screen i.e. not minimized. I've left the default implementation of visible() to return true; just to make sure the code will work as before on platforms that don't yet implement this method.
The new Window::visible() is now used RecordAndSubmitTask, CommandGraph and Viewer to disable rendering to windows that are no longer visible.
This approach is experimental, there are potential weaknesses such as the visible() value changing during the frame, there may well be other instances I haven't foreseen yet.
I have been using vsgviewer and vsgdraw to test the new functionality. The vsgExamples master branch will work fine with this new work, all you'll need to do is recompile vsgExamples.
Hi Robert,
Sorry for being late on this issue. Today, I had a chance to start C++ compilers under Windows and macOS again :-) Latest code works without any issues on Windows, same for https://github.com/vsg-dev/VulkanSceneGraph/issues/137
I will close both issues.
1) Checkout latest master and compile osgExamples on Windows 2) Start
vsgdraw
with-d
flag 3) Minimize the application windowAs a result you will see following messages in the console window: