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

Author Topic: Poor performance using multiple VertexArray  (Read 8139 times)

0 Members and 1 Guest are viewing this topic.

scellow

  • Newbie
  • *
  • Posts: 13
    • View Profile
Poor performance using multiple VertexArray
« on: March 17, 2016, 10:55:08 pm »
Hello,

I'm actually making a tilemap using VertexArray, my tilemap is split in multiple chunks

Each chunk has it's own VertexArray

One Tile = 16x16 pixels
One Chunk = 128x128 tiles = 2048x2048 pixels
Map = 2048x2048 tiles = 4194304 tiles
Number of chunks = 256

And i'm getting 12fps when i render all the chunks, it's really bad performance for only 256 draw calls...

Here is a ready to use project, so you can test: https://bitbucket.org/Scellow/projecttr

Is there something i'm missing? I also tried using RenderTexture but i get same result..

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 10815
    • View Profile
    • development blog
    • Email
Re: Poor performance using multiple VertexArray
« Reply #1 on: March 18, 2016, 12:29:37 am »
Is your GPU driver installed & uptodate?
Did you test this in release mode?

Have you run a profiler over your code?
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

Hapax

  • Hero Member
  • *****
  • Posts: 3351
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: Poor performance using multiple VertexArray
« Reply #2 on: March 18, 2016, 01:57:10 am »
Each chunk has it's own VertexArray
[...]
One Chunk = 128x128 tiles = 2048x2048 pixels
[...]
Number of chunks = 256
And i'm getting 12fps when i render all the chunks, it's really bad performance for only 256 draw calls...
Why are you drawing all 256 chunks that are each 2048x2048?
Surely you only need to draw the one(s) that are actually visible.
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*

scellow

  • Newbie
  • *
  • Posts: 13
    • View Profile
Re: Poor performance using multiple VertexArray
« Reply #3 on: March 18, 2016, 11:35:42 am »
Is your GPU driver installed & uptodate?
Did you test this in release mode?

Have you run a profiler over your code?

GPU driver is installed and up to date, tried with both NVIDIA and AMD card

I did tested in debug and release mode, but same result

I tried to profile CPU and GPU usage, i'm not really experienced in profiling, but GPU usage was all the time at 100% when drawing these 256 chunks

I'm not sure what i should check when i profile, can you suggest me something please?

Each chunk has it's own VertexArray
[...]
One Chunk = 128x128 tiles = 2048x2048 pixels
[...]
Number of chunks = 256
And i'm getting 12fps when i render all the chunks, it's really bad performance for only 256 draw calls...
Why are you drawing all 256 chunks that are each 2048x2048?
Surely you only need to draw the one(s) that are actually visible.

I know i should only draw the visible ones, but i want to draw them all for my map editor (being able to zoom-out is a feature)

krzat

  • Full Member
  • ***
  • Posts: 107
    • View Profile
Re: Poor performance using multiple VertexArray
« Reply #4 on: March 18, 2016, 01:42:22 pm »
12fps seems reasonable when drawing 8 million triangles. You should use render targets, and probably manually implement mipmaps, since SFML doesn't support them.
SFML.Utils - useful extensions for SFML.Net

Jesper Juhl

  • Hero Member
  • *****
  • Posts: 1405
    • View Profile
    • Email
Re: Poor performance using multiple VertexArray
« Reply #5 on: March 19, 2016, 02:24:18 pm »
I know i should only draw the visible ones, but i want to draw them all for my map editor (being able to zoom-out is a feature)
Then just draw more when zooming out..

ggggggggggggggg

  • Newbie
  • *
  • Posts: 36
    • View Profile
    • Email
Re: Poor performance using multiple VertexArray
« Reply #6 on: March 21, 2016, 09:12:25 am »
You should be using something like a QuadTree to find out what you should be drawing. Have a camera class, get its bounds, and use the QuadTree to query what objects are inside the camera's bounds. You should *never* have a draw loops that just iterates over every entity inside your game.

If you make the code available again (It says I don't have access to look at the repository) I can test your code with a QuadTree.
« Last Edit: March 21, 2016, 09:16:41 am by asusralis »

krzat

  • Full Member
  • ***
  • Posts: 107
    • View Profile
Re: Poor performance using multiple VertexArray
« Reply #7 on: March 23, 2016, 02:06:01 pm »
You should be using something like a QuadTree to find out what you should be drawing. Have a camera class, get its bounds, and use the QuadTree to query what objects are inside the camera's bounds. You should *never* have a draw loops that just iterates over every entity inside your game.

If you make the code available again (It says I don't have access to look at the repository) I can test your code with a QuadTree.

Quad tree is pointless for tile maps, and he want's to have full zoom out anyway.
SFML.Utils - useful extensions for SFML.Net

ggggggggggggggg

  • Newbie
  • *
  • Posts: 36
    • View Profile
    • Email
Re: Poor performance using multiple VertexArray
« Reply #8 on: March 24, 2016, 07:30:24 am »
Quad tree is pointless for tile maps

A QuadTree excels with many static objects that don't move. A tile map is literally perfect for a QuadTree. Even if he's clumping his tiles into giant objects, something he probably shouldn't be doing, a QuadTree would still heavily reduce the amount the draw calls.

and he want's to have full zoom out anyway.

That has nothing to do with spatial indexing. If he wants to zoom all the way, fine, a QuadTree won't help when he's drawing every entity on screen. But for the mast majority of applications you're not zoomed all the way out.

Hapax hit this problem on the head and a QuadTree would be the way to do what he suggested.

"Why are you drawing all 256 chunks that are each 2048x2048?
Surely you only need to draw the one(s) that are actually visible."
« Last Edit: March 24, 2016, 07:33:43 am by asusralis »

krzat

  • Full Member
  • ***
  • Posts: 107
    • View Profile
Re: Poor performance using multiple VertexArray
« Reply #9 on: March 25, 2016, 08:42:05 am »
You don't need quad tree for tile map, because getting visible tiles is as simple as leftCorner / tileSize and rightCorner/tileSize (or in his case chunk size).
It kinda works like spatial hashing, simplest case.
« Last Edit: March 25, 2016, 08:45:25 am by krzat »
SFML.Utils - useful extensions for SFML.Net

scellow

  • Newbie
  • *
  • Posts: 13
    • View Profile
Re: Poor performance using multiple VertexArray
« Reply #10 on: May 23, 2016, 01:33:38 am »
Sorry for late reply

But i "solved" my issue by using Image and Texture instead of VertexArray

That's the only way i found to be able to render 4 millions of tiles while zoomed out with constant 60+ FPS

And i'm able to save lot of texture swap since i'm only dealing with colors data (only one draw call by chunks, even if i'm using multiple different tilesets)

Here is the updated code of the Chunk:

using System;
using SFML.Graphics;
using SFML.System;
using TheRoguer.Client.Legacy.Managers;
using TheRoguer.Client.Legacy.Utils;
using TheRoguer.Client.Legacy.Data;

namespace TheRoguer.Client.Legacy.World.Map
{
    public class Chunk : Drawable
    {

        private Texture m_texture;
        public Vector2f Position;
        private Image m_image;
        private Sprite m_sprite;
        private bool m_dirty;

        public Chunk()
        {
            m_texture = new Texture(TileMap.CHUNK_SIZE * TileMap.TILE_SIZE, TileMap.CHUNK_SIZE * TileMap.TILE_SIZE);
            m_image = new Image(TileMap.CHUNK_SIZE * TileMap.TILE_SIZE, TileMap.CHUNK_SIZE * TileMap.TILE_SIZE);
            m_sprite = new Sprite(m_texture);
        }

        public void Reset(int offsetX, int offsetY)
        {
            Position = new Vector2f(offsetX, offsetY + 4);
            m_sprite.Position = Position;
        }

        public void Draw(RenderTarget target, RenderStates states)
        {
            target.Draw(m_sprite);
        }


        public void Update(int time, int delta)
        {
            if (m_dirty)
            {
                m_texture.Update(m_image);
                m_sprite.Texture = m_texture;
                m_dirty = false;
            }
        }

        public void Paint(int x, int y, TextureData textureData)
        {

            var textureRegion = AssetManager.Instance.GetRegion(textureData);
            if (textureRegion.Texture == null)
                Log.Error(GetType(), $"Texture Region for {textureData.File}:{textureData.Index} not found");

            var world_x = x * TileMap.TILE_SIZE;
            var world_y = y * TileMap.TILE_SIZE;


            for (var tex = 0; tex < textureRegion.Width; tex++)
            {
                for (var tey = 0; tey < textureRegion.Height; tey++)
                {
                    var color = textureRegion.GetColor(tex, tey);
                    var pix_x = world_x + tex;
                    var pix_y = world_y + tey;
                    m_image.SetPixel((uint) pix_x, (uint) pix_y, color);
                }
            }

            m_dirty = true;
        }

        public void Dispose()
        {
            PoolingManager.Instance.Recycle(this);
        }
    }
}