MapBuffer works but not BufferSubdata

See the code sample:


//////////////////////////////////////////////////////////////////////////////
inline void GLVBOHandlera::load_resource_into_vbo(
  vboresourceid_type resource_id)
{
  ResourceInfo& resource(resources[resource_id]);

  BOOST_ASSERT(resource.orphan_id != orphan_id);

//std::cout << "loading: " << resource_id << std::endl;

  resource.orphan_id = orphan_id;
  resource.vbo_ptr = current_ptr;

/*
  boost::uint8_t* buffer_ptr(boost::reinterpret_pointer_cast<boost::uint8_t>(
    glMapBufferARB(GL_ARRAY_BUFFER, GL_WRITE_ONLY)));
  std::memcpy(buffer_ptr + std::size_t(current_ptr), resource.client_ptr,
    resource.client_size);
  glUnmapBufferARB(GL_ARRAY_BUFFER);
*/

  glBufferSubData(GL_ARRAY_BUFFER,
    GLintptr(current_ptr), resource.client_size, resource.client_ptr);

  current_ptr += resource.client_size;
}

If I use glMapBuffer() everything works, but if I use glBufferSubData() , some batches I upload don’t render. What could be the cause? No errors are reported by the GL. The traces also make sense. The bug occurs both on Windows and Linux. But I tested on 1 card/driver combo only.

Maybe the reason is my use of a caching VBO? Specifically, the batches are processed like this:

  • load batch into VBO if not already there
  • render batch

Maybe GL is freaked by me trying to update a VBO that something is already being rendered from?

EDIT:

If I add the following check after glBufferSubData():


  boost::uint8_t const* buffer_ptr_(
    boost::reinterpret_pointer_cast<boost::uint8_t>(glMapBufferARB(
    GL_ARRAY_BUFFER, GL_READ_ONLY)));
  BOOST_ASSERT(!std::memcmp(buffer_ptr_ + std::size_t(current_ptr),
    resource.client_ptr, resource.client_size));
  glUnmapBufferARB(GL_ARRAY_BUFFER);

It passes! But the batch still will not render.

This looks like a driver problem so far. Yeah, Photon’s benching/testing comes into play here.

Yeah, that’s weird. If there’s a bug in your code, I sure don’t see it.

With your Map/cmp/Unmap hack working, that suggests to me too that it’s a driver issue. Using a glFinish there instead might also clear it up, but would be even more of a hack.

Say, why are you trying to use SubData?

Yeah, I’ll try the glFinish() hack.

I try to use SubData(), as I have benched that it loaded the caching VBO about a whole millisecond faster on my system than MapBuffer() when cache misses occurred on my nvidia system ( now it’s broken down). Usually, this is not an issue though, as the caching VBO approach works great most of the time, i.e. in most cases the difference between the two approaches is not significant. Still, both approaches ought to work. Interestingly, I’ve noticed this text about SubData():

Consider using multiple buffer objects to avoid stalling the rendering pipeline during data store updates. If any rendering in the pipeline makes reference to data in the buffer object being updated by glBufferSubData, especially from the specific region being updated, that rendering must drain from the pipeline before the data store can be updated.

It is from the GL 2 man pages. Maybe this means, that only MapBuffer() is suitable for VBO caching. I haven’t noticed anything such for MapBuffer(). On the other hand, the driver this fails with is the latest ATI beta for windows and linux…

It still shouldn’t misbehave. Probably an ATI driver bug.

Though if you’re talking about caching multiple batches in a single VBO buffer, I’d think MapBufferRange (with careful selection of flags) is really the API to use.