Condividi tramite


Miglioramenti di Direct3D 9Ex

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

In questo argomento sono contenute 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 esegue in modo efficiente il rendering delle immagini 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 loro contenuto sul desktop usando un metodo denominato Blt Mode Present to DWM (o Blt Model). Con il modello Blt, DWM gestisce una copia dell'area di rendering Direct3D 9Ex per la composizione desktop. Quando l'applicazione viene aggiornata, il nuovo contenuto viene copiato nell'area DWM tramite un blt. Per le applicazioni che contengono contenuto Direct3D e GDI, i dati GDI vengono copiati anche nell'area DWM.

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

Le statistiche presenti sono informazioni di temporizzazione 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 modificare la frequenza di presentazione dei fotogrammi video per una presentazione più uniforme. In Windows Vista, dove DWM gestisce una copia corrispondente dell'area di cornice 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 Flip Model devono usare le API D3D9Ex per ottenere statistiche presenti. Quando DWM è abilitato, la modalità finestra e la modalità esclusiva a schermo intero Direct3D 9Ex possono aspettarsi 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 le statistiche presenti in tempo reale, anziché dopo che il frame è stato visualizzato sullo schermo; le stesse informazioni sulle statistiche presenti sono disponibili per le applicazioni con modalità finestra Flip-Model abilitate come applicazioni a schermo intero; un flag aggiunto nelle API D3D9Ex consente alle applicazioni Flip Model di eliminare in modo efficace fotogrammi in ritardo 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. Queste applicazioni che usano le informazioni sulle statistiche presentano vantaggi dall'uso di Flip Model abilitato per i miglioramenti delle statistiche.

Presentazione in modalità flip Direct3D 9EX

I miglioramenti delle prestazioni della modalità flip Direct3D 9Ex sono significativi nel sistema quando DWM è attivo e quando l'applicazione è in modalità finestra, anziché in modalità esclusiva a schermo intero. Nella tabella e nella figura seguente viene illustrato un confronto semplificato tra utilizzo della larghezza di banda di memoria e letture di sistema e scritture di applicazioni finestrate che scelgono Flip Model rispetto al modello di utilizzo predefinito Blt.

Modalità Blt presente a 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 l'area dell'applicazione a DWM
3. Dopo aver completato la copia della superficie condivisa, DWM esegue il rendering dell'area dell'applicazione sullo schermo (lettura, scrittura)
3. DWM esegue il rendering dell'area dell'applicazione sullo schermo (lettura, scrittura)

illustrazione di un confronto del modello blt e del 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 direct3D 9Ex Flip Mode presentano miglioramenti delle statistiche quando DWM è attivo, indipendentemente dal fatto che l'applicazione sia in modalità finestra o in modalità esclusiva a schermo intero.

Modelli di programmazione e API

Le nuove applicazioni con frequenza dei fotogrammi o video che usano LE API Direct3D 9Ex in Windows 7 possono sfruttare la memoria e il risparmio di potenza e la presentazione migliorata offerta dalla modalità Flip Presente durante l'esecuzione in Windows 7. Quando viene eseguito nelle versioni precedenti di Windows, il runtime Direct3D impostazione predefinita l'applicazione in modalità Blt Present.

Flip Mode Present comporta 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 di API GDI simultanee.

È possibile modificare le applicazioni esistenti per sfruttare Flip Mode Present, con gli stessi vantaggi e avvisi delle applicazioni appena 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 a Flip Model, 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::CreateDeviceExin 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 si modificano le applicazioni Direct3D 9Ex per Windows 7, è consigliabile prendere in considerazione 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 indietro 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 le statistiche associate a D3DSWAPEFFECT_FLIPEX, è consigliabile impostare il numero di buffer indietro su da 2 a 4.

L'uso di D3DSWAPEFFECT_FLIPEX nelle versioni del sistema operativo Windows Vista o precedenti 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 Mode Present to DWM. Consente all'applicazione un utilizzo più efficiente della memoria e della potenza e consente anche all'applicazione di sfruttare le statistiche 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 indietro aggiuntivo e ruota il buffer che appartiene 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 per la progettazione per applicazioni modello Direct3D 9Ex Flip

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

Usare la modalità capovolgimento presente in un HWND separato dalla modalità Blt presente

Le applicazioni devono usare Direct3D 9Ex Flip Mode Presente in un HWND che non è destinato anche ad altre API, tra cui Blt Mode Present Direct3D 9Ex, altre versioni di Direct3D o GDI. La modalità Flip Present può essere usata per presentare le finestre figlio; ovvero, le applicazioni possono usare Flip Model quando non sono miste con 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 diretta3d, ognuna con il proprio hwnd

Poiché il modello Blt gestisce una copia aggiuntiva della superficie, è possibile aggiungere contenuti GDI e altri contenuti Direct3D allo stesso HWND tramite aggiornamenti a fasi da Direct3D e GDI. Usando il modello Flip, sarà visibile solo il contenuto Direct3D 9Ex in D3DSWAPEFFECT_FLIPEX catene di scambio passate a DWM. 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 di capovolgimento e il contenuto diretto3d e gdi si trovano nello stesso hwnd

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

Pertanto, 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 mentre una finestra viene scorrevole. Queste funzioni richiedono anche gli aggiornamenti del modello Blt per il contenuto GDI e Direct3D 9Ex. Le applicazioni che usano entrambe le funzioni non visualizzeranno necessariamente il contenuto della finestra visibile che scorre sullo schermo quando l'applicazione è in modalità finestra e DWM è abilitata. È 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 frame delle applicazioni del modello Flip Direct3D 9Ex

Le statistiche presenti sono informazioni sulla tempistica dei fotogrammi che le applicazioni multimediali usano per sincronizzare i flussi video e audio e recuperare da errori di riproduzione video. Per abilitare la disponibilità delle statistiche presenti, l'applicazione Direct3D 9Ex deve assicurarsi che il parametro BehaviorFlags passato all'applicazione 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 si modifica l'applicazione Direct3D 9Ex per Windows 7, è consigliabile 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, ignorando essenzialmente fotogrammi intermedi.

Le applicazioni FlipEx abilitate a finestra possono usare questo flag per aggiornare immediatamente una superficie con un frame più avanti nella coda DWM Present, ignorando i frame intermedi. Ciò è particolarmente utile per le applicazioni multimediali che vogliono eliminare 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 viene specificato in modo non corretto.

Per ottenere informazioni sulle statistiche, 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 di 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à con finestra e schermo intero.

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

Per FlipEx presenta 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 a off
  • Modifica della modalità: modalità finestrata a o da schermo intero o a schermo intero alle 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 presente dell'ultima chiamata Presente eseguita da un dispositivo visualizzato 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, 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 si modifica l'applicazione Direct3D 9Ex per Windows 7, è consigliabile considerare le informazioni seguenti sulla struttura D3DPRESENTSTATS :

  • Il valore PresentCount restituito da GetLastPresentCount non viene aggiornato quando una chiamata PresentEx con D3DPRESENT_DONOTWAIT specificata 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 rispetto a SyncRefreshCount in D3DPRESENTSTATS:
    • PresentRefreshCount è uguale a SyncRefreshCount quando l'applicazione presenta in ogni vsync.
    • SyncRefreshCount viene ottenuto nell'intervallo vsync quando il presente è stato inviato, SyncQPCTime è approssimativamente il tempo associato all'intervallo vsync.
typedef struct _D3DPRESENTSTATS {
    UINT PresentCount;
    UINT PresentRefreshCount;
    UINT SyncRefreshCount;
    LARGE_INTEGER SyncQPCTime;
    LARGE_INTEGER SyncGPUTime;
} D3DPRESENTSTATS;

Sincronizzazione frame per applicazioni finestrate quando DWM è disattivato

Quando DWM è disattivato, le applicazioni finestrate vengono visualizzate direttamente nella schermata di monitoraggio 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 DWM, Windows 7 restituirà le informazioni sulle statistiche dei frame per le applicazioni finestrate quando DWM è disattivato. Le statistiche del frame restituite quando DWM è disattivato sono solo stime.

Walk-Through di un modello Flip Direct3D 9Ex e presente esempio di statistiche

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

  1. Assicurarsi 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 a FlipEx associato Statistiche presenti per l'esempio 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 ripristinare da errori

  1. Code Present chiama: 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 Dell'helper Per archiviare tutti gli ID present (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 visualizzata la cornice (PresentRefreshCount) del frame con 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 recuperare 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 relative al rilevamento degli errori e al ripristino

  1. Il ripristino di glitch accetta N (variabile g_iQueueDelay nel codice di esempio) numero di chiamate Presenti in cui N (g_iQueueDelay) è uguale g_iImmediates più lunghezza della coda Presente, ovvero:

    • Ignora fotogrammi con Intervallo presente D3DPRESENT_FORCEIMMEDIATE, oltre
    • Presenta in coda che devono essere elaborati
  2. Impostare un limite alla lunghezza dell'interruzione (GLITCH_RECOVERY_LIMIT nell'esempio). Se l'applicazione di esempio non riesce a recuperare da un errore troppo lungo (ad esempio, 1 secondo o 60 vsyncs su monitor a 60Hz), passare all'animazione intermittente e reimpostare la coda del helper Presente.

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 una cornice di cui è stato eseguito il 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 numero di intervalli di sincronizzazione di 4. Pertanto si è verificato un errore. I 3 fotogrammi successivi vengono presentati con D3DPRESENT_INTERVAL_FORCEIMMEDIATE. L'errore deve richiedere un totale di 8 chiamate Presenti prima di essere ripristinato. Il frame successivo verrà visualizzato come per il numero di intervalli di sincronizzazione di destinazione.

Riepilogo delle raccomandazioni di programmazione per la sincronizzazione dei fotogrammi

  • Creare un elenco di backup di tutti gli ID LastPresentCount (ottenuto tramite GetLastPresentCount) e l'oggetto PresentRefreshCount stimato di tutti i present 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 presente di frame visualizzati, per assicurarsi che l'applicazione gestisce l'errore restituito dalla chiamata.

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

  • Quando una cornice viene presentata 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. Pertanto, il numero di code o backbuffer presenti non deve essere troppo lungo, quindi ci sono meno errori di frame da recuperare. Il numero ottimale di backbuffer è da 2 a 4.

  • Se la classe PresentRefreshCount stimata è successiva all'effettivo PresentRefreshCount, potrebbe verificarsi la limitazione di DWM. Le soluzioni seguenti sono possibili:

    • 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 la riduzione della qualità, la rimozione degli effetti e così via)
    • specificando DwmEnableMMCSS per evitare la limitazione della limitazione DWM in generale
  • Verificare le prestazioni delle funzionalità e delle statistiche frame dell'applicazione negli scenari seguenti:

    • con DWM su e disattivato
    • modalità esclusive e finestrate a schermo intero
    • hardware di funzionalità inferiore
  • Quando le applicazioni non possono eseguire il ripristino da un numero elevato di frame rilevati con D3DPRESENT_FORCEIMMEDIATE Presente, possono potenzialmente eseguire le operazioni seguenti:

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

Conclusione dei 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 dei fotogrammi, con feedback in tempo reale per il rilevamento e il recupero 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 e alla documentazione MSDN. Per altre informazioni, vedere DirectX Developer Center su MSDN.

Invito all'azione ##

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

DirectX Developer Center su MSDN