Du bist nicht angemeldet.

Werbeanzeige

LukasBanana

Alter Hase

  • »LukasBanana« ist der Autor dieses Themas

Beiträge: 1 096

Beruf: Student

  • Private Nachricht senden

1

16.08.2016, 00:18

GraphicsPipeline in Direct3D12 und Vulkan

Hat jemand von euch schon etwas Erfahrung mit Direct3D12 und/oder Vulkan gesammelt?

Ein wesentlicher Unterschied scheint mir im Moment vor allem das Erstellen eines Pipeline-State Objekts zu sein.
Hierbei werden diesmal nicht (wie noch bei D3D11) die Rasterizer-State, Depth/Stencil-State und Blend-State Objekte getrennt erstellt und gebunden,
sondern alles zusammen in einem großen Pipeline-State Objekt. Sogar die Shader und die Vertex- und Index Buffer müssen dabei angegeben werden.
Was letzten Endes bedeutet, dass für jeden separaten Vertex Buffer ein extra Pipeline-State Objekt erstellt werden muss.

Ich frage mich nun, wie man wohl am sinvollsten das Handling betreibt, damit man eben nicht für jedes 3D Objekt auf dem Bildschirm, ein extra Pipeline-State Objekt braucht.
Ich sehe da im Moment keine bessere Lösung, als einen gut verwalteten Vertex-Buffer Atlas.
Dadurch würden auch nur ein bzw. wenige Vertex-Buffer Bindings auftreten und mit den ensprechenden Draw-Calls kann man ja Offset-Indices angeben.

Wie stellt ihr euch hier ein gutes Render-State Management vor?

dot

Supermoderator

Beiträge: 9 833

Wohnort: Graz

  • Private Nachricht senden

2

16.08.2016, 01:59

Mir scheint du hast da ein bissl was falsch verstanden. Resource Bindings sind nicht wirklich Teil des Pipeline State Object. Insbesondere Vertex- und Index Buffer Bindings. Die sind Teil der Command List... ;)

LukasBanana

Alter Hase

  • »LukasBanana« ist der Autor dieses Themas

Beiträge: 1 096

Beruf: Student

  • Private Nachricht senden

3

16.08.2016, 11:21

Ok, irgendwie habe ich mich hier und hier etwas verguckt bzgl. eines Vertex/Index Buffers.

Nichts desto weniger bedarf ein so großes State Objekt doch einer gewissen Verwaltung, oder wie seht ihr das?

Wenn man eine kleine Szene hat, mit nur einem Vertex Input Format und nur einem Shader, kann man das natürlich beim Programmstart binden und dann munter fröhlich drauf los rendern.
Aber sobald man mehrere Shader verwendet, und unterschiedliche Vertex Input Formate und dann vielleicht auch noch die Render Reihenfolge wegen Transparenzen beachten muss, wird es schon etwas schwieriger.

dot

Supermoderator

Beiträge: 9 833

Wohnort: Graz

  • Private Nachricht senden

4

16.08.2016, 11:38

Ich seh kein wirkliches Problem. Es war ja auch bisher eigentlich so, dass Shader, Rasterizer State, Blend State etc. logisch zusammengehört haben. Du erzeugst nun halt am Anfang für jede dieser Kombinationen ein Pipeline State Objekt...

Schrompf

Alter Hase

Beiträge: 1 431

Wohnort: Dresden

Beruf: Softwareentwickler

  • Private Nachricht senden

5

16.08.2016, 12:15

Man kann das sicher auch irgendwie hashen und ablegen, aber erstmal stimme ich dot zu: es war doch jetzt schon so, dass man in jeder halbwegs komplexen Engine DrawCalls mit allen notwendigen Parametern sammelt und sortiert. Dann hast Du doch pro DrawCall eh einen Gesamt-Blob. Entweder man lässt sich jetzt was wirklich Cleveres einfallen, um wiederkehrende DrawCalls dynamisch zu erkennen und die Blobs vom letzten Frame wieder zuzuordnen. Oder man lagert das Problem an die nächsthöhere Schicht aus und reicht nur ein Interface raus, mit dem sich die Nutzer des Renderers abstrahierte Blobs anlegen können. Der Blob könnte dann z.B. "dieses Modell mit diesem Material" sein, und die Engine kann dann in diesem Blob ablegen, welches Pipeline Object sie für den ShadowMap Pass angelegt hat usw.

Ich theoretisiere hier aber nur rum, weil mir leider bisher die Zeit gefehlt hat, tatsächlich mal was damit zu machen.
Häuptling von Dreamworlds. Baut aktuell an nichts konkretem, weil das Vollzeitangestelltenverhältnis ihn fest im Griff hat. Baut daneben nur noch sehr selten an der Open Asset Import Library mit.

David_pb

Community-Fossil

Beiträge: 3 886

Beruf: 3D Graphics Programmer

  • Private Nachricht senden

6

17.08.2016, 12:39

Tatsächlich stellt PSO-Management eins der häufigsten Probleme dar. Wenn deine Engine (wie viele Engines) ein DX11 (oder sogar DX9) orientiertes Design hat, ist das weitgehend inkompatibel mit vielen DX12 Konzepten. Der einzige Vorteil den du dann hast, ist, das du mal siehst was du dem Treiber bisher zugemutet hast! (;))

Also: Idealerweise würdest du dein Usercode/Highlevel-Render-Code/etc (wie bereits von dot und Schrompf angesprochen) so designen das du im Voraus weißt was für Pipelines du brauchst. D.h. du könntest PSOs wie Assets behandeln und einfach mit allen anderen Assets laden. Dafür brauchst du Kontrolle über deine Pipeline, also keine fein granulares "SetXYZ"-Stateinterface mehr. Mit einem "Stateless-Rendering"-Design (einfach mal googlen) bekommst du das quasi "umsonst". Das hat viele nette Nebeneffekte, dein Rendercode wird deutlich sauberer, dein Spiel bekommt keine "zufälligen" Framespikes usw...

Falls ein Refactoring für dein Highlevel-Code nicht möglich ist dann gibt es natürlich andere Optionen. Viele Engines haben eine art Statemanager in dem Pipeline-States getracked werden. Wenn du einen Draw/Dispatch absetzt wird ein neues PSO erzeugt (oder ein altes, äquivalentes PSO aus einem Dictionary geladen). Der Ansatz funktioniert selbst mit "DX9-Style" Interfaces aber kann extreme Framedrops zur Folge haben. Das Problem ist nämlich, dass die Zeit zum Compilen von PSOs gern mal im Millisekundenbreich liegen kann. Um das zu vermeiden kannst du eine Liste von den am häufigst genutzten PSOs führen und beim Programmstart erstellen. Wie du an die Informationen kommst bleibt dir überlassen, das kann so simpel sein wie, einfach das Spiel zu spielen und sich alle erzeugten PSO-Beschreibungen zu dumpen, fertig! (Doom macht das z.B. so mit deren Vulkan Implementierung).

Damit wirst du aber sicherlich keine optimale Performanz erreichen können. Dafür ist es absolut notwendig dein Design auf einer hohen Ebene zu ändern:

"DX12-Backends profitieren von Applikationswissen und sollten so flach wie möglich sein. Einen DX11-Treiber zu emulieren wird zwangsläufig in schlechter(er) Performanz enden"

Ein wesentlicher Unterschied scheint mir im Moment vor allem das Erstellen eines Pipeline-State Objekts zu sein.


Auch andere Konzepte unterscheiden sich deutlich von DX11/GL. PSOs sind nur eines von vielen Puzzleteilen (aka Stolpersteinen??) die notwendig sind um ein wirklich performantes DX12-Backend zu bekommen.
@D13_Dreinig

Werbeanzeige