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.
Related
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.
I have a D3D11 application for Windows Store that currently does not use antialiasing, and I would like to enable it.
According to MSDN, MSAA is disabled in Windows Store apps:
DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL
Use this flag to specify the flip presentation model and to specify that DXGI persist the contents of the back buffer after you call IDXGISwapChain1::Present1. This flag cannot be used with multisampling.
Note Windows Store apps must use DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL.
Because this limitation applies only to the back buffer, it sounds like the best workaround is to create a new off-screen render target, enable MSAA on that, render everything to it, and immediately before Present, blit the off-screen target to the back buffer (probably with ResolveSubresource).
I've started implementing this, but I'm not sure how to modify my swap chain and render target view. Can anybody advise me as to the correct order of operations here?
What you suggest is correct. Create an MSAA render target using CreateTexture2D followed by CreateRenderTargetView. The DXGI_SAMPLE_DESC field of D3D11_TEXTURE2D_DESC contains the MSAA settings. Then render your scene to this render target, and ResolveSubresource into the back buffer. The swap chain doesn't need to change.
Is it possible to hide OpenGL window and the rendering are still running? I use glutHideWindow which will never trigger display function.
If that is not possible, is it possible in the program to change the focus of the current window? I want to run opengl program but I don't need that window. In fact, I want to use the framebuffer that opengl updates at each frame in another program. But it's always annoying to toggle between the two programs. (They both have window)
Is it possible to hide OpenGL window and the rendering are still running?
Yes and No to both parts of the question.
If you hide a window, all the pixels of the window's viewport will fail the pixel ownership test when rendering. So you can't use a hidden window as a drawable for OpenGL to operate on.
What you need is an off-screen drawable to draw to.
The modern variant are Framebuffer Objects (FBOs), which you can create on a regular OpenGL context, that might even work on a hidden window. FBOs take some drawable attachments (render buffers, textures) and allow OpenGL to draw to these instead to the window.
An older method are PBuffers, also widely supported, but not as easy to use as FBOs.
Note that if you want to perform off-screen rendering on Linux/X11 the X server must be active, i.e. owning the VT so that the GPU actually processes the commands. So you can't just start an X server "in the background" but have another X server use the display device.
After creating the window, you can use glutHideWindow() to go offscreen. Then you still render as nomal and use glReadPixels to read back and get buffer to use it later.
I want to render a scene and display it on the monitor, while rendering another one to a texture.
Do I need to create two swapchains? How do I create the second swapchain in this case? I tried to call CreateSwapChainForCoreWindow but got memory access exceptions.
Swapchains are really just for displaying stuff.
To render to something, you have to add a render target view to the device via the OMSetRenderTargets() call. You can create render target views via CreateRenderTargetView(), which takes a resource as input. Textures are resources too... you just have to create them with the D3D11_BIND_RENDER_TARGET flag.
That's just a few cues that should be able to point you into the right direction.
Btw, Swapchains have buffers, which are resources that are used to create a render target view as well. That's how you render to a swapchain; it really doesn't have anything to do with "swapchains" at all.
I was wondering; is it possible to acquire write access to the graphics card's primary buffer though the windows api, yet still allow read access to what should be there? To clarify, here is what I want:
Create a directx device on a window
and hide it. Use the stencil buffer
to apply an alpha channel to pixels
not written to by my code.
Acquire the entirety
of current display adapter's buffer.
I.e. have a pointer to a buffer, in
the current bit depth and
resolution, that contains the
current screen without whatever I
drew to the screen. I was thinking
of, instead of hiding my window,
simply use a LAYERED window and
somehow acquire the buffer before my
window's pixels get blitted to it.
Copy the buffer acquired in step 2 into a new memory location
Blit my directx's device's primary buffer to the buffer built in step 3
Blit the buffer in step 4 to the screen
GOTO 2
So the end result is drawing hardware accelerated 3D directly to the window's desktop while still rendering other applications.
There are better ways to create a window without borders. You might try experimenting with the dwStyle parameter of CreateWindow, for example. It looks as if you pass in WS_OVERLAPPED | WS_POPUP and it results in a borderless window, which is what you appear to want. (see this forum post).
I also think the term "borderless window" is not correct, because I'm hardly getting any results in Google for searches including those words.
Is there any reason why you wouldn't just do this normally with GDI and use windowed mode for DirectX? Why bother with full-screen mode when you need to render with a window?