IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Windows Presentation Foundation Discussion :

Consommation CPU WPF/DirectX dans une D3DImage


Sujet :

Windows Presentation Foundation

  1. #1
    Nouveau membre du Club
    Homme Profil pro
    Inscrit en
    Mars 2013
    Messages
    8
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations forums :
    Inscription : Mars 2013
    Messages : 8
    Par défaut Consommation CPU WPF/DirectX dans une D3DImage
    Bonjour,

    Je suis surpris par la forte consommation CPU de DirectX dans WPF. Environ 30% pour un scène mise à jour 30 fois par seconde sur Windows XP (sachant que le PC de test est plus puissant que le PC qui recevra l'application...).

    J'utilise une DLL codée en C++ avec Directx9 et j'affiche le rendu dans WPF à l'aide d'un D3DImage. J'ai repris le code d'exemple de Microsoft que l'on trouve ici : http://msdn.microsoft.com/en-us/library/cc656785.aspx

    Dans la fonction de rendu, je limite le rafraichissement pour respirer un peu (sinon, les événements souris sont asphyxiés !). C'est une limitation grossière, mais une mesure du nombre de FPS dans le code Directx me donne 30 images/seconde. J’arrangerai ça plus tard .

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
     
            private long _PreviousFrameTime = 0;
            void CompositionTarget_Rendering(object sender, EventArgs e)
            {
                RenderingEventArgs args = (RenderingEventArgs)e;
     
                // Control FPS
                long elapsedTicks = DateTime.Now.Ticks - _PreviousFrameTime;
                TimeSpan elapsedSpan = new TimeSpan(elapsedTicks);
     
                if (elapsedSpan.TotalMilliseconds < 1000d / 40d)
                   return;
     
                // It's possible for Rendering to call back twice in the same frame 
                // so only render when we haven't already rendered in this frame.
                if (d3dimg.IsFrontBufferAvailable && _lastRender != args.RenderingTime)
                {
                    IntPtr pSurface;
                    HRESULT.Check(GetBackBufferNoRef(out pSurface));
                    if (pSurface != IntPtr.Zero)
                    {
                        d3dimg.Lock();
                        // Repeatedly calling SetBackBuffer with the same IntPtr is 
                        // a no-op. There is no performance penalty.
                        d3dimg.SetBackBuffer(D3DResourceType.IDirect3DSurface9, pSurface);
                        HRESULT.Check(Render());
                        d3dimg.AddDirtyRect(new Int32Rect(0, 0, d3dimg.PixelWidth, d3dimg.PixelHeight));
                        d3dimg.Unlock();
     
                        _lastRender = args.RenderingTime;
                    }
                }
                _PreviousFrameTime = DateTime.Now.Ticks;
         }
    L'outil Visual profiler me dit qu'il passe 20% dans l' "UCE process queue". Je ne sais pas trop ce que c'est, mais quand je commente AddDirtyRect(), l'occupation CPU tend vers 0 (ne pas faire le new à chaque cycle ne change strictement rien).

    Qu'en pensez-vous ?

    EDIT: Question subsidiaire : sur un PC équipé d'un XP SP3, le d3dimg.IsFrontBufferAvailable passe à true deux fois, puis reste à false indéfiniment. Du coup l'application reste ouverte, mais la scène ne s'affiche pas...

    Je n'ai pas de Visual Studio sur ce PC, donc j'ai des difficultés à déboguer...

    Avez-vous une idée sur ce qui pourrait se passer ?

  2. #2
    Nouveau membre du Club
    Homme Profil pro
    Inscrit en
    Mars 2013
    Messages
    8
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations forums :
    Inscription : Mars 2013
    Messages : 8
    Par défaut
    Je me permets de remonter le sujet, avec l'espoir d'un petit coup de pouce

  3. #3
    Membre confirmé
    Profil pro
    Inscrit en
    Juillet 2010
    Messages
    52
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2010
    Messages : 52
    Par défaut
    Bonjour,
    Je n'ai malheureusement pas de réponse à te donner, mais je pensais as-tu regardé du côté de sharpdx ou slimdx ? Peux-être qu'en regardant leurs codes cela te permettra de trouver une solution.

  4. #4
    Nouveau membre du Club
    Homme Profil pro
    Inscrit en
    Mars 2013
    Messages
    8
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations forums :
    Inscription : Mars 2013
    Messages : 8
    Par défaut
    Bonne idée. Je vais regarder un peu le code pour voir s'ils font des choses semblables

  5. #5
    Membre extrêmement actif
    Inscrit en
    Avril 2008
    Messages
    2 573
    Détails du profil
    Informations personnelles :
    Âge : 65

    Informations forums :
    Inscription : Avril 2008
    Messages : 2 573
    Par défaut
    bonjour sfxzeus

    Premierement pour le FPS tu peux te passer du penalisant event "CompositionTarget_Rendering" (160 FPS) en utilsant DispatcherTimer avec le FPS souhaite....
    Code behind .cs du winform:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
     
      public Window1()
            {
                InitializeComponent();
                // Set up the initial state for the D3DImage.
                HRESULT.Check(SetSize(512, 512));
                HRESULT.Check(SetAlpha(false));
                HRESULT.Check(SetNumDesiredSamples(4));
     
                /*   CALL À INITIALIZE DispatcherTimer   */
                int myFPS = 30;
                createTheRenderingWithCorrectFPS(myFPS);
     
                /* out CompositionTarget*/
                //CompositionTarget.Rendering += new EventHandler(CompositionTarget_Rendering);
     
                _adapterTimer = new DispatcherTimer();
                _adapterTimer.Tick += new EventHandler(AdapterTimer_Tick);
                _adapterTimer.Interval = new TimeSpan(0, 0, 0, 0, 500);
                _adapterTimer.Start();
     
                // 
     
                _sizeTimer = new DispatcherTimer(DispatcherPriority.Render);
                _sizeTimer.Tick += new EventHandler(SizeTimer_Tick);
                _sizeTimer.Interval = new TimeSpan(0, 0, 0, 0, 200);
                _sizeTimer.Start();
            }
     
     
            void AdapterTimer_Tick(object sender, EventArgs e)
            {
                POINT p = new POINT(imgelt.PointToScreen(new Point(0, 0)));
     
                HRESULT.Check(SetAdapter(p));
            }
     
     
            void SizeTimer_Tick(object sender, EventArgs e)
            {
                // Given that the D3DImage is at 96.0 DPI, its Width and Height  
                // properties will always be integers. ActualWidth/Height  
                // may not be integers, so they are cast to integers.  
                uint actualWidth = (uint)imgelt.ActualWidth;
                uint actualHeight = (uint)imgelt.ActualHeight;
                if ((actualWidth > 0 && actualHeight > 0) &&
                    (actualWidth != (uint)d3dimg.Width || actualHeight != (uint)d3dimg.Height))
                {
                    HRESULT.Check(SetSize(actualWidth, actualHeight));
                }
            }
     
            /*ICI INITIALIZE DispatcherTimer*/
            public void createTheRenderingWithCorrectFPS(int whichFPS)
            {
                DispatcherTimer _timer = new DispatcherTimer();
                _timer.Interval = TimeSpan.FromMilliseconds(1000d / whichFPS);
                _timer.Start();
                _timer.Tick += new EventHandler(_timer_Tick);
            }
     
            /* DANS TIMER_TICK  LE CODE de CompositionTarget_Rendering */
            void _timer_Tick(object sender, EventArgs e)
            {
     
                //Refresh the 3D scene
                if (d3dimg.IsFrontBufferAvailable )
                {
                    IntPtr pSurface = IntPtr.Zero;
                    HRESULT.Check(GetBackBufferNoRef(out pSurface));
                    if (pSurface != IntPtr.Zero)
                    {
                        d3dimg.Lock();
                        // Repeatedly calling SetBackBuffer with the same IntPtr is  
                        // a no-op. There is no performance penalty.
                        d3dimg.SetBackBuffer(D3DResourceType.IDirect3DSurface9, pSurface);
                        HRESULT.Check(Render());
                        d3dimg.AddDirtyRect(new Int32Rect(0, 0, d3dimg.PixelWidth, d3dimg.PixelHeight));
                        d3dimg.Unlock();
     
                    }
                }
            }
    Ensuite relativemnt à Win XP avec SP3 +l'eventuel HotFix voici que dit MSDN Doc (rubrique
    For best performance on Windows XP, which uses the Windows XP Display Driver Model (XDDM), create a lockable surface that behaves correctly when the IDirect3DSurface9::GetDC method is called. Internally, the BitBlt method transfers the surface across devices in hardware. The GetDC method always works on XRGB surfaces. However, if the client computer is running Windows XP with SP3 or SP2, and if the client also has the hotfix for the layered-window feature, this method only works on ARGB surfaces.
    The video card must support the D3DDEVCAPS2_CAN_STRETCHRECT_FROM_TEXTURES driver capability.
    En clair cote C++ il faut utiliser un Surface DirectX XRGB si on veut un BitBlt hardware (copy video hardware ) du bloc image...
    Si on utilise un Surface DirectX ARGB c'est le software qui est utilise pour copier le bloc image ...evidemment plus lent .
    Il faut regarder de ce cote peut etre & inspecter aussi le D3DDEVCAPS2 de la carte.....
    lien MSDN :
    http://www.google.fr/url?sa=t&rct=j&...43287494,d.ZWU
    bon code...

  6. #6
    Nouveau membre du Club
    Homme Profil pro
    Inscrit en
    Mars 2013
    Messages
    8
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations forums :
    Inscription : Mars 2013
    Messages : 8
    Par défaut
    Merci beaucoup.

    Je vais regarder tout ça aujourd'hui

  7. #7
    Nouveau membre du Club
    Homme Profil pro
    Inscrit en
    Mars 2013
    Messages
    8
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations forums :
    Inscription : Mars 2013
    Messages : 8
    Par défaut
    Je suis en train de regarder la gestion de mes surfaces. Je sais maintenant que:

    - D3DDEVCAPS2_CAN_STRETCHRECT_FROM_TEXTURES est supporté sur ma GC.
    - Dans mon code C++, lorsque l'alpha est désactivé, on utilise le format D3DFMT_X8R8G8B8.

    La création de la surface de rendu est la suivante:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    HRESULT CRenderer::CreateSurface(UINT uWidth, UINT uHeight, bool fUseAlpha, UINT m_uNumSamples)
    {
        HRESULT hr = S_OK;
     
        SAFE_RELEASE(m_pd3dRTS);
     
        IFC(m_pd3dDevice->CreateRenderTarget(
            uWidth,
            uHeight,
            fUseAlpha ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8,
            static_cast<D3DMULTISAMPLE_TYPE>(m_uNumSamples),
            0,
            m_pd3dDeviceEx ? FALSE : TRUE,  // Lockable RT required for good XP perf
            &m_pd3dRTS,
            NULL
            ));
     
        IFC(m_pd3dDevice->SetRenderTarget(0, m_pd3dRTS));
     
        m_uWidth = uWidth;
        m_uHeight = uHeight;
     
    Cleanup:
        return hr;
    }
    J'ai lu également cette article fort intéressant : http://www.codeproject.com/Articles/...on-to-D3DImage

    Je commence à me dire que les performances moyennes que j'obtiens sont normales...(en directx pur, je consomme rien en CPU ).

Discussions similaires

  1. Réponses: 1
    Dernier message: 11/01/2013, 13h14
  2. Directx dans une WinForm
    Par CryoCid dans le forum DirectX
    Réponses: 4
    Dernier message: 16/11/2011, 15h46
  3. Performance d'un contrôle WPF imbriqué dans une Winform
    Par Gold.strike dans le forum Windows Presentation Foundation
    Réponses: 8
    Dernier message: 12/07/2011, 18h18
  4. Réponses: 7
    Dernier message: 17/10/2007, 18h06
  5. [WPF]Scroll dans une ListBox
    Par guitoux1 dans le forum Windows Presentation Foundation
    Réponses: 7
    Dernier message: 12/06/2007, 11h43

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo