8

Question: Why does my CPU register ~30% when blur is applied versus ~6% when no blur is applied to an animated object?

Details:

I have a set of randomly generated items on a page that have a CSS animation assigned (in a CSS file) and randomly generated values for width, height, and importantly, blur, applied inline.

CSS file styles looks like:

animation-name: rise;
animation-fill-mode: forwards;
animation-timing-function: linear;
animation-iteration-count: 1;
-webkit-backface-visibility: hidden;
-webkit-perspective: 1000;
-webkit-transform: translate3d(0,0,0);

transform: translateZ(0);

width, height and blur are applied inline via style attribute.

<div class="foo" style="width:99px;height:99px;
                        filter:blur(2px);
                        -webkit-filter:blur(2px) opacity(0.918866247870028);
                        -moz-filter:blur(2px) opacity(0.918866247870028);
                        -o-filter:blur(2px) opacity(0.918866247870028);
                        -ms-filter:blur(2px) opacity(0.918866247870028);"></div>

With the blur enabled my CPU usage is ~30%. When I disable the blur, CPU usage goes down to ~6%.

What's happening here? Is chrome only able to GPU accelerate when no blur is applied? If so, why?

Update 1:

The animation rise looks as follows:

@keyframes rise {
    0% {
        transform: translateY(0px);
    }
    100% {
        transform: translateY(-1000px);
    }
}
Jamie Dixon
  • 53,019
  • 19
  • 125
  • 162
  • Irrelevant, but you have a typo in `filter:blur(2)px` – Chris Feb 09 '16 at 13:55
  • Good spot Chris. Thanks. – Jamie Dixon Feb 09 '16 at 13:57
  • 2
    I'm surprised. I would expect a high CPU usage when blur is used and **NOT** hardware accelerated. Blur is an expensive operation. Have you checked in the dev tools with the `show layer borders` setting under `rendering` that it is on the GPU? – Colin Bacon Feb 09 '16 at 14:21
  • with `show layer borders` turned on I see each animated object with its own border. I'm not familiar with this tool. Since they have their own layers, does this mean they're being hardware accelerated? – Jamie Dixon Feb 09 '16 at 14:40
  • I see that there is 23MB GPU Memory used when blur is turned on and 20.6MB GPU Memory used when blur is off. Is this a good indicator that the GPU is being used in both cases? – Jamie Dixon Feb 09 '16 at 14:48
  • @JamieDixon Sounds like it. I always use `show layer borders` for a quick check as it adds a mustard coloured square around elements that are layered (see https://developer.chrome.com/devtools/docs/rendering-settings). If an element has it's own layer then it is on the GPU – Colin Bacon Feb 09 '16 at 15:26
  • @ColinBacon I get a mustard border around one element on the page but the animated pieces have a blue border. Is that significant? – Jamie Dixon Feb 09 '16 at 15:33
  • @JamieDixon I'm not entirely sure why it is blue for your blur. If you were to replace it with a `box-shadow` for example if would probably be mustard. Given that it has boxed the element, it suggests it is on the GPU. Would be interesting to know if the colour change has any other meaning to it. Also worth a read http://www.html5rocks.com/en/tutorials/speed/layers/ – Colin Bacon Feb 09 '16 at 15:41
  • Could you update with which properties you are animating as well? – Emil Feb 09 '16 at 19:24
  • Hi @Emil. The property that's being animated is `transform: translateY(0)` to `transform: translateY(-1000px)`. I'll add this to my question also. – Jamie Dixon Feb 09 '16 at 20:06
  • Blur is indeed an expensive operation, did you compare the CPU usage with different amounts of blur? – xpy Feb 11 '16 at 18:21
  • Hi @xpy. I'm generating ~70 items on the page and each one has a random amount of blur applied (calculated at runtime). I'm yet to see any differences between re-generations. – Jamie Dixon Feb 14 '16 at 12:39
  • Basically, creating a blur is a processor intensive operation, especially in animation. If your hardware can multi-task with a graphics accelerator this helps, but numerous memory read-writes will still be needed. – Arif Burhan Mar 19 '16 at 17:48

2 Answers2

2

I don’t think the blur is actually causing your issues, it just seems to make it more noticeable than before. The problem is that the transform: translateY in your animation is overwriting the transform: translateZ(0) you’re using to force GPU acceleration.

This is a timeline recording for the the code you’re running right now, notice how there’s all this activity on the main and raster threads:

enter image description here

Now compare this to a recording where I applied will-change: transform to the .foo:

enter image description here

No activity on the main and raster whatsoever.

There’s two steps to applying this fix:

  1. Apply will-change: transform to .foo. This will let the browser know you intend to change that property and have it render that element on the GPU to account for this.

  2. No versions of Edge and IE support will-change at the moment. Therefore we’ll use transform: translate3d(0, -1000px, 0); in the animation to force GPU acceleration. Note this is a hack, so we’ll detect support for will-change and use transform: translateY in browsers that support it.

Final code:

@keyframes rise {
    0% {
        transform: translate3d(0, 0, 0);
    }
    100% {
        transform: translate3d(0, 1000px, 0);
  }
}

@supports (will-change: transform) {
  @keyframes rise {
      0% {
          transform: translateY(0px);
      }
      100% {
          transform: translateY(1000px);
    }
  }
}

div {
  width: 100px;
  height: 100px;
  background: #f00;
  animation: rise forwards 2s linear infinite;
  will-change: transform;
}

See here for a working version: http://jsbin.com/mosuvikoto/edit?html,css,output

Mattijs
  • 56
  • 7
-2

Don't blur it in inline styles. Put your blur in the style file.

Zasha
  • 56
  • 1
  • 13