I'm working on a game with JavaScript using Electron.js. I'm using the HTML <canvas>
element with 2d
context as renderer. At some point, I've noticed that the game runs quite slow (less than 30 FPS).
Every frame, a piece of code is run by requestAnimationFrame()
. I ran it through a profiler and it showed that my code is fine (takes around 2ms per frame) and that page repaints take much longer than I would expect (sometimes it's more than 30ms per paint).
Since the game renderer is too complex, I can't provide a full example, but here's a bit of my code:
// Set up the canvas
let r = document.getElementById("render");
let ctx = r.getContext("2d", {
alpha:0,
willReadFrequently:true
});
// Set up offscreen canvas
let offR = new OffscreenCanvas(1920, 1080);
let offCtx = offR.getContext("2d", {
willReadFrequently: true
});
// Set canvas size
r.width = 1920;
r.height = 1080;
function drawVoxes() {
for(let vx of voxes) {
// If not empty, draw its texture
if(vx.value != 0) {
offCtx.drawImage( dataobj.textures.tiles[vx.value - 1], vx.rX, vx.rY, vx.width, vx.height );
}
}
}
function renderFrame() {
// fpsTicker.tick();
// Clear canvases
ctx.clearRect(0, 0, r.width, r.height);
offCtx.clearRect(0, 0, r.width, r.height);
// Draw background
ctx.drawImage(buf, 0, 0);
// Draw grid
drawVoxes();
// Apply to the main canvas
ctx.drawImage(offR, 0, 0);
// Set up for the next frame
requestAnimationFrame(renderFrame);
}
requestAnimationFrame(renderFrame);
buf
is an OffscreenCanvas
object,voxes
is an array of custom helper objects,dataobj
is an object that stores all the map data.I hope this example is enough for you to understand.
Why is this happening? Is it normal? And what can I do to lower the paint times?
EDIT: The only element on-screen is that single <canvas>
for rendering.
Disabling the willReadFrequently
canvas context flag fixed the issue and paints do not take 30ms anymore.