Améliorations de Direct3D 9Ex

Cette rubrique décrit la prise en charge ajoutée de Windows 7 pour le mode Flip Mode Present et ses statistiques actuelles associées dans Direct3D 9Ex et Desktop Window Manager. Les applications cibles incluent des applications de présentation vidéo ou basées sur la fréquence d’images. Les applications qui utilisent Direct3D 9Ex Flip Mode Present réduisent la charge des ressources système lorsque DWM est activé. Les améliorations des statistiques de présentation associées au mode Flip Mode Present permettent aux applications Direct3D 9Ex de mieux contrôler le taux de présentation en fournissant des mécanismes de rétroaction et de correction en temps réel. Des explications détaillées et des pointeurs vers des exemples de ressources sont inclus.

Cette rubrique contient les sections suivantes.

Améliorations apportées à Direct3D 9Ex pour Windows 7

La présentation en mode flip de Direct3D 9Ex est un mode amélioré de présentation d’images dans Direct3D 9Ex qui transfère efficacement les images rendues au Gestionnaire de fenêtres de bureau Windows 7 (DWM) pour la composition. À compter de Windows Vista, DWM compose l’intégralité du bureau. Lorsque DWM est activé, les applications en mode fenêtré présentent leur contenu sur le bureau à l’aide d’une méthode appelée Mode Blt Present to DWM (ou Blt Model). Avec Blt Model, DWM conserve une copie de la surface rendue Direct3D 9Ex pour la composition desktop. Lorsque l’application est mise à jour, le nouveau contenu est copié sur la surface DWM par le biais d’un blt. Pour les applications qui contiennent du contenu Direct3D et GDI, les données GDI sont également copiées sur la surface DWM.

Disponible dans Windows 7, le mode Flip Present to DWM (ou Flip Model) est une nouvelle méthode de présentation qui permet essentiellement de transmettre des handles de surfaces d’application entre les applications en mode fenêtré et DWM. En plus d’économiser des ressources, Flip Model prend en charge les statistiques actuelles améliorées.

Les statistiques actuelles sont des informations de minutage d’images que les applications peuvent utiliser pour synchroniser les flux vidéo et audio et récupérer des problèmes de lecture vidéo. Les informations de minutage des images dans les statistiques actuelles permettent aux applications d’ajuster la vitesse de présentation de leurs images vidéo pour une présentation plus fluide. Dans Windows Vista, où DWM conserve une copie correspondante de la surface d’image pour la composition du bureau, les applications peuvent utiliser les statistiques de présentation fournies par DWM. Cette méthode d’obtention des statistiques actuelles sera toujours disponible dans Windows 7 pour les applications existantes.

Dans Windows 7, les applications Direct3D 9Ex qui adoptent le modèle flip doivent utiliser les API D3D9Ex pour obtenir les statistiques actuelles. Lorsque DWM est activé, les applications Direct3D 9Ex en mode fenêtré et en mode exclusif plein écran peuvent s’attendre à recevoir les mêmes informations statistiques présentes lors de l’utilisation du modèle flip. Les statistiques actuelles du modèle à retournement Direct3D 9Ex permettent aux applications d’interroger les statistiques actuelles en temps réel, plutôt qu’une fois la trame affichée à l’écran ; les mêmes informations statistiques actuelles sont disponibles pour les applications en mode fenêtré Flip-Model activées que pour les applications plein écran ; Un indicateur ajouté dans les API D3D9Ex permet aux applications Flip Model d’ignorer efficacement les images tardives au moment de la présentation.

Le modèle flip Direct3D 9Ex doit être utilisé par les nouvelles applications de présentation vidéo ou basées sur la fréquence d’images qui ciblent Windows 7. En raison de la synchronisation entre DWM et le runtime Direct3D 9Ex, les applications qui utilisent flip model doivent spécifier entre 2 et 4 backbuffers pour garantir une présentation fluide. Les applications qui utilisent des informations de statistiques présentes tireront parti de l’utilisation du modèle flip activé présentent des améliorations des statistiques.

Présentation en mode flip de Direct3D 9EX

Les améliorations des performances de Direct3D 9Ex Flip Mode Present sont significatives sur le système lorsque DWM est activé et lorsque l’application est en mode fenêtré, plutôt qu’en mode exclusif plein écran. Le tableau et l’illustration suivants présentent une comparaison simplifiée des utilisations de la bande passante mémoire et des lectures et écritures système des applications fenêtrés qui choisissent Flip Model par rapport au modèle Blt d’utilisation par défaut.

Mode Blt présent dans DWM D3D9Ex Flip Mode Present to DWM
1. L’application met à jour son frame (écriture)
1. L’application met à jour son frame (écriture)
2. Le runtime Direct3D copie le contenu de surface vers une surface de redirection DWM (lecture, écriture)
2. Le runtime Direct3D transmet la surface de l’application à DWM
3. Une fois la copie de surface partagée terminée, DWM restitue la surface de l’application à l’écran (lecture, écriture)
3. DWM restitue la surface de l’application à l’écran (lecture, écriture)

illustration d’une comparaison du modèle blt et du modèle de retournement

Le mode Flip Present réduit l’utilisation de la mémoire système en réduisant le nombre de lectures et d’écritures par le runtime Direct3D pour la composition de trames fenêtré par DWM. Cela réduit la consommation d’énergie du système et l’utilisation globale de la mémoire.

Les applications peuvent tirer parti du mode flip direct3D 9Ex présentent des améliorations des statistiques lorsque DWM est activé, que l’application soit en mode fenêtré ou en mode exclusif plein écran.

Modèle de programmation et API

Les nouvelles applications de mesure de la fréquence d’images ou de vidéo qui utilisent les API Direct3D 9Ex sur Windows 7 peuvent tirer parti des économies de mémoire et d’énergie, ainsi que de la présentation améliorée offerte par le mode Flip Present lors de l’exécution sur Windows 7. (Lors de l’exécution sur les versions précédentes de Windows, le runtime Direct3D utilise par défaut l’application en mode Blt Présent.)

Le mode retour présent implique que l’application peut tirer parti des mécanismes de rétroaction et de correction des statistiques de présentation en temps réel lorsque DWM est activé. Toutefois, les applications qui utilisent le mode Flip Mode Present doivent connaître les limitations lorsqu’elles utilisent le rendu simultané de l’API GDI.

Vous pouvez modifier des applications existantes pour tirer parti du mode flip présent, avec les mêmes avantages et mises en garde que les applications nouvellement développées.

Comment choisir le modèle Flip Direct3D 9Ex

Les applications Direct3D 9Ex qui ciblent Windows 7 peuvent opter pour le modèle flip en créant la chaîne d’échange avec la valeur d’énumération D3DSWAPEFFECT_FLIPEX . Pour choisir le modèle Flip, les applications spécifient la structure D3DPRESENT_PARAMETERS , puis passent un pointeur vers cette structure lorsqu’elles appellent l’API IDirect3D9Ex::CreateDeviceEx . Cette section décrit comment les applications qui ciblent Windows 7 utilisent IDirect3D9Ex::CreateDeviceEx pour choisir le modèle flip. Pour plus d’informations sur l’API IDirect3D9Ex::CreateDeviceEx , consultez IDirect3D9Ex::CreateDeviceEx sur MSDN.

Pour des raisons pratiques, la syntaxe de D3DPRESENT_PARAMETERS et IDirect3D9Ex::CreateDeviceEx est répétée ici.

HRESULT CreateDeviceEx(
  UINT Adapter,
  D3DDEVTYPE DeviceType,
  HWND hFocusWindow,
  DWORD BehaviorFlags,
  D3DPRESENT_PARAMETERS* pPresentationParameters,
  D3DDISPLAYMODEEX *pFullscreenDisplayMode,
  IDirect3DDevice9Ex **ppReturnedDeviceInterface
);
typedef struct D3DPRESENT_PARAMETERS {
    UINT BackBufferWidth, BackBufferHeight;
    D3DFORMAT BackBufferFormat;
    UINT BackBufferCount;
    D3DMULTISAMPLE_TYPE MultiSampleType;
    DWORD MultiSampleQuality;
    D3DSWAPEFFECT SwapEffect;
    HWND hDeviceWindow;
    BOOL Windowed;
    BOOL EnableAutoDepthStencil;
    D3DFORMAT AutoDepthStencilFormat;
    DWORD Flags;
    UINT FullScreen_RefreshRateInHz;
    UINT PresentationInterval;
} D3DPRESENT_PARAMETERS, *LPD3DPRESENT_PARAMETERS;

Lorsque vous modifiez les applications Direct3D 9Ex pour Windows 7 afin d’opter pour le modèle flip, vous devez prendre en compte les éléments suivants concernant les membres spécifiés de D3DPRESENT_PARAMETERS :

BackBufferCount

(Windows 7 uniquement)

Lorsque SwapEffect est défini sur le nouveau type d’effet de chaîne d’échange D3DSWAPEFFECT_FLIPEX, le nombre de mémoires tampons d’arrière-mémoire doit être égal ou supérieur à 2, pour éviter une pénalité des performances de l’application en raison de l’attente de la libération de la mémoire tampon Present précédente par DWM.

Lorsque l’application utilise également les statistiques présentes associées à D3DSWAPEFFECT_FLIPEX, nous vous recommandons de définir le nombre de mémoires tampons arrière sur de 2 à 4.

L’utilisation de D3DSWAPEFFECT_FLIPEX sur Windows Vista ou les versions précédentes du système d’exploitation échoue à partir de CreateDeviceEx.

SwapEffect

(Windows 7 uniquement)

Le nouveau type d’effet de chaîne d’échange D3DSWAPEFFECT_FLIPEX désigne le moment où une application adopte le mode flip présent dans DWM. Il permet à l’application d’utiliser plus efficacement la mémoire et l’alimentation, et permet également à l’application de tirer parti des statistiques présentes en plein écran en mode fenêtré. Le comportement de l’application plein écran n’est pas affecté. Si Windowed a la valeur TRUE et SwapEffect a la valeur D3DSWAPEFFECT_FLIPEX, le runtime crée une mémoire tampon d’arrière-plan supplémentaire et fait pivoter le handle qui appartient à la mémoire tampon qui devient la mémoire tampon avant au moment de la présentation.

Indicateurs

(Windows 7 uniquement)

L’indicateur D3DPRESENTFLAG_LOCKABLE_BACKBUFFER ne peut pas être défini si SwapEffect est défini sur le nouveau type d’effet de chaîne d’échange D3DSWAPEFFECT_FLIPEX.

Instructions de conception pour les applications de modèle flip Direct3D 9Ex

Suivez les instructions des sections suivantes pour concevoir vos applications Direct3D 9Ex Flip Model.

Utiliser le mode retournement présent dans un HWND distinct du mode Blt présent

Les applications doivent utiliser le mode inverse Direct3D 9Ex présent dans un HWND qui n’est pas également ciblé par d’autres API, y compris le mode Blt Present Direct3D 9Ex, d’autres versions de Direct3D ou GDI. Le mode Flip Present peut être utilisé pour présenter aux fenêtres enfants ; autrement dit, les applications peuvent utiliser le modèle flip lorsqu’il n’est pas mélangé avec le modèle Blt dans le même HWND, comme illustré dans les illustrations suivantes.

illustration d’une fenêtre parente direct3d et d’une fenêtre enfant gdi, chacune avec son propre hwnd

illustration de la fenêtre parente gdi et d’une fenêtre enfant direct3d, chacune avec son propre hwnd

Étant donné que Blt Model conserve une copie supplémentaire de la surface, GDI et d’autres contenus Direct3D peuvent être ajoutés au même HWND par le biais de mises à jour fragmentaires de Direct3D et GDI. À l’aide du modèle flip, seul le contenu Direct3D 9Ex dans D3DSWAPEFFECT_FLIPEX chaînes d’échange passées à DWM sera visible. Toutes les autres mises à jour de contenu Blt Model Direct3D ou GDI seront ignorées, comme illustré dans les illustrations suivantes.

illustration du texte gdi qui peut ne pas être affiché si le modèle de retournement est utilisé et que le contenu direct3d et gdi sont dans le même hwnd

illustration du contenu direct3d et gdi dans lequel dwm est activé et l’application est en mode fenêtré

Par conséquent, le modèle flip doit être activé pour les mémoires tampons de chaîne d’échange où le modèle Direct3D 9Ex Flip seul s’affiche sur l’ensemble du HWND.

Ne pas utiliser le modèle flip avec ScrollWindow ou ScrollWindowEx de GDI

Certaines applications Direct3D 9Ex utilisent les fonctions ScrollWindow ou ScrollWindowEx de GDI pour mettre à jour le contenu de la fenêtre lorsqu’un événement de défilement utilisateur est déclenché. ScrollWindow et ScrollWindowEx effectuent des blts du contenu de fenêtre à l’écran à mesure qu’une fenêtre fait défiler. Ces fonctions nécessitent également des mises à jour du modèle Blt pour le contenu GDI et Direct3D 9Ex. Les applications qui utilisent l’une ou l’autre fonction n’affichent pas nécessairement le contenu de fenêtre visible qui défile à l’écran lorsque l’application est en mode fenêtré et que DWM est activé. Nous vous recommandons de ne pas utiliser les API ScrollWindow et ScrollWindowEx de GDI dans vos applications, et de redessiner leur contenu à l’écran en réponse au défilement.

Utiliser une chaîne d’échange D3DSWAPEFFECT_FLIPEX par HWND

Les applications qui utilisent flip model ne doivent pas utiliser plusieurs chaînes d’échange de modèle flip ciblant le même HWND.

Synchronisation d’images des applications de modèle flip Direct3D 9Ex

Les statistiques présentes sont des informations de minutage d’images que les applications multimédias utilisent pour synchroniser les flux vidéo et audio et récupérer à partir de problèmes de lecture vidéo. Pour activer la disponibilité des statistiques actuelles, l’application Direct3D 9Ex doit s’assurer que le paramètre BehaviorFlags que l’application transmet à IDirect3D9Ex::CreateDeviceEx contient l’indicateur de comportement de l’appareil D3DCREATE_ENABLE_PRESENTSTATS.

Pour plus de commodité, la syntaxe de IDirect3D9Ex::CreateDeviceEx est répétée ici.

HRESULT CreateDeviceEx(
  UINT Adapter,
  D3DDEVTYPE DeviceType,
  HWND hFocusWindow,
  DWORD BehaviorFlags,
  D3DPRESENT_PARAMETERS* pPresentationParameters,
  D3DDISPLAYMODEEX *pFullscreenDisplayMode,
  IDirect3DDevice9Ex **ppReturnedDeviceInterface
);

Direct3D 9Ex Flip Model ajoute l’indicateur de présentation D3DPRESENT_FORCEIMMEDIATE qui applique le comportement de l’indicateur de présentation D3DPRESENT_INTERVAL_IMMEDIATE . L’application Direct3D 9Ex spécifie ces indicateurs de présentation dans le paramètre dwFlags que l’application transmet à IDirect3DDevice9Ex::P resentEx, comme illustré ici.

HRESULT PresentEx(
  CONST RECT *pSourceRect,
  CONST RECT *pDestRect,
  HWND hDestWindowOverride,
  CONST RGNDATA *pDirtyRegion,
  DWORD dwFlags
);

Lorsque vous modifiez votre application Direct3D 9Ex pour Windows 7, vous devez tenir compte des informations suivantes sur les indicateurs de présentation D3DPRESENT spécifiés :

D3DPRESENT_DONOTFLIP

Cet indicateur est disponible uniquement en mode plein écran ou

(Windows 7 uniquement)

lorsque l’application définit le membre SwapEffect de D3DPRESENT_PARAMETERS pour D3DSWAPEFFECT_FLIPEX dans un appel à CreateDeviceEx.

D3DPRESENT_FORCEIMMEDIATE

(Windows 7 uniquement)

Cet indicateur ne peut être spécifié que si l’application définit le membre SwapEffect de D3DPRESENT_PARAMETERS pour D3DSWAPEFFECT_FLIPEX dans un appel à CreateDeviceEx. L’application peut utiliser cet indicateur pour mettre à jour immédiatement une surface avec plusieurs images ultérieurement dans la file d’attente présente DWM, en ignorant essentiellement les images intermédiaires.

Les applications avec FlipEx fenêtrés peuvent utiliser cet indicateur pour mettre à jour immédiatement une surface avec un cadre qui se trouve ultérieurement dans la file d’attente présente DWM, en ignorant les images intermédiaires. Cela est particulièrement utile pour les applications multimédias qui souhaitent ignorer les images qui ont été détectées comme tardives et présenter les images suivantes au moment de la composition. IDirect3DDevice9Ex::P resentEx retourne une erreur de paramètre non valide si cet indicateur est spécifié de manière incorrecte.

Pour obtenir les informations de statistiques présentes, l’application obtient la structure D3DPRESENTSTATS en appelant l’API IDirect3DSwapChain9Ex::GetPresentStatistics .

La structure D3DPRESENTSTATS contient des statistiques sur les appels IDirect3DDevice9Ex::P resentEx . L’appareil doit être créé à l’aide d’un appel IDirect3D9Ex::CreateDeviceEx avec l’indicateur D3DCREATE_ENABLE_PRESENTSTATS . Sinon, les données retournées par GetPresentStatistics ne sont pas définies. Une chaîne de permutation Direct3D 9Ex avec flip-model fournit des informations de statistiques présentes en mode fenêtré et en mode plein écran.

Pour les chaînes d’échange Direct3D 9Ex avec Blt-Model en mode fenêtré, toutes les valeurs de structure D3DPRESENTSTATS seront de zéro.

Pour les statistiques de présentation FlipEx, GetPresentStatistics retourne D3DERR_PRESENT_STATISTICS_DISJOINT dans les situations suivantes :

  • Premier appel à GetPresentStatistics , qui indique le début d’une séquence
  • Transition DWM de activé à désactivé
  • Changement de mode : transitions en mode fenêtré vers ou à partir du plein écran ou transitions plein écran vers plein écran

Pour plus de commodité, la syntaxe de GetPresentStatistics est répétée ici.

HRESULT GetPresentStatistics(
  D3DPRESENTSTATS * pPresentationStatistics
);

La méthode IDirect3DSwapChain9Ex::GetLastPresentCount retourne le dernier PresentCount, c’est-à-dire l’ID présent du dernier appel Present réussi effectué par un appareil d’affichage associé à la chaîne d’échange. Cet ID present est la valeur du membre PresentCount de la structure D3DPRESENTSTATS . Pour les chaînes d’échange Direct3D 9Ex avec Blt-Model, en mode fenêtré, toutes les valeurs de structure D3DPRESENTSTATS sont des zéros.

Pour plus de commodité, la syntaxe de IDirect3DSwapChain9Ex::GetLastPresentCount est répétée ici.

HRESULT GetLastPresentCount(
  UINT * pLastPresentCount
);

Lorsque vous modifiez votre application Direct3D 9Ex pour Windows 7, vous devez tenir compte des informations suivantes sur la structure D3DPRESENTSTATS :

  • La valeur PresentCount renvoyée par GetLastPresentCount ne se met pas à jour lorsqu’un appel PresentEx avec D3DPRESENT_DONOTWAIT spécifié dans le paramètre dwFlags retourne un échec.
  • Lorsque PresentEx est appelé avec D3DPRESENT_DONOTFLIP, un appel GetPresentStatistics réussit, mais ne retourne pas une structure D3DPRESENTSTATS mise à jour lorsque l’application est en mode fenêtré.
  • PresentRefreshCount et SyncRefreshCount dans D3DPRESENTSTATS :
    • PresentRefreshCount est égal à SyncRefreshCount lorsque l’application présente sur chaque vsync.
    • SyncRefreshCount est obtenu sur l’intervalle vsync lorsque le présent a été envoyé. SyncQPCTime correspond approximativement à l’heure associée à l’intervalle vsync.
typedef struct _D3DPRESENTSTATS {
    UINT PresentCount;
    UINT PresentRefreshCount;
    UINT SyncRefreshCount;
    LARGE_INTEGER SyncQPCTime;
    LARGE_INTEGER SyncGPUTime;
} D3DPRESENTSTATS;

Synchronisation d’images pour les applications fenêtrés lorsque DWM est désactivé

Lorsque DWM est désactivé, les applications fenêtrés s’affichent directement sur l’écran du moniteur sans passer par une chaîne inversée. Dans Windows Vista, il n’existe aucune prise en charge de l’obtention des informations de statistiques de trame pour les applications fenêtrés lorsque DWM est désactivé. Pour gérer une API où les applications n’ont pas besoin d’être compatibles avec DWM, Windows 7 retourne les informations des statistiques de trame pour les applications fenêtrés lorsque DWM est désactivé. Les statistiques de trame retournées lorsque DWM est désactivé sont des estimations uniquement.

Walk-Through d’un modèle de retournement Direct3D 9Ex et d’un exemple de statistiques de présentation

Pour choisir la présentation FlipEx pour l’exemple Direct3D 9Ex

  1. Vérifiez que l’exemple d’application s’exécute sur Windows 7 ou version ultérieure du système d’exploitation.
  2. Définissez le membre SwapEffect de D3DPRESENT_PARAMETERS pour D3DSWAPEFFECT_FLIPEX dans un appel à CreateDeviceEx.
    OSVERSIONINFO version;
    ZeroMemory(&version, sizeof(version));
    version.dwOSVersionInfoSize = sizeof(version);
    GetVersionEx(&version);
    
    // Sample would run only on Win7 or higher
    // Flip Model present and its associated present statistics behavior are only available on Windows 7 or higher operating system
    bool bIsWin7 = (version.dwMajorVersion > 6) || 
        ((version.dwMajorVersion == 6) && (version.dwMinorVersion >= 1));

    if (!bIsWin7)
    {
        MessageBox(NULL, L"This sample requires Windows 7 or higher", NULL, MB_OK);
        return 0;
    }

Pour choisir également l’exemple FlipEx present statistics for Direct3D 9Ex

    // Set up the structure used to create the D3DDevice
    D3DPRESENT_PARAMETERS d3dpp;
    ZeroMemory(&d3dpp, sizeof(d3dpp));

    d3dpp.Windowed = TRUE;
    d3dpp.SwapEffect = D3DSWAPEFFECT_FLIPEX;        // Opts into Flip Model present for D3D9Ex swapchain
    d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8;
    d3dpp.BackBufferWidth = 256;                
    d3dpp.BackBufferHeight = 256;
    d3dpp.BackBufferCount = QUEUE_SIZE;
    d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_ONE;

    g_iWidth = d3dpp.BackBufferWidth;
    g_iHeight = d3dpp.BackBufferHeight;

    // Create the D3DDevice with present statistics enabled - set D3DCREATE_ENABLE_PRESENTSTATS for behaviorFlags parameter
    if(FAILED(g_pD3D->CreateDeviceEx(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
                                      D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_ENABLE_PRESENTSTATS,
                                      &d3dpp, NULL, &g_pd3dDevice)))
    {
        return E_FAIL;
    }

Pour éviter, détecter et récupérer des problèmes

  1. Appels de file d’attente présents : le nombre recommandé de backbuffer est de 2 à 4.

  2. L’exemple Direct3D 9Ex ajoute un backbuffer implicite, la longueur réelle de la file d’attente Présente est le nombre de backbuffers + 1.

  3. Créez la structure de file d’attente Present d’assistance pour stocker tous les ID présents (PresentCount) soumis avec succès et associés, calculés/attendus à PrésentRefreshCount.

  4. Pour détecter l’occurrence d’un problème :

    • Appelez GetPresentStatistics.
    • Obtenez l’ID présent (PresentCount) et le nombre vsync où l’image est affichée (PresentRefreshCount) de l’image dont les statistiques actuelles sont obtenues.
    • Récupérez le PresentRefreshCount attendu (TargetRefresh dans l’exemple de code) associé à l’ID présent.
    • Si PresentRefreshCount réel est plus tard que prévu, un problème s’est produit.
  5. Pour récupérer après un problème :

    • Calculez le nombre d’images à ignorer (g_ variable iImmediates dans l’exemple de code).
    • Présentez les images ignorées avec des D3DPRESENT_FORCEIMMEDIATE d’intervalle.

Considérations relatives à la détection et à la récupération des problèmes

  1. La récupération de glitch prend N (g_iQueueDelay variable dans l’exemple de code) nombre d’appels Présents où N (g_iQueueDelay) est égal à g_iImmediates plus la longueur de la file d’attente Présente, c’est-à-dire :

    • Ignorer les images avec l’intervalle présent D3DPRESENT_FORCEIMMEDIATE, plus
    • Présentes en file d’attente qui doivent être traitées
  2. Définissez une limite à la longueur du problème (GLITCH_RECOVERY_LIMIT dans l’exemple). Si l’exemple d’application ne peut pas se remettre d’un problème trop long (c’est-à-dire 1 seconde ou 60 vsyncs sur un moniteur de 60 Hz), passez par-dessus l’animation intermittente et réinitialisez la file d’attente de l’assistance présente.

VOID Render()
{
    g_pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);

    g_pd3dDevice->BeginScene();

    // Compute new animation parameters for time and frame based animations

    // Time-based is a difference between base and current SyncRefreshCount
    g_aTimeBasedHistory[g_iBlurHistoryCounter] = g_iStartFrame + g_LastSyncRefreshCount - g_SyncRefreshCount;
    // Frame-based is incrementing frame value
    g_aFrameBasedHistory[g_iBlurHistoryCounter] = g_iStartFrame + g_iFrameNumber;

    RenderBlurredMesh(TRUE);    // Time-based
    RenderBlurredMesh(FALSE);   // Frame-based

    g_iBlurHistoryCounter = (g_iBlurHistoryCounter + 1) % BLUR_FRAMES;

    DrawText();

    g_pd3dDevice->EndScene();

    // Performs glitch recovery if glitch was detected
    if (g_bGlitchRecovery && (g_iImmediates > 0))
    {
        // If we have present immediates queued as a result of glitch detected, issue forceimmediate Presents for glitch recovery 
        g_pd3dDevice->PresentEx(NULL, NULL, NULL, NULL, D3DPRESENT_FORCEIMMEDIATE);
        g_iImmediates--;
        g_iShowingGlitchRecovery = MESSAGE_SHOW;
    }
    // Otherwise, Present normally
    else
    {
        g_pd3dDevice->PresentEx(NULL, NULL, NULL, NULL, 0);
    }

    // Add to helper Present queue: PresentID + expected present refresh count of last submitted Present
    UINT PresentCount;
    g_pd3dSwapChain->GetLastPresentCount(&PresentCount);
    g_Queue.QueueFrame(PresentCount, g_TargetRefreshCount);
    
    // QueueDelay specifies # Present calls to be processed before another glitch recovery attempt
    if (g_iQueueDelay > 0)
    {
        g_iQueueDelay--;
    }

    if (g_bGlitchRecovery)
    {
        // Additional DONOTFLIP presents for frame conversions, which basically follows the same logic, but without rendering
        for (DWORD i = 0; i < g_iDoNotFlipNum; i++)
        {
            if (g_TargetRefreshCount != -1)
            {
                g_TargetRefreshCount++;
                g_iFrameNumber++;
                g_aTimeBasedHistory[g_iBlurHistoryCounter] = g_iStartFrame + g_LastSyncRefreshCount - g_SyncRefreshCount;
                g_aFrameBasedHistory[g_iBlurHistoryCounter] = g_iStartFrame + g_iFrameNumber;
                g_iBlurHistoryCounter = (g_iBlurHistoryCounter + 1) % BLUR_FRAMES;
            }
            
            if (g_iImmediates > 0)
            {
                g_pd3dDevice->PresentEx(NULL, NULL, NULL, NULL, D3DPRESENT_FORCEIMMEDIATE | D3DPRESENT_DONOTFLIP);
                g_iImmediates--;
            }
            else
            {
                g_pd3dDevice->PresentEx(NULL, NULL, NULL, NULL, D3DPRESENT_DONOTFLIP);
            }
            UINT PresentCount;
            g_pd3dSwapChain->GetLastPresentCount(&PresentCount);
            g_Queue.QueueFrame(PresentCount, g_TargetRefreshCount);

            if (g_iQueueDelay > 0)
            {
                g_iQueueDelay--;
            }
        }
    }

    // Check Present Stats info for glitch detection 
    D3DPRESENTSTATS PresentStats;

    // Obtain present statistics information for successfully displayed presents
    HRESULT hr = g_pd3dSwapChain->GetPresentStats(&PresentStats);

    if (SUCCEEDED(hr))
    {
        // Time-based update
        g_LastSyncRefreshCount = PresentStats.SyncRefreshCount;
        if ((g_SyncRefreshCount == -1) && (PresentStats.PresentCount != 0))
        {
            // First time SyncRefreshCount is reported, use it as base
            g_SyncRefreshCount = PresentStats.SyncRefreshCount;
        }

        // Fetch frame from the queue...
        UINT TargetRefresh = g_Queue.DequeueFrame(PresentStats.PresentCount);

        // If PresentStats returned a really old frame that we no longer have in the queue, just don't do any glitch detection
        if (TargetRefresh == FRAME_NOT_FOUND)
            return;

        if (g_TargetRefreshCount == -1)
        {
            // This is first time issued frame is confirmed by present stats, so fill target refresh count for all frames in the queue
            g_TargetRefreshCount = g_Queue.FillRefreshCounts(PresentStats.PresentCount, g_SyncRefreshCount);
        } 
        else
        {
            g_TargetRefreshCount++;
            g_iFrameNumber++;

            // To determine whether we're glitching, see if our estimated refresh count is confirmed
            // if the frame is displayed later than the expected vsync count
            if (TargetRefresh < PresentStats.PresentRefreshCount)
            {
                // then, glitch is detected!

                // If glitch is too big, don't bother recovering from it, just jump animation
                if ((PresentStats.PresentRefreshCount - TargetRefresh) > GLITCH_RECOVERY_LIMIT)
                {
                    g_iStartFrame += PresentStats.SyncRefreshCount - g_SyncRefreshCount;
                    ResetAnimation();
                    if (g_bGlitchRecovery)
                        g_iGlitchesInaRow++;    
                } 
                // Otherwise, compute number of immediate presents to recover from it -- if we?re not still trying to recover from another glitch
                else if (g_iQueueDelay == 0)
                {
                      // skip frames to catch up to expected refresh count
                    g_iImmediates = PresentStats.PresentRefreshCount - TargetRefresh;
                    // QueueDelay specifies # Present calls before another glitch recovery 
                    g_iQueueDelay = g_iImmediates + QUEUE_SIZE;
                    if (g_bGlitchRecovery)
                        g_iGlitchesInaRow++;
                }
            }
            else
            {
                // No glitch, reset glitch count
                g_iGlitchesInaRow = 0;
            }
        }
    }
    else if (hr == D3DERR_PRESENT_STATISTICS_DISJOINT)
    {
        // D3DERR_PRESENT_STATISTICS_DISJOINT means measurements should be started from the scratch (could be caused by mode change or DWM on/off transition)
        ResetAnimation();
    }

    // If we got too many glitches in a row, reduce framerate conversion factor (that is, render less frames)
    if (g_iGlitchesInaRow == FRAMECONVERSION_GLITCH_LIMIT)
    {
        if (g_iDoNotFlipNum < FRAMECONVERSION_LIMIT)
        {
            g_iDoNotFlipNum++;
        }
        g_iGlitchesInaRow = 0;
        g_iShowingDoNotFlipBump = MESSAGE_SHOW;
    }
}

Exemple de scénario

  • L’illustration suivante montre une application avec un nombre de backbuffers de 4. La longueur réelle de la file d’attente Present est donc de 5.

    illustration d’une application rendue d’images et d’une file d’attente présente

    L’image A est ciblée pour être affichée à l’écran sur le nombre d’intervalles de synchronisation de 1, mais il a été détecté qu’elle s’affichait sur le nombre d’intervalles de synchronisation de 4. Par conséquent, un problème s’est produit. Les 3 images suivantes sont présentées avec D3DPRESENT_INTERVAL_FORCEIMMEDIATE. Le problème doit prendre un total de 8 appels présents avant d’être récupéré. L’image suivante s’affiche en fonction de son nombre d’intervalles de synchronisation ciblés.

Résumé des recommandations de programmation pour la synchronisation d’images

  • Créez une liste de sauvegarde de tous les ID LastPresentCount (obtenus via GetLastPresentCount) et l’estimation de PresentRefreshCount associée de tous les cadeaux envoyés.

    Notes

    Lorsque l’application appelle PresentEx avec D3DPRESENT_DONOTFLIP, l’appel GetPresentStatistics réussit, mais ne retourne pas une structure D3DPRESENTSTATS mise à jour lorsque l’application est en mode fenêtré.

  • Appelez GetPresentStatistics pour obtenir le PrésentRefreshCount réel associé à chaque ID présent des images affichées, afin de vous assurer que l’application gère les retours d’échec de l’appel.

  • Si PresentRefreshCount réel est plus tard que l’estimation de PresentRefreshCount, un problème est détecté. Compensez en soumettant des images en retard' Présent avec D3DPRESENT_FORCEIMMEDIATE.

  • Lorsqu’une image est présentée en retard dans la file d’attente Présente, toutes les images en file d’attente suivantes sont présentées en retard. D3DPRESENT_FORCEIMMEDIATE corrige uniquement l’image suivante à présenter après tous les cadres mis en file d’attente. Par conséquent, le nombre de files d’attente présentes ou de backbuffer ne doit pas être trop long. Il y a donc moins de problèmes d’image à rattraper. Le nombre optimal de backbuffers est de 2 à 4.

  • Si l’estimation de PresentRefreshCount est postérieure à l’actuel PresentRefreshCount, une limitation DWM peut s’être produite. Les solutions suivantes sont possibles :

    • réduction de la longueur de la file d’attente présente
    • réduire les besoins en mémoire GPU avec tout autre moyen en plus de réduire la longueur de la file d’attente actuelle (c’est-à-dire, la diminution de la qualité, la suppression des effets, et ainsi de suite)
    • spécification de DwmEnableMMCSS pour empêcher la limitation DWM en général
  • Vérifiez les performances des fonctionnalités d’affichage et des statistiques d’image de l’application dans les scénarios suivants :

    • avec DWM activé et désactivé
    • modes exclusifs et fenêtrés en plein écran
    • matériel à faible capacité
  • Lorsque les applications ne peuvent pas récupérer à partir d’un grand nombre d’images glitchées avec D3DPRESENT_FORCEIMMEDIATE Présent, elles peuvent potentiellement effectuer les opérations suivantes :

    • réduire l’utilisation du processeur et du GPU en effectuant un rendu avec moins de charge de travail.
    • dans le cas du décodage vidéo, décodez plus rapidement en réduisant la qualité et, par conséquent, l’utilisation du processeur et du GPU.

Conclusion sur les améliorations de Direct3D 9Ex

Sur Windows 7, les applications qui affichent la fréquence d’images vidéo ou de jauge pendant la présentation peuvent opter pour le modèle inversé. Les améliorations actuelles des statistiques associées à Flip Model Direct3D 9Ex peuvent bénéficier aux applications qui synchronisent la présentation par fréquence d’images, avec des commentaires en temps réel pour la détection et la récupération des problèmes. Les développeurs qui adoptent le modèle flip direct3D 9Ex doivent prendre en compte le ciblage d’un HWND distinct du contenu GDI et de la synchronisation de fréquence d’images. Reportez-vous aux détails de cette rubrique et à la documentation MSDN. Pour obtenir une documentation supplémentaire, consultez Centre de développement DirectX sur MSDN.

À vous d’agir !

Nous vous encourageons à utiliser direct3D 9Ex Flip Model et ses statistiques actuelles sur Windows 7 lorsque vous créez des applications qui tentent de synchroniser la fréquence d’images de présentation ou de récupérer à partir de problèmes d’affichage.

Centre de développement DirectX sur MSDN