Vélemény: lesz Apple konzol, meg nem is

Miért kell az Apple-nek ez az irány?

Az új Metal API esetében egy alacsony szintű hardverelérést biztosító rendszerről van szó, de nem minden szempontból követi azt az irányt, amit mondjuk az AMD Mantle vagy a Microsoft DirectX 12. Ez önmagában baj, hiszen az alapvető problémák szempontjából az Apple is ugyanúgy meg akarja oldani a mai szabványos API-k igen gyenge hatékonyságát, ám eközben az előbb említett rendszerek még lényeges extrákat is bevezetnek, amelyek a Metal API-ból már hiányoznak. Bár ezt fel lehet fogni úgy is, hogy a Metal nem tud annyit, amennyit a Mantle vagy éppen a DirectX 12, de valójában arról van szó, hogy az Apple más fogyasztásszintre nevező hardverekre tervezte, így bizonyos esetekben eltérő megoldást választottak az adott problémára, noha különböző frissítésekkel folyamatosan beépíthető lesz bármilyen extra képesség.

Bár a felhasználók úgy tekintenek az alacsony szintű hardverelérést biztosító API-kra, amelyek csak a processzorlimitet oldják fel, ez valójában egy teljesen téves nézőpont, ami valószínűleg a Mantle API eredményeit tekintve alakult ki. Lényegesen komolyabb problémával állunk szemben, amelyek nemhogy a sebességet növelését, de bizonyos játékötletek megvalósítását is lehetetlenné teszik, és kimutathatóan rontják a felhasználói élményt. Ezzel sem a Mantle kapcsán, sem a DirectX 12 API-ról szóló cikkünkben nem foglalkoztunk, mivel úgy gondoltuk, hogy érthető a probléma gyökere, de most a Metal API bemutatása előtt bepótoljuk ezt a hiányosságot. Vélhetőleg ebből érthető lesz, hogy az ipar több neves szereplője nem úri hóbort miatt fejleszt alacsony szintű hozzáférést.

A lényeg megértéséhez előbb azt kell pontosan látni, hogy az aktuális DirectX és OpenGL API-k által használt modell hogyan is működik. Elviekben úgy magyarázható el az API-k lényege, hogy az ezekre írt program képes futni az adott API-t támogató hardvereken. Ez eddig tiszta sor, de a legtöbb felhasználó úgy gondolja, hogy a grafikus API egy paranccsal valamit elér a grafikus vezérlőn belül, majd ha a parancs visszatér, akkor a hardver befejezte a munkát, és mehet a következő parancs. Ez jó lenne, ha így működne, de sajnos nagyon távol áll az igazságtól, éppen ezért a grafikus vezérlő sosem dolgozik szinkronban a központi processzorral.

A két részegység nem vár egymásra, mivel az API parancsok elküldése folyamatos, és azok majd idővel visszatérnek. Ez már hatékonyabb modell, de biztos lesz olyan, amikor az egyik parancs várakozásra kényszerül egy másik parancs miatt, vagy éppen a grafikus vezérlő nem tud dolgozni, mert a CPU még nem állította elő a szükséges API parancsot. Mindkét esetben kihasználatlan lesz a hardver, mivel vagy nincs mit számolni, vagy nem hatékony az, ahogyan történik a feldolgozás.

Erre reagálva a mai grafikus eszközillesztők úgy vannak megírva, hogy az adott képkockához szükséges összes parancsot előbb gyűjtsék össze, majd utána mehet a tényleges leképzés. Ez relatíve hatékony kihasználáshoz vezet, de a várakozás miatt egy képkocka-késleltetés is keletkezik, mivel a következő képkockára a parancsok összegyűjtése akkor történik meg, amikor az aktuális képkocka már számítás alatt van. Ha még így sem ideális a hardver kihasználása, akkor akár két képkockára előre is össze lehet gyűjteni a parancsokat, ami két extra képkocka késleltetését adja hozzá a teljes számításhoz. Időnként esetleg szükség lehet szinkronizálásra, ami biztosítja, hogy a központi processzor és a grafikus vezérlő a megfelelő ütemben dolgozzon, de az API-kba épített szinkronizáló parancsok drasztikus beavatkozásnak számítanak, így ezek kiadásakor a teljes futószalag leáll egy rövid ideig, ami teljesítménycsökkenéshez vezet.

Szintén nem kedvezők az aktuális API-kban az állapotváltások. A program oldalán az adott shaderbe definiálni kell a bemeneti adatot, mely esetleg különbözhet attól, amit az adott puffer tárol (ugyanez vonatkozhat az adatok mentésére is). Manapság erre a problémára a grafikus eszközillesztők tartalmaznak előre definiált shader kódokat (rutinokat), melyeket szimplán beillesztenek az alkalmazás eredeti kódjába. Ezzel lényegében az adatkonverzió bármilyen formában megtörténhet, de gond még így is lesz. Rögtön felmerül az a kérdés, hogy mikor egészítse ki a driver a shadert? A meghajtó ugyanis nem tudja, hogy mi történik a kódon belül, csupán alapvető szabályokat követ, amelyekre a rendszerprogramozók felkészítették.

A helyzet önmagában egyszerű, mert csak az állapotváltásokra kell ideálisan reagálni. Ha egy új rajzolási parancs új shadert igényel, akkor még azelőtt újra kell fordítani a driver által kiegészített kódot, mielőtt megérkezne a parancs. A gond ott merül fel, hogy a driver addig nem tudja, hogy milyen shaderre lesz szükség, amíg a parancs meg nem érkezik. A parancsot tehát meg kell várni, majd a rendszer csak azt követően fordítja újra a shadert, miután kiderült mire van szükség. Ez kapásból azt jelenti, hogy a program futtatása egy pillanatra megakad. Mindez kivédhetetlen, és egy hosszú ideig számolt képkockát fog eredményezni, aminek egy úgynevezett mikroakadás lesz az eredménye. Szerencsére a következő képkockára vonatkozóan a driverek elmentik az újrafordított shadert, amit legközelebb szimplán csak betöltenek, tehát a fordítással járó időveszteséget egy shader adott kiegészítése esetben csak egyszer kell felvállalni.

A fentiekben két nagyon alapvető problémát írtunk le, amelyek szimplán csak abból erednek, hogy az API-k és a hozzájuk készült driverek túl sok dolgot elrejtenek a program elől. A fejlesztők ezt a működési modellt csupán úgy szokták leírni, hogy egy feketedoboz megpróbál valamit varázsolni, ami vagy működik, vagy nem. Ha működik, akkor annak örülni kell, de ha nem, akkor az hihetetlen mértékű probléma a program fejlesztésére nézve, ugyanis a driver által végzett beavatkozások a programozó számára láthatatlanok. Éppen ezért lehetetlen eldönteni, hogy a programkódban vagy a driverben van a hiba. Ilyenkor jellemzően kialakulnak a diskurzusok az érintett hardvergyártókkal, amelyek olyan problémákhoz is vezethetnek, hogy a fejlesztő szerint a driver a hibás, míg a drivert író csapat szerint a programkódban kell keresni a megoldást. Újabban a felhasznált API fejlesztőit is bevonják, ami jellemzően csak annyit ér, hogy van egy harmadik fél is, akire lehet mutogatni. Ez kétségtelenül nem viszi előre a fejlesztést, így az adott stúdió számára mindenképp be kell lépni egy gyártói partnerprogramba, mert akkor legalább számításba veszik a visszajelzéseket, és az adott drivert író csapat számára is fontos lesz az alkalmazás működésének kiértékelése. Ez a többi céggel való munkát is előreviszi, hiszen ha az egyik érintettel kapcsolatban kiderült, hogy a meghajtó működése miatt nem jó a sebesség, akkor gyanítható, hogy a programkód megfelelő.

Igazából a fejlesztők számára egy nagy probléma van a mai modellel: nem látják, hogy a grafikus driver mit ügyködik a hardveren belül, így képtelenek tökéletesen kiértékelni és optimalizálni. Emellett, ha a sebesség nem jó, és feltételezhető, hogy ennek a driver az oka, akkor várni kell a javításra. Ez elfogadhatónak tűnik, de nem ritka, hogy három hónapig keresik a hiba okát, ami rengeteg idő. Ez az a pont, aminél tovább már egy stúdió sem vár, és inkább újraírják a problémás kódot, még akkor is, ha tényleg a driver az oka a gyenge teljesítménynek. Összegességében az egész szisztéma nehezen átlátható, nem mellesleg rengeteg pénzt emészt fel egy jól működő kód elkészítése, és az egyre komplexebb játékok esetében már nagy az esélye annak, hogy a kiadásra ítélt kód sem optimalizált, mert szimplán nincs több idő javítani rajta.

Mint az látható, a probléma oka vitathatatlanul az API, mivel nem ad kontrollt a fejlesztő számára a hardver hatékony programozására. Bár jellemzően felhozható az a tény, hogy kevesebb kódot kell beírni a magas szintű hardverelérést biztosító platformokon, ami jól hangzik, de igazából ez sarkított nézet. Már ma is rengeteg pénzt költenek a stúdiók csak arra, hogy az egyes driverek működését megértsék. Ennek megfelelően képesek lesznek úgymond befolyásolni azokat annak érdekében, hogy gyorsuljon a kód. Ez elvileg nem rossz stratégia, de sokszor stabilitási problémához vezet, ami például a Frostbite 3 motorra is jellemző: a játék a DirectX 11(.1)-es API-n futtatva ledobhatja magáról az erőforrást, ami az alkalmazás lefagyásához vezet. A driverek működésének befolyásolását egyik gyártó sem ajánlja, de 30-50%-os teljesítménynövekedés lehetősége rejlik csak ebben, tehát érthető, hogy miért vizsgálják és alkalmazzák ezt a lehetőséget a stúdiók, akár annak kockázatát is felvállalva, hogy a program – DXGI_ERROR_DEVICE_HUNG hibával – néha lefagyhat.

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

  • Kapcsolódó cégek:
  • Apple

Azóta történt

Előzmények

Hirdetés