I want to customize std::vector class in order to use an OpenGL buffer object as storage.
Is it possible doing so without relying in a specific implementation of STL, by writing a custom allocator and/or subclassing the container?
My problem is how to create wrapper methods for glMapBuffer/glUnmapBuffer in order to user the buffer object for rendering which leave the container in a consistent state.
You can, but that doesn’t make it a good idea. And even that you can is dependent on your compiler/standard library.
Before C++11, allocators can not have state. They can cannot have useful members, because the containers are not required to actually use the allocator you pass it. They are allowed to create their own. So you can set the type of allocator, but you cannot give it a specific allocator instance and expect that instance to always be used.
So your allocator cannot just create a buffer object and store the object internally. It would have to use a global (or private static or whatever) buffer. And even then, multiple instances would be using the same buffer.
You could get around this by having the allocator stores (in private static variables) a series of buffer objects and mapped pointers. This would allow you to allocate a buffer object of a particular size, and you get a mapped pointer back. The deallocator would use the pointer to figure out which buffer object it came from and do the appropriate cleanup for it.
Of course, this would be utterly useless for actually doing anything with those buffers. You can’t use a buffer that is currently mapped. And if your allocator deletes the buffer once the vector is done with the memory, then you can never actually use that buffer object to do something.
Also, don’t forget: unmapping a buffer can fail for unspecified reasons. If it does fail, you have no way of knowing that it did, because the unmap call is wrapped up in the allocator. And destructors shouldn’t throw exceptions.
C++11 does make it so that allocators can have state. Which means that it is more or less possible. You can have the allocator survive the
std::vectorthat built the data, and therefore, you can query the allocator for the buffer object post-mapping. You can also store whether the unmap failed.That still doesn’t make it a good idea. It’ll be much easier overall to just use a regular old
std::vectorand useglBufferSubDatato upload it. After all, mapping a buffer with READ_WRITE almost guarantees that it’s going to be regular memory rather than a GPU address. Which means that unmapping is just going to perform a DMA, whichglBufferSubDatadoes. You won’t gain much performance by mapping.Reallocation with buffer objects is going to be much more painful. Since the
std::vectorobject is the one that decides how much extra memory to store, you can’t play games like allocating a large buffer object and then just expanding the amount of memory that the container uses. Every time the std::vector thinks that it needs more memory, you’re going to have to create a new buffer object name, and the std::Vector will do an element-wise copy from mapped memory to mapped memory.Not very fast.
Really, what you want is to just make your own container class. It isn’t that hard. And it’ll be much easier to control when it is mapped and when it is not.