Part of the Khronos Group
OpenGL.org

The Industry's Foundation for High Performance Graphics

from games to virtual reality, mobile phones to supercomputers

Page 1 of 2 12 LastLast
Results 1 to 10 of 12

Thread: selectively writing to buffers

  1. #1
    Intern Newbie
    Join Date
    Jan 2013
    Posts
    46

    selectively writing to buffers

    Hi,

    I ran into something weird, or something that I don't know how it works exactly.

    What I want to do when rendering to multiple targets is that I selectively write to certain color buffers in my shader, but leave others alone.
    for example


    Code :
    gl_FragData[3] = vec4(0,1,0,1);


    without setting the fragment data for the first 3 buffers...

    This doesn't seem to go well. for example, if I don't explicity set a value in the color buffer 4, it seems to copy the color value from the first color buffer for some reason instead of leaving it alone.

    So I though: ok I HAVE to explicitly set all a value on all used color buffers, so then if I don't want to touch one of the buffers, I just use blending and I write a value with an alpha of 0, so it doesn't effect the buffer. This doesn't work as expected.

    It seems that the blending only looks at the color buffer 0 ? if I write a some color-value with an alpha of 0 to the color buffer 0, it doesn't seem to matter what I write to the other buffers, it doesn't write anything.

    So not sure if you can follow what I'm explaining, but bottom line is: I would like to selectively write to certain color buffers in my shaders, and leave the other alone. Any ideas on how to do that properly? Or am I trying something impossible and do I need another solution?


    Thank you!

    Cheers,
    Bram

  2. #2
    Advanced Member Frequent Contributor arekkusu's Avatar
    Join Date
    Nov 2003
    Posts
    781
    It works as described in the specification.

    For a fragment shader linked with some number of active outputs, any output not written to is undefined. You can't depend on an unwritten buffer keeping the old value. So, within a single draw call, you can't selectively write to some buffers, you must write to all buffers made active via glDrawBuffers().
    Across multiple draw calls, of course you are free to change the set of active draw buffers (and then you might as well also change the current program.)

    With a single program and set of draw buffers, you can use blending to effectively keep some old values, as you described. You will have to ensure the blend state is set up appropriately for each draw buffer. If you don't need real blending for the buffers you do want to write to, you can simply enable and disable blending for each buffer (requires EXT_draw_buffers2, or GL3.0) with the same ZERO, ONE glBlendFunc for all draw buffers. On the other hand if you need some real blending for the buffers you want to write to, you'll have to set the glBlendFunc and/or glBlendEquation for each buffer (requires ARB_draw_buffers_blend, or GL4.0).

    The caveat with the blending approach is that you still can't change the blend enable (or func/equation) within a single draw call. So no matter what, you're limited to one set of active + "active but effectively disabled" buffers, per draw call. And you pay all the computation/bandwidth cost of writing something to a buffer just to leave it unchanged-- might as well change glDrawBuffers per draw call.

    On GL4.2+ another option might be to use ARB_shader_image_load_store, and write directly to images, bypassing the raster blend state. Then you have complete control over which images are updated.

  3. #3
    Intern Newbie
    Join Date
    Jan 2013
    Posts
    46
    Hi arekkusu,

    thanks for your reply, most of it makes sense now. Only thing is that don't understand why the alpha I write to buffer 0 effects the other buffers as well. How exactly does that happen?

    you can use blending to effectively keep some old values, as you described. You will have to ensure the blend state is set up appropriately for each draw buffer.
    I'm not sure how to set up blending for all buffers appropriatly, apperently now it's only set on the first buffer? How do you do that? I'm working in OSG btw, but I'm sure if I know how to do it in openGL I can make it happen with some help from others...

  4. #4
    Advanced Member Frequent Contributor arekkusu's Avatar
    Join Date
    Nov 2003
    Posts
    781
    During blending, there is no way that the alpha of fragment output zero can affect other outputs. Blending is applied independently to each buffer.
    However there are other operations (like alpha test, or alpha-to-coverage) where output zero's alpha is special and can affect (i.e. discard) all outputs.

    Read the documentation on glEnablei, or glBlendFunc/Equationi.

  5. #5
    Intern Newbie
    Join Date
    Jan 2013
    Posts
    46
    if that is so, which I think would be very logical, then I don't understand this:

    In a shader to draw water:

    void main()
    {
    gl_FragData[0] = vec4(0,0,0,1);
    gl_FragData[1] = vec4(0,0,0,0);
    gl_FragData[2] = vec4(0,0,0,0);
    gl_FragData[3] = vec4(0,1,0,1);
    }
    in the shade that renders the screen:

    vec4 color = vec4(texture2DRect( colorsRect, gl_TexCoord[0].st ).rgb, 1);
    vec4 waterColor = texture2DRect( waterRect, gl_TexCoord[0].st );

    gl_FragColor=waterColor;
    return;


    if I change the first shader to


    void main()
    {
    gl_FragData[0] = vec4(0,0,0,0);
    gl_FragData[1] = vec4(0,0,0,0);
    gl_FragData[2] = vec4(0,0,0,0);
    gl_FragData[3] = vec4(0,1,0,1);
    }
    (as it needs to be), then there are no green pixels on my screen anymore (and I'm rendering only the buffer 3). so it really really seems like the value I write to buffer 0 effects buffer 3... so weird.

  6. #6
    Intern Newbie
    Join Date
    Jan 2013
    Posts
    46
    to be more precise:

    this

    void main()
    {
    gl_FragData[0] = vec4(0,0,0,0.1);
    gl_FragData[1] = vec4(0,0,0,0);
    gl_FragData[2] = vec4(0,0,0,0);
    gl_FragData[3] = vec4(0,1,0,1);
    }

    will still give me bright green pixels (not 10% alpha)

    while this


    void main()
    {
    gl_FragData[0] = vec4(0,0,0,0.1);
    gl_FragData[1] = vec4(0,0,0,0);
    gl_FragData[2] = vec4(0,0,0,0);
    gl_FragData[3] = vec4(0,1,0,0.5);
    }

    will give me 50% dark green pixels.

    So it doesn't seem to be that the alpha of fragdata0 is used, but it does seem like it need something different than 0, or else it won't render anything in any buffer... weird

  7. #7
    Member Regular Contributor malexander's Avatar
    Join Date
    Aug 2009
    Location
    Ontario
    Posts
    316
    It's very likely the alpha test, then. It's a compatiblity mode test, and likely works off the first buffer, not the union of all of them. Try:

    glDisable(GL_ALPHA_TEST);

    before you render to your MRTs.

  8. #8
    Intern Newbie
    Join Date
    Jan 2013
    Posts
    46
    Thank you, it was indeed the alpha test!

  9. #9
    Member Regular Contributor Nowhere-01's Avatar
    Join Date
    Feb 2011
    Location
    Novosibirsk
    Posts
    251
    were you testing with Intel\AMD card by any chance? because i've actually foolishly done the same thing, not setting output color for all the draw buffers for some draw calls and nVidia with it's relaxed drivers makes this a deceptively reliable thing to do.

  10. #10
    Intern Newbie
    Join Date
    Jan 2013
    Posts
    46
    I am testing with AMD radeon 6800 here. I guess the tricky thing is that 'undefined' behavior does not produce any errors. So I was very surprised to see the terrain rendering in buffer 3, while I never drew any of those pixels to it. apparently with my card/drivers it used the output from buffer0 to fill buffers that were not written to. Probably makes sense when you know the inner workings of the drivers and hardware, but I don't

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •