Live data from Hacker News

RT64: N64 graphics renderer in emulators and native ports

github.com

11–20 of 54 posts

Re: RT64: N64 graphics renderer in emulators and native ports

#12
post #4

> Uses ubershaders to guarantee no stutters due to pipeline compilation. I may sound way out of the loop here, but... How come this was never a problem for older dx9/dx11/GL games and emulators?

Older games used precompiled shaders. These are inaccessible to the game devs and usually handled by the hardware makers, so the platform OEM for consoles and the video card OEM on PCs. Game devs have begged for the ability to write their own shaders for years and finally got it with DX11 and Vulkan. And that's when things went to hell. Instead of the shaders being written and compiled for the specific hardware, they…

Compiling shaders directly from a high level representation to the GPU ISA only really happens on consoles.

In DirectX on PC, shaders have been compiled into an intermediate form going back to Direct3D 8. All of these intermediate forms are lowered into an ISA-specific instruction set by the drivers.

This final compilation step is triggered lazily when a draw happens, so if you are working on a "modern" engine that uses thousands of different material types your choices to handle this are to a) endure a hiccup as these shaders are compiled the first time they are used, b) force compilation at a load stage (usually by doing like a 1x1 pixel draw), or c) restructure the shader infrastructure by going to a megashader or similar.

Re: RT64: N64 graphics renderer in emulators and native ports

#13
post #6
post #4

> Uses ubershaders to guarantee no stutters due to pipeline compilation. I may sound way out of the loop here, but... How come this was never a problem for older dx9/dx11/GL games and emulators?

In those gl/dx games (built for non-specific hardware) all the textures and shaders are compiled either during the game's build OR before you get into the scene. Many console systems, particularly Nintendo, do that precompilation specifically for the hardware GPU that is inside the console. That is not known to the emulator in advance (unless someone publishes a shader compilation alongside the rom...) so when the sh…

That's not quite how ubsershaders work. They're a "fallback" shader in the sense that they rather inefficiently implement the entire pipeline, but they do implement the entire pipeline. The shader being compiled in another thread will be more efficient as it uses only the logic needed for whatever configuration the game is calling up. But the visual result is identical in the ubsershaders case, that's the whole point. If you want, and your host system is powerful enough, you can turn ubsershaders on all the time and disable the entire compilation thread and associated cache.

I believe the term was coined by Dolphin team, who did a pretty good high level writeup of the feature here:

https://dolphin-emu.org/blog/2017/07/30/ubershaders/

Re: RT64: N64 graphics renderer in emulators and native ports

#14

Earlier quoted context omitted.

Older games used precompiled shaders. These are inaccessible to the game devs and usually handled by the hardware makers, so the platform OEM for consoles and the video card OEM on PCs. Game devs have begged for the ability to write their own shaders for years and finally got it with DX11 and Vulkan. And that's when things went to hell. Instead of the shaders being written and compiled for the specific hardware, they…

Compiling shaders directly from a high level representation to the GPU ISA only really happens on consoles. In DirectX on PC, shaders have been compiled into an intermediate form going back to Direct3D 8. All of these intermediate forms are lowered into an ISA-specific instruction set by the drivers. This final compilation step is triggered lazily when a draw happens, so if you are working on a "modern" engine that u…

> Compiling shaders directly from a high level representation to the GPU ISA only really happens on consoles.

When targeting Apple platforms, you can use the metal-tt tool to precompile your shaders to ISA. You give it a list of target triples and a JSON file that describes your PSO. metal-tt comes with Xcode, and is also available for Windows as part of the Game Porting Toolkit.

Unfortunately, most people don’t do that. They’re spoiled by the Steam monoculture, in which Steam harvests the compiled ISA from gamers’ machines and makes it available on Valve’s CDN.

Re: RT64: N64 graphics renderer in emulators and native ports

#15
post #4

> Uses ubershaders to guarantee no stutters due to pipeline compilation. I may sound way out of the loop here, but... How come this was never a problem for older dx9/dx11/GL games and emulators?

To answer that question in the context of Vulkan I highly recommend reading the proposal document for VK_EXT_shader_object which contains a great explanation in the problem statement about how modern graphics APIs ended up in this situation:

https://github.com/KhronosGroup/Vulkan-Docs/blob/main/propos...

The gist of it is that graphics APIs like DX11 were designed around the pipelines being compiled in pieces, each piece representing a different stage of the pipeline. These pieces are then linked together at runtime just before the draw call. However the pieces are rarely a perfect fit requiring the driver to patch them or do further compilation, which can introduce stuttering.

In an attempt to further reduce stuttering and to reduce complexity for the driver Vulkan did away with these piece-meal pipelines and opted for monolithic pipeline objects. This allowed the application to pre-compile the full pipeline ahead of time alleviating the driver from having to piece the pipeline together at the last moment.

If implemented correctly you can make a game with virtually no stuttering. DOOM (2016) is a good example where the number of pipeline variants was kept low so it could all be pre-compiled and its gameplay greatly benefits from the stutter-free experience.

This works great for a highly specialized engine with a manageable number of pipeline variants, but for more versatile game engines and for most emulators pre-compiling all pipelines is untenable, the number of permutations between the different variations of each pipeline stage is simply too great. For these applications there was no other option than to compile the full pipeline on-demand and cache the result, making the stutter worse than before since there is no ability to do piece-meal compilation of the pipeline ahead of time.

This gets even worse for emulators that attempt to emulate systems where the pipeline is implemented in fixed-function hardware rather than programmable shaders. On those systems the games don't compile any piece of the pipeline, the game simply writes to a few registers to set the pipeline state right before the draw call. Even piece-meal compilation won't help much here, thus ubershaders were used instead to emulate a great number of hardware states in a single pipeline.

Re: RT64: N64 graphics renderer in emulators and native ports

#16
post #6

Earlier quoted context omitted.

In those gl/dx games (built for non-specific hardware) all the textures and shaders are compiled either during the game's build OR before you get into the scene. Many console systems, particularly Nintendo, do that precompilation specifically for the hardware GPU that is inside the console. That is not known to the emulator in advance (unless someone publishes a shader compilation alongside the rom...) so when the sh…

That's not quite how ubsershaders work. They're a "fallback" shader in the sense that they rather inefficiently implement the entire pipeline, but they do implement the entire pipeline. The shader being compiled in another thread will be more efficient as it uses only the logic needed for whatever configuration the game is calling up. But the visual result is identical in the ubsershaders case, that's the whole point…

It predates dolphin's use of it, though don't ask me by how long. Here's a reference to the term from 2008: https://realtimecollisiondetection.net/blog/?p=73

Re: RT64: N64 graphics renderer in emulators and native ports

#17

I guess the big test will be running Kaze Emanuar’s code through it.

For those who haven't heard, Kaze is the guy who optimized Mario 64's code, fixed some physics bugs, etc., claims roughly 6x speedup, so that he can make a mod / ROM-hack that runs smoother despite having better graphics: https://www.youtube.com/watch?v=t_rzYnXEQlE

Re: RT64: N64 graphics renderer in emulators and native ports

#18
post #4

> Uses ubershaders to guarantee no stutters due to pipeline compilation. I may sound way out of the loop here, but... How come this was never a problem for older dx9/dx11/GL games and emulators?

It happened all the time. I've played plenty of D3D11 games where clicking to shoot my gun would stutter the first time it happened as it was compiling shaders for the bullet fire particle effects.

Driver caches mean that after everything gets "prewarmed", it won't happen again.

Re: RT64: N64 graphics renderer in emulators and native ports

#19
post #16

Earlier quoted context omitted.

That's not quite how ubsershaders work. They're a "fallback" shader in the sense that they rather inefficiently implement the entire pipeline, but they do implement the entire pipeline. The shader being compiled in another thread will be more efficient as it uses only the logic needed for whatever configuration the game is calling up. But the visual result is identical in the ubsershaders case, that's the whole point…

It predates dolphin's use of it, though don't ask me by how long. Here's a reference to the term from 2008: https://realtimecollisiondetection.net/blog/?p=73

Ubershader actually has three different opposite meanings, unfortunately.

The classic usage is a single source shader which is specialized using #define's and compiled down to hundreds of shaders. This is what Christer uses in that blog post above (and Aras does as well in his ubershader blog post)

Dolphin used it to mean a single source shader that used runtime branches to cover all the bases as a fallback while a specialized shader was compiled behind the scenes.

The even more modern usage now is a single source shader that only uses runtime branches to cover all the features, without any specialization behind the scenes, and that's what Dario means here.

Re: RT64: N64 graphics renderer in emulators and native ports

#20

I guess the big test will be running Kaze Emanuar’s code through it.

For those who haven't heard, Kaze is the guy who optimized Mario 64's code, fixed some physics bugs, etc., claims roughly 6x speedup, so that he can make a mod / ROM-hack that runs smoother despite having better graphics: https://www.youtube.com/watch?v=t_rzYnXEQlE

Just about a Fabrice Bellard level of competence there
Post reply on HN