Miért probléma a shader fordítás PC-n?

A hagyományos és az explicit grafikus API-kkal sem volt jó a helyzet, holott konzolokon vajsima a kapott élmény.

Shader fordítás régen

Ha kimondjuk azt a szót, hogy shader, valószínűleg sokan a grafikára gondolnak, és teszik ezt jó okkal, ugyanakkor maguk a shaderek olyan programok, amelyek egy adott probléma megoldását célozzák a grafikus vezérlőn belül. Régebben ezeket kizárólag arra használták a fejlesztők, hogy saját transzformációs és megvilágítási modelleket írjanak, de a hardverek, illetve nem elhanyagolható módon a szoftverkörnyezet fejlődésének hála mára már általános feladatok elvégzésére is jók.

Egy ideje viszont téma PC-s körökben, hogy a shader fordítás nem túl jól megoldott, és erre időnként jön még egy-egy játék, amely akadozó működésével felerősíti a vitát. De honnan ered ez a probléma? Miért nem oldották meg az explicit API-k? Mi kellene ahhoz, hogy működjön a rendszer? Csupa kérdés, amire nem igazán ad senki választ, és különösen bosszantó lehet a méregdrága hardvereket vásárló PC-seknek, hogy konzolon ez a jelenség nem is létezik, ott vajsima élményt lehet kapni ebből a szempontból. Jelen cikkben megpróbáljuk megválaszolni, hogy mitől is történik mindez, illetve felvázolunk egy potenciális megoldást, ami a PC-t is megmentené az akadozásoktól.

Mielőtt azonban belevágnánk, érdemes kiemelni, hogy a hagyományos API-k esetében keletkező kisebb akadások nem ugyanattól vannak, mint amik az explicit API-kat sújtják. Ahhoz, hogy ezt jobban megértsük, látni kell, hogy a régebbi API-k hogyan működtek. Az OpenGL-t itt különösebben nem vizsgálnánk, mert az a shader fordítások szempontjából maga volt a katasztrófa. Nagyon sokáig a rendszer magát a shaderek forrásának szállítását követelte meg a fejlesztők részéről, amiből aztán nemhogy gyors kódot nem lehetett valós időben fordítani, de sokszor hibátlant sem, ugyanis nem volt elég egyértelmű a specifikáció az egyes esetek kezelését tekintve. Ennek eredménye az lett, hogy egy program akár ugyanazt a shader többféle gyártóhoz is hozzáigazította, és csak imádkozhattak a fejlesztők, hogy az érintett cégek ne módosítsanak shader fordítójukon, mert ha megtették, akkor onnantól kezdve volt némi esélye annak, hogy meszeltek a programfuttatásnak.

Az OpenGL ilyen szempontból játékra teljesen alkalmatlan API volt, és ezen már az sem segített, hogy időközben a Khronos Group elintézte hozzá a SPIR-V támogatását, addigra ugyanis a játékfejlesztők túlléptek ezen a poklon.

A DirectX 11 – továbbá számos korábbi verzió – már sokkal átgondoltabb rendszer volt a shader fordításokat tekintve, ugyanis a Microsoft nem engedte meg a fejlesztőknek a magas szintű HLSL kódok szállítását, ezeket le kellett fordítani úgynevezett D3D bájtkódra, kevésbé ismert néven DXBC-re. Ezt a műveletet az fxc fordítóval lehetett elvégezni, és ez egy nagyon-nagyon lassú procedúra volt, mivel a kód optimalizálása is nagyrészt ezen a ponton történt meg.

A shader fordítás vázlata DirectX 11 API-val
A shader fordítás vázlata DirectX 11 API-val [+]

Maga a D3D bájtkód egy viszonylag egyszerű fájlként jellemezhető, amely logikailag három nagyobb részre osztható. A fő adatokat a kódtörzs szolgáltatja, itt van lényegében minden olyan kód, ami magához az algoritmushoz kapcsolódik, és ennek van egy elő-, illetve egy utótagja. Maga a kódtörzs úgy lett tervezve, hogy utólag ne nagyon lehessen változtatni rajta valós időben, de az elő- és utótag már könnyen frissíthető, és ezen a ponton a grafikus eszközillesztők shader fordítói élnek különböző specifikus kiegészítésekkel, amelyek igazodnak a kódtörzsben elemzett adatokhoz, megfelelő módon fordítva le magát a D3D bájtkódot az adott grafikus vezérlő által emészthető formába. Utóbbi valós időben történik, és nem is túlságosan olcsó művelet, de valamelyik grafikus kernel szál élvégzi a munkát a processzor segítségével.

Mondhatjuk azt, hogy ez az egész átgondoltnak tűnik, de közel sem az. A Directx 11-ben rengeteg objektum volt megkülönböztetve, amelyeket ugyan a D3D bájtkód elő- és utótagjának frissítése által futtatási időben jól tudott kezelni a grafikus eszközillesztő, de ezek az aprócska műveletek rengeteg API hívást eredményeztek, amelyek az esetek jó részében meg is akasztották a munkavégzést, akadályozva az alkalmazás skálázását a sok maggal rendelkező processzorokon. Ráadásul annak ellenére, hogy az fxc fordító igen sokáig generálta a D3D bájtkódot, nem volt garancia arra, hogy az adott hardveren optimálisan fog futni, és időnként akár a lefordított és leszállított shadereket is lecserélték a gyártók a meghajtóból, hogy jobb legyen a sebesség. Ezek mind olyan tényezők voltak, amelyeket senki nem akart látni, mert alapvetően sok hibára adott lehetőséget, illetve az elő- és utótag frissítése, valamint a D3D bájtkódok hardver számára értelmezhető kódra való lefordítása is sok processzoridőt vett igénybe, nem kevésszer akasztva meg rövid időkre az elméletben folyamatosra tervezett játékélményt. És ezzel sajnos utólag semmit sem lehetett tenni, maga a rendszer volt így tervezve.

A cikk még nem ért véget, kérlek, lapozz!

Azóta történt

Előzmények

Hirdetés