Freigeben über


Direct3D 9Ex-Verbesserungen

In diesem Thema wird die Unterstützung von Windows 7 für Flip Mode Present und die zugehörigen vorhandenen Statistiken in Direct3D 9Ex und Desktop Window Manager beschrieben. Zielanwendungen umfassen Video- oder Bildfrequenz-basierte Präsentationsanwendungen. Anwendungen, die Direct3D 9Ex Flip Mode Present verwenden, reduzieren die Systemressourcenlast, wenn DWM aktiviert ist. Aktuelle Statistikverbesserungen in Verbindung mit Flip Mode Present ermöglichen Direct3D 9Ex-Anwendungen eine bessere Kontrolle der Darstellungsrate durch Echtzeit-Feedback und Korrekturmechanismen. Ausführliche Erläuterungen und Zeiger auf Beispielressourcen sind enthalten.

Dieses Thema enthält folgende Abschnitte:

Verbesserungen bei Direct3D 9Ex für Windows 7

Flip Mode Presentation of Direct3D 9Ex ist ein verbesserter Modus für die Darstellung von Bildern in Direct3D 9Ex, die gerenderte Bilder effizient an Windows 7 Desktop Window Manager (DWM) für die Komposition übergeben. Ab Windows Vista verfasst DWM den gesamten Desktop. Wenn DWM aktiviert ist, präsentieren Anwendungen im Fenstermodus ihre Inhalte auf dem Desktop mithilfe einer Methode namens Blt Mode Present to DWM (oder Blt Model). Mit Blt Model verwaltet DWM eine Kopie der gerenderten Direct3D 9Ex-Oberfläche für die Desktopkomposition. Wenn die Anwendung aktualisiert wird, wird der neue Inhalt über einen Blt in die DWM-Oberfläche kopiert. Für Anwendungen, die Direct3D- und GDI-Inhalte enthalten, werden die GDI-Daten ebenfalls auf die DWM-Oberfläche kopiert.

In Windows 7 ist Flip Mode Present zu DWM (oder Flip Model) eine neue Präsentationsmethode, die im Wesentlichen das Übergeben von Ziehpunkten von Anwendungsoberflächen zwischen Anwendungen im Fenstermodus und DWM ermöglicht. Zusätzlich zum Speichern von Ressourcen unterstützt Flip Model erweiterte aktuelle Statistiken.

Aktuelle Statistiken sind Frame-Timing-Informationen, mit denen Anwendungen Video- und Audiodatenströme synchronisieren und aus Videowiedergabefehlern wiederherstellen können. Die Frame-Timing-Informationen in den vorliegenden Statistiken ermöglichen es Anwendungen, die Darstellungsrate ihrer Videoframes für eine reibungslosere Präsentation anzupassen. In Windows Vista, bei dem DWM eine entsprechende Kopie der Frameoberfläche für die Desktopkomposition verwaltet, können Anwendungen die von DWM bereitgestellten Statistiken verwenden. Diese Methode zum Abrufen vorhandener Statistiken steht weiterhin in Windows 7 für vorhandene Anwendungen zur Verfügung.

In Windows 7 sollten Direct3D 9Ex-basierte Anwendungen, die Flip Model übernehmen, D3D9Ex-APIs verwenden, um aktuelle Statistiken abzurufen. Wenn DWM aktiviert ist, können der Fenstermodus und Direct3D 9Ex-Anwendungen im Vollbildmodus die gleichen aktuellen Statistikinformationen erwarten, wenn Sie Flip Model verwenden. Das Direct3D 9Ex Flip Model ermöglicht es Anwendungen, Statistiken in Echtzeit nach aktuellen Statistiken abzufragen, anstatt nachdem der Frame auf dem Bildschirm angezeigt wurde; Die gleichen aktuellen Statistikinformationen sind für Flip-Model-fähige Anwendungen im Fenstermodus als Vollbildanwendungen verfügbar; Ein hinzugefügtes Flag in D3D9Ex-APIs ermöglicht Flip-Modellanwendungen, späte Frames zur Präsentationszeit effektiv zu verwerfen.

Direct3D 9Ex Flip Model sollte von neuen Video- oder Bildfrequenz-basierten Präsentationsanwendungen verwendet werden, die auf Windows 7 abzielen. Aufgrund der Synchronisierung zwischen DWM und der Direct3D 9Ex-Laufzeit sollten Anwendungen, die Flip Model verwenden, zwischen 2 und 4 Hintergrundpuffer angeben, um eine reibungslose Präsentation sicherzustellen. Diese Anwendungen, die aktuelle Statistikinformationen verwenden, profitieren von der Verwendung des Flip-Modells aktivierter Statistik-Erweiterungen.

Direct3D 9EX Flip Mode Presentation

Leistungsverbesserungen des Direct3D 9Ex Flip Mode Present sind für das System wichtig, wenn DWM aktiviert ist und wenn sich die Anwendung im Fenstermodus befindet, anstatt im exklusiven Vollbildmodus. Die folgende Tabelle und Abbildung zeigen einen vereinfachten Vergleich von Speicherbandbreitennutzungen und Systemlesungen und Schreibvorgängen von Fensteranwendungen, die Flip-Modell im Vergleich zum Standardverwendungs-Blt-Modell auswählen.

Blt Mode Present zu DWM D3D9Ex Flip Mode Present zu DWM
1. Die Anwendung aktualisiert ihren Frame (Schreiben)
1. Die Anwendung aktualisiert ihren Frame (Schreiben)
2. Direct3D-Laufzeit kopiert Oberflächeninhalte auf eine DWM-Umleitungsoberfläche (Lese-, Schreibzugriff)
2. Direct3D-Laufzeit übergibt die Anwendungsoberfläche an DWM
3. Nachdem die Kopie der freigegebenen Oberfläche abgeschlossen wurde, rendert DWM die Anwendungsoberfläche auf dem Bildschirm (Lese-, Schreibzugriff)
3. DWM rendert die Anwendungsoberfläche auf dem Bildschirm (Lesen, Schreiben)

Abbildung eines Vergleichs des Blt-Modells und des Flip-Modells

Flip Mode Present reduziert die Systemspeicherauslastung, indem die Anzahl der Lese- und Schreibvorgänge durch die Direct3D-Laufzeit für die Fenster-Frame-Komposition durch DWM reduziert wird. Dadurch wird der Stromverbrauch des Systems und die Gesamtspeicherauslastung reduziert.

Anwendungen können die Vorteile des Direct3D 9Ex Flip Mode nutzen, um Statistiken zu verbessern, wenn DWM aktiviert ist, unabhängig davon, ob sich die Anwendung im Fenstermodus oder im exklusiven Vollbildmodus befindet.

Programmiermodell und APIs

Neue Video- oder Framerate-Gauging-Anwendungen, die Direct3D 9Ex-APIs unter Windows 7 verwenden, können den Speicher und die Energieeinsparungen sowie die verbesserte Präsentation nutzen, die von Flip Mode Present geboten wird, wenn sie unter Windows 7 ausgeführt wird. (Wenn sie unter früheren Windows-Versionen ausgeführt wird, wird von der Direct3D-Laufzeit standardmäßig die Anwendung auf „Blt Mode Present” festgelegt.)

Flip Mode Present beinhaltet, dass die Anwendung die Vorteile von Feedback- und Korrekturmechanismen in Echtzeit nutzen kann, wenn DWM aktiviert ist. Anwendungen, die Flip Mode Present verwenden, sollten jedoch Einschränkungen beachten, wenn sie gleichzeitiges GDI-API-Rendering verwenden.

Sie können vorhandene Anwendungen so ändern, dass sie die Vorteile von Flip Mode Present nutzen, mit den gleichen Vorteilen und Vorbehalten wie bei neu entwickelten Anwendungen.

So melden Sie sich beim Direct3D 9Ex Flip-Modell an

Direct3D 9Ex-Anwendungen, die auf Windows 7 abzielen, können sich für das Flip-Modell entscheiden, indem sie die Swapchain mit dem D3DSWAPEFFECT_FLIPEX Enumerationswert erstellen. Um das Flip-Modell zu aktivieren, geben Anwendungen die Struktur D3DPRESENT_PARAMETERS an und übergeben dann einen Zeiger an diese Struktur, wenn sie die IDirect3D9Ex::CreateDeviceEx-API aufrufen. In diesem Abschnitt wird beschrieben, wie Anwendungen, die auf Windows 7 abzielen, IDirect3D9Ex::CreateDeviceEx verwenden, um sich für das Flip-Modell zu entscheiden. Weitere Informationen zur IDirect3D9Ex::CreateDeviceEx-API finden Sie unter IDirect3D9Ex::CreateDeviceEx auf MSDN.

Die Syntax von D3DPRESENT_PARAMETERS und IDirect3D9Ex::CreateDeviceEx wird hier wiederholt.

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;

Wenn Sie Direct3D 9Ex-Anwendungen für Windows 7 so ändern, dass sie sich für das Flip-Modell entscheiden, sollten Sie die folgenden Elemente zu den angegebenen Elementen von D3DPRESENT_PARAMETERS berücksichtigen:

BackBufferCount

(Nur Windows 7)

Wenn SwapEffect auf den neuen D3DSWAPEFFECT_FLIPEX Swapchain-Effekttyp festgelegt ist, sollte die Anzahl der Hintergrundpuffer gleich oder größer als 2 sein, um zu verhindern, dass eine Anwendungsleistungsstrafe aufgrund des Wartens auf den vorherigen Present-Puffer, der von DWM freigegeben wird.

Wenn die Anwendung auch vorhandene Statistiken verwendet, die D3DSWAPEFFECT_FLIPEX zugeordnet sind, empfiehlt es sich, die Anzahl der Hintergrundpuffer auf 2 bis 4 festzulegen.

Wenn Sie D3DSWAPEFFECT_FLIPEX unter Windows Vista oder früheren Betriebssystemversionen verwenden, wird ein Fehler von CreateDeviceEx zurückgegeben.

SwapEffect

(Nur Windows 7)

Der neue D3DSWAPEFFECT_FLIPEX Swapchain-Effekttyp bestimmt, wann eine Anwendung den Flip Mode Present zu DWM annimmt. Es ermöglicht der Anwendung eine effizientere Nutzung von Arbeitsspeicher und Energie und ermöglicht der Anwendung auch die Nutzung von Statistiken im Vollbildmodus im Fenstermodus. Das Anwendungsverhalten im Vollbildmodus ist nicht betroffen. Wenn „Windowed” auf TRUE festgelegt ist und SwapEffect auf D3DSWAPEFFECT_FLIPEX festgelegt ist, erstellt die Laufzeit einen zusätzlichen Hintergrundpuffer und dreht, welcher Handle zum Puffer gehört, der zur Präsentationszeit zum Frontpuffer wird.

Flags

(Nur Windows 7)

Das D3DPRESENTFLAG_LOCKABLE_BACKBUFFER-Flag kann nicht festgelegt werden, wenn SwapEffect auf den neuen D3DSWAPEFFECT_FLIPEX Swapchain-Effekttyp festgelegt ist.

Entwurfsrichtlinien für Direct3D 9Ex Flip-Modellanwendungen

Verwenden Sie die Richtlinien in den folgenden Abschnitten, um Ihre Direct3D 9Ex Flip Model-Anwendungen zu entwerfen.

Verwenden Sie den Flip Mode Present in einer von Blt Mode Present getrennten HWND

Anwendungen sollten den Direct3D 9Ex Flip Mode Present in einem HWND verwenden, der nicht auch von anderen APIs ausgerichtet ist, einschließlich Blt Mode Present Direct3D 9Ex, andere Versionen von Direct3D oder GDI. Der Flip Mode Present kann verwendet werden, um untergeordnete Fenster anzuzeigen. d. h. Anwendungen können das Flip-Modell verwenden, wenn es nicht mit Blt Model in derselben HWND gemischt wird, wie in den folgenden Abbildungen gezeigt.

Abbildung des übergeordneten Direct3d-Fensters und eines untergeordneten gdi-Fensters mit jeweils eigenem hwnd

Abbildung des übergeordneten gdi-Fensters und eines untergeordneten direct3d-Fensters mit jeweils eigenem hwnd

Da das Blt-Modell eine zusätzliche Kopie der Oberfläche verwaltet, können GDI und andere Direct3D-Inhalte demselben HWND über Stückaktualisierungen von Direct3D und GDI hinzugefügt werden. Mithilfe des Flip-Modells werden nur Direct3D 9Ex-Inhalte in D3DSWAPEFFECT_FLIPEX Swapchains angezeigt, die an DWM übergeben werden. Alle anderen Blt Model Direct3D- oder GDI-Inhaltsupdates werden ignoriert, wie in den folgenden Abbildungen dargestellt.

Abbildung von gdi-Text, der möglicherweise nicht angezeigt wird, wenn das Flip-Modell verwendet wird, und direct3d- und gdi-Inhalt sich in demselben hwnd befinden

Abbildung von direct3d- und gdi-Inhalten, in denen dwm aktiviert ist und sich die Anwendung im Fenstermodus befindet

Daher sollte das Flip-Modell für Swapchain-Puffer-Oberflächen aktiviert werden, auf denen das Direct3D 9Ex Flip-Modell allein für den gesamten HWND gerendert wird.

Flip-Modell nicht mit dem ScrollWindow- oder ScrollWindowEx-Element von GDI verwenden

Einige Direct3D 9Ex-Anwendungen verwenden die Funktionen ScrollWindow oder ScrollWindowEx von GDI, um Fensterinhalte zu aktualisieren, wenn ein Benutzerlaufereignis ausgelöst wird. ScrollWindow und ScrollWindowEx führen Fensterinhalte auf dem Bildschirm aus, während ein Fenster gescrollt wird. Diese Funktionen erfordern auch Blt-Modellupdates für GDI- und Direct3D 9Ex-Inhalte. Anwendungen, die eine der beiden Funktionen verwenden, zeigen nicht unbedingt sichtbare Fensterinhalte auf dem Bildschirm an, wenn sich die Anwendung im Fenstermodus befindet und DWM aktiviert ist. Es wird empfohlen, die ScrollWindow- und ScrollWindowEx-APIs von GDI nicht in Ihren Anwendungen zu verwenden und stattdessen deren Inhalt auf dem Bildschirm als Reaktion auf das Scrollen neu zu zeichnen.

Verwenden einer D3DSWAPEFFECT_FLIPEX Swapchain pro HWND

Anwendungen, die Flip-Modell verwenden, sollten nicht mehrere Flip-Modell-Swapchains für den gleichen HWND verwenden.

Framesynchronisierung von Direct3D 9Ex Flip-Modellanwendungen

Aktuelle Statistiken sind Frame-Timing-Informationen, mit denen Medienanwendungen Video- und Audiodatenströme synchronisieren und aus Videowiedergabefehlern wiederherstellen können. Um die Verfügbarkeit von Statistiken zu aktivieren, muss die Direct3D 9Ex-Anwendung sicherstellen, dass der BehaviorFlags-Parameter, den die Anwendung an IDirect3D9Ex::CreateDeviceEx übergibt, das Geräteverhaltenskennzeichen D3DCREATE_ENABLE_PRESENTSTATS enthält.

Die Syntax von IDirect3D9Ex::CreateDeviceEx wird hier wiederholt.

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

Das Direct3D 9Ex Flip-Modell fügt die D3DPRESENT_FORCEIMMEDIATE Präsentationsflagge hinzu, das das Verhalten D3DPRESENT_INTERVAL_IMMEDIATE Präsentationskennzeichnung erzwingt. Die Direct3D 9Ex-Anwendung gibt diese Präsentationskennzeichnungen im dwFlags-Parameter an, den die Anwendung an IDirect3DDevice9Ex::PresentEx übergibt, wie hier gezeigt.

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

Wenn Sie Ihre Direct3D 9Ex-Anwendung für Windows 7 ändern, sollten Sie die folgenden Informationen zu den angegebenen D3DPRESENT Präsentationskennzeichnungen berücksichtigen:

D3DPRESENT_DONOTFLIP

Dieses Kennzeichen ist nur im Vollbildmodus oder

(Nur Windows 7)

wenn die Anwendung das SwapEffect-Element von D3DPRESENT_PARAMETERS auf D3DSWAPEFFECT_FLIPEX in einem Aufruf von CreateDeviceEx festlegt.

D3DPRESENT_FORCEIMMEDIATE

(Nur Windows 7)

Dieses Flag kann nur angegeben werden, wenn die Anwendung das SwapEffect-Element von D3DPRESENT_PARAMETERS auf D3DSWAPEFFECT_FLIPEX in einem Aufruf von CreateDeviceEx festlegt. Die Anwendung kann diese Kennzeichnung verwenden, um sofort eine Oberfläche mit mehreren Frames später in der DWM Present-Warteschlange zu aktualisieren, im Wesentlichen überspringen Zwischenframes.

FlipEx-aktivierte Anwendungen mit Fenstern können diese Kennzeichnung verwenden, um sofort eine Oberfläche mit einem Frame zu aktualisieren, der sich später in der DWM Present-Warteschlange befindet und Zwischenframes überspringt. Dies ist besonders nützlich für Medienanwendungen, die Frames verwerfen möchten, die zur Kompositionszeit als spät erkannt wurden und nachfolgende Frames darstellen. IDirect3DDevice9Ex::P resentEx gibt einen ungültigen Parameterfehler zurück, wenn dieses Flag nicht ordnungsgemäß angegeben ist.

Zum Abrufen vorhandener Statistikinformationen ruft die Anwendung die Struktur D3DPRESENTSTATS durch Aufrufen der IDirect3DSwapChain9Ex::GetPresentStatistics-API ab.

Die Struktur D3DPRESENTSTATS enthält Statistiken zu IDirect3DDevice9Ex::PresentEx-Aufrufen. Das Gerät muss mit einem Aufruf IDirect3D9Ex::CreateDeviceEx mit dem Flag D3DCREATE_ENABLE_PRESENTSTATS erstellt werden. Andernfalls werden die von GetPresentStatistics zurückgegebenen Daten nicht definiert. Eine Flip-Model-fähige Direct3D 9Ex-Swapchain stellt Statistiken sowohl im Fenster- als auch im Vollbildmodus bereit.

Für Blt-Model-fähige Direct3D 9Ex-Swapchains im Fenstermodus sind alle D3DPRESENTSTATS Strukturwerte Nullen.

Für FlipEx-Statistiken gibt GetPresentStatistics in den folgenden Situationen D3DERR_PRESENT_STATISTICS_DISJOINT zurück:

  • Erster Aufruf von GetPresentStatistics, der den Anfang einer Sequenz angibt
  • DWM-Übergang von „Ein” zu „Aus”
  • Modusänderung: Entweder „Fenstermodus zu” oder von „Vollbild- oder Vollbildmodus zu Vollbildübergängen”

Aus Gründen der Einfachheit wird die Syntax von GetPresentStatistics hier wiederholt.

HRESULT GetPresentStatistics(
  D3DPRESENTSTATS * pPresentationStatistics
);

Die Methode IDirect3DSwapChain9Ex::GetLastPresentCount gibt den letzten PresentCount zurück, d. h. die Present-ID des letzten erfolgreichen Present-Aufrufs, der von einem Anzeigegerät durchgeführt wurde, das der Swapchain zugeordnet ist. Diese Present-ID ist der Wert des PresentCount-Members der D3DPRESENTSTATS-Struktur. Für Blt-Model-fähige Direct3D 9Ex-Swapchains während des Fenstermodus sind alle D3DPRESENTSTATS Strukturwerte Nullen.

Die Syntax von IDirect3DSwapChain9Ex::GetLastPresentCount wird hier wiederholt.

HRESULT GetLastPresentCount(
  UINT * pLastPresentCount
);

Wenn Sie Ihre Direct3D 9Ex-Anwendung für Windows 7 ändern, sollten Sie die folgenden Informationen zu den angegebenen D3DPRESENTSTATS-Struktur berücksichtigen:

  • Der PresentCount-Wert, den GetLastPresentCount zurückgibt, wird nicht aktualisiert, wenn ein PresentEx-Aufruf mit D3DPRESENT_DONOTWAIT angegeben im dwFlags-Parameter fehler zurückgibt.
  • Wenn PresentEx mit D3DPRESENT_DONOTFLIP aufgerufen wird, wird ein GetPresentStatistics-Aufruf erfolgreich ausgeführt, gibt jedoch keine aktualisierte D3DPRESENTSTATS Struktur zurück, wenn sich die Anwendung im Fenstermodus befindet.
  • PresentRefreshCount im Vergleich zu SyncRefreshCount in D3DPRESENTSTATS:
    • PresentRefreshCount ist gleich SyncRefreshCount , wenn die Anwendung auf jeder vsync angezeigt wird.
    • SyncRefreshCount wird im vsync-Intervall abgerufen, wenn das Aktuelle übermittelt wurde, SyncQPCTime ist ungefähr die Zeit, die dem vsync-Intervall zugeordnet ist.
typedef struct _D3DPRESENTSTATS {
    UINT PresentCount;
    UINT PresentRefreshCount;
    UINT SyncRefreshCount;
    LARGE_INTEGER SyncQPCTime;
    LARGE_INTEGER SyncGPUTime;
} D3DPRESENTSTATS;

Framesynchronisierung für Fensteranwendungen, wenn DWM deaktiviert ist

Wenn DWM deaktiviert ist, werden Fensteranwendungen direkt auf dem Bildschirm angezeigt, ohne durch eine Flipchain zu gehen. In Windows Vista gibt es keine Unterstützung für das Abrufen von Framestatistiken für Fensteranwendungen, wenn DWM deaktiviert ist. Um eine API aufrechtzuerhalten, bei der Anwendungen nicht DWM-fähig sein müssen, gibt Windows 7 Framestatistikinformationen für Fensteranwendungen zurück, wenn DWM deaktiviert ist. Die Framestatistiken, die zurückgegeben werden, wenn DWM deaktiviert ist, sind nur Schätzungen.

Walk-Through eines Direct3D 9Ex Flip-Modell und aktuelle Statistikbeispiele

So melden Sie sich für ein FlipEx-Beispiel für Direct3D 9Ex an

  1. Stellen Sie sicher, dass die Beispielanwendung unter Windows 7 oder höher unter der Betriebssystemversion ausgeführt wird.
  2. Legen Sie das SwapEffect-Mitglied von D3DPRESENT_PARAMETERS auf D3DSWAPEFFECT_FLIPEX in einem Aufruf von CreateDeviceEx fest.
    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;
    }

So melden Sie sich auch für die mit FlipEx verbundene Präsentationsstatistik für das Direct3D 9Ex-Beispiel an

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

Vermeidung, Erkennung und Behebung von Störungen

  1. Warteschleife aktuelle Aufrufe: Die empfohlene Hintergrundpufferanzahl liegt zwischen 2 und 4.

  2. Im Direct3D 9Ex-Beispiel wird ein impliziter Hintergrundpuffer hinzugefügt, die tatsächliche Länge der Warteschlange ist Hintergrundpufferanzahl + 1.

  3. Erstellen Sie eine Hilfsstruktur für die Present-Warteschlange, um alle erfolgreich übermittelten Present-IDs (PresentCount) und den zugehörigen, berechneten/erwarteten PresentRefreshCount zu speichern.

  4. So erkennen Sie das Glitch-Vorkommen:

    • Rufen Sie GetPresentStatistics auf.
    • Rufen Sie die Present-ID (PresentCount) und die vsync-Anzahl ab, in der der Frame angezeigt wird (PresentRefreshCount) des Frames, dessen aktuelle Statistiken abgerufen werden.
    • Rufen Sie den erwarteten PresentRefreshCount (TargetRefresh im Beispielcode) ab, der der Present-ID zugeordnet ist.
    • Wenn PresentRefreshCount später als erwartet ist, ist ein Glitch aufgetreten.
  5. Nach einer Störung wiederherstellen:

    • Berechnen Sie, wie viele Frames übersprungen werden sollen (g_ iImmediates-Variable im Beispielcode).
    • Präsentieren Sie die übersprungenen Frames mit D3DPRESENT_FORCEIMMEDIATE.

Überlegungen zur Glitch-Erkennung und Wiederherstellung

  1. Die Glitch-Wiederherstellung akzeptiert N (g_iQueueDelay Variable im Beispielcode) Anzahl der Present-Aufrufe, wobei N (g_iQueueDelay) g_iImmediates plus Länge der Present-Warteschlange entspricht, das heißt:

    • Überspringen von Frames mit dem Present-Intervall D3DPRESENT_FORCEIMMEDIATE, plus
    • In der Warteschlange befindliche Presents, die bearbeitet werden müssen
  2. Legen Sie eine Grenze für die Glitch-Länge fest (GLITCH_RECOVERY_LIMIT im Beispiel). Wenn die Beispielanwendung nicht von einem zu langen Glitch (d. h. 1 Sekunde oder 60 vsyncs auf 60Hz Monitor) wiederherstellen kann, springen Sie über die intermittierende Animation, und setzen Sie die Present-Hilfswarteschlange zurück.

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

Beispielszenario

  • Die folgende Abbildung zeigt eine Anwendung mit der Hintergrundpufferanzahl 4. Die tatsächliche Länge der Present-Warteschlange ist daher 5.

    Abbildung einer gerenderten Applicas-Frames und einer Present-Warteschlange

    Frame A ist darauf ausgerichtet, die Anzahl der Synchronisierungsintervalle von 1 auf dem Bildschirm zu aktivieren, wurde jedoch erkannt, dass es bei der Synchronisierungsintervallanzahl von 4 angezeigt wurde. Daher ist ein Glitch aufgetreten. Nachfolgende 3 Frames werden mit D3DPRESENT_INTERVAL_FORCEIMMEDIATE präsentiert. Der Glitch sollte insgesamt 8 Present-Aufrufe dauern, bevor er wiederhergestellt wird. Der nächste Frame wird gemäß der Anzahl der zielbezogenen Synchronisierungsintervalle angezeigt.

Zusammenfassung der Programmierempfehlungen für die Framesynchronisierung

  • Erstellen Sie eine Sicherungsliste aller LastPresentCount-IDs (abgerufen über GetLastPresentCount) und zugeordnete geschätzte PresentRefreshCount aller übermittelten Presents.

    Hinweis

    Wenn die Anwendung PresentEx mit D3DPRESENT_DONOTFLIP aufruft, wird der GetPresentStatistics-Aufruf erfolgreich ausgeführt, gibt jedoch keine aktualisierte D3DPRESENTSTATS-Struktur zurück, wenn sich die Anwendung im Fenstermodus befindet.

  • Rufen Sie GetPresentStatistics auf, um den tatsächlichen PresentRefreshCount abzurufen, der jeder angezeigten Present-ID von Frames zugeordnet ist, um sicherzustellen, dass die Anwendung Fehlerrückgänge vom Aufruf verarbeitet.

  • Wenn PresentRefreshCount später als PresentRefreshCount ist, wird ein Glitch erkannt. Kompensieren Sie das Senden von Verzögerungen mit D3DPRESENT_FORCEIMMEDIATE von Frames.

  • Wenn ein Frame spät in der Present-Warteschlange angezeigt wird, werden alle nachfolgenden in die Warteschlange eingereihten Frames verspätet angezeigt. D3DPRESENT_FORCEIMMEDIATE korrigiert nur den nächsten Frame, der nach allen in die Warteschlange eingereihten Frames angezeigt wird. Daher sollte die Anzahl der Bilder in der Warteschlange oder im Hintergrundpuffer nicht zu groß sein, damit es weniger Störungen gibt, die aufgeholt werden müssen. Die optimale Hintergrundpufferanzahl beträgt 2 bis 4.

  • Wenn PresentRefreshCount später als der tatsächliche PresentRefreshCount ist, ist möglicherweise eine DWM-Drosselung aufgetreten. Die folgenden Lösungen sind möglich:

    • Verringerung der Länge der aktuellen Warteschlange
    • Reduzierung der GPU-Speicheranforderungen mit allen anderen Mitteln neben der Verringerung der Länge der aktuellen Warteschlange (d. h. Verringern der Qualität, Entfernen von Effekten usw.)
    • Angeben von DwmEnableMMCSS, um die DWM-Drosselung im Allgemeinen zu verhindern
  • Überprüfen Sie die Leistung von Anwendungsanzeigefunktionen und Framestatistiken in den folgenden Szenarien:

    • Mit DWM ein- und ausschalten
    • Exklusiv- und Fenstermodi im Vollbildmodus
    • Hardware mit geringerer Leistungsfähigkeit
  • Wenn Anwendungen mit D3DPRESENT_FORCEIMMEDIATE Present keine großen Anzahl von glitched Frames wiederherstellen können, können sie möglicherweise die folgenden Vorgänge ausführen:

    • Reduzieren Sie die CPU- und GPU-Auslastung, indem Sie mit weniger Arbeitsauslastung rendern.
    • im Falle der Videodecodierung, decodieren Sie schneller, indem Sie die Qualität reduzieren und daher CPU- und GPU-Auslastung reduzieren.

Fazit zu Direct3D 9Ex-Verbesserungen

Unter Windows 7 können Anwendungen, die Video- oder Bildfrequenz während der Präsentation anzeigen, das Flip-Modell verwenden. Die aktuellen Verbesserungen der Statistiken, die mit Flip Model Direct3D 9Ex verknüpft sind, können Anwendungen nutzen, die die Präsentation pro Framerate synchronisieren, mit Echtzeitfeedback für die Erkennung und Wiederherstellung von Glitch. Entwickler, die das Direct3D 9Ex Flip-Modell übernehmen, sollten eine separate HWND von GDI-Inhalten und Bildfrequenzsynchronisierung berücksichtigen. Weitere Informationen finden Sie in diesem Thema. Weitere Dokumentation finden Sie im DirectX Developer Center auf MSDN.

Call-to-Action

Wir empfehlen Ihnen, das Direct3D 9Ex Flip-Modell und seine aktuellen Statistiken unter Windows 7 zu verwenden, wenn Sie Anwendungen erstellen, die versuchen, die Bildfrequenz der Präsentation zu synchronisieren oder aus Anzeigestörungen wiederherzustellen.

DirectX Developer Center auf MSDN