8
$\begingroup$

I'm trying to figure out what the best way is to generate an OpenGL texture using a compute shader. So far, I've read that pixel buffer objects are good for non-blocking CPU -> GPU transfers, and that compute shaders are capable of reading and writing buffers regardless of how they're bound. Ideally, I'd like to avoid as many copies as possible. In other words, I'd like to allocate a buffer on the GPU, write compressed texture data to it, and then use that buffer as a texture object in a shader.

Currently, my code looks something like this:

GLuint buffer;
glGenBuffers(1, &buffer);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, buffer);
glBufferStorage(GL_SHADER_STORAGE_BUFFER, tex_size_in_bytes, 0, 0);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);

// Bind buffer to resource in compute shader
// execute compute shader

glBindBuffer(GL_PIXEL_UNPACK_BUFFER, buffer);
glCompressedTexImage2D(GL_TEXTURE_2D, 0, fmt, w, h, 0, tex_size_in_bytes, 0);

Is this correct? I read somewhere about guaranteeing synchronization, too. What do I need to add to make sure that my compute shader completes execution prior to copying from the buffer object?

$\endgroup$
  • $\begingroup$ Would you like to specify which texture compression format you prefer? I am guessing but your answer will likely involve a compute-mode texture compression routine. $\endgroup$ – ap_ Sep 10 '15 at 17:13
3
$\begingroup$

After looking into this for a while, I found out a couple of things:

  1. You cannot avoid a memcpy: You cannot write directly into texture storage allocated for a compressed texture using only OpenGL API calls. This means that you cannot avoid the call to glCompressedTexImage2D with a bound PBO. That being said, you may be able to use a 16-bit RGBA texture and a GLSL image type in your compute shader.

  2. You do need to synchronize memory: In order to make sure that your compute shader finishes writing to your storage buffer, you must make sure that all reads and writes to it finish. This is done by calling glMemoryBarrier with GL_SHADER_STORAGE_BARRIER_BIT.

The full code for something that writes into a buffer to be used as a compressed texture looks like this:

GLuint buffer;
glGenBuffers(1, &buffer);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, buffer);
glBufferStorage(GL_SHADER_STORAGE_BUFFER, tex_size_in_bytes, 0, 0);

glUseProgram(compute_shader_prog);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, compute_shader_bind_point, buffer);
glDispatchCompute(wg_x, wg_y, wg_z);
glMemoryBarrier(GL_SHADER_STORAGE_BUFFER_BIT);

glBindBuffer(GL_PIXEL_UNPACK_BUFFER, buffer);
glCompressedTexImage2D(GL_TEXTURE_2D, 0, fmt, w, h, 0, tex_size_in_bytes, 0);
$\endgroup$
  • $\begingroup$ "you may be able to use a 16-bit RGBA texture and a" AND A WHAT??? :) $\endgroup$ – Nathan Reed Sep 19 '15 at 1:12
  • 2
    $\begingroup$ Haha, this is what happens when you leave the tab open to finish later. Edited. $\endgroup$ – Mokosha Sep 19 '15 at 1:13
  • 1
    $\begingroup$ GL_SHADER_STORAGE_BARRIER_BIT Wrong barrier. The barrier you provide states how you will use the memory. Not how the shader wrote to it. You are doing a pixel transfer, so you need to use GL_TEXTURE_UPDATE_BARRIER_BIT $\endgroup$ – Nicol Bolas Nov 5 '16 at 17:57
  • 1
    $\begingroup$ Are you sure? According to the docs, GL_TEXTURE_UPDATE_BARRIER_BIT is used when synchronizing calls to glTexImage, and has nothing to do with the memory used in storage buffers. I think you meant GL_PIXEL_BUFFER_BARRIER_BIT? $\endgroup$ – Mokosha Dec 9 '16 at 4:00

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.