En lägre generation på väg

Under året som passerat har nästan varje stor spellansering, nya versioner av prestandamätningsverktyg och drivrutiner från hårdvarutillverkarna handlat om två saker – "stöder den DirectX 12 eller Vulkan" och "vilka prestandaförbättringar fås med lågnivågränssnitten?".

Så vad är det egentligen lågnivågränssnitt gör annorlunda än högnivågränssnitten? För att svara på frågan får vi först gå tillbaka till den era där utvecklargränssnitt som DirectX 9 och tidigare togs fram. Den huvudsakliga uppgiften för ett grafik-API är att sammanställa ett antal instruktioner som processor- och grafikkretsen ska utföra. Denna lista kallas kommandolistan.

När DirectX 9 var under utveckling bestod prestandaförbättringar främst av de årliga förbättringarna i processorers klockhastighet. Då var det ett rimligt designbeslut att DirectX använder en enskild åtkomstbegäran (context) för att skicka beräkningsanrop (eng. draw call) till grafikkretsen. API:et kontrollerar anropen i åtkomstbegäran och skapar sedan en kommandolista som grafikkretsen ska utföra.

DX9_illustration.jpg

Exekveringsmodellen för DirectX 9 var seriell,
och skalar därför inte väl till många processorkärnor och samtidiga trådar.

DX11_illustration.jpg

Med DirectX 11 blev gränssnittet mer parallelliserat, men innehöll fortfarande många kontrollmekanismer.

DX12_illustration.jpg

DirectX 12 kombinerade parallelliserade egenskaper med avlägsnade kontrollmekanismer, vilket gav mer frihet och mer ansvar till utvecklarna.

Problemet med denna process är att den är sekventiell, vilket i moderna spel blir problematiskt då flerkärniga processorer och grafikkretsar med tusentals grafikkärnor ställer höga krav på parallelliserade beräkningar. En större grad av parallellisering blev möjligt i DirectX 11 där något som kallas Deferred Contexts gjorde det möjligt för spel att skicka anrop oberoende av varandra i multipla mjukvarutrådar.

Parallelliseringen till trots var alla anrop tvungna att gå genom en och samma åtkomstbegäran, och grafikdrivrutinen kunde endast utföra kommandolistan när samtliga beräkningsanrop kontrollerats och godkänts. DirectX 11 blev därmed också begränsad sett till hur flerkärniga processorer kunde utnyttjas, och hur flexibelt utvecklare kunde växla mellan omedelbar exekvering av beräkningsanrop.

DirectX 12 ändrar på denna modell rejält och tar bort flera av stegen som står mellan en applikations begäran och att kommandolistan skickas till grafikkretsen. I DirectX 12 kan kod skapa flera kommandolistor parallellt, och utvecklaren får även större kontroll över när dessa skickas till grafikkretsen.

Drivrutinsmodellen är dessutom bantad på ett sätt som innebär att kommandolistorna kan utföras med mindre fördröjning (eng. overhead) då koden mer liknar den kod som hårdvaran exekverar.

GPU_pipeline_asynch.jpg

En mer parallell och flexibel exekveringsprocess (pipeline) gör att lågnivåramverken kan utnyttja resurser mer effektivt, däribland processorkärnor.

Bristen på mellanhänder som kontrollerar de anrop som utgör kommandolistorna innebär dock att ett större ansvar ställs på utvecklaren. Utvecklaren måste se till att alla resurser som används i kommandolistorna, exempelvis texturer och kodstycken, är tillgängliga under hela exekveringsprocessen (eng. pipeline).

Under stora och komplexa projekt kan alltså allvarliga fel infinna sig lättare i lågnivågränssnitt som DirectX 12 och Vulkan, då gränssnitten inte fångar dessa fel tidigt i processen som med föregångarna DirectX 9 och OpenGL.

Detta större krav kan kanske till viss del förklara det hittills relativt begränsade antal spel som verkligen lyckas dra nytta av DirectX 12/Vulkan. Trots att ett antal titlar som lanserades under 2016 bestyckades med stöd för gränssnitten har få av dessa åtnjutit några större prestandavinster och i vissa fall även sett försämringar. Ett nämnvärt undantag är 2016 års förnämligt kodade Doom, som såg signifikanta prestandavinster med Vulkan-stöd aktiverat.