1 Punkte von GN⁺ 2024-08-31 | 1 Kommentare | Auf WhatsApp teilen
  • 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 merged gemergt
  • 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

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 GpuBuffers dienen als Container, um interne Ressourcenreferenzen zu cyclen
    • Später wurde das Cycling-Konzept auf einen booleschen Wert vereinfacht, und mehrere WriteOptions-Enums wurden entfernt
  • 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 CreateShaderModule sofort 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
  • 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, glslc und spirv-cross im 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
  • 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 VkInstance und VkSurfaceKHR auf
    • Vorgeschlagen wurde eine Änderung der Include-Reihenfolge von Vulkan-Headern und SDL_vulkan.h in SDL_gpu_vulkan.c
    • Ebenfalls vorgeschlagen wurde, eine Warnung zu einem möglicherweise nicht initialisierten suitableQueueFamilyIndex durch Initialisierung mit 0 zu unterdrücken
  • Auch die Notwendigkeit einer Aktualisierung von dynapi wurde angesprochen
    • Es wurde darauf hingewiesen, dass es durch Ausführen von gendynapi.py unter src/dynapi/ aktualisiert wird
    • Als Caveat wurde genannt, dass dabei viele Warnungen zu fehlender Dokumentation erscheinen
  • Es gab den Vorschlag, den Byte-Size-Typ in API-Funktionssignaturen auf size_t umzustellen, aber für die GPU-API kam man zu dem Schluss, Uint32 beizubehalten
    • 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 Uint64 erwähnt, letztlich wurde aber die Beibehaltung von Uint32 vorgeschlagen

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_VULKAN und SDL_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 und testsprite dadurch 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 SetSwapchainParameters aufzurufen
    • Obwohl der Render Driver nach dem Claim SetSwapchainParameters aufruft, blieb die 60-FPS-Begrenzung im D3D12-Driver bestehen und wurde zum Untersuchungsgegenstand

1 Kommentare

 
GN⁺ 2024-08-31
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.

    • Unreal/Unity sind nicht die einzigen Lösungen. Es gibt auch das recht populäre bgfx(https://github.com/bkaradzic/bgfx), und soweit ich weiß auch sokol gfx(https://github.com/floooh/sokol). Natürlich gibt es auch noch viele weniger bekannte.
    • Ich habe früher einmal bgfx [1], das es erlaubt, Grafikcode und Shader einmal zu schreiben und dabei auch Konsolen zu unterstützen, mit einem SDL2-Stack und Swift [2] integriert. Selbst aus der Perspektive von jemandem, der solche Tools vorher nie benutzt hatte, war das eine ziemlich gute Erfahrung.
      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/
    • Erwähnenswert ist auch, dass Godot plattformübergreifende Shader hat. Die Sprache GDShader basiert stark auf der OpenGL Shader Language, ist aber keine 1:1-Kopie und wird passend zur Zielplattform kompiliert. Für PS5 und Xbox muss man allerdings mit Drittanbietern zusammenarbeiten. Jemand hat auch Nintendo-Builds für Personen veröffentlicht, die die Nintendo-NDA unterschrieben haben.
    • Aber warum braucht es eine SDL API statt gfx-rs / wgpu? Ich frage mich, ob wirklich noch eine weitere Neuentwicklung nötig war.
  • 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.

    • WebGPU hat so lange gebraucht, weil man sich entschied, statt SPIR-V eine eigene Shading-Sprache zu entwickeln. SDL hat diesen Fehler nicht gemacht und überlässt Shader-Compiler und Konvertierungs-Tools den Nutzern.
      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
    • Die wichtigsten Mitwirkenden am SDL3-GPU-Projekt haben Erfahrung mit FNA3D und Refresh, zwei plattformübergreifenden GPU-Abstraktionsschichten, die sowohl auf PCs als auch auf Konsolen zielen. Dieses Wissen und der bestehende Open-Source-Code boten die Grundlage, um etwas Schnelles und zugleich Hochwertiges zusammenzusetzen.
    • Weil es keinen Ausschuss gab und weil motivierte Entwickler da waren, die das Ergebnis für ihre eigenen Projekte brauchten. Besonders die Leute aus dem FNA-Umfeld.
    • Ganz einfach. SDL GPU lässt den Rest der Eule weg, also den Teil, der Shader in einem gemeinsamen Format in API-spezifische Zwischendarstellungen umwandelt.
  • Freut mich, zum dx12-Teil beigetragen zu haben :)

    • Schön. Geplant ist, modernes HLSL als Ziel zu verwenden, daher werde ich anfangs wohl dieses Backend nutzen. Hoffentlich erzeugt DXC am Ende brauchbares SPIR-V.
    • Kannst du Materialien empfehlen, um DX12 zu lernen?
  • 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 nur Windows/Linux/Android unterstützen will, kann man argumentieren, dass die SDL-GPU-API unnötig aufgebläht ist.
      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.
    • SDL2 war nicht nur „SDL1 mit expliziten Fenster-Handles“. Es gab viele Änderungen und neue Funktionen in der gesamten API, und wie bei SDL3 auch größere Änderungen am Grafik-Subsystem. SDL1 nutzte Software-Rendering, SDL2 brachte Hardware-Beschleunigung hinzu.
      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.
    • Das Problem ist, dass OpenGL faktisch tot ist und Vulkan in Bezug auf Benutzerfreundlichkeit nur ein dürftiger Ersatz für OpenGL ist.
    • Auch eine Render-API war für viele SDL-Nutzer bereits unnötiger Ballast. SDL2 war in Bezug auf die Binärgröße schon deutlich größer als SDL1.
      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.