On je dost problém v tom, že se v dnešních hrách všechny "modely" neustále mění. Lidi proste chtějí animace a chtějí aby se od sebe postavy/domy/tráva/kameny lišili.
Je úplně jedno, že scéna obsahuje 1000 "stejných" postav, když každá postava je v trochu jiný fázy animace, to znamená jinej model, jinej model znamená samostatný draw cally.
Navíc už dávno nestačí aby byla postava 1 model s 1 texturou. Přehazujeme brnění, oblečení, zbraně a kdoví co ještě (včetně zuby? oči?...). Není jednoduchý programově složit několik animovaných objektů se samostatnými texturami (meshů) do jednoho objektu s jednou texturou.
A v případě nezávislých animací to výkonově není ani možný. Vemte si třeba pohyb očí, kdyby oči nebyly samostatnej objekt tak se vám každej frame pohybu oka mění ta gigantická textura na gigantickým modelu co by byla pro renderování ideální. Jenže v dnešním DX/OGL by to znamenalo to texturu nagenerovat pokaždý znova a poslat ji celou znova do grafický karty.
Tím se dostávám k materiálům: kovový zbraně mají materiál který se pro světlo chová jinak než kožené brnění atd.. V praxi to znamená, že se aplikují jiné shadery, což zase znamená, že to bude minimálně samostatná textura a takřka jistě samostatný objekt.
Nevím jestli DX/OGL umožnuje jednoduše aplikovat shader na část objektu, ale enginy ne. O tomhle bylo demo s růžně barvenou tříkolkou u tuším unreal enginu 4, takže aktuálně by to možná v nejmodernějších enginech už šlo, ale znamená to grafiky naučit pracovat s novejma metodama a v novejch nástrojích, taže zase roky zpoždění před nasazením do praxe..
Pak k tomu přihoďte fyziku, třeba povlávání vlasů, trávy a oblečení ve větru. Na základě fyziky spočítaný animace nejdou předpočítat nijak předem. Takže nejen, že přibývá spousta animací, ale ještě je každá animace z pohledu renderingu úplně jiná a musí se nestále dokola samostatně přepočítávat.
Zkuste si klidně zprogramovat některý z prastarejch (ale pořád aktuálních) tutoriálů pro OpenGL. Nejdřív Vám ukážou display listy, aby se každá krabice nemusela posílat do GPU pořád znova, a hned v další lekci je, že pak nejdou animace. Výsledkem je, že si do display listu dáte krabice bez předních stěn, ktery tam pak doděláváte samostatně. protože jim chcete měnit barvy nebo tak něco.
No a ve stávajících DX/OpenGL tohle všechno vždycky putuje na grafickou kartu jednou cestou a pouze v jednom vláknu. (Multithreaded rendering to trochu zlepšuje, ale stejně nejde rvát modely do grafiky paralelně 100% času viz dál).
Takže čím modernější hra, kde se všechno hejbe tím menší šance je na zmenšení počtu volání API funkcí (drawcalls)
V DX a OGL si driver hlídá stavy všeho v paměti GPU, takže minimálně v každym framu a spíš i při volání některých funkcí, řídící vlákno zastaví veškerou manipulaci s GPU částí systému (zjednodušeně) zkontroluje stav všeho co potřebuje pro vykonání dané funkce, případně udělá nějaký akce aby se dostalo do stavu kdy může být ta funkce provedena a práce mezi tím stojí. To je první část driver overheadu.
Další část část driver overheadu je daná přímo VDDM modelem. Aplikace běží user módu (což v podstatě znamená, že nemůže rozbít windows), ale DX/OGL grafický drivery a rendering běží v kernel módu (což znamená, že když se tam něco rozbije tak to v lepším případě končí bluescreenem). Jenže díky tomu volání funkcí mezi aplikací a driverem podléhá spoustě chaosu a zdržení, kterýmu se říká context switch. V podstatě jde o softwarovej interrupt, uložení celýho stavu procesoru: registry, stack atd. a po skonční interruptu zase obnovní zpátky. (pokud to někoho zajímá najděte si jak funguje "NT system call").
Context switch je celkem pomalá operace a Drivery DX/OGL se ji snaží elimininovat interním batchováním callů, takže když zavoláte API funkci vykoná se to někdy až driver řekne, že je čas. A je dost pravděpodobný, že se změní i pořadí vykonání toho co aplikace zavolala, protože driver ví nejlíp co engine dělá
. Problém batchování potom není ani tak latence samotná jako spíš to, že latence neustále a nekontrolovaně kolísá podle toho jak driver batchuje. Takže engine si v podstatě nemůžete připravit data na grafický kartě, který nepotřebuje k vykreslení aktuálního framu dopředu bez následků. Je velice pravděpodobný, že se do toho namotá driver a zdrží vám aktuální frame protože bude přenášed data co pro něj nepotřebuje.. a není nad tím žádná kontrola..
V Mantle (DX12, Vulkan) jak já sem to pochopil máte multivláknový přístup do paměti grafické karty, takže si tam můžete model, textury a jiné blbosti strkat podle libosti z libovolnýho vlákna. Ten navíc nějakým pro mě záhadným způsobem obchází velkou část context switchů. (HW virtualizace GPU paměti co je v GCN?)
Pak máte nějakou rendering frontu (nebo i víc front), která vám to všechno kreslí na display. Ta se taky vyrábí v user mode kódu (převážně?). Ale její zpracování se řídí obdobou drawcallů, které už díky WDDM prochází do kernel mode funkcí. Ale v tuhle chvíli už vy jakožto engine musíte zaručit že to co fronta použije tak všechno leží v paměti tam, kde ste řekli že bude, jinak to zkončí strašlivým rozbitím toho co se zobrazuje.
Plus nějaké další teoretické úspory času a přenosů mezi CPU a GPU, jelikož díky přístupu do GPU paměti můžete modifikovat textury a modely a nemusíte je nahrávat přež API celé znova.
Když to vezmu hodně zjednodušeně tak v Mantle/DX12/Vulkan tak příprava a přesun dat pro rendering jde multivláknově mimo grafickej driver (tak jak je znám v dnešní podobě) čímž se zbavíte jeho overheadu. Grafickej driver je podstatně jednodužší protože se už nevěnuje organizaci assetů, čímž se zase zmenší jeho overhead a stabilizují jeho latence. Na engine se přesunula práce s assets na GPU co předtím dělal driver, jenže to není velkej problém, protože si to engine stejně organizoval v CPU paměti a do GPU posílal přez API funkce a o mnoho víc toho nebude dělat ani teď.