-1

When I finnaly consider my game engine done, this happens : rx480, i3 7100 rendering 40 * 25 quads with 29 fps. I am using OpenTK and this is my render Engine code:

public static void Render(Entity model, int x = 0, int y = 0, int sx = 0, int sy = 0)
    {
        if (sx == 0 || sy == 0)
        { 
        sx = model.texture.Width;
        sy = model.texture.Height;
        }
        Bind(model.texture, x, y, sx, sy);
        GL.Rotate(model.rX, 0, 0, 1);
        GL.Begin(PrimitiveType.Quads);
        GL.TexCoord2(0f, 0f);
        GL.Vertex2(model.vertices[0] + model.position);
        GL.TexCoord2(1f, 0f);
        GL.Vertex2(model.vertices[1] + model.position);
        GL.TexCoord2(1f, 1f);
        GL.Vertex2(model.vertices[3] + model.position);
        GL.TexCoord2(0f, 1f);
        GL.Vertex2(model.vertices[2] + model.position);
        GL.End();
        GL.Rotate(0 - model.rX, 0, 0, 1);
    }

    private static void Bind(Bitmap bitmap, int X, int Y, int SizeX, int SizeY)
    {

        GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (float)TextureMinFilter.Nearest);
        GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (float)TextureMagFilter.Nearest);

        BitmapData data = bitmap.LockBits(new Rectangle(X, Y, SizeX, SizeY),
       ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppPArgb);

        GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, data.Width, data.Height, 0,
            OpenTK.Graphics.OpenGL.PixelFormat.Bgra, PixelType.UnsignedByte, data.Scan0);

        bitmap.UnlockBits(data);
    }

    public static void Render(TextElement text)
    {
        Render(new Entity(text.verts, text.pos, text.rot, text.prerender));

    }

    public static void Render(Sprite sprite, int state, Display disp)
    {
        Vector2[] vec = {
            Vector2.Zero,
            new Vector2(((float) sprite.spriteSize.Width / disp.w.Width), 0),
            new Vector2(0,((float) sprite.spriteSize.Height / disp.w.Height)),
            new Vector2(((float)sprite.spriteSize.Width / disp.w.Width), ((float)sprite.spriteSize.Height / disp.w.Height)),
        };
        Entity ent = new Entity(vec, sprite.position, sprite.rot, sprite.texture);

        Render(ent,(int) sprite.states[state].X, (int) sprite.states[state].Y, sprite.spriteSize.Width, sprite.spriteSize.Height);
    }

    public static void Render(TerrainCamera cam, Tile[] tiles, Scene scene, Size size, Display d, Scene[] LightScene)
    {
        Vector2[] states = {Vector2.Zero };
        for (int x = 0; x < size.Width; x++)
        {
            for (int y = 0; y < size.Height; y++)
            {

                Vector2 pos = new Vector2((float)(x * tiles[0].Textures[0].Width) / d.w.Width, (float)(y * tiles[0].Textures[0].Height) / d.w.Height);
                Sprite ent = new Sprite(tiles[cam.GetTile(x, y, scene)].Textures[tiles[cam.GetTile(x, y, scene)].animState], new Size(tiles[0].Textures[0].Width, tiles[0].Textures[0].Height), states, 0, pos);
               Shader(pos.X, pos.Y, tiles[0].Textures[0].Width / d.w.Width, tiles[0].Textures[0].Height / d.w.Height, Color.FromArgb(254, LightScene[0].Level[x, y], LightScene[1].Level[x, y], LightScene[2].Level[x, y]));
                Render(ent, 0, d);
                GL.Color4(1f, 1f, 1f, 1f);
            }
        }
    }

    public static void Shader(float X, float Y, float SizeX, float SizeY, Color ShaderColor)
    {
        GL.Color4(ShaderColor);
        GL.Begin(PrimitiveType.Quads);
        GL.Vertex2(X, Y);
        GL.Vertex2(X + SizeX, Y);
        GL.Vertex2(X + SizeX, Y + SizeY);
        GL.Vertex2(X, Y + SizeY);
        GL.End();

    }

VSync turned off. I think I am overloading the cpu creating new sprites. Even with ShaderQuads off the fps is still terrible. Should I use texture Coordinates? I am also rendeing text with GDI+ (not the best for performance). My old tilemapping game did just fine with the same number of quads and shaders(200 fps). Can I save Time Binding the textures?

Could you help me please?

Gizego
  • 17
  • 5

1 Answers1

1

You're using immediate mode drawing commands, i.e. glBegin(…), glVertex(…), glEnd(). Performance is eaten up by the function call overhead. Start using vertex arrays, ideally contained in buffer objects (VBOs) and batch your draws into the least number of glDraw…(…) calls possible.

Another problem is, that your Bind method recreates the texture object anew (glTexImage creates a completely new texture object) for each and every drawing call. Creating texture objects is expensive! Just create the texture object once and just bind it when you need it (glBindTexture).

datenwolf
  • 159,371
  • 13
  • 185
  • 298
  • Thanks a lot. I am going to port a old java opengl code with vaos and vbos. How do I shade without the color command? Do I need GLSL Shaders? How do I generate a texture from a bitmap (BindTexture just uses textureID) How do I place a bitmap in gpu memory with that texture ID? – Gizego Dec 24 '17 at 17:55
  • What about indices rendering – Gizego Dec 24 '17 at 18:13
  • @Gizego: The way your `Bind` method works is based on *ancient* OpenGL-1.0 (obsolete since 1996), which didn't have texture objects. Essentially what you have to do is using `glGenTextures` to create texture object names (OpenGL calls numerical IDs/handles "names"), then bind a name with `glBindTexture`. With that done `glTexImage…` loads the texture into that object. Later to use it you just have to call `glBindTexture` with the same name again and that's it. – datenwolf Dec 24 '17 at 20:44
  • 1
    Why do people remove reputation from questions with sense? – Gizego Dec 25 '17 at 12:25
  • 1
    This is not exactly correct. Proper use of immediate mode is very fast. Even with glVertex() calls. The problem in the code above lies in the op uploading bitmaps on for essentially every quad. Not even binding different textures, but quite literally recreating textures. As well as doing full matrix multiply twice per rendering a single quad. – JBeurer Jan 14 '18 at 14:58
  • The whole code written by the OP is like a "best of" collection of bad coding practices. It has completely unnecessary memory allocations all over the place. Function drawing a quad is called "Shader" among other completely insane things. – JBeurer Jan 14 '18 at 15:01
  • Ancient OpenGL 1.1 can be really fast (tens of thousands of sprites) quite effortlessly. Introduction of glDrawArrays in OpenGL 1.1 is sufficient for pretty much all basic 2D rendering work. No need for VBOs and VAOs since for 2D usually all the vertices are recreated every frame anyway. – JBeurer Jan 14 '18 at 15:06
  • 1
    @JBeurer: The problem with the use of immediate mode these days is, that it does not reflect the way modern GPUs operate. The original IrixGL immediate mode API design was a close match of how the SGI rasterizer hardware operated back then. Today when using immediate mode `glBegin()` essentially creates a set of arrays (one for each vertex attribute touched) and calls to `glVertex` commit-append the next value tuple to these arrays. `glEnd()` then effectively loads the array into a VBO/VAO and executes. – datenwolf Jan 14 '18 at 15:39
  • 1
    @datenwolf, that is true. The appeal of OpenGL 1.1 is that it reduces amount of code necessary. Vulkan type API reflects how GPUs operate even more accurately with even less overhead. Does that mean that we all should be using Vulkan? Of course not. OpenGL 1.1 has a nice, sane and pleasant API which is quite performant as long as you have a basic understanding of what you're doing. And it reduces all the boilerplate when making fairly simple 2D (or perhaps even lowpoly 3D) games or tools. – JBeurer Jan 14 '18 at 15:51