X-Plane 12.04b3 ships with a new feature called “Zink”, which we hope is going to alleviate a lot of the long standing issues that many users, especially with AMD GPUs have suffered from. This hopefully provides a work around for both flickering plugin drawing, eg. EFIS screens that either flicker or are missing altogether, but also potential improvements in performance by decreasing driver overhead.
If this sounds like you, you are welcome to give this a try right now by upgrading to 12.04b3, going into the Graphics settings and checking the “Use Zink plugin bridge” check box. Restart X-Plane and if everything goes to plan, X-Plane should look exactly the way you are used to but most importantly your plugins should look right and your performance might be better too. Because Zink is built on top of Vulkan, it’s only available to Windows and Linux users and is not applicable to macOS and Metal.
If you only take one thing away from this blog post, I hope it’s this image showing the difference between native Vulkan/OpenGL interop as well as Zink interop gives you an idea of why we are excited about this:
Now that I hopefully have your attention, let me elaborate how we got here and what this means for both users and developers. First of, Zink is actually a graphics driver that sits between plugins and X-Plane and translates plugin OpenGL rendering into native Vulkan commands that get executed by the same Vulkan device that X-Plane is using for rendering. Of course, X-Plane itself no longer uses OpenGL, but it’s is still very important for plugin development. A long time ago, when X-Plane was still OpenGL based and the plugin SDK was first made, it seemed like an absolute no-brainer to just expose the X-Plane OpenGL context to plugins directly and let them handle all their drawing needs themselves. It gives the most flexibility and control over everything, and it also makes it easy for the SDK because there is no need to make fancy drawing routines to be used by plugins.
Fast forward to the Vulkan and Metal port and we suddenly have an issue: Neither Vulkan nor Metal is OpenGL, but there are now hundreds of plugins out there that all assume X-Plane uses OpenGL and the OpenGL context is there. Killing OpenGL for plugins would mean countless plugins would stop working, requiring potentially lengthy update processes or maybe they’ll just never work at all again because the author lost interest in X-Plane or developing the plugin. This is how we ended up with the OpenGL Bridge in X-Plane 11.50: We create a real OpenGL context, share some memory from within Vulkan to that OpenGL context, then let plugins continue to draw how they used to do. X-Plane takes care of all of the heavy synchronization and resource creation rules under the hood and everyone is happy. Everyone? Well, no, not quite…
The problem with Vulkan/OpenGL interop
The big problem with Vulkan/OpenGL interop is that it relies on the driver to support this properly. As it turns out, driver support for this is flaky at best, if you own an AMD card you can probably tell long stories about issues. The most prominent one is flickering or altogether missing rendering, in which case plugin drawing is either completely missing or flickering in and out of existence making it basically impossible to use plugins. The other issue is performance, captured in the screenshot above, where the OpenGL bridge adds almost 10ms per frame, although I have seen numbers as bad as 30ms per frame. For reference, 33ms is the time one frame can take at most to reach 30 FPS! This wasn’t always the case, it used to run much better, but driver regressions are a real thing and this isn’t really something the hardware vendors test. Not that I can be too mad about this, X-Plane is one of the very few applications that uses this feature at all. Despite having filed numerous bug reports with the vendors, unfortunately the problems were never completely fixed, so even during the 11.50 days we started thinking about alternatives. During the X-Plane 11 days it was at least somewhat easy to tell users to switch back to OpenGL to avoid the flickering, even though that usually meant a hit in performance because the Vulkan backend was just so much faster.
There are of course other open source OpenGL drivers out there that aren’t Zink. The most well known one is probably Angle, a implementation of OpenGL ES by Google. None of them work for us however, because of another terrible decision made many years ago: X-Plane has always used a compatibility profile OpenGL context. What that means doesn’t matter, but the end result is that X-Plane and by extension plugins, rely on the existence of OpenGL commands from the 90s! Most modern implementations of OpenGL will happily ignore everything from the compatibility profile because it’s a nightmare to implement and doesn’t map very nicely to modern hardware at all. But a lot of plugins make use of these old features and rely on the fixed function pipeline. Which, by the way, is also the reason we didn’t just expose Vulkan or Metal to developers. Writing either a Vulkan or Metal renderer requires a ton of overhead, is deeply complicated and error prone. Writing correct code requires testing on different hardware, reading a few thousand pages of specification text and having a good understanding of the underlying hardware. Most plugin developers don’t venture past the fixed function pipeline, it would be absolutely unreasonable to expect them to spend the time and effort involved in this.
What’s a Zink?
Luckily we don’t have to throw any developers into the deep end because there is Zink. Zink is part of the Mesa open source project and is a backend for the Gallium driver, which is the OpenGL frontend provided by Mesa. Okay, lots of big words here, let’s simplify this a bit: Gallium implements OpenGL 1.0 to OpenGL 4.6, which basically means “all of OpenGL”. But it doesn’t actually do anything with it, it just does all of the heavy lifting required to make OpenGL work. Backends are what actually turn the intermediate data that Gallium produces into real commands to be executed by a GPU. There are a lot of these backends: For example there are multiple software renderers that just use the CPU, there are implementations that talk to AMD GPUs, Nvidia GPUs, Intel GPUs, things I never even heard about, it’s all there. But among all of those backends there is also Zink. Zink just takes what Gallium produces and builds Vulkan commands out of it to be executed by any Vulkan capable hardware. This is what makes Zink so great for us, it’s a real OpenGL implementation that includes all of the hard and complicated bits we need to make plugins work.
Of course I’ve made it sound easier than it really is, “just” writing a Gallium backend that magically speaks Vulkan is a lot of hard work. The unsung hero of all this is Mike Blumenkrantz, head honcho and lead developer of Zink. He’s spent years getting Zink to the point it is at and is contentiously working on improving it, both in terms of supported features as well as performance. He’s also an absolute legend and none of this Zink interop X-Plane stuff would exist if it wasn’t for his help, not just in getting Zink to where it is but also answering tons of our questions during the integration. Big shout out to Mike! While I’m doing shout outs, it would be unfair of me to not also mention AMD. While they are partially the reason we are here today, they also provided us with help and driver updates to make Zink work together with X-Plane and every engineer of theirs that I have met along this journey has been nothing but kind and helpful.
I’m a user, how does this affect me?
If you are on X-Plane 12.04b3, open your graphics settings and enable the Zink backend. By default we run with the native OpenGL backend for compatibility reasons, although the long term goal is to switch to Zink exclusively, but not anytime soon. There is a chance some or all of your plugins will explode, we’ve done testing with third party developers on this, but the area touched by this immense and we can’t test every plugin out there. If it breaks, no worries, please file a bug report and let us know, fall back to the native OpenGL backend and try again in the future. The idea behind Zink is to make it as much a “it just works” thing as possible, but it’s the first step and if it isn’t perfect right out of the gate, I hope you have some patience with us. I’m saying this because like I said, the surface area touched is immense here and shipping a whole graphics driver with an application isn’t really something super common and, as I have found out, sometimes breaks stuff.
The good news is that Zink is open source and we are building it ourselves, which means that for the first time we can actually see under the hood when things explode. I have very high hopes that this will help us track down issues much faster than usually. Normally drivers come with all debug data stripped, so a few times I have seen bugs that just end somewhere in the driver with no way to tell what even happened or how to reproduce it. Sometimes we don’t even have any information at all because it got so thoroughly muddied.
I’m a developer, how does this affect me?
Well, same as above: Test your plugins, file bugs, be patient. But also, there are a few things you might want to be aware of in general:
First, X-Plane now finally lets you enable a debug GL context. If you run X-Plane with
--debug_gl, X-Plane will make a debug GL context for you and then wire up the necessary callbacks. By default it’ll print all messages into stdout and errors get a big in sim pop up. But you can always redirect it to something of your choosing by calling
glDebugMessageCallbackARB() with your own callback. Please don’t ship plugins with a handler enabled though, because it might lead to other developers not being able to set their own callback as there can only be one. The debug GL context is available when running through Zink and also the native GL driver.
Gotcha wise, there are two that I’m aware of:
- In theory you can make a shared GL context for background GL processing, but it might not be 100% stable. I’m still trying to track down an issue somewhere in the stack that leads to resources being incorrectly deleted, so if you run into issues with a shared GL context, this might be it. Please try it though!
- Don’t disable and/or enable
GL_FRAMEBUFFER_SRGB, this will lead to all subsequent rendering to disappear. This bug I have tracked down further into Mesa and the problem is that the driver will create a copy of the image to add or remove the sRGB bit, but it never ends up copying the result back over. In theory this should be handled by just a view on the same image without any copies, but either way this is currently broken.
If you want to test Zink as part of some CI solution, you can also run X-Plane with
--no_zink through the command line and it’ll override whatever was set in the graphics settings.
I’m on macOS and I feel left out
First of all, I’m sorry to hear that. 12.04 has great things for macOS users as well that I’m sure you’ll love. Long term, we are having ideas of running Zink on macOS too, just this time on top of Metal. GL on macOS is already emulated through Metal, it’s just done by Apple without visibility or ways to tap into that. We have a bit of a pipe dream of running plugins on top of Zink on top of MoltenVK on top of Metal, but this is purely in the ideas bin right now and no code for this has been written. There would be two advantages for this approach though: First, Apple has deprecated OpenGL already in macOS and while I do believe they will continue to support it, lest their pro users will climb on their roof and shout bloody murder, they clearly have no interest in expanding OpenGL support any further. Secondly, if we get OpenGL bridging down to just Zink on all platforms, it’d be a boon for developers because they can target just one OpenGL implementation and cover all platforms in one go. It’d also finally bring OpenGL 4.6 support to macOS, which is currently held back to OpenGL 2.1.