PDA

View Full Version : Persistent buffer mappings



Dark Photon
07-23-2015, 07:30 AM
My aim is to use a persistent buffer mapping to upload batch data for draw calls to the GPU.

* We're tuning for a system which doesn't support PERSISTENT | COHERENT mappings.
* It also doesn't support the GL_CLIENT_MAPPED_BUFFER_BARRIER_BIT memory barrier.
* Therefore, we're trying to use the GL_MAP_FLUSH_EXPLICIT_BIT MapBuffer flag with glFlushMappedBufferRange​ between writes to flush data to the GPU.

For background, see this short paragraph in the wiki:

* Buffer_Object_Streaming#Persistent_visibility (https://www.opengl.org/wiki/Buffer_Object_Streaming#Persistent_visibility)

So for the normal use case (omitting the "buffer full"/orphaning case here), you have:


ptr = glMapBufferRange( target, 0, length, GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT | GL_MAP_UNSYNCHRONIZED_BIT | GL_MAP_FLUSH_EXPLICIT_BIT );
offset = 0;

for batch in batches:
{
memcpy( ptr, batch_data, batch_size );
glFlushMappedBufferRange( target, offset, batch_size );
ptr += batch_size;
offset += batch_size;

...setup vertex attribs...
glDrawElements(...);
}

glUnmapBuffer( target );


The question is, is this a valid thing to do?

It's valid to issue draw calls on mapped buffers even without PERSISTENT|COHERENT, correct?

And the glFlushMappedBufferRange is supposed to make the results visible to the server/GPU, right?

The reason I ask is we've hit a driver which isn't drawing anything with the glFlushMappedBufferRange approach, but it draws perfectly with the UnmapBuffer+MapBufferRange pair per draw call. ...yet the driver (per spec) is supposed to support glFlushMappedBufferRange and GL_MAP_FLUSH_EXPLICIT_BIT. I think this is a bug, but I'm not 100% certain.

Thanks for any thoughts or ideas you might have on this!

Alfonse Reinheart
07-23-2015, 07:46 AM
It's valid to issue draw calls on mapped buffers even without PERSISTENT|COHERENT, correct?

No it is not. It is not valid to use a buffer in any way while it is mapped, unless it is persistent mapped. That's why persistent mapping was invented.

Dark Photon
07-23-2015, 08:00 AM
Ok, thanks. I did see the spec language on GL_MAP_PERSISTENT_BIT, but couldn't find the text in the spec that actually said it was an error without this to have the server read data from a mapped buffer.

A follow-up question: Then what's the point of glFlushMappedBufferRange()?

GClements
07-23-2015, 02:18 PM
A follow-up question: Then what's the point of glFlushMappedBufferRange()?
To tell the implementation you changed a particular portion of the buffer.

If the buffer is mapped with GL_MAP_FLUSH_EXPLICIT_BIT, glUnmapBuffer() will not automatically flush the entire mapped range, only the ranges which are explicitly flushed by that call.

If the buffer is mapped with GL_MAP_PERSISTENT_BIT, the client is allowed to write to the buffer while the server reads from it. But that doesn't guarantee that the client's writes will become visible to the server. For that, you need to either use a memory barrier (which may require the entire region to be flushed), unmap it (which kind of defeats the point of a persistent mapping, and also may require the entire region to be flushed), or ... use GL_MAP_FLUSH_EXPLICIT_BIT and glFlushMappedBufferRange() to flush specific ranges.

AFAICT, the general point of that call (and GL_MAP_FLUSH_EXPLICIT_BIT) is to support the use of shadow copies without requiring either flushing the entire mapped region or write snooping.

Dark Photon
07-23-2015, 05:26 PM
AFAICT, the general point of that call (and GL_MAP_FLUSH_EXPLICIT_BIT) is to support the use of shadow copies without requiring either flushing the entire mapped region or write snooping.

Hmmm, that makes some sense. Flushing at a different size and/or rate than you're mapping. Even though you still can't use the data in GL calls while the buffer is mapped.


If the buffer is mapped with GL_MAP_PERSISTENT_BIT, the client is allowed to write to the buffer while the server reads from it. But that doesn't guarantee that the client's writes will become visible to the server. For that, you need to either:
- use a memory barrier (which may require the entire region to be flushed),
- unmap it (which kind of defeats the point of a persistent mapping, and also may require the entire region to be flushed), or ...
- use GL_MAP_FLUSH_EXPLICIT_BIT and glFlushMappedBufferRange() to flush specific ranges.

Ok. Or apparently use GL_MAP_COHERENT_BIT in combination, so that the "data written to the store by either the client or server will be visible to any subsequently issued GL commands with no further action taken by the application."

Thanks for the info here, guys! It definitely helped fix up my misunderstanding.