Page 1 of 1

Canvas performance is costly if I clear() and draw on it again?

Posted: Sat Feb 15, 2020 6:31 pm
by cazura
Hi, I want to know a little more of Canvas performance. I know that creating new canvas is something you do only once. But what if I need to update it? If I put all the "set canvas/clear/draw" operations in a function and call it when it needs to be updated, is it bad?

I have elements that don't move, like menus and backgrounds stuff, BUT their opacity can change. So for example: If the player free a new option in the game, the option that was with a low opacity and inacessible now has the full opacity since it is available.

So I would update the canvas the moment the player actives this option. This would cut a lot of my loops inside the draw/update calls.

EDIT: I would also like to know my limits in case of it being not costly. In which point would be too far call these canvas updates constantly?

Re: Canvas performance is costly if I clear() and draw on it again?

Posted: Sat Feb 15, 2020 6:40 pm
by zorg
If you have a canvas for just the GUI/menu elements, then you can do a love.graphics.setColor before you draw that canvas to the screen, setting the opacity of the whole canvas' contents.

That said, setting, clearing and drawing to a canvas is NOT any more costly than what löve already does to the window itself, clearing it every frame, plus whatever drawing commands you call in love.draw on it. Creating a new canvas is what's costly, as in, do not call love.graphics.newCanvas every frame; if you're not doing that, you're fine. :3

Re: Canvas performance is costly if I clear() and draw on it again?

Posted: Sat Feb 15, 2020 6:44 pm
by cazura
zorg wrote: Sat Feb 15, 2020 6:40 pm If you have a canvas for just the GUI/menu elements, then you can do a love.graphics.setColor before you draw that canvas to the screen, setting the opacity of the whole canvas' contents.

That said, setting, clearing and drawing to a canvas is NOT any more costly than what löve already does to the window itself, clearing it every frame, plus whatever drawing commands you call in love.draw on it. Creating a new canvas is what's costly, as in, do not call love.graphics.newCanvas every frame; if you're not doing that, you're fine. :3
I see, thank you!

The thing is that I'm using only one canvas for all the menus, but the opacity is for individuals elements. Having a canvas for each individual element is not a good thing, is it?

Re: Canvas performance is costly if I clear() and draw on it again?

Posted: Sat Feb 15, 2020 7:44 pm
by MrFariator
Each individual element might be a bit much, depending on how many you have. If it's only from few to ten canvases, that should be fine. Any more than that and it'll depend on how many canvas switches etc you are doing per frame. Just monitor and see if any notable performance penalties incur, and do any optimizations as necessary.

For reference, I use about 8~11 canvases at most at any one time in my project, and it trucks along fine. Of course, I try my best at making the draw calls sequential in that it doesn't have swap back and forth between canvases, shaders, textures or some such too much.

Re: Canvas performance is costly if I clear() and draw on it again?

Posted: Sat Feb 15, 2020 9:16 pm
by raidho36
Rendering to (an RGB8) canvas has the same performance impact as rendering directly to the screen. What causes graphics slowdowns is draw call saturation, that is your GPU driver can't push any more draw commands to the GPU per second. It happens to be a pretty low number so a whole slew of techniques were developed specifically to reduce draw call count. The #1 technique you should care about is draw batching, because it by default incorporates a lot of other techniques. Not only does batching reduces the number of draw calls needed to render the entire batch to 1, it also forces not using GPU commands that incur draw call overhead such as texture or shader switching. LOVE has automatic batching but it's not the best in terms of performance - manual batching does better - and it doesn't stop you from doing silly things like alternating the current texture between each sprite in a render queue. The #2 technique is overdraw reduction which is a collection of different basic techniques, but you're unlikely to be at the point where that's a problem. The idea being that you avoid rendering blank pixels, such as by creating a sprite mesh that tightly wraps your sprite. In 2d games that's not usually possible but if it is, no blending + depth testing is enabled with reverse order rendering such that background pixels obscured by the foreground pixels never get rendered.