Gli autori del Dolphin hanno pubblicato un post molto interessante su come hanno risolto un problema piuttosto fastidioso dell’emulazione GameCube e Wii: lo stuttering che si verificava quando i giochi cambiavano shader “al volo”.

Detta in maniera brutalmente semplificata, mentre su GameCube e Wii gli shader si potevano cambiare “al volo” durante il gameplay, su PC ogni shader va compilato dai driver della GPU prima di poter essere usato, in modo da poter fare così fronte alla varietà hardware tipica dell’ambiente.

Di solito i giochi PC precompilano gli shader prima di usarli, ad esempio all’avvio del gioco o durante i caricamenti, ma ovviamente questa soluzione non è possibile quando si deve emulare un altro sistema in tempo reale, per cui ad ogni cambio di shader del gioco emulato il Dolphin perdeva qualche frame (e a volte molti frame) a ricompilare gli shader necessari.

Metroid Prime 3 è uno dei giochi dove il problema della compilazione realtime degli shader si avverte di più

Per risolvere il problema si sono tentate varie strade, tra cui il caching degli shader man mano che venivano compilati, ed il rendering dilazionato degli elementi grafici i cui shader dovevano ancora essere compilati.

Niente stuttering, ma anche elementi grafici che appaiono con un percettibile ritardo

Alla fine la soluzione è stata di scrivere un vero e proprio emulatore da far girare sulla GPU, da compilare una volta sola e a cui passare in tempo reale i parametri necessari per riprodurre i vari effetti della GPU di GameCube e Wii.

Gli autori del Dolphin hanno chiamato questa soluzione Ubershader, e il risultato, dopo un bel po’ di tinkering e bugfixing, è stato quello voluto:

Finalmente Metroid Prime 3 gira in maniera fluida e senza artefatti

L’unico problema è che questa forma di emulazione è molto pesante per le GPU, e chi non ha una scheda grafica moderna potrebbe non riuscire a far girare i giochi a velocità piena a meno di non ridurre drasticamente la risoluzione.

Per ovviare a questo problema gli autori del Dolphin hanno creato una modalità ibrida, dove l’emulatore usa gli Ubershader mentre in background vengono compilati gli shader in modalità classica, che vengono impiegati non appena sono pronti.

In questo modo la GPU deve “faticare” solo nei primi istanti, dopodiché può andare liscia usando il codice ottimizzato e precompilato.

Il progetto comunque ovviamente è tutt’altro che concluso, e c’è ancora molta strada da fare, in particolare per risolvere tutte le problematiche legate al comportamento non sempre chiarissimo dei driver delle schede grafiche.

Ad ogni modo, gli Ubershader sono sicuramente un notevole achievement tecnico, e chissà che non ispirino anche gli autori di altri emulatori di sistemi “moderni” a implementare tecniche simili per ottimizzare il loro codice.

Trovate il post originale con tutti i dettagli del caso che qui sono stati omessi qui:
https://dolphin-emu.org/blog/2017/07/30/ubershaders/

Sembra essere una soluzione veramente ottima, il team dolphin è veramente avanti quando si parla di emulazione

Questi son veramente dei fighi.

è proprio così, molte volte i problemi apprantemente impossibili si risolvono con le cose più semplici, il fatto è che i pregiudizi iniziali nell’approcciarli ci portano fuoristrada in partenza, andandoci a cercare già soluzioni di una certa complessità e scartando a priori di tentare con qualcosa di semplice

Bellissimo articolo, bell’achievemente da un progetto non-commerciale di quella complessita’ (che la gente si aspetta runni su HW molto diversi e complessi).
L’idea comunque di “ubershader” esiste da tempo nella CG, tendenzialmente e’ usata in scenari in cui si fa raytracing su GPU, dove per minimizzare la divergenza logica palese dei vari raggi che colpiscono cose diverse e quindi dovrebbero eseguire shaders sempre molto diversi, si inglobano tutti gli shaders dei materiali in un unico “ubershader” (anche chiamato uberkernel), appunto, e si esegue solo quello. Rimangono tutti i problemi relativi a flow control ecc ma le performance migliorano.

Shader Variant Generation

Drivers can do things in ways we don’t expect and cannot control. When we have to generate a new pipeline for a different blend or depth states, some drivers aren’t smart enough to share the shaders between pipelines. This will cause a minor stutter the first time a new blending mode is used. Most of the time the variants a game will use are generated within the first few minutes of play, but it can still be frustrating when you’re seeking perfection.

Questa parte e’ interessante, in teoria il driver patcha semplicemente lo shader quando la blendmask e’ nota (perche’ non e’ sempre nota quando si va a compilare il driver), ricompilare TUTTO lo shader e’ si’ uno spreco di risorse, ma potenzialmente anche una win perche’ ad esempio si possono fare delle ottimizzazioni extra nello shader finale (per dire, se sai che il blend e’ con 0, puoi eliminare dei bei chunk di codice ricompilando tutto, questo e’ un caso limite ma comunque anche negli altri casi qualche temp register+qualche MOV la risparmi), quindi ok che magari vedi lo stutter, ma magari se non lo facessero gli FPS medi calerebbero…. Chi lo sa! Il fatto che lo faccia Intel, che ha core piccoli tutto sommato, non mi sorprende in questo senso, magari sanno che ogni istruzione e registro per loro e’ vitale.