Force Hardware Acceleration with translate3d... Sometimes

Try the demo!

The last PhoneGap application that I developed had a feature that allowed you to drag an image around the screen so you could drop it in a folder or a trash can… you get the idea. The images were relatively large. Each image took up most of the display area of an iPad. The dragging animation worked by dynamically updating the -webkit-transform property with a translate3d value that followed a touch around the screen.

While testing the application I noticed that the image appeared to “stick” when a drag operation started. I could drag a short distance from the starting point of the pan gesture before the image snapped to the right location. When I dropped the image and started dragging again, I experienced the same stickiness. This was most noticeable on a first generation iPad (remember, always test on old hardware).

I found that by applying an identity translate3d to the image element in CSS, there was no delay at the start of a drag operation. For example:

.draggable-image {
  -webkit-transform: translate3d(0px,0px,0px);
}

Why does this work? And what are the performance implications?

This article explains the hardware accelerated rendering path in Chrome in a lot of detail. The web view powering an iOS or Android PhoneGap application may have a slightly different approach to hardware accelerated rendering, but hopefully it is close enough!

Allow me to grossly oversimplify the hardware accelerated rendering path for a moment…

When an element is rendered in hardware, the element and all of its children are first rendered to a bitmap, and then the bitmap is uploaded to the GPU as a texture. Once the texture is uploaded to the GPU, the element can be transformed very quickly. Whenever the element or its children need to be redrawn, the element must be re-rendered to a bitmap and uploaded to the GPU again.

It stands to reason that larger or more complex elements will take longer to render to a bitmap and subsequently upload to the GPU. To avoid this performance penalty, you can either:

  • make elements smaller or less complex, or
  • force elements into hardware acceleration as early as possible, and ensure they stay hardware accelerated.

If the latter is your only option, the simplest way to do this is to put an identity translate3d on the element. The tradeoff is that the element’s texture remains in VRAM for longer, and VRAM is limited on mobile devices. In my case, a smoother dragging transition was worth the cost of some extra VRAM.

One quick way to see this in action is to exceed the maximum texture size for a mobile device. When an element larger than the maximum texture size switches to hardware acceleration, you will see an ugly flicker and a sort of “blocking in” effect as the texture tiles comprising the element make their way to the GPU. By applying an identity translate3d in CSS, this ugly flicker will only happen once, provided the element does not change later on.

With smaller, less complex elements, you will see no noticeable performance penalty when switching between software and hardware rendering, so saving VRAM may be the better option. As with any piece of application performance advice, test it for yourself before blindly applying a rule!

comments powered by Disqus