On a Nexus 7, the Gangnam Style Doom demo through CocoonJS runs at a healthy 35 FPS. On an iPad 3, the same demo runs at 5 FPS!
My own project (using ThreeJS) runs at 50-60 FPS on a Nexus 7 and on a cheap $100 Android handset (Cubot P9), runs at 30FPS. On an iPad3, it runs at around 15 FPS.
Why so slow on the iPad? The iPad3 runs most 3D games just fine, nice and smooth.
My own tests seem to indicate this is related to the number of 3D objects,not the number of polygons e.g. 100 low-poly cubes (1200 polys) is slow, whereas one object with 6000 polygons runs fast.
I don't think this is a ThreeJS issue, as the Gangnam Doom demo uses PlayCanvas.
I'm surprised no one else has noticed this. Has anyone tested the Gangnam demo on iPad 4/Air?
Any thoughts appreciated.
As far as I know the iPhone/iPad does not have 3d acceleration yet. That is why you get low FPS. On three.js you can choose which renderer to use. Either the WebGLRenderer (when there is acceleration) or the CanvasRenderer (when there is no acceleration). Android on the other hand, does support 3D acceleration so the speed you are seeing has only to do with how fast/slow the device is.
Related
Background
While working on a complex full-screen 2D animation utilizing multiple <canvas> layers I found out a problem with Safari. The rendering performance drops sharply after the canvas gets bigger than exactly 3840x3840. I ran multiple tests (benchmark I wrote: https://codepen.io/kiler129/full/Exbgrqp) and obtained this peculiar graph:
(click for a readable full-size copy)
Data analysis
Steady 60 FPS/realtime is kept until 3840x3840, then it drops to unusable 2-25 FPS
There's a correlation between larger fill % (100% vs 20%) of the canvas and FPS, as well as larger number of draw calls per frame (d/f) and FPS -> nothing unusual here, it's pretty linear
Buffered canvases (drawing to off-screen & then copying) are way less performant for simple operations
Brave, and any other Chromium-based browsers, keep steady 60 FPS basically forever (even with screen-scaled 10000x10000 plane)
2018 iPad running Safari behaves identically to 2021 MBP with M1 Max, just a little bit slower overall
The 3840px is exactly 4K. While I have a 4K monitor disconnecting it and rebooting doesn't change the steep drop point (MBP has a 3456x2234 screen). Even assuming that the 4K resolution is cached somewhere this doesn't explain the same drop on the iPad which has nothing to do with 4K screens.
I also checked what actually takes time in Safari and it seems that the rendering to the screen and not the actual drawing on canvas is the culprit. That will explain why using buffering gives such bad results. The times for drawing are actually slower on Chromium-based browsers, yet the times are hardly correlated to anything:
Why such a large canvas?!
To avoid X-Y problem situation, I'm answering this ahead of time. I stumbled upon this issue in a real-world tests and then prepared the benchmark trying to eliminate all variables from the real-world application. 3840px is perfectly reasonable when used on HiDPI/"retina" displays; with x2 scaling it gives 1920px screen real estate which is quite normal. While the benchmark clips the viewport the real code doesn't (it doesn't seem to make a measurable difference).
Bug?
Is there anything I can do here, or this is a some sort of a limitation/bug of the WebKit/Safari? While testing the Safari doesn't crash but window becomes very unresponsive until the rendering is stopped.
The only solution I see is detecting FPS drop and disabling retina scaling on Safari.
I'm building a creative simulation in p5.js by employing double pendula. Here is the link to the stripped-down version of the code (I'm not sure it can be made smaller):
https://github.com/amzon-ex/amzon-ex.github.io/tree/master/dp-sketch-stripped
Here is where you can see the animation: https://amzon-ex.github.io/dp-sketch-stripped/dp-sketch.html
When I run this on my laptop (Windows 10, MS Edge 88) I get about 55-60 fps, which is what I want. However, when I run the same sketch on a mobile device (Android, Chrome 88) the performance is very poor and I hardly get 5-6 fps. I do not understand what is complicated about my code that contributes to such a poor performance. I have ran other kinds of p5.js sketches before on mobile and they've worked well.
Any insight is appreciated.
Since I have a few files in the project link I provided, here's a quick guide (there is absolutely no need to read everything):
sketch.js is the key file, which builds the animation. It takes an image, builds an array filled with brightness values from the image (array lumamap, in setup()). Then I draw trails for my pendula where the brightness of the trail at any pixel corresponds to the brightness value in lumamap.
dp-sketch.html is the HTML container for the p5 sketch.
libs/classydp.js houses the DoublePendulum class which describes a double pendulum object.
As I've found out with some help, the issue is tied to varying pixel density on different devices. As mobile devices have higher pixel density compared to desktops/laptops, my 500x500 canvas becomes much bigger on those displays, hence leading to many more pixels to render. Coupled with the fact that mobile processors are weaker in comparison to desktop processors, the lag/low framerate is expected.
This can be avoided by setting pixelDensity(1) in setup(); which avoids rendering larger canvases on dense-pixel devices.
For personal education I am trying to build a Pong implementation in JavaScript / HTML.
I have been reading up on rendering performance, but when I apply the theory in practice, it seems to fall short.
From my understanding, requestAnimationFrame should provide me with fluid stable 60 fps animation, given my logic and subsequent rendering can be completed within a 16 ms timeframe. In this case, each iteration takes between 1 - 2 ms and yet, I see my framerate jumps between 45 fps and 75 fps, occasionally producing "long frames".
I am running Chrome on OS X 10.12 on a Mac Mini (Late 2012).
I have tried using a canvas, I have tried a CSS animate approach and I have tried a top/left approach. I have tried Safari and I have tried incognito. However, the jank remains.
What am I missing?
For reference, here is my script (in CoffeeScript):
class window.PongGame
#launch: ->
window.pong = new PongGame()
pong.start()
constructor: ->
#ball_size = 32
#width = 640
#height = 480
#y = #height / 2
#x = 0
#yVel = 3
#xVel = 3
#ball = document.getElementById("pong_ball")
start: ->
requestAnimationFrame => #new_frame()
new_frame: ->
#handle_collisions()
#move_ball()
#animate()
requestAnimationFrame => #new_frame()
handle_collisions: ->
if (0 <= #x <= #width - #ball_size) is false
#xVel = -#xVel
if (0 < #y < #height - #ball_size) is false
#yVel = -#yVel
move_ball: ->
#x += #xVel
#y += #yVel
animate: ->
#ball.setAttribute("style", "transform: translate(#{#x}px, #{#y}px); width: #{#ball_size}px; height: #{#ball_size}px")
Jsfiddle: https://jsfiddle.net/nielsbuus/ptLk3ma0/2/
Update
I have tested my code on an older MacBook Pro (2011) and the framerate is almost stable - a lot closer to 60 fps fixed than my Mac Mini.
There are several fun facts to keep in mind, with regard to requestAnimationFrame performance in browsers...
Using the profiler affects the results. I'm working on a three.js based WebGL project where the integrated FPS counter reports a relatively steady 60fps. But, if I activate Chrome's timeline tool and measure my frame rendering times, the timeline shows the app dropping 4-6 frames per second, even when there is no code in the render loop at all.
The browser manages lots of other activities, and they can affect animation performance. Running my app in a long lived Firefox instance with lots of memory in use always gets worse performance than running it in a fresh instance. Streaming video in another tab in Chrome cuts the framerate for my app in another down to 30 FPS (probably because they are both contending for GPU time). Garbage collection can eat tons of time out of a frame budget, minimizing object allocations and GC is an important concern for complex apps with lots of animation.
In particular, when using Chrome's timeline tool as you are, be sure to enable JS Profiling, and expand the GPU activity band. Your code is probably well within the 16.6ms frame budget, but on my system a dropped frame is usually associated with heavy GPU activity.
My advice? Don't take the profiler's results as absolute or representative of real world performance, and make peace with browser animation performance being a bit of a roller coaster :).
You might also consider using the FPS counter developed for three.js (but usable anywhere I believe), which I presume has less of a distorting impact than the heavyweight profiling tools in modern browsers. Keeping it running in development can alert you to serious performance problems as you run into them.
I am developing a web application (JS/CSS/AngularJS) which is going to run on a touchscreen client.
As the application grows I run into a performance problem: I mentioned that the applicaion is not running with 60fps but 30 or something. Therefore I used the chrome built-in timeline tool to profile what's going on under the hood.
Okay - there are many long frames which limit the fps to ~30. The reason are the large GPU blocks (green) you can see in the screenshots).
Zoomed in:
It seems that the GPU is taking much time to... render? calculate? ...?
Unfortunally I don't have any further information what the GPU does in this time. There are some CSS effects and transforms but nothing really spectacular.
It's running on a Intel HD Graphics 530 (onboard) but I think is should even perform with 60fps on this one.
I'd like to know if there is any way to get further information what is slowing down the GPU that much and/or if there are any common CSS tricks to speed up my page. Or is there anything I can tweak at the GPU itself?
Thanks!
The Game is developed for windows 8 app store using HTML5 and JavaScript, CreateJS is also used for most the functions.The object which moves by incrementing coordinates works normally and with normal speed as expected when the laptop is on Battery, the moment laptop is plugged to power the animation picks up speed and overall all game looks as though its fast forwarded.
Any pointers for this behavior is much appreciated.
If you are using requestanimationframe to drive your game loop, then this would explain it.
This is adaptive based on power - running at 60fps on AC and 30fps on battery.
Details: http://blogs.msdn.com/b/ie/archive/2011/07/05/using-pc-hardware-more-efficiently-in-html5-new-web-performance-apis-part-1.aspx