XNA and D3DImage - WOOO!

161 views
Skip to first unread message

Jeremiah Morrill

unread,
Aug 9, 2008, 8:48:53 PM8/9/08
to wpf-di...@googlegroups.com
Hey guys,

I just popped the XNA 3.0 CTP DLLs into reflector and found that it is possible to use XNA with the D3DImage using a tad bit of reflection and the MDX assembly, Microsoft.DirectX.Direct3D.  I tried it out and it worked!
I'm sure theres some extra issues I'll have to work out, but here is the XNA code to get the backbuffer surface pointer:

        unsafe public IntPtr GetBackBuffer()
        {
            Type deviceType = typeof(GraphicsDevice);
            FieldInfo fi = deviceType.GetField("pComPtr", BindingFlags.NonPublic | BindingFlags.Instance);
            object ptr = fi.GetValue(graphics.GraphicsDevice);
            IntPtr pComPtr = new IntPtr(Pointer.Unbox(ptr));

            Microsoft.DirectX.Direct3D.Device dev = new Microsoft.DirectX.Direct3D.Device(pComPtr);

            return dev.GetBackBuffer(0, 0, Microsoft.DirectX.Direct3D.BackBufferType.Mono).GetObjectByValue(unchecked((int)0xd2b543af));
        }

One step closer to using the *fun* 3D API :)

-Jer

Jeremiah Morrill

unread,
Aug 9, 2008, 9:02:47 PM8/9/08
to wpf-di...@googlegroups.com
BTW, heres a screenshot of the sexy XNA default CornflowerBlue being rendered to the D3DImage (WPF app on the left, XNA App on the right).  Not much to look at, but just want to show some evidence :)

-Jer
Capture.JPG

Dr. WPF

unread,
Aug 9, 2008, 9:35:05 PM8/9/08
to wpf-di...@googlegroups.com

Rock on, Jer!  That’s the coolest CornflowerBlue I’ve seen all day!  :-p

(Can’t wait to see what you really cook up with this!)

> />>
>

Dr. WPF - Online Office at http://www.drwpf.com/blog/


Jeremiah Morrill

unread,
Aug 9, 2008, 10:14:37 PM8/9/08
to wpf-di...@googlegroups.com
So what is the proper thing to do with the window you use for D3D content (the hWnd the device is initialized with)?  I might be reading your D3D example incorrectly, but it seems you make a 0x0 window.  Is it safe to say the window should just be hidden?  Are there any performance impacts with this?  For instance, is D3D rendering to the surface and then to the window also even though its hidden?  Sorry I'm a little confused on how some of this stuff works.

-Jer

BTW, if anyone uses that XNA backbuffer snippet, you will probably get a LoaderLock exception.  Loaderlocks are not *really* exceptions...You can just hit play to continue on or just turn off the loaderlock exceptions in VS.

Dr. WPF

unread,
Aug 10, 2008, 4:14:47 AM8/10/08
to wpf-di...@googlegroups.com

More great questions!  This lets me know where I’ve fallen short in the article.  J

The window represents a very small perf cost.  A few cycles are used to create it and then it consumes a small amount of memory.  I wouldn’t worry about it too much.  Afterall, if you open Spy++ at any given moment, you’ll likely see dozens of non-visible windows, all existing for different reasons. 

In this scenario, the hwnd exists only because it is required by CreateDevice().  We never actually show the window or present our back buffer.

In a normal DX app, the window would be used for two purposes:  1) monitoring focus changes, and 2) determining where to render on the display. 

Wrt focus, you’ve probably noticed that if you have multiple DX apps running simultaneously, the one in the foreground has much smoother animations than the windows in the background.  DX monitors focus explicitly for this reason so that it can give preferential treatment to a device when it is associated with the foreground window.

Wrt rendering, the only time the hwnd would be used by DX for rendering is when the back buffer is transferred to the front buffer.  This is called “presenting” the back buffer.  We never do that in a D3DImage scenario.

This is the really cool part of how the whole D3DImage mechanism works...  We render our scene to a custom surface, but we never present it.  Instead, we let WPF copy the contents of that surface to its own render target.  Then WPF will present its own back buffer (which now contains the composed scenes) to its front buffer.

The way this works on Vista is even cooler...  Since we create a 9Ex device on Vista, WPF can actually use our device to create a temporary surface that is ”shared” with WPF’s surface (shared surfaces are only supported via 9Ex devices).  It can then copy our surface to the shared surface via a hardware accelerated operation.

Clearly, this approach isn’t possible on a D3D9 device on XP.  The XP approach involves using a lockable surface to do the copy.  This still affords decent perf, but it’s not as performant as the shared surface approach (which, btw, is very similar to how the DWM works to get its excellent perf... you can think of the D3DImage architecture on Vista as a little microcosm of the DWM architecture... okay, there are some notable differences, but the surface sharing approach is similar J).

I digress...  getting back to the hwnd question...  If it really bothers you to have this almost useless window lying around, you do have another option.  You could use the handle of the main window in your WPF app to create the D3D device.  Just supply it to the unmanaged library via InitializeScene() or some such mechanism.  In WPF, you can get the hwnd for a Window instance using (PresentationSource.FromVisual(this) as HwndSource).Handle  (assuming “this” represents the Window or a Visual within it).

Was that a lot more information than you wanted?  J

Quoting "wpf-di...@googlegroups.com" <wpf-di...@googlegroups.com>:

> So what is the proper thing to do with the window you use for D3D content
> (the hWnd the device is initialized with)?  I might be reading your D3D
> example incorrectly, but it seems you make a 0x0 window.  Is it safe to say
> the window should just be hidden?  Are there any performance impacts with
> this?  For instance, is D3D rendering to the surface and then to the window
> also even though its hidden?  Sorry I'm a little confused on how some of
> this stuff works.
>
> -Jer
>
> BTW, if anyone uses that XNA backbuffer snippet, you will probably get a
> LoaderLock exception.  Loaderlocks are not *really* exceptions...You can
> just hit play to continue on or just turn off the loaderlock exceptions in
> VS.
>
>
>
> On Sat, Aug 9, 2008 at 6:35 PM, Dr. WPF <a...@drwpf.com> wrote:
>
>> Rock on, Jer!  That's the coolest CornflowerBlue I've seen all day!  :-p
>>

>> (Can't wait to see what you *really* cook up with this!)

Jeremiah Morrill

unread,
Aug 10, 2008, 5:48:32 AM8/10/08
to wpf-di...@googlegroups.com
This is exactly the information I've needed!!  And as always, very detailed.

I have updated my XNA snippet so it follows your explanation and your example closer and now it only renders to the WPF Window and the XNA window is blank (as I would expect).  I'll see if I can hijack XNA a little more and see if I coerce it to run the 9Ex device for Vista if its not already.

Here is the new snippet for XNA->D3DImage interop that goes in the XNA Microsoft.Xna.Framework.Game sub-class:


        private Surface m_surface;
        private int WIDTH = 300;
        private int HEIGHT = 300;

        unsafe protected override void BeginRun()

        {
            Type deviceType = typeof(GraphicsDevice);
            FieldInfo fi = deviceType.GetField("pComPtr", BindingFlags.NonPublic | BindingFlags.Instance);
            object ptr = fi.GetValue(graphics.GraphicsDevice);
            IntPtr pComPtr = new IntPtr(Pointer.Unbox(ptr));

            Microsoft.DirectX.Direct3D.Device dev = new Microsoft.DirectX.Direct3D.Device(pComPtr);

            m_surface = dev.CreateRenderTarget(WIDTH, HEIGHT, Format.X8R8G8B8, Microsoft.DirectX.Direct3D.MultiSampleType.None, 0, System.Environment.OSVersion.Version.Major >= 6);

            dev.SetRenderTarget(0, m_surface);

            base.BeginRun();
        }
       
        unsafe public IntPtr GetBackBuffer()
        {
            /* TODO:  Figure out how to convert Surface.UnmanagedComPointer to IntPtr */
            return m_surface.GetObjectByValue(unchecked((int)0xd2b543af));

Sacha Barber

unread,
Aug 10, 2008, 6:30:17 AM8/10/08
to wpf-di...@googlegroups.com
WOW man thats amazing. How the hell did you do that.




Date: Sat, 9 Aug 2008 18:02:47 -0700
From: jeremiah...@gmail.com
To: wpf-di...@googlegroups.com
Subject: Re: XNA and D3DImage - WOOO!

Get Hotmail on your mobile from Vodafone Try it Now!

Sacha Barber

unread,
Aug 10, 2008, 6:31:29 AM8/10/08
to wpf-di...@googlegroups.com

Jeremiah Morrill

unread,
Aug 10, 2008, 6:09:29 PM8/10/08
to wpf-di...@googlegroups.com
It was done with Reflector + Doc's assistance + Brute Force.

Here's a screenshot of some real XNA content in WPF.  Fiery buttons will turn the WPF enterprise application market on it's head, haha ;)

I'm going to try to inject a IDirect3DDevice9Ex into the XNA and see what happens under Vista.  The GraphicsDevice class in XNA can take an unmanaged pointer to IDirect3DDevice9 (via the GraphicsDevice::GetManagedObject internal factory method), which is the super-class of the 9Ex...So I have high hopes it will work...

I'll stop spaming you guys about this, but I'll let ya know when I have a full XNA solution via a blog post.

-Jer
Capture.JPG

Sacha Barber

unread,
Aug 11, 2008, 3:48:52 AM8/11/08
to wpf-di...@googlegroups.com
cool




Date: Sun, 10 Aug 2008 15:09:29 -0700

Get fish-slapping on Messenger! Play Now

Marlon Grech

unread,
Aug 17, 2008, 3:47:30 AM8/17/08
to wpf-di...@googlegroups.com
hey Jer,

Can you please make the source code for this available online or send it to via email... please please please

Jeremiah Morrill

unread,
Aug 17, 2008, 4:05:14 AM8/17/08
to wpf-di...@googlegroups.com
I made a blog post about it here:  http://jmorrill.hjtcentral.com/Home/tabid/428/EntryID/259/Default.aspx

The XNA code is just an example XNA app I jacked off the XNA website.

Unfortunately, the code is very mangled as I am still hacking away at getting the 9Ex device working in XNA.  With a hex editor, and ILDASM (could not just ildasm->il file->ilasm because of native code inside the libs), I have been able to change the hardcoded D3DPOOL_MANAGED to D3DPOOL_DEFAULT.  XNA now successfully loadeds a Texture2D class w/ a 9Ex device!  It still crashes when you try to load a texture via the ContentManager.Load...but I feel I'm getting much closer.  If I am successful...I don't know the viability of a hex edited XNA...but it'd be cool still!

-Jer

Marlon Grech

unread,
Aug 17, 2008, 4:07:50 AM8/17/08
to wpf-di...@googlegroups.com
IT IS COOL.... I am gonna try it out .... hihi.... sunday breakfast....

Jeremiah Morrill

unread,
Aug 17, 2008, 4:10:29 AM8/17/08
to wpf-di...@googlegroups.com
I'd like to add that the performance w/o the 9Ex device was pretty damned good...but with knowing it can be better, I really wanna "shoe-horn" it in ;)

If you need any help on the Xna->D3DImage, hit me up.  I'll be glad to help.

-Jer

Marlon Grech

unread,
Aug 17, 2008, 4:11:11 AM8/17/08
to wpf-di...@googlegroups.com
thanks Jer!!!

Jeremiah Morrill

unread,
Aug 17, 2008, 10:43:42 AM8/17/08
to wpf-di...@googlegroups.com
Reply all
Reply to author
Forward
0 new messages