Integrating with WPF through IDirect3Dsurface9

1,383 views
Skip to first unread message

Thomas Sevaldrud

unread,
Jan 26, 2014, 5:26:07 AM1/26/14
to anglep...@googlegroups.com
Hi,

I am working on a 3D visualization project where the GUI needs to be in WPF. This requirement is unfortunately beyond my control, but since my visualization OpenGL code already runs nicely in ANGLE I was hoping that I could make it work anyway...

Is there a way to retrieve the current Direct3D Device or even better the currently used backbuffer IDirect3dSurface9 from ANGLE? In this case I could hook this up to a WPF D3DImage. I've done this in earlier projects where I had to integrate native D3D with WPF.

Now that ANGLE supports both DX11 and DX9, is there a way to ensure that I'm always using the DX9 backend?

Any help or insight on these issues would be greatly appreciated

- Thomas


Geoff Lang

unread,
Jan 27, 2014, 11:04:58 AM1/27/14
to tseva...@gmail.com, anglep...@googlegroups.com
You may be able to get the HWND from the WPF window and use that to initialize ANGLE instead.  We don't expose the D3D objects across the API boundary. 


-- 
You received this message because you are subscribed to the Google Groups "angleproject" group.
To unsubscribe from this group and stop receiving emails from it, send an email to angleproject...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

Shannon Woods

unread,
Jan 27, 2014, 11:14:01 AM1/27/14
to anglep...@googlegroups.com, tseva...@gmail.com
Well, we do provide access to D3D texture share handles via EGL_ANGLE_surface_d3d_texture_2d_share_handle.

To ensure that you're always using the D3D9 back-end, follow the steps on the DevSetup page under "Choosing a D3D Backend", but instead of ensuring that ANGLE_ENABLE_D3D11 is 1, you'll want to ensure that it is 0. There is also EGL_ANGLE_direct3d_display, which Chrome currently uses to choose a backend at runtime-- but it's important to note that this extension is a bit of a temporary hack, and will be replaced with one based on EGL_EXT_platform_base.

Thomas Sevaldrud

unread,
Jan 27, 2014, 12:28:25 PM1/27/14
to shanno...@chromium.org, anglep...@googlegroups.com
Hi, and thanks for helping :-)

I was looking at the EGL_ANGLE_surface_d3d_texture_2d_share_handle extension, and this enables sharing of textures right? So I could set up ANGLE to render to a texture, and then I could use this texture to render in the WPF window? This is definitely one way of doing it, but ideally, I'd want to use a D3DImage in a WPF User control which has a SetBackBuffer(D3DResourceType.IDirect3DSurface9, IntPtr) where the IntPtr is a pointer to the Direct3D surface which can be shared between the managed and unmanaged code.

Currently I'm doing all my GL rendering in Qt which uses ANGLE as a backend for OpenGL. This means that I basically have no control over the ANGLE initialization (at least without patching the Qt code), so something like an "EGL_ANGLE_surface_d3d_handle" extension would probably be just perfect for me :-) It could work just like the above extension only it would return a pointer to the current D3DSurface instead of the texture share handle. 

I also looked at the EGL_ANGLE_direct3d_display, but apparently that only allows me to specify that I want DX11 with DX9 as fallback. I can't specify that I prefer DX9, or did I misunderstand here?

Thanks again for helping, and I apologise in advance for abusing the library in this way, but I can't see any other option for efficient 3D rendering in WPF if I want to use OpenGL  :-) 

- Thomas

Shannon Woods

unread,
Jan 27, 2014, 12:37:57 PM1/27/14
to anglep...@googlegroups.com, shanno...@chromium.org
Yes, EGL_ANGLE_direct3d_display just has options for DX11-only, and DX11 with a DX9 fallback, because the default behavior is to provide DX9 only. If you want DX11 never to be used, ANGLE_ENABLE_D3D11 should not be enabled.

Thomas Sevaldrud

unread,
Jan 27, 2014, 12:59:55 PM1/27/14
to anglep...@googlegroups.com, shanno...@chromium.org
Right, this can also be controlled when compiling Qt, so that takes care of the DX9/11 issue at least :-)

- Thomas

Thomas Sevaldrud

unread,
Feb 2, 2014, 6:46:00 AM2/2/14
to anglep...@googlegroups.com
Ok, so I ended up doing this. The following code is run after setup of the GL context in a hidden window:

    EGLSurface sfc = eglGetCurrentSurface(EGL_DRAW);
    egl::Surface* surface = static_cast<egl::Surface*>(sfc);
    rx::SwapChain9* swap_chain9 = dynamic_cast<rx::SwapChain9*>(surface->getSwapChain());
    if(!swap_chain9)
        return NULL;

    IDirect3DSurface9* surf = swap_chain9->getRenderTarget();
    return surf;

The returned surface can be used as back buffer in a D3DImage in a WPF application. This renders correctly with no "airspace issues", i.e I can render WPF controls on top of it and it blends correctly.

However, this solution feels a little bit dirty... Aside from the obvious potential for future changes in the internals of the ANGLE classes, can anyone tell me if this solution is sound enough? I.e can the swapbuffer's rendertarget be used in this manner, or is it just random luck that it works? :-)

I would feel a little more "future proof" if I could use a supported extension. I tried using the EGL_ANGLE_surface_d3d_texture_2d_share_handle extension, but I was never able to get a share handle (it was always NULL). How am I supposed to set up the EGL context in order to get this handle?

The best would be an extension get the the render surface directly, but with a little bit more control of the setup and context. What would be the procedure of proposing such an extension? My employer needs this functionality for a project, and we would be able to put some hours and effort into both the specification and implementation of this extension. Or are there compelling reasons that such an extension should not work?

Best regards,
Thomas Sevaldrud

Nicolas Capens

unread,
Feb 7, 2014, 10:01:52 AM2/7/14
to Thomas Sevaldrud, anglep...@googlegroups.com
Hi Thomas,

Hacking into the internals of ANGLE like that is definitely not recommended. Other projects have done this as well and they broke when we changed the Surface and SwapChain classes. The proper way to do it is to use EGL_ANGLE_surface_d3d_texture_2d_share_handle.

It's odd that it doesn't work for you. Did you call eglQuerySurfacePointerANGLE(display, surface, EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE, &handle) ? What was its return value, the value of 'handle', and were there any GL errors recorded? Note that the handle is of type HANDLE and you still have to create a texture/resource for it, as described in the extension:

"The Direct3D share handle may be passed as the pSharedHandle parameter of the Direct3D9Ex CreateTexture function, or via the Direct3D10 OpenSharedResource function. If used with Direct3D 9, the level argument to CreateTexture must be 1, and the dimensions must match the dimensions of the EGL surface. If used with Direct3D 10, OpenSharedResource should be called with the ID3D10Texture2D uuid to obtain an ID3D10Texture2D object."

The only requirement for the extension is that your system supports Direct3D9Ex. So no Windows XP.

Cheers,
Nicolas

John Bauman

unread,
Feb 7, 2014, 6:31:33 PM2/7/14
to nicolas...@gmail.com, Thomas Sevaldrud, angleproject
One thing to note is that you can only get  EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE on a pbuffer and not a window surface.

Thomas Sevaldrud

unread,
Feb 10, 2014, 7:08:17 AM2/10/14
to John Bauman, nicolas...@gmail.com, angleproject
'm using ANGLE through Qt, and have tried setting up both a window target and an FBO target. In both cases, the shared handle is null. I guess I could make it work with a PBuffer if I set up the EGL context manually. However, I don't think this solution would be as good as getting an IDirect3DSurface9, because this surface handle can be used directly in the D3DImage .NET class. 

I am by no means a DirectX expert (that's why I want to use OpenGL in the first place :-)) and maybe I have just misunderstood some basic DX concepts here, but with a shared texture handle I guess I would need to render a textured surface which means dragging in SlimDX or some other DX wrapper in my WPF application. Alternatively I could possibly do this in the C++ code by programming DX9 directly and then use the IDirect3DSurface9 from my second render surface, but it would still be more cumbersome than simply using the render target surface that is already there.

As I mentioned in an earlier mail, I would really like to see an ANGLE extension for this functionality. I would think that I am not alone in finding this functionality useful? As I also mentioned I can help in whatever way I can with the specification and implementation of such an extension

Thomas Sevaldrud

unread,
Feb 12, 2014, 5:39:53 AM2/12/14
to Chris Araman, angleproject
Hi Chris, glad to hear that I'm not the only one who needs this functionality. I can at least verify that the method works nicely in our app :-) 

Below is a proposal for an extension that would solve this cleanly. I can implement it and test it according to the angle project guidelines and write the extension text if I get an indication from this list if such a patch would be accepted

The extension would be a variant of the ANGLE_surface_d3d_texture_2d_share_handle. Let's call it ANGLE_surface_d3d9_handle for example. It would be dependent on EGL_ANGLE_query_surface_pointer, and simply return the IDirect3DSurface9 handle or NULL if no such handle exists (if you have a DX11 renderer for example). Typical usage:

  void* handle = NULL;
  eglQuerySurfacePointerANGLE(dpy, sfc, EGL_D3D9_SURFACE_HANDLE_ANGLE , &handle);

The code changes would be minimal: In libEGL.cpp (around line 500 in my version) simply add a switch case:

EGLBoolean __stdcall eglQuerySurfacePointerANGLE(EGLDisplay dpy, EGLSurface surface, EGLint attribute, void **value)
{

...
        switch (attribute)
        {
          case EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE:
            {
                rx::SwapChain *swapchain = eglSurface->getSwapChain();
                *value = (void*) (swapchain ? swapchain->getShareHandle() : NULL);
            }

          case EGL_D3D9_SURFACE_HANDLE_ANGLE:
            {
                rx::SwapChain *swapchain = eglSurface->getSwapChain();
                *value = (void*) (swapchain ? swapchain->getRenderTargetSurfaceHandle() : NULL);
            }


The getRenderTargetSurfaceHandle() method would be a virtual in rx::SwapChain returning the renderTarget in rx::SwapChain9 and NULL in rx::SwapChain11

- Thomas


On Wed, Feb 12, 2014 at 12:46 AM, Chris Araman <car...@fuzebox.com> wrote:
I'm also interested in exactly this solution for composition of OpenGL rendered content in a WPF application. We have a cross-platform OpenGL renderer, and need to overlay platform-specific content. In order to take part in WPF composition, we need to render using a D3DImage. ANGLE would allow us to avoid writing a redundant DirectX renderer, but only if we can (safely) access the underlying IDirect3DSurface9. Details here:
http://msdn.microsoft.com/en-us/library/cc656710(v=vs.110).aspx

Shannon Woods

unread,
Feb 13, 2014, 5:07:52 PM2/13/14
to anglep...@googlegroups.com, Chris Araman
Yes, we'd be willing to consider such an extension. One of the concerns, though, would be that it would be useful only in a DX9 setup, to a subset of users (which is one reason we've gone with the API-agnostic texture share handle, which can be used across both DX9 and DX11). And there's the possibility that future changes to our Surface and SwapChain handling might break things for the extension.

Also worth noting-- it would be best to base any work on the es3proto branch (our development branch), as there are significant changes there versus master, and we anticipate es3proto to be merged back to mainline soon.

Thomas Sevaldrud

unread,
Feb 14, 2014, 3:44:39 AM2/14/14
to shanno...@chromium.org, angleproject, Chris Araman
I agree with the DX11 concern, but I'm not sure if this particular functionality would be relevant for DX11? WPF is based on DX9 and the API's of any future WPF/DX11 integration I think would be hard to predict. Also, if you want to do the integration in a pure C++ app with DX11 I guess there are other, simpler ways of doing this? But then again, I'm no DX expert so I may be way off here. 

One thing that would make this extension more consistent and useful was if we could introduce an extra enum value, EGL_D3D9_ONLY_DISPLAY_ANGLE to the EGL_ANGLE_direct3d_display extension, would that be a possibility? Then we could also consider changing the surface handle extension to be more backend neutral, i.e. we could call it EGL_D3D_SURFACE_HANDLE and also return a corresponding handle for DX11 if something like this exists? But this would require that the user has control over which backend to use, or at least a way to query it.

- Thomas

Shannon Woods

unread,
Feb 14, 2014, 3:31:37 PM2/14/14
to anglep...@googlegroups.com, shanno...@chromium.org, Chris Araman
We're actually changing the way that specific backends are requested at runtime in ANGLE. You may want to take a look at the in-progress patches to implement EGL_ANGLE_platform_angle_d3d, based on EGL_EXT_platform_base, and the extnesion text for that extension, recently added to the repository. The in-progress implementation is here: https://chromium-review.googlesource.com/#/c/185396/ There is an explicit D3D9 token in this extension.

Thomas Sevaldrud

unread,
Feb 18, 2014, 4:07:41 AM2/18/14
to shanno...@chromium.org, angleproject, Chris Araman
Looks like just what I need :-)

So the only remaining issue is if we should make a generic render surface handle extension or if it should be D3D9 specific. I tend towards 9-specific, since I don't see the exact use case for a DX11 version of it yet, but of course let me know if you have comments on this. 

- Thomas

Shannon Woods

unread,
Feb 18, 2014, 5:08:17 PM2/18/14
to anglep...@googlegroups.com, shanno...@chromium.org, Chris Araman
I don't know very much about WPF interoperability, but from what I can gather, DX10+ interop is meant to be done with textures, for which we already expose share handles, so an additional extension likely won't be of use to DX11 ANGLE. Most of my cross-API worry is that, as main development will be increasingly focused on ES 3.0 and D3D 11, further work or rearchitecture could may cause problems for the extension implementation but escape notice.

Thomas Sevaldrud

unread,
Feb 19, 2014, 5:54:13 AM2/19/14
to shanno...@chromium.org, angleproject, Chris Araman
Ok, then I think we should make this a D3D9 specific extension. I can see your point regarding future refactorings, but as long as there will be a D3D9 path in ANGLE I can't imagine that it will be rewritten so much that it should break this extension beyond repair. It is after all a very simple feature. 

Also, an extension is not guaranteed to be available, and no developer should make his code 100% dependent on any extension without a fallback path. In that case he should at least base his code on a version of Angle that has this extension.

I will of course be using this extension and can take responsibility for maintaining it if necessary.

- Thomas


Chris Araman

unread,
Mar 19, 2014, 8:34:41 PM3/19/14
to anglep...@googlegroups.com, shanno...@chromium.org, Chris Araman
Thomas, were you able to implement this extension in Angle?

Did it enable you to render with WPF's D3DImage?

Thomas Sevaldrud

unread,
Mar 20, 2014, 7:02:14 AM3/20/14
to Chris Araman, angleproject, shanno...@chromium.org
It worked nicely with D3DImage through the hack I described above. I haven't gotten around to implementing the extension yet, since I got swamped with some other work here :-) 

It is on my todo-list though and it should be real simple, so hopefully I'll get around to it soon.

- Thomas


On Thu, Mar 20, 2014 at 1:34 AM, Chris Araman <car...@fuzebox.com> wrote:
Thomas, were you able to implement this extension in Angle?

Did it enable you to render with WPF's D3DImage?

--
You received this message because you are subscribed to the Google Groups "angleproject" group.
To unsubscribe from this group and stop receiving emails from it, send an email to angleproject...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply all
Reply to author
Forward
0 new messages