Améliorations de Direct3D 9Ex

Cette rubrique décrit la prise en charge ajoutée de Windows 7 pour Flip Mode Present et ses statistiques présentes associées dans Direct3D 9Ex et Desktop Window Manager. Les applications cibles incluent des applications de présentation basées sur la vidéo ou la fréquence d’images. Les applications qui utilisent Le mode Flip Direct3D 9Ex Réduisent la charge des ressources système lorsque DWM est activé. Les améliorations des statistiques associées au mode Flip Present permettent aux applications Direct3D 9Ex de mieux contrôler le taux de présentation en fournissant des mécanismes de commentaires 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élioration de 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 met efficacement les images rendues sur Windows 7 Desktop Window Manager (DWM) pour la composition. À compter de Windows Vista, DWM compose l’ensemble du Bureau. Lorsque DWM est activé, les applications en mode fenêtre présentent leur contenu sur le Bureau à l’aide d’une méthode appelée Blt Mode Present to DWM (ou Blt Model). Avec Blt Model, DWM conserve une copie de la surface rendue par 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 Présent sur DWM (ou Modèle Flip) 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être et DWM. Outre l’enregistrement des ressources, Flip Model prend en charge les statistiques présentes améliorées.

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

Dans Windows 7, les applications Direct3D 9Ex qui adoptent flip model doivent utiliser des API D3D9Ex pour obtenir des statistiques présentes. Lorsque DWM est activé, le mode fenêtre et les applications Direct3D 9Ex en mode exclusif plein écran peuvent s’attendre à ce que les mêmes informations de statistiques présentent les mêmes informations de statistiques lors de l’utilisation du modèle flip. Direct3D 9Ex Flip Model présente des statistiques permettent aux applications d’interroger des statistiques présentes en temps réel, plutôt qu’après l’affichage de l’image sur l’écran; les mêmes informations de statistiques actuelles sont disponibles pour les applications en mode fenêtre Flip-Model activées en tant qu’applications en 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.

Direct3D 9Ex Flip Model doit être utilisé par de nouvelles applications de présentation basées sur la vidéo ou 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. Ces applications qui utilisent des informations de statistiques présentes bénéficieront de l’utilisation du modèle Flip activé présente des améliorations des statistiques.

Présentation en mode Flip Direct3D 9EX

Les améliorations des performances du mode Flip Direct3D 9Ex Sont importantes sur le système lorsque DWM est activé et quand l’application est en mode fenêtre, plutôt que en mode exclusif plein écran. Le tableau et l’illustration suivants montrent une comparaison simplifiée des utilisations de bande passante mémoire et des lectures et écritures de systèmes d’applications fenêtres qui choisissent Flip Model par rapport au modèle Blt d’utilisation par défaut.

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

illustration of a comparison of the blt model and the flip model

Le mode Flip Présente réduit l’utilisation de la mémoire système en réduisant le nombre de lectures et d’écritures par le runtime Direct3D de la composition d’images fenêtres par DWM. Cela réduit la consommation d’alimentation 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être ou en mode exclusif plein écran.

Modèle de programmation et API

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

Flip Mode Present implique que l’application puisse tirer parti des mécanismes de commentaires de statistiques et de correction en temps réel lorsque DWM est activé. Toutefois, les applications qui utilisent le mode Flip Mode Présent doivent être conscientes des limitations lorsqu’elles utilisent le rendu de l’API GDI simultanée.

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

Comment choisir le modèle d’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 plus de commodité, 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 des applications Direct3D 9Ex pour Windows 7 pour choisir le modèle flip, vous devez prendre en compte les éléments suivants sur 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 back doit être égal ou supérieur à 2 pour empêcher une pénalité de performances d’application suite à l’attente de la mise en mémoire tampon Présente précédente à libérer par DWM.

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

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

SwapEffect

(Windows 7 uniquement)

Le nouveau type d’effet de chaîne d’échange D3DSWAPEFFECT_FLIPEX désigne lorsqu’une application adopte le mode Flip Présent sur DWM. Elle 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 mode fenêtres. Le comportement de l’application en plein écran n’est pas affecté. Si Windowed est défini sur TRUE et SwapEffect est défini sur D3DSWAPEFFECT_FLIPEX, le runtime crée une mémoire tampon supplémentaire et fait pivoter le handle qui appartient à la mémoire tampon qui devient la mémoire tampon frontale 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

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

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

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

illustration of direct3d parent window and a gdi child window, each with its own hwnd

illustration of gdi parent window and a direct3d child window, each with its own 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 via des mises à jour fragmentaires à partir de Direct3D et de 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 of gdi text that might not be displayed if flip model is used and direct3d and gdi content are in the same hwnd

illustration of direct3d and gdi content in which dwm is enabled and the application is in windowed mode

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

N’utilisez pas de 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 de contenu de fenêtre sur l’écran en tant que fenêtre est défilementée. Ces fonctions nécessitent également des mises à jour de 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 la fenêtre visible faisant défiler l’écran lorsque l’application est en mode fenêtre 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 sur l’écran en réponse au défilement.

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

Les applications qui utilisent le modèle Flip 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 des 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 prendre en compte les 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 sur D3DSWAPEFFECT_FLIPEX dans un appel à CreateDeviceEx.

D3DPRESENT_FORCEIMMEDIATE

(Windows 7 uniquement)

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

Les applications FlipEx avec fenêtre peuvent utiliser cet indicateur pour mettre à jour immédiatement une surface avec un cadre qui se trouve plus loin dans la file d’attente DWM Present, en ignorant les images intermédiaires. Cela est particulièrement utile pour les applications multimédias qui souhaitent ignorer les images détectées comme tardives et présentes ultérieures 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 des informations de statistiques, 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 d’échange Direct3D 9Ex compatible avec le modèle flip fournit des informations de statistiques présentes en mode fenêtre et plein écran.

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

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

  • Premier appel à GetPresentStatistics jamais , qui indique le début d’une séquence
  • Transition d’un DWM d’un à l’autre
  • Modification du mode : mode fenêtre vers ou à partir de l’écran plein ou plein écran vers les transitions en 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 Présent 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 compatibles avec Blt-Model, tandis qu’en mode fenêtre, toutes les valeurs de structure D3DPRESENTSTATS seront nulles.

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 prendre en compte les informations suivantes sur la structure D3DPRESENTSTATS :

  • La valeur PresentCount retournée par GetLastPresentCount ne se met pas à jour lorsqu’un appel PresentEx avec D3DPRESENT_DONOTWAIT spécifié dans le paramètre dwFlags retourne l’échec.
  • Lorsque PresentEx est appelé avec D3DPRESENT_DONOTFLIP, un appel GetPresentStatistics réussit, mais ne retourne pas de structure D3DPRESENTSTATS mise à jour lorsque l’application est en mode fenêtre.
  • PresentRefreshCount et SyncRefreshCount dans D3DPRESENTSTATS :
    • PresentRefreshCount est égal à SyncRefreshCount lorsque l’application est présente sur chaque vsync.
    • SyncRefreshCount est obtenu sur l’intervalle vsync lorsque le présent a été soumis, SyncQPCTime est approximativement le temps associé à 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êtres lorsque DWM est désactivé

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

Walk-Through d’un modèle d’flip Direct3D 9Ex et présente des exemples de statistiques

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

  1. Vérifiez que l’exemple d’application s’exécute sur Windows version du système d’exploitation 7 ou ultérieure.
  2. Définissez le membre SwapEffect de D3DPRESENT_PARAMETERS sur 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 associé à 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 à partir de problèmes

  1. File d’attente Présente les appels : le nombre de backbuffer recommandés 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 une structure de file d’attente Present d’assistance pour stocker tous les ID présents soumis avec succès (PresentCount) et associés, calculés/attendus PresentRefreshCount.

  4. Pour détecter l’occurrence de glitch :

    • Appelez GetPresentStatistics.
    • Obtenez l’ID Présent (PresentCount) et le nombre vsync où le cadre est affiché (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 glitch s’est produit.
  5. Pour récupérer à partir d’un glitch :

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

Considérations relatives à la détection et à la récupération de glitch

  1. La récupération glitch prend N (variable g_iQueueDelay 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 Present, autrement dit :

    • Ignorer les images avec l’intervalle Présent D3DPRESENT_FORCEIMMEDIATE, ainsi que
    • Présenté en file d’attente qui doit être traité
  2. Définissez une limite à la longueur du glitch (GLITCH_RECOVERY_LIMIT dans l’exemple). Si l’exemple d’application ne peut pas récupérer à partir d’un glitch trop long (autrement dit, 1 seconde ou 60 vsyncs sur un moniteur de 60Hz), passez à l’animation intermittente et réinitialisez la file d’attente d’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 le nombre de backbuffers de 4. La longueur réelle de la file d’attente Présente est donc 5.

    illustration of an applicas rendered frames and present queue

    Le cadre A est ciblé pour passer à l’écran sur le nombre d’intervalles de synchronisation de 1, mais a été détecté qu’il a été affiché sur le nombre d’intervalles de synchronisation de 4. Par conséquent, un glitch s’est produit. Les 3 images suivantes sont présentées avec D3DPRESENT_INTERVAL_FORCEIMMEDIATE. Le glitch doit prendre un total de 8 appels présents avant sa récupération . Le cadre suivant s’affiche conformément au nombre d’intervalles de synchronisation ciblé.

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 associées PresentRefreshCount de tous les objets Présentés soumis.

    Notes

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

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

  • Si presentRefreshCount réel est supérieur à l’estimation de PresentRefreshCount, un glitch est détecté. Compenser en soumettant des cadres en retard avec D3DPRESENT_FORCEIMMEDIATE.

  • Lorsqu’une image est présentée en retard dans la file d’attente Present, toutes les images mises en file d’attente suivantes sont présentées en retard. D3DPRESENT_FORCEIMMEDIATE corrigera uniquement le cadre suivant à présenter après tous les cadres mis en file d’attente. Par conséquent, la file d’attente ou le nombre de backbuffers présents ne doivent pas être trop longs. Il n’y a donc pas de problèmes d’images moins nombreux à rattraper. Le nombre optimal de backbuffers est de 2 à 4.

  • Si l’estimation de PresentRefreshCount est ultérieure à la valeur Actuelle PresentRefreshCount, la limitation DWM peut s’être produite. Les solutions suivantes sont possibles :

    • réduction de la longueur de file d’attente Présente
    • réduction des besoins en mémoire GPU avec tout autre moyen en plus de réduire la longueur de file d’attente actuelle (autrement dit, réduire la qualité, supprimer les effets, et ainsi de suite)
    • spécification de DwmEnableMMCSS pour empêcher la limitation DWM en général
  • Vérifiez la fonctionnalité d’affichage des applications et les performances des statistiques d’images dans les scénarios suivants :

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

    • réduisez l’utilisation du processeur et du GPU en rendant 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 Flip. 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 de glitch. Les développeurs qui adoptent le modèle Flip Direct3D 9Ex doivent cibler un HWND distinct du contenu GDI et de la synchronisation de fréquence d’images en compte. Reportez-vous aux détails de cette rubrique et de la documentation MSDN. Pour obtenir de la documentation supplémentaire, consultez Le Centre de développement DirectX sur MSDN.

À vous d’agir !

Nous vous encourageons à utiliser Direct3D 9Ex Flip Model et ses statistiques présentes 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 des glitches d’affichage.

Centre de développement DirectX sur MSDN