Can I copy contents of texture buffers to vertex buffer like this?

I’ve got 2 image2D texture buffers, one containing vertex position data, and the other containing vertex colour data. I’m trying to copy this data into a vertex buffer directly on the GPU. Is this the right way to do it?

I have confirmed the textures contain the correct data using a preexisting raytracing shader, but my aim is to use this texture data to create a mesh without having to pull the texture data back to the CPU.

I create my vao/vbo/ebo like so:

    const size_t num_vertices = _map_terrain_texture_shape.x * _map_terrain_texture_shape.y;
    const size_t total_vertex_position_bytes = num_vertices * sizeof(glm::vec4);
    const size_t total_vertex_colour_bytes = num_vertices * sizeof(glm::vec4);
    const size_t total_vertex_bytes = total_vertex_position_bytes + total_vertex_colour_bytes;

    std::vector<uint32_t> indices = _make_indices(_map_terrain_texture_shape);
    const size_t total_index_bites = indices.size() * sizeof(uint32_t);

    glGenVertexArrays(1, &_vao);
    glGenBuffers(1, &_vbo);
    glGenBuffers(1, &_ebo);

    glBindVertexArray(_vao);

    glBindBuffer(GL_ARRAY_BUFFER, _vbo);
    glBufferData(GL_ARRAY_BUFFER, total_vertex_bytes, nullptr, GL_STATIC_DRAW);

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _ebo);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, total_index_bites, indices.data(), GL_STATIC_DRAW);

    glEnableVertexAttribArray(VERTEX_POSITION_ATTRIB_INDEX);
    glEnableVertexAttribArray(VERTEX_COLOUR_ATTRIB_INDEX);

    // vertex draw positions
    glVertexAttribPointer(VERTEX_POSITION_ATTRIB_INDEX, glm::vec4::length(), GL_FLOAT, GL_FALSE, sizeof(glm::vec4), (void*)0);
    // vertex colours
    glVertexAttribPointer(VERTEX_COLOUR_ATTRIB_INDEX, glm::vec4::length(), GL_FLOAT, GL_FALSE, sizeof(glm::vec4), (void*)total_vertex_position_bytes);

    glDisableVertexAttribArray(VERTEX_POSITION_ATTRIB_INDEX);
    glDisableVertexAttribArray(VERTEX_COLOUR_ATTRIB_INDEX);

    glBindVertexArray(0);

And then I copy the data from the pre-existing textures into the vertex array like so:

    const size_t num_vertices = _map_terrain_texture_shape.x * _map_terrain_texture_shape.y;
    const size_t total_vertex_position_bytes = num_vertices * sizeof(glm::vec4);
    const size_t total_vertex_colour_bytes = num_vertices * sizeof(glm::vec4);

    const auto position_texture_id = _main_state.terrain_generator->map_terrain_vertex_position_texture->id;
    const auto colour_texture_id = _main_state.terrain_generator->map_terrain_vertex_colour_texture->id;

    glBindBuffer(GL_COPY_WRITE_BUFFER, _vbo);

    glBindBuffer(GL_COPY_READ_BUFFER, position_texture_id);
    glCopyBufferSubData(position_texture_id, _vbo,
                        0, 0,
                        total_vertex_position_bytes);

    glBindBuffer(GL_COPY_READ_BUFFER, colour_texture_id);
    glCopyBufferSubData(colour_texture_id, _vbo,
                        0, total_vertex_position_bytes,
                        total_vertex_colour_bytes);

    glBindBuffer(GL_COPY_READ_BUFFER, 0);
    glBindBuffer(GL_COPY_WRITE_BUFFER, 0);

Currently I’m getting a black screen when I run my rasterizing shader instead of my raytrace shader. I have checked and double checked how the rasterizing renderer is setup, and I cannot find a fault there so far, so I’m wondering if my mistake is in how I’m copying this data (as I’ve never tried to do this before)

Hello.
I haven’t done OpenGL programming in a while and I’m sorry - right now I cannot even check the code thoroughly.
The only weird thing I see is that you disable the vertex attribute arrays right before unbinding the vertex array. IIRC you don’t need to do that; you can leave them enabled as part of the vertex array state. Better yet, if you don’t re-enable them before rendering with that vertex array, then of course you’ll see nothing rendered.

Does position_texture_id refer to a buffer or a texture? You can’t treat buffers as textures or vice versa. If you want to get the data out of a texture, you have to either use glGetTexImage (or similar) or bind it to a framebuffer and use glReadPixels.

Note that texture image data typically isn’t stored in raster scan order. It’s more likely to be tiled or Hilbert curve, or something similar which maximises the probability of adjacent pixels being in adjacent memory. This is why you can’t just get a pointer to the texture data like with most CPU-side image formats.

1 Like

Interesting! And yes, it is a texture I’m purposely trying to either treat as a vertex buffer or copy it to a vertex buffer.

glCopyBufferSubData allows different types of buffers including texture buffers and vertex buffers, so presumably it will copy from one to another? The driver or what have you will know how to read the texture ofcourse so any idea if I can formulate this so it does copy it?

There aren’t “different types of buffers”. A buffer is a buffer. There are different ways in which you can use a buffer, but each of those mechanisms can be applied to any buffer. The specification originally stated that a driver might optimise buffer storage based upon how a buffer was first used, but no driver implemented this and the language has since been removed.

It’s not clear what you mean by a “texture buffer”.

It could be a buffer bound to GL_PIXEL_UNPACK_BUFFER, which is the source for a glTexImage* (or similar) command. Or a buffer bound to GL_PIXEL_PACK_BUFFER, which is the destination for a glGetTexImage* or glReadPixels (or similar) command.

Or possibly a buffer texture (glTexBuffer), which is essentially a mechanism for accessing a buffer via texelFetch (buffer textures can’t be sampled, which precludes the use of the other texture functions). Unlike glTexImage*, this doesn’t make a copy of the data. Note that there isn’t a mechanism for the converse, i.e. accessing a texture’s data as if it were a buffer; you have to actually extract the data with glGetTexImage or similar.

By different types of buffer, I mean the readTarget/writeTarget or readBuffer/writeBuffer. I’m still unclear how I’m meant to use this properly if it’s even capable of doing what I want, as I thought I was using it properly as far as I can follow the docs. The target/buffer types are listed here:

https://registry.khronos.org/OpenGL-Refpages/gl4/html/glCopyBufferSubData.xhtml

Forgive me if I’m misuing nomencloture here

What GClements said about buffer objects not having types. Given that, the natural rewording of your question:

  • Does glCopyBufferSubData() allow copying between two arbitrary buffer objects?

The answer is yes. “Regardless” of what the buffer object has been used for in the past, contains in the present, or will be used for in the future.