Share via


Verwenden Context-Local DDI-Handles

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

Jedes Objekt (z. B. Ressource, Shader usw.) verfügt über kontextlokale DDI-Handles.

Angenommen, ein Objekt wird mit drei verzögerten Kontexten verwendet. In dieser Situation verweisen vier Handles auf dasselbe Objekt (ein Handle für jeden verzögerten Kontext und ein weiteres Handle für den unmittelbaren Kontext). Da jeder Kontext gleichzeitig von einem Thread bearbeitet werden kann, stellt ein kontextlokales Handle sicher, dass mehrere CPU-Threads nicht mit ähnlichem Arbeitsspeicher konkurrieren (entweder absichtlich oder unbeabsichtigt). Kontextlokale Handles sind auch intuitiv, da der Treiber wahrscheinlich einen Großteil dieser Daten ändern muss, die ohnehin logisch pro Kontext zugeordnet sind (z. B. kann das Objekt an den Kontext gebunden sein usw.).

Es gibt immer noch die Unterscheidung zwischen einem unmittelbaren Kontexthandle und einem verzögerten Kontexthandle. Insbesondere wird garantiert, dass es sich bei dem unmittelbaren Kontexthandle um den ersten zugeordneten Handle und um das letzte Handle handelt, das zerstört wird. Das entsprechende direkte Kontexthandle wird beim "Öffnen" jedes verzögerten Kontexthandles bereitgestellt, um sie miteinander zu verknüpfen. Es gibt derzeit kein Konzept, dass ein Objekt über ein DDI-Handle pro Gerät verfügt (d. h. ein Handle, das vor dem unmittelbaren Kontexthandle erstellt und nach dem unmittelbaren Kontexthandle zerstört wird und nur in der Reihenfolge bei der Erstellung des Kontexthandles referenziert wird).

Einige Handles verfügen über Abhängigkeitsbeziehungen mit anderen Handles (z. B. haben Ansichten eine Abhängigkeit von der entsprechenden Ressource). Die Für den unmittelbaren Kontext vorhandene Garantie für die Erstellungs- und Zerstörungsreihenfolge wird auch auf verzögerte Kontexthandles erweitert (d. a. die Runtime erstellt ein kontextlokales Ressourcenhandle, bevor die Runtime kontextlokale Ansichtshandles für diese Ressource erstellt, und die Laufzeit zerstört ein kontextlokales Ressourcenhandle, nachdem die Laufzeit alle Kontextlokalansichtshandles für diese Ressource zerstört hat). Wenn die Runtime ein kontextlokales Handle erstellt, stellt die Runtime auch die entsprechenden kontextlokalen Abhängigkeitshandles bereit.

Treiberdatenorganisation

Es gibt einige Bedenken in Bezug auf Treiberdaten organization, die Aufmerksamkeit erfordern. Wie Direct3D, Version 10, kann die richtige Lokalität von Daten Cachefehler zwischen der API und dem Treiber reduzieren. Die richtige Lokalität von Daten kann auch das Cache-Thrashing verhindern, das auftritt, wenn mehrere Teile häufig zugegriffener Daten in denselben Cacheindex aufgelöst werden und die Assoziativität des Caches erschöpft wird. Der DDI wurde seit Direct3D Version 10 entwickelt, um zu verhindern, dass sich solche Probleme manifestieren, indem der Treiber die API darüber informiert, wie viel Arbeitsspeicher der Treiber benötigt, um einen Handle zu erfüllen, und die API, die den Wert des Handles zuweist. Neue Threadprobleme wirken sich jedoch auf den DDI-Entwurf im Direct3D-Zeitrahmen, Version 11, aus.

Natürlich bieten kontextlokale Handles eine Möglichkeit zum Zuordnen von Objektdaten pro Kontext, wodurch Konflikte zwischen Threads vermieden werden. Da solche Daten jedoch für jeden verzögerten Kontext repliziert werden, ist die Größe dieser Daten ein großes Problem. Dies bietet die natürliche Rationalisierung, um schreibgeschützte Daten zwischen dem unmittelbaren Kontexthandle und den verzögerten Kontexthandles freizugeben. Beim Erstellen von verzögerten Kontexthandles wird das direkte Kontexthandle bereitgestellt, um die Verbindung zwischen Handles herzustellen. Alle Daten, die sich außerhalb des zurückgestellten Kontexts befinden, können jedoch Lokalitätsvorteile mit API-Daten erzielen, und die zusätzliche Indirektierungsebene zu schreibgeschützten Daten verhindert, dass Lokalitätsvorteile auf die schreibgeschützten Daten ausgeweitet werden. Einige schreibgeschützte Daten können in jede Kontexthandle-Region repliziert werden, wenn die Lokalitätsvorteile die Datenduplizierung rechtfertigen. Der Arbeitsspeicher, der die einzelnen verzögerten Kontexthandles sichert, sollte jedoch mit einem solchen Premium-Wert berücksichtigt werden, dass es sich lohnen könnte, daten, die nicht an den Handle angepasst sind, zu verschieben, wenn diese Daten relativ groß sind und nicht so häufig auf sie zugegriffen wird wie andere Daten. Im Idealfall ist der Datentyp, der jedem verzögerten Kontexthandle zugeordnet ist, sowieso alle Hochfrequenzdaten; daher wären die Daten nicht groß genug, um eine Verlagerung für notwendig zu halten. Natürlich muss der Fahrer diese widersprüchlichen Beweggründe ausgleichen.

Um das Design der Treiberdaten effizient kompatibel mit Direct3D Version 10 zu machen, aber nicht in der Implementierung unterschiedlich, sollten die schreibgeschützten Daten zusammenhängend (aber immer noch von und nach getrennt) die unmittelbaren Kontextdaten befinden. Wenn der Treiber diesen Entwurf verwendet, muss sich der Treiber bewusst sein, dass zwischen den daten des unmittelbaren Kontexthandles und den schreibgeschützten Daten eine Cachezeile erforderlich ist. Da ein Thread die einzelnen Kontexthandledaten häufig (wenn nicht gleichzeitig) bearbeitet werden kann, treten zwischen den Daten des unmittelbaren Kontexthandles und den daten des verzögerten Kontexthandles Strafen bei falscher Freigabe auf, wenn keine Cachezeilenauffüllung verwendet wird. Der Treiberentwurf muss sich der Bestrafung falscher Freigaben auskennen, die sich manifestieren, wenn Zeiger regelmäßig zwischen Kontexthandlespeicherbereichen eingerichtet und durchlaufen werden.

Die Direct3D-Runtime verwendet die folgenden Direct3D 11 DDI für verzögerte kontextbezogene lokale Handles:

Damit die Direct3D-Runtime die vom Treiber erforderliche Größe des verzögerten Kontexthandles abrufen kann, müssen die vorherigen DDI-Funktionen verwendet werden. Unmittelbar nach der Erstellung eines Objekts für den unmittelbaren Kontext ruft die Runtime CalcDeferredContextHandleSize auf, um den Treiber nach dem Speicherplatz abzufragen, den der Treiber benötigt, um verzögerte Kontexthandles für dieses Objekt zu erfüllen. Die Direct3D-API muss jedoch ihren CLS-Speicherzuteilung optimieren, indem sie bestimmt, wie viele eindeutige Handlegrößen und deren Werte zugegriffen wird. die Runtime ruft die CheckDeferredContextHandleSizes-Funktion des Treibers auf, um diese Informationen abzurufen. Daher fordert die API während der Geräteinstanziierung ein Array von verzögerten Kontexthandlesgrößen durch doppelte Abfrage an. Die erste Umfrage besteht darin, anzufordern, wie viele Größen zurückgegeben werden, während die zweite Umfrage in einem Array übergeht, um den Wert jeder Größe abzurufen. Der Treiber muss angeben, wie viel Arbeitsspeicher er benötigt, um ein Handle zusammen mit welchem Handletyp zu erfüllen. Der Treiber kann mehrere Größen zurückgeben, die einem bestimmten Handletyp zugeordnet sind. Es ist jedoch nicht definiert, dass der Treiber jemals einen Wert von CalcDeferredContextHandleSize zurückgibt, der nicht auch im CheckDeferredContextHandleSize-Array entsprechend zurückgegeben wurde.

Beim Erstellen der DDI-Handles werden die Create-Methoden für den verzögerten Kontext verwendet. Untersuchen Sie beispielsweise die Funktionen CreateBlendState(D3D10_1) und DestroyBlendState . Der HDEVICE verweist natürlich auf den entsprechenden verzögerten Kontext (im Gegensatz zum unmittelbaren Kontext); andere CONST-Strukturzeiger sind NULL (vorausgesetzt, das Objekt verfügt über keine Abhängigkeiten); und das D3D10DDI_HRT*-Handle ist ein D3D10DDI_H*-Handle für das entsprechende unmittelbare Kontextobjekt.

Für Objekte, die Abhängigkeiten aufweisen (z. B. Haben Ansichten eine Abhängigkeitsbeziehung zu ihrer entsprechenden Ressource), ist der Strukturzeiger, der das Abhängigkeitshandle bereitstellt, nicht NULL. Das einzige gültige Element der Struktur ist jedoch das Abhängigkeitshandle. während die restlichen Elemente mit null gefüllt sind. Beispielsweise ist der D3D11DDIARG_CREATESHADERRESOURCEVIEW Zeiger in einem Aufruf der CreateShaderResourceView(D3D11) -Funktion des Treibers nicht NULL , wenn die Runtime diese Funktion in einem verzögerten Kontext aufruft. In diesem CreateShaderResourceView(D3D11)-Aufruf weist die Runtime dem hDrvResource-Member von D3D11DDIARG_CREATESHADERRESOURCEVIEW das entsprechende kontextlokale Handle für die Ressource zu. Die restlichen Mitglieder von D3D11DDIARG_CREATESHADERRESOURCEVIEW sind jedoch mit 0 0 gefüllt.

Der folgende Beispielcode zeigt, wie die Direct3D-Runtime die Erstellungsanforderung einer Anwendung und die erste Verwendung des verzögerten Kontexts für Aufrufe des Benutzermodusanzeigetreibers übersetzt, um sofortige und verzögerte Kontexte zu erstellen. Der Aufruf von ID3D11Device::CreateTexture2D der Anwendung initiiert den Laufzeitcode im folgenden Abschnitt "Resource Create". Der Aufruf der Anwendung an ID3D11Device::CopyResource initiiert den Laufzeitcode im folgenden Abschnitt "Verzögerte Kontextressourcennutzung".

// Device Create
 IC::pfnCheckDeferredContextHandleSizes( hIC, &u, NULL );
pArray = malloc( u * ... );
IC::pfnCheckDeferredContextHandleSizes( hIC, &u, pArray );

// Resource Create
 s = IC::pfnCalcPrivateResourceSize( hIC, &Args );
pICRHandle = malloc( s );
 IC::pfnCreateResource( hIC, &Args, pICRHandle, hRTResource );
 s2 = IC::pfnCalcDeferredContextHandleSize( hIC, D3D10DDI_HT_RESOURCE, pICRHandle );

// Deferred Context Resource Usage
pDCRHandle = malloc( s2 );
 DC::pfnCreateResource( hDC, NULL, pDCRHandle, pICRHandle );

Probleme mit pfnSetErrorCb

Keine der Create-Funktionen gibt einen Fehlercode zurück, der für das Threadingmodell der Direct3D-Version 11 ideal gewesen wäre. Alle Create-Funktionen verwenden pfnSetErrorCb , um Fehlercodes aus dem Treiber abzurufen. Um die Kompatibilität mit dem Direct3D-Treibermodell der Version 10 zu maximieren, wurden keine neuen DDI-Erstellungsfunktionen eingeführt, die Fehlercodes zurückgeben. Stattdessen muss der Treiber weiterhin den einheitlichen Geräte-/unmittelbaren Kontext verwenden, D3D10DDI_HRTCORELAYER mit pfnSetErrorCb während der Erstellungsfunktionen umgehen. Wenn der Treiber Befehlslisten unterstützt, sollte der Treiber die entsprechende pfnSetErrorCb verwenden, die dem entsprechenden Kontext zugeordnet ist. Das heißt, verzögerte Kontextfehler sollten an den bestimmten verzögerten Kontextaufruf von pfnSetErrorCb mit dem entsprechenden Handle usw. gehen.

Zurückgestellte Kontexte können E_OUTOFMEMORY über einen Aufruf von pfnSetErrorCb von DDI-Funktionen zurückgeben, die zuvor nur D3DDDIERR_DEVICEREMOVED zugelassen haben (z. B . Draw, SetBlendState usw.), da die Anforderungen an den verzögerten Kontextspeicher mit jedem Aufruf einer DDI-Funktion ständig wachsen. Die Direct3D-API löst eine lokale Kontextentfernung aus, um den Treiber bei einem solchen Fehlerfall zu unterstützen, der die teilweise erstellte Befehlsliste effektiv auslöscht. Die Anwendung ermittelt weiterhin, dass sie eine Befehlsliste aufzeichnet. Wenn die Anwendung jedoch schließlich die Funktion FinishCommandList aufruft, gibt FinishCommandList einen Fehlercode von E_OUTOFMEMORY zurück.