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

Author Topic: Performance of different primitive types, and sf::Sprite vs vertex array?  (Read 607 times)

0 Members and 1 Guest are viewing this topic.

StriderPulse599

  • Newbie
  • *
  • Posts: 16
    • View Profile
Does using triangle primitive for vertex array results in better performance than rectangles? CPU is currently the main bottleneck and using rectangles will cut out a good chunk of calculations (and make my life easier).

I've also read on another topic that storing sf::Sprite objects have the same performance as vertex array at end of the day. Can someone confirm this is a truth? https://en.sfml-dev.org/forums/index.php?topic=22076.0

Hapax

  • Hero Member
  • *****
  • Posts: 3351
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Each sf::Sprite that is drawn uses a "draw call". The draw call is most often the most significant time wasted when drawing multiple objects. If there are very many sprites, the number of draw calls is high and can cause performance issues.

However, using a vertex array (or similar) allows you to draw multiple shapes at once with just one draw call, which can severely improve performance. Those shapes can be textured and rectangular so multiple sprites can be mimicked.

As for primitives, if you want to draw rectangles, you simply use the triangles primitives and create two triangles to create each rectangle. It requires a slight duplication of vertices and would therefore be 6 vertices per quad/rectangle:
sf::VertexArray rectangles(sf::PrimitiveType::Triangles, 12u); // 2 rectangles = 12 vertices

std::size_t firstVertexOfRectangle;
sf::Vector2f topLeft;
sf::Vector2f bottomRight;

// first rectangle: 100,100 - 300,200 (200x100)
firstVertexOfRectangle = 0u;
topLeft = { 100.f, 100.f };
bottomRight = { 300.f, 200.f };

rectangles[firstVertexOfRectangle + 0u].position = topLeft;
rectangles[firstVertexOfRectangle + 1u].position = { topLeft.x, bottomRight.y };
rectangles[firstVertexOfRectangle + 2u].position = bottomRight;
rectangles[firstVertexOfRectangle + 5u].position = { topLeft.y, bottomRight.x };
rectangles[firstVertexOfRectangle + 3u] = rectangles[firstVertexOfRectangle + 0u];
rectangles[firstVertexOfRectangle + 4u] = rectangles[firstVertexOfRectangle + 2u];

// second rectangle: 500,200 - 600,500 (100x300)
firstVertexOfRectangle = 6u;
topLeft = { 500.f, 200.f };
bottomRight = { 600.f, 500.f };

rectangles[firstVertexOfRectangle + 0u].position = topLeft;
rectangles[firstVertexOfRectangle + 1u].position = { topLeft.x, bottomRight.y };
rectangles[firstVertexOfRectangle + 2u].position = bottomRight;
rectangles[firstVertexOfRectangle + 5u].position = { topLeft.y, bottomRight.x };
rectangles[firstVertexOfRectangle + 3u] = rectangles[firstVertexOfRectangle + 0u];
rectangles[firstVertexOfRectangle + 4u] = rectangles[firstVertexOfRectangle + 2u];

// later: window.draw(rectangles); // draws both rectangles with just one draw code

Note that the actual assigning of the vertices is the same both times.

You can assign colours and the texture co-ordinates in the same way. You can do that before the assigning of the "+ 3u" and "+ 4u" (at the time when the positions are assigned) as we're duplicating the entire vertex including colour and texture! 8)
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*

StriderPulse599

  • Newbie
  • *
  • Posts: 16
    • View Profile
Each sf::Sprite that is drawn uses a "draw call". The draw call is most often the most significant time wasted when drawing multiple objects. If there are very many sprites, the number of draw calls is high and can cause performance issues.

However, using a vertex array (or similar) allows you to draw multiple shapes at once with just one draw call, which can severely improve performance. Those shapes can be textured and rectangular so multiple sprites can be mimicked.

As for primitives, if you want to draw rectangles, you simply use the triangles primitives and create two triangles to create each rectangle. It requires a slight duplication of vertices and would therefore be 6 vertices per quad/rectangle:
sf::VertexArray rectangles(sf::PrimitiveType::Triangles, 12u); // 2 rectangles = 12 vertices

std::size_t firstVertexOfRectangle;
sf::Vector2f topLeft;
sf::Vector2f bottomRight;

// first rectangle: 100,100 - 300,200 (200x100)
firstVertexOfRectangle = 0u;
topLeft = { 100.f, 100.f };
bottomRight = { 300.f, 200.f };

rectangles[firstVertexOfRectangle + 0u].position = topLeft;
rectangles[firstVertexOfRectangle + 1u].position = { topLeft.x, bottomRight.y };
rectangles[firstVertexOfRectangle + 2u].position = bottomRight;
rectangles[firstVertexOfRectangle + 5u].position = { topLeft.y, bottomRight.x };
rectangles[firstVertexOfRectangle + 3u] = rectangles[firstVertexOfRectangle + 0u];
rectangles[firstVertexOfRectangle + 4u] = rectangles[firstVertexOfRectangle + 2u];

// second rectangle: 500,200 - 600,500 (100x300)
firstVertexOfRectangle = 6u;
topLeft = { 500.f, 200.f };
bottomRight = { 600.f, 500.f };

rectangles[firstVertexOfRectangle + 0u].position = topLeft;
rectangles[firstVertexOfRectangle + 1u].position = { topLeft.x, bottomRight.y };
rectangles[firstVertexOfRectangle + 2u].position = bottomRight;
rectangles[firstVertexOfRectangle + 5u].position = { topLeft.y, bottomRight.x };
rectangles[firstVertexOfRectangle + 3u] = rectangles[firstVertexOfRectangle + 0u];
rectangles[firstVertexOfRectangle + 4u] = rectangles[firstVertexOfRectangle + 2u];

// later: window.draw(rectangles); // draws both rectangles with just one draw code

Note that the actual assigning of the vertices is the same both times.

You can assign colours and the texture co-ordinates in the same way. You can do that before the assigning of the "+ 3u" and "+ 4u" (at the time when the positions are assigned) as we're duplicating the entire vertex including colour and texture! 8)

I know that triangles can be used to make rectangles and it only takes two more points, but I want to know if there is performance difference between triangle and rectangle primitive.

Btw, where I can post for feedback on my rendering pipeline?
« Last Edit: October 25, 2023, 10:10:32 am by StriderPulse599 »

Hapax

  • Hero Member
  • *****
  • Posts: 3351
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
I should point out that the quads primitive has been deprecated so triangles should always be used (for multiple separate shapes including quads/rectangles).

Your original post was unclear to me. It seemed like your mention of "rectangles" was the sf::RectangleShape object and it reads as though you are comparing "rectangle shapes" with "vertex array with triangles".
So, yes, you should always use triangle primitive in a vertex array instead of the quad/rectangle primitive as the quad primitive has been deprecated should be considered as if removed/not available.
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*