<p>You can put your data in one piece of memory on the CPU and then copy it in with <code>glBufferStorage</code>. It's just a bunch of <code>memcpy</code> calls.</p>
<p>With C++20's <code>std::span</code> (or the GSL version), you can even make a function to build byte-spans from any number of <code>vector&lt;T&gt;</code>s (even of different types) and do the building and <code>memcpy</code>'s manually.</p>
<pre><code>
#include &lt;vector&gt;
#include &lt;concepts&gt;
#include &lt;ranges&gt;
#include &lt;span&gt;
#include &lt;cstdint&gt;
#include &lt;cstring&gt;

using byte_range = std::span&lt;std::byte const, std::dynamic_extent&gt;;

template&lt;std::ranges::contiguous_range Rng&gt;
byte_range get_span(Rng const &amp;rng)
{
    auto sp = std::span(rng);
    return std::as_bytes(sp);
}

template&lt;std::ranges::contiguous_range ...Rngs&gt;
    requires (sizeof...(Rngs) &gt; 0)
GLuint upload_to_buffer(Rngs const &amp;...rngs)
{
    std::array&lt;byte_range, sizeof...(rngs)&gt; spans =
        {get_span(rngs)...};

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

    std::vector&lt;std::byte&gt; byte_buff(buffer_size);

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

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

<span class="math-container">```</span>
</code></pre>

CC BY-SA 4.0
2021-10-05T05:44:40.140Z
The answer is very helpful. But the code example feels way too complicated, maybe needlessly so.
Lenny White
CC BY-SA 4.0
2021-10-05T13:35:24.680Z
@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.
Nicol Bolas
CC BY-SA 4.0
2021-10-04T15:55:25.687Z
2021-10-04T15:55:25.687Z
Nicol Bolas
<p>I would like to use <code>glBufferStorage</code> to load data once into the vertex buffer. However sometimes I want to pass non-interleaved data from separate arrays like shown below.</p>
<pre><code>glBufferStorage(GL_ARRAY_BUFFER, sizeVerts+sizeUVs, 0, 0);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeVerts, verts.data());
glBufferSubData(GL_ARRAY_BUFFER, sizeVerts, sizeUVs, uvs.data());
</code></pre>
<p>Because of this I have to specify <code>GL_DYNAMIC_STORAGE_BIT</code> flag, despite loading the data once, and thus use a less performant alternative.</p>
<p>Are there any workarounds to this problem?</p>
<p>Or does using <code>GL_DYNAMIC_STORAGE_BIT</code> not lead to a significant performance hit, and should I just use it despite loading data once?</p>

<opengl><c++><vertex-buffer-object>
Passing non-interleaved data to glBufferStorage without using glBufferSubData
Lenny White
# Passing non-interleaved data to glBufferStorage without using glBufferSubData

(Asked by: username_0 on 2021-10-04)

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?

**Tags:** opengl, c++, vertex-buffer-object


---

## 1 answers

### Answer by username_1 on 2021-10-04. Score: 1 | Accepted answer

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

```

```

> **Comments:**
> **username_0**: The answer is very helpful. But the code example feels way too complicated, maybe needlessly so.  
> **username_1**: @username_0: 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.  

---

