Share via


Direct3D 9Ex-Verbesserungen

In diesem Thema wird beschrieben, wie Windows 7 in Direct3D 9Ex und DesktopFenster-Manager den Flip Mode Present und die zugehörigen aktuellen Statistiken unterstützt. Zielanwendungen umfassen Video- oder Bildfrequenz-basierte Präsentationsanwendungen. Anwendungen, die Direct3D 9Ex Flip Mode Present verwenden, reduzieren die Systemressourcenlast, wenn DWM aktiviert ist. Verbesserungen der aktuellen Statistiken im Zusammenhang mit Flip Mode Present ermöglichen Es Direct3D 9Ex-Anwendungen, die Darstellungsrate besser zu steuern, indem sie Feedback- und Korrekturmechanismen in Echtzeit bereitstellen. Ausführliche Erläuterungen und Zeiger auf Beispielressourcen sind enthalten.

Dieses Thema enthält folgende Abschnitte:

Verbesserungen an Direct3D 9Ex für Windows 7

Flip Mode Presentation of Direct3D 9Ex ist ein verbesserter Modus zur Darstellung von Bildern in Direct3D 9Ex, der gerenderte Bilder effizient an Windows 7 Desktop Window Manager (DWM) für die Komposition übergibt. Ab Windows Vista erstellt 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 Dem Blt-Modell verwaltet DWM eine Kopie der gerenderten Direct3D 9Ex-Oberfläche für die Desktopkomposition. Wenn die Anwendung aktualisiert wird, wird der neue Inhalt über ein Blt auf 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.

Der in Windows 7 verfügbare Flip Mode Present to DWM (oder Flip Model) ist eine neue Präsentationsmethode, die im Wesentlichen das Übergeben von Handles von Anwendungsoberflächen zwischen Anwendungen im Fenstermodus und DWM ermöglicht. Flip Model unterstützt nicht nur Ressourcen, es unterstützt erweiterte aktuelle Statistiken.

Aktuelle Statistiken sind Frame-Timing-Informationen, die Anwendungen verwenden können, um Video- und Audiostreams zu synchronisieren und nach Störungen der Videowiedergabe wiederherzustellen. Die Frame-Timing-Informationen in der aktuellen Statistik ermöglichen es Anwendungen, die Darstellungsrate ihrer Videoframes für eine reibungslosere Darstellung anzupassen. In Windows Vista, wo DWM eine entsprechende Kopie der Frameoberfläche für die Desktopkomposition verwaltet, können Anwendungen die von DWM bereitgestellten aktuellen Statistiken verwenden. Diese Methode zum Abrufen vorhandener Statistiken ist in Windows 7 für vorhandene Anwendungen weiterhin verfügbar.

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

Direct3D 9Ex Flip Model sollte von neuen Video- oder Bildfrequenz-basierten Präsentationsanwendungen für Windows 7 verwendet werden. Aufgrund der Synchronisierung zwischen DWM und der Direct3D 9Ex-Runtime sollten Anwendungen, die Flip-Modell verwenden, zwischen 2 und 4 Backbuffer angeben, um eine reibungslose Darstellung zu gewährleisten. Anwendungen, die aktuelle Statistikinformationen verwenden, profitieren von der Verwendung von Flip-Modell-fähigen Verbesserungen für die Gegenwartsstatistik.

Direct3D 9EX Flip Mode Präsentation

Leistungsverbesserungen von Direct3D 9Ex Flip Mode Present sind auf dem System erheblich, wenn DWM aktiviert ist und sich die Anwendung im Fenstermodus befindet, anstatt im exklusiven Vollbildmodus. Die folgende Tabelle und Abbildung zeigen einen vereinfachten Vergleich von Speicherbandbreitennutzungen und Systemlese- und Schreibvorgängen von Anwendungen mit Fenstern, die Flip-Modell im Vergleich zum Standardmäßigen Blt-Modell auswählen.

Blt-Modus für DWM vorhanden D3D9Ex Flip Mode Present to DWM
1. Die Anwendung aktualisiert ihren Frame (Schreiben)
1. Die Anwendung aktualisiert ihren Frame (Schreiben)
2. Direct3D Runtime kopiert Oberflächeninhalte auf eine DWM-Umleitungsoberfläche (Lesen, Schreiben)
2. Direct3D-Runtime übergibt die Anwendungsoberfläche an DWM
3. Nachdem die Kopie der freigegebenen Oberfläche abgeschlossen ist, rendert DWM die Anwendungsoberfläche auf dem Bildschirm (Lesen, Schreiben).
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 Arbeitsspeicherauslastung des Systems, indem die Anzahl der Lese- und Schreibvorgänge durch die Direct3D-Runtime für die Framekomposition mit Fenstern durch DWM reduziert wird. Dies reduziert den Energieverbrauch des Systems und die Gesamtspeicherauslastung.

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

Programmiermodell und APIs

Neue Video- oder Bildfrequenz-Messanwendungen, die Direct3D 9Ex-APIs unter Windows 7 verwenden, können die Speicher- und Energieeinsparungen sowie die verbesserte Präsentation nutzen, die von Flip Mode Present angeboten wird, wenn sie unter Windows 7 ausgeführt wird. (Wenn die Direct3D-Runtime unter früheren Windows-Versionen ausgeführt wird, wird die Anwendung standardmäßig auf Blt Mode Present festgelegt.)

Flip Mode Present bedeutet, dass die Anwendung das Feedback und Korrekturmechanismen für aktuelle Statistiken in Echtzeit nutzen kann, wenn DWM aktiviert ist. Anwendungen, die den Flip Mode Present verwenden, sollten sich jedoch der Einschränkungen bewusst sein, wenn sie gleichzeitiges GDI-API-Rendering verwenden.

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

So melden Sie sich für das Direct3D 9Ex Flip-Modell an

Direct3D 9Ex-Anwendungen, die auf Windows 7 ausgerichtet sind, können sich für das Flip-Modell entscheiden, indem sie die Swapchain mit dem D3DSWAPEFFECT_FLIPEX Enumerationswert erstellen. Um sich für das Flip-Modell zu entscheiden, geben Anwendungen die D3DPRESENT_PARAMETERS-Struktur an und übergeben dann einen Zeiger auf diese Struktur, wenn sie die IDirect3D9Ex::CreateDeviceEx-API aufrufen. In diesem Abschnitt wird beschrieben, wie Anwendungen für Windows 7 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.

Zur Vereinfachung wird die Syntax von D3DPRESENT_PARAMETERS und IDirect3D9Ex::CreateDeviceEx 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 Punkte zu den angegebenen Membern von D3DPRESENT_PARAMETERS berücksichtigen:

BackBufferCount

(Nur Windows 7)

Wenn SwapEffect auf den neuen D3DSWAPEFFECT_FLIPEX Swapchaineffekttyp festgelegt ist, sollte die Anzahl der Zurückpuffer gleich oder größer als 2 sein, um eine Leistungseinbuße der Anwendung zu verhindern, da auf den vorherigen Present-Puffer gewartet wird, der von DWM freigegeben wird.

Wenn die Anwendung auch aktuelle Statistiken verwendet, die D3DSWAPEFFECT_FLIPEX zugeordnet sind, empfiehlt es sich, die Anzahl des Rückpuffers 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 Swapchaineffekttyp gibt an, wann eine Anwendung flip mode Present to DWM verwendet. Es ermöglicht der Anwendung eine effizientere Nutzung von Arbeitsspeicher und Energie und ermöglicht es der Anwendung, die Vorteile von Vollbild-Präsentationsstatistiken im Fenstermodus zu nutzen. Das Verhalten der Vollbildanwendung ist nicht betroffen. Wenn Windowed auf TRUE und SwapEffect auf D3DSWAPEFFECT_FLIPEX festgelegt ist, erstellt die Laufzeit einen zusätzlichen Rückpuffer und rotiert, welches Handle zum Puffer gehört, der zur Präsentationszeit zum fronten Puffer wird.

Flags

(Nur Windows 7)

Das D3DPRESENTFLAG_LOCKABLE_BACKBUFFER-Flag kann nicht festgelegt werden, wenn SwapEffect auf den neuen D3DSWAPEFFECT_FLIPEX Swapchaineffekttyp 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 des Flip Mode Present in einem separaten HWND von Blt Mode Present

Anwendungen sollten direct3D 9Ex Flip Mode Present in einem HWND verwenden, der nicht auch von anderen APIs bestimmt ist, einschließlich Blt Mode Present Direct3D 9Ex, anderen Versionen von Direct3D oder GDI. Flip Mode Present kann verwendet werden, um untergeordnete Fenster zu präsentieren; Das heißt, Anwendungen können Flip-Modell verwenden, wenn es nicht mit Blt-Modell im gleichen HWND gemischt ist, 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 Blt Model eine zusätzliche Kopie der Oberfläche verwaltet, können GDI und andere Direct3D-Inhalte demselben HWND durch schrittweise Updates von Direct3D und GDI hinzugefügt werden. Mit dem Flip-Modell sind nur Direct3D 9Ex-Inhalte in D3DSWAPEFFECT_FLIPEX Swapchains sichtbar, die an DWM übergeben werden. Alle anderen Aktualisierungen von Blt Model Direct3D- oder GDI-Inhalten werden ignoriert, wie in den folgenden Abbildungen gezeigt.

Abbildung von gdi-Text, der möglicherweise nicht angezeigt wird, wenn das Flip-Modell verwendet wird und direct3d- und gdi-Inhalte sich im gleichen hwnd befinden

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

Daher sollte Flip Model für Swapchainpufferoberflächen aktiviert werden, auf denen das Direct3D 9Ex Flip Model allein im gesamten HWND gerendert wird.

Verwenden Sie das Flip-Modell nicht mit scrollWindow oder ScrollWindowEx von GDI.

Einige Direct3D 9Ex-Anwendungen verwenden die Funktionen ScrollWindow oder ScrollWindowEx von GDI, um den Inhalt von Fenstern zu aktualisieren, wenn ein Benutzerscrollereignis 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 beide Funktionen verwenden, zeigen nicht unbedingt sichtbare Fensterinhalte beim Scrollen 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, sondern stattdessen deren Inhalte auf dem Bildschirm als Reaktion auf den Bildlauf neu zu zeichnen.

Verwenden einer D3DSWAPEFFECT_FLIPEX Swap Chain pro HWND

Anwendungen, die Flip Model verwenden, sollten nicht mehrere Flip Model-Swapchains für dieselbe HWND verwenden.

Framesynchronisierung von Direct3D 9Ex Flip Model-Anwendungen

Die vorliegenden Statistiken sind Framezeitinformationen, die Medienanwendungen verwenden, um Video- und Audiostreams zu synchronisieren und nach Videowiedergabefehlern wiederherzustellen. Um die Verfügbarkeit der aktuellen Statistiken zu aktivieren, muss die Direct3D 9Ex-Anwendung sicherstellen, dass der BehaviorFlags-Parameter , den die Anwendung an IDirect3D9Ex::CreateDeviceEx übergibt, das Geräteverhaltensflag D3DCREATE_ENABLE_PRESENTSTATS enthält.

Der Einfachheit halber wird hier die Syntax von IDirect3D9Ex::CreateDeviceEx wiederholt.

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

Direct3D 9Ex Flip Model fügt das D3DPRESENT_FORCEIMMEDIATE Präsentationsflag hinzu, das das D3DPRESENT_INTERVAL_IMMEDIATE Präsentationsflagverhalten erzwingt. Die Direct3D 9Ex-Anwendung gibt diese Präsentationsflags im dwFlags-Parameter an, den die Anwendung an IDirect3DDevice9Ex::P resentEx ü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äsentationsflags berücksichtigen:

D3DPRESENT_DONOTFLIP

Dieses Flag ist nur im Vollbildmodus verfügbar oder

(Nur Windows 7)

, wenn die Anwendung den SwapEffect-Member von D3DPRESENT_PARAMETERS in einem Aufruf von CreateDeviceEx auf D3DSWAPEFFECT_FLIPEX festlegt.

D3DPRESENT_FORCEIMMEDIATE

(Nur Windows 7)

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

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

Um aktuelle Statistikinformationen abzurufen, ruft die Anwendung die D3DPRESENTSTATS-Struktur ab, indem sie die IDirect3DSwapChain9Ex::GetPresentStatistics-API aufruft .

Die D3DPRESENTSTATS-Struktur enthält Statistiken zu IDirect3DDevice9Ex::P resentEx-Aufrufen . Das Gerät muss mithilfe eines IDirect3D9Ex::CreateDeviceEx-Aufrufs mit dem D3DCREATE_ENABLE_PRESENTSTATS-Flag erstellt werden. Andernfalls sind die von GetPresentStatistics zurückgegebenen Daten nicht definiert. Eine Flip-Model-fähige Direct3D 9Ex-Swapkette bietet aktuelle Statistikinformationen sowohl im Fenstermodus als auch im Vollbildmodus.

Bei Direct3D 9Ex-Swapketten mit Blt-Modell-Unterstützung im Fenstermodus sind alle D3DPRESENTSTATS-Strukturwerte Nullen.

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

  • Erster Aufruf von GetPresentStatistics überhaupt, der den Beginn einer Sequenz angibt
  • DWM-Übergang von ein zu aus
  • Moduswechsel: Entweder Fenstermodus zu oder von Vollbild- oder Vollbildmodus zu Vollbildübergängen

Der Einfachheit halber wird hier die Syntax von GetPresentStatistics wiederholt.

HRESULT GetPresentStatistics(
  D3DPRESENTSTATS * pPresentationStatistics
);

Die IDirect3DSwapChain9Ex::GetLastPresentCount-Methode gibt die letzte PresentCount-ID des letzten erfolgreichen Present-Aufrufs zurück, der von einem Anzeigegerät ausgeführt wurde, das der Swapchain zugeordnet ist. Diese Gegenwarts-ID ist der Wert des PresentCount-Members der D3DPRESENTSTATS-Struktur . Bei Direct3D 9Ex-Swapketten mit Blt-Modell-Unterstützung sind im Fenstermodus alle D3DPRESENTSTATS-Strukturwerte Nullen.

Der Einfachheit halber wird hier die Syntax von IDirect3DSwapChain9Ex::GetLastPresentCount wiederholt.

HRESULT GetLastPresentCount(
  UINT * pLastPresentCount
);

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

  • Der von GetLastPresentCount zurückgegebene PresentCount-Wert wird nicht aktualisiert, wenn ein PresentEx-Aufruf mit D3DPRESENT_DONOTWAIT, der im dwFlags-Parameter angegeben ist, einen Fehler zurückgibt.
  • Wenn PresentEx mit D3DPRESENT_DONOTFLIP aufgerufen wird, ist ein GetPresentStatistics-Aufruf erfolgreich, 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-Instanz angezeigt wird.
    • SyncRefreshCount wird für das vsync-Intervall abgerufen, wenn die Gegenwart übermittelt wurde. SyncQPCTime entspricht ungefähr der 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 Windows-Anwendungen, wenn DWM deaktiviert ist

Wenn DWM deaktiviert ist, werden Fensteranwendungen direkt auf dem Monitorbildschirm angezeigt, ohne eine Flip-Kette zu durchlaufen. In Windows Vista wird das Abrufen von Framestatistikinformationen für Fensteranwendungen nicht unterstützt, wenn DWM deaktiviert ist. Um eine API beizubehalten, 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-Flipmodells und eines Aktuellen Statistikbeispiels

So wählen Sie flipEx-Präsentation für Direct3D 9Ex-Beispiel

  1. Stellen Sie sicher, dass die Beispielanwendung unter Windows 7 oder höher ausgeführt wird.
  2. Legen Sie den SwapEffect-Member von D3DPRESENT_PARAMETERS in einem Aufruf von CreateDeviceEx auf D3DSWAPEFFECT_FLIPEX 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 aktivieren Sie auch das Mit FlipEx zugeordnete Beispiel für Aktuelle Statistiken für 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;
    }

Um zu vermeiden, erkennen Und wiederherstellen von Störungen

  1. Warteschlangenanrufe: Die empfohlene Backbufferanzahl liegt zwischen 2 und 4.

  2. Das Direct3D 9Ex-Beispiel fügt einen impliziten Backbuffer hinzu, wobei die tatsächliche Aktuelle Warteschlangenlänge backbuffer count + 1 ist.

  3. Erstellen Sie eine Hilfswarteschlangenstruktur, um alle erfolgreich übermittelten Present-ID (PresentCount) und zugeordnete, berechnete/erwartete PresentRefreshCount zu speichern.

  4. So erkennen Sie das Auftreten eines Fehlers:

    • Rufen Sie GetPresentStatistics auf.
    • Rufen Sie die Aktuelle ID (PresentCount) und die vsync-Anzahl ab, in der der Frame angezeigt wird (PresentRefreshCount) des Frames, dessen aktuelle Statistiken abgerufen werden.
    • Rufen Sie die erwartete PresentRefreshCount (TargetRefresh im Beispielcode) ab, die der Present-ID zugeordnet ist.
    • Wenn der tatsächliche PresentRefreshCount höher als erwartet ist, ist ein Fehler aufgetreten.
  5. So stellen Sie die Wiederherstellung nach einer Störung her:

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

Überlegungen zur Erkennung und Wiederherstellung von Störungen

  1. Die Glitchwiederherstellung nimmt die N (g_iQueueDelay Variable im Beispielcode) anzahl von Present-Aufrufen an, wobei N (g_iQueueDelay) g_iImmediates plus Länge der Aktuellen Warteschlange entspricht, d.a.:

    • Überspringen von Frames mit D3DPRESENT_FORCEIMMEDIATE D3DPRESENT_FORCEIMMEDIATE für Gegenwartsintervall, plus
    • In die Warteschlange eingereihte Geschenke, die verarbeitet werden müssen
  2. Legen Sie einen Grenzwert auf die Fehlerlänge (GLITCH_RECOVERY_LIMIT im Beispiel) fest. Wenn die Beispielanwendung nach einem zu langen Fehler nicht wiederhergestellt werden kann (d. h. 1 Sekunde oder 60 vsyncs auf einem 60Hz-Monitor), springen Sie über die zeitweilige Animation, und setzen Sie die Warteschlange "Present helper" 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 einer Backbufferanzahl von 4. Die tatsächliche Länge der aktuellen Warteschlange beträgt daher 5.

    Abbildung einer applicas gerenderten Frames und einer vorhandenen Warteschlange

    Frame A ist darauf ausgerichtet, auf dem Bildschirm bei der Anzahl des Synchronisierungsintervalls von 1 zu wechseln, aber es wurde erkannt, dass es bei der Anzahl des Synchronisierungsintervalls von 4 angezeigt wurde. Daher ist ein Fehler aufgetreten. Nachfolgende 3 Frames werden mit D3DPRESENT_INTERVAL_FORCEIMMEDIATE angezeigt. Der Fehler sollte insgesamt 8 aktuelle Aufrufe dauern, bevor er wiederhergestellt wird. Der nächste Frame wird gemäß der Anzahl des zielbezogenen Synchronisierungsintervalls angezeigt.

Zusammenfassung der Programmierempfehlungen für die Framesynchronisierung

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

    Hinweis

    Wenn die Anwendung PresentEx mit D3DPRESENT_DONOTFLIP aufruft, ist der GetPresentStatistics-Aufruf erfolgreich, 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 aktuellen ID der angezeigten Frames zugeordnet ist, um sicherzustellen, dass die Anwendung fehlerretouren aus dem Aufruf verarbeitet.

  • Wenn der tatsächliche PresentRefreshCount höher als geschätzter PresentRefreshCount ist, wird ein Fehler erkannt. Kompensieren Sie, indem Sie verzögerte Frames mit D3DPRESENT_FORCEIMMEDIATE übermitteln.

  • Wenn ein Frame zu spät in der Warteschlange "Gegenwart" angezeigt wird, werden alle nachfolgenden Frames in der Warteschlange zu spät angezeigt. D3DPRESENT_FORCEIMMEDIATE korrigiert nur den nächsten Frame, der nach allen in die Warteschlange eingereihten Frames angezeigt wird. Daher sollte die Anzahl der Vorhandenen Warteschlangen oder Backbuffer nicht zu lang sein, sodass es weniger Framestörungen gibt, die nachgeholt werden müssen. Die optimale Backbufferanzahl beträgt 2 bis 4.

  • Wenn der geschätzte PresentRefreshCount höher als der tatsächliche PresentRefreshCount ist, ist möglicherweise eine DWM-Drosselung aufgetreten. Folgende Lösungen sind möglich:

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

    • mit dwm ein- und ausgeschaltet
    • Exklusive Vollbild- und Fenstermodi
    • Hardware mit geringeren Funktionen
  • Wenn Anwendungen mit D3DPRESENT_FORCEIMMEDIATE Vorhanden nicht aus einer 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 Workload rendern.
    • bei der Video-Decodierung schneller decodieren, indem die Qualität und damit die CPU- und GPU-Auslastung verringert werden.

Fazit zu Direct3D 9Ex-Verbesserungen

Unter Windows 7 können Anwendungen, die während der Präsentation Video- oder Bildfrequenz anzeigen, das Flip Model auswählen. Die vorliegenden Statistikverbesserungen, die mit Flip Model Direct3D 9Ex verknüpft sind, können Anwendungen zugute kommen, die die Präsentation pro Bildfrequenz synchronisieren, mit Echtzeitfeedback für die Erkennung und Wiederherstellung von Störungen. Entwickler, die das Direct3D 9Ex Flip-Modell verwenden, sollten eine separate HWND von GDI-Inhalten und die Synchronisierung der Bildfrequenz berücksichtigen. Weitere Informationen finden Sie in diesem Thema und in der MSDN-Dokumentation. Weitere Dokumentation finden Sie unter DirectX Developer Center auf MSDN.

Call-to-Action

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

DirectX Developer Center auf MSDN