Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I am programming in C++ OpenGl with GLSL. Until now I have been using a data structure that is composed of std::vector filled with structures of vertexes and with their parameters (position , normal, color ...) as a global variable for all the code. My question is, as I am using VBOs for drawing - is this a good approach to this problem?

I am asking because I happen to have a lot of memory related trouble with this structure. I am trying to generate a terrain with a lot of vertices - more than 1 million. This seems to work, but as I refill the buffer I get memory related issues (crushes that occur, more or less randomly).

So again the question is, is this a good data structure to use / and look for the faults in my code, or should I change to something else? Or what data structure would be advisable?

share|improve this question
    
do you "refill" with push_back()? because if so then you might be constantly reallocating close to 100MB of memory when loading the last vertices –  dreta Sep 23 '12 at 18:57

4 Answers 4

std::vectors work great.

They have performance at about the same level as a raw c-style array as internally they are basically just a c-style array. There are a few points though.

  • Make sure you allocate their size up front when possible either at construction or with std::vector::resize (or even better use reserve). By default vectors grow exponentially since they are a continuous block of memory at each resize they will need to copy every element across.

  • The std::vector functions are bounds checked, this might cause slowdowns however you still have access to the c-style methods so you can sacrifice bounds checking for speed. Use vector::[] rather than vector::at(x).

  • float* vertices = &vector[0]; Will give you the raw C array for use in whatever functions you want.

  • C++11 has uniform initialization which makes the syntax for initializing the vectors with fixed data much nicer since you don't have to push_back everything. But it's no use for reading data in from a file or generating at runtime.

Consider looking at GLM for your base vertices vector type (as in x,y,z vector, not std::vector) type. It's a linear algebra library based on GLSL and is part of the OpenGL SDK (officially recommended support libraries) so it's about as official as you can get. It also has matrix operations which is useful as with modern OpenGL things like glRotate, glTranslate, glPushMatrix, glPopMatrix have all been removed from the core profile. It's very optimized and also has some noise generation functions.

share|improve this answer
    
Just a note on vector resize copying - actually, for each added element, the copy constructor is called. This has the additional weight (according to the old standard, at least) of extra allocations in such cases as containers are nested (std::vector<std::string> and such). As you can imagine, each container element will be fully copied and reallocated. And since vector copy operation can't use memcpy, it is sub-optimal with POD types too. Also, bounds are checked only in debug builds. –  snake5 Sep 23 '12 at 18:35
1  
@snake5: "for each added element, the copy constructor is called" - not in compilers supporting rvalue references (the move constructor will be called). "since vector copy operation can't use memcpy" - C++ containers may specialize on std::is_pod and therefore use memcpy for POD types; I don't know if any standard vector implementations do this today. "bounds are checked only in debug builds" - std::vector::at, which David refers to, always check bounds. –  user744 Sep 23 '12 at 19:15
    
Ah, you're right. I had once indeed found that specialization in STL that comes with MSVC 2010. And about that std::vector::at - found out that it can actually throw an exception. So it seems to be inappropriate for game development - stackoverflow.com/questions/5257190/… –  snake5 Sep 24 '12 at 0:31

I've had a quick look at VBOs in OpenGL and they seem to be a good way to transfer large amounts of vertices to the Driver. They rely on all the stuff you passed being in one contiguous block of memory.

You're wondering is the STL vector class a good fit? Well it is if you can treat it as single contiguous block of memory for passing to the functions that OpenGL will use for transferring Vertex data between your array and the VBO. So can you do that with a std vector class? According to its documentation:

vector containers have their elements stored in contiguous storage locations, which means that their elements can be accessed not only using iterators but also using offsets on regular pointers to elements.

Thats good news. You can get the memory address of the start of this array ising the techniques shown in the code below. After that fast operations are permitted such as calling memcpy or passing this address to OpenGL.

typedef struct {
  long double x, y, z;
} V3;


int main (int argc, const char * argv[])
{
 const int nElems = 100000;
 vector<V3> vec(nElems);
 V3 v;
 V3 *pv = &vec[0];
 for (int i = 0; i < nElems; i++) {
   pv[i] = v;
 }
 pv = &vec[0];
 vector<V3> vec2(nElems);
 V3 *pv2 = &vec[0];
 memcpy(pv2, pv, sizeof(V3)*nElems);
}

I would stick with it for the moment. Its not the cause of this problem:

I get memory related issues(crushes that occur, more or less randomly).

If its crashing at least you can trap it in the debugger.

share|improve this answer

It is a good enough data structure. For any problems you're having with it, I'd suggest you just run your app in debug mode. If you're doing some byte-fu (copying/modifications) with vector's data, you should check that before everything else. Otherwise, vector has enough assertions placed to let you know where the problem is.

share|improve this answer

In addition to the notes given in the other answers about use of std::vector, you seem to have a problem in that you're refilling your VBOs every frame.

This is not a good use-case of VBOs (you almost may as well be using old-fashioned client-side arrays, in fact). You need to look at keeping your data static; fill VBOs once-only at load time then use the already-filled VBOs for drawing (if you need to do any animation of data in a vertex then move the animation from the CPU to shader code).

If you want to only draw a subset of data each frame, then you'll get more performance by using a GL_ELEMENT_ARRAY_BUFFER, which can be dynamic, but make sure that you're using a proper buffer-streaming setup for this (see http://www.opengl.org/wiki/Buffer_Object_Streaming for further information).

Now, to some this may seem "wasteful" - you're keeping static data in GPU memory that may not be accessed during the current frame. Don't fall into that trap; view a VBO as being like a cache instead; the data may not be needed immediately, but there's a high chance that it will be needed soon, and when that time comes it'll be there, ready and waiting for you.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.