Die wichtigsten Probleme bei Windows-Titeln

Die Microsoft Windows Gaming and Graphics Technologies Developer Relations-Gruppe führt jedes Jahr Leistungsanalysen für viele Windows-Spiele durch. Während dieser Sitzungen erhalten wir praktische Erfahrungen, um uns an das Feedback und die Anfragen der Entwickler zu binden, die wir täglich erhalten. Gelegentlich helfen wir, einen mysteriösen Absturz oder ein anderes Problem in einem Titel aufzuspüren, was uns weitere Einblicke in Probleme gibt, auf die Entwickler stoßen.

In diesem Artikel werden viele der häufig auftretenden Probleme erläutert, die bei PC-Spielen der aktuellen Generation aufgetreten sind.

CPU-Limited Leistung

Die überwiegende Mehrheit der Spiele ist durch die CPU-Leistung auf Systemen mit leistungsstarken Grafikverarbeitungseinheiten (GPUs) eingeschränkt. Dies ist manchmal auf eine schlechte Verwendung von Batching für Zeichnungsübermittlungen zurückzuführen, aber in der Regel liegt dies daran, dass andere Spielesysteme einen großen Teil der verfügbaren CPU-Zyklen verbrauchen. In den wenigen Fällen, in denen wir die GPU als Einschränkung gesehen haben, ist die Ursache sehr hohe Füllraten oder Pixel-Shaderanforderungen in hochauflösenden Einstellungen oder eine niedrige Vertex-Shaderleistung durch eine Video-Karte.

Da die meisten Titel CPU-begrenzt sind, ergeben sich die größten Leistungsgewinne durch die Optimierung CPU-intensiver Spielesysteme. In der Regel sind die KI- oder Physiksysteme und die zugehörige Logik zur Kollisionserkennung die hauptverbraucher von CPU-Zyklen in gut benehmenden Microsoft Direct3D-Anwendungen. Jede Arbeit zur Verbesserung dieser Systeme kann die Gesamtleistung des Spiels verbessern.

Unzureichende Batchverwaltung

Um eine gute Parallelität mit der GPU zu erreichen, müssen Zeichnungsbatches genügend Geometrie enthalten – und die Shader haben die richtige Komplexität –, um die Video-Karte beschäftigt zu halten, während nicht so viele Batches verwendet werden, dass der Befehlspuffer überflutet wird. Bei Hardware der aktuellen Generation empfehlen wir etwa 300 oder weniger Draw-Batch-Übermittlungen pro Frame (weniger bei CPUs mit geringerer Leistung), um zu verhindern, dass die Verarbeitung des Befehlspuffers durch den Treiber zu einem Leistungsengpass wird. Einige andere API-Zustandsaufrufe und Treiberkombinationen können zu einer kostspieligen CPU-Verarbeitung führen (z. B. Treiberkompilierung von Shadern), daher wird dringend eine routinemäßige Leistungsanalyse empfohlen.

Übermäßiges Kopieren von Arbeitsspeicher

Während der Entwicklung der meisten PC-Titel verwenden Entwickler praktische Datenstrukturen und Zeichenfolgen für die Inhaltsverwaltung. Die CPU-Arbeit, die für den Zeichenfolgenvergleich, das Kopieren und andere Manipulationen erforderlich ist, hat häufig einen messbaren Mehraufwand, insbesondere unter Berücksichtigung der Leistungstreffer, die mit dem Cache- und Speichersubsystem verbunden sind. Bei der Entwicklung dieser Systeme sollten Pläne zur Beseitigung oder Minimierung der Abhängigkeit von der Zeichenfolgenverarbeitung erstellt werden, sobald das Produkt in die primären Test- und Releasephasen eintritt.

Übermäßige Verwendung der dynamischen Zeichnungsübermittlung

Moderne Videohardware schneidet beim Umgang mit statischen Daten gut ab. High-End-Adapter verfügen häufig über eine sehr große Menge an Videospeicher, aber dieser Speicher kann nicht effektiv von dynamischen Daten genutzt werden.

Während für dynamische Inhalte einigermaßen effiziente Nutzungsmuster von dynamischen Vertexpuffern/Indexpuffern implementiert werden können, überlasten viele Titel diese Redewendung für ansonsten statischen Inhalt. Dies sehen wir am häufigsten bei BSP-Strukturen (Binary Space Partitioning) und portalbasierten Systemen, die Geometrie in einer Datenstruktur speichern, die nicht der Hardware zugeordnet ist und in Puffern für jeden Frame verarbeitet werden muss. Wenn Sie so viele Inhalte wie möglich in statische Ressourcen stecken, können Sie den Bandbreitenaufwand für die Übertragung von Daten an die Video-Karte erheblich reduzieren, den integrierten VRAM besser nutzen und den CPU-/Cache-Mehraufwand für die Verarbeitung dieser Inhalte reduzieren.

Hoher Aufwand bei der Dateiverarbeitung

PC-Spiele haben sich einen Ruf für lange Ladezeiten erworben, insbesondere im Vergleich zu Konsolentiteln mit strengen Ladezeitanforderungen. Unsere Analyse der Art und Weise, wie viele Titel das Dateisubsystem nutzen, zeigt einige häufige Probleme.

Der Mehraufwand für das Öffnen einer Datei ist in der Regel viel höher als von Entwicklern erwartet. Bei bedarfsgesteuerten Virenscannern, die weit verbreitet sind, und der zusätzlichen Funktionalität von NTFS ist das Öffnen einer Datei ein ziemlich teurer Vorgang. Viele Dateien gleichzeitig zu öffnen oder dieselbe Datei wiederholt zu öffnen und zu schließen, ist daher eine schlechte Methode, um mit der Dateiverwaltung umzugehen. Einige Spiele haben versucht, diese Leistungskosten zu verringern, indem sie vor dem Öffnen auf das Vorhandensein einer Datei getestet haben. Die Realität ist, dass das Testen auf das Vorhandensein einer Datei auf NTFS das Öffnen der Datei erfordert, sodass das Testen vor dem Öffnen dazu führt, dass die Kosten doppelt bezahlt werden.

Spiele, die Add-On-Änderungen oder Mods zulassen oder noch Entwicklungsgerüste zum Überschreiben von Datendateien enthalten, können aufgrund der Überprüfung auf diese Dateien zu erheblichen Verzögerungen beim Laden des Spiels führen, auch wenn diese Dateien nicht vorhanden sind. Es wird empfohlen, dass Spiele nur nach diesen Dateien suchen, wenn sie mit einem speziellen Befehlszeilenschalter oder einem anderen Modusindikator ausgeführt werden, sodass nur die Benutzer, die diese Funktionalität nutzen, tatsächlich die Leistungskosten dieser (oft umfangreichen) Überprüfungen bezahlen.

Zusätzliche Leistung kann aus dem Dateisystem wie folgt erzielt werden:

  • Geeignete Verwendung der Dateisystemhinweise FILE_FLAG_RANDOM_ACCESS und FILE_FLAG_SEQUENTIAL_SCAN
  • Größenanpassung von Puffern, um eine große Anzahl von Aufrufen der Lese-/Schreib-APIs des Betriebssystems zu vermeiden
  • asynchroner Zugriff auf Dateien
  • Laden von Threads im Hintergrund

Wir empfehlen auch dringend, Daten offline zu konvertieren (während der Build- oder Installationszeit), anstatt sich bei der ersten Ausführung des Spiels auf die Konvertierung zu verlassen, da dies für jeden Benutzer eine erhebliche Leistungssteuer bedeutet.

Langsame und frustrierende Installation

Ein weiteres häufiges Problem, das wir gesehen haben, sind sehr lange Installationszeiten für viele moderne PC-Spiele. Die Installationsprogramme fordern den Benutzer mehrmals auf, manchmal einfach, um dem Benutzer mitzuteilen, z. B. "Sie müssen DirectX nicht installiert haben.". Im Allgemeinen erfordern diese fehlerhaften Installationsprogramme, dass der Benutzer mehrmals Weiter oder OK auswählen muss, bevor die Installation des Spiels tatsächlich beginnt. Sobald es beginnt, haben wir gesehen, dass einige Titel eine Stunde oder mehr dauern, bis der Benutzer die Möglichkeit erhält, das Spiel zu spielen. Wir sind der festen Meinung, dass die erste Stunde der Spielerfahrung nicht die Installation sein sollte.

Es wird eine Reihe von Ansätzen für die Installation empfohlen. Halten Sie zunächst die Eingabeaufforderungen einfach und auf ein Minimum. Zweitens: Entwerfen Sie Ihre Spieldaten so, dass einige oder alle Datendateien nach Möglichkeit direkt vom Verteilungsdatenträger verwendet werden können – moderne DVD-Laufwerke haben eine sehr hohe Bandbreite. Drittens sollten Sie die Installation bei Bedarf in Ihren Titeln implementieren, um den Installationsprozess zu reduzieren oder zu beseitigen und benutzern zu ermöglichen, so schnell wie möglich in das Spiel einsteigen zu können. (Weitere Informationen zur Installation bei Bedarf finden Sie unter Installieren bei Bedarf für Spiele.)

Weitere Empfehlungen zur Spieleinstallation finden Sie unter Vereinfachen der Installation von Spielen.

Fehlende Berücksichtigung des physischen Arbeitsspeichers

Aufgrund der großen Variabilität der PC-Hardware auf dem Markt verwenden Titel in der Regel Ad-hoc-Konfigurationstests, um Standardeinstellungen für die Ebene grafischer Details auszuwählen. Einige der Titel, die wir gesehen haben, verwenden in diesen Tests die Größe des Videospeichers, können dies jedoch nicht mit der größe des physischen Arbeitsspeichers korrelieren. Um Situationen mit verlorenen Geräten zu bewältigen, muss der Großteil des Videospeichers (sowohl der lokale VRAM auf der Karte als auch die nicht lokale AGP-Speicherblende) durch physischen Arbeitsspeicher unterstützt werden, entweder durch die Verwendung von verwalteten Ressourcen oder benutzerdefinierten Datenstrukturen. Einige High-End-Grafikkarten verfügen über VRAM-Größen, die mit der Größe von Low-End-CPU-Speichern konkurrieren. In Situationen, in denen das System im Vergleich zum video-Karte über einen begrenzten physischen Arbeitsspeicher verfügt, können die meisten dieser VRAM nicht effektiv genutzt werden, und niedrigere Detaileinstellungen sollten konfiguriert werden.

Over-Reliance für Real-Time Audio sample rate Conversion

Eine weitere häufige Quelle für die CPU-Zyklusverbrennung ist, wenn das Audiosystem erforderlich ist, um die Wiedergaberate während der Mischung in den Hardwarepuffer zu konvertieren. Bei WDM-Treibern (Windows Driver Model) wird das Hardwarepufferformat nicht direkt von der Anwendung gesteuert, da es sich um eine Ressource auf Kernelebene handelt. Stattdessen wird das Format basierend auf dem Format mit der höchsten Qualität aller Quellen und den Funktionen der Hardware ausgewählt. Standardmäßig verwendet Windows XP für diesen Prozess eine hochwertige Konvertierung der Samplerate, und wenn die Mehrheit der Audiobeispiele eine Ratenkonvertierung erfordert, wird ein erheblicher Teil der CPU-Zyklen verbraucht.

Es wird empfohlen, alle DirectSound-Puffer mit der gleichen Abtastrate zu erstellen. Wenn Sie die WaveOut-Funktionen von Microsoft Win32 nutzen, sollten Sie auch hier eine konsistente Abtastrate verwenden. Bei WDM-Treibern werden alle Puffer vom Kernel gemischt, und wenn Sie eine höhere Samplingrate für einige von ihnen verwenden, werden die Stichprobenraten aller restlichen Elemente in Übereinstimmung konvertiert. Beachten Sie, dass dies bedeutet, dass für alle Audiobeispiele die gleiche Wiedergaberate verwendet wird, einschließlich aller Streaming-Audio-Dekomprimierungspuffer. Das Festlegen der primären Pufferrate hat keine Auswirkungen, es sei denn, Sie zielen auf Windows 98 oder Windows Millennium Edition ab.

Hinweis

Unter Windows Vista und höheren Versionen des Betriebssystems verwenden DirectSound und waveOut die Windows Audio Session API (WASAPI) für die gesamte Audioausgabe.

 

Fragmentierung des virtuellen Arbeitsspeichers

Wir haben eine Reihe neuer Probleme im Zusammenhang mit dem 32-Bit-Grenzwert für den Prozessspeicherspeicher festgestellt. Während 2 GB virtueller Adressraum für Prozesse im Benutzermodus in der Vergangenheit mehr als ausreichend waren, hat die zunehmende Verwendung von großen Dateien mit Speicherzuordnung, benutzerdefinierten Speicherzuteilungen und die zunehmende VRAM-Größe (die dem Prozessbereich zugeordnet werden muss) zu Situationen führen, in denen die Zuordnungen des virtuellen Speicherplatzes fehlschlagen. Einige Nicht-Microsoft-DLLs verwenden Feste Startstandorte in der Mitte des virtuellen Adressraums, was zu Einer Fragmentierung führt, die zu fehlerhaften Zuordnungen führt.

Diese Probleme treten am häufigsten auf, wenn das Spiel ein benutzerdefiniertes Speicherzuordnungsschema verwendet, das versucht, einen großen kontinuierlichen Teil des virtuellen Speicherplatzes zuzuweisen. Wir empfehlen, Allocators so zu schreiben, dass sie bei Bedarf größere Teile des virtuellen Adressraums anfordern. Beispiel: Anfordern von 64 oder 256 MB gleichzeitig, aber nicht 1 GB. Es sollte jedoch darauf geachtet werden, dass keine weitere Fragmentierung verursacht wird. Das Aufkommen von 64-Bit-Betriebssystemen und -Hardware wird diese Probleme in Der Zukunft erheblich unterstützen, aber auf 32-Bit-Systeme der aktuellen Generation muss Vorsicht geachtet werden.

Manipulation des Floating-Point Control-Word

Als Debughilfe haben einige Entwickler Ausnahmen für die Gleitkommaeinheit (Gleitkommaeinheit, FPU) über Bearbeitungen des Gleitkommasteuerungsworts aktiviert. Dies ist sehr problematisch und führt wahrscheinlich zum Absturz des Prozesses. Genau wie die aufrufende Konvention erfordert, dass das ebx-Register beibehalten wird, geht die Mehrheit des Systems davon aus, dass sich die FPU in einem Standardzustand befindet, vernünftige Ergebnisse liefert und keine Ausnahmen generiert. Treiber und andere Systemkomponenten berechnen häufig Ergebnisse basierend auf der Annahme, dass Standardfehlerwerte in den Registern für schlechte Bedingungen angezeigt werden. Wenn Ausnahmen aktiviert sind, werden diese jedoch nicht behandelt und führen zu Abstürze.

Direct3D legt die Gleitkommaeinheit als Teil der Initialisierung für den aufrufenden Thread auf Single-Precision und Round-to-Nearest fest, es sei denn, das D3DCREATE_FPU_PRESERVE-Flag wird verwendet. In diesem Fall bleibt das Gleitkomma-Steuerelementwort unberührt. Da das Steuerelementwort eine Einstellung pro Thread ist, kann die Leistung optimieren, wenn Sie sicherstellen, dass alle Anwendungsthreads auf den Modus mit einfacher Genauigkeit festgelegt sind. Denken Sie daran, dass das Aufrufen _control87 nicht für x64-native Codierung gültig ist, die stattdessen ausschließlich SSE verwendet, und es ist extrem teuer für die PowerPC-basierte Architektur der Xbox 360 CPU.

Hinweis

Wenn Sie das Steuerelementwort ändern, verwenden Sie _controlfp_s , und beachten Sie, dass Sie bei x64-Plattformen die Gleitkommagenauigkeit nicht über das Steuerelementwort ändern können.

 

In allen Bibliotheken, in denen wir unterschiedliche Rundungsregeln oder ein anderes Verhalten benötigen – z. B. beim Umgang mit Softwarevertexshadern oder kompilieren – speichern wir das Steuerelementwort und stellen es wieder her. Wenn ein Spiel nicht standardmäßige Rundungs- oder FPU-Ausnahmen verwenden muss, sollte es das Gleitkommasteuerungswort speichern und wiederherstellen, und Sie sollten sicher sein, dass kein externer Code aufgerufen wird, der nicht nachweislich sicher vor diesen Problemen ist, einschließlich System-APIs.

Optionale Installation der DirectX-Runtime

Eine Reihe von Spielen fragt den Benutzer, ob DirectX installiert werden soll. Dies kann zu Problemen führen, wenn der Benutzer davon ausgeht, dass auf dem System die neueste Verteilerversion von DirectX installiert ist und die Installation übersprungen wird. Anschließend wird die Installation erfolgreich fortgesetzt. Wenn das Spiel eine bestimmte Version von D3DX oder eine andere aktualisierte Funktionalität erfordert, die nicht installiert wurde, funktioniert das Spiel nicht, und der Benutzer wird sehr frustriert.

Es wird dringend empfohlen, dass das Installationsprogramm des Spiels automatisch die DirectX-Verteiler installiert, für die das Spiel erstellt wurde. Der DirectX-Installationsprozess ist so konzipiert, dass überprüft wird, ob etwas aktualisiert werden muss, und es wird schnell zurückgegeben, wenn dies nicht der Fall ist. Es ist also nicht erforderlich, den Benutzer nach der Installation von DirectX zu fragen.

Eine automatische Installation von DirectX kann durch Ausführen des folgenden Befehls über Ihr Installationspaket ausgeführt werden: dxsetup.exe /silent

Darüber hinaus kann die tatsächliche Größe des verteilbaren Ordners so konfiguriert werden, dass nur die Cabinet-Dateien (.cab) enthalten sind, die tatsächlich für die Zielplattformen und die Nutzung des Spiels benötigt werden.

Hinweis

Bevor Sie dxsetup verwenden, lesen Sie Nicht so direktes Setup.

 

Übermäßige Verwendung der Threadsynchronisierung

Bei der Profilerstellung von Spielen hängen die wichtigsten Hotspots häufig mit dem Betreten und Verlassen kritischer Abschnitte zusammen. Mit der Verbreitung von Multi-Core-CPUs hat die Verwendung von Multithreading in Spielen erheblich zugenommen, und viele Implementierungen sind auf eine starke Verwendung der Threadsynchronisierung angewiesen. Die CPU-Zeit, um einen kritischen Abschnitt zu nehmen, auch ohne jeglichen Konflikt, ist ziemlich bedeutend, und alle anderen Formen der Threadsynchronisierung sind noch teurer. Daher muss darauf geachtet werden, die Verwendung dieser Grundtypen zu minimieren.

Eine häufige Quelle für übermäßige Synchronisierung in Spielen ist die Verwendung von D3DCREATE_MULTITHREADED. Dieses Flag sorgt zwar dafür, dass Direct3D-Thread für das Rendern aus mehreren Threads sicher ist, es wird jedoch ein sehr konservativer Ansatz verfolgt, der zu einem hohen Synchronisierungsaufwand führt. Spiele sollten diese Kennzeichnung vermeiden. Entwerfen Sie stattdessen die Engine so, dass die gesamte Kommunikation mit Direct3D aus einem einzelnen Thread erfolgt und jede Kommunikation zwischen Threads direkt verarbeitet wird. Weitere Informationen zum Entwerfen von Multithread-Spielen finden Sie im Artikel Programmieren für mehrere Kerne auf Xbox 360 und Microsoft Windows.

Verwendung von RDTSC

Die Verwendung des RDTSC der x86-Anweisung wird nicht empfohlen. RDTSC kann das Timing für einige Energieverwaltungsschemas, die die CPU-Frequenz dynamisch ändern, und auf vielen Multikern-CPUs, für die der Zykluszähler nicht zwischen Kernen synchronisiert wird, nicht ordnungsgemäß berechnen. Spiele sollten stattdessen die QueryPerformanceCounter-API verwenden. Weitere Informationen zu Problemen mit RDTSC und der Implementierung von Zeitsteuerung mit hoher Auflösung mit QueryPerformanceCounter finden Sie im Artikel Spielzeitsteuerung und Mehrkernprozessoren.