0

I'm making a 2d engine in OpenGl c# using opentk. i draw 36500 sprites @ 45 fps and 50000 sprites @ 30 fps. Im on a laptop, but with good specs. it can run crysis3 on very high smooth. specs: i7 4810mq quad core @ 3.8 ghz 6mb cache, gtx 870m, 8gb ram. now i think my program is being slow... i use vbo's. each sprite is made out of 6 vertices, 2 triangles. they are textured. indexing doesn't seem to improve the speed. the class vbo contains integers that stre the vbo id. vbodata contains arrays of vertex,texture and indices data. the renderer class contains more renderercores rendercore code:

using OpenTK.Graphics.OpenGL;
using System;
using System.Threading;

namespace TortoiseEngineBuilder
{
public class RendererCore
{
    private VBO vbos;
    private VBOData data;
    private int verCount;
    private int texCount;
    private int indCount;

    public RendererCore()
    {
        vbos = new VBO();
        data = new VBOData();
        Console.WriteLine("init renderer");
    }

    public void AddData(Sprite sprite, bool debug = false, int dVBO = 0, int dStart = 0, int dEnd = 100)
    {
        //vertices + indices
        for (int i = 0; i < sprite.VertexData.Length; i++)
        {
            data.VertexData[verCount + i] = sprite.VertexData[i];
        }
        for (int i = 0; i < sprite.IndicesData.Length; i++)
        {
            data.IndicesData[indCount + i] = (uint)((indCount) + sprite.IndicesData[i]);
        }
        //textures
        for (int i = 0; i < sprite.TextureData.Length; i++)
        {
            data.TextureData[texCount + i] = sprite.TextureData[i];
        }
        texCount += sprite.TextureData.Length;
        verCount += sprite.VertexData.Length;
        indCount += sprite.IndicesData.Length;
        if (debug) OutPutArraysVbo(dStart, dEnd);
    }

    public void ClearData()
    {
        data = new VBOData();
    }

    public void SetVBOFromData()
    {
        VBOData d = new VBOData(verCount, texCount, indCount);
        for (int i = 0; i < verCount; i++)
        {
            d.VertexData[i] = data.VertexData[i];
        }
        for (int i = 0; i < texCount; i++)
        {
            d.TextureData[i] = data.TextureData[i];
        }
        for (int i = 0; i < indCount; i++)
        {
            d.IndicesData[i] = data.IndicesData[i];
        }
        SetVBO(ref d);
        System.GC.Collect();
    }

    public void CreateVBO()
    {
        GL.GenBuffers(1, out vbos.textureBufferID);
        GL.GenBuffers(1, out vbos.vertexBufferID);
        GL.GenBuffers(1, out vbos.indiciesBufferID);
        Console.WriteLine(vbos.textureBufferID + ":" + vbos.textureBufferID + ":" + vbos.indiciesBufferID);
    }

    public void SetVBO(ref VBOData vboData)
    {
        // TexCoord Array Buffer
        {
            GL.BindBuffer(BufferTarget.ArrayBuffer, vbos.textureBufferID);
            GL.BufferData(BufferTarget.ArrayBuffer, (IntPtr)(vboData.TextureData.Length * sizeof(float)), vboData.TextureData, BufferUsageHint.StaticDraw);
            GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
        }
        // Vertex Array Buffer
        {
            GL.BindBuffer(BufferTarget.ArrayBuffer, vbos.vertexBufferID);
            GL.BufferData(BufferTarget.ArrayBuffer, new IntPtr(vboData.VertexData.Length * sizeof(float)), vboData.VertexData, BufferUsageHint.StaticDraw);
            GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
        }
        // Element Array Buffer
        {
            GL.BindBuffer(BufferTarget.ElementArrayBuffer, vbos.indiciesBufferID);
            GL.BufferData(BufferTarget.ElementArrayBuffer, (IntPtr)(vboData.IndicesData.Length * sizeof(int)), vboData.IndicesData, BufferUsageHint.StaticDraw);
            GL.BindBuffer(BufferTarget.ElementArrayBuffer, 0);
        }
        vbos.elementCount = vboData.IndicesData.Length - 6;
    }

    public void DrawVBO(int textureID)
    {
        GL.EnableVertexAttribArray(0);
        // Texture Data Buffer Binding
        {
            GL.EnableClientState(ArrayCap.TextureCoordArray);
            GL.BindBuffer(BufferTarget.ArrayBuffer, vbos.textureBufferID);
            GL.TexCoordPointer(2, TexCoordPointerType.Float, sizeof(float) * 2, IntPtr.Zero);
            GL.BindTexture(TextureTarget.Texture2D, textureID);
        }
        // Vertex Array Buffer
        {
            GL.EnableClientState(ArrayCap.VertexArray);
            GL.BindBuffer(BufferTarget.ArrayBuffer, vbos.vertexBufferID);
            GL.VertexAttribPointer(0, 3, VertexAttribPointerType.Float, false, sizeof(float)*3, 0);
        }
        // Element Array Buffer
        {
            GL.Enable(EnableCap.IndexArray);
            GL.IndexPointer(IndexPointerType.Int, sizeof(uint), IntPtr.Zero);
            GL.BindBuffer(BufferTarget.ElementArrayBuffer, vbos.indiciesBufferID);
        }
        //draw
        {
            GL.DrawElements(PrimitiveType.Triangles, indCount, DrawElementsType.UnsignedInt, vbos.indiciesBufferID);
            GL.DisableClientState(ArrayCap.VertexArray);
            GL.DisableVertexAttribArray(0);
        }
    }

    public void OutPutArraysVbo(int begin, int end, bool vertex = true, bool textures = false, bool indices = false)
    {
        for (int i = begin; i < end; i++)
        {
            if (vertex) Console.WriteLine("VertexData[" + i + "]= " + data.VertexData[i]);
        }
        Console.WriteLine("---------------------------------");
        for (int i = begin; i < end; i++)
        {
            if (textures) Console.WriteLine("TextureData[" + i + "]= " + data.TextureData[i]);
        }
        Console.WriteLine("---------------------------------");
        for (int i = begin; i < end; i++)
        {
            if (indices) Console.WriteLine("IndicesData[" + i + "]= " + data.IndicesData[i]);
        }
        Console.WriteLine("===================================");
    }

    public void OutPutArraysData(VBOData data, int begin, int end, bool vertex = true, bool textures = false, bool indices = false)
    {
        for (int i = begin; i < end; i++)
        {
            if (vertex) Console.WriteLine("VertexData[" + i + "]= " + data.VertexData[i]);
        }
        Console.WriteLine("---------------------------------");
        for (int i = begin; i < end; i++)
        {
            if (textures) Console.WriteLine("TextureData[" + i + "]= " + data.TextureData[i]);
        }
        Console.WriteLine("---------------------------------");
        for (int i = begin; i < end; i++)
        {
            if (indices) Console.WriteLine("IndicesData[" + i + "]= " + data.IndicesData[i]);
        }
        Console.WriteLine("===================================");
    }
}

}

main program code:

using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
using System.Xml.Serialization;

using OpenTK;
using OpenTK.Graphics.OpenGL;
using System.Threading;

namespace TortoiseEngineBuilder { public class MainThread : GameWindow {
FPS FpsCounter; Random r; Renderer renderer; TextureManager textureLoader;

    int WWidth = 1920;
    int WHeight = 1080;
    string WTitle = "TortoiseEngine3";

    int sprites_vbo = 36500;
    int sprites;
    ThreadTask t;

    public MainThread()
    {
        Console.WriteLine("init display BEGIN");
        //init console
        Console.WriteLine("Constructor Called Succesful!");
        Console.WriteLine("Press a Key to proceed running the constructor");
        Console.ReadKey();
        Console.Title = WTitle;
        Console.ForegroundColor = ConsoleColor.Green;
        //init display
        Title = WTitle;
        Width = WWidth;
        Height = WHeight;
        //init obj's that are always needed
        FpsCounter = new FPS();
        renderer = new Renderer();
        textureLoader = new TextureManager();
        renderer.Init(WWidth, WHeight, WWidth, WHeight);
        //set some GL.{}
        GL.ClearColor(Color.Black);
        Console.WriteLine("init display COMPLETE");
        //instantiate game obj's
        r = new Random();
        //feed the GPU
        for (int i = 0; i < sprites_vbo; i++)
        {
            renderer.AddData(0, new Sprite(r.Next(1920), r.Next(1080), r.Next(50, 100), r.Next(50, 100)));
            renderer.AddData(10,new Sprite(r.Next(1920), r.Next(1080), r.Next(50,100), r.Next(50,100)));
        }
        renderer.AddData(0,new Sprite(0,0,0,0));
        renderer.AddData(10,new Sprite(0,0,0,0));
        renderer.Create(0);
        renderer.Set(0);
        //renderer.Create(10);
        //renderer.Set(10);
        renderer.GetArrayData(0,0,200,false,false,true);
        sprites = sprites_vbo;
    }

    protected override void OnLoad(EventArgs e)
    {
        Console.WriteLine("init textures BEGIN");
        textureLoader.SaveTexture("assets/smile_blue.png", "smileBlue");
        textureLoader.SaveTexture("assets/smile_red.png", "smileRed");
        Console.WriteLine("init textures COMPLETE");
    }

    protected override void OnUpdateFrame(FrameEventArgs e)
    {
        base.OnUpdateFrame(e);
        //renderer.AddData(0, new Sprite(r.Next(1920/2),r.Next(1080),r.Next(50,100),r.Next(50,100)));
        //renderer.AddData(10, new Sprite(r.Next(1920/2,1920), r.Next(1080), r.Next(50, 100), r.Next(50, 100)));
        //renderer.AddData(0, new Sprite(r.Next(1920 / 2), r.Next(1080), r.Next(50, 100), r.Next(50, 100)));
        //renderer.AddData(10, new Sprite(r.Next(1920 / 2, 1920), r.Next(1080), r.Next(50, 100), r.Next(50, 100)));
        renderer.Set(0);
        //renderer.Set(10);

        //sprites += 4;
        Title = "sprites: " + sprites + " FPS: " + FpsCounter.GetFPS();
    }

    protected override void OnRenderFrame(FrameEventArgs e)
    {
        base.OnRenderFrame(e);
        renderer.Init(Width,Height,WWidth,WHeight);
        renderer.Start(Width, Height);
        {
            renderer.Draw(0,textureLoader.getTexture("smileBlue"));
            //renderer.Draw(10, textureLoader.getTexture("smileRed"));
        }
        renderer.End(this);
        renderer.CheckError();
    }
    public static void Main(string[] args)
    {
        using (MainThread p = new MainThread())
        {
            Console.WriteLine("RUN");
            p.Run();
        }
    }
}

}

is this code slow?(when compared)
if it is: what is the expected performance if it would run efficient?
if it is: what can i do to improve the speed?

genpfault
  • 51,148
  • 11
  • 85
  • 139
cody b
  • 3
  • 4
  • Possibly a question better suited to http://codereview.stackexchange.com/? – Benjamin James Drury Mar 08 '15 at 23:54
  • possible duplicate of [OpenGL c#(OpenTk) why is this vbo slow?](http://stackoverflow.com/questions/28840145/opengl-copentk-why-is-this-vbo-slow) – vesan Mar 09 '15 at 04:03
  • 1. use VAO to reduce GL calls (all the VBO settings), 2. switching between textures is slow faster is make single texture image for more objects and render them with single bind call ... 3. if you have VBO per sprite then it is the same as with textures, group more objects to single VBO to reduce the GL calls per frame ... If you want to compare the numbers search for spec/datasheet of your gfx and see the triangle/s value ... – Spektre Mar 09 '15 at 09:49

0 Answers0