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:

  1. Never register for a drawing callback you’re not going to use.
  2. Do delay registering for a drawing callback until it is possible to need it.
  3. 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.)

About Ben Supnik

Ben is a software engineer who works on X-Plane; he spends most of his days drinking coffee and swearing at the computer -- sometimes at the same time.

13 comments on “Plugins: Do Not Register Drawing Callbacks That Do Not Draw

  1. “…this has become not the case.” Prose if there ever was such!

    Why #2? Why does position in the plugin code matter? Is the scanning introduced in 11.10 smart enough to wade through conditionals and the like? Even then though, runtime behavior will obviously vary per frame.

    1. Do you mean: why should you delay registering a drawing callback until it is _possibly_ necessary to draw?

      The answer is: to avoid the performance penalty of having the draw callback when it is not really needed. Consider XSquawkBox or another drawing multiplayer plugin.

      Users leave XSquawkBox installed and running _all_ the time. But when not connected to the network, the plugin _never_ needs to draw…we know this about the plugin – it’s inert when disconnected.

      So the right thing for XSquawkBox and its multiplayer lib to do is to not register the draw callback until the user connects to the network. That way the user doesn’t have to uninstall XSquawkBox to recover the FPS from the drawing callback registration.

  2. Two things:

    1. I’ve been researching the method by which drawing the various XPLMDrawingPhase’s can be disabled to increase performance for systems that are only presenting instrumentation. This would be similar in effect to Sandy Barbour’s DrawingDisabler plugin. Given a brief exchange we had some weeks ago, this blog post and the SDK entry for XPLMDrawCallback_f, I’m wondering if we’re heading in a direction where disabling drawing attempts could result in a performance penalty, rather than a performance gain.

    2. Upon visiting the SDK this morning, I note that the whole thing has been nicely formatted to be “pretty.” Unfortunately, as with the blog you see right here, the paragraphs and code text are so narrow as to use only 1/4 of the available screen width. This is okay for the blog, I guess, but this is truncating all of the code examples on the right. Some of the lines are pretty wide, and you cannot scroll easily since the scroll bars are waaay down at the bottom, at the end of some rather long examples.

    I would agree that the old Wiki site was a bit Wonky, but this new format is barely usable in many cases. Given the extensive use that many hobbyists and pro’s alike make of the SDK site, I think it would be a real benefit to update the stylesheet or whatever to make better use of the real estate on the browser page. More width, please! This is not smartphone territory. 😉

    1. Hi Steve,

      1. Draw disabling is going to get deprecated. The notion that plugins can go in and sanely remove pieces of our rendering pipeline is totally crazy, and even now the support for it is deteriorating because the actual structure of the rendering engine is NOTHING like the set of enums we declared in 2001.

      At this point it’s only safe to use a small subset of the draw callbacks, and disabling them is a bad idea.

      In the future I expect to publish some guidance as to which callbacks to use, and that guidance will be to never disable things.

      2. I think at default page size the paragraph width is acceptable – it could be slightly wider but since it was done by an actual graphic designer and not a programmer, I’m not looking to second guess it.

      1. 1. That’s disappointing, since there is a use model for disabling non-2D rendering on X-Plane slave systems used only for instrumentation.

        2. Please reconsider your second, or perhaps third guess, my friend, if you would! 😉

        Really, try this on for size and see if you think it’s a sane way to present a code example:

        https:/code-sample/draw-terrain-object/

        Do *you* use the SDK website for code examples and the like? 😉

        Graphics designers apparently do not fully consider long term utility these days. I respect their skills, but if you honestly think that only using less than the full available width of a 16:10 screen is wise for documents that are far more likely to be used by desktop deployments, I can only agree to disagree. 🙂

        If nothing else, the code window should be resizable for those of us that don’t refer to the SDK website on a smartphone. 😀 Graphics designers, just as much as we code pushers, can err. And I’m both, for what little that is worth! (So I guess I get twice as many chances to mess up. Aren’t I lucky!)

        1. For non-2-d rendering, put the sim into “2-d panel only” mode – we’ll bypass stuff in the rendering engine that you can’t get at via the SDK.

    2. Re: the SDK layout, there’s one case where I agree with you: cases where the table of contents sidebar would be empty. (This applies only to a few of the sample code pages.) I’ve rolled out a fix for that now.

      1. Hi,

        I humbly suggest to add a button, before the code example, to allow to display the code in a popup window where all the width assets will be used. If it will be colored too then great.

        My 2 cents, if LR doesn’t want to invest in this, just copy paste the code to your editor, that’s what I have done.

        Cheers

        1. That works, but the older Wiki site did not require that. We would have one more step to research something, and time is valuable. Why there was any need to change the look of the information is beyond me. Developers don’t give 2 cents about how pretty a site is, only how quickly they can drive to the answers they need. Get a graphics guy involved and… 😉

          Good idea to resolve the code display problem.

          We have these beautiful widescreen displays these days, and they’re a boon to use, as long as practical decisions are made. The SDK site only uses half of the available width.

  3. I’m not a plugin developer, but I think the golden rules (for whatever feature) are (in chronological order):
    1) Provide the right API
    2) Provide a correct (ideal) usage example (real-world usable)
    3) After you told people how to do it correctly in 2), tell them what not to do.
    4) Avoid any incompatible changes to the API (i.e.: changes to the specification).

    Steps 2) and 3) could be one if you define exact rules what is allowed, and everything that is no allowed is forbidden then (telling what is allowed, and what is forbidden, amy leave some grey zone behind).

    At the moment, some specs are rather “thin”, like https:/sdk/xplm_Phase_Objects/ 😉

  4. On 2): I picked a random example, finding code that made my hair stand up:

    PLUGIN_API int XPluginStart(
    char * outName,
    char * outSig,
    char * outDesc)
    {
    strcpy(outName, “HelloWorld3Plugin”);
    strcpy(outSig, “xpsdk.examples.helloworld3plugin”);
    strcpy(outDesc, “A Hello World plug-in for the XPLM300 SDK.”);

    It’s very much against about all safe C programming conventions to pass back strings like that! (I’d use (e.g.) “const char **outSig” in the formal parameters and then “*outSig = String_Literal”. Of course for dynamically created texts that has to be more careful. The other safe alternative is to pass the buffer limits as formal parameters, like “size_t lenOutSig”, allowing to use “strncopy(outSig, String, lenOutSig)” for example.

    1. Yeah, the use of the declaration with no buffer overrun conventions is definitely a mistake – one that dates back to the original API. In the modern extensions we’ve used callbacks, so that no one is ever filling in someone else’s buffer.

      This kind of thing is hard to fix – a wise person once told me (one blog commment ago 😉 that amongst the golden rules of API design are to not introduce incompatible changes.

Comments are closed.