85

I am moving 10,000 small div elements in a css3 experiment from the top of the browser viewport to the bottom. For this test I use 2 different approaches:

  1. With GPU acceleration using translate3D(x, y, z) or translateZ(0)
  2. No GPU acceleration by simply adjusting the top property in css

Using NO hardware-acceleration runs fairly smooth on Google Chrome.

If I enable hardware-acceleration performance becomes a lot worse. It's so bad the boxes aren't even spread out evenly anymore:

With GPU/Hardware acceleration:



Without GPU/Hardware acceleration:



Question

Why is that so? Shouldn't using the GPU improve performance?

Demo application

https://www.timo-ernst.net/misc/hwtest/

Source

https://github.com/valnub/hwtest

My hardware used for test

  • Apple Macbook Pro 15" 2015 Model
  • CPU 2,8 GHz Intel Core i7
  • 16 GB RAM
  • macOS Big Sur 11.2

Update (2014-11-13): Since this question is still attracting attention I'd like to point out that the problem itself still seems to exist although the mentioned stuttering might not be visible anymore in the provided demo on modern hardware. Older devices might still see performance issues.

*Update II (2021-02-17): The problem still persists but you will have to increase the number of boxes being moved in the demo based on the hardware used. I changed the UI of the demo app so you can now adjust the number of boxes moved to create a stuttering animation for your specific hardware. To replicate the issue I recommend to create enough boxes to see stuttering with GPU/hardware acceleration enabled. Then tick off the box and run the test again without acceleration. The animation should be smoother.

Timo Ernst
  • 15,243
  • 23
  • 104
  • 165
  • 9
    The real question is why some browsers want authors to resort to silly hacks like "null" transforms to activate hardware acceleration. Firefox defers to the GPU as much as possible, while IE chooses to ACCELERATE \_ALL\_ THE THINGS! But interesting question here nevertheless, as it seems to demonstrate that hacks like this can even backfire sometimes. – BoltClock Apr 09 '12 at 04:38
  • 2
    @BoltClock'saUnicorn Basically I agree with you. But hasn't it always been like this with cross-browser issues? :-) – Timo Ernst Apr 09 '12 at 15:38
  • 6
    I asked this question quite a while ago but I noticed now that the number of items moved seems to have a big impact on the problem. Moving few big objects is more performant than moving lots of small items when using 3D-acceleration because all the 3D-accelerated layers have to be transferred to the GPU and the way back. So even if the GPU does a good job, the transfer of many objects might be a problem so that using GPU acceleration might not be worth it. – Timo Ernst Mar 22 '13 at 12:53
  • 1
    I see no performance difference in the example on any browser and have voted to close as no longer reproducible. – Jason C Nov 11 '14 at 14:24
  • @JasonC I guess that depends on the computer that you use. On my 2010 Macbook Pro I still see significant stutter. So I increased the number of moving "boxes" by 2. You might see the performance decrease now. – Timo Ernst Nov 11 '14 at 21:12
  • 1
    @Timo Just checked on whatever the latest Firefox and Chrome are, and IE11, on Windows 7 64-bit, on a fairly old 2.3 GHz i5 Thinkpad with an nVidia 4200M, both options seem smooth to me. *shrug* – Jason C Nov 11 '14 at 22:04
  • 1
    Recommending this question remain open for historical reasons - just because it is fixed now on newer hardware and browsers doesn't mean it won't affect someone using older soft/hardware. Would be worth editing the question itself with a statement to indicate as much. – brandonscript Nov 12 '14 at 18:25
  • @remus Good idea, done. I also find mddw's answer very helpful if I run into performance issues in general. – Timo Ernst Nov 13 '14 at 09:32
  • your example code crashes firefox. – Codebeat May 05 '15 at 12:32
  • @Erwinus Tried on FF 35 on Windows 64-Bit and works fine. There's a chance that your computer runs out of memory though which can cause a crash due to many objects created in the test. – Timo Ernst May 06 '15 at 13:05
  • @Timo: Run it with FF 37, Win7-64bit, 16GB of RAM – Codebeat May 06 '15 at 19:54

6 Answers6

101

I always add :

-webkit-backface-visibility: hidden;
-webkit-perspective: 1000;

When working with 3d transform. Even "fake" 3D transforms. Experience tells me that these two lines always improve performances, especially on iPad but also on Chrome.

I did test on your exemple and, as far as I can tell, it works.

As for the "why" part of your question... I don't know. 3D transform are a young standard, so implementation is choppy. That's why it's a prefixed property : for beta testing. Someone could fill a bug report or a question and have the team investigate.

Edit per August 19th 2013:

There's regular activity on this answer, and I just lost an hour finding that IE10 also need this. So don't forget :

backface-visibility: hidden;
perspective: 1000;
Timo Ernst
  • 15,243
  • 23
  • 104
  • 165
mddw
  • 5,570
  • 1
  • 30
  • 32
  • Damn, you're right. Adding those two css attributes definitely fixes the problem. Do you know if that problem only occurs in webkit? – Timo Ernst Apr 13 '12 at 13:04
  • Mh, I checked on the definition of `-webkit-backface-visibility` and w3c says "The backface-visibility property defines whether or not an element should be visible when not facing the screen." http://www.w3schools.com/cssref/css3_pr_backface-visibility.asp Now, I think that this doesn't really fix the problem. It more looks like a "cheap trick" to remove the back of 3D objects from the render tree. It does make sense that removing the back will cause a performance boost. – Timo Ernst Apr 13 '12 at 13:09
  • Maybe using translateZ on a lot of objects without turning of backface makes it too heavy for the GPU. Maybe Firefox is smarter and turns off backface alone when Z=0 ? – mddw Apr 13 '12 at 15:51
  • 3
    I did another test. Basically the same as test #1 but this time I let the boxes also rotate around the z-axis via `-webkit-transform: rotateZ(360deg);` http://dl.dropbox.com/u/17844821/zeug/hwtest2.html - This time the hardware accelerated version is faster! If I remove rotation, hardware acceleration slows the animation down. If your theory is true then this shouldn't be working (because the only difference is that I added `rotateZ(360)`). On the other hand, maybe chrome is smart enough to realize that for a rotation around the Z-axis no redrawing of the backside of those tiles is required? – Timo Ernst Apr 13 '12 at 17:05
  • Yes, I suspect something like this, Chrome must infer the backside non consistently. It's only a hunch, it's been a while I wanted to look at the source to understand how exactly transitions are handled, so maybe it's the moment. – mddw Apr 14 '12 at 15:14
  • 1
    This is no longer the case in iOS6 :-( – Michael Mullany Sep 25 '12 at 04:39
  • Excellent point, I wanted to edit this answer when I read about it yesterday. I'll wait to see the exact changes. – mddw Sep 25 '12 at 08:06
  • 1
    I am not able to understand what is the reason behind using perspective: 1000. Is that a random value or it has to be the same? What if my element already has some perspective applied to it? – Nilesh Aug 23 '13 at 12:36
  • An old iOS version needed a perspective set for backface to work. Nowadays I think it's useless, but well, bad habits... moreover it lacks an unit, mandatory as per W3C rules. If you need a perspective, you're working in 3D, so this question does not apply. – mddw Aug 23 '13 at 15:07
  • 2
    @Timo Just a heads up, w3schools is not affiliated with the w3c: http://www.w3fools.com/ – Kyle Robinson Young May 20 '14 at 15:30
  • ``-webkit-transform: rotateZ(360deg)``?? This is incredible, incredible... man, all I wanted to do was to scale the screen. Then cue the horrible flickering and every other bug you could think of. – Agamemnus Aug 15 '14 at 19:03
  • 7
    you should add **where** to add these lines, not just a general "just add this.." myself I know where, but many wouldn't. – vsync Aug 21 '14 at 09:30
  • 1
    @mddw I can second that. Where do I need to add these lines? Do I add it in the definition of my animation class or do I specify it at each keyframe stage? – jezzipin Jan 27 '15 at 10:59
  • 4
    Add it to the parent of the elements you are animating. – mddw Jan 27 '15 at 11:07
  • i testet it now on my Android (A5) for testing a slide-navigation. It's a huge difference! Frame-rate increased from 8fps to 30fps. Thx – AppGeer Sep 21 '15 at 18:24
  • I don't really notice any performance increase. Doesn't translating a parent with many children count as *translating many elements*? – Alexander Derck Oct 13 '16 at 07:22
  • Several years later I realised that this is a great suggestion which improves performance but doesn't answer the actual question why the problem is happening at all. Therefore I accepted Dan's reply as it answers the question: https://stackoverflow.com/a/31040118/286149 – Timo Ernst Feb 17 '21 at 22:29
9

The reason animation was slower when you added the null transform hack (translateZ(0)) is that each null 3D transform creates a new layer. When there are too many of these layers, rendering performance suffers because the browser needs to send a lot of textures to the GPU.

The problem was noticed in 2013 on Apple's homepage, which abused the null transform hack. See http://wesleyhales.com/blog/2013/10/26/Jank-Busting-Apples-Home-Page/

The OP also correctly noticed the explanation in their comment:

Moving few big objects is more performant than moving lots of small items when using 3D-acceleration because all the 3D-accelerated layers have to be transferred to the GPU and the way back. So even if the GPU does a good job, the transfer of many objects might be a problem so that using GPU acceleration might not be worth it.

Community
  • 1
  • 1
Dan Dascalescu
  • 143,271
  • 52
  • 317
  • 404
  • 1
    I accepted this because it answers the question why the problem is actually happening. However, mddw is providing a great solution to the issue in his answer: https://stackoverflow.com/a/10133679/286149 – Timo Ernst Feb 17 '21 at 22:36
6

Interesting. I've tried playing with a few options in about:flags, specifically these ones:

GPU compositing on all pages Uses GPU-accelerated compositing on all pages, not just those that include GPU-accelerated layers.

GPU Accelerated Drawing Enable GPU accelerated drawing of page contents when compositing is enabled.

GPU Accelerated Canvas 2D Enables higher performance of canvas tags with a 2D context by rendering using Graphics Processor Unit (GPU) hardware.

Enabled those, tried it and failed miserably with the tickbox enabled (just like you did). But then I noticed yet another option:

FPS counter Shows a page's actual frame rate, in frames per second, when hardware acceleration is active.

Given the highlight in the flag description, I'd speculate that hardware acceleration was, in fact, on for me even without the ticked checkbox since I saw the FPS counter with the options above turned on!

TL;DR: hardware acceleration is, in the end, a user preference; forcing it with dummy translateZ(0) will introduce redundant processing overhead giving the appearance of lower performance.

Oleg
  • 24,465
  • 8
  • 61
  • 91
  • 2
    Well, then check this out. I did another test. Basically the same as test #1 but this time I additionally let the boxes rotate around their own axis by adding `-webkit-transform: rotateZ(360deg);` http://dl.dropbox.com/u/17844821/zeug/hwtest2.html - This time the hardware accelerated version is faster! If I remove the rotation, hardware acceleration slows the animation down. – Timo Ernst Apr 12 '12 at 15:01
  • @valmar: are you enabling the fps counter? In this new example I see it regardless of how I set the checkbox meaning that hardware acceleration is still forced. I guess your question boils down to "why is `translateZ(0)` slower than `rotateZ(360deg)`" – Oleg Apr 12 '12 at 22:56
  • Actually, no. `translateZ(0)` is ALWAYS active. It's actually required to trigger 3d acceleration. `rotateZ(360deg)` just additionally adds the rotation animation. So I'd say the question is: Why is the animation with 3D hardware acceleration smoother with `rotateZ(360deg)` than without? – Timo Ernst Apr 13 '12 at 12:52
  • 1
    can't believe it. Rotation of heavy images is faster without hardware acceleration... – ProblemsOfSumit Nov 06 '13 at 10:35
0

Check chrome://flags in chrome. It says

"When threaded compositing is enabled, accelerated CSS animations run on the compositing thread. However, there may be performance gains running with accelerated CSS animations, even without the compositor thread."

Lion
  • 965
  • 10
  • 21
0

My expericence is that GPUs aren't generally faster for all kind of graphics. For very "basic" graphics they can be slower.

You might have gotten different result if you were rotating an image - that's the kind of thing GPUs are good at

Also consider that translateZ(0) is an operation in 3 dimensions, while changing top or left is a 2 dimensional operation

sabof
  • 8,062
  • 4
  • 28
  • 52
  • Most likely its an implementation issue. GPUs are much faster for all graphics, as long as you implement it right ;) – scientiaesthete Apr 15 '12 at 23:26
  • 1
    `translateZ(0)` actually does nothing but "activate" 3D hardware acceleration. It's a hack but it works. When adding that css attribute, the selected html element as well as all child elements will get force-calculated by the GPU rather than CPU. – Timo Ernst Apr 16 '12 at 12:34
  • I don't know all the low-level implementation details. I had similar issues with QT - hardware acceleration slowing things down. I don't know at which point (or whether) the computer realizes that translateZ(0) can be ignored, and the transformation can be processed as movement in 2 dimensions. (No perspective, no anti-aliasing, no z += 0 for every pixel) – sabof Apr 16 '12 at 18:37
  • scientiaesthete, GPU is not faster for doing the math for *all* graphics, since it takes CPU effort to move the commands & memory to the GPU & GPU-memory. There is a breaking-point of complexity for that effort to become worth while. YMMV < prior assembly hand-optimizer here ;) – tomByrer Oct 25 '13 at 09:51
  • GPUs are much faster for the actual computation part. However, all currently available GPUs have pretty heavy setup phase before actual computation can start. For "simple" content, letting the CPU do all the rendering may be faster than GPU setup + GPU computation. A well implemented browser will automatically do the right choice and there's no way any random content author can do better. – Mikko Rantalainen Jul 11 '14 at 12:00
-2

I saw you two demo, I think I know the reason you confused:

  1. The animation elements Do not use the left or top to change the location, try to use the -webkit-transform;
  2. All child elements need to turn on hardware acceleration such as use translateZ () or translate3D;
  3. FPS measure animation fluency, your demo FPS on average only 20FPS.

Above, only a personal opinion, thank you!

Andrew Barber
  • 39,603
  • 20
  • 94
  • 123
  • Welcome to Stack Overflow! Please do not use signatures/taglines in your posts. Your user box counts as your signature, and you can use your profile to post any information about yourself you like. [FAQ on signatures/taglines](http://stackoverflow.com/faq#signatures) – Andrew Barber Jan 23 '13 at 04:09
  • 3
    I already explained why, and it's also mentioned why in the FAQ entry I linked to. You *already have* a signature - look to the right, where it shows your name and avatar picture. – Andrew Barber Jan 23 '13 at 04:17
  • 好吧,你“淫”了。不过还是很感谢,还不太熟悉“stackoverflow”的规则。 – 一丝冰凉 Jan 23 '13 at 04:19
  • 1
    You are welcome. Please also note that this is an English-only website. :) Your name is fine, but your posts should be done in English, please. – Andrew Barber Jan 23 '13 at 04:22
  • 4
    苦逼了,I don't speak english, please forgive me. – 一丝冰凉 Jan 23 '13 at 04:26