Atomoco blog

keeping up with keeping up

4 notes

GPU memory management with hardware accelerated CSS transitions.

See that? That’s the difference that GPU hardware acceleration of CSS transitions can make on an iOS device. If you don’t know what CSS transitions are, you might want to stop reading now.

For those that are left, I won’t bore you with how CSS transitions can provide basic animations, or how they can be GPU hardware accelerated on iOS devices, which can make an incredibly low-powered platform like an iPad offer smoother animation than big desktops running javascript.

Instead I’ll run through how Bardot currently does the “next page” trick, and how I’m trying to improve it.

As a caveat, I’m just imparting what I’ve learnt through trial, error and Google - I wouldn’t count myself as an expert on this.

Bardot is built in “pages” and “spreads”. Pages are… er, pretty self explanatory, and spreads are the equivalent of opening a magazine spread (ie two or more pages facing each other). Bardot actually has three piles of spreads *, at any one time you see only one spread on-screen - in the “viewport”. Either side of the viewport are two other piles, and when you hit the “next page” button, the piles all shuffle along one direction or the other.

The mechanism for doing this on most modern browsers is simplicity itself. Spreads in each pile have a particular class (“.read”, “.active”, “.unread”) and to move them around means changing their class via javascript, CSS transitions and transforms do the rest for you. As an aside, that makes quick changes to the animation a doddle (Make it quicker? Tweak the CSS style. Add a 3D flip out movement? Tweak the CSS style).

That all looks fine on desktop browsers, but iOS devices need a bit more help. They’ve got pretty limited processing power, and extremely limited memory, which often ends up with low frame-rates, sudden disappearances, or giving the “tiling” effect you see in the video above. This is especially true when you’re creating something off-screen, then moving it into view (like we are here), because mobile devices are optimised to only deal with on-screen pixels to keep them lean and mean.

To get around that, we can hand off the “compositing” of certain elements to the 3D GPU chip in the iPad or iPhone, which is way more adept at flinging tiles around a screen. You can move an element to the GPU by adding a 3D CSS style to an object (some use “-webkit-transform:translateZ(0)”, others use “-webkit-transform:scale3d(1)”)

In the case of Bardot, I created a style class called “.zippy” with a transform of “translateZ(0)”. When a page-forward event occurs, the top of the “.unread” pile is changed to a class of “.active.zippy”, and the retreating spread is given a class of “.read.zippy”. So “.read” and “.active” are the classes that determine where the spreads move to, and “.zippy” is the class that adds a sprinkling of acceleration.

The question begs: “So why don’t we hand everything off to the GPU with 3D CSS?”. Well, the GPU is also really limited in the amount of memory it can handle, and the more you stuff into it, the more it stutters and you’re back to where you started. In Bardot, one of those spreads could be thousands of pixels in size, it doesn’t take many of those to really bung up a GPU.

The trick is memory management. In Bardot, only the “.zippy” spreads are hardware accelerated, and once a spread is moved off-page, the “.zippy” class is removed to reduce the load on the GPU.

The result is buttery smooth animations in both directions. Simples.

* Note:  I’ve tried building systems with a long continuous “conveyor belt” of pages in the past, and although the theory behind that is cleaner (moving a huge track of pages past the viewport), I find working in three piles is easier to manage, especially when you get into dealing with layouts that are many spreads long. A track would becomes tens thousands of pixels wide and you have to deal with big margin offset numbers. Not pretty.

  1. jalbertbowdenii reblogged this from atomoco
  2. sydlawrence reblogged this from atomoco
  3. ukd1 reblogged this from atomoco
  4. atomoco posted this