Grafická pipeline: jak se vytváří obraz
18.2.2015, Pavel Šantrůček, článek
Dnes se podíváme na grafickou pipeline tak, aby souvislosti byly co nejvíce srozumitelné i pro čtenáře, kteří se o tuto problematiku dosud nezajímali. Půjde o předzvěst dalších článků o grafických kartách včetně recenzí zajímavých modelů.
Kapitoly článku:
Dříve než přiletíme nad oblast potrubí s názvem DirectX, raději trochu zpomalím kvůli vysvětlení jedné důležité věci, o které byla zmínka v minulé kapitole. Co jsou to Shadery?
Shadery jsou více či méně komplexní programy, fragmenty kódu nebo funkce, které běží na grafické kartě (resp. na jejích „stream procesorech“). Ulevují tak zátěži CPU v herní smyčce a jejich funkcí je většinou manipulovat s vertexy nebo pixely vykreslovaných objektů (odtud jsou výrazy jako „vertex shader“ nebo „pixel shader“). Jsou psány jazykem vyšší úrovně silně připomínajícím jazyk C. U DirectX se tento jazyk nazývá HLSL (High Level Shader Language) a u OpenGL zase GLSL (OpenGL Shader Language).
Takže doletěli jsme nad DirectX a vidíme, že se nám tohle potrubí trochu klikatí:
Nad tímto poletíme s patřičnou úctou a hodně vysoko. Nad některými úseky potrubí budeme muset snížit výšku, tak jen doufám, že se nezřítíme.
Tady poletíme vysoko. V této startovní části API přijímá požadavky na vykreslení z aplikace (Draw Calls). Nějakým způsobem tyto požadavky validuje a může i kontrolovat případné chyby v různých parametrech nebo v kódu shaderů. Dále se pokouší (někdy úspěšně a někdy zase ne) nalézt nějaké souvislosti mezi jednotlivými Draw Calls a pokud nějaké nalezne, může některé Draw Calls sloučit dohromady.
Pokud je práce v hotova, upravené požadavky na vykreslení jsou následně odesílány do části UMD (User Mode Driver), který je poměrně důležitou součástí našeho potrubí, takže malinko ubereme výšku a hodně změníme směr.
UMD je pro nás jedna z nejzajímavějších zastávek celého potrubí DirectX. V první řadě je třeba poznamenat, že tato část pipeline není součástí DirectX jako takového. Je to DLL knihovna, která je součástí ovladače grafické karty daného výrobce. Zde se provádí samotná kompilace shaderů do kódu, kterému grafická karta rozumí. Zde se také na tomto kódu provádí celá řada optimalizací, které však přesahují rozsah tohoto článku. Knihovna UMD pracuje ve stejném adresním prostoru jako program hry a každá aplikace využívající DirectX pracuje s vlastní instancí této knihovny. Pokud někdy dojde k pádu knihovny UMD z důvodu nějaké chyby (třeba při kompilaci), dojde k pádu také aplikace, která tuto konkrétní instanci UMD využívá (samotné Windows a ostatní aplikace tím ale nejsou postiženy).
Pro nás je zde důležitá ještě jedna věc. Pokud výrobce grafické karty vydává nový ovladač, v kterém slibuje nárůsty výkonu v některých hrách, pak se tyto optimalizace s největší pravděpodobností odehrávají právě v této knihovně. Fungovat by to mělo přibližně následujícím způsobem.
Herní vývojář si při vývoji hry programuje shadery. Pokud se na jejím vývoji podílí i nějaký výrobce grafických čipů (Nvidia, AMD), jsou tyto shadery programovány s ohledem na architekturu grafických karet tohoto výrobce. Je nasnadě, že ostatní výrobci jsou tak znevýhodněni. Takže co s tím mají dělat?
Pokud se postižený výrobce dostane ke zdrojovým kódům shaderů, může si pak pro architekturu svých čipů napsat vlastní (a pro něj výhodnější) verzi těchto shaderů. Když pak v průběhu hry dojde na kompilaci HLSL kódu shaderů, jednoduše původní (pro něj nevýhodnou) verzi vymění za verzi shaderu vlastního. Pokud se vše zdaří, máme tu ony slibované nárůsty výkonu.
Poslední věcí, ale asi tou nejdůležitější, kterou má UMD na starosti, je vytváření tzv. „Command buffers“. Jde vlastně o dávkový seznam příkazů a dat v řeči, které konkrétní grafická karta rozumí. Hotový Command buffer je pak vrácen zpět do pipeline DirectX k dalšímu zpracování. Nic dalšího nás tady asi zajímat nebude, takže zůstáváme ve stejné výšce a vracíme se zpět nad potrubí DirectX. Tam v dáli je vidět nějaký velký zásobník, takže rychle k němu.
Naší další zastávkou je„Content Queue“, což je vlastně fronta (zásobník), kde se shromažďují a ukládají Command buffers vytvořené v UMD. U DirectX se do této fronty vejdou Command buffers v maximálním množství 3 hotových snímků. Fronta má jediný účel, kterým je absorbování nepravidelnosti dodávek Draw Calls do API z herní smyčky aplikace. Pokud se herní smyčka opozdí a po určitou dobu nedodává na zpracování do API žádné Draw Calls, zbytek pipeline se nezastaví, ale čerpá Command Buffer právě z tohoto zásobníku. Zásobník se opětovně naplní, až herní smyčka začne znovu generovat nové Draw Calls.
Letíme-li nízko, tak tento zásobník „předhotovených“ snímků se zdá mít jen samá pozitiva a světlou budoucnost, ale nenechte se zmýlit, toto řešení s sebou přináší i nějaké nevýhody. Poletíme-li výše tak, abychom viděli grafické potrubí celé, ti přemýšlivější už to asi uvidí. My se ale k nevýhodám tohoto zásobníku dostaneme později, až zde budeme někdy zkoumat Input lag.
Zásobník jsme obletěli, takže vzhůru na další zastávku tam, kde vidíme nějaký plánovač.
Úkolem tohoto plánovače je rozhodnout, který Command Buffer ze zásobníku bude přednostně odeslán do další zastávky pipeline (KMD).
DirectX a jeho potrubí v jednom okamžiku nemusí využívat pouze vaše hra. Pokud hrajete hru v okně, je třeba zobrazovat i okolí tohoto okna. I když je to velmi nepravděpodobné, můžete hrát také 2 hry najednou. Z proletu nad UMD již víme, že každá aplikace přistupující k DirectX disponuje svou vlastní instancí UMD, který generuje Command Buffers. V grafické pipeline tedy mohou být Command Buffers z různých aplikací a právě Kernel Scheduler rozhoduje o tom, který Command Buffer z jaké aplikace bude mít přednost a bude pokračovat potrubím dále, a který bude muset počkat. Jakmile Kernel Scheduler rozhodne o vítězi, odešle jej do další a poslední zastávky – Kernel Mode Driver. My tam samozřejmě poletíme za ním.
KMD je stejně jako UMD součástí ovladače grafické karty a je to také poslední zastávka pipeline DirectX. KMD je právě ta část pipeline, která komunikuje přímo s hardwarem grafické karty. Odtud je odesílán dávkový Command Buffer na Command Procesor grafické karty s příkazy na vykreslení objektů. Když grafická karta scénu (snímek) na monitoru vykreslí, je o tom KMD informován pomocí HW přerušení. Ačkoliv se zde děje ještě spoustu jiných, důležitých a zajímavých věcí, pro nás jsou už tyto informace nadbytečné. Snad ještě jedna věc stojí za zmínku.
Pokud se pokoušíte o přetaktování grafické karty a váš pokus skončí neúspěchem, pak právě KMD jako jediný může „vytuhlou“ grafickou kartu resetovat a se známou hláškou „Ovladač zobrazení přestal reagovat a byl obnoven“ se mu to většinou i podaří. Windows žijí dál a vy jste spokojeni. Pokud ne, reset počítače to jistě spraví.
V každém případě právě opouštíme vzdušný prostor potrubí DirectX. Myslím, že to nakonec ani tak moc nebolelo. Komu tyto informace nestačily, ať si vezme vrtulník a letí se porozhlédnout sám. Aby toho nebylo najednou zase tak moc, raději teď přistaneme a dáme si krátkou pauzu. Příště už totiž poletíme nad samotnou grafickou kartou a monitorem a čerstvých sil bude jistě potřeba.
Pokud budete chtít přestávku oživit nějakými dotazy či připomínkami, vaše komentáře jsou vítány v diskuzi pod článkem.
Pokračování článku: Grafická pipeline: jak se tvoří obraz II
Shadery jsou více či méně komplexní programy, fragmenty kódu nebo funkce, které běží na grafické kartě (resp. na jejích „stream procesorech“). Ulevují tak zátěži CPU v herní smyčce a jejich funkcí je většinou manipulovat s vertexy nebo pixely vykreslovaných objektů (odtud jsou výrazy jako „vertex shader“ nebo „pixel shader“). Jsou psány jazykem vyšší úrovně silně připomínajícím jazyk C. U DirectX se tento jazyk nazývá HLSL (High Level Shader Language) a u OpenGL zase GLSL (OpenGL Shader Language).
Takže doletěli jsme nad DirectX a vidíme, že se nám tohle potrubí trochu klikatí:
Nad tímto poletíme s patřičnou úctou a hodně vysoko. Nad některými úseky potrubí budeme muset snížit výšku, tak jen doufám, že se nezřítíme.
Direct3D Runtime
Tady poletíme vysoko. V této startovní části API přijímá požadavky na vykreslení z aplikace (Draw Calls). Nějakým způsobem tyto požadavky validuje a může i kontrolovat případné chyby v různých parametrech nebo v kódu shaderů. Dále se pokouší (někdy úspěšně a někdy zase ne) nalézt nějaké souvislosti mezi jednotlivými Draw Calls a pokud nějaké nalezne, může některé Draw Calls sloučit dohromady.
Pokud je práce v hotova, upravené požadavky na vykreslení jsou následně odesílány do části UMD (User Mode Driver), který je poměrně důležitou součástí našeho potrubí, takže malinko ubereme výšku a hodně změníme směr.
User Mode Driver (UMD)
UMD je pro nás jedna z nejzajímavějších zastávek celého potrubí DirectX. V první řadě je třeba poznamenat, že tato část pipeline není součástí DirectX jako takového. Je to DLL knihovna, která je součástí ovladače grafické karty daného výrobce. Zde se provádí samotná kompilace shaderů do kódu, kterému grafická karta rozumí. Zde se také na tomto kódu provádí celá řada optimalizací, které však přesahují rozsah tohoto článku. Knihovna UMD pracuje ve stejném adresním prostoru jako program hry a každá aplikace využívající DirectX pracuje s vlastní instancí této knihovny. Pokud někdy dojde k pádu knihovny UMD z důvodu nějaké chyby (třeba při kompilaci), dojde k pádu také aplikace, která tuto konkrétní instanci UMD využívá (samotné Windows a ostatní aplikace tím ale nejsou postiženy).
Pro nás je zde důležitá ještě jedna věc. Pokud výrobce grafické karty vydává nový ovladač, v kterém slibuje nárůsty výkonu v některých hrách, pak se tyto optimalizace s největší pravděpodobností odehrávají právě v této knihovně. Fungovat by to mělo přibližně následujícím způsobem.
Herní vývojář si při vývoji hry programuje shadery. Pokud se na jejím vývoji podílí i nějaký výrobce grafických čipů (Nvidia, AMD), jsou tyto shadery programovány s ohledem na architekturu grafických karet tohoto výrobce. Je nasnadě, že ostatní výrobci jsou tak znevýhodněni. Takže co s tím mají dělat?
Pokud se postižený výrobce dostane ke zdrojovým kódům shaderů, může si pak pro architekturu svých čipů napsat vlastní (a pro něj výhodnější) verzi těchto shaderů. Když pak v průběhu hry dojde na kompilaci HLSL kódu shaderů, jednoduše původní (pro něj nevýhodnou) verzi vymění za verzi shaderu vlastního. Pokud se vše zdaří, máme tu ony slibované nárůsty výkonu.
Poslední věcí, ale asi tou nejdůležitější, kterou má UMD na starosti, je vytváření tzv. „Command buffers“. Jde vlastně o dávkový seznam příkazů a dat v řeči, které konkrétní grafická karta rozumí. Hotový Command buffer je pak vrácen zpět do pipeline DirectX k dalšímu zpracování. Nic dalšího nás tady asi zajímat nebude, takže zůstáváme ve stejné výšce a vracíme se zpět nad potrubí DirectX. Tam v dáli je vidět nějaký velký zásobník, takže rychle k němu.
Content Queue
Naší další zastávkou je„Content Queue“, což je vlastně fronta (zásobník), kde se shromažďují a ukládají Command buffers vytvořené v UMD. U DirectX se do této fronty vejdou Command buffers v maximálním množství 3 hotových snímků. Fronta má jediný účel, kterým je absorbování nepravidelnosti dodávek Draw Calls do API z herní smyčky aplikace. Pokud se herní smyčka opozdí a po určitou dobu nedodává na zpracování do API žádné Draw Calls, zbytek pipeline se nezastaví, ale čerpá Command Buffer právě z tohoto zásobníku. Zásobník se opětovně naplní, až herní smyčka začne znovu generovat nové Draw Calls.
Letíme-li nízko, tak tento zásobník „předhotovených“ snímků se zdá mít jen samá pozitiva a světlou budoucnost, ale nenechte se zmýlit, toto řešení s sebou přináší i nějaké nevýhody. Poletíme-li výše tak, abychom viděli grafické potrubí celé, ti přemýšlivější už to asi uvidí. My se ale k nevýhodám tohoto zásobníku dostaneme později, až zde budeme někdy zkoumat Input lag.
Zásobník jsme obletěli, takže vzhůru na další zastávku tam, kde vidíme nějaký plánovač.
Kernel Scheduler
Úkolem tohoto plánovače je rozhodnout, který Command Buffer ze zásobníku bude přednostně odeslán do další zastávky pipeline (KMD).
DirectX a jeho potrubí v jednom okamžiku nemusí využívat pouze vaše hra. Pokud hrajete hru v okně, je třeba zobrazovat i okolí tohoto okna. I když je to velmi nepravděpodobné, můžete hrát také 2 hry najednou. Z proletu nad UMD již víme, že každá aplikace přistupující k DirectX disponuje svou vlastní instancí UMD, který generuje Command Buffers. V grafické pipeline tedy mohou být Command Buffers z různých aplikací a právě Kernel Scheduler rozhoduje o tom, který Command Buffer z jaké aplikace bude mít přednost a bude pokračovat potrubím dále, a který bude muset počkat. Jakmile Kernel Scheduler rozhodne o vítězi, odešle jej do další a poslední zastávky – Kernel Mode Driver. My tam samozřejmě poletíme za ním.
Kernel Mode Driver
KMD je stejně jako UMD součástí ovladače grafické karty a je to také poslední zastávka pipeline DirectX. KMD je právě ta část pipeline, která komunikuje přímo s hardwarem grafické karty. Odtud je odesílán dávkový Command Buffer na Command Procesor grafické karty s příkazy na vykreslení objektů. Když grafická karta scénu (snímek) na monitoru vykreslí, je o tom KMD informován pomocí HW přerušení. Ačkoliv se zde děje ještě spoustu jiných, důležitých a zajímavých věcí, pro nás jsou už tyto informace nadbytečné. Snad ještě jedna věc stojí za zmínku.
Pokud se pokoušíte o přetaktování grafické karty a váš pokus skončí neúspěchem, pak právě KMD jako jediný může „vytuhlou“ grafickou kartu resetovat a se známou hláškou „Ovladač zobrazení přestal reagovat a byl obnoven“ se mu to většinou i podaří. Windows žijí dál a vy jste spokojeni. Pokud ne, reset počítače to jistě spraví.
V každém případě právě opouštíme vzdušný prostor potrubí DirectX. Myslím, že to nakonec ani tak moc nebolelo. Komu tyto informace nestačily, ať si vezme vrtulník a letí se porozhlédnout sám. Aby toho nebylo najednou zase tak moc, raději teď přistaneme a dáme si krátkou pauzu. Příště už totiž poletíme nad samotnou grafickou kartou a monitorem a čerstvých sil bude jistě potřeba.
Pokud budete chtít přestávku oživit nějakými dotazy či připomínkami, vaše komentáře jsou vítány v diskuzi pod článkem.
Pokračování článku: Grafická pipeline: jak se tvoří obraz II