DirectX 12 Multi-engine: asynchronní shadery v praxi
20.11.2015, Pavel Šantrůček, recenze
Co jsou to asynchronní shadery a k čemu vlastně slouží? Jak zapadají do kontextu DirectX 12? Které grafické karty je podporují, které zase ne a proč? V dnešním článku odpovíme právě na takovéto otázky.
Kapitoly článku:
DirectX 11
My jsme si fungování DirectX vysvětlili již dříve v našem článku Grafická pipeline: jak se vytváří obraz. Abyste ale nemuseli opětovně číst celý tento článek, v rychlosti vše zopakuji.
Engine hry, tedy vlastně jeho část nazvaná Renderer (vykreslovač), vytváří příkazy na vykreslení objektu. Tyto příkazy jsou zasílány do API DirectX, které by se mělo následně postarat o vykreslení objektu na grafické kartě. Vše se tak děje pomocí jediného jádra procesoru.
Příkazy, které hra vytváří, jsou různého typu a nás dnes budou zajímat především následující tři. Příkaz na vykreslení (Draw call) obsahuje informace co vykreslit, jak to vykreslit a co k tomu použít (třeba texturu). Příkaz výpočetní (Dispatch call) obsahuje informace, co vypočítat a co k tomu použít (třeba tu samou texturu) a konečně příkaz kopírovací, který zase obsahuje informace o tom, co a kam zkopírovat.
V DirectX Runtime jsou tyto příkazy nejdříve validovány a některé příkazy jsou zde sloučeny, UMD (User Mode Driver) následně příkazy zkompiluje (přeloží) do kódu, kterému daná grafická karta rozumí. U grafických karet Nvidia je zde proveden také základní sheduling (ošetření různých závislostí, reorder atp.).
Když UMD svou práci dokončí, takto upravené příkazy (Command buffers) putují do zásobníku nazvaného Context queue, kde jsou tyto příkazy shromažďovány až do počtu 3 snímků. Z tohoto zásobníku pak Kernel Sheduler vybírá, jaké příkazy (z jaké aplikace) na grafickou kartu odešle k exekuci. Když se rozhodne, vybrané příkazy jsou zaslány do KMD (Kernel Mode Driver).
V KMD musí být každý příkaz, který obsahuje nějaký odkaz (adresu) na zdroj v paměti (naší texturu), zkontrolován, jestli jsou tyto odkazy platné. Pokud se adresa zdroje v paměti změnila, musí být také opraven odkaz v našem příkazu. Pokud odkazovaný zdroj v paměti není umístěn vůbec, musí se do paměti nejdříve nahrát. Teprve až se KMD ujistí, že vše je v pořádku a všechny zdroje jsou alokovány na těch správných místech (adresách) v paměti a daný příkaz má tedy k dispozici vše, co bude ke své práci potřebovat, odešle konečně tyto příkazy pomocí jediné příkazové fronty (Command queue) na zpracování ke GPU.
Grafická karta, konkrétně její část GCP (Graphics Command Processor), pak z tohoto seznamu příkazů (Command list) bere sekvenčně tyto příkazy a odesílá je na výpočetní jednotky GPU k vlastnímu zpracování.
Je to sice vše hodně zjednodušeně napsáno, ale nám to pro další vysvětlení stačit rozhodně bude. Sami vidíte, že než naše příkazy doputovaly na GPU, trávily v DirectX nezdravě dlouhou dobu (API overhead). Co je ale pro nás dnes podstatné, celá pipeline je výsostně sériovou záležitostí, protože příkazy jsou na GPU zasílány jedinou frontou sekvenčně (tedy jeden za druhým), paralelní exekuce těchto příkazů je tedy prakticky vyloučena.