Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: How to optimize multiple draws  (Read 4251 times)

0 Members and 1 Guest are viewing this topic.

fatess

  • Newbie
  • *
  • Posts: 2
    • View Profile
How to optimize multiple draws
« on: May 21, 2021, 05:05:12 am »
Hi,
I'm working on a cellular automaton and I have to print a grid of cells with sfml.
It's working fine when cells are about less than 600, but when the grid gets bigger, the 600+ draw function calls really slow down the software. Is there any way to make it faster?

This is the problematic part of the code: the vector can contain up to 518400 elements, and with 600 it already starts to take some time to draw all.

Quote
           automatonWindow.clear()
           for(Person currentPerson : *evolutionIterator){
                //Set cell color according to it's status
                personCell.setPosition(x, y);
                automatonWindow.draw(personCell);
            }
            automatonWindow.display()
           

kojack

  • Jr. Member
  • **
  • Posts: 79
    • View Profile
Re: How to optimize multiple draws
« Reply #1 on: May 21, 2021, 09:22:07 am »
What does a cell look like? If it's just a solid colour representing it's status, then you could use a texture. Set it's pixels to represent the cells. Then you can have any size (well, up to 8192x8192, maybe 16384x16384 depending on gfx card and if sfml lets it) with a single draw call.

For example:
                sf::Texture tex;
                tex.create(64, 64);

                sf::Image img;
                img.create(64, 64);

                img.setPixel(10, 20, sf::Color::Red);
                tex.update(img);
 
This makes a texture (which you'd use for a sprite or quad, etc) and an image. You can change the cells in the image using setPixel, then when all cell statuses are up to date, call tex.update(img) to upload the current image to the texture.

If the cells aren't simple blocks, something more complicated might be needed. (Shader, or multi pass blending)

AnhBao

  • Newbie
  • *
  • Posts: 10
    • View Profile
    • Email
Re: How to optimize multiple draws
« Reply #2 on: July 11, 2021, 02:36:33 pm »
It has been 1 month... have you found a way? I intend to make Minesweeper but the same problem happens. The only thing i can do is to limit fps to about 10 or so.

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 9909
    • View Profile
    • development blog
    • Email
Re: How to optimize multiple draws
« Reply #3 on: July 11, 2021, 04:10:55 pm »
What hasn't really been mentioned is that you can use a vertex array, to drop the draw call from hundreds down to one.

There are also other optimizations possible, like using a render texture and tracking only the changes and re-rendering those changes instead of the whole frame.
Official FAQ: https://www.sfml-dev.org/faq.php
Nightly Builds: https://www.nightlybuilds.ch/
——————————————————————
Dev Blog: https://dev.my-gate.net/
Thor: http://www.bromeon.ch/libraries/thor/

firet

  • Newbie
  • *
  • Posts: 7
  • Gamedev, web dev and C++ programmer.
    • View Profile
    • Future Games official site
    • Email
Re: How to optimize multiple draws
« Reply #4 on: July 12, 2021, 06:26:05 pm »
Hey! Here's a simple way of doing this that nobody has mentioned. Say you have a 50 by 50 grid of gray squares. When a square is clicked, it turns white. Here's a simple way of cutting down render calls a TON:
  • Create an image (PNG or JPG) of your 50 by 50 grid.
  • Render this image as a Sprite instead of 2500 separate squares.
  • When you click, use an algorithm to detect which cell you clicked.
  • Draw a WHITE RECTANGLESHAPE on top of the grid with the width and height of one cell at the position of the cell clicked.
Online I am: firet; flesheatindragon; Future Games.

AnhBao

  • Newbie
  • *
  • Posts: 10
    • View Profile
    • Email
Re: How to optimize multiple draws
« Reply #5 on: July 18, 2021, 11:04:29 am »
Uhmm so what about when there are many white cells... Isn't it the same

Stauricus

  • Sr. Member
  • ****
  • Posts: 299
    • View Profile
    • Email
Re: How to optimize multiple draws
« Reply #6 on: July 18, 2021, 03:09:36 pm »
Hey! Here's a simple way of doing this that nobody has mentioned. Say you have a 50 by 50 grid of gray squares. When a square is clicked, it turns white. Here's a simple way of cutting down render calls a TON:
  • Create an image (PNG or JPG) of your 50 by 50 grid.
  • Render this image as a Sprite instead of 2500 separate squares.
  • When you click, use an algorithm to detect which cell you clicked.
  • Draw a WHITE RECTANGLESHAPE on top of the grid with the width and height of one cell at the position of the cell clicked.

the problem doing it is that you kill exactly the purpose of tiles: repetition of small parts (tilesets) to avoid large textures. also, many videocards can't handle textures bigger than 8192x8192, so for 50x50 tiles you max tile size will be 163,84x163,84. for 100x100 maps, it will be 81,92x81,92  :P

firet

  • Newbie
  • *
  • Posts: 7
  • Gamedev, web dev and C++ programmer.
    • View Profile
    • Future Games official site
    • Email
Re: How to optimize multiple draws
« Reply #7 on: July 18, 2021, 06:30:21 pm »
Uhmm so what about when there are many white cells... Isn't it the same
One workaround (don’t recommend) is to swap once half the tiles are white. By then, you can have the image be a WHITE grid image and just render individual grey tiles which you REMOVE when clicked.
Online I am: firet; flesheatindragon; Future Games.

firet

  • Newbie
  • *
  • Posts: 7
  • Gamedev, web dev and C++ programmer.
    • View Profile
    • Future Games official site
    • Email
Re: How to optimize multiple draws
« Reply #8 on: July 18, 2021, 06:32:04 pm »
Hey! Here's a simple way of doing this that nobody has mentioned. Say you have a 50 by 50 grid of gray squares. When a square is clicked, it turns white. Here's a simple way of cutting down render calls a TON:
  • Create an image (PNG or JPG) of your 50 by 50 grid.
  • Render this image as a Sprite instead of 2500 separate squares.
  • When you click, use an algorithm to detect which cell you clicked.
  • Draw a WHITE RECTANGLESHAPE on top of the grid with the width and height of one cell at the position of the cell clicked.

the problem doing it is that you kill exactly the purpose of tiles: repetition of small parts (tilesets) to avoid large textures. also, many videocards can't handle textures bigger than 8192x8192, so for 50x50 tiles you max tile size will be 163,84x163,84. for 100x100 maps, it will be 81,92x81,92  :P
Fine point, but you can easily break the single grey grid texture into four 25x25 textures.
Online I am: firet; flesheatindragon; Future Games.

AnhBao

  • Newbie
  • *
  • Posts: 10
    • View Profile
    • Email
Re: How to optimize multiple draws
« Reply #9 on: July 19, 2021, 10:40:57 am »
@Stauricus: Uhhh i dont really get it... So it's better to handle multiple smaller sprites than a big one? Sorry if my question sounds silly but i'm still quite new
@firet: :'> n^2 and n^2/2 doesnt make a big difference when you having large n I think

Stauricus

  • Sr. Member
  • ****
  • Posts: 299
    • View Profile
    • Email
Re: How to optimize multiple draws
« Reply #10 on: July 19, 2021, 03:16:24 pm »
@Stauricus: Uhhh i dont really get it... So it's better to handle multiple smaller sprites than a big one? Sorry if my question sounds silly but i'm still quite new

yes, in general it is.
smaller sprites (tiles) can be repeated trough the level. so you can use the same tile dozens of times, at the cost of one small texture.
if you are going to make a big level with a single image, there is no point in using tiles. just create a big organic image.
for example, compare Diablo levels and Postal levels (both games are from 1997). Diablo levels are much bigger, because they are made with tiles, repetition; Postal have smaller levels, made with a single big image for each one.

for the question itself, in SFML the best approach is VertexArray, as already said. you use a tileset and draw everything at once, in a single draw call. we even have a specific tutorial for that:
https://www.sfml-dev.org/tutorials/2.5/graphics-vertex-array.php#example-tile-map

 

anything