3
$\begingroup$

I'm sending a large number of data to the vertex shader. I use glBufferData to generate my VBO. Later on I have to replace the data in my VBO so I do the following:

glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferSubData(GL_ARRAY_BUFFER, sizeof(glm::mat4) * models().size(), &models[0], GL_DYNAMIC_DRAW);

What I noticed is when I used the above code (I'm assuming) that some of the previous data is left in the VBO because I not only draw the new objects I want to but also some of the old ones.

Therefore I had to change my code to the following:

glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(glm::mat4) * models().size(), &models[0], GL_DYNAMIC_DRAW);

The reason I don't like the above aproach is because according to Khronos

When replacing the entire data store, consider using glBufferSubData rather than completely recreating the data store with glBufferData. This avoids the cost of reallocating the data store.

How do I replace the whole VBO with my new data, but if my new data is smaller than the old data then how do I reallocated the VBO efficiently? Or is there something equivalent to a NULL terminating character where the graphics card can know not to read any further data?

The reason I ask this is because from my understanding glBufferStorage is like glBufferData except that the data store generated by glBufferStorage is immutable meaning that the size of the data store cannot be changed, as stated on Khronos and on Stackoverflow.

glBufferStorage and glNamedBufferStorage create a new immutable data store.

But if glBufferData creates a data store which cannot shrink in size then what's the point of it? (Unless I'm misunderstanding its intended use)

$\endgroup$
2
$\begingroup$

There is a difference between "can" and "should".

You "should" not use glBufferData to change the size of an existing non-immutable buffer. You can still do so, but don't expect this to be advantageous.

You "can" not change the size of an immutable buffer with any function.

How do I replace the whole VBO with my new data, but if my new data is smaller than the old data then how do I reallocated the VBO efficiently?

Why would you want to? If the size of your data got smaller, then it is entirely possible that a few frames from now it will be bigger again. Perhaps bigger than it was before. That extra storage isn't waste; it is extra storage you're keeping around because you intend to use it at some point in the future.

The cost of allocating memory is high; you should avoid it whenever possible. If you need to increase the size of a buffer, then the implementation must allocate new storage for it. You want to avoid that whenever possible.

What you ought to be doing is figuring out what a reasonable maximum size would be for this data, and then allocate a buffer of that size.

Or is there something equivalent to a NULL terminating character where the graphics card can know not to read any further data?

That's up to you. You tell OpenGL exactly how many vertices to read from a vertex buffer. This is determined based on:

  1. The vertex format for each attribute.
  2. The offset within the buffer for each attribute.
  3. The number of vertices you send in the glDraw* command.

OpenGL doesn't arbitrarily process data; it reads the data you tell it to read. If you want it to not read past a certain point, stop telling it to read past that point ;)

$\endgroup$
  • $\begingroup$ Assume I have a data store of size 2MB then I use glBufferSubData to add new data which is 1.5MB. Wouldn't there be an extra 0.5MB of data in the data store which I don't potentially want to draw? $\endgroup$ – Archmede Jan 23 '18 at 0:25
  • $\begingroup$ or I suppose that where I'd just draw less primitives with glDraw*. Is that correct? $\endgroup$ – Archmede Jan 23 '18 at 0:43
  • 1
    $\begingroup$ @Archmede: Why would you draw using data that you don't want to draw from? $\endgroup$ – Nicol Bolas Jan 23 '18 at 1:04
  • $\begingroup$ My specific scenario is I fill data with terrain (like minecraft) but when I move somewhere else on the map I'll refill the data store with new terrain but this new terrain might contain less data than the old terrain. So wouldn't there be some data from the old terrain left in the data store if the new terrain contained less data? Make sense? $\endgroup$ – Archmede Jan 23 '18 at 1:37
  • $\begingroup$ So what if there's old data there? Why would you tell OpenGL to read from the old data? As I said, "You tell OpenGL exactly how many vertices to read from a vertex buffer." So why would you tell OpenGL to read from part of a buffer that doesn't contain relevant data? $\endgroup$ – Nicol Bolas Jan 23 '18 at 1:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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