Why DX12 for Windows Builds Instead of VK?
InklingGirl opened this issue · comments
As a user, I am curious as to what considerations motivated the decision to use Direct3D 12 for builds generated for Windows & only use Vulkan w/ builds generated for GNU/Linux?
(Opposed to Direct3D 12, )Vulkan is:
- Free/libre & open-source software (F/LOSS)
- Even lower level & faster than Direct3D 12
- Cross-platform w/ Windows, GNU/Linux, Android, FreeBSD, Nintendo Switch, etc.
- Supports Windows as far back as Windows XP, where Direct3D 12 only supports Windows & its minimum supported version of it is Windows 10
Why not just maintain one low-level graphics API i.e. Vulkan to rule them all? The devs of dolphin-emu
originally supported Direct3D 12 too (although they at least gave Windows users the option of Vulkan), before quickly deprecating it when they reviewed & recognised the above advantages of Vulkan & that maintaining just Vulkan created less work for themselves than also maintaining Direct3D 12 (especially in the days before VKD3D12 real-time API calls translation).
The tools from this repo only handle generating C code from MIPS instructions, it doesn't do anything graphic related. This question is offtopic for this repository, it would be better suited in an actual recompiled game project like https://github.com/Zelda64Recomp/Zelda64Recomp, or even in the graphic renderer library repo used by said project (https://github.com/rt64/rt64).
To answer your question:
- From what I have heard, the Zelda64Recomp project decided to default to D3D12 on Windows builds instead of Vulkan because on their testing it was marginally faster than Vulkan on Windows.
- RT64 have support for both because of the RHI (Rendering Hardware Interface) it uses, which is a very thin wrapper around those graphic renderers. There's even an on going effort to add a Metal renderer so recomp projects can be used on Macs (check rt64/rt64#9).
- The Zelda64Recomp project can change the graphic renderer on Windows by using a configuration file (no GUI at the moment, idk if there are plans to add this setting in the future).
- Open
%localappdata%/Zelda64Recomp/graphics.json
and changeAPI
toVulkan
. note that this setting is case sensitive.
- Open
Oh, so sorry that this is the wrong repo, there have just been a lot of videos lately about n64recomp
(mostly focusing on zelda64recomp
) & the way they mention the APIs makes it sound like that is what the software in this repo chooses at re/compilation. Thank you for offering what insights you can, though.
I am curious as to what considerations motivated the decision to use Direct3D 12 for builds generated for Windows & only use Vulkan w/ builds generated for GNU/Linux?
Windows builds also include Vulkan support, the default being D3D12 is just a usability concern for reasons I'll outline further.
Free/libre & open-source software (F/LOSS)
Vulkan is an API, it is not software I can easily run and modify on my own in most places where it'll run realistically. The vast majority of drivers are proprietary black boxes which we have zero control over of how the API is implemented. It's just one more choice and not any less valid than D3D12.
Even lower level & faster than Direct3D 12
This is very much not the case, and whatever advantage Vulkan had due to synchronization barriers has been pretty much compensated and completely up to par with the introduction of enhanced barriers, which I'll be implementing on the current backend in the near future.
Why not just maintain one low-level graphics API i.e. Vulkan to rule them all? The devs of dolphin-emu originally supported Direct3D 12 too (although they at least gave Windows users the option of Vulkan), before quickly deprecating it when they reviewed & recognised the above advantages of Vulkan & that maintaining just Vulkan created less work for themselves than also maintaining Direct3D 12 (especially in the days before VKD3D12 real-time API calls translation).
Because not one graphics API can rule them all, as Vulkan has very heavy shortcomings when targeting Windows that makes it less preferable for one reason or another. Some of them are due to the specification missing a few things D3D12 provides, and most of them are reasons linked to the actual market reality. A vast majority of games on Windows ship with D3D12. It is where features and optimizations land on first. It is what most vendors are working with. It often provides the best integration of various features with the OS and gets features ahead of time that take a while to show up in Vulkan.
Whatever reasons Dolphin had to drop or adopt the APIs again is entirely from design decisions carried over from having to implement things in the backends far beyond the scope of what they should've been. It is a program that has carried across multiple hardware generations, so these problems are expected. RT64 makes a bet that these low-level APIs are unlikely to change much in the future, and therefore the abstraction has been put at the lowest level possible for basically no cost. There's no actual maintenance cost to having both D3D12 and Vulkan because by design, both backends can't diverge at all. The situation will be the exact same with Metal and any other APIs that are introduced that are compatible with this idea. Dropping support for D3D12 provides no benefits whatsoever that you might be imagining.
There's plenty of benefits to leveraging both APIs and whichever fits best for the target platform. The developers behind these APIs have worked very hard to provide great validation tools that make my job much easier when I need to verify why something doesn't work. Even better, thanks to the decision to maintain both APIs, I get to leverage both of these at the same time and find things the other one might have not considered. This was also a recent realization in my case that Vulkan does not expose a particular hardware optimized layout that D3D12 does since Enhanced Barriers was introduced, which shows neither API is flawless. This situation often repeats itself as Vulkan has to deal with a lot of limitations carrying over from its 1.0 design that in many ways D3D12 does not have to.
If you want the nitty-gritty of reasons why I would definitely not want to default to Vulkan in Windows in the current state, here's a few issues that come to mind:
- Presentation is very finicky for Vulkan on Windows. The only reliable way to get a swap chain that actually works with HDR, low latency and the ability to take screenshots while in fullscreen (!) is to present through DXGI. This technique requires a bunch of cross-API hacks that aren't even reliable to execute and are definitely not worth the trouble implementing. NVIDIA offers an specific control panel option to work around this to basically insert their own DXGI handling on top of Vulkan, a workaround I wouldn't even dare to put on a usage guide to expect people to do. People shouldn't be messing with the control panel of their GPU!
- I'm also pretty certain there's just no support for DXGI Swap Effects in Vulkan, as the Swap Chain API is not as descriptive as the DXGI one when it comes to this behavior. I've pretty much always experienced a significantly lower input latency thanks to the use of this mode no matter how much the Vulkan code resembles the same.
- It's been already multiple times I've encountered situations that straight up work worse in the Vulkan driver than in the D3D12 driver that is only explained by the vendor spending more time on one API than the other. For the sake of comparison in the same exact AMD hardware, creating a Raytracing PSO took around 10 seconds in D3D12 while in Vulkan it took a whopping 10 minutes and consumed 40 GB of RAM during runtime compilation. I have no good conclusion to draw from this other than the fact that Vulkan is basically not the clear priority nor is it guaranteed to behave well if the driver isn't up to date. The situation I described isn't even a performance concern, it's straight up not shippable to end users.
- Vendors are much more likely to have shipped a D3D12 driver for their hardware that works properly than a Vulkan one, as the amount of applications that use D3D12 and likely got properly tested vastly outnumber the Vulkan ones. If I need to take a bet on which one to default to, I'm using the one that is clearly preferred on the target platform.
I like Vulkan as much as anyone else for many of the reasons that are often stated. It is not a clear winner in all scenarios and the strategy of deploying the API that is likelier to have more support from vendors in the target platform is completely valid. If this approach does not work for targeting the edge cases you've brought up: good, Vulkan is available for you there as an option. By no means does it add a maintenance cost to the project and you'll not find any instances of it holding it back thanks to how RT64's RHI was designed.
Thank you for the thorough explanation @DarioSamo.