# Passing non-interleaved data to glBufferStorage without using glBufferSubData

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)
{
std::array<byte_range, sizeof...(rngs)> spans =
{get_span(rngs)...};

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;
}

$$$$
`
• The answer is very helpful. But the code example feels way too complicated, maybe needlessly so. Oct 5 '21 at 5:44
• @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. Oct 5 '21 at 13:35