SFML community forums

Bindings - other languages => DotNet => Topic started by: scellow on March 17, 2016, 10:55:08 pm

Title: Poor performance using multiple VertexArray
Post by: scellow 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..
Title: Re: Poor performance using multiple VertexArray
Post by: eXpl0it3r 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?
Title: Re: Poor performance using multiple VertexArray
Post by: Hapax 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.
Title: Re: Poor performance using multiple VertexArray
Post by: scellow 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)
Title: Re: Poor performance using multiple VertexArray
Post by: krzat 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.
Title: Re: Poor performance using multiple VertexArray
Post by: Jesper Juhl 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..
Title: Re: Poor performance using multiple VertexArray
Post by: ggggggggggggggg 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.
Title: Re: Poor performance using multiple VertexArray
Post by: krzat 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.
Title: Re: Poor performance using multiple VertexArray
Post by: ggggggggggggggg 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."
Title: Re: Poor performance using multiple VertexArray
Post by: krzat 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.
Title: Re: Poor performance using multiple VertexArray
Post by: scellow 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);
        }
    }
}