Miglioramenti di Direct3D 9Ex

Questo argomento descrive il supporto aggiunto di Windows 7 per Flip Mode Present e le statistiche presenti associate in Direct3D 9Ex e Desktop Window Manager. Le applicazioni di destinazione includono applicazioni di presentazione basate su video o fotogrammi. Le applicazioni che usano la modalità Flip Direct3D 9Ex Presentano riducono il carico delle risorse di sistema quando DWM è abilitato. Presenta miglioramenti delle statistiche associati alla modalità Flip Present consente alle applicazioni Direct3D 9Ex di controllare meglio la frequenza di presentazione fornendo meccanismi di feedback e correzione in tempo reale. Sono inclusi spiegazioni dettagliate e puntatori alle risorse di esempio.

Questo argomento include le sezioni seguenti.

Informazioni migliorate su Direct3D 9Ex per Windows 7

La presentazione in modalità flip di Direct3D 9Ex è una modalità migliorata di presentazione delle immagini in Direct3D 9Ex che distribuisce in modo efficiente le immagini sottoposte a rendering a Windows 7 Desktop Window Manager (DWM) per la composizione. A partire da Windows Vista, DWM compone l'intero desktop. Quando DWM è abilitato, le applicazioni in modalità finestra presentano il contenuto sul desktop usando un metodo denominato Blt Mode Present to DWM (o Blt Model). Con il modello Blt, DWM mantiene una copia della superficie di rendering Direct3D 9Ex per la composizione desktop. Quando l'applicazione viene aggiornata, il nuovo contenuto viene copiato nella superficie DWM tramite un blt. Per le applicazioni che contengono contenuto Direct3D e GDI, i dati GDI vengono copiati anche nella superficie DWM.

Disponibile in Windows 7, Flip Mode Present to DWM (or Flip Model) è un nuovo metodo di presentazione che consente essenzialmente il passaggio di handle di superfici dell'applicazione tra applicazioni in modalità finestra e DWM. Oltre a salvare le risorse, Flip Model supporta statistiche presenti avanzate.

Le statistiche presenti sono informazioni sulla tempistica dei fotogrammi che le applicazioni possono usare per sincronizzare i flussi video e audio e recuperare da errori di riproduzione video. Le informazioni sulla tempistica dei fotogrammi nelle statistiche presenti consentono alle applicazioni di regolare la frequenza di presentazione dei fotogrammi video per una presentazione più fluida. In Windows Vista, dove DWM mantiene una copia corrispondente della superficie di fotogramma per la composizione desktop, le applicazioni possono usare le statistiche presenti fornite da DWM. Questo metodo di recupero delle statistiche presenti sarà comunque disponibile in Windows 7 per le applicazioni esistenti.

In Windows 7, le applicazioni basate su Direct3D 9Ex che adottano Il modello Flip devono usare le API D3D9Ex per ottenere statistiche presenti. Quando DWM è abilitato, le applicazioni direct3D 9Ex in modalità esclusiva a schermo intero e in modalità finestra possono prevedere le stesse informazioni sulle statistiche presenti quando si usa Flip Model. Direct3D 9Ex Flip Model presenta statistiche che consentono alle applicazioni di eseguire query per visualizzare le statistiche in tempo reale, anziché dopo che il fotogramma è stato visualizzato sullo schermo; le stesse informazioni presenti sulle statistiche sono disponibili per le applicazioni abilitate per flip model in modalità finestra come applicazioni a schermo intero; un flag aggiunto nelle API D3D9Ex consente alle applicazioni Flip Model di eliminare in modo efficace i fotogrammi tardivi in fase di presentazione.

Direct3D 9Ex Flip Model deve essere usato da nuove applicazioni di presentazione basate su video o fotogrammi destinate a Windows 7. A causa della sincronizzazione tra DWM e il runtime Direct3D 9Ex, le applicazioni che usano Flip Model devono specificare tra 2 e 4 backbuffer per garantire una presentazione uniforme. Le applicazioni che usano le informazioni di presentazione delle statistiche trarranno vantaggio dall'uso di Flip Model abilitato per presentare miglioramenti alle statistiche.

Presentazione in modalità flip Direct3D 9EX

I miglioramenti delle prestazioni di Direct3D 9Ex Flip Mode Present sono significativi nel sistema quando DWM è attivato e quando l'applicazione è in modalità finestra, anziché in modalità esclusiva a schermo intero. La tabella e l'illustrazione seguenti illustrano un confronto semplificato tra utilizzo della larghezza di banda della memoria e letture e scritture di sistema delle applicazioni finestra che scelgono Flip Model rispetto al modello Blt di utilizzo predefinito.

Modalità Blt presente in DWM Modalità flip D3D9Ex presente in DWM
1. L'applicazione aggiorna il frame (scrittura)
1. L'applicazione aggiorna il frame (scrittura)
2. Il runtime Direct3D copia il contenuto della superficie in una superficie di reindirizzamento DWM (lettura, scrittura)
2. Il runtime Direct3D passa la superficie dell'applicazione a DWM
3. Al termine della copia della superficie condivisa, DWM esegue il rendering della superficie dell'applicazione sullo schermo (Lettura, Scrittura)
3. DWM esegue il rendering della superficie dell'applicazione sullo schermo (lettura, scrittura)

illustrazione di un confronto tra il modello blt e il modello flip

Flip Mode Present riduce l'utilizzo della memoria di sistema riducendo il numero di letture e scritture dal runtime Direct3D per la composizione della cornice finestrata da DWM. Ciò riduce il consumo di energia del sistema e l'utilizzo complessivo della memoria.

Le applicazioni possono sfruttare la modalità flip Direct3D 9Ex presenta miglioramenti delle statistiche quando DWM è attivo, indipendentemente dal fatto che l'applicazione sia in modalità finestra o in modalità esclusiva a schermo intero.

Modello di programmazione e API

Le nuove applicazioni video o di valutazione della frequenza dei fotogrammi che usano LE API Direct3D 9Ex in Windows 7 possono sfruttare i vantaggi della memoria e del risparmio di potenza e della presentazione migliorata offerta dalla modalità Flip presente quando è in esecuzione in Windows 7. Durante l'esecuzione nelle versioni precedenti di Windows, il runtime Direct3D usa per impostazione predefinita l'applicazione come Blt Mode Present.

Flip Mode Present implica che l'applicazione può sfruttare i meccanismi di feedback e correzione delle statistiche presenti in tempo reale quando DWM è attivo. Tuttavia, le applicazioni che usano Flip Mode Present devono essere consapevoli delle limitazioni quando usano il rendering simultaneo dell'API GDI.

È possibile modificare le applicazioni esistenti per sfruttare la modalità Flip Present, con gli stessi vantaggi e avvertenze delle nuove applicazioni sviluppate.

Come acconsentire esplicitamente al modello Flip Direct3D 9Ex

Le applicazioni Direct3D 9Ex destinate a Windows 7 possono acconsentire esplicitamente al modello Flip creando la catena di scambio con il valore di enumerazione D3DSWAPEFFECT_FLIPEX. Per acconsentire esplicitamente al modello Flip, le applicazioni specificano la struttura D3DPRESENT_PARAMETERS e quindi passano un puntatore a questa struttura quando chiamano l'API IDirect3D9Ex::CreateDeviceEx. Questa sezione descrive come le applicazioni destinate a Windows 7 usano IDirect3D9Ex::CreateDeviceEx per acconsentire esplicitamente al modello Flip. Per altre informazioni sull'API IDirect3D9Ex::CreateDeviceEx , vedere IDirect3D9Ex::CreateDeviceEx su MSDN.

Per praticità, la sintassi di D3DPRESENT_PARAMETERS e IDirect3D9Ex::CreateDeviceEx viene ripetuta qui.

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;

Quando modifichi le applicazioni Direct3D 9Ex per Windows 7 per acconsentire esplicitamente al modello Flip, devi considerare gli elementi seguenti relativi ai membri specificati di D3DPRESENT_PARAMETERS:

BackBufferCount

(Solo Windows 7)

Quando SwapEffect è impostato sul nuovo tipo di effetto della catena di scambio D3DSWAPEFFECT_FLIPEX, il conteggio del buffer nascosto deve essere uguale o maggiore di 2, per evitare una penalità delle prestazioni dell'applicazione in seguito all'attesa del buffer Presente precedente da rilasciare da DWM.

Quando l'applicazione usa anche statistiche associate a D3DSWAPEFFECT_FLIPEX, è consigliabile impostare il numero di buffer nascosto su da 2 a 4.

L'uso di D3DSWAPEFFECT_FLIPEX in Windows Vista o versioni precedenti del sistema operativo restituirà un errore da CreateDeviceEx.

SwapEffect

(Solo Windows 7)

Il nuovo tipo di effetto della catena di scambio D3DSWAPEFFECT_FLIPEX designa quando un'applicazione adotta la modalità flip present a DWM. Consente all'applicazione un utilizzo più efficiente della memoria e dell'alimentazione e consente anche all'applicazione di sfruttare le statistiche presenti a schermo intero in modalità finestra. Il comportamento dell'applicazione a schermo intero non è interessato. Se Windowed è impostato su TRUE e SwapEffect è impostato su D3DSWAPEFFECT_FLIPEX, il runtime crea un buffer nascosto aggiuntivo e ruota qualsiasi handle appartenga al buffer che diventa il buffer anteriore in fase di presentazione.

Flag

(Solo Windows 7)

Impossibile impostare il flag D3DPRESENTFLAG_LOCKABLE_BACKBUFFER se SwapEffect è impostato sul nuovo tipo di effetto della catena di scambio D3DSWAPEFFECT_FLIPEX .

Linee guida di progettazione per applicazioni modello Direct3D 9Ex Flip

Usare le linee guida nelle sezioni seguenti per progettare le applicazioni Direct3D 9Ex Flip Model.

Usa la modalità flip presente in un HWND separato dalla modalità Blt presente

Le applicazioni devono usare la modalità flip Direct3D 9Ex presente in un HWND che non è destinato anche ad altre API, tra cui la modalità Blt Presente Direct3D 9Ex, altre versioni di Direct3D o GDI. Flip Mode Present può essere usato per presentare alle finestre figlio; vale a dire, le applicazioni possono usare Flip Model quando non è mescolato con il modello Blt nello stesso HWND, come illustrato nelle illustrazioni seguenti.

illustrazione della finestra padre direct3d e di una finestra figlio gdi, ognuna con il proprio hwnd

illustrazione della finestra padre gdi e di una finestra figlio direct3d, ognuna con il proprio oggetto hwnd

Poiché Blt Model mantiene una copia aggiuntiva della superficie, GDI e altri contenuti Direct3D possono essere aggiunti allo stesso HWND tramite aggiornamenti a fasi da Direct3D e GDI. Usando il modello flip, solo il contenuto Direct3D 9Ex in D3DSWAPEFFECT_FLIPEX catene di scambio passate a DWM sarà visibile. Tutti gli altri aggiornamenti del contenuto Blt Model Direct3D o GDI verranno ignorati, come illustrato nelle illustrazioni seguenti.

illustrazione del testo gdi che potrebbe non essere visualizzato se viene usato il modello flip e il contenuto direct3d e gdi si trovano nello stesso hwnd

illustrazione del contenuto direct3d e gdi in cui dwm è abilitato e l'applicazione è in modalità finestra

Di conseguenza, il modello Flip deve essere abilitato per le superfici dei buffer della catena di scambio in cui il modello Flip Direct3D 9Ex esegue il rendering dell'intero HWND.

Non usare il modello flip con scrollWindow o ScrollWindowEx di GDI

Alcune applicazioni Direct3D 9Ex usano le funzioni ScrollWindow o ScrollWindowEx di GDI per aggiornare il contenuto della finestra quando viene attivato un evento di scorrimento utente. ScrollWindow e ScrollWindowEx eseguono blts del contenuto della finestra sullo schermo quando viene eseguito lo scorrimento di una finestra. Queste funzioni richiedono anche aggiornamenti del modello Blt per il contenuto GDI e Direct3D 9Ex. Le applicazioni che usano una delle due funzioni non visualizzeranno necessariamente il contenuto della finestra visibile sullo schermo quando l'applicazione è in modalità finestra e DWM è abilitato. È consigliabile non usare le API ScrollWindow e ScrollWindowEx di GDI nelle applicazioni e ridisegnare il contenuto sullo schermo in risposta allo scorrimento.

Usare una catena di scambio D3DSWAPEFFECT_FLIPEX per HWND

Le applicazioni che usano Flip Model non devono usare più catene di scambio di modelli Flip destinate allo stesso HWND.

Sincronizzazione dei fotogrammi delle applicazioni modello Direct3D 9Ex Flip

Le statistiche presenti sono informazioni sulla tempistica dei fotogrammi usate dalle applicazioni multimediali per sincronizzare i flussi video e audio e recuperare da errori di riproduzione video. Per abilitare la disponibilità delle statistiche, l'applicazione Direct3D 9Ex deve assicurarsi che il parametro BehaviorFlags passato all'applicazione a IDirect3D9Ex::CreateDeviceEx contenga il flag di comportamento del dispositivo D3DCREATE_ENABLE_PRESENTSTATS.

Per praticità, la sintassi di IDirect3D9Ex::CreateDeviceEx viene ripetuta qui.

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

Direct3D 9Ex Flip Model aggiunge il flag di presentazione D3DPRESENT_FORCEIMMEDIATE che applica il comportamento del flag di presentazione D3DPRESENT_INTERVAL_IMMEDIATE . L'applicazione Direct3D 9Ex specifica questi flag di presentazione nel parametro dwFlags che l'applicazione passa a IDirect3DDevice9Ex::P resentEx, come illustrato di seguito.

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

Quando modifichi l'applicazione Direct3D 9Ex per Windows 7, devi considerare le informazioni seguenti sui flag di presentazione D3DPRESENT specificati:

D3DPRESENT_DONOTFLIP

Questo flag è disponibile solo in modalità schermo intero o

(Solo Windows 7)

quando l'applicazione imposta il membro SwapEffect di D3DPRESENT_PARAMETERS su D3DSWAPEFFECT_FLIPEX in una chiamata a CreateDeviceEx.

D3DPRESENT_FORCEIMMEDIATE

(Solo Windows 7)

Questo flag può essere specificato solo se l'applicazione imposta il membro SwapEffect di D3DPRESENT_PARAMETERS su D3DSWAPEFFECT_FLIPEX in una chiamata a CreateDeviceEx. L'applicazione può usare questo flag per aggiornare immediatamente una superficie con diversi fotogrammi più avanti nella coda DWM Present, essenzialmente ignorando i fotogrammi intermedi.

Le applicazioni abilitate per FlipEx con finestra possono usare questo flag per aggiornare immediatamente una superficie con un frame più avanti nella coda DWM Present, ignorando i fotogrammi intermedi. Ciò è particolarmente utile per le applicazioni multimediali che vogliono eliminare i fotogrammi rilevati in ritardo e presentare fotogrammi successivi in fase di composizione. IDirect3DDevice9Ex::P resentEx restituisce un errore di parametro non valido se questo flag è specificato in modo non corretto.

Per ottenere informazioni sulle statistiche presenti, l'applicazione ottiene la struttura D3DPRESENTSTATS chiamando l'API IDirect3DSwapChain9Ex::GetPresentStatistics.

La struttura D3DPRESENTSTATS contiene statistiche sulle chiamate IDirect3DDevice9Ex::P resentEx. Il dispositivo deve essere creato usando una chiamata IDirect3D9Ex::CreateDeviceEx con il flag D3DCREATE_ENABLE_PRESENTSTATS . In caso contrario, i dati restituiti da GetPresentStatistics non sono definiti. Una catena di scambio Direct3D 9Ex abilitata per il modello flip fornisce informazioni sulle statistiche presenti in modalità a schermo intero e finestra.

Per le catene di scambio Direct3D 9Ex abilitate per il modello Blt in modalità finestra, tutti i valori di struttura D3DPRESENTSTATS saranno zeli.

Per FlipEx presentano statistiche, GetPresentStatistics restituisce D3DERR_PRESENT_STATISTICS_DISJOINT nelle situazioni seguenti:

  • Prima chiamata a GetPresentStatistics mai, che indica l'inizio di una sequenza
  • Transizione DWM da on a off
  • Modifica della modalità: modalità finestra da o verso schermo intero o transizioni a schermo intero

Per praticità, la sintassi di GetPresentStatistics viene ripetuta qui.

HRESULT GetPresentStatistics(
  D3DPRESENTSTATS * pPresentationStatistics
);

Il metodo IDirect3DSwapChain9Ex::GetLastPresentCount restituisce l'ultimo PresentCount, ovvero l'ID Present dell'ultima chiamata Present eseguita da un dispositivo di visualizzazione associato alla catena di scambio. Questo ID presente è il valore del membro PresentCount della struttura D3DPRESENTSTATS . Per le catene di scambio Direct3D 9Ex abilitate per il modello Blt-Model, mentre in modalità finestra, tutti i valori della struttura D3DPRESENTSTATS saranno zero.

Per praticità, la sintassi di IDirect3DSwapChain9Ex::GetLastPresentCount viene ripetuta qui.

HRESULT GetLastPresentCount(
  UINT * pLastPresentCount
);

Quando modifichi l'applicazione Direct3D 9Ex per Windows 7, devi considerare le informazioni seguenti sulla struttura D3DPRESENTSTATS:

  • Il valore PresentCount restituito da GetLastPresentCount non viene aggiornato quando una chiamata PresentEx con D3DPRESENT_DONOTWAIT specificato nel parametro dwFlags restituisce un errore.
  • Quando PresentEx viene chiamato con D3DPRESENT_DONOTFLIP, una chiamata GetPresentStatistics ha esito positivo ma non restituisce una struttura D3DPRESENTSTATS aggiornata quando l'applicazione è in modalità finestra.
  • PresentRefreshCount e SyncRefreshCount in D3DPRESENTSTATS:
    • PresentRefreshCount è uguale a SyncRefreshCount quando l'applicazione viene visualizzata in ogni vsync.
    • SyncRefreshCount viene ottenuto nell'intervallo vsync quando è stato inviato il presente, SyncQPCTime è approssimativamente l'ora associata all'intervallo vsync.
typedef struct _D3DPRESENTSTATS {
    UINT PresentCount;
    UINT PresentRefreshCount;
    UINT SyncRefreshCount;
    LARGE_INTEGER SyncQPCTime;
    LARGE_INTEGER SyncGPUTime;
} D3DPRESENTSTATS;

Sincronizzazione dei fotogrammi per le applicazioni finestra quando DWM è disattivato

Quando DWM è disattivato, le applicazioni con finestra vengono visualizzate direttamente sullo schermo del monitor senza passare attraverso una catena di capovolgimento. In Windows Vista non è disponibile alcun supporto per ottenere informazioni sulle statistiche dei frame per le applicazioni finestrate quando DWM è disattivato. Per mantenere un'API in cui le applicazioni non devono essere consapevoli di DWM, Windows 7 restituirà le informazioni sulle statistiche dei frame per le applicazioni finestrate quando DWM è disattivato. Le statistiche dei frame restituite quando DWM è disattivato sono solo stime.

Procedura dettagliata di un modello Flip Direct3D 9Ex e presente esempio di statistiche

Per acconsentire esplicitamente alla presentazione FlipEx per l'esempio Direct3D 9Ex

  1. Verificare che l'applicazione di esempio sia in esecuzione in Windows 7 o versione successiva del sistema operativo.
  2. Impostare il membro SwapEffect di D3DPRESENT_PARAMETERS su D3DSWAPEFFECT_FLIPEX in una chiamata a 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;
    }

Per acconsentire esplicitamente anche all'esempio Present Statistics associato a FlipEx per 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;
    }

Per evitare, rilevare e recuperare da errori

  1. Chiamate di accodamento: il numero di backbuffer consigliato è compreso tra 2 e 4.

  2. L'esempio Direct3D 9Ex aggiunge un backbuffer implicito, la lunghezza effettiva della coda presente è il numero di backbuffer + 1.

  3. Creare la struttura della coda presente helper per archiviare tutti gli ID presento (PresentCount) inviati correttamente e associati, calcolati/previsti PresentRefreshCount.

  4. Per rilevare l'occorrenza degli errori:

    • Chiamare GetPresentStatistics.
    • Ottenere l'ID presente (PresentCount) e il conteggio vsync in cui viene visualizzato il fotogramma (PresentRefreshCount) del frame le cui statistiche presenti vengono ottenute.
    • Recuperare l'oggetto PresentRefreshCount (TargetRefresh nel codice di esempio) associato all'ID presente.
    • Se presentRefreshCount effettivo è successivo al previsto, si è verificato un errore.
  5. Per eseguire il ripristino da glitch:

    • Calcolare il numero di fotogrammi da ignorare (g_ variabile iImmediates nel codice di esempio).
    • Presentare i fotogrammi ignorati con intervallo D3DPRESENT_FORCEIMMEDIATE.

Considerazioni sul rilevamento e il ripristino degli errori

  1. Il recupero degli errori accetta N (variabile g_iQueueDelay nel codice di esempio) numero di chiamate Present in cui N (g_iQueueDelay) è uguale g_iImmediates lunghezza della coda Present, ovvero:

    • Ignorare i fotogrammi con intervallo presente D3DPRESENT_FORCEIMMEDIATE, più
    • Presentazione in coda che deve essere elaborata
  2. Impostare un limite sulla lunghezza dell'interruzione (GLITCH_RECOVERY_LIMIT nell'esempio). Se l'applicazione di esempio non è in grado di eseguire il ripristino da un errore troppo lungo (ad esempio, 1 secondo o 60 vsyncs nel monitor a 60Hz), passare all'animazione intermittente e reimpostare la coda helper present.

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;
    }
}

Scenario di esempio

  • La figura seguente mostra un'applicazione con numero di backbuffer pari a 4. La lunghezza effettiva della coda Presente è quindi 5.

    illustrazione di un'applicazione di frame sottoposti a rendering e di una coda presente

    Frame A è destinato a passare sullo schermo sul numero di intervalli di sincronizzazione pari a 1, ma è stato rilevato che è stato visualizzato nel conteggio degli intervalli di sincronizzazione pari a 4. Pertanto si è verificato un errore. I 3 fotogrammi successivi vengono presentati con D3DPRESENT_INTERVAL_FORCEIMMEDIATE. Il problema dovrebbe richiedere un totale di 8 chiamate Present prima di essere ripristinato. Il fotogramma successivo verrà visualizzato in base al numero di intervalli di sincronizzazione di destinazione.

Riepilogo delle raccomandazioni di programmazione per la sincronizzazione dei frame

  • Creare un elenco di backup di tutti gli ID LastPresentCount (ottenuti tramite GetLastPresentCount) e l'oggetto PresentRefreshCount associato di tutti i regali inviati.

    Nota

    Quando l'applicazione chiama PresentEx con D3DPRESENT_DONOTFLIP, la chiamata GetPresentStatistics ha esito positivo ma non restituisce una struttura D3DPRESENTSTATS aggiornata quando l'applicazione è in modalità finestra.

  • Chiamare GetPresentStatistics per ottenere l'effettivo PresentRefreshCount associato a ogni ID presento dei fotogrammi visualizzati, per assicurarsi che l'applicazione gestisca l'errore restituito dalla chiamata.

  • Se presentRefreshCount effettivo è successivo a quello stimato di PresentRefreshCount, viene rilevato un errore. Compensare inviando i frame di ritardo Presenti con D3DPRESENT_FORCEIMMEDIATE.

  • Quando un frame viene presentato in ritardo nella coda Presente, tutti i fotogrammi in coda successivi verranno presentati in ritardo. D3DPRESENT_FORCEIMMEDIATE correggerà solo il frame successivo da presentare dopo tutti i fotogrammi in coda. Di conseguenza, il numero di backbuffer o coda presente non deve essere troppo lungo, quindi ci sono meno glitch di fotogrammi da recuperare. Il numero ottimale di backbuffer è da 2 a 4.

  • Se presentRefreshCount stimato è successivo all'effettivo PresentRefreshCount, potrebbe essersi verificata la limitazione DWM. Sono possibili le soluzioni seguenti:

    • riduzione della lunghezza della coda presente
    • riduzione dei requisiti di memoria GPU con qualsiasi altro mezzo oltre a ridurre la lunghezza della coda presente (ovvero, riducendo la qualità, rimuovendo gli effetti e così via)
    • specifica di DwmEnableMMCSS per impedire la limitazione della limitazione DWM in generale
  • Verificare le funzionalità di visualizzazione dell'applicazione e le prestazioni delle statistiche dei frame negli scenari seguenti:

    • con DWM attivato e disattivato
    • modalità esclusiva e finestra a schermo intero
    • hardware con funzionalità inferiori
  • Quando le applicazioni non possono eseguire il ripristino da un numero elevato di frame rilevati con D3DPRESENT_FORCEIMMEDIATE Present, possono potenzialmente eseguire le operazioni seguenti:

    • ridurre l'utilizzo della CPU e della GPU eseguendo il rendering con meno carico di lavoro.
    • nel caso di decodifica video, decodificare più velocemente riducendo la qualità e, di conseguenza, l'utilizzo della CPU e della GPU.

Conclusione sui miglioramenti di Direct3D 9Ex

In Windows 7, le applicazioni che visualizzano la frequenza dei fotogrammi video o misuratore durante la presentazione possono acconsentire esplicitamente a Flip Model. I miglioramenti delle statistiche presenti associati a Flip Model Direct3D 9Ex possono trarre vantaggio dalle applicazioni che sincronizzano la presentazione per frequenza di fotogrammi, con feedback in tempo reale per il rilevamento e il ripristino degli errori. Gli sviluppatori che adottano il modello Flip Direct3D 9Ex devono prendere in considerazione un HWND separato dal contenuto GDI e dalla sincronizzazione della frequenza dei fotogrammi. Fare riferimento ai dettagli in questo argomento. Per altre informazioni, vedere DirectX Developer Center su MSDN.

Invito all'azione

Ti invitiamo a usare il modello Flip Direct3D 9Ex e le relative statistiche presenti in Windows 7 quando crei applicazioni che tentano di sincronizzare la frequenza dei fotogrammi di presentazione o di recuperare da errori di visualizzazione.

DirectX Developer Center su MSDN