Sign in to follow this  
vinpowfull

[C# & SlimDX & WPF] Exception when creating the device on XP

Recommended Posts

hi everyone ! I'm running on windows XP, but i have an exception when i create the device. The exception's message is : "D3DERR_INVALIDCALL: Invalid call (-2005530516)" The weird thing is that this creation works in an other example (but the code is ugly and not structured at all, and i don't extend from D3DImage). Here's my class extending from D3DImage, and which will contain all the code for drawing.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Interop;
using System.Windows.Media;
using System.Runtime.InteropServices;
using SlimDX.Direct3D9;
using SlimDX;


namespace D3DImageSample
{
    class D3DImageVisualisation : D3DImage
    {
        #region Attributes
        // Variables de gestion (synchronisation...)
        private IntPtr scene = IntPtr.Zero;
        private TimeSpan tsLastRender = TimeSpan.Zero; // Stocke l'instant du dernier rendu
        // Contexte Direct3D
        public Direct3D direct3DXP = null; //Direct3D est recommandé pour Windows XP (XDDM)
        public Direct3DEx direct3DVista = null; //Direct3DEx est recommandé pour Vista, Seven (WDDM)
        private Device device = null; //Représente la carte graphique
        // Géométrie Direct3D
        [StructLayout(LayoutKind.Sequential)]
        private struct VertexTransformedColored //Représente un point 3D avec une couleur
        {
            public Vector4 Position;
            public int Color;
        }
        private static readonly VertexFormat vfVertexTransformedColored = VertexFormat.Diffuse | VertexFormat.PositionRhw;
        private VertexBuffer vbPointsEntities; //Buffer où sont stockés les points
        #endregion
        
        #region DependencyProperties
        //Indique le nombre de fois où le dessin est répété
        private int NbIterations
        {
            get { return (int)GetValue(NbIterationsProperty); }
            set { SetValue(NbIterationsProperty, value); }
        }
        public static readonly DependencyProperty NbIterationsProperty = DependencyProperty.Register("NbIterations", typeof(int), typeof(Window2), new UIPropertyMetadata(0));        
        #endregion

        #region EventsHandlers
        private void OnCompositionTargetRendering(object sender, EventArgs e)
        {
            //il faut demander le dessin direct3D si on veut un affichage à chaque raffraichissement de WPF
            RenderingEventArgs args = (RenderingEventArgs)e;

            // Il est possible que Rendering survienne 2 fois à la même image
            // donc on ne fait le rendu que s'il n'a pas déjà été fait pour cette image            
            if (this.IsFrontBufferAvailable && tsLastRender != args.RenderingTime)
            {
                IntPtr pSurface = IntPtr.Zero;
                pSurface = device.GetBackBuffer(0, 0).ComPointer; //récupère la surface de dessin Direct3D                
                if (pSurface != IntPtr.Zero)
                {
                    this.Lock();//on verrouille notre D3DImage                    
                    // Les appels répétés à SetBackBuffer avec le même IntPtr est                    
                    // une non-opération. Il n'y a pas de perte de performance                    
                    this.SetBackBuffer(D3DResourceType.IDirect3DSurface9, pSurface);
                    RenderScene();
                    //on déclare que l'image a été mise à jour
                    this.AddDirtyRect(new Int32Rect(0, 0, this.PixelWidth, this.PixelHeight));
                    this.Unlock();
                    tsLastRender = args.RenderingTime;
                }
            }

        }
        private void OnIsFrontBufferAvailableChanged(object sender, DependencyPropertyChangedEventArgs e){
            // Si le front buffer est disponible, alors WPF vient juste de créer un nouveau
            // D3D device, donc nous pouvons commencer à rendre notre scene perso.            
            if (this.IsFrontBufferAvailable)
            {
                BeginRenderingScene();
            }
            else
            {
                // Si le font buffer n'est plus disponible, alors WPF a perdu
                // son D3D device alors il est inutile d'effectuer le rendu
                // tant qu'un nouveau device n'est pas créé.                
                StopRenderingScene();
            }

        }
        #endregion

        #region Constructors
        public D3DImageVisualisation():base()
        {
            
            //A chaque changement dans la disponibilité du FrontBuffer
            this.IsFrontBufferAvailableChanged+=OnIsFrontBufferAvailableChanged;
            
            //
            BeginRenderingScene();
        }      
        #endregion

        #region Direct3D Methods
        private IntPtr InitializeScene()
        {
            #region Create & Config device
            //direct3DVista = new Direct3DEx();
            direct3DXP = new Direct3D();
            HwndSource hwndSource = new HwndSource(0, 0, 0, 0, 0, "test", IntPtr.Zero);            
            PresentParameters ppParameters = new PresentParameters();
            ppParameters.SwapEffect = SwapEffect.Discard;
            ppParameters.DeviceWindowHandle = hwndSource.Handle;            
            ppParameters.Windowed = true;
            ppParameters.PresentFlags = PresentFlags.LockableBackBuffer;
            ppParameters.BackBufferWidth = 800;
            ppParameters.BackBufferHeight= 600;
            ppParameters.AutoDepthStencilFormat = Format.D16Lockable;
            ppParameters.BackBufferFormat = Format.A8B8G8R8;

            try
            {
                device = new Device(
                    direct3DXP,
                    0,
                    DeviceType.Hardware,
                    hwndSource.Handle,
                    CreateFlags.HardwareVertexProcessing,
                    ppParameters);
            }
            catch(Exception e)
            {
                MessageBox.Show(e.Message);
            }
            #endregion

            #region Create geometry, buffers ...
            //on crée la géométrie
            VertexTransformedColored[] verts2 = new VertexTransformedColored[4];
            verts2[0].Position = new Vector4(0, 0, 0.5f, 1.0f);
            verts2[0].Color = System.Drawing.Color.Aqua.ToArgb();
            verts2[1].Position = new Vector4(100, 100, 0.5f, 1.0f);
            verts2[1].Color = System.Drawing.Color.Aqua.ToArgb();
            verts2[2].Position = new Vector4(50, 150, 0.5f, 1.0f);
            verts2[2].Color = System.Drawing.Color.Aqua.ToArgb();
            verts2[3].Position = new Vector4(20, 200, 0.5f, 1.0f);
            verts2[3].Color = System.Drawing.Color.Aqua.ToArgb();
            //crée le vb
            vbPointsEntities = new VertexBuffer(device, 4 * Marshal.SizeOf(new VertexTransformedColored()), Usage.Points, vfVertexTransformedColored, Pool.Managed);
            //on crée un datastream pour remplir le buffer
            DataStream dstm = vbPointsEntities.Lock(0, 0, 0);
            //on écrit le buffer
            dstm.WriteRange<VertexTransformedColored>(verts2);
            vbPointsEntities.Unlock();
            #endregion

            return device.GetBackBuffer(0,0).ComPointer;
        }
        private void BeginRenderingScene()
        {
            if (this.IsFrontBufferAvailable)
            {
                // crée une scène D3D perso. et retourne un pointeur sur sa surface                
                scene=InitializeScene();

                // configure le back buffer avec la nouvelle scene                
                this.Lock();
                this.SetBackBuffer(D3DResourceType.IDirect3DSurface9, scene);
                this.Unlock();
                // leverage the Rendering event of WPF's composition target to
                // update the custom D3D scene
                CompositionTarget.Rendering += OnCompositionTargetRendering;
            }

        }
        private void RenderScene()
        {
            device.Clear(ClearFlags.Target | ClearFlags.ZBuffer, new Color4(0f, 1f, 0f, 0f), 1, 0);
            device.BeginScene();
            device.VertexFormat = vfVertexTransformedColored;
            //device.DrawUserPrimitives<VertexTransformedColored>(PrimitiveType.TriangleList, 0, 1, verts);
            /*for (int i = 0; i < NbIterations; i++)
            {                        
                device.DrawUserPrimitives<VertexTransformedColored>(PrimitiveType.LineStrip, 0, 2, verts2);
            }*/
            device.SetStreamSource(0, vbPointsEntities, 0, Marshal.SizeOf(new VertexTransformedColored()));
            //System.Console.WriteLine(vb.Description.SizeInBytes.ToString());
            for (int i = 0; i < NbIterations; i++)
            {
                device.DrawPrimitives(PrimitiveType.TriangleFan, 0, 2);
            }

            device.EndScene();
        }
        private void StopRenderingScene()
        {
            // Cette procédure est appellée quand WPF perd son D3D device.
            // Dans ce cas, il est très probable que nous ayons perdu le notre aussi,
            // donc nous devrions juste nettoyer la scene.
            // Nous créerons une nouvelle scène quand le D3D device sera de nouveau disponible.            
            CompositionTarget.Rendering -= OnCompositionTargetRendering;

            // release the scene 
            // (this is a call into our custom unmanaged library)
            ReleaseScene();
            scene = IntPtr.Zero;
        }
        private void ReleaseScene()
        {

        }
        #endregion

    }
}


and here's how i create a Window and a Image to test my class
using System;
using System.Collections.Generic;
using System.Linq;
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;

namespace D3DImageSample
{
    /// <summary>
    /// Logique d'interaction pour WindowD3DIV.xaml
    /// </summary>
    public partial class WindowD3DIV : Window
    {
        public WindowD3DIV()
        {
            InitializeComponent();
            myImage.Source=new D3DImageSample.D3DImageVisualisation();
        }
    }
}

finaly the XAML code:
<Window x:Class="D3DImageSample.WindowD3DIV"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:my="clr-namespace:D3DImageSample"
    Title="WindowD3DIV" Height="300" Width="300">
    <StackPanel>
        <Image MaxHeight="800" Name="myImage">        
        </Image>
    </StackPanel>
</Window>

Thanks for any help !

Share this post


Link to post
Share on other sites
Hey, thanks for the links, this will help me a lot :)
So, here's my output :

D3D9 Helper: Enhanced D3DDebugging disabled; Application was not compiled with D3D_DEBUG_INFO
Direct3D9: (ERROR) :Invalid flags specified. GetAdapterIdentifier fails.
'D3DImageSample.exe' : Chargé 'C:\WINDOWS\assembly\NativeImages_v2.0.50727_32\PresentationFramewo#\b4dc4bd8534d90fbb7430926ad990cd9\PresentationFramework.Luna.ni.dll'
'D3DImageSample.exe' (Managé) : 'C:\WINDOWS\assembly\GAC_MSIL\PresentationFramework.Luna\3.0.0.0__31bf3856ad364e35\PresentationFramework.Luna.dll' chargé, chargement des symboles ignoré. Le module est optimisé et l'option du débogueur 'Uniquement mon code' est activée.
'D3DImageSample.exe' : Chargé 'C:\WINDOWS\system32\rsaenh.dll'
'D3DImageSample.exe' (Managé) : 'C:\WINDOWS\assembly\GAC_MSIL\mscorlib.resources\2.0.0.0_fr_b77a5c561934e089\mscorlib.resources.dll' chargé
'D3DImageSample.exe' (Managé) : 'C:\WINDOWS\WinSxS\x86_Microsoft.VC80.CRT_1fc8b3b9a1e18e3b_8.0.50727.3053_x-ww_b80fa8ca\msvcm80.dll' chargé
'D3DImageSample.exe' : Chargé 'C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\diasymreader.dll'
'D3DImageSample.exe' : Chargé 'C:\WINDOWS\assembly\NativeImages_v2.0.50727_32\System.Drawing\6978f2e90f13bc720d57fa6895c911e2\System.Drawing.ni.dll'
'D3DImageSample.exe' (Managé) : 'C:\WINDOWS\assembly\GAC_MSIL\System.Drawing\2.0.0.0__b03f5f7f11d50a3a\System.Drawing.dll' chargé, chargement des symboles ignoré. Le module est optimisé et l'option du débogueur 'Uniquement mon code' est activée.
'D3DImageSample.exe' : Chargé 'C:\WINDOWS\system32\D3DX9_41.dll'
Direct3D9: (ERROR) :Invalid value for BackBufferFormat. ValidatePresentParameters fails.
D3D9 Helper: IDirect3D9::CreateDevice failed: D3DERR_INVALIDCALL
Une exception de première chance de type 'SlimDX.Direct3D9.Direct3D9Exception' s'est produite dans SlimDX.dll
Direct3D9: (INFO) :======================= Hal HWVP Pure device selected

Direct3D9: (ERROR) :Invalid iBackBuffer parameter passed to GetBackBuffer
Direct3D9: (ERROR) :Invalid iBackBuffer parameter passed to GetBackBuffer
Une exception de première chance de type 'System.NullReferenceException' s'est produite dans SlimDX.dll
'D3DImageSample.exe' (Managé) : 'C:\WINDOWS\assembly\GAC_MSIL\PresentationFramework.resources\3.0.0.0_fr_31bf3856ad364e35\PresentationFramework.resources.dll' chargé
Une exception non gérée du type 'System.Windows.Markup.XamlParseException' s'est produite dans PresentationFramework.dll

Informations supplémentaires : Impossible de créer une instance de « WindowD3DIV » définie dans l’assembly « D3DImageSample, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null ». Une exception a été levée par la cible d'un appel. Erreur dans le fichier de balisage « WindowD3DIV.xaml » ligne 1 position 9.

Le programme '[1920] D3DImageSample.exe: Natif' s'est arrêté avec le code 0 (0x0).
Le programme '[1920] D3DImageSample.exe: Managé' s'est arrêté avec le code 0 (0x0).

Share this post


Link to post
Share on other sites
Direct3D9: (ERROR) :Invalid value for BackBufferFormat. ValidatePresentParameters fails.
There's the problem [smile]. I'd guess that your desktop is 16 or 24-bit, but you're asking for a 32-bit backbuffer, which tends not to work in windowed mode.

For windowed mode, you can specify Format.Unknown to say "use the desktop format".

Share this post


Link to post
Share on other sites
Hey that's works you rocks, thank you very much !

But, it's quite surprising since, like i said, it worked very well in another example on the same computer...
Now, i didn't have transparency anymore (not really a problem for the moment), and i have a performance problem :
The CPU is used a lot, i think it's a famous problem, i didn't benefit hardware acceleration :

"For hardware acceleration on XP, the surface must be created as lockable. On Vista, however, a non-lockable surface is preferable (although not required), as it is generally faster.

On XP, the Direct3DCreate9() function must be used to create the D3D device. On Vista, however, you should use the Direct3DCreate9Ex() function to create a D3D 9Ex device. By creating a 9Ex device, WPF will be able to use your device to create its own temporary surface that is shared with the MIL's surface. Then, it can copy your surface to its shared surface via a highly performant GPU routine."
source: http://www.codeproject.com/KB/WPF/D3DImage.aspx

maybe should I create another TOPIC ?
thank you !
EDIT: the performance problem was present in my other example. I'm running XP SP3 and i set "ppParameters.PresentFlags = PresentFlags.LockableBackBuffer;" so i don't know why i don't have hardware acceleration.
On Windows 7RC hardware acceleration seems to be enabled (when i use a direct3DEx device of course), the CPU charge stay low.

Share this post


Link to post
Share on other sites
There is another point i didn't understand :
why must I write Marshal.SizeOf(new VertexTransformedColored()) ??
In all others code samples i saw, the syntax is "Marshal.SizeOf(sizeof(VertexTransformedColored))" but for me it's: Erreur 1 'D3DImageSample.D3DImageVisualisation.VertexTransformedColored' does not have a predefined size, therefore sizeof can only be used in an unsafe context (consider using System.Runtime.InteropServices.Marshal.SizeOf) ??

Well, i spent all my afternoon on this problem, i didn't manage to have good results.
I'm really stuck, i can't go forward while i have 2 fps with 2000 polygons drawed !

I would like to have your advise:
The goal of my program will be to test the drawing of a big 2D map. This map is composed of 50 000 entities which represents 2D polygons with a variable number of points by entities.
I'm thinking to draw each entity with a TriangleFan because I want them to be filled (in fact i want to draw their borders too, will i have to draw the map a second time with a linestrip oO???) this mean i'll have to draw about a half-million triangles (twice??).
Am i in a wrong way ?

thank you

Share this post


Link to post
Share on other sites
ok, another weird thing to me about indexed geometry:

here's my geometry:

#region Create geometry, buffers ...
//on crée la géométrie
VertexTransformedColored[] verts2 = new VertexTransformedColored[6];
verts2[0].Position = new Vector4(0, 0, 0.5f, 1.0f);
verts2[0].Color = System.Drawing.Color.FromArgb(128, 0, 0, 255).ToArgb();
verts2[1].Position = new Vector4(100, 100, 0.5f, 1.0f);
verts2[1].Color = System.Drawing.Color.FromArgb(128, 0, 255, 0).ToArgb();
verts2[2].Position = new Vector4(50, 150, 0.5f, 1.0f);
verts2[2].Color = System.Drawing.Color.FromArgb(128, 255, 0, 255).ToArgb();

verts2[3].Position = new Vector4(0+50, 0, 0.5f, 1.0f);
verts2[3].Color = System.Drawing.Color.FromArgb(128, 0, 0, 255).ToArgb();
verts2[4].Position = new Vector4(100+50, 100, 0.5f, 1.0f);
verts2[4].Color = System.Drawing.Color.FromArgb(128, 0, 255, 0).ToArgb();
verts2[5].Position = new Vector4(50+50, 150, 0.5f, 1.0f);
verts2[5].Color = System.Drawing.Color.FromArgb(128, 255, 0, 255).ToArgb();

//crée le vb
vbPointsEntities = new VertexBuffer(device, verts2.Length * Marshal.SizeOf(new VertexTransformedColored()), Usage.Points, vfVertexTransformedColored, Pool.Managed);
//on crée un datastream pour remplir le buffer
DataStream dstm = vbPointsEntities.Lock(0, 0, 0);
//on écrit le buffer
dstm.WriteRange<VertexTransformedColored>(verts2);
vbPointsEntities.Unlock();


//crée le ib
int[] indices = {0,1,2,3,4,5}; //ok the first triangle is displayed
//int[] indices = { 3, 4, 5, 0, 1, 2 }; // NOTHING IS DISPLAYED !
//datastream
ibPointsIndex = new IndexBuffer(device, indices.Length * sizeof(int), Usage.WriteOnly, Pool.Default, false);
DataStream dstmIndex = ibPointsIndex.Lock(0,0,0);
//on écrit dans le buffer
dstmIndex.WriteRange<int>(indices);
ibPointsIndex.Unlock();

#endregion

#region device config
device.VertexFormat = vfVertexTransformedColored;
device.SetStreamSource(0, vbPointsEntities, 0, Marshal.SizeOf(new VertexTransformedColored()));
device.Indices = ibPointsIndex;
#endregion




and here's my call :

private void RenderScene()
{
device.Clear(ClearFlags.Target | ClearFlags.ZBuffer, new Color4(0f, 1f, 0f, 0f), 1, 0);
device.BeginScene();

for (int i = 0; i < NbIterations; i++)
{
device.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, 3, 0, 1);
}
device.EndScene();
}



so the problem is that when i try to display the first triangle which indices are (0,1,2), it's ok but when i try to display the second one (indices 3,4,5) it doesn't display anything ??! The second triangle is only a x-translation by 50 of the first one...

int[] indices = {0,1,2,3,4,5}; //ok the first triangle is displayed
//int[] indices = { 3, 4, 5, 0, 1, 2 }; // NOTHING IS DISPLAYED !

Seriously i've done some OGL before, i never had such weird problems :@

Share this post


Link to post
Share on other sites
Mike.Popoloski: thank you. I've written all my class again starting from 0.
Now i've transparency and i think (but not sure) hardware acceleration :).

Finaly, i managed to display my map.
Now i've another kind of problem, but i'll create another topic to discuss about it.

Thanks for your help !
Vincent

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this