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

Author Topic: Performance Lag with Vertex Array  (Read 3412 times)

0 Members and 1 Guest are viewing this topic.

DarkNemesis

  • Newbie
  • *
  • Posts: 11
    • View Profile
Performance Lag with Vertex Array
« on: July 04, 2013, 03:02:27 pm »
Hello.
I am making my third game BrickBreaker using Visual Studio 2010 and SFML 2.0.
At first I created a paddle and ball sprite along with a score heading string and score value string, and a score background slider. In short I just had total 5 draw calls and till then the game played very smooth.
Then I used vertex array to draw all the Bricks and the background. The texture used was the background texture, while the bricks were only colored, no texture used for them. I did exactly as it was in the tutorial, but after implementing this, my game speed dropped to like 3 FPS. If I remove drawing just the vertex array, speed returns back to normal, which means the background game logic is fine and don't have much issues.

Here is the code I used : Level class is the one responsible for populating the vertex array, while Display does all the drawing.

Level.h :
class Level : public Drawable, public Transformable
{
        int video_width, video_height, brick_count;
        int level;
        Texture back_texture;
        VertexArray m_vertices;
        virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const
    {
        // apply the transform
        states.transform *= getTransform();

        // apply the tileset texture
        states.texture = &back_texture;

        // draw the vertex array
        target.draw(m_vertices, states);
    }
public:
        Level(void);
        ~Level(void);
        void LevelCreate(std::list<Brick> Tile);
        void Initialize(int a, int b);
        void LevelSet(std::list<Brick>* Tile);
};

Level.cpp :
// ... Showing the main function -->
void Level::LevelCreate(std::list<Brick> Tile)
{
        //Populating Background
        sf::Vertex* quad = &m_vertices[0];
        quad[0].position = sf::Vector2f(0, 0);
        quad[1].position = sf::Vector2f(0.8 * video_width, 0);
    quad[2].position = sf::Vector2f(0.8 * video_width, video_height);
    quad[3].position = sf::Vector2f(0, video_height);

        quad[0].texCoords = sf::Vector2f(0, 0);
        quad[1].texCoords = sf::Vector2f(back_texture.getSize().x, 0);
    quad[2].texCoords = sf::Vector2f(back_texture.getSize().x, back_texture.getSize().y);
    quad[3].texCoords = sf::Vector2f(0, back_texture.getSize().y);

        //Populating Bricks
        int i = 1;
        for (auto tile_no = Tile.begin(); tile_no != Tile.end(); tile_no++, i++)
        {
                sf::Vertex* quad = &m_vertices[i*4];
                quad[0].position = sf::Vector2f(tile_no->GetDimension().x, tile_no->GetDimension().y);
        quad[1].position = sf::Vector2f(tile_no->GetDimension().x + tile_no->GetSize().x, tile_no->GetDimension().y);
        quad[2].position = sf::Vector2f(tile_no->GetDimension().x + tile_no->GetSize().x, tile_no->GetDimension().y + tile_no->GetSize().y);
        quad[3].position = sf::Vector2f(tile_no->GetDimension().x, tile_no->GetDimension().y + tile_no->GetSize().y);
                switch(tile_no->GetDurability())
                {
                case 1 :        quad[0].color = quad[2].color = Color::Green;                          
                         break;
                case 2 :        quad[0].color = quad[2].color = Color::Blue;
                         break;
                case 3 :        quad[0].color = quad[2].color = Color::Red;
                        break;
                case 4 :        quad[0].color = Pcolor; quad[2].color = Pcolor2;
                        break;
                }
        }
        //Removing previous held vertices.
        for (; i <= brick_count; i++)
        {
                auto tile_no = Tile.begin();
                sf::Vertex* quad = &m_vertices[i*4];
                quad[0].position = sf::Vector2f(tile_no->GetDimension().x, tile_no->GetDimension().y);
        quad[1].position = sf::Vector2f(tile_no->GetDimension().x + tile_no->GetSize().x, tile_no->GetDimension().y);
        quad[2].position = sf::Vector2f(tile_no->GetDimension().x + tile_no->GetSize().x, tile_no->GetDimension().y + tile_no->GetSize().y);
        quad[3].position = sf::Vector2f(tile_no->GetDimension().x, tile_no->GetDimension().y + tile_no->GetSize().y);
                switch(tile_no->GetDurability())
                {
                case 1 :        quad[0].color = quad[2].color = sf::Color::Green;                              
                        break;
                case 2 :        quad[0].color = quad[2].color = Color::Blue;
                        break;
                case 3 :        quad[0].color = quad[2].color = Color::Red;
                         break;
                }

        }
}

Actually I use a list for my Bricks. Once a brick is destroyed, it is thrown out of the list, but the vertex array still stores it, so basically I use my third for loop for the vertex array to store some other existing Brick in place of removed bricks. I tried removing the third for loop as well, no performance improvement, only a diff. logic where ghost bricks were shown even after they were destroyed, reason I mentioned above.
So I think there is no problem with the logic.

Another class Display uses an object of Level. It does all the Drawing :

void Display::DrawUpdate()
{
        //Clearing Screen
        BB_Win.clear();

        //Drawing Screen
        BB_Win.draw(Stage);//Vertex Array
        Scor.Draw(BB_Win,Bal.BSpeed(),Life,ScoreValue);//Score Values, just 3 draw calls used here.
        BB_Win.draw(Pad.Draw());        BB_Win.draw(Bal.Draw());// 2 draw calls for paddle and brick

        //Displaying Screen
        BB_Win.display();
}

I don't know why vertex array causes such a lag.. If I remove -- BB_Win.draw(Stage); -- command, I get all my performance back. this is my first time using Vertex array, all help appreciated. Do tell me if I need to provide any more information

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: Performance Lag with Vertex Array
« Reply #1 on: July 04, 2013, 03:11:28 pm »
There's an important piece of code missing: where do you construct the vertex array?

Quote
Once a brick is destroyed, it is thrown out of the list
Do you mean that LevelCreate is called everytime a brick is destroyed? This is very inefficient.

There are two possible ways to improve your code:

1. Keep your current design, but instead of filling the vertex array with dummy bricks, just resize the vertex array to the right size. In LevelCreate you should clear() your vertex array and then append() (only) the needed vertices.

2. Update your vertex array instead of rebuilding it completely everytime a brick is destroyed. To avoid moving a huge amount of vertices when you remove a quad in the middle, simply swap the destroyed one with the last one, and then adjust the size of your vertex array with resize(). Of course it works only if the order is not important, i.e. if bricks never overlap.
Laurent Gomila - SFML developer

DarkNemesis

  • Newbie
  • *
  • Posts: 11
    • View Profile
Re: Performance Lag with Vertex Array
« Reply #2 on: July 05, 2013, 12:42:17 pm »
KK thanks Lauren, I figured out what I was doing wrong, when I read your second idea.
I was using VertexArray for the first time, and so I didn't know exactly how it worked. And out of all the tutorials, I found it a bit short. I copied your tile map but did not understand it properly, especially about resize. I thought resize is the largest coordinates that the VertexArray could store and so I set it to video_width * video_height which went to be more than 10^6 :P
No wonder why it ran so slow even after I tried everything I could. In fact I am amazed how was it able to run at even 3 FPS after storing a million vertices :o
When I read your reply, it made a bit sense about resize and when I tried it, normal speed was back. Guess the mistake was needed, now I am more confident with VertexArrays. Also, I will request you to elaborate the tutorial on this topic if you can since I consider it to be the most useful one (and therefore important too), and a bit harder too, unlike other tutorials which are plain understanding.
One more thing, I did as you said, because I myself wanted to get rid of dummy bricks. But during swapping, is it possible that instead of redefining the new quads, I simply use m_vertices[new_pos] = m_vertices[old_pos]; I tried this, but after 3-4 bricks, it started showing weird results, half triangles instead of quads.
Also, have you removed randomizer class from SFML 2.0??
Thanks again Laurent for the help, you're the best, SFML is such a charm.. :)

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: Performance Lag with Vertex Array
« Reply #3 on: July 05, 2013, 01:12:51 pm »
I'm glad you managed to solve your problem and understand vertex arrays better :)

Quote
I will request you to elaborate the tutorial on this topic
I think the documentation is very clear about the meaning of the argument of the resize function, isn't it?

Quote
But during swapping, is it possible that instead of redefining the new quads, I simply use m_vertices[new_pos] = m_vertices[old_pos]; I tried this, but after 3-4 bricks, it started showing weird results, half triangles instead of quads.
It should work. Do you correctly assign the 4 vertices of the quad?

Quote
Also, have you removed randomizer class from SFML 2.0??
Yes.
Laurent Gomila - SFML developer