Part of the Khronos Group
OpenGL.org

The Industry's Foundation for High Performance Graphics

from games to virtual reality, mobile phones to supercomputers

Results 1 to 10 of 23

Thread: Buffer vs immediate

Hybrid View

  1. #1
    Junior Member Newbie
    Join Date
    Jun 2012
    Posts
    16

    Buffer vs immediate

    I have a stream of points coming in. I need to know which method is the best way to render them.

    I know VBO is much much more efficient than using immediates, but as I said I have a constant stream of points coming in so afaik if I used VBO I would either need to create an array with a size large enough for the max potential points on the screen at one time (then to remove or add a point Id have to search through the whole thing) or recreate the vertex array everytime it is updated. These both seem very very inefficient. And I'm pretty sure there is a better way of doing this that I do not know of...

    Currently I just have an ever changing deque of points that I iterate through as I define vertexs for immediate rendering.

    Whats the best method for rendering an ever changing (new additions and removals) list of verticies (rendered as points)?

  2. #2
    Senior Member OpenGL Pro
    Join Date
    Jan 2007
    Posts
    1,183
    A VBO would still be preferable. You don't have to create one that's large enough for your hypothetical max number of points; just create one that's a nice size for a comfortable amount of points - say, 65536 or thereabouts (you can experiment with different values and tune it to what would work best for you). Make it GL_STREAM_DRAW and your initial BufferData call specifies NULL data.

    At the start of the frame, MapBufferRange it with invalidate buffer, unsynchronized and write-only. Do nothing else yet - definitely don't unmap. Also, keep a counter and init it to 0 here.
    Each time you recieve a point, write it to the mapped VBO pointer, increment the pointer by one and the counter by one.
    If the counter == the max you can hold in the buffer, unmap, DrawArrays, MapBufferRange again (same params - invalidate/unsynch/write-only) and reset the counter to 0.
    At the end of the frame, if the counter is non-0, just unmap and DrawArrays.

    That will do it and give you very good performance.

    If this doesn't suit your usage requirements, you can modify the pattern slightly. For example, you may not be recieving the full stream of points each frame and may need to keep previously received points for more than one frame, so the solution is to retain your existing list as-is, add/remove points from it as required, then when time comes to draw the list just iterate through it using the same pattern as above: MapBufferRange, add point to buffer, check for full, draw and re-init if full, draw anything left over.

    If this seems confusing I'll happily provide sample code.
    Last edited by mhagain; 06-26-2012 at 11:02 AM.

  3. #3
    Junior Member Newbie
    Join Date
    Jun 2012
    Posts
    16
    I have never used a Buffer object setup before so I have a few questions bout where to place certain functions.

    From what Ive read, I know Ill need to call:
    glGenBuffers
    glDeleteBuffers
    glBindBuffer
    glBufferData
    glVertexPointer
    glEnableClientState
    glDrawArrays
    glDisableClientState

    But I have no clue when or how often I need to call these, which will need to be called in my Draw() method and which should be initialized at the start of the program?

  4. #4
    Senior Member OpenGL Pro
    Join Date
    Jan 2007
    Posts
    1,183
    Easiest way is to use something like GLEW to get the function pointers. I assume from your mention of glEnableClientState that you're not using (or proposing to use) generic attrib arrays, so try this for size:
    Code :
    // your point struct might look something like this
    struct drawpoint
    {
        float position[3];
        unsigned char color[4];
    };
     
    // to do - experiment with different sizes and tune for best perf
    #define MAX_POINTS    65536
     
    // let's not have code stretching 4 miles across the screen
    #define BUFFER_MAP_BITS (GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT | GL_MAP_INVALIDATE_BUFFER_BIT)
     
    // using a vector here; just change it to whatever container type you prefer
    std::vector<drawpoint> myWonderfulPoints;
    GLuint pointsvbo = 0;
     
    // call this once only at startup
    void CreateMeABuffer (void)
    {
        glGenBuffers (1, &pointsvbo);
        glBindBuffer (GL_ARRAY_BUFFER, pointsvbo);
        glBufferData (GL_ARRAY_BUFFER, MAX_POINTS * sizeof (drawpoint), NULL, GL_STREAM_DRAW);
        glBindBuffer (GL_ARRAY_BUFFER, 0);
    }
     
    // call this every frame to draw stuff!
    void DrawMeSomePoints (void)
    {
        drawpoint *bufpoints = NULL;
        int pointcount = 0;
     
        glBindBuffer (GL_ARRAY_BUFFER, pointsvbo);
     
        glEnableClientState (GL_VERTEX_ARRAY);
        glEnableClientState (GL_COLOR_ARRAY);
     
        // because bufpoints points to NULL here, this will work (yes, I did test it)
        glVertexPointer (3, GL_FLOAT, sizeof (drawpoint), bufpoints->position);
        glColorPointer (4, GL_UNSIGNED_BYTE, sizeof (drawpoint), bufpoints->color);
     
        if ((bufpoints = (drawpoint *) glMapBufferRange (GL_ARRAY_BUFFER, 0, MAX_POINTS * sizeof (drawpoint), BUFFER_MAP_BITS)) == NULL)
        {
            // error handling here - suggest falling back to immediate mode?  don't forget to call glBindBuffer (GL_ARRAY_BUFFER, 0) and glDisableClientState!
            return;
        }
     
        // you may prefer to use a proper iterator here
        for (int i = 0; i < myWonderfulPoints.size (); i++)
        {
            // adds current point to buffer
            memcpy (&bufpoints[pointcount], &myWonderfulPoints[i], sizeof (drawpoint));
     
            // go to next slot in buffer
            pointcount++;
     
            // check for potential overflow
            if (pointcount == MAX_POINTS)
            {
                // draw what we got so far
                glDrawArrays (GL_POINTS, 0, pointcount);
     
                // re-init buffer and counter
                if ((bufpoints = (drawpoint *) glMapBufferRange (GL_ARRAY_BUFFER, 0, MAX_POINTS * sizeof (drawpoint), BUFFER_MAP_BITS)) == NULL)
                {
                    // error handling here - if this fails we've got bigger problems on our hands than not being able to get a usable pointer!
                }
     
                pointcount = 0;
            }
        }
     
        // draw anything left over
        if (pointcount) glDrawArrays (GL_POINTS, 0, pointcount);
     
        glDisableClientState (GL_VERTEX_ARRAY);
        glDisableClientState (GL_COLOR_ARRAY);
     
        glBindBuffer (GL_ARRAY_BUFFER, 0);
    }
    Last edited by mhagain; 06-26-2012 at 11:54 AM.

  5. #5
    Junior Member Newbie
    Join Date
    Jun 2012
    Posts
    16
    Ah, I cannot thank you enough. That code cleared so much up about Buffer Objects and how to implement them!

    You mentioned the built in vertex atributes... I opted not to use them because I really only need position and color so I assumed defining my own would be more efficient in both memory and speed. Is this correct or does OpenGl perform better with vertices defined using a generic vertex attribute array?

  6. #6
    Senior Member OpenGL Pro
    Join Date
    Jan 2007
    Posts
    1,183
    It doesn't really matter much to be honest. Generic attribs are more flexible and don't tie you to horrible things like abusing extra TexCoordPointers for packing in additional data, and everything that can be done with conventional attribs can also be done with generic attribs too (they also enable you to make the horrible glClientActiveTexture API call go away from your code). Plus they're friendlier for modern OpenGL so if you're thinking of heading in that direction it's not a bad idea to start getting used to them.

  7. #7
    Junior Member Newbie
    Join Date
    Jun 2012
    Posts
    16
    Turns out I only have access to OpenGL 1.4 with ARB extenstions. Should I skip VBO and just use standard vertex arrays?

    (glBindBuffer, GL_ARRAY_BUFFER, and a few others are undefined in this version as I do not have access to glew.h)
    Last edited by Beiufin; 06-27-2012 at 08:55 AM.

  8. #8
    Senior Member OpenGL Pro
    Join Date
    Jan 2007
    Posts
    1,183
    Probably best to stick with standard vertex arrays, yes. There's a good chance that you don't have hardware T&L either, so you won't get much benefit from VBOs even if you could find a driver that supported them.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •