Drawing to Multiple Windows Using Vulkan - c++

I am trying to create an application that could dynamically create additional windows. Each window will be drawn to using Vulkan and I know that this means that each window will have to contain it's own SwapChain resources (image views, framebuffers, etc.) and graphics pipeline (as it is references the swap chain's extents). I am wondering if each window will also have to remember its own present queue family or if I can assume that the same queue family can be used for each window. Specifically to find a present queue family you need to find out if a particular queue family supports surface presentation using:
VkResult vkGetPhysicalDeviceSurfaceSupportKHR(
VkPhysicalDevice physicalDevice,
uint32_t queueFamilyIndex,
VkSurfaceKHR surface,
VkBool32* pSupported);
This requires a VkSurfaceKHR and thus the HWND and HINSTANCE of a particular window, but I'm not sure if the present queue family is likely to change between different windows created by the same operating system or if I can safely use the same one for each window.
Similarly while reviewing swap chain recreation within the vulkan-tutorial I read that VKSurfaceFormatKHR::format rarely changes during window resize and that is the only reason the render pass needs to be reconstructed during the window resizing operation. How safe would it be to skip the render pass recreation in this step during window resizing and how well could the same render pass be used for different windows?
If each window uses a similar graphics pipeline, more specifically uses the same synchronization objects, would it be typical to have each window append to the same command buffer and use a single vkQueueSubmit? I only ask because you need to create a command buffer for each frame in flight, and thus the number of command buffers required would be numWindows * numFramesInFlight which feels excessive, but I'm not sure if it would be any different from a single large command buffer (appended to by each window) per frame in flight.
As an aside, the resources for drawing to multiple windows using Vulkan seems to be fairly scarce, so if anyone knows of any good ones I would greatly appreciate it.

On Windows you could largely assume everything can render to everything. But use you should check that is so anyway. vkGetPhysicalDeviceWin32PresentationSupportKHR does not need surface, and gives a strong hint that the device\queue is a presentation able, and not e.g. compute accelerator or something.
Similarly while reviewing swap chain recreation within the vulkan-tutorial I read that VKSurfaceFormatKHR::format rarely changes during window resize and that is the only reason the render pass needs to be reconstructed
It is not supposed to ever change for the lifetime of the physical device and surface. If it could change, that would be a TOCTOU problem.
If each window uses a similar graphics pipeline, more specifically uses the same synchronization objects, would it be typical to have each window append to the same command buffer and use a single vkQueueSubmit?
Why not. I mean there is nothing "typical" about this. But if it can be done, then it should probably be done. Otherwise if the windows are unrelated then they should probably have each their own private logical device (or even instance).
As an aside, the resources for drawing to multiple windows using Vulkan seems to be fairly scarce
Lot of resources for Vulkan are "scarce". That is because Vulkan is like a lego. Once you know what the individual pieces do, then you can build whatever without needing outside help. Drawing to multiple windows is no different than drawing to a single window, exept you do it multiple times.

Related

ways for Direct2D and Direct3D Interoperability

I want make a Direct2D GUI that will run on a DLL and will render with the Direct3D of the application that I inject into it.
I know that I can simply use ID2D1Factory::CreateDxgiSurfaceRenderTarget to make a DXGI surface and use it as d2d render target, but this require enabling the flag D3D11_CREATE_DEVICE_BGRA_SUPPORT on Direct3D's device.
The problem is that the application creates its device without enabling this flag and, for this reason, ID2D1Factory::CreateDxgiSurfaceRenderTarget fails.
I am trying to find a other way to draw on the application window (externally or inside window's render target) that also works if that window is in full-screen.
I tried these alternatives so far:
Create a d2d render target with ID2D1Factory::CreateDCRenderTarget. This worked, but the part I rendered was blinking/flashing (show and hide very fast in loop). I also called ID2D1DCRenderTarget::BindDC before ID2D1RenderTarget::BeginDraw, but it just blinks but a bit less, so I still had the same issue.
Create a new window that will always be on the top of every other window and render there with d2d but, if the application goes into full-screen, then this window does not show on screen.
Create a second D3D device with enabled the D3D11_CREATE_DEVICE_BGRA_SUPPORT flag and share an ID3D11Texture2D resource between the device of the window and my own, but I wasn't able to make it work... There are not a lot of examples on how to do it. The idea was to create a 2nd device, draw with d2d on that device and then sync the 2 D3D devices – I followed this example (with direct11).
Create a D2D device and share the data of d2d device with d3d device; but, when I call ID2D1Factory1::CreateDevice to create the device it fails because the D3D device is created without enabling the D3D11_CREATE_DEVICE_BGRA_SUPPORT flag. I started with this example.
I've heard of hardware overlay but it works only on some graphics cards and I think I will have problems with this https://learn.microsoft.com/el-gr/windows/win32/medfound/hardware-overlay-support.
I am currently at a dead end; I don't know what to do. Does anyone have any idea that may help me?
Maybe is there any way to draw on screen and work even if a window is in full-screen?
The #3 is the correct one. Here’s a few tips.
Don’t use keyed mutexes. Don’t use NT handles. The only flag you need is D3D11_RESOURCE_MISC_SHARED.
To properly synchronize access to the shared texture across devices, use queries. Specifically, you need a query of type D3D11_QUERY_EVENT. The workflow should look like following.
Create a shared texture on one device, open in another one. Doesn’t matter where it’s created and where imported. Don’t forget the D3D11_BIND_RENDER_TARGET flag. Also create a query.
Create D2D device with CreateDxgiSurfaceRenderTarget of the shared texture, render your overlay into the shared texture with D2D and/or DirectWrite.
On the immediate D3D device context with the BGRA flag which you use for D2D rendering, call ID3D11DeviceContext.End once, passing the query. Then wait for the ID3D11DeviceContext.GetData to return S_OK. If you care about electricity/thermals use Sleep(1), or if you prioritize latency, busy wait with _mm_pause() instructions.
Once ID3D11DeviceContext.GetData returned S_OK for that query, the GPU has finished rendering your 2D scene. You can now use that texture on another device to compose into 3D scene.
The way to compose your 2D content into the render target depends on how do you want to draw your 2D content.
If that’s a small opaque quad, you can probably CopySubresourceRegion into the render target texture.
Or, if your 2D content has transparent background, you need a vertex+pixel shaders to render a quad (4 vertices) textured with your shared texture. BTW you don’t necessarily need a vertex/index buffer for that, there’s a well-known trick to do without one. Don’t forget about blend state (you probably want alpha blending), depth/stencil state (you probably want to disable depth test when rendering that quad), also the D3D11_BIND_SHADER_RESOURCE flag for the shared texture.
P.S. There’s another way. Make sure your code runs in that process before the process created their Direct3D device. Then use something like minhook to intercept the call to D3D11.dll::D3D11CreateDeviceAndSwapChain, in the intercepted function set that BGRA bit you need then call the original function. Slightly less reliable because there’re multiple ways to create a D3D device, but easier to implement, will work faster, and use less memory.

Recreating swapchain vs using dynamic state on resize

I have a vulkan application that uses GLFW as its window manager.
Upon the window resize event, vulkan needs to update its drawable area. I have seen 2 ways that this is possible. One is to recreate the swapchain alongside all of the other objects that are tied to it and the other is to use dynamic state for the viewport so that recreation is not needed.
What is the difference between these two and when should I prefer one over the other?
If the window is resized to a smaller size, the display engine may not force you to change your swapchain image sizes. It may inform you of this through the VK_SUBOPTIMAL_KHR error code (though it may not give you even that if performance of presenting is not affected). However, if the window is resized to be larger, the display engine may throw VK_ERROR_OUT_OF_DATE_KHR. That is not something you can ignore. Nor is it something a display engine can promise to never give you.
This means your code must be able to do swapchain rebuilding. Since you have to make allowances for this regardless, the only question is whether you do it whenever the window is resized or just when the display engine forces you to.
I would say that, if the display engine doesn't make you rebuild the swapchain, then it's probably faster not to. Using dynamic state isn't particularly slower than pipeline state, and its not like you're going to be changing it mid-frame. Indeed, you shouldn't rebuild all of your pipelines just because the swapchain was resized, so you should be using dynamic state for the viewport anyway.
In short: you ought to do both.

What is necessary to toggle fullscreen in DirectX 11?

I've just started learning DX so I know almost nothing about it although I do know OpenGL (to certain extent). I'm follow a tutorial (http://www.rastertek.com/tutdx11.html) and I have a working window rendering just a white background (clear).
Now - how do I actually switch from windowed mode to fullscreen and vice versa? I know there are many tutorials, some even provide a code for doing that but since I'm a newbie that's not really helpful. Why? Because every code sample is different and trying to find a pattern in all of them is apparently too difficult for me.
So I don't ask for code - instead I would like you to tell me what things I need to release/recreate/change to toggle correctly (and all of them). I know I need to change the display settings, I know I have to change something about the swap chain and release/recreate some buffers - but not really sure which exactly.
You can use SetFullScreenState on your swap chain:
swapChain->SetFullScreenState(true, NULL);
MSDN
The main thing you have to do is release all reference to the IDXGISwapChain, call ResizeBuffers, then re-create everything.
Since Win32 throws the WM_SIZE message upon window initialization, it's entirely possible to:
Clear the previous window-size-specific context
If the swap chain already exists, resize it, otherwise create one
Obtain the backbuffer for this window which will be the final 3D rendertarget.
Create a view interface on the rendertarget to use on bind.
Allocate a 2-D surface as the depth/stencil buffer and create a DepthStencil view on this surface to use on bind.
Create a viewport descriptor of the full window size.
Set the current viewport using the descriptor.
inside a static function (unless WinMain has an object from which to call), and call that function when the WM_SIZE message is triggered.
You can check out how the DirectXTK does it here:
https://directxtk.codeplex.com/

Handle Alt Tab in fullscreen OpenGL application properly

When trying to implement a simple OpenGL application, I was surprised that while it is easy to find plenty of examples and documentation on advanced rendering stuff, the Win32 framework is poorly documented and even most samples and tutorials do not implement this properly even for basic cases, not mentioning advanced stuff like multiple monitors. Despite of several hours of searching I was unable to find a way which would handle Alt-Tab reliably.
How should OpenGL fullscreen application respond to Alt-Tab? Which messages should the app react to (WM_ACTIVATE, WM_ACTIVATEAPP)? What should the reaction be? (Change the display resolution, destroy / create the rendering context, or destroy / create some OpenGL resources?)
If the application uses some animation loop, suspend the loop, then just minimize the window. If it changed display resolution and gamma revert to the settings before changing them.
There's no need to destroy OpenGL context or resources; OpenGL uses an abstract resource model: If another program requires RAM of the GPU or other resources, your programs resources will be swapped out transparently.
EDIT:
Changing the window visibility status may require to reset the OpenGL viewport, so it's a good idea to either call glViewport apropriately in the display/rendering function, or at least set it in the resize handler, followed by a complete redraw.

Managing Fonts, Brushes and Pens in MFC

I am about to start a text-rendering window in MFC. Given that the text-rendering window will allow fonts of differing style (and each window can have a different font), I've been thinking about the management of fonts.
Would it make sense to create some kind of a font manager? I was thinking that each time a font is required, the renderer would pass the desired LOGFONT to the manager. If a CFont existed, it would be returned and if not, created. This font manager would be global in the system.
Is this overkill? Does Windows do this kind of thing under-the-hood meaning it is totally un-necessary from an application perspective?
One could also say the same for brushes and pens of a particular colour. Is it faster to store them in a manager of some sort once one is created? E.g, if I create a solid mauve brush, should another window that wants mauve request the existing brush?
Also, I'm guessing that if I load an image on disk to blit, that if two separate windows load the same image from disk, I'll have two images - so these are good candidates to cache (by filename, perhaps?)
Different windows versions have done differing amounts of caching of these things.
My advice hinges on two things:
Don't optimize prematurely. If you can see a possible need to optimize in the future, go ahead and ensure that you architect it such that Fonts are retrieved from a font manager. But, until there is a provable performance deficit, don't bother implementing the cache.
Measure. Make a test case program that creates and destroys hundreds of differently styles fonts and measure how it scales in performance.
I once spent a long time writing a multi threaded renderer. Only to find that, because the GDI drivers serialize access to the hardware anyway, I got zero benefit.
This is an okay strategy for fonts, the Windows font mapper isn't that cheap and the number of fonts that a typical program uses is finite. But not for brushes and pens, they are dirt-cheap so just create and destroy them on the fly.
The ultimate endorsement for this strategy comes from Microsoft's own code, Winforms does this. Beware that caching creates a new problem, you have to invalidate the cache when the user changes system settings. System colors, DPI, that sort of thing. You have to listen for WM_SETTINGCHANGE in a toplevel window.
Windows has/had (it's been a while since I programmed for Windows) had various GetStockXXX functions, such as GetStockFont(). I had a quick Google but no obvious MSDN docs came up.
Edit: see GetStockObject(): http://msdn.microsoft.com/en-us/library/dd144925%28VS.85%29.aspx