efel
efel

Reputation: 1106

opengl3 20k sprites slow framerate?

I have successfully made an opengl 3.x animation in golang. However; the frame by frame update is noticeably slow only after 20k textures rendered. All the sprites do is simply move from the left side of the screen to the right. Keep in mind they are all on top of each other because i was too lazy to randomize location.

I have an updated PC that can run GTA5 on high settings but cannot display 20k sprites (quads with textures) in opengl3 environment??

I must be doing something wrong here. Maybe I need to pack all vertices in one VBO instead of a new vbo for each object? I bindbuffers every object as well. I'm not really sure what is causing this bottleneck. Can someone help as i'm not sure where to go from here?

I have attached my code as reference for anyone that can give some tips on speeding up rendering of 20k sprites in opengl3: http://pastebin.com/SHQtRPn7

Upvotes: 0

Views: 278

Answers (3)

Joonazan
Joonazan

Reputation: 1416

OpenGL calls are expensive. You're doing lots of them ten thousand times in every single frame. Instead you want to do one big draw call if possible. If not, one draw call per textures + program combination.

Instead of passing a matrix as uniform, you can pass a matrix for each object you draw.

This code is not as good as it could be, but it performs orders of magnitude better than yours.

func (drawer *SpriteDrawer) Draw(sprites []Sprite) {
    if len(sprites) == 0 {
        return
    }

    drawer.Use()
    drawer.Texture.Bind(gl.TEXTURE_2D_ARRAY)

    tmp := drawer.GetTransform().To32()
    drawer.camera_uniform.UniformMatrix2x3f(false, &tmp)

    vertexbuffer := gl.GenBuffer()
    defer vertexbuffer.Delete()
    vertexbuffer.Bind(gl.ARRAY_BUFFER)

    stride := int(unsafe.Sizeof(sprites[0]))

    gl.BufferData(gl.ARRAY_BUFFER, stride*len(sprites), sprites, gl.STREAM_DRAW)

    var transform1, transform2, texcoords, texlevel gl.AttribLocation
    transform1 = 0
    transform2 = 1
    texcoords = 2
    texlevel = 3

    transform1.AttribPointer(3, gl.FLOAT, false, stride, unsafe.Offsetof(sprites[0].Transform))
    transform2.AttribPointer(3, gl.FLOAT, false, stride, unsafe.Offsetof(sprites[0].Transform)+unsafe.Sizeof(sprites[0].Transform[0])*3)
    texcoords.AttribPointer(4, gl.FLOAT, false, stride, unsafe.Offsetof(sprites[0].TextureLeft))
    texlevel.AttribPointer(1, gl.FLOAT, false, stride, unsafe.Offsetof(sprites[0].Layer))

    transform1.EnableArray()
    transform2.EnableArray()
    texcoords.EnableArray()
    texlevel.EnableArray()

    gl.DrawArrays(gl.POINTS, 0, len(sprites))

    transform1.DisableArray()
    transform2.DisableArray()
    texcoords.DisableArray()
    texlevel.DisableArray()
}

library this is from

Upvotes: 2

Jas
Jas

Reputation: 870

One problem which I see is that you are creaing a vbo per every frame. Im not sure what you are trying to do. If you are trying to update your vbo, use glBufferSubData() instead. glBufferData() creates a new buffer every time you call it so it will be more expensive than glBufferSubData() for sure. glBufferSubData() just modifies/updates your vbo. This should give your fps a boost.

Upvotes: 1

SurvivalMachine
SurvivalMachine

Reputation: 8356

Without looking at source code, you should use one VBO and combine geometry for all sprites that share a texture and draw them using one draw call.

Upvotes: 2

Related Questions