Änderungen von Direct3D 10

Dieser Abschnitt gilt nur für Windows 7 und höher sowie Windows Server 2008 R2 und höhere Versionen des Windows-Betriebssystems.

In den folgenden Abschnitten wird beschrieben, wie Sich Direct3D 11 von Direct3D 10 geändert hat.

Treiberrückruffunktionen für Kernel-Mode Services

Die gerätespezifischen Rückruffunktionen, die die Direct3D Version 11-Runtime in der D3DDDI_DEVICECALLBACKS-Struktur bereitstellt, wenn die Runtime die CreateDevice(D3D10) -Funktion des Benutzermodusanzeigetreibers aufruft, isolieren den Treiber von Kernelhandles und Kernelfunktionssignaturen. Die Direct3D-Runtime, Version 11, ändert die Rückrufsemantik und damit die Implementierung der Rückruffunktionen, um einen Freethreadmodus zu unterstützen, während frühere Direct3D-Versionslaufzeiten keinen Freithreadmodus unterstützten. Die Regeln für den Vorgang im Freethreadmodus gelten, nachdem der Treiber angibt, dass er den Freethreadmodus (D3D11DDICAPS_FREETHREADED) unterstützt. andernfalls gelten die vorherigen stark eingeschränkten Regeln. Informationen dazu, wie der Treiber die Unterstützung für den Freethreadmodus angibt, finden Sie unter Threading und Befehlslisten. Für Direct3D Version 11 gelten weiterhin die folgenden Einschränkungen:

  • Nur ein einzelner Thread kann gleichzeitig mit einem HCONTEXT arbeiten. Vorhandene Rückruffunktionen, die derzeit einen HCONTEXT verwenden, sind pfnPresentCb, pfnRenderCb, pfnEscapeCb, pfnDestroyContextCb, pfnWaitForSynchronizationObjectCb und pfnSignalSynchronizationObjectCb. Wenn daher mehrere Threads diese Rückruffunktionen aufrufen und denselben HCONTEXT verwenden, muss der Treiber die Aufrufe mit den Rückruffunktionen synchronisieren. Die Erfüllung dieser Anforderung ist ganz natürlich, da diese Rückruffunktionen wahrscheinlich nur aus dem Thread aufgerufen werden, der den unmittelbaren Kontext bearbeitet.

  • Der Treiber darf die folgenden Rückruffunktionen nur bei Aufrufen der folgenden Treiberfunktionen aufrufen, indem er dieselben Threads verwendet, die diese Treiberfunktionen aufgerufen haben:

  • Die PfnDeallocateCb-Rückruffunktion verdient besondere Erwähnung, da der Treiber pfnDeallocateCb nicht aufrufen muss, bevor der Treiber von seiner DestroyResource(D3D10)-Funktion für die meisten Ressourcentypen zurückkehrt. Da DestroyResource(D3D10) eine Freethreadfunktion ist, muss der Treiber die Zerstörung des Objekts zurückstellen, bis der Treiber effizient sicherstellen kann, dass kein vorhandener direkter Kontextverweis vorhanden ist (d. a. der Treiber muss pfnRenderCb vor pfnDeallocateCb aufrufen). Diese Einschränkung gilt auch für freigegebene Ressourcen oder jede andere Rückruffunktion, die HRESOURCE verwendet, um die HRESOURCE-Nutzung mit pfnAllocateCb zu ergänzen. Diese Einschränkung gilt jedoch nicht für Vorwahlen. Weitere Informationen zu primären Ausnahmen finden Sie unter Primäre Ausnahmen. Da einige Anwendungen möglicherweise synchrone Zerstörung erfordern, muss der Treiber sicherstellen, dass er pfnDeallocateCb für alle zuvor zerstörten freigegebenen Ressourcen während eines Aufrufs seiner Flush(D3D10) -Funktion aufruft. Ein Treiber muss auch alle zuvor zerstörten Objekte bereinigen (nur diejenigen, die die Pipeline nicht zum Stillstand kommen) während eines Aufrufs seiner Flush(D3D10)-Funktion. Der Treiber muss dies tun, um sicherzustellen, dass die Runtime Flush(D3D10) als offiziellen Mechanismus aufruft, um verzögerte zerstörte Objekte für die wenigen Anwendungen zu bereinigen, die einen solchen Mechanismus erfordern. Weitere Informationen zu diesem Mechanismus finden Sie unter Verzögerte Zerstörung und Flush(D3D10). Der Treiber muss außerdem sicherstellen, dass alle Objekte, für die die Zerstörung verzögert wurde, vollständig zerstört werden, bevor die DestroyDevice(D3D10) -Funktion des Treibers während der Bereinigung zurückgegeben wird.

Veraltete Möglichkeit, Änderungen von Free-Threaded DDIs zuzulassen

Für Direct3D Version 11 werden das Konzept eines Anzeigegeräts auf API-Ebene und ein unmittelbarer Kontext weiterhin durch das Legacykonzept eines Anzeigegeräts auf DDI-Ebene gebündelt. Diese Bündelung von Anzeigegerät und unmittelbarem Kontext maximiert die Kompatibilität mit DDIs der vorherigen Version (z. B . Direct3D Version 10 DDI) und reduziert die Treiberabwanderung, wenn mehrere Versionen von APIs über mehrere Versionen von DDIs unterstützt werden. Diese Bündelung von Anzeigegerät und unmittelbarem Kontext führt jedoch zu einem verwirrenderen DDI, da die Threadingdomänen nicht sehr explizit sind. Um die Threadinganforderungen mehrerer Schnittstellen und die Funktionen innerhalb dieser Schnittstellen zu verstehen, müssen Sich Treiberentwickler stattdessen auf die Dokumentation beziehen.

Ein Hauptfeature der Direct3D-API, Version 11, besteht darin, dass mehrere Threads gleichzeitig in Erstellungs- und Zerstörungsfunktionen eintreten können. Ein solches Feature ist nicht kompatibel mit der Möglichkeit, dass der Treiber die Funktionstabellenzeiger zum Erstellen und Zerstören austauschen kann, da die Direct3D-DDI-Semantik der Version 10 für Funktionen, die in D3D10DDI_DEVICEFUNCS angegeben sind und D3D10_1DDI_DEVICEFUNCS zulässig sind. Nachdem der Treiber die Funktionszeiger für create (CreateDevice(D3D10)) zurückgibt, sollte der Treiber daher nicht versuchen, das Verhalten zu ändern, indem er diese speziellen Funktionszeiger ändert, wenn der Treiber unter direct3D Version 11 DDI ausgeführt wird und der Treiber DDI-Threading unterstützt. Diese Einschränkung gilt für alle Gerätefunktionen, die mit pfnCreate, pfnOpen, pfnDestroy, pfnCalcPrivate und pfnCheck beginnen. Alle restlichen Gerätefunktionen sind stark mit dem unmittelbaren Kontext verknüpft. Da ein einzelner Thread den unmittelbaren Kontext gleichzeitig bearbeitet, ist es gut definiert, dass der Treiber weiterhin einträge für die sofortige Kontextfunktionstabelle austauschen kann.

pfnRenderCb versus pfnPerformAmortizedProcessingCb

Die Direct3D-API-Funktionen der Version 10 haben die Kernelrückruffunktion pfnRenderCb der Direct3D-Runtime eingebunden, um eine amortisierte Verarbeitung durchzuführen (d. h., anstatt bestimmte Vorgänge für jeden API-Funktionsaufruf auszuführen, hat der Treiber für jeden so vielen API-Funktionsaufrufe amortisierte Vorgänge ausgeführt). Die API nutzt diese Gelegenheit in der Regel, um unter anderem hohe Wasserzeichen zu kürzen und ihre Warteschlange für verzögerte Objektzerstörung auszulöschen.

Damit die Kernelrückruffunktionen so frei wie möglich für den Treiber ausgeführt werden können, verwendet die Direct3D-API nicht mehr pfnRenderCb , wenn der Treiber die Direct3D-Version 11 DDI unterstützt. Daher müssen Treiber, die direct3D Version 11 DDI unterstützen, manuell die Kernelrückruffunktion pfnPerformAmortizedProcessingCb aus demselben Thread aufrufen, der in die Treiber-DDI-Funktion gelangt ist, nachdem der Treiber einen Befehlspuffer für den unmittelbaren Kontext (oder eine ähnliche Häufigkeit) übermittelt hat. Da der Vorgang hohe Wasserzeichen kürzen sollte, wäre es von Vorteil, dies zu tun, bevor der Treiber Befehlspuffer-Präambeln generiert, wenn die DDI-Rückruffunktionen für die Zustandsaktualisierung genutzt werden.

Darüber hinaus sollte der Treiber das API-Amortisierungsproblem kennen und versuchen, auszugleichen, wie oft er die Kernelrückruffunktion pfnPerformAmortizedProcessingCb verwendet. Bei einem Extrem kann der Treiber zu einer Überverarbeitung führen. Wenn der Treiber beispielsweise immer pfnPerformAmortizedProcessingCb zweimal aufgerufen hat (Back-to-Back), möglicherweise aufgrund der Verwendung mehrerer Engines, wäre es für den Treiber effizienter, pfnPerformAmortizedProcessingCb nur einmal aufzurufen. Andererseits erlaubt der Treiber der Direct3D-API möglicherweise keine Arbeit für einen ganzen Frame, wenn der Treiber nie pfnPerformAmortizedProcessingCb aufgerufen hat, möglicherweise aufgrund eines wechselnden Framerenderingentwurfs. Der Treiber muss pfnPerformAmortizedProcessingCb nicht häufiger aufrufen als natürlich, da dies übermäßig ist (wenn der Treiber z. B. pfnPerformAmortizedProcessingCb in einem Zeitrahmen von 1 Millisekunde nicht aufgerufen hat, muss es Zeit sein, die API zu pumpen). Der Treiber muss nur bestimmen, welche der vorhandenen pfnRenderCb-Aufrufe von pfnPerformAmortizedProcessingCb begleitet werden sollen und natürlich der Threadingsemantik des Vorgangs entsprechen.

Für Treiber, die Befehlslisten unterstützen, müssen diese Treiber auch pfnPerformAmortizedProcessingCb aus zurückgestellten Kontexten aufrufen, wenn diesen Treibern der Platz ausgeht (eine ähnliche Häufigkeit wie jede direkte Kontextleerung). Die Direct3D-Runtime, Version 11, erwartet, dass sie während eines solchen Vorgangs zumindest ihre Wasserzeichen mit hohem Wasserzeichen kürzen wird. Da die Threadingsemantik im Zusammenhang mit pfnRenderCb für Direct3D Version 11 gelockert wurde, müssen Parallelitätsprobleme gelöst werden, damit Direct3D Version 11 weiterhin pfnRenderCb ohne Einschränkung einbinden kann.

Neuer DDI-Fehlercode

Der D3DDDIERR_APPLICATIONERROR Fehlercode wird erstellt, damit Treiber an der Überprüfung teilnehmen können, wenn die Direct3D-API version 11 dies nicht getan hat. Wenn der Treiber zuvor den E_INVALIDARG Fehlercode zurückgegeben hat, löste die API eine Ausnahme aus. Das Vorhandensein der Debugebene würde eine Debugausgabe verursachen und darauf hinweisen, dass der Treiber einen internen Fehler zurückgegeben hat. Die Debugausgabe würde dem Entwickler vorschlagen, dass beim Treiber ein Fehler aufgetreten ist. Wenn der Treiber D3DDDIERR_APPLICATIONERROR zurückgibt, bestimmt die Debugebene stattdessen, dass die Anwendung einen Fehler hat.

Rückwirkende Anforderung Free-Threaded CalcPrivate-DDIs

Direct3D, Version 11, erfordert rückwirkend, dass Treiberfunktionen, die mit pfnCalcPrivate in Direct3D Version 10 DDI-Funktionen beginnen, frei threaded sein müssen. Diese rückwirkende Anforderung entspricht dem Verhalten von Direct3D, Version 11 DDI, dass immer erforderlich ist, dass die Funktionen pfnCalcPrivate* und pfnCalcDeferredContextHandleSize frei threaded sein müssen, auch wenn der Treiber angibt, dass DDI-Threading nicht unterstützt wird. Weitere Informationen zu dieser rückwirkenden Anforderung finden Sie unter Rückwirkende Anforderung Free-Threaded CalcPrivate DDIs.

Verzögerte Zerstörung und Leerung D3D10

Da alle Zerstörungsfunktionen jetzt Freithreads sind, kann die Direct3D-Runtime während der Zerstörung keinen Befehlspuffer leeren. Daher müssen die Zerstörungsfunktionen die tatsächliche Zerstörung eines Objekts zurückstellen, bis der Treiber sicherstellen kann, dass der Thread, der den unmittelbaren Kontext bearbeitet, nicht mehr von diesem Objekt abhängig ist, um zu überleben. Jede diskrete Methode des unmittelbaren Kontexts kann die Synchronisierung nicht effizient verwenden, um dieses Zerstörungsproblem zu lösen. Daher sollte der Treiber die Synchronisierung nur verwenden, wenn er einen Befehlspuffer leert. Die Direct3D-Runtime verwendet auch diesen Entwurf, wenn sie mit ähnlichen Problemen umgehen muss.

Aufgrund der Ratifizierung der verzögerten Zerstörung spricht sich die Direct3D-Runtime dafür aus, dass anwendungen, die keine Problemumgehungen für verzögerte Zerstörung tolerieren können, stattdessen explizite Mechanismen verwenden. Daher muss der Treiber seine Warteschlange für verzögerte Zerstörung während der Aufrufe seiner Flush(D3D10) -Funktion verarbeiten (auch wenn der Befehlspuffer leer ist), um sicherzustellen, dass diese Mechanismen tatsächlich funktionieren.

Anwendungen, die eine Form der synchronen Zerstörung erfordern, müssen eines der folgenden Muster verwenden, je nachdem, wie schwer eine Zerstörung sie benötigen:

  • Nachdem die Anwendung sichergestellt hat, dass alle Abhängigkeiten von diesem Objekt freigegeben werden (d. a. Befehlslisten, Ansichten, Middleware usw.), verwendet die Anwendung das folgende Muster:

    Object::Release(); // Final release
    ImmediateContext::ClearState(); // Remove all ImmediateContext references as well.
    ImmediateContext::Flush(); // Destroy all objects as quickly as possible.
    
  • Das folgende Muster ist eine schwerere Zerstörung:

    Object::Release(); // Final release
    ImmediateContext::ClearState(); // Remove all ImmediateContext references as well.
    ImmediateContext::Flush();
    ImmediateContext::End( EventQuery );
    while( S_FALSE == ImmediateContext::GetData( EventQuery ) ) ;
    ImmediateContext::Flush(); // Destroy all objects, completely.
    

Primäre Ausnahmen

Vorwahlen sind Ressourcen, die die Runtime in Aufrufen der CreateResource(D3D11) -Funktion des Treibers erstellt. Die Runtime erstellt einen primären, indem das pPrimaryDesc-Element der D3D11DDIARG_CREATERESOURCE-Struktur auf einen gültigen Zeiger auf eine DXGI_DDI_PRIMARY_DESC-Struktur festgelegt wird. Vorwahlen haben die folgenden wichtigen Ausnahmen in Bezug auf die vorherigen Änderungen von Direct3D 10 zu Direct3D 11:

  • Sowohl die Funktionen CreateResource(D3D11) als auch DestroyResource(D3D10) des Treibers für Vorwahlen sind nicht Freithreads und teilen sich die direkte Kontextthreadingdomäne. Parallelität kann weiterhin mit Funktionen vorhanden sein, die mit pfnCreate und pfnDestroy beginnen, einschließlich CreateResource(D3D11) und DestroyResource(D3D10). Bei Vorwahlen kann jedoch keine Parallelität mit CreateResource(D3D11) und DestroyResource(D3D10) vorhanden sein. Beispielsweise kann der Treiber erkennen, dass ein Aufruf seiner CreateResource(D3D11)- oder DestroyResource(D3D10)-Funktion für eine primäre Funktion gilt, und dadurch feststellen, dass er den unmittelbaren Kontextspeicher für die Dauer des Funktionsaufrufs sicher verwenden oder berühren kann.

  • Die primäre Zerstörung kann nicht von der Direct3D-Runtime zurückgestellt werden, und der Treiber muss die PfnDeallocateCb-Funktion in einem Aufruf der DestroyResource(D3D10) -Funktion des Treibers entsprechend aufrufen.