Freigeben über


Unterstützung von Befehlslisten

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

Die Direct3D-Runtime verwendet die folgenden Direct3D 11 DDI für Befehlslisten:

Die Semantik für die Funktionen CommandListExecute, CalcPrivateCommandListSize, CreateCommandList und DestroyCommandList des Treibers ist größtenteils selbsterklärend und basiert auf anderen ähnlichen DDI-Funktionen und der API-Dokumentation für die entsprechende DDI.

Nachdem die Direct3D-Runtime erfolgreich die Funktion CreateCommandList oder RecycleCreateCommandList des Treibers für den Deferred-Kontext aufgerufen hat, der im hDeferredContext-Mitglied der D3D11DDIARG_CREATECOMMANDLIST-Struktur angegeben ist, auf die der pCreateCommandList-Parameter zeigt, führt die Direct3D-Runtime die folgende Zerstörungssequenz für den Deferred-Kontext durch:

  1. Die Direct3D-Runtime „schließt“ alle geöffneten Handles für Deferred-Objekte. Beachten Sie, dass diese Handles möglicherweise noch an den Deferred-Kontext gebunden sind.

  2. Die Runtime zerstört den Deferred-Kontext.

Während des Aufrufs von CreateCommandList oder RecycleCreateCommandList geben alle Aufrufe, die der Treiber an die state-refresh DDI Callback-Funktionen macht, weiterhin den aktuellen Zustand des Deferred-Kontext zurück. Während des „Schließens“ und der Zerstörung des Deferred-Kontexts spiegeln jedoch alle Aufrufe der state-refresh DDI wider, dass nichts gebunden ist (d. h. unmittelbar nach dem Aufruf von CreateCommandList oder RecycleCreateCommandList ist alles implizit ungebunden).

Ein Deferred-Kontext kann auch aufgegeben werden, entweder explizit von der Anwendung oder aufgrund einer Fehlerbedingung der API oder des Treibers. In solchen Fällen führt die Direct3D-Runtime die folgende Sequenz aus:

  1. Die Direct3D-Runtime ruft die Funktion AbandonCommandList des Treibers auf.

  2. Die Runtime hebt die Bindung von Handles aus dem Deferred-Kontext auf, und zwar einen nach dem anderen.

  3. Die Runtime „schließt“ alle offenen Handles des Deferred-Objekt.

  4. Die Runtime recycelt den Deferred-Kontext entweder oder zerstört ihn.

Die vorangehende Sequenz ähnelt der Zerstörungssequenz eines Immediate-Kontexts. Der Aufruf der Funktion AbandonCommandList des Treibers bietet dem Treiber die Gelegenheit, den Status in den vom Treiber gewünschten Zustand zu bringen.

Während des Aufrufs der Funktion CommandListExecute des Treibers muss der Treiber den Zustand des Deferred-Kontexts so wechseln, dass er dem Zustand entspricht, in dem das Gerät erstellt wurde. Dieser Vorgang wird auch als „clear-state“-Vorgang bezeichnet. Während des Aufrufs der Funktion CommandListExecute des Treibers spiegeln jedoch alle Aufrufe, die der Treiber an die state-refresh DDI Callback-Funktionen macht, immer noch den Zustand dessen wider, was beim letzten DDI-Aufruf an eine Treiberfunktion gebunden war. Beim nächsten DDI-Aufruf einer Treiberfunktion zeigen alle Aufrufe, die der Treiber an die state-refresh DDI-Callback-Funktionen macht, den aktuellen Zustand als vollständig leer an, was den impliziten Zustandswechsel von CommandListExecute widerspiegelt. Diese Tatsache weicht leicht von der typischen Semantik und dem Verhalten der state-refresh DDI Callback-Funktionen ab. Wenn der Treiber eine state-refresh DDI Callback-Funktion während eines Aufrufs einer der SetShader-Funktionen des Treibers aufgerufen hätte, würde die state-refresh DDI Callback-Funktion den neuen Shader, der gebunden wird, als bereits gebunden anzeigen. Dieses abweichende Verhalten des state-refresh DDI-Callbacks bietet dem Treiber mehr Flexibilität, um den alten Zustand während CommandListExecute zu reflektieren.

Die Direct3D Version 11 API stellt sicher, dass keine Abfrage sowohl von der Befehlsliste manipuliert (d. h. QueryBegin oder QueryEnd darauf aufgerufen) als auch nur von dem Kontext „begonnen“ wurde, der versucht, die Befehlsliste auszuführen. Die API stellt außerdem sicher, dass keine Befehlsliste, die die Zuordnung einer dynamischen Ressource aufgezeichnet hat, in einem Kontext ausgeführt wird, in dem dieselbe Ressource aktuell zugeordnet ist. Bevor eine Anwendung die Funktion FinishCommandList aufruft, ruft die Direct3D Runtime die DDI-Funktionen QueryEnd und ResourceUnmap des Treibers für jede Abfrage oder dynamische Ressource auf, die noch eine begonnene Abfrage oder zugeordnete Ressource offen hält, da FinishCommandList implizit Abfragebereiche beendet und jede zugeordnete Ressource aufhebt.

Optimierung für kleine Befehlslisten

Eine Optimierung der Speicherwiederverwendung für Befehlslisten mit geringem Speicherbedarf kann wichtig sein, um Konflikte zwischen den Aufrufen von DDI-Funktionen für Befehlslisten zu verringern und den Overhead bei der Verarbeitung von Aufrufen zu reduzieren, der für Befehlslisten erforderlich ist. Der Verarbeitungsaufwand, der mit jeder Befehlsliste verbunden ist, ist erheblich. Diese Optimierung ist für Befehlslisten gedacht, bei denen der Verarbeitungsaufwand, der für die Befehlslisten erforderlich ist, die CPU-Zeit und den Speicherplatz, der für die Befehlslisten benötigt wird, dominiert. Eine Befehlsliste mit geringem Speicherbedarf ist z. B. ein einzelner Grafikbefehl wie CopyResource. Die Anforderung an den Speicherplatz für CopyResource sind zwei Zeiger. CopyResource erfordert jedoch immer noch die gleiche Menge an Befehlslistenaufrufen wie eine Befehlsliste mit großem Speicherplatzbedarf. Wenn Befehlslisten mit geringem Speicherbedarf sehr häufig generiert werden, wird der Verarbeitungsaufwand, der für die Runtime erforderlich ist, um die Funktionen CreateCommandList, DestroyCommandList, CreateDeferredContext und DestroyDevice(D3D10) (für den Deferred-Kontext) des Treibers aufzurufen, immer wichtiger. Der Speicher, auf den hier Bezug genommen wird, ist der Systemspeicher, in dem die Datenstrukturen des Treibers gespeichert sind, einschließlich des Speichers für DDI-Handles.

Die Funktion RecycleCommandList des Treibers muss den Treiber benachrichtigen, wenn Treiber-Handles nicht mehr verwendet werden (aber noch nicht gelöscht sind) und wenn zuvor unbenutzte Treiber-Handles wieder verwendet werden. Diese Benachrichtigung gilt sowohl für CommandList- als auch für Deferred-Kontext-Handles. Der einzige Speicher, den der Treiber recyceln muss, ist der Speicher, auf den das DDI-Handle zeigt. Das Ziel von RecycleCommandList ist es zwar, den mit dem Handle verbundenen Speicher zu recyceln, aber aus Gründen der Effizienz hat der Treiber die volle Flexibilität, den zu recycelnden Speicher auszuwählen. Der Treiber kann die Größe der Speicherregion, auf die das Handle der Immediate-Kontext-Befehlsliste zeigt, nicht ändern. Diese Größe ist der Rückgabewert von CalcPrivateCommandListSize. Der Treiber kann auch nicht die Größe der Speicherregion ändern, auf die das lokale Handle der Kontextbefehlsliste zeigt. Diese Größe ist der Rückgabewert von CalcDeferredContextHandleSize.

Die DDI-Funktionen RecycleCreateCommandList und RecycleCreateDeferredContext des Treibers müssen Out-of-Memory-Fehlercodes als E_OUTOFMEMORY HRESULT-Werte zurückgeben. Diese Funktionen liefern solche Fehlercodes nicht durch Aufrufe der Funktion pfnSetErrorCb. Diese Anforderung an den Treiber verhindert, dass die Runtime eine geräteweite Synchronisierung verwenden muss, um auf unmittelbare Kontextfehler dieser Treiberfunktionen vom Typ create zu achten. Die Suche nach diesen Fehlern würde bei Befehlslisten mit geringem Speicherplatz zu katastrophalen Konflikten führen.

Die Unterschiede zwischen den Funktionen RecycleDestroyCommandList, RecycleCommandList und RecycleCreateCommandList des Treibers sind wichtig. Zu ihren Funktionen gehören die folgenden.

RecycleDestroyCommandList

Die Runtime ruft die Funktion RecycleDestroyCommandList des Treibers auf, um dem Treiber mitzuteilen, dass eine schlanke Zerstörung erforderlich ist. Das heißt, der Treiber sollte die Zuweisung des Speichers für das DDI-Befehlslisten-Handle noch nicht aufheben. Die Funktion RecycleDestroyCommandList des Treibers ist genauso wie die Funktion DestroyCommandList des Treibers nicht Thread-gebunden.

RecycleCommandList

Die Funktion RecycleCommandList des Treibers informiert den Treiber darüber, dass die Runtime ein Befehlslisten-Handle zurück in den Deferred-Kontext-Cache integriert hat. Die Funktion bietet dem Treiber dann die Gelegenheit, den mit der Befehlsliste verbundenen Speicher wieder in den Deferred-Kontext-Cache zu integrieren. Die Runtime ruft die Funktion RecycleCommandList des Treibers aus dem Deferred-Kontext-Thread auf. Die RecycleCommandList-DDI-Funktion reduziert die Notwendigkeit für den Treiber, eine eigene Synchronisierung durchzuführen.

RecycleCreateCommandList

Die Runtime ruft die Funktion RecycleCreateCommandList des Treibers auf, um ein zuvor nicht verwendetes DDI-Handle wieder vollständig gültig zu machen.

Diese Recycling-DDI-Funktionen bieten Gelegenheiten zur Optimierung, um Ressourcen für Befehlslisten mit geringem Speicherbedarf zu recyceln. Der folgende Pseudocode zeigt die Implementierung der Runtime durch den Flow der Funktionsaufrufe von der API zum DDI :

::FinishCommandList()
{
  // Empty InterlockedSList, integrating into the cache
  Loop { DC::pfnRecycleCommandList }

  If (Previously Destroyed CommandList Available)
 { IC::pfnRecycleCreateCommandList }
 else
  {
    IC::pfnCalcPrivateCommandListSize
    IC::pfnCreateCommandList
    IC::pfnCalcDeferredContextHandleSize(D3D11DDI_HT_COMMANDLIST)
  }

  Loop { DC::pfnDestroy* (context-local handle destroy) }

  IC::pfnRecycleCreateDeferredContext
}
...
Sporadic: DC::pfnCreate* (context-local open during first-bind per CommandList)

CommandList::Destroy()
{
  // If DC still alive, almost always recycle:
  If (DC still alive)
 { IC::pfnRecycleDestroyCommandList }
  Else
 { IC::pfnDestroyCommandList }
  // Add to InterlockedSList
}

Das folgende Zustandsdiagramm zeigt die Gültigkeit eines DDI-Befehlslisten-Handles im Immediate-Kontext. Der grüne Zustand stellt ein Handle dar, das mit CommandListExecute verwendet werden kann.

Diagramm zur Veranschaulichung der Gültigkeitszustände eines DDI-Befehlslisten-Handles im Immediate-Kontext.