Cannot force a canvas refresh in javascript - javascript

I am trying to get a game to refresh canvas regularly with a main loop comprising a function to replay a screen and a function to have the computer calculate a move (if it is its turn). The player can select a move 1-9 and then, if the computer has not gone since the player last made a move, it will calculate its move using a very deep tree. The computer move takes several seconds to make its move. Despite having the canvas update before the computer makes a move, it doesn't ever get refreshed until after the computer has gone, meaning both the player and the computer move are shown simultaneously rather than sequentially. What can I do to ensure the canvas is updated every 100 milliseconds and not just after when the computer has calculated its move?
function playGame() {
function doKeyDown(evt) {
console.log(evt.keyCode)
if (evt.keyCode > 48 && evt.keyCode < 58) {
game.makeMove(evt.keyCode-48); // 1-9 are user actions
}
}
function mainLoop(ctx, game, board) {
board.showBoard(ctx); // display board
game.makeMove(0); // zero is computer move
}
Canvas.canvas = document.getElementById("myCanvas");
let game = new Game();
let board = new Board(game);
window.addEventListener( "keydown", doKeyDown, true);
Canvas.ctx = Canvas.canvas.getContext('2d');
setInterval(() => {mainLoop(Canvas.ctx, game, board)}, 100);
};
document.addEventListener('DOMContentLoaded', playGame);

There are a few things that can definitely help you with ensuring your canvas refreshes when you expect.
move computationally intensive tasks into Web Workers.
utilize window.requestAnimationFrame() instead of setInterval() for rendering.
Web Workers
Web Workers are great for moving computationally intensive tasks into; the MDN documentation for Web Workers states that, "The worker thread can perform tasks without interfering with the user interface." This will allow the computer's move to be calculated without blocking the rendering thread.
For more information on Web Workers see: Web Workers (MDN Web Docs)
window.requestAnimationFrame()
The window.requestAnimationFrame() method is the best current method to achieve animations with. Essentially it causes the browser to execute the provided callback just before the next repaint. This is an improvement over the previous setTimeout() and setInterval() methods as it only calls the callback just before the browser repaint, in other words, it reduces unnecessary computations that can be caused by using setTimeout() and setInterval().
For more information on window.requestAnimationFrame() see: window.requestAnimationFrame() (MDN Web Docs)
For a nice short article on why to choose window.requestAnimationFrame() over setTimeout() and setInterval() see this article by Matt West: Efficient Animations with requestAnimationFrame
Working Example:
I have put together a small working example using codesandbox.io; it uses Web Workers and requestAnimationFrame() as I have described. Note that it uses a timer in place of a computationally intensive task, it uses a 5 second timer to simulate a computer move, and a 1 second timer to simulate a player move.
Code Sandbox: Web Worker & requestAnimationFrame() Example

Related

What is the meaning of frame in requestAnimationFrame in JavaScript?

I am having hard time understanding what are frames in JavaScript. Is frame a data structure? Is it frames as in FPS or refresh rate? Is it a fixed-time slice of window like preemptive scheduling? Also, it the same article it says:
rAFs aren’t throttled for you if they take too long to execute.
What does this means?
I understand how setInterval can cause performance issues when callbacks are long running by basically pilling up too many callback in the queue to execute. Also, What is the relation of frame with event loop of call stack/thread of execution?
Every code which is dedicated to an animation should be executed with requestAnimationFrame. When you say requestAnimationFrame that means: as soon as a frame is ready to be rendered, execute the callback (which should move or transform elements based on the timestamp parameter), and then render the frame. That allows the code which is dedicated to the animation to be run exactly at the same rate than the screen framerate.
The CPU consumption of the animation is then adjusted to what the screen can display.
An usual pattern is to call requestAnimationFrame recursively:
function render(timestamp) {
// Move and transform things
requestAnimationFrame(render);
}
requestAnimationFrame(render);

animation callback architecture and time measuring when using HTLM5 Canvas?

I'm doing some animation with Canvas now, and will be preparing a system for the artists to use to make interactive animations. I'll be using my own timeline as the scenes will be created from some declarative non-js input. My question is: what's the right way to handle the per frame callback and time measurement? In audio (my real-time background), the rule is that there should be only only one master callback method called by the audio system, and any other objects register with it somehow. And all time calculations are done by counting sample ticks of this callback so there is one and only one true clock source (no asking the system clock for anything, just count samples). I assumed this is what I should do in my canvas app but I'm seeing examples in books and sites where multiple objects use requestAnimationFrame, and then check the frame rate by using date objects to measure elapsed time. Am I off base in thinking one master callback is still the most elegant way to go? And can I rely on measuring time in frame ticks assuming I'm getting really 60fps if using requestAnimationFrame?
Your instinct is valid...route all your animation through one requestAnimationFrame loop to keep your animations well coordinated.
The current version of requestAnimationFrame in modern browsers automatically receives a highly accurate timestamp parameter based on the performance object. That timestamp is accurate to 1/1000th of a millisecond.
You cannot rely on counting the number of calls ("ticks") to the animation loop. The loop will be deferred if the prior loop's animation code has not completed or if the system is busy. Therefore, you are not guaranteed 60fps. You are guaranteed the browsers best efforts to get you 60fps.
Bottom line: requestAnimationFrame is not guarenteed to be called at 60fps intervals so you are left with 2 basic animation alternatives:
Use the timestamp to calculate an elaped time and position your objects based on elapsed time.
Increment a counter with each call to the animation loop and postion your objects based on the counter.

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 :)

Properly handling timing for HTML5 canvas engine

I'm working on a multiple projectile simulator for a college project and I'm wondering how to best setup timing in JavaScript rendering to a HTML5 canvas
I'm using an Euler integrator setup for physics and accuracy is very important for this project. The rendering is very bare bones
My question is how to best setup the timing for all this.
Right now I have:
The physics and other logic running in a function that loops using setTimeout() with a fixed time step
The rendering in another function that loops using a requestAnimationFrame() call (flexible time step)
These two loops run sort of simultaneously (I know JavaScript doesn't really support threads without Web Workers) but I don't want the rendering (currently running at a much higher FPS than needed) to be unnecessarily 'stealing' CPU cycles from the physics simulation, if you see what I mean.
Given that physics accuracy is most important here how would you recommend setting up the timing system? (Maybe using Web Workers would be useful here but I havent seen this used in other engines)
Thanks!
I'd suggest that you don't try to 'multithread' unless you're actually doing it, and even then, I wouldn't necessarily recommend it.
The best way to keep everything in synch is to have a single thread of execution. A single setTimeout loop of about 33ms seems to work ok for my games.
Also, in my experience at least, setTimeout offers a much more aesthetic experience than setInterval or requestAnimationFrame. With setInterval, Javascript tries to hard to 'catch up' when frames are delivered late, which makes animation frames inconsistent. With requestAnimationFrame, frames are skipped to ensure a smooth running game, which actually makes things harder, because your users aren't entirely sure their view is up to date at any given second.
One way would be to set an interval for processing physics, and once per x frames, render everything.
var physicsTime;
var renderFrequency;
var frameCount;
setInterval(function(){updateStuff()},physicsTime);
then in updateStuff()
function updateStuff(){
frameCount ++;
if (frameCount >= renderFrequency){
frameCount -= renderFrequency;
render();
}
physics();
}

Categories