Question about FBO, glDrawBuffers, glClear and glClearColor

  1. Is calling glDrawBuffers a change FBO state? That is, is it enough for me to call glDrawBuffers for the active FBO during initialization so that with every new glBindFramebuffer(GL_FRAMEBUFFER, fbo), I do not call glDrawBuffers? I.e
uint colorAttachment0123[4] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3};

void init() {
    glBindFramebuffer(GL_FRAMEBUFFER, fbo);
    glDrawBuffers(4, colorAttachment0123);
    glBindFramebuffer(GL_FRAMEBUFFER, 0);
}

void renderFrame() {
    // use shaders, set values etc
    // ...

    glBindFramebuffer(GL_FRAMEBUFFER, fbo);
    drawModel();
    // glDrawBuffers(4, colorAttachment0123); << no need to call since init was called (???)

    // ...
}
  1. In the code above, I used 4 color attachments. If, for example, a shader writes to everything except, for example, GL_COLOR_ATTACHMENT2, and then another shader writes to GL_COLOR_ATTACHMENT2, will it be normal and safe? I.e
renderFrame:
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glUseProgram(program013);
drawModel();
glUseProgram(program2);
drawAnotherModel();
  1. As I understand it, I must first call glClearColor, and then glClear. Will the following code give all FBOs the same color?
glClearColor(1, 0, 0, 1);
glBindFramebuffer(GL_FRAMEBUFFER, fbo1);
glClear(GL_COLOR_BUFFER_BIT);
glBindFramebuffer(GL_FRAMEBUFFER, fbo2);
glClear(GL_COLOR_BUFFER_BIT);
glBindFramebuffer(GL_FRAMEBUFFER, fbo3);
glClear(GL_COLOR_BUFFER_BIT);

Thank you in advance for your reply!

Yes. Every function on this page (unless otherwise stated) modifies framebuffer state.

What does “normal and safe” mean?

The fragment shader generates output fragment, which contain a number of output colors. If the fragment shader doesn’t write a value for a particular output color, then the value for that color is undefined. Assuming that fragment passes the various tests, the post-FS machinery will attempt to write a value for all of the color images in the framebuffer.

In that case, attachment 2 will get an undefined value for any pixels written by fragments generated from the first shader. This is OpenGL’s defined behavior, so it is technically “normal and safe”; just not very useful (since undefined values are undefined and therefore not reliable).

If another shader comes along and writes to attachment 2, that’s fine, assuming it overwrites all of the undefined values. Of course, if it’s not also writing to the other attachments, then it’s now overwriting those defined values with undefined values.

Note however that above I said “attempt to write”. There are two things that can block that attempt (outside of using blending to just preserve the original value).

The first is the glDrawBuffers state. You can route a particular fragment shader output to GL_NONE, which discards the value.

The second is the write mask. You can use glColorMaski to turn off writes to individual buffers. For your first shader, you can turn off writes to attachment 2, and for your second, you can turn off writes to everything except attachment 2.

1 Like

Yes. The clear colour is context state, not FBO state. There’s only one value, set by glClearColor and read using glGet* with parameter GL_COLOR_CLEAR_VALUE; the value is used for all floating-point and normalised draw buffers (but not integer buffers).

Individual buffers can be cleared with glClearBuffer*, which can also handle signed or unsigned integer buffers. These take the value to store in the buffer as a parameter.

1 Like

Yes, the second shader writes only in attachment 2. I tested on Nvidia and Intel, the values do not become undefined, they remain the same as the first shader wrote them. So, is this behavior implementation-defined?

It’s far more likely that your description of what your code is doing and what your code is actually doing are not the same. Also, “become undefined” could mean “remain the same”; undefined behavior is “undefined” after all.