Handling rendering ”device loss” with Starling


After Flash 11 brought the GPU accelerated 3D rendering with Stage3D it became necessary to handle the possible error conditions Direct3D and OpenGL developers are familiar with. You might expect Starling framework to take care of errors like “device loss” for you but unfortunately this is not the case. I’ll now briefly explain how to properly detect and handle the device loss so that your Flash application won’t crash.

Rendering “device loss” happens when the GPU hardware becomes unavailable to the application – for example when Windows operating system goes to lock screen [this doesn’t seem to happen with all the different Windows versions / hardware]. When a device loss happens, the current Context3D instance and all the buffers, textures and shader programs created with it are disposed. This means that calling any functions on them will throw an exception and crash the application if the exception is not caught.

Luckily the device loss is really easy to detect. Simply check the value of your Context3D instance’s driverInfo and if it is “Disposed” you’ll know the device loss has occurred and the context has been disposed. This check should be added in the beginning of Starling class’s render function and if you detect the context has been disposed simply return from the function immediately. Remember to check this condition also in your application’s enterFrame handler and return from there also if the context has been disposed. Trying to create any new Textures or calling functions that would modify the buffers for example in Image will also throw an exception.

After we have survived to device loss it’s time to get prepared for the new device creation. When the rendering device becomes available again, Flash runtime generates a new Context3D instance automatically and dispatches a CONTEXT3D_CREATE event. Starling is listening to this event but the handler function onContextCreated was not designed to handle more than one context creation so we need to modify it a little. In the beginning of the function set mContext to null and create a new Dictionary for mPrograms. Now Starling is running again with a valid context and shader programs but all the textures and vertex/index buffers are still invalid.

To handle the texture updating you should listen to the CONTEXT3D_CREATE event also outside Starling. If the event occurs the second time you need to reinitialize all the textures. The easiest way to achieve this is to add a function to Starling Texture classes for creating a new base texture and to have all the Texture instances managed with a single class. This manager should have the original bitmap / byte array data required for reinitalizing the textures available either in memory or on disk. By using centralized management like this you don’t need to create new Texture instances but you can continue using the existing ones no matter where they are and you also avoid all the changes to the actual application rendering logic.

The last step is to create new vertex and index buffers with the new context. One way to do this is to add a running id number for the contexts created in Starling. Whenever a new context is created this number is increased by one. Then in all the places where vertex and index buffers are used store this context id when the buffers are created and when you use the buffers check that the id the buffers were created for is the same as the current id. If they are not the same just create new buffers for the current context and store the new id.

After these modifications your Flash application should survive the device loss. The newer versions of operating systems and Flash player might become better not to lose the device but it’s always better safe than sorry.

Post a comment or leave a trackback: Trackback URL.

Comments

  • Daniel Sperl  On February 2, 2012 at 3:33 pm

    Finally, the latest version of Starling finally handles device loss automatically. Just call “Starling.handleContextLoss = true” before you create the Starling instance. (Current GitHub head revision.)

    • villekoskela  On February 2, 2012 at 10:50 pm

      Nice improvement. I’d consider moving the backup logic into ConcreteTexture class by adding there a backup method that takes the needed BitmapData as parameter. Also when the Texture gets disposed the backup’s BitmapData instance might need to be disposed especially if the Texture is generated with the static empty(…) function.

      • Daniel Sperl  On February 3, 2012 at 2:19 pm

        You’re perfectly right, Ville — that was a typical case of “avoid late night coding”, LOL. Now I’ve moved the restore logic into ConcreteTexture, which is the natural place for that. And thanks for the heads-up about the “Texture.empty” method, I overlooked that part. (Which proves: code reviews are a good thing! *g*)

Trackbacks

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: