I would like to use glBufferStorage to load data once into the vertex buffer. However sometimes I want to pass non-interleaved data from separate arrays like shown below.

glBufferStorage(GL_ARRAY_BUFFER, sizeVerts+sizeUVs, 0, 0);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeVerts, verts.data());
glBufferSubData(GL_ARRAY_BUFFER, sizeVerts, sizeUVs, uvs.data());

Because of this I have to specify GL_DYNAMIC_STORAGE_BIT flag, despite loading the data once, and thus use a less performant alternative.

Are there any workarounds to this problem?

Or does using GL_DYNAMIC_STORAGE_BIT not lead to a significant performance hit, and should I just use it despite loading data once?


You can put your data in one piece of memory on the CPU and then copy it in with glBufferStorage. It's just a bunch of memcpy calls.

With C++20's std::span (or the GSL version), you can even make a function to build byte-spans from any number of vector<T>s (even of different types) and do the building and memcpy's manually.

#include <vector>
#include <concepts>
#include <ranges>
#include <span>
#include <cstdint>
#include <cstring>

using byte_range = std::span<std::byte const, std::dynamic_extent>;

template<std::ranges::contiguous_range Rng>
byte_range get_span(Rng const &rng)
    auto sp = std::span(rng);
    return std::as_bytes(sp);

template<std::ranges::contiguous_range ...Rngs>
    requires (sizeof...(Rngs) > 0)
GLuint upload_to_buffer(Rngs const &...rngs)
    std::array<byte_range, sizeof...(rngs)> spans =

    std::size_t buffer_size = 0;
    for(auto const& sp : spans)
        buffer_size += sp.size();

    std::vector<std::byte> byte_buff(buffer_size);

    std::size_t offset = 0;
    for(auto const& sp : spans)
        std::memcpy(&byte_buff[offset], sp.data(), sp.size());

    GLuint buff;
    glCreateBuffer(&buff, 1);
    glNamedBufferStorage(buff, byte_buff.size(), byte_buff.data(), 0);
    return buff;

  • $\begingroup$ The answer is very helpful. But the code example feels way too complicated, maybe needlessly so. $\endgroup$ Oct 5 '21 at 5:44
  • $\begingroup$ @LennyWhite: Outside of some of the newer features of C++, what is complicated about it? You get the range of bytes for each buffer, build a big buffer, copy all of the byte ranges into that buffer, and send it to OpenGL. $\endgroup$ Oct 5 '21 at 13:35

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.