t.niese
t.niese

Reputation: 40852

Is there any use-case for glMapNamedBuffer instead of glGetNamedBufferSubData or glNamedBufferSubData

I know that the following is UB in c++ due how the standard defines lifetime, and how objects are allowed to be used:

Foo* foo = std::reinterpret_cast<Foo *>(malloc(sizeof(struct Foo)));
// read or write to foo

So to my understanding, the following would also be UB:

Foo * foo = std::reinterpret_cast<Foo *>(glMapNamedBuffer(/*...*/));
// read or write to foo

(Foo is a trivial copy and constructable object)

Based on that the pointer I get from glMapNamedBuffer can only be used in combination with std::memcpy to copy data from or into the memory block that pointer is addressing, but if this is the case isn't glMapNamedBuffer kinda useless in the context of c++, as I could use glGetNamedBufferSubData and glNamedBufferSubData instead as I need to copy the data anyway?

Or would the following also be UB and I would need to use a std::memcpy in any case:

Foo foo;
glNamedBufferSubData( 1, 0, sizeof(Foo), &foo);
Foo foo;
glGetNamedBufferSubData( 2, 0, sizeof(Foo), &foo);

Upvotes: 0

Views: 969

Answers (1)

Nicol Bolas
Nicol Bolas

Reputation: 473457

I'm going to forget for the moment the fact that, as someone using a low-level API, you shouldn't be caring about undefined behavior of this sort, since this is pretty much what low-level programming is. So instead, we're in a world where we've decided that the only thing which matters is what the C++ standard actually says.

Given that:

So to my understanding, the following would also be UB:

Well, that rather depends: what is in that memory? Did you put an object there? Is the object you put there a Foo? If you didn't put a Foo there, you can put one there easily enough:

void *mem_ptr = glMapNamedBuffer(/*...*/);
Foo *ptr = new(mem_ptr) Foo;

Now there's a Foo there and we have a pointer to it. What's the problem? You can treat mapping a buffer as a fancy malloc.

Your next thought might be, but wait, what happens when I unmap the memory and map it again? Does OpenGL ensure that I'm getting a pointer to the same object? Could it be mapped to different addresses and break the C++ object model?

Again, given that we've decided to care about things that don't actually matter, OpenGL is entirely ignorant of the C++ object model. It's just looking at bytes of storage; that's all OpenGL preserves. Any particular mapping operation will only preserve the bytes, not the C++ objects around them (which are bound to memory addresses).

But we don't have to care about that if we persistently map buffers (which is the only way you should map buffers, given that you're clearly using APIs that require persistent mapped buffers to be available). There, you just map the pointer and you're done. You can do whatever you need with it.

And if you're reading data, you generally want that data out of the buffer object's memory ASAP. Reading from memory that is genuinely mapped to GPU memory can be exceedingly slow, so just doing a memcpy into an existing object would be appropriate. And with persistent mapped buffers, reading can be done after checking your fence to see if the data is available.

Upvotes: 1

Related Questions