With the recent work on "Proton" by Valve, and the ability to use DXVK with Wine prefixes outside of Steam, there has been intense interest in the performance of running games through Wine compared to native titles. I use the word "native" here loosely: it is intended to mean any game supported as running directly under a GNU/Linux system, and can include anything compiled directly for a GNU/Linux system, eON (Virtual Programming's porting tech), or games packaged with Wine itself (none of which yet include DXVK).
That some titles perform better, from an FPS number perspective, when using DXVK is clear, which has lead to some people asking why this is the case. It's the why that I'd like to discuss here; why DXVK is a winner in some cases, why native wins in others, and some of the drawbacks of each approach.
Please note that this wall-o-text is aimed at the less programmer-savvy crowd, but I welcome any comments from those with more experience on the matter as well. This is a discussion after all, not an attempt at a definitive guide.
For those that don't know, DXVK (in my opinion, a rather excellent project) is an implementation of DirectX 11 (and DirectX 10) built atop Vulkan, for use with Wine. Valve package Wine, DXVK, and some additional patches, together under the name of "Proton", but here I will stick to Wine+DXVK, or simply DXVK, to show that its use is not tied to Steam.
DXVK Performance
In many cases, DXVK will perform better than a native port. Why? After all, a native port shouldn't have any translation overhead. The short answer is: native ports often use OpenGL. That doesn't really explain much of course, but it's important to note that DXVK is built on Vulkan, and so using DXVK will run the rendering of a game ultimately through the Vulkan API, in order to mimic DX11. Many native games use OpenGL instead, although this is slowly changing and will be discussed later, but are ports of something originally designed around Windows and DX11. So the question of Native vs DXVK can at least partially be considered in terms of OpenGL vs Vulkan capabilities, and how each is used to behave like DX11.
Multithreading
The elephant in the room is, of course, OpenGL's lack of API level multithreading. I've written about this before, but the short version is that OpenGL is designed to run on a single thread: texture loading, shader generation, render command submission, all is intended to run from a single thread from the perspective of the OpenGL interface. While drivers might attempt to be clever behind the scenes, the application itself (the game engine) must consider it only as single threaded, and with mostly synchronous calls. As an example, to prepare a shader in OpenGL there might need to be first a file loaded, OpenGL resources created, then text passed into OpenGL to be compiled, OpenGL internal resources filled, additional information added (to be more specific, multiple shader objects linked together into a shader program), any errors checked for and handled, and then the shader can start to be used (which itself can take multiple steps to tell OpenGL what data to use with the shader!). And then maybe a texture can be uploaded. And then something else, and so on. This is typically done sequentially, and while there are ways of attempting some of it in parallel using OpenGL, it's unstable at best.
Compare this to Vulkan, where the resources for shaders can be allocated while loading files, the shaders are partially compiled to begin with, render commands can be constructed in the meantime in another thread, and data transfers to the GPU can be running while that's all happening. It's easy to see here that multiple tasks can be done in parallel; this isn't limited to loading resources, but can also be used with tasks that must be performed every single frame. If the developer really wishes to, then of course Vulkan can be made to run single threaded, but there's little point to requiring that.
This ability of Vulkan to separate out tasks that can run in parallel more easily, makes it far more suitable to running game engine code in a manner more closely resembling DX11.
Code Flow and Features
Vulkan is often called a low-level API. More importantly (and perhaps accurately), it is an explicit API (the developer must tell it very precisely what it should do), and it matches against modern hardware architectures far more closely than OpenGL. This makes Vulkan somewhat flexible in how it is used; difficult to learn perhaps, but adaptable, meaning that how data is handled, how and when GPU resources are allocated, etc, can be made to more closely match DX11. Remember that original games are often written with some variant of DirectX in mind, not OpenGL, and so being able to convert a game engine's logic pathways into something running on GNU/Linux requires fewer hoops to jump through when using Vulkan. This is a big benefit when using DXVK; perhaps some data can be copied directly into GPU memory using Vulkan, whereas OpenGL might need to copy it multiple times, with a bit of converting in between, to achieve the same effect (obviously a slower approach, impacting performance).
Recent versions of OpenGL more or less reach feature parity with DX11, but that can't always be guaranteed, and native games might have been developed before that time. DX11 might be used with an original game, but OpenGL 3.3 used on a GNU/Linux port. Lack of directly translatable features (Compute shaders, for example) only make the ability to use older OpenGL versions to emulate DX11 that much more difficult, and with less performance. DXVK is of course much newer and can take advantage of graphics capabilities that simply weren't available under GNU/Linux when the native port was created. This is an important point: a native port might be well done for the time it was created, but hampered by the graphics interfaces available at the time.
Porting and Effort: OpenGL
Note that prior I mentioned that DXVK is essentially an implementation of DX11, and so it has been a comparison of how Vulkan and OpenGL can be used to work like DX11. The question that can then be asked is: why not rewrite the game to behave more like OpenGL instead? Technically, this would narrow much of the performance gap if it could be done right. OpenGL still suffers from lack of multithreading capabilities, but engines could be designed to minimise the impact of that. The practicality of the situation is, however, that time and effort is required, and rewriting a game engine is no simple feat, if feasible at all. Whatever works to get it shipping is often the best call that can be made.
If the game can start with OpenGL, then it makes it somewhat easier to have performance parity between platforms, however for a long time some of the desirable features that developers wanted were simply not available. OpenGL based code pathways lost out to DirectX, and so much of the work in getting a game to GNU/Linux has been porting after it's been developed to run on Windows.
Factor in developer experience afterwards: there are likely more developers familiar with DX11 than with OpenGL when it comes to game development, at least outside of the indie space.
Porting and Effort: DXVK
Running through Wine, DXVK does not require a particular game to have been ported to GNU/Linux. There's no real porting effort behind the game - the effort is behind a DX11 implementation. Comparisons become a case of looking at DX11 implementations, not game engine changes. This can be both good and bad: the game will come with whatever quirks it has on Windows, and relies on DX11 behaving correctly, but it also means that new quirks are not introduced. The focus of more experienced programmers on a single task (a DX11 implementation) benefits multiple games, rather than each game needing a porting team.
DXVK Drawbacks
Up to now I've perhaps made it sound like DXVK is some wonderland that will always defeat a native port. This is not the case, something I daresay is best illustrated by Feral's work on Rise of the Tomb Raider. The focus of native benefits here is primarily when using recent graphics technology (i.e Vulkan) - while not technically a requirement, in all practical scenarios it will be the case.
Generic
DXVK is generic. It's an attempt to provide an implementation that many games can directly use. This does come with drawbacks (the extent of which can be debated, but they are drawbacks nonetheless). Game specific optimisations are either more difficult, or more limited in scope, with DXVK. Native titles can carry these optimisations further: customise shaders to better suit Vulkan, perhaps texture formats can be changed, or even the threading capabilities further enhanced (remember that Vulkan is newer than DX11). DXVK must also try to support all features of DX11. Native titles do not. This might result in some graphical differences, but can also mean performance is much superior on a native port (if done right), or indeed that a native port will work at all where DXVK will not.
There's another area that causes quite a bit of stutter either initially with DXVK, or always within a game: resource construction. In terms of Vulkan, this will mostly apply to shaders and "pipelines". While shaders are more commonly known about, a pipeline is a data object that describes to Vulkan how rendering will occur: what shaders are going to be used, what hardware features will be needed, the types of resources that will be provided, the format of the resources, and so on. A pipeline contains all that information in one object, but if any of the information were to change, then a new pipeline object must be constructed. This is a very simplified explanation of course, but constructing a new pipeline is relatively expensive, and it's not normally known ahead of time. The same principle with shaders: constructing them and getting them ready is not known ahead of time, particularly with DXVK. Various mechanisms exist to cache them once built, so that later times running through the game they can be loaded much faster, but they must still be loaded at some point, and ultimately cannot be used until they are.
This construction of resources can have an impact on game performance. DXVK cannot tweak a game to attempt to hide the delay of this construction process, where as a native port can (with sufficient developer effort). It's worth noting that the impact of this is going to be highly game specific, and may need quite a bit of developer effort.
Developer Experience
As mentioned earlier, developers for larger titles will likely have more experience with DX11 than with OpenGL. This lack of experience in OpenGL means those older titles may have not been written in quite an efficient manner. I've personally looked across the API calls for various games and been aghast at what was done. The reality is that time available, developer experience, testing resources, etc, have simply been nowhere near what is needed for a quality port. In one particular case, given the effort that was required of a couple of developers, I'm amazed they had anything running at all in the time available!
Ultimately, however, this does mean that DXVK is benefiting from more time, effort, testing, and experience than those developers could hope to give to a native port, especially comparing OpenGL to DX11.
This is perhaps changing with Vulkan, and may not represent the state for newer ports where it is used. Feral, Croteam, Valve, and others, have shown that native titles using Vulkan directly can perform very well going forward. If DX11 is not used for a game, but Vulkan is directly used instead, then of course DXVK no longer becomes applicable.
DXVK of course will continue to benefit older titles, so this ends up being a win-win for gamers.
Stability
I've mostly looked at performance up until now, but a game that crashes most of the time probably isn't as good of an experience as one that performs less, but is more stable.
OpenGL in particular has a few areas of ambiguity. It lacked, and still lacks to a degree, formal driver test suites. Microsoft on the other hand controlled the quality of DirectX far more directly, and it's hard to argue against the documentation, examples, developer tools, and overall resources that Microsoft have supplied to developers for DirectX. This has lead to not only developers being able to test, debug, and tweak their code with more confidence on a Windows platform, but arguably driver quality (performance and stability) being higher for DirectX than for OpenGL. This in turn has invariably affected the quality of native titles on GNU/Linux - the effort required to ensure a game working across multiple hardware and software configurations has been traditionally quite high. DXVK can actually be more stable in some cases simply because it can rely on more thoroughly tested drivers.
Stability is a double edged sword though - DXVK relies on the stability of Wine itself, and naturally on the stability of the original Windows game. My own personal opinion on the matter is that this depends on the game: with older titles, Wine+DXVK might end up being more stable, but newer titles might give that edge to a native port.
It's worth noting that stability is something Khronos have been trying to improve with Vulkan. Driver test suites are available, validation layers for Vulkan are invaluable to a developer, documentation and tutorial resources are actively being worked on, and the standard of Vulkan itself improves with feedback from developers and the community. This all helps DXVK, but also makes the ideal situation being that DXVK is not required for new games if they can use Vulkan directly to begin with.
The Future
Graphics APIs are changing. DX12, Vulkan, and Metal, are slowly encroaching on the older interfaces, giving more capabilities to developers. But these changes take time, and game engines will need to adopt the new technologies. DX11 in particular is still heavily entrenched in a lot of game development, and many games released today will likely have DX11 support. This makes DXVK relevant for some time to come, with both newer titles and the vast catalogue of older games.
GNU/Linux systems are also constantly being changed. New library versions are released, new hardware supported, new APIs developed. Games are not indefinitely supported, and may not work with a new kernel, new driver, new glibc. Like with dos games now running on DOSBox, Wine provides a way for such games to continue to be played, and with software such as DXVK, played without a drastic performance loss.
Equally, continued changes mean new games natively supported on GNU/Linux benefit from newer versions of OpenGL, and of course Vulkan. Improved driver quality from all vendors when compared to even a handful of years ago has made gaming much more enjoyable. Wine+DXVK and native games can quite happily coexist. On a personal note, I like that there's even discussion of which approach runs better - it shows that games now run, and can run well on Linux.
Two years ago I asked the Croteam devs in the Steam forums if they could tell me why I could see only one CPU core going up to 100% and all the others staying at 25% ( https://steamcommunity.com/app/257510/discussions/0/135509024341635313/?ctp=2#c135509823661294050 ), while I was playing the Vulkan version of The Talos Principle, but still the performance was way better than the OpenGL version. I got answer:
"AlenL [developer] 23 Feb, 2017 @ 7:23pm
You are getting 100% CPU load because the CPU is not stalling and waiting for GPU. But you are getting better performance because it uses less cycles to generate rendering commands on Vulkan. That's completely logical.
You are not seeing additional core performance because we haven't implemented native multithreading on Vulkan in that build yet. We have that in the works, but it is not yet ready for release. So your Vulkan and OpenGL are running same threading engines for now."
and
"But nowadays, most games are more limited by CPU overhead. Hence Vulkan."
So even single threaded Vulkan is much more efficient than OpenGL. I guess DX11 performance might come single threaded Vulkan close.
Unfortunately, the latter still seems to be a common pitfall, and we end up with games that run significantly worse on D3D12 than they do with D3D11, even when CPU limited. Latest prominent example of that being Resident Evil 2, which runs faster with D3D11->Vulkan translation than it does with their native D3D12 renderer on Windows. And that just shouldn't happen.
Last edited by YoRHa-2B on 5 February 2019 at 12:07 pm UTC
I must say I'm somewhat glad it's not (only) Vulkan that has such problems...
And do you change the CPU limitation with DXVK, or is it even possible without generating lots of errors?
I guess with more freedom and responsibilities you can easily do things not exactly right.. I suppose it's not DX12 or Vulkan to blame.
No, don't stop your passions! You wrote a great article and I love learning more and completing my picture about the topic!
If I am informed correctly programming OpenGL
wasis a bit like programming a black box. I suppose laboriously programming Vulkan is much more predictable (if you know what you're doing) than guessing what the OGL black box needs.Great! Let's collect the best arguments to use Vulkan in favor of anything else. Here are my ideas:
-unlike DX availlable to any platform that wants to support it
-multithreading support to avoid CPU limitations
-performance on par with DX12. Only custom APIs for special hardware could reach higher efficieny
-more future proof than easier to use older APIs
-multi GPU support
-has tools to convert Vulkan code to DX12 and Metal
-the enormous flexibility of Vulkan that DXVK is a bright showcase for
Last edited by Nevertheless on 5 February 2019 at 9:45 pm UTC