How to get the target fps of requestAnimationFrame? - javascript

I have an animation loop run by requestAnimationFrame.
On my computer, the time between frames obtained this way are more or less 16.667ms corresponding to 60fps. However, https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame states that it doesn't necessarily run at a fixed speed and may try to match the device screen refresh rate which could be 90 or 120 or more these days.
Now what I want to do is to measure the time between frames and simplify the animation on low performance devices if the hardware can't keep up, in pseudocode:
if (elapsed_frame_time > (1000 / magical_function_to_get_the_target_fps_of_requestAnimationFrame()) {
animation.particles *= 0.9;
}
I suppose I could just measure it over a few empty requestAnimationFrame ticks to get the approximate nominal time but is there anything in the standard library that would just tell me what the interval or fps should be?

No there is nothing that let us know the "optimal" frequency of requestAnimationFrame (rAF).
Even measuring it by checking a few rounds is not an exact science. You may very well be measuring while an other app is eating all the available process of the device, your user may be scrolling the page which may have dramatic influence on rAF, you will definitely have outliers and it will be near impossible to tell between a 59.9Hz monitor and a 60Hz one for instance.
So if you really have to go this route
Be sure to use an average FPS, based on a big enough sample and to ignore the first call (because browsers actually execute the callback directly from a non-animated document).
Check the callback's timestamp, since this will represent the time the monitor sent its V-Sync signal and shouldn't be influenced by other scripts on the page.
Probably wait at least a few dropped frames before intervening.
Remember that some users may have dual-monitor systems with various refresh-rates.
Expect some edge cases and browser bugs.

Related

WebGL/OpenGL: comparing the performance

For educational purposes I need to compare the performance of WebGL with OpenGL. I have two equivalent programs written in WebGL and OpenGL, now I need to take the frame rate of them and compare them.
In Javascript I use requestAnimationFrame to animate, and I noticed that it causes the frame rate to be always at 60 FPS, and it goes down only if I switch tab or window. On the other hand if I always call the render function recursively, the window freezes for obvious reasons.
This is how I am taking the FPS:
var stats = new Stats();
stats.domElement.style.position = 'absolute';
stats.domElement.style.left = '450px';
stats.domElement.style.top = '750px';
document.body.appendChild( stats.domElement );
setInterval( function () {
stats.begin();
stats.end();
}, 1000 / 60 );
var render= function() {
requestAnimationFrame(render);
renderer.render(scene,camera);
}
render();
Now the problem if having always the scene at 60 FPS is that I cannot actually compare it with the frame rate of OpenGL, since OpenGL redraws the scene only when it is somehow modified (for example if I rotate the object) and glutPostRedisplay() gets called.
So I guess if there is a way in WebGL to redraw the scene only when it is necessary, for example when the object is rotated or if some attributes in the shaders are changed.
You can't compare framerates directly across GPUs in WebGL by pushing frames. Rather you need to figure out how much work you can get done within a single frame.
So, basically pick some target framerate and then keep doing more and more work until you go over your target. When you've hit your target that's how much work you can do. You can compare that to some other machine or GPU using the same technique.
Some people will suggest using glFinish to check timing. Unfortunately that doesn't actually work because it stalls the graphics pipeline and that stalling itself is not something that normally happens in a real app. It would be like timing how fast a car can go from point A to point B but instead of starting long before A and ending long after B you slam on the brakes before you get to B and measure the time when you get to B. That time includes all the time it took to slow down which is different on every GPU and different between WebGL and OpenGL and even different for each browser. You have no way of knowing how much of the time spent is time spent slowing down and how much of it was spent doing the thing you actually wanted to measure.
So instead, you need to go full speed the entire time. Just like a car you'd accelerate to top speed before you got to point A and keep going top speed until after you pass B. The same way they time cars on qualifying laps.
You don't normally stall a GPU by slamming on the breaks (glFinish) so adding the stopping time to your timing measurements is irrelevant and doesn't give you useful info. Using glFinish you'd be timing drawing + stopping. If one GPU draws in 1 second and stops in 2 and another GPU draws in 2 seconds and stops in 1, your timing will say 3 seconds for both GPUs. But if you ran them without stopping one GPU would draw 3 things a second, the other GPU would only draw 1.5 things a second. One GPU is clearly faster but using glFinish you'd never know that.
Instead you run full speed by drawing as much as possible and then measure how much you were able to get done and maintain full speed.
Here's one example:
http://webglsamples.org/lots-o-objects/lots-o-objects-draw-elements.html
It basically draws each frame. If the frame rate was 60fps it draws 10 more objects the next frame. If the frame rate was less than 60fps it draws less.
Because browser timing is not perfect you might be to choose a slightly lower target like 57fps to find how fast it can go.
On top of that, WebGL and OpenGL really just talk to the GPU and the GPU does the real work. The work done by the GPU will take the exact same amount of time regardless of if WebGL asks the GPU to do it or OpenGL. The only difference is in the overhead of setting up the GPU. That means you really don't want to draw anything heavy. Ideally you'd draw almost nothing. Make your canvas 1x1 pixel, draw a single triangle, and check the timing (as in how many single triangles can you draw one triangle at a time in WebGL vs OpenGL at 60fps).
It gets even worse though. A real app will switch shaders, switch buffers, switch textures, update attributes and uniforms often. So, what are you timing? How many times you can call gl.drawBuffers at 60fps? How many times you can call gl.enable or gl.vertexAttribPointer or gl.uniform4fv at 60fps? Some combination? What's a reasonable combination? 10% calls to gl.verterAttribPointer + 5% calls to gl.bindBuffer + 10% calls to gl.uniform. The timing of those calls are the only things different between WebGL and OpenGL since ultimately they're talking to the same GPU and that GPU will run the same speed regardless.
You actually do not want to use framerate to compare these things because as you just mentioned you are artificially capped to 60 FPS due to VSYNC.
The number of frames presented will be capped by the swap buffer operation when VSYNC is employed and you want to factor that mess out of your performance measurement. What you should do is start a timer at the beginning of your frame, then at the end of the frame (just prior to your buffer swap) issue glFinish (...) and end the timer. Compare the number of milliseconds to draw (or whatever resolution your timer measures) instead of the number of frames drawn.
The correct solution is to use the ANGLE_timer_query extension when available.
Quoting from the specification:
OpenGL implementations have historically provided little to no useful
timing information. Applications can get some idea of timing by
reading timers on the CPU, but these timers are not synchronized with
the graphics rendering pipeline. Reading a CPU timer does not
guarantee the completion of a potentially large amount of graphics
work accumulated before the timer is read, and will thus produce
wildly inaccurate results. glFinish() can be used to determine when
previous rendering commands have been completed, but will idle the
graphics pipeline and adversely affect application performance.
This extension provides a query mechanism that can be used to
determine the amount of time it takes to fully complete a set of GL
commands, and without stalling the rendering pipeline. It uses the
query object mechanisms first introduced in the occlusion query
extension, which allow time intervals to be polled asynchronously by
the application.
(emphasis mine)

Html canvas 1600x1200 screen tearing

I've seen a couple of questions asking about this, but they're all over three years old and usually end by saying theres not much of a way around it yet, so im wondering if anything's changed.
I'm currently working on a game that draws onto a canvas using an interval that happens 60 times a second. It works great on my iphone and PC, which has a faily decent graphics card, but I'm now trying it on a Thinkcentre with intel i3 graphics, and I notice some huge screen tearing:
http://s21.postimg.org/h6c42hic7/tear.jpg - it's a little harder to notice as a still.
I was just wondering if there's any way to reduce that, or to easily enable vertical sync. If there isnt, is there somethingthat I could do in my windows 8 app port of the game?
Are you using requestAnimationFrame (RAF)? RAF will v-sync but setTimeout/setInterval will not.
http://msdn.microsoft.com/library/windows/apps/hh920765
Also, since 30fps is adequate for your users to see smooth motion, how about splitting your 60fps into 2 alternating parts:
"calculate/update" during one frame (no drawing)
and then do all the drawing in the next frame.
And, get to know Chrome's Timeline tool. This great little tool lets you analyze your code to discover where your code is taking the most time. Then refactor that part of your code for high performance.
[ Addition: More useful details about requestAnimationFrame ]
Canvas does not paint directly to the display screen. Instead, canvas "renders" to a temporary offscreen buffer. “Rendering” means the process of executing canvas commands to draw on the offscreen buffer. This offscreen buffer will be quickly drawn to the actual display screen when the next screen refresh occurs.
Tearing occurs when the offscreen rendering process is only partially complete when the offscreen buffer is drawn on the actual display screen during refresh.
setInterval does not attempt to coordinate rendering with screen refresh. So, using setInterval to control animation frames will occasionally produce tearing .
requestAnimationFrame (RAF) attempts to fix tearing by generating frames only between screen refreshes (a process called vertical synching). The typical display refreshes about 60 times per second (that’s every 16 milliseconds).
With requestAnimationFrame (RAF):
If the current frame is not fully rendered before the next refresh,
RAF will delay the painting of the current frame until the next screen refresh.
This delay reduces tearing.
So for you, RAF will likely help your tearing problem, but it also introduces another problem.
You must decide how to handle your physics processing:
Keep it in a separate process—like setInterval.
Move it into requestAnimationFrame.
Move it into web-workers (the work is done on a background thread separate from the UI thread).
Keep physics in a separate setInterval.
This is a bit like riding 2 trains with 1 leg on each—very difficult! You must be sure that all aspects of the physics are always in a valid state because you never know when RAF will read the physics to do rendering. You will probably have to create a “buffer” of your physics variables so they always are in a valid state.
Move physics into RAF:
If you can both calculate physics and render within the 16ms between refreshes, this solution is ideal. If not, your frame may be delayed until the next refresh cycle. This results in 30fps which is not terrible since the eye still perceives lucid motion at 30fps. Worst case is that the delay sometimes occurs and sometimes not—then your animation may appear jerky. So the key here is to spread the calculations as evenly as possible between refresh cycles.
Move physics into web workers
Javascript is single-threaded. Both the UI and calculations must run on this single thread. But you can use web workers which run physics on a separate thread. This frees up the UI thread to concentrate on rendering and painting. But you must coordinate the background physics with the foreground UI.
Good luck with your game :)

Canvas/Javascript periodic slow downs only at beginning

I've been having trouble using the canvas element and can't seem to locate the problem.
The slowdown happens every 5-15 seconds when the page is initially loaded. But, after tabbing over to facebook for a while and chatting with friends, it miraculousy stopped exhibiting slow downs.
My friends also see the periodic slowdowns and they use chrome/firefox
I have no idea what's happening! I'm reading up on memory leaks/heap profiling, but I'm having a hard time locating the problem.
I initially only had one ball bouncing around, but I decided to put in 1000 balls to try and test performance, sorry :P
EDIT1: Ok, I tried running the same code on Firefox(i've been using chrome) and the balls are moving significantly slower on firefox minus the horrible stutter I've been seeing on chrome... What's causing the browsers to use different speeds for the balls?
WARNING WARNING EPILEPSY WARNING Link to live demo
Here's the code
Because you are using request animation frame it will try to hit 60 fps, and if it can't then it will settle for 30 fps, until it can deliver 60 fps. So the slowdown is your canvas running at 30 fps, and the jump to 60 fps makes things seem to speed up.
The reason why you're only hitting 30 fps in the beginning can be varied. In my case my computer is plenty powerful but I've got multiple monitors and I just opened the example in a new window on a new monitor, I suspect my OS limits only 1 monitor at a time to 60 fps unless I'm full screened in a game that takes up all 3 monitors. But this is not your problem, I just use it as an example as to why you need to be profiling and running performance tests yourself on a variety of setups, because there are any number of things that can be causing performance problems.
One of the reasons you get a perceived "slow down" and "speed up" is because you're updating positions on a frame by frame basis, but the time in between frames varies from 33ms to 16ms depending on what the current frame rate is. It would be advisable to make all of your update functions use the delta time (or the elapsed time since the previous frame) as a measure of how much to update the positions.
What you have:
Ball.prototype.update = function() {
this.x += this.velocity.x;
this.y += this.velocity.y;
}
We want to include a delta time in here
Ball.prototype.update = function(deltaTime) {
this.x += this.velocity.x * deltaTime;
this.y += this.velocity.y * deltaTime;
}
The only difference here will be that you're going to have to express your velocity in relation to time. For example, your velocity will be expressed as 100 pixels per second, and your delta Time will be expressed in seconds as well (with a value of around .016 or .033)
This won't fix the 30 fps but it will make your balls move at a consistent speed. When you first load the page, the browser needs to load all the other scripts you're including, parse and evaluate them, and in some cases will fire off some Garbage Collection (as is the case with the included jQuery). If you don't need jQuery or other such additional files you can avoid including them.
More importantly, you don't have to start rendering full speed ahead as soon as the page loads. In the case of games, they'll have their own loading screens and title screens preceding actual game rendering that players won't be able to tell the difference between 30 fps and 60 fps on anyway.

Scheduling update "threads" in JS / WebGL

Currently, I am rendering WebGL content using requestAnimationFrame which runs at (ideally) 60 FPS. I'm also concurrently scheduling an "update" process, which handles AI, physics, and so on using setTimeout. I use the latter because I only really need to update objects roughly 30 times per second, and it's not really part of the draw sequence; it seemed like a good idea to save the remaining CPU for actual render passes, since most of my animations are fairly hardware intensive.
My question is one of best practices. setTimeout and setInterval are not particularly kind to battery life and CPU consumption, especially when the browser is not in focus. On the other hand, using requestAnimationFrame (or tying the updates directly into the existing render phase) will potentially enforce far more updates every second than are strictly necessary, and may stop updating altogether when the browser is not in focus or at other times the browser deems unnecessary for "animation".
What is the best course of action for updating, but not rendering content?
setTimeout and setInterval are not particularly kind to battery life and CPU consumption
Let's be honest: Neither is requestAnimationFrame. The difference is that RAF automatically turns off when you leave the tab. That behavior can be emulated with setTimeout if you use the Page Visibility API, though, so in reality the power consumption problems between the two are about on par if used intelligently.
Beyond that, though, setTimeout\Interval is perfectly appropriate for use in your case. The only thing that you may want to be aware of is that you'll be hard pressed to get it perfectly in sync with the render loop. You'll have cases where you may draw one too many times before your animation update hits, which can lead to minor stuttering. If you're rendering at 60hz and updating at 30hz it shouldn't be a big issue, but you'll want to be aware of it.
If staying perfectly in sync with the render loop is important to you, you could simply have a if(framecount % 2) { updateLogic(); } at the top of your RAF callback, which effectively limits your updates to 30hz (every other frame) and it's always in sync with the draw.

How to prevent a javascript stack overflow?

I've been building Conway's Life with javascript / jquery in order to run it in a browser Here. Chrome, Firefox and Opera or Safari do this pretty fast so preferably don't use IE for this. IE9 is ok though.
While generating the new generations of Life I am storing the previous generations in order to be able to walk back through the history. This works fine until a certain point when memory fills up, which makes the browser(tab) crash.
So my question is: how can I detect when memory is filling up? I am storing an array for each generation in an array which forms the history of generations. This takes massive amounts of memory which crashes the browser after a few thousands of generations, depending on available memory.
I am aware of the fact that javascript can't check the amount of available memory but there must be a way...
I doubt that there is a way to do it. Even if there is, it would probably be browser-specific. I can suggest a different way, though.
Instead of storing all the data for each generation, store snapshots taken every once in a while. Since the Conway's Game of Life is deterministic, you can easily re-generate future frames from a given snapshot. You'll probably want to keep a buffer of a few frames so that you can make rewinding nice and smooth.
In reality, this doesn't actually solve the problem, since you'll run out of space eventually. However, if you store every n frames, your application will last n times longer, which might just be long enough. I would recommend that you impose some hard limits on how far into the past you can rewind so that you have a cap on how much you have to store. Determine that how many frames that would be (10 minutes at 30 FPS = 18000 frames). Then, divide frames by how many frames you can store (profile various web browsers to figure this out) and that is the interval between snapshots you should use.
Dogbert pretty much nailed it. You can't know exactly how much available memory there is but you can know how potentially large your dataset will be.
So, take the size of each object stored in the array, multiply by array dimensions and that's the size of one iteration. Multiply that by the desired number of iterations to see how much space total it will take, and adjust accordingly.
Or, inspired by Travis, simply run the pattern in reverse from the last known array. It is deterministic after all.

Categories