1

In my app I render my Direct3D content to the window, as recommended, using the swap chain in flip sequential mode (IDXGISwapChain1, DXGI_SWAP_EFFECT_SEQUENTIAL), in a window without redirection bitmap (WS_EX_NOREDIRECTIONBITMAP)

However for the purpose of smooth window resizing (without lags and flicker), I want to intercept live resize enter/exit events and temporarily switch the rendering to ID2D1HwndRenderTarget to the window's redirection surface, which seems to be offer the smoothest possible resize.

The question is - how to render the Direct3D content to ID2D1HwndRenderTarget?

The problem is that obviously the Direct3D rendering and ID2D1HwndRenderTarget belong to different devices and I don't seem to find a way to interop them together.

What ideas come to mind:

A. Somehow assign ID2D1HwndRenderTarget to be the output frame buffer for 3D rendering. This would be the best case scenario, because it would minimize buffer copying.

  1. Somehow obtain a ID3D11Texture2D or at least an IDXGISurface from the ID2D1HwndRenderTarget
  2. Create render target ID3D11Device::CreateRenderTargetView from the DXGI surface / Direct3D texture
  3. Set render target ID3D11DeviceContext::OMSetRenderTargets
  4. Render directly to the ID2D1HwndRenderTarget

The problem is in step 1. ID2D1HwndRenderTarget and its ancestor ID2D1RenderTarget seem pretty scarce and don't seem to provide this capability. Is there a way to obtain a DXGI or D3D surface from the ID2D1HwndRenderTarget?

B. Create an off-screen Direct3D frame buffer texture, render the 3D content there and then copy it to the window render target.

  1. Create off-screen texture ID3D11Texture2D (ID3D11Device::CreateTexture2D)

  2. Create a ID2D1Device using D2D1CreateDevice (from the same IDXGIDevice as my ID3D11Device)

  3. Create a ID2D1DeviceContext using ID2D1Device::CreateDeviceContext

  4. Create a ID2D1Bitmap using ID2D1DeviceContext::CreateBitmapFromDxgiSurface

  5. Draw the bitmap using ID2D1HwndRenderTarget::DrawBitmap

Unfortunately, I get the error message "An operation failed because a device-dependent resource is associated with the wrong ID2D1Device (resource domain)". Obviously, the resource comes from a different ID2D1Device But how to draw a texture bitmap from one Direct2D device onto another?

C. Out of desperation, I tried to map the content of my frame buffer to CPU memory using IDXGISurface::Map, however this is tricky because it requires D3D11_USAGE_STAGING and D3D11_CPU_ACCESS_READ flags when creating the texture, which then seems make it impossible to use this texture as an output frame buffer (or am I missing something?). And generally this technique will be most likely very slow, because it involves syncing between CPU and GPU, and copying the whole texture at least two times.

Has anyone ever succeeded with the task of rendering 3D content to a ID2D1HwndRenderTarget? Please share your experience. Thanks!

user1548418
  • 457
  • 4
  • 14
  • You can get a (DXGI) device from the render target: QI the render target for ID2D1DeviceContext, and then call ID2D1DeviceContext::GetDevice and ID2D1Device2::GetDxgiDevice – Simon Mourier Nov 26 '21 at 13:09
  • Thank you! I've tried it and the returned `IDXGIDevice` is null, with `HRESULT = A call to this method is invalid`. I have also tried `ID2D1DeviceContext::GetTarget` (QI'd the device context from the `ID2D1HwndRenderTarget`) and then `ID2D1Bitmap1::GetSurface`, but also got a null `IDXGISurface` and the same error message. I've got the impression that `ID2D1HwndRenderTarget` works without any DXGI under the hood. It may be some kind of software emulation (WARP?). Any other ideas? – user1548418 Nov 26 '21 at 15:57
  • My understanding is ID2D1HwndRenderTarget is backed by a simple (GPU) ID2D1Bitmap and that's it. Why do you need this type of render target if you already have a swapchain on a hwnd? – Simon Mourier Nov 26 '21 at 16:25
  • 1
    You may be right. The reason to use `ID2D1HwndRenderTarget` - the swap chain sucks during window resizing. The content noticeably lags behind the window border movement, there is a glimpse of background etc. It's a notorious problem. By contrast, `ID2D1HwndRenderTarget` is synced with window resizing and offers the best appearance during resize. See: https://raphlinus.github.io/personal/2018/04/08/smooth-resize.html. So my idea is to temporarily switch to `ID2D1HwndRenderTarget` during resize and back to swap chain when resizing is done. – user1548418 Nov 26 '21 at 17:16
  • If you want real cooperation with Windows (owned by the Desktop Window Manager), you should use Direct Composition (either with the old version or with the newer WinRT's Windows.UI.Composition which is accessible to Win32 desktop apps), this avoids the nasty resizing effect. – Simon Mourier Nov 26 '21 at 17:36
  • I do already use DWM and DirectComposition in combination with Direct3D and I agree that it performs better than pure swap chain in terms of window resizing. However, the lag is still noticeable and I'm not (yet) willing to compromise on it, because I clearly observe that `ID2D1HwndRenderTarget` gives a much better, actually the perfect window resizing experience. I want to give it a shot. – user1548418 Nov 26 '21 at 21:38

0 Answers0