2
votes

I have my OpenGL code working but I am trying to improve its performance a bit (would like to bump up the frame-rate a bit on older devices). I am trying to do this using a Vertex Buffer Object.

All my code does is draw a series of 360 GL_TRIANGLES that have a texture applied to them. I interweave the coordinates and the texture coordinates into a data structure.

typedef struct {
    GLfloat vertex[2];
    GLfloat texture[2];
    GLfloat padding[4];
} TextureVertex2D;

typedef struct {
    TextureVertex2D textureVertex[3];
} TextureTriangle2D;

Here is the relevant part of my initialization

textureTriangles = (TextureTriangle2D*)malloc(360 * sizeof(TextureTriangle2D));

glGenTextures(1, &texture[0]);
glBindTexture(GL_TEXTURE_2D, texture[0]);

// This section is the only new code introduced for the VBOs.
glGenBuffers(1, &buffer[0]);
glBindBuffer(GL_ARRAY_BUFFER, buffer[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(TextureTriangle2D)*360, textureTriangles[0].textureVertex[0].vertex, GL_DYNAMIC_DRAW);
// end new code    

glVertexPointer(2, GL_FLOAT, sizeof(TextureVertex2D), textureTriangles[0].textureVertex[0].vertex);
glTexCoordPointer(2, GL_FLOAT, sizeof(TextureVertex2D), textureTriangles[0].textureVertex[0].texture);

/*
textureTriangles is filled and the texture image is loaded in
*/

For the saving to the actual VBO, I have tried two methods (both of which have had the same result)

// Option 1
GLvoid* vbo_buffer = glMapBufferOES(GL_ARRAY_BUFFER, GL_WRITE_ONLY_OES);
memcpy(vbo_buffer, textureTriangles[0].textureVertex[0].vertex, 360 * sizeof(TextureTriangle2D));
glUnmapBufferOES(GL_ARRAY_BUFFER); 

// Option 2
glBufferSubData(GL_ARRAY_BUFFER, sizeof(TextureVertex2D), 360 * sizeof(TextureTriangle2D), textureTriangles[0].textureVertex[0].vertex);

Then I bind the buffer

glBindBuffer(GL_ARRAY_BUFFER, buffer[0]);

And finally perform the drawing

glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);

glDrawArrays(GL_TRIANGLES, 0, 3*360);

glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);

Without the VBOs, the drawing works fine. After I add the VBO code above, the drawing is no longer in the right spot (offset by a few pixels) and it locks up my entire app. Any ideas?

2
In your glBufferSubData the second argument should be 0 instead of sizeof(TextureVertex2D). But you should use glBufferData when updating the whole buffer, anyway.Christian Rau

2 Answers

1
votes

When using VBOs, the last argument to gl...Pointer is not a pointer to some array containing the vertex data, but a byte offset into the currently bound GL_ARRAY_BUFFER. So you don't specifiy the addresses of your CPU vertex data, which you already copied into the buffer, but the offsets in this buffer data where the attributes are stored:

glVertexPointer(2, GL_FLOAT, sizeof(TextureVertex2D), 
    offsetof(TextureVertex2D,vertex));
glTexCoordPointer(2, GL_FLOAT, sizeof(TextureVertex2D), 
    offsetof(TextureVertex2D,texture));
0
votes

In this line:

glBufferData(GL_ARRAY_BUFFER, sizeof(TextureTriangle2D)*360, textureTriangles[0].textureVertex[0].vertex, GL_DYNAMIC_DRAW);

I think you should specify sizeof(TextureTriangle2D)*360*3 since each triangle (using GL_TRIANGLES in the draw array request) requires 3 vertices coordinates.

I don't have much information about passing 3D coordinates using just 2 coordinates (I guess having Z fixed to zero?) but the declaration itself should be subject to review on your side

I would have expected:

typedef struct {
    GLfloat vertex[3];
    GLfloat texture[2];
    GLfloat padding[3];
} TextureVertex2D;

But this depends a lot on your engine.