Architektur und Programmierung von Grafik- und Koprozessoren
Die Grafik Pipeline
Stefan Zellmann
Lehrstuhl f¨ur Informatik, Universit¨at zu K¨oln
SS2019
Lernziele
1. Host Interface- die Studierenden verstehen das
Zusammenspiel zwischen “Kernel Mode” und “User Mode”
Ger¨atetreibern, die mehreren Betriebssystemprozessen den gleichzeitigen Zugriff auf die Grafikkarte erlauben.
2. Kommandoverarbeitung - die Studierenden verstehen den Kontrollfluss von Zeichenkommandos, die die Applikation an die Grafikkarte verschickt.
3. Architekturen- die Studierenden kennen
Architekturprinzipien, die bei modernen Grafikkarten eine Rolle spielen.
4. Moderne Grafik APIs - die Vorlesungseinheit bereitet die Studierenden auf moderne Grafik APIs wie DirectX 12 oder Vulkan vor. Die Studierenden verstehen, welche Rolle
Nebenl¨aufigkeit und Synchronisation bei der Programmierung moderner Grafikkarten spielen.
Kurze Einf¨ uhrung in Grafik APIs
Immediate Mode vs. Retained Mode APIs
Immediate Mode APIs
Application Library Display
Updates Scene
Draw Commands
Abbildung:vgl. Windows Dev Center - Windows Graphics: Retained Mode Versus Immediate Mode.
Immediate Mode vs. Retained Mode APIs
Retained Mode APIs
Application Library Display
Updates Scene
Draw Commands Update Commands
Abbildung:vgl. Windows Dev Center - Windows Graphics: Retained Mode Versus Immediate Mode.
Immediate Mode APIs
3D APIs traditionellImmediate Mode - wenn Programm Zeichenbefehl spezifiziert,sieht es so aus, als w¨urde der Befehl unmittelbar ausgef¨uhrt.
Realit¨at: Treiberpuffert Kommandos und schickt Batches von Zeichenbefehlen an GPU. Batches beinhalten potentiell Zeichenbefehle von verschiedenen Threads oder sogar
verschiedenen Applikationen. Komplizierte Heuristiken, um zu entscheiden, wie gepuffert wird.
Das kann teils zu ¨uberraschendem Performanzverhalten f¨uhren!
Moderne APIs (Vulkan, D3D12): nicht Immediate, Applikation steuert, wann welche Speicherbefehlezu submittieren sind, sowie Abh¨angigkeiten zwischen Kommandos + Synchronisation ⇒viel weniger komplexe Treiber.
Immediate Mode APIs
I Auf den folgenden Folien: OpenGL-¨ahnlicher Pseudo Code dient zur Illustration, Programmausschnitte unvollst¨andig.
I Kein OpenGL Tutorial, nur Konzepte.
I Konzepte gelten auch f¨ur alte Direct3D Versionen.
Immediate Mode APIs
g l B e g i n ( G L _ T R I A N G L E S );
// Red t r i a n g l e g l C o l o r 3 u b (255 ,0 ,0);
g l V e r t e x 3 f (0 ,0 ,0);
g l V e r t e x 3 f (1 ,0 ,0);
g l V e r t e x 3 f (1 ,1 ,0);
// G r e e n t r i a n g l e g l C o l o r 3 u b (0 ,255 ,0);
g l V e r t e x 3 f (0 ,0 ,0);
g l V e r t e x 3 f (1 ,0 ,0);
g l V e r t e x 3 f (1 ,1 ,0);
g l E n d ();
Immediate Mode APIs
I Immediate Mode APIs bilden den Zeichenalgorithmus ab, nicht die zugrundeliegende Hardware.
I Hardware:hochparallel, f¨ur hohen Durchsatzoptimiert.
I Besonderes Merkmal von GPUs: hohe Bandbreite, daf¨ur vergleichsweise hohe Latenz: z. B. bei Host-Interconnect (PCIe), aber auch bei GDDR Speicher.
I Immediate Mode Operationen wie die von oben h¨atten eine unglaublich hohe Latenz ⇒ Pufferung n¨otig.
I Frage: wer puffert Daten?
I Treiber: Produktivit¨at.
I Anwendungsentwickler: applikationsspezifisches Wissen⇒ h¨oheres Potential f¨ur bessere Performanz.
Immediate Mode APIs
Graphic APIs, egal welche, unterst¨utzen heute zumindest Pufferung von Daten:
// O n l y o n c e :
g l B i n d B u f f e r ( G L _ A R R A Y _ B U F F E R , vbo );
g l B u f f e r D a t a ( G L _ A R R A Y _ B U F F E R , n u m _ v e r t s , verts , G L _ S T A T I C _ D R A W );
// Later , w h e n r e n d e r i n g :
g l B i n d B u f f e r ( G L _ A R R A Y _ B U F F E R , vbo );
g l D r a w B u f f e r ( vbo );
Anwender hat aber generell wenig Kontrolle, wann Daten kopiert werden, welche Speicherbereiche genutzt werden etc.
GPU Zustandsmaschine
Traditionelle GPU APIs implementieren den
Rasterisierungsalgorithmus mittels Zustandsmaschinen:
g l A c t i v e T e x t u r e ( G L _ T E X T U R E 0 );
g l B i n d T e x t u r e ( G L _ T E X T U R E _ 2 D , tex );
g l T e x I m a g e 2 D ( . . . ) ; g l E n a b l e ( G L _ L I G H T 0 );
g l L i g h t f v ( G L _ L I G H T 0 , G L _ P O S I T I O N , pos );
g l M a t r i x M o d e ( G L _ M O D E L V I E W );
g l L o a d M a t r i x ( mv );
gefolgt von Zeichenbefehlen:
g l B i n d B u f f e r ( G L _ A R R A Y _ B U F F E R , vbo );
g l D r a w B u f f e r ( fb );
g l X S w a p B u f f e r s (); // p l a t f o r m s p e c i f i c !
GPU Zustandsmaschine
glActiveTexture(GL TEXTURE0)- aktive Textureinheit ist jetzt
’0’.
glEnable(GL LIGHT0)- aktive Lichtquelle ist jetzt ’0’.
glMatrixMode(GL MODELVIEW)- als n¨achstes wird MV Matrix ver¨andert.
glBindBuffer(GL ARRAY BUFFER, vbo)- der gerade gebundene Buffer ist Vertex-Buffer mitHandle’vbo’.
GPU Zustandsmaschine
Programmablauf exemplarisch f¨ur (altes) OpenGL:
1. Erzeuge Fenster, erzeuge OpenGL Kontext(e). Binde Kontexte an Threads.
2. Initialisiere Framebuffer, Zeichnen in Backbuffer etc.
3. Starte “Render-Loop”:
I Pushe intrinsische Kameraparameter und globale Kameratransformation auf Matrix Stack.
I Traversiere Szenengraph (Baumstruktur, die Geometrie hierarchisch mit Transformationen / Materialeigenschaften etc.
verkn¨upft).
I Pushe individuelle Transformationen auf Matrix Stack.
I Initialisiere Materialien / Texturen etc. per Geometrie.
I Submitte Geometrie (Vertex Buffer).
I Setze Beleuchtungsparameter, Zeichen-State (Depth Buffering, Alpha Blending, Backface Culling, ...)
I Pr¨asentiere Bild, indem Front- und Backbuffer vertauscht werden.
GPU Zustandsmaschine
Zustand wurde / wird inKontexten gespeichert. Kontext speichert gesamten Zustand zu Zeitpunktt.
Shading State 1 Diffuse:
Specular:
Rough: 1.0 Light-Pos: (0,0,-1) Light-Col.:
Geom. Buffers
EnableBlending Shading State 2 Diffuse:
Specular:
Rough: 0.0 Light-Pos: (1,0,1) Light-Col.:
DisableDepth SetClipPlane
Geom. Buffers
Present
GPU Zustandsmaschine
Kontexte von GPU und API verwaltet, Benutzer kann Zustand durch API Calls ver¨andern.
// GPU K o n t e x t ( i m p l i z i t ) {
b l e n d i n g : no d e p t h t e s t : yes d i f f u s e : (255 ,0 ,0) s p e c u l a r : ( 2 5 5 , 2 5 5 , 2 5 5 )
r o u g h : 1.0
l i g h t 1 : d i s a b l e d ; l i g h t p o s 1 : (0 ,0 ,1) l i g n t c o l 1 : ( 2 5 5 , 2 5 5 , 2 5 5 ) c l i p p l a n e 1 : no
}
// P r o g r a m m :
g l E n a b l e ( G L _ L I G H T 1 );
g l L i g h t f v ( G L _ L I G H T 1 , G L _ P O S I T I O N , { 0 ,0 , -1 });
GPU Zustandsmaschine
I GPU Kontexte sind sehr schwergewichtig, speichern gesamten Rendering State.
I Fr¨uhe API Versionen: nicht CPU Multi-Threading “aware”.
Ein Kontext pro Thread, kein Sharing, kein Austausch und keine Synchronisation.
I Umschalten zwischen Threads: binde ganz anderen Kontext, unklar, welcher State sich unterscheidet.
Ressourcen Handles
I Ressourcen werden ¨uberHandlesverwaltet. Einfache Datentypen (GLint,GLenum), teils Objekte mit opaker Struktur (z. B. GLXContext).
I Kein direkter Zugriff auf GPU Speicher, keine Pointer etc.
I Ressourcen sind an Kontexte gebunden, Teilen von Ressourcen durch mehrere Threads oder Prozesse schwergewichtig.
Zeichenbefehle
Der eigentliche Algorithmus steckte in den Zeichenbefehlen und war in den Anfangszeiten von GPUs außer ¨uber denState nicht beeinflussbar.
g l B i n d B u f f e r ( G L _ A R R A Y _ B U F F E R , vbo );
g l D r a w B u f f e r ( fb );
g l X S w a p B u f f e r s ();
Zeichenbefehle
g l F i n i s h (); // or
g l F l u s h (); // or
g l X S w a p B u f f e r s (); // or ..
Verschiedene Kommandos (Zeichnen, State Change, etc.) laufen beim API auf. Es ist dem API / Treiber ¨uberlassen, wann die Befehle ausgef¨uhrt werden (direkt oder sp¨ater). Kommandos wie SwapBuffer(),Flush(),Finish()f¨uhren dazu, dass die Pipeline stalled und die aufgelaufenen Befehle (in endlicher Zeit, nicht notwendigerweise sofort) abgearbeitet werden m¨ussen.
Shader Programme
Sp¨atere GPUs: Shader Programme, die den Ablauf des
Rasterisierungsalgorithmusauf der GPU selbstbeeinflussten (vgl.
AlgorithmusRasterisierung):
a c t i v a t e _ v e r t e x _ b u f f e r ( h a n d l e ) d r a w _ t r i a n g l e s () {
for ( e a c h v e r t e x )
v e r t e x _ s h a d e r (); /* - - - - */
t r i a n g l e _ s e t u p ();
for ( e a c h t r i a n g l e ) s c a n _ c o n v e r t ();
for ( e a c h f r a g m e n t ) for ( e a c h l i g h t )
f r a g m e n t _ s h a d e r (); /* - - - - */
d e p t h _ t e s t ();
a l p h a _ b l e n d i n g ();
}
p r e s e n t ();
Shader Programme
I C-artige Programme, die auf GPU ablaufen. Werden an dedizierten Einsprungpunkten in die Grafik Pipeline eingeh¨angt.
I Mit Vertex Shadernkann die Vertex Transformationsphase (Model-View und Perspektivische Transformation, Clipping, Transformation in normalisierte Ger¨atekoordinaten)
modifiziertwerden.
I Geometrie Shader schließen sich an Vertex Phase an.
Programm erh¨alt ein Vertex als Input und emittiert weitere Vertices.
I Mit Fragment Shadern kann die Fragment Phase modifiziert werden, im Rahmen derer die Fragment Farbe bestimmt wird.
Shader Programme
Nomenklatur
Bezeichnungen weichen je nach API und Konvention etwas ab.
Manchmal werden die KonzepteShaderund Programmvermischt.
D3D nennt Fragment ShaderPixel Shader.
Wir verwenden dieOpenGLKonvention: Vertex Shader,Fragment Shaderund ggf. weitere bilden zusammen einShader Programm.
Shader Programme
Shading Languages
I Es existieren eine Reihe:
I GLSL (“GLSlang”) - Teil des OpenGL Standards.
I HLSL - Microsoft DirectX Shading Language.
I Nvidia Cg - identisch mit HLSL, jedoch kompatibel mit OpenGL.
I API-neutrale Sprachen, z. B. OpenShadingLanguage; Sprachen f¨ur spezielle APIs wie z. B. Pixars RenderMan.
I GL ARB fragment program (OpenGL 1.3) - erste OpenGL Spezifikation f¨ur programmierbare Fragment Stage,
Assembler-artig, kein Branching etc.
Shader Programme
I Shader Programme werden hochparallel ausgef¨uhrt.
I Implizites paralleles Programmiermodell.
I Keinerlei Zugriff auf andere Shader Instanzen.
I Vulkan / Modernes OpenGL: minimaler Vertex Shader verpflichtend (außer Compute). Ohne minimalen Fragment Shader kein Bild (manchmal Ergebnis kein Bild).
Vertex Shader
Einfacher Vertex Shader (lose basierend aufOpenGL Shading Language(GLSL)) . Applikation verwaltet Viewing
Transformationsmatrix und perspektivische Transformationsmatrix und ¨ubergibt sie an alle Vertex Shader Instanzen.
a t t r i b u t e v e c 3 p o s i t i o n ; in m a t 4 v i e w _ m a t ;
in m a t 4 p r o j _ m a t ; v o i d m a i n () {
g l _ P o s i t i o n = v i e w _ m a t * p r o j _ m a t * v e c 4 ( p o s i t i o n , 1 . 0 ) ; }
Vertex Shader
Benutzerspezifische globale Attribute:
a t t r i b u t e v e c 3 p o s i t i o n ; in m a t 4 v i e w _ m a t ; // g l o b a l in m a t 4 p r o j _ m a t ; // g l o b a l in f l o a t t i m e ; // g l o b a l v o i d m a i n () {
p o s i t i o n . x += cos ( t i m e );
p o s i t i o n . y += sin ( t i m e );
g l _ P o s i t i o n = v i e w _ m a t * p r o j _ m a t * v e c 4 ( p o s i t i o n , 1 . 0 ) ; }
Vertex Shader
Benutzerdefinierteper Vertex Attribute:
a t t r i b u t e v e c 3 p o s i t i o n ; // per v e r t e x in m a t 4 v i e w _ m a t ;
in m a t 4 p r o j _ m a t ;
a t t r i b u t e v e c 3 n o r m a l ; // per v e r t e x v o i d m a i n () {
...
g l _ N o r m a l = t r a n s f o r m ( normal , v i e w _ m a t , p r o j _ m a t );
...
}
Vertex Shader
Vertex Output geht sp¨ater durch Raster Engines⇒ benutzerdefinierte Attribute werden w¨ahrend Scan Konvertierung interpoliert!
varying: interpolierte Attribute stehen sp¨ater in Fragment Phase zur Verf¨ugung.
a t t r i b u t e v e c 3 p o s i t i o n ; in m a t 4 v i e w _ m a t ;
in m a t 4 p r o j _ m a t ; v a r y i n g v e c 3 n o r m a l ; v a r y i n g v e c 2 uv ; v o i d m a i n () {
...
}
Fragment Shader
Einfacher Fragment Shader mit diffusem Beleuchtungsmodell.
varyingAttribute aus Vertex Shader. Fragment-spezifischer Input (z. B.light dir).
// S i m p l e d i f f u s e s h a d e r in s a m p l e r 2 D tex ;
in v e c 3 l i g h t _ d i r ; v a r y i n g v e c 3 n o r m a l ; v a r y i n g v e c 2 uv ; out v e c 4 f r a g _ c o l o r ; v o i d m a i n () {
// 2 - D t e x t u r e a c c e s s
v e c 3 d i f f = t e x 2 D ( tex , uv );
// S i m p l e ( single - s i d e d ) L a m b e r t s h a d i n g d i f f *= max (0.0 , dot ( l i g h t _ d i r , n o r m a l ));
// W r i t e r e s u l t
f r a g _ c o l o r = ve c 4 ( diff , 1 . 0 ) ; }
Shader Programme
I Neue APIs: mehr programmierbare Pipeline Stages.
I Geometrie Shader: folgen auf Vertex Stage. Programmatisch Erzeugung weiterer Polygone.
I Tesselation Shader: niedrig aufgel¨oste Geometrie kann durch Tesselierungverfeinert werden, z. B. mit Bezier Patches (Subdivision SurfaceAlgorithmen).
I Weitere programmierbare Stages z. B. im Zusammenhang mit Multisampling.
I Wir gehen vereinfachend nur von Vertex und Fragment Shadern aus.
Shader Programme
Shader werdenzur Programmlaufzeitkompiliert und gelinkt.
G L u i n t vs = g l C r e a t e S h a d e r ( G L _ V E R T E X _ S H A D E R );
G L u i n t fs = g l C r e a t e S h a d e r ( G L _ F R A G M E N T _ S H A D E R );
g l S h a d e r S o u r c e ( vs , s t r l e n ( v e r t _ s h a d e r _ s t r ) , v e r t _ s h a d e r _ s t r , 0);
g l C o m p i l e S h a d e r ( vs );
g l S h a d e r S o u r c e ( fs , s t r l e n ( f r a g _ s h a d e r _ s t r ) , f r a g _ s h a d e r _ s t r , 0);
g l C o m p i l e S h a d e r ( fs );
G L u i n t p r o g = g l C r e a t e P r o g r a m ();
g l A t t a c h S h a d e r ( prog , vs );
g l A t t a c h S h a d e r ( prog , fs );
g l L i n k P r o g r a m ( p r o g );
g l U s e P r o g r a m ( p r o g );
Shader Programme
I Laufzeitkompilation und Linking.
I Laufzeit Overhead (wegen Caching meistens nur erster Programmlauf).
I OpenGL Runtime muss Compiler integrieren.
I Traditionell sehr fehleranf¨allig - IHVs (Independent Hardware Vendors) legen Sprachstandard unterschiedlich aus.
I Treiber muss Compiler-generierten Intermedi¨arcode in Maschinencode ¨ubersetzen.
I Shader Programme stehen im Klartext im Binary, k¨onnen einfach mit Hex-Editor ausgelesen werden.
I Vulkan API: Shader werden zur Compile Zeit in optimierten Intermedi¨arcode (SPIR-V) ¨ubersetzt.
Hierarchische Pipeline
Alte Versionen von Direct3D und OpenGL hatten hierarchische Pipelines:
I Stack f¨ur Transformationsmatrizen.
I Stack f¨ur generellen State.
I Wende Transformationen / Materialien etc. auf Teile der Geometrie an, indem State / Transformationen auf Stack gepush()ed werden. Wenn entsprechende Teile der Geometrie gezeichnet,pop() vom Stack.
Hierarchische Pipeline
Neue APIs gehen davon aus, dass die Applikation den hierarchischen State samt Transformationen verwaltet (z. B.
Szenengraph Bibliothek), und dass Transformationen als uniforme Variablen anShader Instanzen¨ubergeben werden.
Kompletter Matrix Stack in OpenGL deprecated. Viele
Betriebssystemhersteller (insb. Microsoft, Apple) unterst¨utzen nur sehr alte OpenGL Versionen, daher noch viel legacy Code, der auf alten OpenGL Konzepten aufbaut.