Search code examples
macosopenglgraphicstexturespbo

Uploading texture to GPU by PBO not working (OpenGL version 4.1)


I have read the famous tutorial OpenGL Pixel Buffer Object (PBO). I tested the sample code on my computer and it works (although with PBO on, its performance didn't improve but at least it's rendering correctly).

The problem is in the sample code the OpenGL context version is quite old (Version: 2.1 INTEL-10.22.29), and the OpenGL context version for my project is version: 4.1 INTEL-10.22.29 which doesn't support extension GL_ARB_pixel_buffer_object any more.

I have read this Map and fill texture using PBO (OpenGL 3.3), so I change my code to:

// generating buffers and textures
glGenVertexArrays(1, &_vertex_array);
glBindVertexArray(_vertex_array);

glGenBuffers(1, &_vertex_buffer);
glBindBuffer(GL_ARRAY_BUFFER, _vertex_buffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertexs_data), vertexs_data, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);

glGenBuffers(1, &_uv_buffer);
glBindBuffer(GL_ARRAY_BUFFER, _uv_buffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(uvs_data), uvs_data, GL_STATIC_DRAW);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, (void*)0);

glGenBuffers(1, &_pixel_buffer);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, _pixel_buffer);
glBufferData(GL_PIXEL_UNPACK_BUFFER, DATA_SIZE, 0, GL_STREAM_DRAW);

glGenTextures(1, &_texture);
glBindTexture(GL_TEXTURE_2D, _texture);

and render loop:

glBindTexture(GL_TEXTURE_2D, _texture);
// ======== start process PBO =========
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, _pixel_buffer);
glBufferData(GL_PIXEL_UNPACK_BUFFER, DATA_SIZE, 0, GL_STREAM_DRAW);
GLubyte *ptr = (GLubyte*) glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_READ_WRITE);
if( ptr != nullptr )
{
    cout<<"map pixel buffer success"<<endl;
    memcpy(ptr, DATA_SIZE, data );
    glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);   
}
// ========= end process PBO ==========

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB,
             _window_width, _window_height,
             0, GL_RGB,
             GL_UNSIGNED_BYTE, data
);
glGenerateMipmap(GL_TEXTURE_2D);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
// draw commands goes here

My code is simply rendering a single color texture, if I comment the block from ======== start process PBO ========= to ========= end process PBO ========== then everything goes well, but with this block, it just failed and all I get is a black screen. I already checked that the glMapBuffer works correctly and I successfully write the texture data to memory pointed by ptr( checking by print out its value ), but I can't figure out why I didn't get my expected result.

Thanks in advance.

My Environment:

OS: macOS sierra 10.12.3 (16D32)
Graphics: Intel Iris Graphics 6100 1536 MB

Solution

  • EDIT

    This answer has been accepted, but it requires modifications. Here they are:

    First my eye pointed out a cast from (void*). No, this can't be, memcpy() will cast it again.
    Then I arrived to glTextImage2D. And erroneously thought it can not be used with PBO (dam, I make too mistakes due to rush. I must relax...). Thanks Nico Bolas corrected me.

    Then, slowly reading again, it was just a matter of not using a pointer to client data in glTextImage2D, change data to 0

    Docs say clearly about this last parameter:

    If a non-zero named buffer object is bound to the GL_PIXEL_UNPACK_BUFFER target (see glBindBuffer) while a texture image is specified, data is treated as a byte offset into the buffer object's data store.

    OLD:

    GLubyte *ptr = (GLubyte*) glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_READ_WRITE);
    You are degenerating the returned pointer. Let it be (void*) if you only use it in a memcpy() command:
    void* ptr = glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_READ_WRITE);

    EDIT: (after I read again that you want to copy from PBO to a texture)

    glTextImage2D() reads from a pointer data while glTexSubImage2D() can be used to read from a bound PBO. In this last case the last parameter to glTexSubImage2D()is an offset to that PBO (0 if no offset is needed).