Tag: inside x-plane

A Slow Motion Car Crash

I’m driving at 55 mph on the highway. I drive over a nail, lose a tire, skid off the road, crash through the guard rail, plunge off a cliff, and die. That’s not much fun. But when you get to the accident site, you’ll probably be able to piece together what happened. The skid marks, the nail, the hole in the guard rail, the car wreckage below – you can connect the dots.

Now…let’s say I’m driving 500 mph. Same nail, same out of control crash. But this time it’s going to be a lot harder to tell what happened. Lord knows where the nail ends up, the distance from the nail strike to exiting the highway is going to be a lot bigger, and the car is going to be in smaller pieces scattered over a wider distance. It’s going to take a lot longer to piece together what went wrong.

That, in a nutshell, describes the motivation for an X-Plane beta with all of the debug and safety checks on. X-Plane’s normal operation is like the car doing 500 mph – when it crashes and dies, there’s very little left that can be used to figure out what went wrong. When there is a bug in the code that destabilizes the sim, finding it via crashes in release builds takes a lot of developer time and slows the whole beta down.

With the safety checks on, X-Plane still crashes when something goes wrong – but the bodies and wreckage are all a lot closer to the scene of the crime, and the evidence left around is in much better shape.

One of the side effects of the safety builds is that they catch “harmless” coding mistakes – (harmless in quotes – the bug might seem harmless but who knows if that will always be true). XSquawkBox now quits the sim with an ugly alert box because it reads off the end of a piece of the airplane data structure via the plugin system. This hasn’t hurt things in the past, but it’s not really correct. Beta 5 should fix the underlying problem, letting you run XSquawkBox again. (The fix will be in X-Plane, not XSquawkBox.)

Posted in Development by | Comments Off on A Slow Motion Car Crash

Lego Brick Code

When Sergio first proposed generic instruments, his model was “lego bricks”. The idea was to provide a number of very basic parts for panel makers and let panel makers mix and match. The result would be huge flexibility for airplane authors without code bloat.

The problem with non-generic instruments is that there is such a huge variety of behavior among airplanes…if Plane-Maker were to have options for every possible plane, the “special equipment” screen would require 3000 tabs and be completely unusable. Hence the need for a smaller unit of modeling: the lego brick.

The prop disc is the first feature I have done that is meant to be used only by a plugin, e.g. “lego brick” code. The X-Plane systems code sometimes suffers from the same “code bloat” problem as the instruments: a ton of very specific, very tweaky behaviors that interact in strange ways and become very difficult to manage. It’s not that the systems code is bad code – it’s that the scope of the problem is simply too large. That is, you can’t expect X-Plane to cleanly simulate the systems of every airplane ever in a ton of detail through an a la carte menu of check-boxes.

The idea of the prop disc is: someone (LR or otherwise) can write a plugin that encodes a certain style of prop disc. That plugin can then be picked up and moved around like a generic instrument between planes (perhaps with a corresponding text file to control it).

If someone else comes up with a different/better prop-disc algorithm, compatibility isn’t an issue…that person writes a new prop disc plugin and the airplane author selects the one desired. Think of it as sort of a portable flight model that stays with your plane.

So we win in three ways:

  • Anyone can write the prop disc algorithm, not just LR.
  • The code lives with the plane, to avoid compatibility problems.
  • More than one plugin can exist, giving authors an a la carte menu.

That’s the theory at least.

Posted in Aircraft, Development by | 2 Comments

The Will to Rewrite

FSBreak interviewed Austin last week….it’s an interesting listen and they cover a lot of ground. A few comments on Laminar’s approach to developing software:

That Code Stinks!

Austin is absolutely correct that we (LR) write better software because neither of us are shy about telling the other when a piece of code stinks. But I think Austin deserves the credit for creating this environment. An “ego-free” zone where people can criticize each other honestly and freely is a rare and valuable thing, in many domains, not just music.

When I first came to LR, Austin created this environment by responding positively to feedback, no matter how, um, honest. When I first came to LR 100% of the code was written by him and 0% by me. Thus if I was going to say “this piece of code really needs to be different”, it was going to be Austin to either run with it or try to defend his previous work.

To his credit, Austin ran with it, 100% of the time. I can’t think of a single time that he didn’t come down on the side of “let’s make X-Plane better”. That set the tone for the environment we have now: one that is data driven, regardless of who the original author is.

I would say this to any programmer who faces a harsh critique of code: good programmers write bad code! I have rewritten the culling code (the code that decides whether an OBJ really needs to be drawn*) perhaps four times now in the last five years. Each time I rewrote the code, it was a big improvement. But that doesn’t make the original code a mistake – the previous iterations were still improvements in their day. Programming is an iterative process. It is possible to write code that is both good and valuable to the company and going to need to be torn out a year later.

A Rewrite Is Not A Compatibility Break

Austin also points to the constant rewriting of X-Plane as a source of performance. This is true too – Austin has a zero tolerance policy toward old crufty code. If we know the code has gotten ugly and we know what we would do to make the code clean, we do that, immediately, without delay. Why would you ever put off fixing old code?

Having worked like this for a while, I am now amazed at the extent to which other organizations (including ones I have worked in) are willing to put off cleaning up code organization problems.

Simply put, software companies make money by changing code, and the cost is how long the changes take. If code is organized to make changing it slower, this fundamentally affects the financial viability of the company! (And the longer the code is left messy, the more difficult it will be to clean up later.)

But I must also point out one critical detail: rewriting the code doesn’t mean breaking compatibility! Consider the OBJ engine, which has been rewritten more times than I care to remember. It still loads OBJ2 files from X-Plane 620.

When we rework a section of the sim, we make sure that the structure of the code exactly matches what we are working on now (rather than what we were working on two years ago) so that new development fits into the existing code well. But it is not necessary to drop pieces of the code to achieve that. I would describe this “refactoring” as straightening a curvy highway so you can drive faster. If the highway went from LA to San Francisco, it still will – just in less time.

In fact, I think the issue of compatibility in X-Plane’s flight model has a lot more to do with whether the goal is to emulate reality or past results. This debate is orthoganal to refactoring code on a regular basis.

* Since OBJs are expensive to draw and there are a huge number of OBJs in a scenery tile, the decision about whether to draw an OBJ is really important to performance. Make bad decisions, you hurt fps. Spend too long debating what to draw, you also hurt fps!

Posted in Development by | 4 Comments

To Copy Or To Reference

In designing interfaces for building planes, writing plugins, etc. one of the main design questions that keeps coming up is: to copy or to reference? Should authors simply refer to an art asset, piece of data, or code in order to utilize it, or should the author copy a snapshot into the custom add-on. There isn’t one right answer. Here are the main considerations.

Performance and Efficiency

One of the obvious considerations is efficiency: in some cases we might be able to provide better performance when an art asset is referred from a common source.

For example, in some cases X-Plane will consolidate VRAM use based on actual files, so a library object is loaded once no matter how many packages use it, but is loaded many times if a package copies it.

(In other cases X-Plane will actually merge multiple copies of a resource – referencing is only a win in some cases.)

An indirect consideration: if an art asset is provided by Laminar Research and is used by reference, then a new update can provide a new, better optimized art asset – see below.

Dependencies and Contracts

When someone uses an art asset, algorithm, etc. by reference, it creates an implicit contract by the provider of the asset by reference to not change the properties of the asset. By comparison, when the asset is copied, the contract is only to support the format that the asset is encoded in.

This is the main reason why I am often against providing new assets by reference, whether it is a new dataref, texture, etc. Often I will simply send a user a snippet of code, rather than making X-Plane’s version available via a dataref. The idea is that copying does not create a new interface (and thus a new “contract”) between X-Plane and the add-on.

Copyright and Legal Issues

For historical reasons, the US legal system describes the privileges of intellectual property owners by regulating the act of copying. (To say that this is a bit quaint in the digital age doesn’t even scratch the surface, but that’s a rant for another post.) The result of this particular regulation of copying (but not of referencing) is that the decision to provide an asset by copy vs. reference has legal implications. If the author does not want to go through licensing, referencing may be the only option.

Posted in Development, File Formats by | 2 Comments

X-Plane 930 Performance and Crashes

I have received a number of emails bringing up crashes and performance problems in the X-Plane 930 betas – some of the writers are concerned that 930 might be a lame patch, going final with crashes and lousy performance.

To assuage this concern, let me make a few comments on where we are in the beta process, the likely future schedule, and the problems themselves.
The Schedule
X-Plane 930 has been an absurdly long beta. Going into the beta I had the mindset that we should take the beta slowly to have time to discover driver bugs on a wide variety of hardware – why rush and miss something?
I think we took this too far. To run a “slow” beta we have run other development simultaneous to the beta, but that in turn has stretched the beta to epic lengths.
We are starting to try to clamp down and close out the beta now, but it is going to get interrupted again. Austin and I will be traveling to attend the X-Plane conference in France, and from there we will spend two weeks working with Sergio in Italy. Given how rarely we go to Europe, we cannot pass up the opportunity to work with Sergio in person – we have a few problems in the sim where getting the three of us in one room is the best course of action.
Unfortunately our internet connectivity during the trip will be limited, and we can only bring some of our equipment, so closing out the beta while on the road is really not an option. Thus there will be yet another beta delay. Hopefully when we return, we can close the beta out for good.
Performance Problems
I have seen a number of emails regarding framerate with 930. A few notes on framerate and betas:
I try to save framerate for last in a beta. Most performance problems have two possible causes.
  1. We communicate with the video card driver in a way that is fast on our systems but astoundingly slow on other systems. We discover this from slow performance in a particular piece of the code on other hardware.
  2. The new beta does something new that is more expensive than what the old build did, and users have not figured out how to (or do not have a way to) turn this more expensive option off.

The solution to case 1 is to use another driver call; the solution to case 2 is to make sure the rendering options provide a way to turn the feature off. (We simply cannot guarantee that a new, nicer looking feature run without a fps penalty – we can only give you a choice between better visuals and faster fps.)

Either way, framerate work tends to be the last thing on my beta list for this reason: other bug fixes may cause framerate problems, typically in category 1 – that is, a bug fixes makes use of a new driver call that we find out has hurt performance. Thus I try to do all performance fixes at the end of beta when we won’t be adding new code.
This means that in practice, I have spent nearly zero time looking at performance. I am just starting that process this week, so it will be a little bit before I find problems.
Unfortunately often performance problems manifest only in the hardware I do not own – despite having a pile of computers in my office (a pile that seems to grow deeper and less manageable every year) there are just a ton of systems out there. So a lot of the performance bugs will get fixed by users trying experiments and reporting back to me – a slow process despite some of the really great efforts by our users.
Crashes
Crashes sometimes are manifestations of gross code defects, but often they fall into the category of driver problems too. I will be working to piece together the puzzle of strange behavior over the next few weeks; usually the solution is to not do some action that we thought was legal but fails in some hardware cases.
Don’t Panic
As always, my final message regarding the beta is: don’t panic. When it gets quiet over the next few weeks, it is because of travel, and even once Austin and I are back in the office, it will be slightly slow going to piece together problems on hardware other than our own.
Posted in Development, News by | Comments Off on X-Plane 930 Performance and Crashes

ATTR_light_level vs. Generic Instruments

Propsman caught something:

…is modifying the value of a batch of ATTR_light_level tris comparable [performance-wise] with toggling the state of a backlit generic instrument? Instinct tells me that you must have the latter more streamlined than the former, but maybe not?

He is right: in the current implementation, ATTR_light_level is probably a bit more expensive than using generic instruments. This may not be true in the future though.
  • The generic instrument code is pretty tight.
  • Right now ATTR_light_level sometimes has to adjust shaders, which can be expensive.
  • In the future, ATTR_light_level has the potential to be very heavily optimized, while the generic instrument code will always be CPU based.

But to put it in perspective, all instrument drawing is slow compared to scenery drawing – in the scenery world we draw 50,000 triangles of identical OpenGL state in a row, and modern cards do that very, very well.  In the panel, we have to put in a lot of CPU time to figure out how to draw each quad or tri-strip.  Fortunately you probably don’t have 50,000 individually programmed flashing lights in your panel.  Heck – there’s “only” 3608 datarefs published by the sim.

Perhaps other questions are important when picking ATTR_light_level vs. panel texture:
  • Which is more useful: to be able to have several variant images and variant images that are not “lights” (this is only possible by generics) or the ability to vary the light level gradually and not just have on or off (this is only possible with ATTR_light_level)?
  • Which is simpler to author given the rest of the panel?

In other words, it’s all pretty “slow”, but fortunately “slow” isn’t that slow.  If your light has to blink, you may want to pick what looks best and is straightforward to author.

Posted in Aircraft, Aircraft & Modeling, Cockpits, Development, Modeling by | 3 Comments

Datarefs Vs. Commands IV: Duplication

In my previous posts I have tried to explain the difference between commands and datarefs, and when you might use each.  To review:

  • A dataref represents information. You can always read it, and you might be able to change it.
  • A command represents an action.  You can always invoke the action, but you can’t tell if it worked without looking at a dataref.

So…why is there so much overlap and duplication?

Dataref Vs. Dataref
There is duplication in the datarefs because we don’t delete old datarefs when we add newer, improved ones. The old datarefs stay in place to keep old plugins working. Here are a few reasons why we’ve added new datarefs:
  • The cockpit2/ and flightmodel2/ sections were added as a new, simpler, easier to use interface for authors in version 9.  (Read more here and here and here.)
  • In some cases, the old dataref was a bit-field while the new one is a simple integer. While plugins can use bitfields, modelers cannot animate using bit fields.
  • In some cases, the old dataref did not represent a clean view of the data. Some old datarefs exposed X-Plane internal structures that are not appropriate for long-term use.

To see this in action, let’s look at the autopilot.  How many ways are there to set the autopilot mode?

  1. sim/cockpit/autopilot/heading_mode. This is the original heading mode, and it is marked deprecated, because it exposes a bunch of internal X-Plane autopilot values.
  2. sim/cockpit/autopilot/autopilot_state. This is the ideal autopilot dataref for plugins. It provides all functions, but since it is a bit-field it is not useful for authors.
  3. sim/cockpit2/autopilot/heading_mode. This is a clone of the original heading_mode into the cockpit2 domain. Honestly I am not sure how it got there – I know it was me who put it there, but it sure is a dumb idea; the original dataref is deprecated, so it was stupid of me to duplicate it!
  4. sim/cockpit2/autopilot/heading_state. This is coming in 930 and provides a heading-state enum set appropriate for authors…basically an enum that matches the two heading bits of the autopilot_state dataref that programmers were using.

How do you sort through this? Three rules of thumb:

  • Try to use sim/cockpit2 and sim/flightmodel2 when possible.
  • More recent datarefs are usually better.
  • Use the most useful dataref you can find.
Commands Vs. Commands
Sometimes there is some duplication of commands, e.g.
sim/engines/carb_heat_on                           Carb heat on.
sim/engines/carb_heat_off                          Carb heat off.
sim/engines/carb_heat_toggle                       Carb heat toggle.
Here it’s a lot more obvious why there are multiple commands: they affect the carb heat in multiple ways. Typically this is done because commands are mapped to joysticks and other USB hardware; some hardware generates a button press when a command is toggled, but some hardware generates two commands, one for the off and one for the on position.
The rule of thumb is: use the command that gives you the action you want.
Commands Vs. Datarefs
Very often there will be a command and a writable dataref.  Typically we need them both:
  • The command is needed to let users set up their joystick and keyboard.
  • The dataref predates version 9 – writing it was the only way to invoke an action.

Newer datarefs are more likely to be read-only, as we put new “changing the sim” functionality into commands.  To go back to our autopilot example, we have on command: sim/autopilot/heading that lets us arm heading mode.  This command is probably preferable to any of the datarefs for changing the autopilot state.

My previous post discusses writing to a dataref. vs. actuating a command in more detail.
Posted in Aircraft, Development, Modeling by | 4 Comments

Datarefs Vs. Commands III: What Is My command Doing?

It turns out that understanding what a command is doing gets really complicated.
The key idea to untangling it all is this:
  • Commands have duration, and that duration is the amount of time you “hold down” the button or key that actuates the command.
  • Not all commands do things for the entire duration.
An example will clarify this:
  • When you press and hold down the ‘p’ key to pause the sim, the sim pauses (or unpauses) instantly the moment you press the p key.  Holding the p key down for a long time does not change this.  Pause is a “momentary” command.
  • You have to keep the starter button/key held down for a few seconds to start an engine. If you press it and release it, the starter motor will only run for a fraction of a second, which is not enough time to start an aircraft engine.  Engine start is a “duration” command.
Virtual Datarefs
A “virtual dataref” isn’t really a dataref at all – it’s a string you can enter into an OBJ or generic instrument that looks like a dataref, but actually is something else.  There is one “set” of virtual datarefs in X-Plane right now.
In X-Plane, you can enter

CMND=some/command/name

into a generic instrument or obj animation – this creates a “virtual dataref” around the command’s “activation status”.  The virtual dataref acts like a read-only integer-type dataref whose value is 0 if the command is not being pressed right now and 1 if it is.
For example, if you animate a push button using CMND=sim/starters/engage_starter_1 (key framing the animation to be “out” when the virtual dataref is 0 and 1 when it is in) then you will have a button that appears to be pressed whenever the starters are engaged.  This will happen no matter how the starter is engaged – your animation will happen whether the user presses a joystick button, holds down a key, clicks on a manipulator, or a plugin runs the command.
Basically, virtual datarefs that provide “activation status” of commands exist so that you can animate the buttons in your virtual cockpit to match what the user is doing with the mouse, keyboard, etc.  These datarefs are read-only; use trigger generic instruments and command manipulators to actually run the command.
For Programmers
In that last section I pointed out that a virtual dataref is not a real dataref at least 3 times. Why am I harping on this?  Well, programmers, you cannot use XPLMFindDataRef to access virtual datarefs yourself.  Sorry.
Virtual datarefs exist to give authors of OBJs and panels access to command activation status, something they would not normally have.
Plugin programmers don’t need this – if you are programming a plugin you simply use XPLMRegisterCommandHandler and you will be told when the command is being actuated and released.  Using a command handler is a lot more efficient than reading a dataref because you will receive a call only when the command is pressed, instead of having to check the dataref value every frame.  If you need to monitor a lot of commands, the callbacks are a lot more efficient.
Command Activation Is Not The Same As System Activation
Let’s go back to the case of the “pause” command and review.  Here’s what we know about the pause command.
  • The command sim/operation/pause_toggle will change the sim’s pause state.  The instant this command is pressed, the sim will pause (if it is runnning) or unpause (if it is paused).
  • Holding down the sim/operation/pause_toggle command has no effect beyond its initial press. Hold it down for an hour, it doesn’t matter.
  • The virtual dataref CMND=sim/operation/pause_toggle tells you if the pause command is being held down at any instant.
Here’s what we know about the pause dataref.
  • The dataref sim/time/paused is 1 if the sim is paused, 0 if it is not.
  • This dataref cannot be written!
So here’s what I mean when I say: command activation is not the same as system activation.
  • CMND=sim/operation/pause_toggle tells you if the pause button is being held down.
  • sim/time/paused tells you if the sim is actually paused or not.
  • They are simply not the same!
This becomes important when you start to model the buttons in airplanes.  Take for example an autopilot button for altitude hold.  In many planes, the button can be pushed in, and the moment you do, the altitude hold “arm” light will turn on.  Keep the button held in and it doesn’t have any more effect.  Altitude hold arm is a momentary command, but it has a system status indicator light.
I receive a number of questions about how to model this – and the answer is: take advantage of the fact that command activation (is the button pushed in) and system activation (is the light on) are not the same.
  • You would use a read-only dataref for the autopilot state to turn on the indicator light.  (There are two ways to do this: use ATTR_light_level to turn a _LIT texture on and off, or use panel texture and map a generic instrument like a rotary or an annunciator.)
  • You would use a command to make the button work.  Probably you’d use a command manipulator on the button mesh.
  • You would key frame the button’s animation based on the virtual dataref wrapped around the command you are using with the manipulator.
The result will be a button that lights up when the AP is armed but pushes in while it is being pressed (whether via the mouse in the 3-d cockpit or a joystick button press or a keyboard button press).
In my final post, I’ll comment on how much overlap there is between datarefs and commands.
Posted in Aircraft & Modeling, Development, Modeling by | Comments Off on Datarefs Vs. Commands III: What Is My command Doing?

Datarefs Vs. Commands II: Which One Should I Use?

There is a lot of overlap between the datarefs and commands; very often there is both a dataref (telling information about some part of the sim) and a command (which takes action to change some part of the sim).  Which should you use?
Here are some general guidelines:
  • If you want to set up a joystick or keyboard, you have to use a command. The joystick and keyboard configuration dialog box lets you associate actions with a keystroke or button press, not information!
  • If you need to show the status of a system (E.g. “is the landing gear down”) use a dataref. I will cover this issue in more detail in part 3, but basically only datarefs show you information.
The ambiguous case is whether to use a dataref write or a command to change a system when both exist.
  • If there is a command that exactly does what you want to do, prefer the command over the dataref.  For example, it is better to arm the autopilot using the commands than the datarefs.  Changing the autopilot state often involves changing a lot of variables at once in complex ways.  When you issue the command, that work is done for you, correctly, every time.
  • If the command is not really suitable for your purpose, use a dataref.  For example, to change the engine throttle position, do not use the command sim/engines/throttle_up to move it up “a little bit.”  Use the dataref sim/cockpit2/engine/actuators/throttle_ratio to set the throttle to the precise position you want.  The throttle-up command exists so that users with no joystick or mouse wheel can fly with the keyboard by pressing the F1-F2 keys (bound to throttle-up, throttle-down).  It is not meant to precisely control the throttle position!
(I will discuss why there are so much overlap between commands and datarefs in part 4.)
Posted in Aircraft, Development, Modeling by | Comments Off on Datarefs Vs. Commands II: Which One Should I Use?

DataRefs Vs. Commands I: What’s The Difference

What is the difference between a dataref and a command? They serve different purposes in X-Plane, but it’s easy to get them confused, especially because the names can look so similar. If you only take one thing away from this comparison, it should be:

  • Datarefs are information.
  • Commands are actions.

Datarefs

A dataref is a single bit of published information. For example, the user’s indicated airspeed, as seen by the pilot, is a dataref, stored in:

sim/cockpit2/gauges/indicators/airspeed_kts_pilot

Datarefs have names that do not change. Datarefs made available by X-Plane start with sim/ while datarefs made available by plugins start with another prefix. Datarefs have been in X-Plane since the release of the plugin system in version 6.70.

You can always read a dataref, but sometimes you can change it. Trying to change a dataref usually has one of three actions:

  • If the dataref is not writable at all, nothing happens.
  • If the dataref is writable, it will change.
  • Sometimes a dataref may be writable, but only after changing some other sim configuration. For example, you can only “write” to the control surface deflection datarefs after setting the control surface override dataref to 1. (If you don’t set this override, X-Plane will constantly write its own ideas of the control surface positions to the control surface datarefs and your changes will be lost.)

You can read and write datarefs:

Commands

A command is an action that the sim can take on your behalf. For example, the command

sim/autopilot/altitude_arm

arms the autopilot for altitude hold.

Like datarefs, commands have permanent names, starting with sim/ for X-Plane or other prefixes for plugins. Commands have been available in X-Plane since version 9.0.

You can always actuate a command, but there is no guarantee that it will do anything. For example, the engine starter command won’t start the engine if the plane has electrical starters and the battery is dead.

You can use commands by:

Plugins

Plugins can add both new datarefs and new commands to the sim. Plugins can also change the behavior of all built-in sim commands, and can change the information in some datarefs.

Where Do I Find Datarefs And Commands

X-Plane’s default commands and datarefs are listed in the text files Commands.txt and Datarefs.txt in the Resources/plugins folder. (Note: providing the command list is new to X-Plane 930.) The dataref list is also available on the X-Plane SDK Wiki.

Up next: when should I use a command and when should I use a dataref?
Posted in Aircraft & Modeling, Development, File Formats, Modeling, Panels, Scenery by | Comments Off on DataRefs Vs. Commands I: What’s The Difference