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 --zink or --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.
All aircraft in the X-Plane 12 world cast a wake turbulence – a wing cutting through the air in X-Plane 12 leaves a vortex in the air that swirls inward over the wingtip, and sinks slowly as it dissipates energy over time. The strength of the vortex and its lifetime depends on the lift force generated by the wing (i.e. a wing that has to lift a 172 does not create a strong vortex, whereas a wing that supports a 747 surely does). Over the course of its life, the vortex sinks slowly and is displaced by the prevailing wind.
Flying through such a vortex can be dangerous! If you cross the vortex left by an airliner while flying a 172 yourself, be prepared to be tossed around or even flipped upside down. If you do the same with roles reversed, you might see a slight bump just enough to ripple the surface of your coffee (be sure not to do this in an A350 as spilled coffee can cause in-flight engine shutdowns).
Wakes left by AI aircraft
AI aircraft in X-Plane run the full flight model. That is, each wing is calculated using the same methods and with the same accuracy as for the user aircraft. Thus the amount of energy left in the wake vortex is clearly known, it just comes from the flight model. Therefore, if ATC clears that 747 to take off before you, be sure to stay above their flight path until you can turn away from it. For landing, stay above the preceding planes path and touch down slightly further down the runway than they did to stay safe.
Wakes left by online traffic, live traffic, and other plugins
For aircraft that are not run by the X-Plane flight model, such as other players’ aircraft from an online network, or real-world traffic injected from a plugin like Live Traffic using data from an ADS-B exchange, X-Plane makes a best effort guess based on the data provided by the plugin. The plugin can tell X-Plane how heavy the aircraft is, and its wing area and wingspan. In the absence of this data, X-Plane will fall back on a fairly conservative light aircraft estimate, assuming a Learjet-sized aircraft weighing 10 tons with a 12m wingspan. This means you are not going to get flipped upside down in your 737 if you end up flying through a wake left by an old plugin. This is to minimize user frustration with existing online flying plugins. Since the wakes are technically an extension of the TCAS override API used by plugins since X-Plane 11.50, all plugins that show traffic in X-Plane 11.50 are compatible with wake turbulence generation and will gain that base functionality automatically when used in X-Plane 12.
Wake turbulence data for plugin authors
Plugins can use new datarefs starting with X-Plane 12 to inform X-Plane of physical properties of the non-player aircraft that are then used for a more accurate strength and duration of the wake. By writing to the new datarefs, a plugin providing traffic data can upgrade from the “generic Learjet wake” to an accurate wake representative of the aircraft they are actually drawing.
Learn about wake turbulence avoidance
In X-Plane, you can cheat and make the wake left by an aircraft visible by having it drawn in the sky in a color scheme showing its danger (from red over orange and yellow down to green) so you can avoid it (or fly through it on purpose to experience the effect). Wake visualization is just one of the many graphical flight model outputs available. Press Ctrl+M to toggle graphical flight model output in X-Plane. By repeatedly pressing Ctrl-M you can cycle through all the visualizations available, while a small white label tells you what you are looking at. Keep toggling until you see “Wake Turbulence” displayed and marvel at the air disturbance waiting to make your day interesting.
You can also use X-Avion on your iPad to have wake turbulence danger zones visualized – this works in real airplanes using ADS-B data, and it works in X-Plane when driving X-Avion over network.
This post is just targeted at plugin developers who are modernizing their object drawing – if you don’t write plugin code, the Cincinnati Zoo has been showing their animals on Youtube – it’ll be a lot more entertaining than this post. (An XPLMInstance cannot tunnel down two feet in fifteen seconds – one point for the zoo animals.)
XPLMInstance makes a persistent object that lives inside X-Plane that is visible in the 3-d world. It changes how you draw from “run some drawing code every frame” to “tell X-Plane that there is a thing and update its data every now and then.”
Instancing is actually a lot easier than draw callbacks! But there are two tricky gotchas:
1. You must create the custom DataRefs for your OBJ’s animation before you load the object itself with the SDK. (If the DataRefs do not exist at load time, the animations are disabled as “unresolved to any DataRef”.)
2. When you create the instance, make sure your custom DataRefs are on the list of DataRefs for that instance.
Here’s the really baffling thing: if you create the custom DataRef and then add it to the instance’s list, your DataRef callbacks will not be called.
Wha?
Here’s the trick: the DataRef you register is a global identifier, allowing the object to refer to what it wants to listen to. That’s why you have to create the DataRef – so that the identifier exists.
But when you create an instance, each instance has memory that holds a different copy of those DataRefs.
For example, let’s say you have a truck with four DataRefs, and you make five instances. X-Plane allocates 20 slots (four DataRefs times five instances) to store five copies of each DataRef’s values.
The instances never look at the DataRef itself. They only look at their local copies. That’s why when you push different data to the instance with XPLMSetInstancePosition, each instance animates with its own values – each instance looks at its own local data.
This is also why you won’t see your DataRef callbacks called (unless you use DataRefEditor or some other tool). The object rendering engine isn’t looking at the DataRefs themselves, it’s looking at the local copies.
In other words, XPLMInstance turns DataRefs from the pull model you are used to (X-Plane pulls on your read function to get the value) to a push model (you push set with XPLMSetInstancePosition into the instance’s memory).
This implies two things about your add-on:
It doesn’t really matter what your DataRef read functions do – they can just return zero, and
You can’t use tools like DataRefEditor or DataRefTool to debug your animations. (That didn’t work well in legacy code either, but it really won’t work now.)
If you try the obvious optimization of not creating your custom DataRefs (“hey, no one calls them”) before you create your instance, you will find that animation just stops working. This is because we need the DataRef to be that global identifier to match your instance data with the animations of the object itself.
One last note: if your old code used sim/graphics/animation/draw_object_x/y/z to determine which object was being animated (from inside a plugin “get” function) you do not need to do this anymore. Because each instance has its own local copies and your DataRef function isn’t called, this technique is obsolete.
In summary:
You must register custom DataRefs.
Their callbacks can just return 0 – they’ll never be called.
Always list your custom DataRefs for animation when you create an instance.
Do not use draw_object_x/y/z; use XPLMSetInstancePosition to create per-specific-instance animation.
We have updated the X-Plane plugin SDK and related documentation for X-Plane 11.50. Here are some links:
New Plugin SDK: version 3.02 adds the new modern 3-d drawing callback for OpenGL/Vulkan, and deprecates the drawing callbacks that are unavailable in Vulkan/Metal. Download it here.
(Updating to the new SDK is not mandatory for your add-on to be Vulkan-compatible, but it can help catch drawing callbacks that will not work, and it is necessary to use the new 3-d drawing tech.)
Plugin Compatibility Guide:a short guide that focuses on issues existing plugins might have with X-Plane 11.50. If you are updating a plugin, read this!
OpenGL Drawing Guide:complete documentation for all aspects of drawing using OpenGL with X-Plane. If your plugin uses OpenGL, this is a must-read.
Drawing Over 3-d in 2-d: this sample code shows how to draw in a 2-d window or drawing callback with coordinates that match the 3-d world. Many 3-d plugins that draw need this kind of drawing, e.g. to label routes or aircraft with UI that matches the 3-d world.
Instancing Example Plugin:a sample plugin that draws objects using the XPLMInstancing APIs. Many add-ons will need to transition from object drawing to instancing to be compatible with Vulkan. We strongly recommend moving to instancing – it provides the fastest, most compatible drawing path, particle system support, and in the future will support FMOD sound.
Instancing is actually much easier to use than XPLMDrawObject and bypasses a lot of complexity and chaos. Instancing works with all versions of X-Plane 11, and the sample has everything you need.
X-Plane has always shipped with the shaders visible to everyone as plain text in the Resources/shader directory. Partly this was due to making it convenient to load the shaders into OpenGL itself, but we also don’t have anything to hide there either so it doesn’t make much sense to try to hide them. You are more than welcome to look and poke at our shaders and if you learn something about X-Plane in the process, that’s awesome!
However, the one big caveat to that is that we never considered the shaders to be part of the publicly accessible interface and they are in no way stable across versions. X-Plane is an actively developed product and we are making a lot of changes to the codebase, including the shaders, so you should never ever distribute a plugin or tool that modifies the shaders. Since we give no guarantee that our shaders will remain stable across versions, you’ll always be left worrying that we might break your add-on.
Additionally, there is a big change to the shader system coming in 11.30 that will definitely break all existing plugins that are modifying shaders. This blog post will cover the upcoming changes and hopefully convince everyone that the shader system is in flux and not to be relied upon as a basis for add-ons. Read More
I’ve gotten a handful of emails from third-party devs recently asking the question:
I have a bunch of XPWidget-based windows. When will I be able to use them with fancy new features like UI scaling, pop-out support, VR support, etc.?
Happily, the answer is: now!
I really buried the lede on this one, but back in X-Plane 11.20, as part of adding plugin support for VR windows, we added a new “mode” for XPWidget-based plugins. It all starts with a call to opt-in to the “modern” window APIs like this:
From this point forward, all widget windows you create will be backed by a modern XPLM window, and can therefore be used with all the new XPLMDisplay APIs. All you have to do from there is call XPGetWidgetUnderlyingWindow() get the XPLMWindowID of your window to pass to those APIs.
Posted inPlugins
by Tyler Young|Comments Off on Widget Windows, You Fancy Now!
X-Plane 11.20r2 has only one bug that we are trying to fix: a bug in the plugin SDK that can cause some plugins to crash when creating and destroying windows.
Tyler and I dug into this and found that the fix was a bit more intrusive than we wanted for this late in an RC.
So: if you are a plugin developer and you are working with the new SDK, either for VR compatibility, to use the new 3.x APIs, or just because you are updating the plugins, and you have time this weekend, please email me and I can send you our new fixed XPLM DLLs.
My hope is to get half a dozen plugin developers to bang on them over the weekend, so that when we cut 11.20r3, it really will be the release.
Edit: RC3 is live – thanks to everyone who helped!
The CEF post generated a lot of controversy, and rather than replying directly in the comments (and doing a bunch of copy & paste), I thought I’d collect my responses to the major objections here.
Objection: Nobody wants to browse the web in X-Plane!
Yes and no. I agree that, unless you’re in VR, a full-fledged web browser is totally useless. Nobody wants to be browsing cat pictures while flying. But CEF is really not designed to power a traditional web browser.
Consider this list of a bunch of other applications that nobody wants a web browser in:
Spotify
Adobe Acrobat
Evernote
The Steam client
The Atom text editor
The GitHub desktop client
WhatsApp
What do all those applications have in common? They’re built on CEF, or the closely related Electron project.
My point is this: the primary use case for CEF is not to build a full-fledged browser—it’s to support things like HTML5 user interfaces, which massively lower the bar for creating nice, easy-to-use plugins. It could also support things like displaying PDF charts or other electronic flight bag features—things that are theoretically possible without a webview, but which have such a high barrier to entry that nobody wants to tackle them.
We are always looking for ways to both
get more people involved in creating X-Plane add-ons, and
give existing plugin developers better tools so that they can create things they couldn’t have before.
Doing so makes the X-Plane community stronger, and supports the creation of add-ons that might otherwise not have existed.
Objection: This is a waste of time. What you should be working on is [some other feature].
As I mentioned previously, CEF is being used in X-Plane right now to enable in-app upgrades. This is obviously the most boring non-feature we could ever ship, and I understand why power users (people who might have bought X-Plane 11 on day 1!) are irritated.
The reality is: some features we ship for end-users*, and some we ship to “pay the bills.” Paying the bills is boring, but important: having X-Plane be financially successful ensures that we can continue improving the sim (ahem, in ways that end users actually care about!) for decades to come. In this particular case, we have reason to believe the current purchasing process is convoluted enough that it’s losing us sales. In-app upgrades will increase sales by some (small) percentage, so even though it’s not a direct improvement to the sim for existing users, it’s funding future development.
One more thing worth mentioning on the topic of “I wish you’d do x instead” is that we have a handful of full-time developers now, with people specializing in very different areas, so we tend to have a lot of features in progress at any one time. It’s certainly not the case that, say, Sidney stopped working on improving performance while I was off integrating CEF. 🙂
Objection: I don’t want X-Plane plugins using webviews!
The reason we’re having this discussion is that plugin developers are already using CEF—and they’re doing so in ways that are incompatible with other developers’ implementations.
It’s certainly an option for us to bury our heads in the sand and ignore this—we could force users to choose between, say, installing a Flight Factor plane and installing a fancy new web-based plugin (or using future X-Plane core features). Ultimately, though, this hurts both the end users who would have otherwise chosen “all of the above,” and it hurts the add-on makers who lose sales because users were forced to choose.
We can’t stop add-on makers from using webviews, but we can make sure that doing so doesn’t lead to a compatibility nightmare for end users.
Objection: CEF represents a massive security hole!
This is absolutely a concern for us. Webviews in X-Plane present two major attack surfaces:
The possibility of running untrusted code (e.g., a nefarious site exploits a browser vulnerability to execute harmful code on your machine)
The possibility of sending data somewhere you didn’t want it to go (e.g., a nefarious site masquerades as your bank’s web site, and sends your login info to bad guys)
We’re still in the “exploration” phase here, trying to understand plugin developers’ needs, but there are a lot of ways we could mitigate these threats. A few possibilities, listed from most extreme to least:
Don’t allow remote connections at all; plugin-created webviews could only load local assets (HTML, JS, etc.) that were bundled with the plugin
Disable JavaScript entirely
Require plugins to provide a whitelist of URLs that are deemed safe to send & receive data from
Disable JavaScript loaded from external (or non-whitelisted) domains
Allow user preferences to control the above policies (or even disable webviews entirely)
Objection: CEF will slow the sim down. This is bloatware!
That’s for measurement to decide! In our tests, having CEF displaying static pages while flying didn’t slow down the sim by any amount we could measure. And since CEF doesn’t run on the main X-Plane thread, the OS can schedule CPU-intensive things like page loads around X-Plane’s work. There is definitely some memory overhead involved (a few hundred megabytes), but considering the existing footprint of X-Plane, it’s not a crazy amount.
And, like everything in X-Plane, if you want to tune it to get the last drop of performance, you’d be free to avoid using features & add-ons that depend on webviews.
Objection: Don’t use CEF—You should use WebKit, Gecko, Servo, etc. instead.
I did a lot of research and test implementations (on Windows, I went so far as to use Trident, the underlying engine to Internet Explorer!), and the only webview framework I found that meets X-Plane’s requirements was CEF.
* Aside: What does 11.20 include for end-users? A few highlights from the release notes:
In the X-Plane 11.20b1, we’re shipping a web browser for the first time. We’re using the Chromium Embedded Framework (CEF)—essentially the same guts as Chrome, wrapped inside X-Plane.
For the time being, it’s being used in one place only*: to support in-app upgrades, so that if you have the demo, you can buy the full version of X-Plane without having to go to the web site. The web view is seamless—you can’t tell by looking at the app that it’s not just part of the native X-Plane user interface.
While its present use is quite limited, if all goes well, we’d like to expand its use elsewhere in the sim—in The Glorious Future™, we could potentially use it to load online charts and the like.
But, there’s a hitch!
There’s not a good way to load two copies of CEF at a time. And, since some plugins (like the ones used in the new Flight Factor A320 Ultimate) depend on a version of CEF provided by a (global) plugin, we have to disable X-Plane’s web browser functionality in the presence of that plugin. This isn’t a big deal right now—after all, if you’ve installed payware, you probably already own the sim anyway—but it will be a shame if, in The Glorious Future™, you have to choose between your payware and core X-Plane functionality.
The situation is even worse than you might expect: CEF absolutely doesn’t support multiple initialization calls in the lifetime of an app—you can’t initialize it, shut it down, then re-initialize it. That means it’s not even possible for plugin authors to be good citizens and “relinquish” CEF to X-Plane, such that you could at least use X-Plane’s browser whenever you’re not using an add-on that depends on it. It’s all or nothing! In fact, you’ll have to uninstall the CEF plugin before X-Plane can use a web view itself.
There are two possible fixes here:
At some point in the future, we provide access to CEF via the plugin SDK. If we did, it would have to be to the C API only—no fancy C++ wrappers for you. Speaking as someone with the memory of writing for the C API fresh in his mind, let me say: this isn’t a whole lot of fun, and it’s rife with the potential for memory leaks. Moreover, this would break any existing addons that depend on CEF—they would be forced to migrate to the SDK version of the API.
We could (theoretically) compile an X-Plane-specific version of CEF that would not conflict with the version plugins are using. This would require renaming all the Objective-C symbols on Mac, and renaming the DLL on Windows. I’ve not investigated this for feasibility, but it’s certainly theoretically possible. This would allow X-Plane’s version of CEF to coexist with (one) plugin-provided copy, albeit at double the CPU and memory cost.
Having us expose CEF via the SDK is not an unequivocal win. CEF is notoriously incompatible between versions—you can more or less guarantee that even minor updates will break compatibility of the API somewhere. That means X-Plane would be stuck at a fixed version of CEF for at least the lifetime of a major version to prevent breaking plugins. X-Plane 11.20 uses CEF release 3202; it would be at least the next major version before we updated CEF to a newer version. There are two major downsides to this:
When X-Plane updates to that newer version, it would break plugins compiled against old versions of the SDK that depend on CEF. That’s a lot more aggressive than our normal deprecation policy, and it makes CEF plugins a potential maintenance headache for plugin devs.
If your add-on really, really needs features from the latest and greatest CEF release, you’re out of luck—wait a couple years (!!) and maybe we’ll update.
So, here’s what I’d like to hear from plugin devs:
Are you currently, or are you planning to use CEF in the future?
Would you be willing to use the C version of the CEF API only?
Would you be able to accept the limitations and potential headaches (outlined above) of X-Plane-determined CEF versions and compatibility?
If you don’t mind telling me a bit about your intended use cases, that’d be very helpful as well!
EDITED TO ADD: There’s a third option here that I didn’t consider: X-Plane could provide a “wrapper” around CEF that offers “just” a browser surface, and simple interfaces like the ability to change the URL programmatically. This has the advantage that we could update CEF regularly without breaking the API (though there’s always the risk that a new version of Chromium would change how it handles your HTML + CSS + JS). The disadvantages are twofold:
a) If a plugin developer really, really needs the full power of the CEF API, they’re out of luck (or we’re back to square one with respect to having to disable core X-Plane functionality in order to support the plugin).
b) New XPLM APIs are a massive tax on our development time. Every time we need to make a change, we have to go test a dozen plugins… then go through an extensive beta… then inevitably hear about a show-stopping bug we introduced three hours after a release goes final. 😀 In contrast, providing a (major-version-stable), transparent copy of CEF costs us very little dev time; time that would otherwise be spent maintaining the XPLM API can be spent on, like, major features.
* Aside: This is actually how we test a lot of new tech in X-Plane: we find a single, relatively out-of-the-way place to make use of it, ship it in a major version update, and wait to see if it blows up. Betas catch a lot of bugs, but not all, so this is a way of hedging our bets when it comes to code that hasn’t been battle-hardened. This is how we worked the bugs out of the user interface framework (Plane Maker’s panel editor was the testbed), the X-Plane 11 particle system (behind the scenes, it was used for some very minor effects in X-Plane 10.51), and more.
Plugin developers: the title says it all – don’t register a drawing callback that doesn’t actually draw anything.
When I write it like that, it sounds a little bit silly, but some plugins register a drawing callback on startup, because they might draw something – but then only do the drawing when certain things happen. I am guilty of this myself – libxplanemp registers its drawing callbacks at init time even if there are no multiplayer planes to draw.
Most plugins did this for simplicity and to avoid any strange rules about when you could register things – the original 1.0 SDK was a lot pickier than what we have now. And back in 1537 when the French invaded Flanders, the cost of a no-op a draw callback was pretty cheap – just the cost of the function call-out and a few instructions of book keeping.
Over time, as X-Plane’s renderer has become more complex, this has become not the case. X-Plane now does some significant work to save and restore GL state when we hit a drawing callback, and that overhead is going to become significantly more expensive when we move to Vulkan/Metal.
To optimize this, Tyler modified the drawing callback code in 11.10 – starting with 11.10 if we find that no plugin has registered a given drawing callback, we skip the entire process, including the OpenGL book keeping.
So if your plugin goes in and registers a callback for every single drawing callback type then we have to fall back to the slow path, carefully stashing our GL state and prepping for your running at each drawing callback point.
Here’s my guidance:
Never register for a drawing callback you’re not going to use.
Do delay registering for a drawing callback until it is possible to need it.
Don’t try to optimize your drawing callbacks by registering and de-registering per frame.
So as an example, it would be reasonable for a multiplayer API to register a drawing callback when the first airplane enters the system and then keep it around until the last airplane goes away, even if that airplane is off screen.
(The reason for that last rule is: if we have to make an expensive graphics transition once we discover that drawing callbacks will be needed, we don’t want to get thrashed by drawing callbacks disappearing and then re-appearing over and over.)