Any way to get canvases to be more efficient?

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
Before you make a thread asking for help, read this.
Sky_Render
Prole
Posts: 48
Joined: Fri Jul 05, 2019 2:59 am

Any way to get canvases to be more efficient?

Post by Sky_Render » Fri Feb 21, 2020 3:01 am

I'm currently trying to render quite a number of 2D layers with complex elements to them, and thus far canvases are definitely better than rendering direct-to-screen, but I'm still getting noticeable frame drops when I try to have more than about 20 layers on screen at once. Rendering the canvas to an image first actually reduced the FPS even worse (and made updates to layers take nearly three orders of magnitude longer). Ostensibly I could render a few of the layers on the same meta-layer and cut it down to around 15, but I would like to know if there's any other alternative that would work better than a canvas for this sort of thing.

User avatar
raidho36
Party member
Posts: 2063
Joined: Mon Jun 17, 2013 12:00 pm

Re: Any way to get canvases to be more efficient?

Post by raidho36 » Fri Feb 21, 2020 6:25 am

I believe the source of your problem is trying to issue a billion GPU draw calls per second, canvases have nothing to do with it. By "rendering to image" do you mean fetching ImageData from canvas? That transfers the entire texture contents from GPU to RAM, it's not a fast operation.

Sky_Render
Prole
Posts: 48
Joined: Fri Jul 05, 2019 2:59 am

Re: Any way to get canvases to be more efficient?

Post by Sky_Render » Fri Feb 21, 2020 7:28 am

raidho36 wrote:
Fri Feb 21, 2020 6:25 am
I believe the source of your problem is trying to issue a billion GPU draw calls per second, canvases have nothing to do with it. By "rendering to image" do you mean fetching ImageData from canvas? That transfers the entire texture contents from GPU to RAM, it's not a fast operation.
Then perhaps I need some advice on how to proceed here. The gist of it is: I'm using tilemaps that use multiple tilesets and I need to render around 14 layers per map (plus a few lighting and sprite layers, but they're actually very efficient compared to the tilemap layers!). These layers can all potentially get animation updates, but I resolved how to get that more efficient; nonetheless, it means that rendering multiple layers into one canvas isn't especially practical. What would be the best methodology for this? Any help is appreciated!

User avatar
raidho36
Party member
Posts: 2063
Joined: Mon Jun 17, 2013 12:00 pm

Re: Any way to get canvases to be more efficient?

Post by raidho36 » Fri Feb 21, 2020 7:41 am

Are you already using sprite batching? If not, do. Shove your entire tilemap collection into a single texture atlas. This will avoid breaking the batch for no reason. If you have too many tiles to fit in one maximum size texture then split them into fewest amount of render grouped (tiles that are rendered in uninterrupted sequence) textures otherwise; prioritize putting the most tiles in a single sheet over tidy and logical separation. Tweak your render order so that first you render all tiles from sheet A, then all tiles from sheet B etc. Put your sprites into the atlas as well to avoid breaking batches.

Sky_Render
Prole
Posts: 48
Joined: Fri Jul 05, 2019 2:59 am

Re: Any way to get canvases to be more efficient?

Post by Sky_Render » Fri Feb 21, 2020 3:02 pm

raidho36 wrote:
Fri Feb 21, 2020 7:41 am
Are you already using sprite batching? If not, do. Shove your entire tilemap collection into a single texture atlas. This will avoid breaking the batch for no reason. If you have too many tiles to fit in one maximum size texture then split them into fewest amount of render grouped (tiles that are rendered in uninterrupted sequence) textures otherwise; prioritize putting the most tiles in a single sheet over tidy and logical separation. Tweak your render order so that first you render all tiles from sheet A, then all tiles from sheet B etc. Put your sprites into the atlas as well to avoid breaking batches.
I am using a sprite atlas for the tile textures, yes. I'm not really sure how I can efficiently set it to render tiles only from a particular tileset first, however. It seems like that would add more steps than it saves, seeing as I'd have to have the engine assemble temporary tables of each tile to be rendered for each tileset. It seems like that could easily add steps to the process, in fact... I must be missing something here. Here's how I have it working right now: after it's resolved the current map and layer, it loops to check what tileset it's pulling from for the current tile and then draws that tile to the canvas.

User avatar
raidho36
Party member
Posts: 2063
Joined: Mon Jun 17, 2013 12:00 pm

Re: Any way to get canvases to be more efficient?

Post by raidho36 » Sat Feb 22, 2020 2:17 am

Well your argument patently makes no sense so I'll just make a general advice. GPU draw calls are at a premium and everything that will touch a GPU counts as at least 1 draw call. Switching a texture, switching a shader, updating shader uniforms, uploading a texture, downloading a texture, switching render target, rendering anything, and so on and so forth. Rendering tiles individually is a quick way to exhaust your draw call budget because you draw of thousands of them per frame, so this needs to be batched. Doing things like any of the listed above will break the batch and undo the benefits. The best way to avoid it is to batch them manually, then it's impossible to break batches by default.

Sky_Render
Prole
Posts: 48
Joined: Fri Jul 05, 2019 2:59 am

Re: Any way to get canvases to be more efficient?

Post by Sky_Render » Sat Feb 22, 2020 2:22 am

raidho36 wrote:
Sat Feb 22, 2020 2:17 am
Well your argument patently makes no sense so I'll just make a general advice. GPU draw calls are at a premium and everything that will touch a GPU counts as at least 1 draw call. Switching a texture, switching a shader, updating shader uniforms, uploading a texture, downloading a texture, switching render target, rendering anything, and so on and so forth. Rendering tiles individually is a quick way to exhaust your draw call budget because you draw of thousands of them per frame, so this needs to be batched. Doing things like any of the listed above will break the batch and undo the benefits. The best way to avoid it is to batch them manually, then it's impossible to break batches by default.
Here's the funny thing about that: I tried switching over to SpriteBatch objects today to see if that would help, and it was slower than my method. Massively slower: I could only draw about 10 layers with SpriteBatches before slowdown set in, and those layers could not contain any tiles from more than one tileset. Either I'm using SpriteBatch wrong somehow, or I've managed to find a more efficient alternative completely by accident. Either way, I am disappointed.

User avatar
raidho36
Party member
Posts: 2063
Joined: Mon Jun 17, 2013 12:00 pm

Re: Any way to get canvases to be more efficient?

Post by raidho36 » Sat Feb 22, 2020 2:40 am

Autobatching is enabled by default since version 11 but it's 20 to 50 percent slower than manual batching (for whatever reason). If your manual batching wasn't faster then yes it's because you're using it wrong. The idea of a batch is that you insert as many sprites into it as possible to render in one operation, saving draw call budget. Have you been trying to render sprites one at a time using a SpriteBatch as a middle type?

Sky_Render
Prole
Posts: 48
Joined: Fri Jul 05, 2019 2:59 am

Re: Any way to get canvases to be more efficient?

Post by Sky_Render » Sat Feb 22, 2020 3:32 am

raidho36 wrote:
Sat Feb 22, 2020 2:40 am
Autobatching is enabled by default since version 11 but it's 20 to 50 percent slower than manual batching (for whatever reason). If your manual batching wasn't faster then yes it's because you're using it wrong. The idea of a batch is that you insert as many sprites into it as possible to render in one operation, saving draw call budget. Have you been trying to render sprites one at a time using a SpriteBatch as a middle type?
Nope, the process goes like this: it reads the full tilemap and assembles the SpriteBatch from quads during love.load. It's left stored in memory and called as a single draw command in love.draw. Again, I can only get about 10 layers drawn using that method before lag sets in horribly, whereas the "draw to canvas once and render" method gives me around 15 to 20 tileset-count-agnostic layers before lag sets in.

Nelvin
Party member
Posts: 114
Joined: Mon Sep 12, 2016 7:52 am
Location: Germany

Re: Any way to get canvases to be more efficient?

Post by Nelvin » Sat Feb 22, 2020 10:05 am

It would help if you give us some numbers and more details about your canvas sizes and the nature of your game. Is it a single screen or a scrolling game (because you created your batches on load and did not change them anymore)? How many tiles per layer, size of the tiles, size of the tileset (i.e. number of tiles), how big are your canvases ...

Post Reply

Who is online

Users browsing this forum: Nelvin and 25 guests