Jump to content
  • Advertisement
Sign in to follow this  
daVinci

How to use D2D with D3D11?

This topic is 2504 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I want to use Direct2D1 to write to a render target created with a Direct3D 11 swap chain. Is this possible?

As I understand the above, it enables you to share a texture between two Direct3D 11 and 10.1 devices. However I can't see how to share a swap chain render target because it does not have the D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX (or equivalent) flag.

Am I missing something?

JB.

[Edited by - JB2009 on September 22, 2009 3:41:58 PM]

Share this post


Link to post
Share on other sites
Advertisement
I don't think that's possible, you have to draw to a texture and then copy that to the screen.

I have tried the following couple of ways, each with its problems. Perhaps DieterVW who seems to know what he's talking about can comment if any of these is the recommended way, and if I have missed something obvious. =)

1. Use a shared texture of the same size as the screen as the render-target. Lock it with the mutex, draw all D3D11 graphics into it, then lock it for D2D and draw that on top, then copy it to the screen. Looks the same as using D2D with a D3D10.1 render-target, but suffers from lag from the syncing.

2. Draw D3D11 geometry directly to the screen, and use a shared texture as the D2D render-target. When everything is drawn in both D2D and D3D11, alpha-blend the D2D texture to the screen. As far as I can see this can't work with antialiasing in D2D, since only premultiplied and ignored alpha are supported for DXGI render-targets (except for DXGI_FORMAT_A8_UNORM render targets, as stated here. A texture of that format can't be opened with OpenSharedHandle from D3D10.1). This causes bad edges to the text when drawn with anti-aliasing (pre-blended to background color, not to screen contents), so text must be drawn with DWRITE_MEASURING_MODE_GDI_CLASSIC.
(There seems to be a bug with this, with performance deteriorating when drawing a lot of text. I'm not sure if the bug is in my program, but changing to DWRITE_MEASURING_MODE_NATURAL gets rid of the problem, with no other change in the code).

Share this post


Link to post
Share on other sites
Creating a a backbuffer with the mutex isn't possible -- and as mentioned above, this would have performance issues since you have to sync usage between devices.

Though this won't solve every scenario, using a shared rendertarget created by the developer will work the best. This target can actually be cleared to transparent and then all D2D/DWrite drawing can be done. Pre-multiplied alpha is actually exactly what you want (more on this below). You can then composite the shared render target over the main 3D scene, or use it as a texture in future frames. The composite in 3D will also be done using pre-multiplied blending.

You optionally can render to an MSAA render target in D2D and then resolve and copy the contents to the shared resource to bring it back to D3D.

In this scenario you can avoid performance loss by using several shared resources. An update from D2D will likely only take a couple frames at most (meaning that the frame will be drawn and available to the 3D device within a couple frames), and then will be available for the composite in 3D. This should work for a lot of UI, though is imperfect if your plan is to do something like putting text tags above moving units in a game. In such a case it's probably best to render that text to a cached texture which would be used directly in drawing the 3D scene.

For a detailed analysis of why pre-multiplied alpha is always the way to go, read this: http://home.comcast.net/~tom_forsyth/blog.wiki.html#[[Premultiplied%20alpha]]

Share this post


Link to post
Share on other sites
That works perfectly, I didn't know how the premultiplied alpha works. Thanks again for all your explanations!
With D2D antialiasing it's not noticeable that the text isn't multisampled, even when composite with a multisampled render target behind it.

Share this post


Link to post
Share on other sites
DieterVW, Erik - many thanks for your help.

What is the best way to combine ("composite") the shared render target with the D3D11 backbuffer? (I'm straight from D3D9).

JB.

Share this post


Link to post
Share on other sites
Draw a fullscreen textured quad with alpha-blending:
D3D11_BLEND_DESC::RenderTarget[0].SrcBlend = D3D11_BLEND_ONE;
D3D11_BLEND_DESC::RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;

Share this post


Link to post
Share on other sites
Thanks again DieterVW and Erik - especially for the instructions on the basic strategies involved.

I've got the D2D1+D311 strategy working well with white text onto a dark 3D scene, but not with black text onto a light 3D scene.

Am I aiming for a shared render target texture where all the pixels are transparent (i.e. Alpha=0) except for where the 2D drawing/text is? If so, is this achieved by creating the D2D brushes with Alpha=1, and clearing the D2D1 render target to transparent using the D2D1RenderTarget.Clear method with Color=Anything and Alpha=0?

JB.


[Edited by - JB2009 on September 25, 2009 1:47:26 PM]

Share this post


Link to post
Share on other sites
Yes, that is the method I use at least. Does the text not show up if it's black, and if so what happens with gray text?
Perhaps there's something wrong with the blend-state.

Share this post


Link to post
Share on other sites
Erik,

> Yes, that is the method I use at least.
> Does the text not show up if it's black,
> and if so what happens with gray text?
> Perhaps there's something wrong with the blend-state.

The problem was that the pixel shader used for the compositing was ignoring the texture alpha component. With this fixed the results are very impressive - particularly for larger fonts. The fonts blend well with any background colour. With very small fonts the results are less clear than using the D3D9 D3DXFont. Maybe there are options (e.g. clear type etc) to fix this - I haven't looked yet.

Thanks for your help,

JB.

[Edited by - JB2009 on September 30, 2009 10:21:48 AM]

Share this post


Link to post
Share on other sites
Remaining D2D1/D311 interop issues:

1) My biggest concern is the time that D2D1 is adding to the frame time. I'm seeing 1.5 to 2.7 ms additional time (depending on window size) over the equivalent D3D9 approaches. I haven't yet established whether this is "per window" for multiple window applications. The additional time is incurred as soon as the ID2D1 BeginDraw/EndDraw are added (i.e. without actually drawing anything). The amount of drawing only has a very small effect on the amount of time.

For my application this is time I can not afford to lose. Caching the 2D content is not an option for me because at least some of the text changes every frame (and even a single item of text incurs the full time overhead).

An important question for me is: Will this problem continue to exist when (if?) D2D1 becomes compatible with D3D11? (And also, was this a problem with D2D1 and D3D10.1?).

2) If I add both GDI content (i.e. using IDXGISurface1.GetDC) AND D2D1 (using the DieterVW method), I either get an exception when drawing the D2D1 Quad to the D3D11 back buffer, or the GDI content appears but not the D2D1. Can they work together? Is it to do with the key values used with the mutexes? I'm updating a D3D9 library to D3D11, and cannot prevent GDI and text (via D2D1) being used together.

JB.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!