Jump to content
  • Advertisement
Sign in to follow this  
Uthman

OpenGL VBO / IBO Woes

This topic is 2860 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi guys. This is my first post on gamedev in years (literally -- my last 3 posts were in 2007, one post in 2006, then a bunch in 2005), so it's great to be back in 'the game' after going through many many life altering experiences

So, my question today is about opengl's vertex buffer objects. I've read every tutorial on the internet for every different platform that exists, but I couldn't resolve this issue.

I have a custom vertex class which include some (but not much) extra garbage in it, in addition to the VNT data:


class Vertex {
int stuffA;
float pos[3];
float tc[2];
float n[3];
int stuffB;
};

class Tri {
unsigned short v[3];
};


Since there isn't too much extra data in the 'stuffs' and since i am not loading up huge models, i don't mind just dumping all of the data into my VBO:


Vertex verts[3]; Tri tris[1]; /* initialize both with data.. */
GLuint vertexBuffer = 0;
GLuint indexBuffer = 0;

glGenBuffersARB(1, &vertexBuffer);
glBindBufferARB(GL_ARRAY_BUFFER_ARB, vertexBuffer);
glBufferDataARB(GL_ARRAY_BUFFER_ARB, 3*sizeof(Vertex), verts[0].pos, GL_STATIC_DRAW_ARB);

glGenBuffersARB(1, &indexBuffer);
glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, indexBuffer);
glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, sizeof(unsigned short)*3, tris[0].v, GL_STATIC_DRAW);


Finally, in my main loop, I render everything. Now, here is the issue -- the structure of my Vertex class may (and most likely will) be changing in the near future. In order to save me much headache, I've been using the offsetof() function defined in stddef.h to get my byte offsets. I assumed this would work, but my project keeps crashing. Now here is there interesting part --- if I move member variable 'stuffA' to the end of the class, the program doesn't crash! What am I doing wrong??


glBindBufferARB(GL_ARRAY_BUFFER, vertexBuffer);
glEnableVertexAttribArrayARB(0);
glVertexAttribPointerARB(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex,pos) );

glEnableVertexAttribArrayARB(1);
glVertexAttribPointerARB(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex,n) );

glEnableVertexAttribArrayARB(2);
glVertexAttribPointerARB(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex,tc) );

glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_SHORT, (void*)offsetof(Vertex,pos) );


As always, thank you for any assistance provided ahead of time, and your help is greatly appreciated =)

Share this post


Link to post
Share on other sites
Advertisement
Why are you trying to feed your custom struct into a VBO? You'd be much better off piping your vertex data to tightly packed arrays (at least temporarily).

GLfloat* vertices = new GLfloat[numVertices * 3];


Do you plan on holding all that vertex data in memory the whole time?

Don't push your structs into VBOs. That's just asking for trouble.

Share this post


Link to post
Share on other sites
In the above example, static_draw was used; however in production, stream_draw will be used for the vertices and static_draw for the indicies. Position and normals will be updated, and textures will most likely remain static.

I am aware that the best practice would be to create a tightly packed VBO of (position and normals) and create that using stream_draw, and then create a texture VBO which would be static_draw and create the IBO which would also be static (3 VBO's total).

But for this specific implementation, my primary concern is that I cannot figure out what is causing the code to break and GL to explode =/.

Share this post


Link to post
Share on other sites
Quote:
Original post by Uthman
But for this specific implementation, my primary concern is that I cannot figure out what is causing the code to break and GL to explode =/.


But that is my primary concern. I guess I just have a tunnel-vision biased way of approaching VBOs given my background, but looking at your code, I just struggle to see how it ever would work, much less why it is failing specifically.

removed -- I misinterpreted part of the problem.

Share this post


Link to post
Share on other sites
In fact optimial performance for vertex shader comes from interleaving your custom struct into the VBO, as it will be a cache hit for all data members on each shader pass.

If you pack all "positions" into a big array, and normal in another big array and pass them to your VBO, cache will have a miss for each vertex attribute data, thus fetching will be slower, resulting in a worse performance for the VBO.

As for your question, what do you mean by it explodes?

Share this post


Link to post
Share on other sites
Quote:
Original post by kilah
In fact optimial performance for vertex shader comes from interleaving your custom struct into the VBO, as it will be a cache hit for all data members on each shader pass.

If you pack all "positions" into a big array, and normal in another big array and pass them to your VBO, cache will have a miss for each vertex attribute data, thus fetching will be slower, resulting in a worse performance for the VBO.


This might be true for when the data is stored in memory outside the GPU, but are you sure the data stays that way once it is piped over to the GPU itself?

Plus, correctness is more important than speed. Optimization comes later. ;)

Share this post


Link to post
Share on other sites
Sure he needs to get his things done before trying more complex behavior I agree with you there, testing non interleaved data is less error prone than doing specific optimizations.

As for interleaving VBOs and driver behavior: OpenGL drivers have full freedom on how they handle inner data of their VBOs. Yet that doesn't mean that they do optimize on language allowed behaviors.

As for my personal experience, data seems to raw streamed into driver selected memory and then copied to cache as a block, as cache optimizations for memory alignment seems to increase performance of the VBOs a LOT. Looks like drivers take a DMA approach on VBO data mapping, yet I might be wrong.

In short: if language allows interleaving data, driver will not bother to do so, as it is allowed by the language itself.

Share this post


Link to post
Share on other sites
By explode, I meant the call stack crashes right into opengl assembly code.

I think the above example is simple enough that it should work without causing any errors. There are other examples on the net that have verbatim duplicate code, just without two ints packed into the Vertex structure that work.. I'm unable to see what is causing the code to break

Check out this program on opengl.org for example; the originator has his vertex class padded to 64 bytes using 4 floats.

-------------

So I've made some progress. The Drawelements call needed to point to the start of my ibo, not to the byte offset of my position vector. That helped stop the program from crashing:


glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_SHORT, (void*)0 );


However, now, when stuffA is in the beginning of the Vertex class, nothing is drawn. When it is at the end of the class, the triangle is drawn as usual.

Share this post


Link to post
Share on other sites
to me what you just mentioned looks like 3 possible errors:

- Wrong element copy into your struct.
- Wrong vertex shader attribute read
- Wrong offset on interleaved data.

Check this 3 possibilities, which I am pretty sure they are the reason of your troubles right now

Share this post


Link to post
Share on other sites
You were right:
- Wrong element copy into your struct.
- Wrong offset on interleaved data.

These two were correct. The problem was here:
- Wrong vertex shader attribute read

I was mixing GLES1.1 with GLES2.0. I don't have any vertex or fragment shader programs, because this is a gles1.1 application. Instead of using glEnableVertexAttribArrayARB / glVertexAttribPointerARB, I should have been using the deprecated glEnableClientState / glVertexPointer. Once I made the appropriate switch, everything seemed to work, and I could put my class member variables in any order and pack all sorts of ridiculous data in there that shouldn't even be on the gpu to begin with without breaking my program.

Cheers !

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!