Page 1 of 1

Scissor vs Canvas for offscreen optimization?

Posted: Tue Aug 13, 2019 5:42 pm
by rougan
Hi!

I have a tile map which can be moved about by the user, thereby parts of it coming and going off the screen. I'm currently using a spritebatch to draw the tiles, and am looking for the best way to prevent off-screen drawing.

My first thought was a canvas. As far as I understand, the two (relevant) benefical properties of canvases are:

1. Reduce draw calls by pre-rendering canvas.
2. Prevent wasteful offscreen drawing.

However- as the map will be moved around a lot, I'll need to frequently re-render the canvas contents. Even when re-rendering every frame, will using a canvas improve performance (like the case of clearing/readding to spritebatches)? Given these frequent re-renderings, will whacking in a love.graphics.setScissor instead provide similar performance enhancements?

Furthermore, is using spritebatches to draw to a canvas unecessary by virtue of the negligible performance difference? Is it a spritebatch OR canvas kinda deal?

So I guess my final question is: will a spritebatch+canvas be any more effecient than a spritebatch+setScissor in the situation above?

Thanks for any help! :awesome: (I'm finding this equally interesting and confusing lol)

Re: Scissor vs Canvas for offscreen optimization?

Posted: Tue Aug 13, 2019 6:12 pm
by raidho36
GPUs do offscreen culling by default. Drawing stuff than can't fit on the screen will not further impact performance.

Code: Select all

local img = love.graphics.newImage ( 'test.jpg' )

local mag = 0

function love.keypressed ( key, code )
	if code == 'up' then
		mag = mag + 1
	elseif code == 'down' then
		mag = mag - 1
	end
end

function love.draw ( )
	local t = love.timer.getTime ( )
	for i = 1, 1000 do
		love.graphics.draw ( img, 0, 0, 0, 2 ^ mag, 2 ^ mag )
	end
	love.graphics.print ( ( love.timer.getTime ( ) - t ) * 1000, 10, 10 )
	love.graphics.pring ( love.timer.getFPS ( ), 10, 30 )
	love.graphics.print ( 2 ^ mag, 10, 50 )
end
What you should worry about is culling down on the amount of draw calls - GPUs nor CPUs can guess whether or not the draw call will end up on screen to cancel it in beforehand. Some draw calls cannot be "cancelled" like this altogether - such as texture or shader switch. Simple frustum culling should do the job for your tiles. If they're placed on a grid, then you can render only visible tiles by iterating over the grid by computing min and max coordinates, rather loop over every tile in the map and check if it's within the camera view.

You shouldn't cache tiles like this. If your performance sucks that much, it'll still suck either way - when drawing all tiles every frame or when redrawing the cache - but instead of sucking all the time, it'll suck whenever the player tries to move but it runs fine otherwise, which feels worse. You can try caching large chunks of tiles and then render those megatiles like normal, bigger tiles. It'll run well most of the time but when the player reaches the boundary and new batch of chunks needs to be drawn, there will be a lag spike. Finally, you can make the entire map in photoshop whichever way you want it, and export it as 1024x1024 textures. With compression, that's 2 megabytes of VRAM per megatile, so any modern hardware should be able to store your entire level like this.

All that said, unless you're doing extreme amounts of layering and overdraw (like Factorio does) or some other ridiculously GPU intensive rendering, you can just render your tiles with litte thought given to it beyond frustum culling and LOVE will autobatch them in a single draw call, and performance will be just fine. That's on assumption that all of your level tiles are on the same texture atlas, but you should know all about it already.

Re: Scissor vs Canvas for offscreen optimization?

Posted: Tue Aug 13, 2019 8:58 pm
by rougan
Thank you for the details! Didn't realise a majority of that- and I think you may be right, I am most lilkely overthinking from a performance standpoint. I feel like I only want to turn a blind eye as an educated decision.