WPF D3DImage with SlimDx

Started by
12 comments, last by juergen1969 15 years, 6 months ago
Hi all, is there a well working sample using SlimDx with .Net Framwork 3.5 (SP1) available? I checked the blog from SteveKr. The sample works very well till I open the Task-Manager in Windows Vista. The Device is lost. Sometims I can recreate it. After the second or third time the program crashes with an exception in SlimDX in "Result.cpp". So I'm searching for a better sample. Best regards, Juergen
Advertisement
Using SlimDX in Framework 3.5 isn't any different than using it anywhere else. Using it with WPF is another issue altogether though, as you have airspace issues to worry about. What's this sample you're using / what kind of code are we talking about here?

Losing the device is expected when you do things like that, it sounds like the code is not handling the reset correctly. But you're going to have to provide more information.
Ok, here is my little sample program. If I try to reset the device (device.Reset) it fails with an exception.
If I get an Exception in RenderD3D() I try to create it again. Sometimes it works sometimes not. I want to use the new control D3DImage because it's implemented in WPF and the hole application is written in WPF. At the moment I use a 3D-control written in WinForms inside the WPF-application.

Ok, here is the code:

using System;using System.Collections.Generic;using System.Text;using System.Windows;using System.Windows.Controls;using System.Windows.Data;using System.Windows.Documents;using System.Windows.Input;using System.Windows.Media;using System.Windows.Media.Imaging;using System.Windows.Shapes;using System.Windows.Interop;using System.Drawing;using SlimDX;using SlimDX.Direct3D9;namespace D3DIMageTest{	/// <summary>	/// Interaction logic for Window1.xaml	/// </summary>	public partial class Window1 : Window	{		SlimDX.Direct3D9.Direct3D direct3D = new SlimDX.Direct3D9.Direct3D();		Device device;  		Sprite sprite;  		Texture texture;  		public Window1()		{			InitializeComponent();			Loaded += new RoutedEventHandler(Window_Loaded);		}				private void Window_Loaded(object sender, RoutedEventArgs e)  		{  			InitializeD3D();  			CompositionTarget.Rendering += OnRendering;  			d3dimage.IsFrontBufferAvailableChanged += new DependencyPropertyChangedEventHandler(OnIsFrontBufferAvailableChanged);						d3dimage.Lock();  			d3dimage.SetBackBuffer(D3DResourceType.IDirect3DSurface9, device.GetBackBuffer(0, 0).ComPointer);  			d3dimage.Unlock();  		}				public void InitializeD3D()  		{  			HwndSource hwnd = new HwndSource(0, 0, 0, 0, 0, "test", IntPtr.Zero);  						PresentParameters pp = new PresentParameters();  			pp.SwapEffect = SwapEffect.Discard;  			pp.DeviceWindowHandle = hwnd.Handle;  			pp.Windowed = true;  			pp.BackBufferWidth = 400;  			pp.BackBufferHeight = 400;  			pp.BackBufferFormat = Format.X8R8G8B8;  						device = new Device(direct3D, 0, 			                    DeviceType.Hardware, 			                    hwnd.Handle, 			                    CreateFlags.HardwareVertexProcessing, 			                    pp);					}						private void OnRendering(object sender, EventArgs e)		{			try {				d3dimage.Lock(); 				d3dimage.SetBackBuffer(D3DResourceType.IDirect3DSurface9, device.GetBackBuffer(0, 0).ComPointer);  				RenderD3D();				d3dimage.AddDirtyRect(new Int32Rect(0, 0, d3dimage.PixelWidth, d3dimage.PixelHeight));				d3dimage.Unlock();			}			catch (Direct3D9Exception ex) {				string msg = ex.Message;			}		}				void OnIsFrontBufferAvailableChanged(object sender, DependencyPropertyChangedEventArgs e)		{			if (d3dimage.IsFrontBufferAvailable) {				InitializeD3D();  				CompositionTarget.Rendering += OnRendering;  				d3dimage.IsFrontBufferAvailableChanged += new DependencyPropertyChangedEventHandler(OnIsFrontBufferAvailableChanged);								d3dimage.Lock();  				d3dimage.SetBackBuffer(D3DResourceType.IDirect3DSurface9, device.GetBackBuffer(0, 0).ComPointer);  				d3dimage.Unlock();  			} 			else {				CompositionTarget.Rendering -= OnRendering; 			}						}		public void RenderD3D()		{            Result result;			try {                if (d3dimage.IsFrontBufferAvailable)                {                    result = device.TestCooperativeLevel();                    if (result.IsFailure) {                        throw new Direct3D9Exception();                    }                    device.Clear(ClearFlags.Target, new Color4(System.Drawing.Color.Yellow), 0, 0);                    device.BeginScene();                    device.EndScene();                    device.Present();                }			}			catch (Exception ex) {				string msg = ex.Message;				InitializeD3D();				CompositionTarget.Rendering += OnRendering;  				d3dimage.IsFrontBufferAvailableChanged += new DependencyPropertyChangedEventHandler(OnIsFrontBufferAvailableChanged);								d3dimage.Lock();  				d3dimage.SetBackBuffer(D3DResourceType.IDirect3DSurface9, device.GetBackBuffer(0, 0).ComPointer);  				d3dimage.Unlock();  			}		}	}}

[Mod edit -- added source tags]

[Edited by - Promit on September 10, 2008 5:40:16 PM]
This might be one of those times you have to create an Ex device. Lucky for you, we added support for just this occasion. Switch to using Direct3DEx and DeviceEx, and see if that works out better.
SlimDX | Ventspace Blog | Twitter | Diverse teams make better games. I am currently hiring capable C++ engine developers in Baltimore, MD.
Quote:Original post by jpetrie
Using it with WPF is another issue altogether though, as you have airspace issues to worry about.


.Net 3.5 SP1 adds the ability to use the D3DImage object. This object allows you to work around the airspace problems that previously made using DirectX with WPF very ugly. The D3DImage object is an ImageSource. Thefore, you can apply an IDirect3DSurface9 as if it was any other WPF brush.

I'd recommend checking out the following if you have not done so already.
Video outlining .NET 3.5 SP1 Pixel Shader Support and D3DImage
Dr WPF's D3DImage article

I have had good sucess using the D3DImage object with XNA and a small bit of reflection hackery. :-)
Quote:Original post by Billr17
Quote:Original post by jpetrie
Using it with WPF is another issue altogether though, as you have airspace issues to worry about.


.Net 3.5 SP1 adds the ability to use the D3DImage object. This object allows you to work around the airspace problems that previously made using DirectX with WPF very ugly. The D3DImage object is an ImageSource. Thefore, you can apply an IDirect3DSurface9 as if it was any other WPF brush.

Right, but that doesn't change how one would use SlimDX itself (which is what I meant by 'another issue'). As for using D3DImage, I don't have much input on that -- looks like it's designed to deal with unmanaged D3D, and SlimDX exposes the unmanaged COM interfaces as IntPtrs, so that's likely what you'd want to use -- as the OP is doing. Beyond that I can't really provide a whole lot of insight...

Promit's suggestion of the Ex interface is worth a look, and there may also be issues with the D3DImage doing something to the D3D interface that SlimDX doesn't expect (or vise-versa), but it's hard to tell without more in-depth analysis.

Making sure unmanaged debugging is enabled so you can see the native D3D debug spew is also worth doing, if there's just a resource that isn't being released before the reset (a pretty common issue), that'll be easy to see with the output.
I tried the same code with Direct3DEx and DeviceEx and everything works fine.

Thank you very much,
Jürgen
Now I have a problem with my textures. I get them with Texture.FromFile().
Each time I want to load a texture I get a "D3DERR_INVALIDCALL: Invalid call (-2005530516)".
I use now the Direct3D9.DeviceEx. It works with the normal Device.

HwndSource hwnd = new HwndSource(0, 0, 0, 0, 0, "test", IntPtr.Zero);  			PresentParameters pp = new PresentParameters();  pp.SwapEffect = SwapEffect.Discard;  pp.DeviceWindowHandle = hwnd.Handle;  pp.Windowed = true;  pp.BackBufferWidth = 400;  pp.BackBufferHeight = 400;  pp.BackBufferFormat = Format.X8R8G8B8;           device = new DeviceEx(direct3D, 0,                     DeviceType.Hardware,                     hwnd.Handle,                     CreateFlags.HardwareVertexProcessing,                     pp);			sprite = new Sprite(device); texture = Texture.FromFile(device, "pic.jpg");
What do the debug runtimes give you?
Mike Popoloski | Journal | SlimDX
FromFile probably defaults to managed pool, which isn't legal on an Ex device. Use the version that specifies the pool explicitly, and pass default.
SlimDX | Ventspace Blog | Twitter | Diverse teams make better games. I am currently hiring capable C++ engine developers in Baltimore, MD.

This topic is closed to new replies.

Advertisement