Neue GPU-API von SDL3 wurde gemergt
(github.com/libsdl-org)- Der PR #9312 für die neue GPU API von SDL3 wurde am 29. August 2024 gemergt; angesichts des nahenden SDL 3.0 wurde der Refresh-basierte Ansatz schnell eingebracht, um mehr Review zu erhalten
- Der Vorschlag sah vor, Refresh, die Grafikkomponente von MoonWorks, als finalen API-Kandidaten für SDL_gpu zu verwenden; unterstützt wurden Vulkan und die PS5-Grafik-API, außerdem war Support für D3D11 Deferred Context in Arbeit
- Das API-Design nutzt ein modernes Rendering-Modell, das Arbeit in Render Passes, Compute Passes und Copy Passes aufteilt; Schreiboperationen auf Ressourcen können intern per Cycling abgewickelt werden, um Abhängigkeiten zwischen Frames zu vermeiden
- Bei Shadern wurde der Fokus vom anfänglichen Vorschlag mit Offline Compilation hin zur Validierung von Runtime-Shader-Erzeugung verschoben; diskutiert wurde eine Struktur, die backend-spezifische IR-Formate entgegennimmt, damit SDL selbst keinen Shader-Compiler wrappen muss
- Direkt nach dem Merge folgten weitere Anpassungen an API-Funktionsnamen, Build-Konfigurations-Makros, UTF-8-BOM und der 60-FPS-Begrenzung der D3D12-Swapchain; thatcosmonaut erhielt Commit-Rechte
Ausgangspunkt des PR und Merge-Status
- PR #9312 begann als Vorschlag für eine neue GPU-API, um SDL_gpu schnell Review zu verschaffen
- Ziel war es, angesichts des nahenden SDL 3.0 möglichst schnell „mehr Augen“ darauf zu bekommen
- Am 29. August 2024 wurde er nach der Bestätigung
It's mergedgemergt
- Direkt nach dem Merge gab es die Bitte, Änderungen kurz zurückzustellen und Review sowie Anpassungen vorzunehmen
- Später war der Status
everything is merged, und es wurde darauf hingewiesen, dass Änderungen am GPU-Teil wieder gemergt werden können - thatcosmonaut wurde Commit-Rechte hinzugefügt, da er voraussichtlich eingehende Änderungen reviewen würde
- Später war der Status
Refresh-basierter API-Kandidat
- Im Zentrum des Vorschlags stand, Refresh, die Grafikkomponente von MoonWorks, als finalen API-Kandidaten für SDL_gpu zu verwenden
- MoonWorks wurde als Projekt beschrieben, das eher ein Nachfolger von XNA ist, statt XNA wie FNA neu zu implementieren
- Refresh ähnelt FNA3D, zielt aber auf moderne APIs wie Vulkan ab
- Refresh unterstützte damals Vulkan und die PS5-Grafik-API
- Support für D3D11 Deferred Context war in Arbeit
- Es wurde beschrieben, dass Refresh in Produktion für Samurai Gunn 2 auf PC und Konsolen eingesetzt wird
- Der PR-Autor nannte thatcosmonaut als wichtigsten Ansprechpartner und erklärte, dass auch das FNA Core Team an der weiteren Arbeit beteiligt sein werde
API-Design und Ressourcenbehandlung
- Die API ist als moderne Rendering-API mit Fokus auf Deferred Contexts aufgebaut
- Arbeit wird in Render Passes, Compute Passes und Copy Passes aufgeteilt
- Der Rest der API wurde als relativ standardnah beschrieben, mit Aufrufen für Binding, Rendering und Compute Dispatch
- Alle Schreiboperationen auf Ressourcen können per Cycling Abhängigkeiten zwischen Frames vermeiden
- Grafik-Ressourcen-Handles wie
GpuBuffersdienen als Container, um interne Ressourcenreferenzen zu cyclen - Später wurde das Cycling-Konzept auf einen booleschen Wert vereinfacht, und mehrere
WriteOptions-Enums wurden entfernt
- Grafik-Ressourcen-Handles wie
- Anfangs gab es wegen Problemen beim Verhalten der Daten-API im AMD-D3D11-Treiber mehrere
WriteOptions-Enums- Es wurde erklärt, dass sich nicht vollständig umgehen ließ, dass die D3D11-Daten-API auf AMD nicht wie erwartet funktioniert
- Später wurde dieser Teil vereinfacht und das Verhalten im Code dokumentiert
Diskussion zum Shader-System
- Die anfängliche Shader-Lösung war ein Skript namens
shaderbuild.py- Es diente als Frontend für Offline-Shader-Build-Tools auf der Client-Maschine
- Die Struktur bündelte mehrere Formate und leitete sie passend an die jeweiligen Rendering-Backends weiter
- Dieser Ansatz wurde als Design beschrieben, das Online Shader Compilation nicht verhindert
- Es wurde erklärt, dass künftig SDLSL-Quellcode in ein Binary eingebettet und in
CreateShaderModulesofort in den benötigten Backend-Bytecode umgewandelt werden könnte - Als Vorteil wurde genannt, dass Online Compilation erlaubt werden kann, ohne die öffentliche API zu brechen
- Es wurde erklärt, dass künftig SDLSL-Quellcode in ein Binary eingebettet und in
- In externem Feedback kamen Bedenken auf, dass reine Offline Compilation zu bestimmten Engines nicht passt
- Es wurde angemerkt, dass es für Entwickler umständlich sein könne, Python,
glslcundspirv-crossim PATH installieren zu müssen - Außerdem gab es die Ansicht, dass im SDL-Ökosystem ein Offline-Shader-Compiler-Tool als separate Satellite Library natürlicher sein könnte
- Es wurde angemerkt, dass es für Entwickler umständlich sein könne, Python,
- Später wurde das Shader-System in Richtung einer Trennung zwischen „raw“ Shadern und „portable“ Shadern angepasst
- Der FNA3D-Port wurde als Stresstest für Support zur Runtime-Shader-Erzeugung verwendet
- Erwähnt wurde eine Konfiguration, die mit dem MojoShader-SPIR-V-Emitter unter Vulkan direkt weiterreicht und für andere Backends über die optionale separate Bibliothek SDL_shader konvertiert
- Ziel ist eine Struktur, bei der SDL selbst nicht weiß oder sich darum kümmert, woher ein Shader stammt
Backends und Testfortschritt
- Die anfängliche Refresh-basierte Implementierung wurde als stark bewertet, weil bereits ein Vulkan-Backend existierte
- Es gab die Einschätzung, dass das Vulkan-Backend auf Basis von Refresh 2.0 sehr performant sei
- Dass Compute ein First-Class-Feature ist, wurde ebenfalls als wichtiger Unterschied zum bisherigen SDL_GPU-Entwurf genannt
- Von Ende März bis Anfang April 2024 wurden mehrere Beispiele realer laufender Spiele geteilt
- Es wurde erklärt, dass ein Zustand erreicht wurde, der ohne Offline-Shader-Compilation funktioniert
- Eine aktuelle Revision wurde geteilt, in der Streets of Rage 4 bootet
- Wizorb lief unter Metal
- Celeste erreichte für einen erheblichen Teil der Trace Database den In-Game-Zustand
- Parallel wurden weitere Funktionen ergänzt
- Es wurde erwähnt, dass Hardware-Instancing im nächsten Push hinzugefügt werden sollte
- Später kamen Instancing und Occlusion Queries hinzu, und es wurde mitgeteilt, dass die Metal-Implementierung noch vervollständigt werden müsse
Build-, API- und Plattformprobleme aus dem Review
- Wegen der Include-Reihenfolge von Vulkan traten Fehler durch Neudefinitionen der Typedefs
VkInstanceundVkSurfaceKHRauf- Vorgeschlagen wurde eine Änderung der Include-Reihenfolge von Vulkan-Headern und
SDL_vulkan.hinSDL_gpu_vulkan.c - Ebenfalls vorgeschlagen wurde, eine Warnung zu einem möglicherweise nicht initialisierten
suitableQueueFamilyIndexdurch Initialisierung mit 0 zu unterdrücken
- Vorgeschlagen wurde eine Änderung der Include-Reihenfolge von Vulkan-Headern und
- Auch die Notwendigkeit einer Aktualisierung von dynapi wurde angesprochen
- Es wurde darauf hingewiesen, dass es durch Ausführen von
gendynapi.pyuntersrc/dynapi/aktualisiert wird - Als Caveat wurde genannt, dass dabei viele Warnungen zu fehlender Dokumentation erscheinen
- Es wurde darauf hingewiesen, dass es durch Ausführen von
- Es gab den Vorschlag, den Byte-Size-Typ in API-Funktionssignaturen auf
size_tumzustellen, aber für die GPU-API kam man zu dem Schluss,Uint32beizubehalten- Es gab die Einschätzung, dass gleichzeitige 32-/64-Bit-Kompatibilität schwierig werden könnte, wenn Buffer-Größen sehr groß werden
- Als Alternative wurde
Uint64erwähnt, letztlich wurde aber die Beibehaltung vonUint32vorgeschlagen
Folgeanpassungen nach dem Merge
- Nach dem Merge wurden in #10622 mehrere Tweaks vorgenommen
- Es wurde darauf hingewiesen, dass zuerst gemergt werden solle, damit Beta-Nutzer die neuen Funktionsnamen erhalten
- Das Problem, dass in der Build-Konfiguration jeweils das rechte Makro definiert sein musste, etwa
SDL_GPU_VULKAN SDL_VIDEO_VULKANundSDL_GPU_METAL SDL_VIDEO_METAL, wurde in #10622 behoben - Auch das UTF-8-BOM-Problem in den GPU-Quelldateien wurde in #10622 behoben
- Auf D3D12-Seite wurde festgestellt, dass
D3D12_ClaimWindow()die Swapchain auf VSYNC setzt undtestspritedadurch auf 60 FPS begrenzt wird- Es wurde erklärt, dass der beabsichtigte Workflow darin besteht, in der Claim-Window-Phase eine Swapchain mit den allgemein unterstützten Parametern SDR und VSYNC zu erstellen, danach die Unterstützung abzufragen und anschließend
SetSwapchainParametersaufzurufen - Obwohl der Render Driver nach dem Claim
SetSwapchainParametersaufruft, blieb die 60-FPS-Begrenzung im D3D12-Driver bestehen und wurde zum Untersuchungsgegenstand
- Es wurde erklärt, dass der beabsichtigte Workflow darin besteht, in der Claim-Window-Phase eine Swapchain mit den allgemein unterstützten Parametern SDR und VSYNC zu erstellen, danach die Unterstützung abzufragen und anschließend
1 Kommentare
Hacker-News-Kommentare
SDL3 befindet sich noch in der Preview-Phase, aber die neue GPU API wurde in den Main-Branch gemergt, und die SDL3-Maintainer nehmen gerade die letzten Anpassungen vor.
So wie ich es verstanden habe, liegt der Kern dieser neuen GPU API darin, dass man Grafikcode und Shader einmal schreibt und sie dann ohne großen Aufwand auf mehreren Plattformen einschließlich Konsolen laufen. Früher brauchte man dafür Unity oder Unreal oder eine eigene Custom-Lösung.
WebGPU/WGSL ist ebenfalls ein ähnlicher plattformübergreifender Grafik-Stack, aber soweit ich weiß, hat niemand ein Konsolen-Backend dafür gebaut. Umgekehrt scheint die SDL3 GPU API derzeit WebGPU nicht als Backend zu unterstützen.
Ich freue mich auf SDL3, weil es eine Konsolenabstraktion einführt und dadurch keine zusätzliche Abhängigkeit für die GPU API mehr nötig ist. Außerdem unterstützt Godot das Steam Deck offiziell, und hoffentlich künftig auch mehr Konsolen. In diesem Zusammenhang treibt Miguel de Icaza die Einführung von Swift in Godot voran und arbeitet auch daran, den Editor mit SwiftUI auf das iPad zu portieren. Der Fortschritt [3] ist interessant.
[1] https://bkaradzic.github.io/bgfx/overview.html
[2] https://github.com/bgbernovici/myndsmith
[3] https://blog.la-terminal.net/xogot-code-editing/
Zusätzlicher Kontext steht hier: https://icculus.org/finger/flibitijibibo?date=2024-06-15&time=13-14-16
Ich bin gespannt, wie sich dieser Trend etablieren wird. Am Ende ist es gut, wenn es mehr Optionen gibt, um Custom-Game-Engines und Apps zu bauen.
Ich arbeite mich in letzter Zeit tief in Vulkan ein; das Lernen macht Spaß und bringt Aha-Momente, aber wegen der Natur von Vulkan fühlt sich der Fortschritt langsam an. Hätte es SDL3 zu Beginn gegeben, hätte ich mich wahrscheinlich gern dafür entschieden und hätte für die investierte Zeit wohl auch mehr vorzeigbare Ergebnisse gehabt.
Ob diese API in der Praxis wirklich etwas taugt, wird sich erst mit der Zeit zeigen. Vor allem Ressourcensynchronisierung und die Art der Objektumbenennung werden entscheidend sein.
Man wird auch sehen müssen, ob sie schneller ist als WebGPU oder andere Abstraktionen. Ebenso bleibt abzuwarten, ob sie klein bleibt, selbst wenn man Driver-Bugs umgehen muss.
Ich bin auch skeptisch gegenüber dem neuen Bytecode für die Shading-Sprache. Bei WebGPU war das Parsen von Shadern zur Laufzeit nie ein Problem und ist sehr schnell. Auch die Erzeugung nativer Shader geht schnell [1]. Langsam ist die Pipeline-Erstellung, und dabei hilft dieser Bytecode nicht.
[1] http://kvark.github.io/naga/shader/2022/02/17/shader-translation-benchmark.html
Ich frage mich, wie sie das so schnell geschafft haben. WebGPU Native hat eine lange Entwicklungszeit hinter sich und ist immer noch nicht endgültig abgeschlossen, während die SDL-GPU-API sogar mehr Plattformen unterstützt, also wirkte es eher so, als müsste es noch länger dauern.
Es gibt ein Schwesterprojekt [1] für eine plattformübergreifende Shading-Sprache und ein weiteres Projekt [2], das bestehende Sprachen ineinander umwandelt, aber die sind fertig, wenn sie fertig sind, und der Rest der API muss darauf nicht warten.
WebGPU ist das Ergebnis eines Ausschusses aus Herstellern und Sprachjuristen oder Standardjuristen, der es inmitten von Politik und Bürokratie geschaffen hat, und das merkt man. SDL_GPU wurde dagegen vor allem von Spieleentwicklern gebaut, die Pragmatismus über alles stellen, und wird deshalb aus dem Elfenbeinturm heraus manchmal belächelt.
[1]: https://github.com/libsdl-org/SDL_shader_tools
[2]: https://github.com/flibitijibibo/SDL_gpu_shadercross
Freut mich, zum dx12-Teil beigetragen zu haben :)
Vielleicht probiere ich es mal aus. Für mich war SDL immer qualitativ hochwertige Software. Es kompiliert schnell, lässt sich auf vielen Plattformen einfach bauen und funktioniert immer zuverlässig. Deshalb habe ich auch hohe Erwartungen an diese neue API.
Insgesamt bin ich ein großer Fan von SDL.
Als ich nach einer plattformübergreifenden Spielebibliothek gesucht habe, fühlten sich SDL und seine API wie genau die richtige Balance an. Ich wollte einfach eine C/C++-Bibliothek, die ich zum Erstellen eines Fensters und eines Grafik-Kontexts aufrufen kann, plus ein schnelles Sprite-Rendering-Framework. Ich brauchte keine komplette IDE oder aufgeblähte Bibliotheken und wollte auch keine neue Sprache lernen.
Bei SDL3 habe ich das Gefühl eines Second-System-Effekts. SDL2 war SDL1 mit expliziten Fenster-Handles recht ähnlich, daher ist SDL3 eher das zweite als das dritte System. SDL1/2 waren eine dünne Schicht um plattformspezifischen Boilerplate-Code zum Öffnen von Fenstern und Verarbeiten von Eingabeereignissen, sodass man schnell zu dem OpenGL-Rendering-Code kam, den man eigentlich schreiben wollte.
Wenn man aber auch Apple-Betriebssysteme unterstützen will, ist man an OpenGL 4.1 gebunden. Apple hat es schon vor 5 Jahren offiziell als veraltet markiert, daher kann man moderne GPU-Funktionen wie Compute Shader nicht nutzen.
Man kann auch den Vulkan-Weg gehen und auf Apple-Systemen MoltenVK verwenden, aber Vulkan ist deutlich komplexer als OpenGL. Wie Leute oft sagen: „1000 Zeilen Code für ein einziges Dreieck.“ Das Ziel der GPU-API von SDL3 ist es, eine zugänglichere, aber dennoch ausreichend flexible Alternative zu bieten.
Bei Konsolen dürfte es wohl ähnlich aussehen.
Viele Leute haben darum gebeten, „etwas wie SDL_render zu haben, aber mit Shader-Unterstützung, die auf allen Plattformen funktioniert“, und das war offenbar der Ausgangspunkt.
SDL3 fügt auch eine höherstufige Audio-API hinzu, aber deren Vorteile kenne ich nicht gut.
Außerdem hat sich SDL2 seit 2.0.0 erheblich weiterentwickelt, und SDL3 setzt diese Entwicklung fort, indem es API-inkompatible Änderungen zulässt. SDL3 ist keine komplette Neuschreibung, und aus Sicht von SDL-Nutzern dürfte der Umstieg von SDL2 auf SDL3 nicht besonders schwierig sein.
Und SDL1/2 waren auch nie nur so „dünn“, dass sie kein eigenes High-Level-Grafiksystem hatten. Es ist nützlich, dass neue oder einfache Nutzer direkt etwas auf den Bildschirm bringen können.
Wie ahefner anmerkt, war SDL1 nach heutigen Maßstäben zwar ziemlich „dünn“, bot aber genug, um grundlegende Dinge auf dem Bildschirm darzustellen, ohne selbst Pixelmathematik schreiben zu müssen, und in den 90ern war das ziemlich hilfreich.
Trotzdem könnte diese Abstraktion Anforderungen erfüllen, die über einfache 2D-Spiele hinausgehen, und gleichzeitig auf ein Grafik-API-Ökosystem zielen, das leider immer stärker fragmentiert. Der Traum einer universellen OpenGL(Next)-Zukunft ist vorbei. Allerdings scheint der schwierigste Teil, nämlich die Shader-Konvertierung, noch zu fehlen.
Ich habe diese Bibliothek noch nie benutzt, aber wenn ich den verlinkten Thread richtig verstanden habe, würde ich jetzt gerne Beispiele für die nun verfügbaren plattformübergreifenden GPU-Compute-Funktionen sehen. Mich würde interessieren, ob jemand Empfehlungen hat, wo man damit am besten anfängt.