You.i Engine One Performance: Overdraw

John Cassidy
John Cassidy
You.i Engine One_Overdraw_thumbnail

You.i Engine One is a cross-platform SDK and rendering engine that utilizes C++ or React Native and Adobe After Effects to create single codebase applications across a large number of supported platforms.

Since the Engine is responsible for rendering, we need to discuss how your application is rendered when you write your application, and ways that you can proactively prevent performance hiccups by being aware of a concept called Overdraw.

Painter’s Algorithm

You.i Engine One_Overdraw_painters

You.i Engine One renders using the Painter’s Algorithm. This means it draws one layer at a time, starting at the back and moving towards the front. The result is that some areas of the screen, or canvas, are drawn over multiple times. When this happens, we say that this area has been overdrawn. Each time an area is overdrawn, it increases the average amount of overdraw for the entire screen.

If your screen has significant overdraw, it can reduce the speed at which your screen renders and this will impact the performance of your application by making your app appear jittery, as the frames per second (FPS) will be reduced during transitions or animations.

How to Observe Overdraw

While running a debug build, the debug panel is available to you in the following ways:

macOS/iOS/Android:
triple click (press) the top left of app or F3

PS4/XBoxOne:
Click down the right trigger

AndroidTV/FireTV/tvOS/Tizen:
Triple click the play button on remote

If any of these fail (because a remote doesn’t have a play button), you can use a variation of the konami code:

up up down down left right left right select

You.i Engine One_Overdraw_debug panel

Turning on the option to View Overdraw will change your application to display it tinted with a bunch of different colours, and also add a small number at the top of the screen that indicates the average overdraw for the current screen.

This average value is important as we are striving for a value of < 2.5 in order to minimize the impact on navigation, animations, and general performance. This is typically more evident on lower-end devices, but you can debug overdraw on any platform you like.

You.i Engine One_Overdraw sample

The following breakdown represents what the different colours indicate:

White: drawn zero or one times (no overdraw)

Blue: drawn twice (overdrawn once)

Green: drawn three times (overdrawn twice)

Light Red: drawn four times (overdrawn thrice)

Dark Red and shades of Purple: drawn five or more times (overdrawn four or more times)

Scene Tree Representation

Regardless if you create a screen with JSX or After Effects Compositions, the representation in the Scene Tree is what matters. Remember, each JSX component (and each layer in an After Effects Composition) map to a You.i Engine One Counterpart which builds up the Scene Tree in order to represent what the engine understands as the structure of the application.

Constructing a Screen in JSX

The following code sample generates a screen where various View’s are overlaid on top of one another with flex.

const Container = () => {
  return (
    <View style={{ flex: 1, backgroundColor: 'white' }}>
      { /* 0.0 overdraw */}
      <View style={{ flex: 1, backgroundColor: 'white' }}>
        { /* 1.0 overdraw. Draws entire screen for second time. */}
        <View style={{ flex: 1, backgroundColor: 'transparent' }}>
          { /* 1.0 overdraw. no additional drawing here. */}
        </View>
        <View style={{ flex: 1, backgroundColor: 'white' }}>
          { /* 1.5 overdraw. Draws half the screen one more time */}
          <View style={{ flex: 1, backgroundColor: 'white' }}>
            { /* 2.0 overdraw. Draws half the screen again. */}
            <View style={{ flex: 1, backgroundColor: 'transparent' }}>
              { /* 2.0 overdraw, does nt add to overdraw */}
            </View>
            <View style={{ flex: 1, backgroundColor: 'white' }}>
              { /* ~2.2 overdraw, draws half of half the screen again */}
            </View>
          </View>
        </View>
      </View>
    </View>  
  );
}

Note that a number of these views have a transparent background. When the background does not have a colour, it is marked as transparent (via backgroundColor or opacity value) it will not count towards overdraw as the engine knows to ignore it.

Constructing a screen with AE Composition

A simple After Effects Compositions where white solids are overlaid in a similar manner would construct a Scene Tree representation identical to the JSX implementation above.

You.i Engine One_Overdraw_scene tree

Scene Tree representation

In both of the above scenarios, the result is a very boring white screen that isn’t worth showing. However, if we enable our debug panel to show overdraw, we can see what is happening at the engine rendering level:

You.i Engine One_Overdraw_white box

Looking at this construction, it’s easy to see where moderate improvements could be made to reduce the overdraw. You will still have some overdraw, and that itself is not bad, but we want to limit the average number on the screen as much as possible to ensure it doesn’t impact performance.

Common areas of improvement

Removing placeholder images

Many applications will use placeholder items to represent images that will soon be present. They are either in the process of loading, or they will start to load when the user reaches a certain threshold when navigating the list.

When the image loads, a common mistake is not not remove the background of the underlying view that was acting as a placeholder. In this case, the placeholder was a <View/> with a background colour and an overlaid <Text /> that simply said “Placeholder”.

You.i Engine One_Overdraw_placeholder

On the left, the image has been loaded in overtop of the placeholder (a common tactic in AE Compositions) and the placeholder was not removed. On the right, it was removed (or hidden). The result is less overdraw on the right.

When working with AE Compositions and images, you may define an ImageSet timeline that will play when the image is ready. This is typically used to fade in an image, but we can also use it to fade out any placeholder layer we no longer need to be visible.

 

You.i Engine One_Overdraw_fade out

The same can be achieved in JSX by either replacing the underlying component (trade-off is that you are destroying/creating new views) or simply hiding them with opacity style property.

Removing unnecessary backgrounds

In addition to views and screens that you create yourself, a common situation where you might experience overdraw without realizing it is when you use libraries such as react-navigation with default settings.

When creating a StackNavigator, configuration options are available to set defaults for all cards being used in that Stack Navigator. One of the abilities is to set the background style of the Card itself and another more hidden configuration is the container style of the transition Container.

Setting both of these to an opaque value will result in an overdraw value of 1 for just that Card. I typically will make the card style transparent, and set the transition container to have a background (so you can see the background sliding in). This is typically the same colour for each screen, so it makes sense to set it in one particular place.

  
const RootStack = createStackNavigator(
  {
    // list of screens
  },
  {
    headerMode: "none",
    // set this to transparent if you want to rely on the value below
    transparentCard: true,
    transitionConfig: (transitionProps, prevTransitionProps, isModal) => {
      const defaultConfig = StackViewTransitionConfigs.defaultTransitionConfig(
        transitionProps,
        prevTransitionProps,
        isModal
      );
      return {
        ...defaultConfig,
        containerStyle: {
          // or set to transparent to give individual screens control
          backgroundColor: DEFAULT_BACKGROUND_COLOR
        }
      };
    }
  }
);

Additionally, it’s important to check other parent <View/> to see if they are also setting a background style that isn’t even being shown. For example, the <View /> that wraps the Stack Navigator likely does not need to have a background set.

Knowing is half the battle…

Overdraw is a concept that once you are aware it exists—and aware of what you can do to limit its impact—you will start to see it everything. It is a simple and straightforward performance enhancement that will ensure unnecessary background styles are not contributing to performance issues in your application.

Here’s something similar we think you’ll enjoy.