Bewährte Methoden für die Ressourcenverwaltung

Verwaltete Texturen, auch als automatische Texturverwaltung bezeichnet, sind in DirectX seit Version 6 verfügbar, mit mehreren Überarbeitungen und Verbesserungen in nachfolgenden Releases. Ab der Veröffentlichung der Direct3D 9-API umfasst die automatische Ressourcenverwaltung die Unterstützung für Texturen, Vertexpuffer und Indexpuffer, die alle über eine konsistente freigegebene Schnittstelle verfügen. Durch die Verwendung des Direct3D-Ressourcen-Managers können Anwendungen die Behandlung von Verloren gegangenen Geräten erheblich vereinfachen und sich auf das System verlassen, um eine angemessene Überlastung von Videospeicherressourcen zu bewältigen.

Entwickler haben manchmal Probleme mit der Verwendung verwalteter Ressourcen, teilweise aufgrund der abstrakten Natur des Systems. Während viele häufige Szenarien für Ressourcen gut für verwaltete Ressourcen geeignet sind, funktionieren einige Fälle besser, wenn nicht verwaltete Ressourcen verwendet werden. In diesem Artikel werden bewährte Methoden für den Allgemeinen Umgang mit Ressourcen sowie das Verhalten verwalteter und nicht verwalteter Ressourcen erläutert, und es werden einige Details dazu erläutert, wie Ressourcen in der Regel von der Laufzeit und den Treibern behandelt werden.

In diesem Artikel werden die folgenden Konzepte behandelt:

Videospeicher

Damit das Videosystem eine Ressource verwenden kann, muss sie sich im Arbeitsspeicher befinden, auf den die GPU zugreifen kann. Der lokale Videospeicher bietet die beste Leistung für die GPU, und bestimmte Ressourcen (z. B. Renderziele und Tiefen-/Schablonenpuffer) müssen sich im lokalen Videospeicher befinden. Mit dem Aufkommen von AGP kann die GPU auch direkt auf einen Teil des Systemspeichers zugreifen. Dieser Speicherbereich, der als AGP-Blende bezeichnet wird, wird als nicht lokaler Videospeicher bezeichnet und steht nicht für andere Zwecke zur Verfügung. Der nicht lokale Videospeicher kann von der CPU gelesen und in diesen geschrieben werden, die in der Regel keinen hochleistungsorientierten Zugriff auf den lokalen Videospeicher hat und daher ideal für die Verwendung als freigegebene Speicherressource ist. Eine wichtige Sache, die Sie beim AGP-Speicher beachten sollten, ist, dass er wie der lokale Videospeicher in Situationen mit verlorenen Geräten ungültig ist und persistente Ressourcen, die sich dort befinden, wiederhergestellt werden müssen.

Abbildung 1. Beziehung von GPU, CPU, Video-RAM und System-RAM

Beziehung von GPU, CPU, Video-RAM und System-RAM

Einige integrierte Videolösungen verwenden eine Einheitliche Speicherarchitektur (Unified Memory Architecture, UMA), bei der Standard Arbeitsspeicher von allen Komponenten der Systeme adressierbar ist. Direct3D unterstützt UMA, ohne dass änderungen an der Anwendung erforderlich sind. Dabei werden dieselben Hinweise wie für lokale Videospeicherkonfigurationen verwendet. Für solche Systeme befinden sich Ressourcen immer im Systemspeicher, und der Treiber ist dafür verantwortlich, sicherzustellen, dass Ressourcen ähnlich wie in einer herkömmlicheren Architektur funktionieren, während er die Uma-Eigenschaften und jedes spezifische Verhalten der Hardwareimplementierung nutzt.

Abbildung 2. GPU und CPU haben gleichen Zugriff auf System-RAM in einer einheitlichen Speicherarchitektur

GPU und CPU haben gleichen Zugriff auf System-RAM in einer einheitlichen Speicherarchitektur

Verwaltete Ressourcen

Die Meisten Ihrer Ressourcen sollten als verwaltete Ressourcen in POOL_MANAGED erstellt werden. Alle Ihre Ressourcen werden im Systemspeicher erstellt und dann nach Bedarf in den Videospeicher kopiert. Situationen mit verlorenen Geräten werden automatisch aus der Systemspeicherkopie behandelt. Da nicht alle verwalteten Ressourcen gleichzeitig in den Videospeicher passen müssen, können Sie den Arbeitsspeicher überlasten, wobei nur ein kleinerer Videoarbeitsspeicherarbeitssatz für ressourcen erforderlich ist, um in einem bestimmten Frame gerendert zu werden. Beachten Sie, dass es wahrscheinlich ist, dass der Großteil dieses Sicherungsspeichersystemspeichers im Laufe der Zeit auf den Datenträger ausgelagert wird, weshalb der Vorgang zum Zurücksetzen langsam sein kann, da diese Daten zurückgefragt werden müssen, um den verlorenen Videospeicher wiederherzustellen.

Die Runtime behält einen Zeitstempel für die letzte Verwendung einer Ressource bei. Wenn eine Videospeicherbelegung beim Laden einer benötigten verwalteten Ressource fehlschlägt, werden ressourcen basierend auf diesem Zeitstempel auf LRU-Weise freigegeben. Die Verwendung von SetPriority hat Vorrang vor dem Zeitstempel, sodass häufiger verwendete Ressourcen auf einen höheren Prioritätswert festgelegt werden sollten. Direct3D 9.0 verfügt über begrenzte Informationen über den vom Treiber verwalteten Videospeicher, sodass die Laufzeit möglicherweise mehrere Ressourcen entfernen muss, um eine ausreichend große Region zu erstellen, damit die Zuordnung erfolgreich ist. Richtige Prioritäten können dazu beitragen, Situationen zu beseitigen, in denen etwas entfernt wird und kurz danach wieder benötigt wird. Die Anwendung kann auch EvictManagedResources aufrufen, um zu erzwingen, dass alle verwalteten Ressourcen entfernt werden. Auch dies kann ein zeitaufwändiger Vorgang sein, um alle Ressourcen neu zu laden, die für den nächsten Frame erforderlich sind, ist aber sehr nützlich für Ebenenübergänge, bei denen sich der Arbeitssatz erheblich ändert, und zum Entfernen der Fragmentierung des Videospeichers.

Eine Frameanzahl wird auch beibehalten, damit die Laufzeit erkennen kann, ob die Ressource, die sie gerade entfernt hat, frühzeitig im aktuellen Frame verwendet wurde. Dies bedeutet, dass mehr Ressourcen in einem einzelnen Frame verwendet werden, als in den Videospeicher passen. Dadurch wird die Ersetzungsrichtlinie ausgelöst, um für den Rest des Frames zu einer MRU-Mode anstelle von LRU zu wechseln, da dies unter solchen Bedingungen tendenziell etwas besser funktioniert. Ein solches Verrenkungsverhalten wirkt sich erheblich auf die Renderingleistung aus. Beachten Sie, dass das Konzept des aktuellen Frames an EndScene gebunden ist, sodass jede Anwendung, die verwaltete Ressourcen nutzt, diese Methode regelmäßig aufrufen muss.

Entwickler, die weitere Informationen darüber finden möchten, wie sich verwaltete Ressourcen in ihrer Anwendung verhalten, können die RESOURCEMANAGER-Ereignisabfrage über die IDirect3DQuery9-Schnittstelle verwenden. Dies funktioniert nur, wenn die Debugruntimes verwendet werden, sodass diese Informationen nicht von der Anwendung abhängig werden können, sondern detaillierte Informationen zu den ressourcen, die von der Runtime verwaltet werden.

Während das Verständnis der Funktionsweise des Ressourcen-Managers beim Optimieren und Debuggen Ihrer Anwendungen hilfreich sein kann, ist es wichtig, Ihre Anwendung nicht zu eng an die Implementierungsdetails der aktuellen Laufzeit oder der Treiber zu binden. Änderungen des Treibers oder Änderungen an der Hardware können das Verhalten erheblich ändern, und zukünftige Versionen von Direct3D verfügen über eine deutlich verbesserte und anspruchsvolle Ressourcenverwaltung.

Driver-Managed-Ressourcen

Direct3D-Treiber können die Funktion für vom Treiber verwaltete Texturen implementieren, die durch D3DCAPS2_CANMANAGERESOURCE angegeben wird, wodurch der Treiber die Ressourcenverwaltung anstelle der Laufzeit verarbeiten kann. Für den (seltenen) Treiber, der dieses Feature implementiert, kann das genaue Verhalten des Ressourcen-Managers des Treibers stark variieren, und Sie sollten sich an den Anbieter des Treibers wenden, um Details dazu zu erhalten, wie dies für die Implementierung funktioniert. Alternativ können Sie sicherstellen, dass stattdessen immer der Laufzeit-Manager verwendet wird, indem Sie beim Erstellen des Geräts D3DCREATE_DISABLE_DRIVER_MANAGEMENT angeben.

Standardressourcen

Während verwaltete Ressourcen einfach, effizient und einfach zu verwenden sind, gibt es Zeiten, in denen die direkte Verwendung von Videospeicher bevorzugt oder sogar erforderlich ist. Solche Ressourcen werden in der Kategorie POOL_DEFAULT erstellt. Die Verwendung solcher Ressourcen führt zu zusätzlichen Komplikationen für Ihre Anwendung. Code ist erforderlich, um die Situation mit verlorenen Geräten für alle POOL_DEFAULT Ressourcen zu bewältigen, und Leistungsaspekte müssen beim Kopieren von Daten in sie berücksichtigt werden. Wenn Sie USAGE_WRITEONLY nicht angeben oder ein Renderziel sperren können, kann dies auch zu schwerwiegenden Leistungseinbußen führen.

Das Aufrufen der Sperre für eine POOL_DEFAULT Ressource führt wahrscheinlicher dazu, dass die GPU angehalten wird, als mit einer POOL_MANAGED Ressource zu arbeiten, es sei denn, bestimmte Hinweisflags werden verwendet. Abhängig vom Speicherort der Ressource kann sich der zurückgegebene Zeiger auf einen temporären Systemspeicherpuffer oder ein Zeiger direkt auf den AGP-Arbeitsspeicher befinden. Wenn es sich um einen temporären Systemspeicherpuffer handelt, müssen die Daten nach dem Entsperren-Aufruf in den Videospeicher übertragen werden. Wenn die Videoressource nicht schreibgeschützt ist, müssen die Daten während der Sperre in den temporären Puffer übertragen werden. Wenn es sich um einen AGP-Speicherbereich handelt, werden temporäre Kopien vermieden, aber das erforderliche Cacheverhalten kann zu einer langsamen Leistung führen.

Es sollte darauf geachtet werden, eine vollständige Cachezeile von Daten in einen beliebigen Zeiger auf den AGP-Blendenspeicher zu schreiben, um die Strafe durch Schreibkombinieren zu vermeiden, was einen Lese-/Schreibzyklus auslöst, und der sequenzielle Zugriff auf den Speicherbereich wird bevorzugt. Wenn Ihre Anwendung während der Erstellung zufälligen Zugriff auf Daten vornehmen muss und Sie keine verwaltete Ressource für den Puffer verwenden möchten, sollten Sie stattdessen mit einer Systemspeicherkopie arbeiten. Nachdem die Daten erstellt wurden, können Sie das Ergebnis in den gesperrten Ressourcenspeicher streamen, um eine hohe Strafe für den Cacheschreibvorgang zu vermeiden.

Das flag LOCK_NOOVERWRITE kann verwendet werden, um Daten für einige Ressourcen effizient anzufügen, aber im Idealfall können mehrere Sperren - und Entsperraufrufe an dieselbe Ressource vermieden werden. Die richtige Verwendung der verschiedenen Sperrflags ist für eine optimale Leistung wichtig, ebenso wie die Verwendung eines cachefreundlichen Musters des Datenzugriffs beim Auffüllen von gesperrtem Speicher.

Verwenden von verwalteten und Standardressourcen

Das Kombinieren von Zuordnungen verwalteter und POOL_DEFAULT Ressourcen kann zu einer Fragmentierung des Videospeichers führen und die Ansicht des für verwaltete Ressourcen verfügbaren Videospeichers der Laufzeit verwirren. Im Idealfall sollten Sie alle POOL_DEFAULT Ressourcen erstellen, bevor Sie POOL_MANAGED Ressourcen verwenden oder den EvictManagedResources-Aufruf verwenden, bevor Sie nicht verwaltete Ressourcen zuweisen. Denken Sie daran, dass alle Zuordnungen aus POOL_DEFAULT, die sich im Videospeicher befinden, den Speicher für die Lebensdauer der Ressource binden, die für die Verwendung durch den Ressourcen-Manager oder für andere Zwecke nicht verfügbar ist.

Beachten Sie, dass die Version 9-Runtime im Gegensatz zu früheren Versionen von Direct3D einige verwaltete Ressourcen automatisch entfernt, bevor eine fehlgeschlagene nicht verwaltete Ressourcenzuordnung aufgrund eines Mangels an Videospeicher aufgibt. Dies kann jedoch möglicherweise zu einer zusätzlichen Fragmentierung führen und sogar eine Ressource an einem suboptimalen Speicherort erzwingen (z. B. mit einer statischen Textur im nicht lokalen Videospeicher). Auch hier empfiehlt es sich, alle erforderlichen nicht verwalteten Ressourcen vorab und vor der Verwendung von verwalteten Ressourcen zuzuordnen.

Dynamische Standardressourcen

Daten, die mit hoher Häufigkeit generiert und aktualisiert werden, benötigen den Sicherungsspeicher nicht, da alle Informationen beim Wiederherstellen des Geräts neu erstellt werden. Solche Daten werden in der Regel am besten in POOL_DEFAULT erstellt, wobei der USAGE_DYNAMIC Hinweis angegeben wird, damit der Treiber Beim Platzieren der Ressource Optimierungsentscheidungen treffen kann, da er weiß, dass sie häufig aktualisiert wird. Dies bedeutet in der Regel, dass die Ressource in einen nicht lokalen Videospeicher versetzt wird. Daher ist der Zugriff der GPU in der Regel viel langsamer als der lokale Videospeicher. Für UMA-Architekturen kann der Treiber eine bestimmte Platzierung für dynamische Ressourcen auswählen, um den CPU-Schreibzugriff zu optimieren.

Diese Verwendung ist typisch für Software-Skinning-Lösungen und CPU-basierte Partikelsysteme, die Vertex-/Indexpuffer ausfüllen, und das LOCK_DISCARD-Flag stellt sicher, dass in Fällen, in denen die Ressource aus dem vorherigen Frame noch verwendet wird, keine Stags entstehen. Die Verwendung einer verwalteten Ressource würde in diesem Fall einen Systemspeicherpuffer aktualisieren, der dann in den Videospeicher kopiert und dann nur für ein oder zwei Frames verwendet wird, bevor er ersetzt wird. Bei Systemen mit nicht lokalem Videospeicher wird die zusätzliche Kopie durch die ordnungsgemäße Verwendung dieses dynamischen Musters eliminiert.

Standardtexturen können nicht gesperrt werden und können nur über UpdateSurface oder UpdateTexture aktualisiert werden. Einige Systeme unterstützen dynamische Texturen, die gesperrt werden können, und verwenden das LOCK_DISCARD-Muster, aber ein Capabilities-Bit (D3DCAPS2_DYNAMICTEXTURES) muss überprüft werden, bevor Sie solche Ressourcen verwenden. Für hochdynamische Texturen (Video oder prozedurale Texturen) könnte Ihre Anwendung übereinstimmende POOL_DEFAULT und POOL_SYSTEMMEM Ressourcen erstellen und Videospeicherupdates mithilfe von UpdateTexture verarbeiten. Bei sehr häufigen und teilweisen Updates ist das UpdateTexture-Paradigma wahrscheinlich die bessere Wahl.

So nützlich dynamische Ressourcen auch sein können, achten Sie beim Entwerfen von Systemen, die stark auf dynamische Übermittlung basieren. Statische Ressourcen sollten in POOL_MANAGED platziert werden, um sowohl eine gute Auslastung des lokalen Videospeichers zu gewährleisten, als auch um die begrenzte Bus- und Standard Arbeitsspeicherbandbreite effizienter zu nutzen. Bei Ressourcen, die teilweise statisch sind, stellen Sie möglicherweise fest, dass die Kosten für einen gelegentlichen Upload in den lokalen Videospeicher viel geringer sind als der konstante Busdatenverkehr, der durch dynamisches Erstellen generiert wird.

Systemspeicherressourcen

Ressourcen können auch in POOL_SYSTEMMEM erstellt werden. Obwohl sie nicht von der Grafikpipeline verwendet werden können, können sie als Quellen zum Aktualisieren POOL_DEFAULT Ressourcen mithilfe von UpdateSurface oder UpdateTexture verwendet werden. Ihr Sperrverhalten ist einfach, obwohl es zu Brüchen kommen kann, wenn sie von einer der oben genannten Methoden verwendet werden.

Obwohl sie sich im Systemspeicher befinden, sind POOL_SYSTEMMEM Ressourcen auf dieselben Formate und Funktionen (z. B. maximale Größe) beschränkt, die vom Gerätetreiber unterstützt werden. Der POOL_SCRATCH Ressourcentyp ist eine weitere Form der Systemspeicherressource, die alle Formate und Funktionen nutzen kann, die von der Laufzeit unterstützt werden, aber vom Gerät nicht zugegriffen werden kann. Scratch-Ressourcen sind in erster Linie für die Verwendung durch Inhaltstools vorgesehen.

Abbildung 3. Speicherressourcen in Video-RAM, AGP-Blende und System-RAM

Speicherressourcen in Video-RAM, AGP-Blende und System-RAM

Allgemeine Empfehlungen

Wenn Sie die technischen Implementierungsdetails der Ressourcenverwaltung korrekt erhalten, können Sie Ihre Leistungsziele für Ihre Anwendung erreichen. Die Planung, wie die Ressourcen direct3D präsentiert werden, und das architektonische Design für das rechtzeitige Laden der Daten ist eine kompliziertere Aufgabe. Es wird eine Reihe bewährter Methoden empfohlen, wenn Sie diese Entscheidungen für Ihre Anwendung treffen:

  • Verarbeiten Sie alle Ihre Ressourcen vorab. Während der Entwicklung ist es praktisch, sich auf eine teure Ladezeitkonvertierung und -optimierung für Ihre Ressourcen zu verlassen, aber dies führt zu einer hohen Leistungsbelastung für die Computer Ihrer Benutzer. Vorverarbeitete Ressourcen sind schneller zu laden, schneller zu verwenden und bieten Ihnen die Möglichkeit, anspruchsvolle Off-Line-Arbeiten zu erledigen.
  • Vermeiden Sie es, viele Ressourcen pro Frame zu erstellen. Die erforderlichen Treiberinteraktionen können CPU und GPU serialisieren, und die betreffenden Vorgänge sind schwer, da sie häufig Kernelübergänge erfordern. Verteilen Sie die Erstellung auf mehrere Frames, oder verwenden Sie Ressourcen wieder, ohne sie zu erstellen/freizugeben. Im Idealfall sollten Sie mehrere Frames warten, bevor Sie Ressourcen sperren oder freigeben, die kürzlich zum Rendern verwendet wurden.
  • Stellen Sie am Ende des Frames sicher, dass Sie die Bindung aller Ressourcenkanäle (d. b. Streamquellen, Texturphasen und aktuelle Indizes) aufheben. Auf diese Weise wird sichergestellt, dass klammernde Verweise auf Ressourcen entfernt werden, bevor sie bewirken, dass der Ressourcen-Manager ressourcenresident bleibt, die tatsächlich nicht mehr verwendet werden.
  • Verwenden Sie für Texturen komprimierte Formate (z. B. DXTn) mit mip-maps, und erwägen Sie die Verwendung eines Texturatlas. Diese reduzieren die Bandbreitenanforderungen erheblich, und sie können die Gesamtgröße der Ressourcen reduzieren, wodurch sie effizienter werden.
  • Verwenden Sie für Geometrie die indizierte Geometrie, da dadurch Vertexpufferressourcen komprimiert werden, und moderne Videohardware ist stark für die Wiederverwendung von Scheitelpunkten optimiert. Durch die Verwendung programmierbarer Vertexshader können Sie die Vertexinformationen komprimieren und während der Vertexverarbeitung erweitern. Dies trägt wiederum dazu bei, die Bandbreitenanforderungen zu reduzieren und Vertexpufferressourcen effizienter zu machen.
  • Vermeiden Sie eine Überoptimierung Ihrer Ressourcenverwaltung. Zukünftige Revisionen von Treibern, Hardware und Betriebssystem können möglicherweise Zu Kompatibilitätsproblemen führen, wenn die Anwendung zu stark auf eine besondere Kombination abgestimmt ist. Da die meisten Anwendungen CPU-gebunden sind, verursacht die teure CPU-basierte Verwaltung im Allgemeinen mehr Leistungsprobleme, als sie löst.

Verwalten von Ressourcen

Verlorene Geräte

Leistungsoptimierungen

Komprimierte Texturressourcen

Abfragen

D3DUSAGE

D3DPOOL

D3DCREATE