One example of Image Load / Stores that I have seen could be done using framebuffers instead of Image Load / Stores. Framebuffers have been available longer in OpenGL and so my question is:

Why would you use Images instead of Framebuffers?

What advantages do they offer?

The referenced example says:

Note that this demo can also easily be imlemented using Framebuffer Objects. But with Framebuffer Objects you cannot write to arbitrary locations in a texture, though.

I am not exactly sure what is meant here. My understanding is that you can write to whatever pixel coordinates you want in an FBO. Am I mistaken here?


Why would you use Images instead of Framebuffers?

Image Load/Store is not intended to replace framebuffers. It's a feature that allows (relatively) arbitrary reading and writing to memory. So you would use images when you need to arbitrarily read and write to memory. You would use framebuffers when you're rasterizing primitives for rendering purposes.

The fact that you can build scenarios where you would use the latter in place of the former does not mean that this is the purpose of the feature.

What advantages do they offer?

Again, it's not meant to replace framebuffers. But the comparison is pretty simple.

A particular FS invocation cannot:

  • Choose what framebuffer texel(s) to write to. An FS invocation will only ever write outputs to the framebuffer texel(s) that map to its current fragment location. gl_FragCoord is an input value; it is non-modifiable. An FS's outputs will either be discard or written to the framebuffer texel(s) corresponding to gl_FragCoord.xy.

    Yes, through point rasterization, you can select which fragment is being generated. But it isn't the fragment shader itself that's deciding this; it's whatever process wrote the vertex to the buffer that it's being read from. That is not under the direct control of the FS invocation itself.

  • Choose to write to multiple distinct framebuffer texel(s) locations. A fragment cannot cover multiple texels.

  • Choose which output attachments in the framebuffer to write to. The decision of which fragment shader outputs will be written is made by the write mask state, which the FS has zero control over. An FS can choose to be discarded, but that discards all of its outputs.
  • Choose to read from the current framebuffer texel(s) it is writing to. Blending is done by a fixed-function stage; the FS has zero control over this. The closest you can get is to employ some texture barrier gymnastics, but that's not something the FS can directly control.
  • Choose to read from framebuffer texel(s) other than the one it's writing to. Even with texture barrier gymnastics, you cannot read from other people's texels.

Now granted, image load/store doesn't exactly make read/modify/write passes easy, due to incoherent memory access rules.

Of course, image load/store cannot handle (easily):

  • Depth testing. Or at least, not in any way that is nearly as efficient as the rasterizer. The read/modify/write nature of the depth test makes this exceedingly tricky with image load/store. With a regular depth buffer however, this is trivial.
  • Simple blending. Again, you can do it, but it's really hard, and far less efficient than the normal rendering process.

To write to an arbitrary location in a FBO you need to do rasterization of point primitive at that location. This is significantly more costly than a single imageStore because it involves invoking the vertex shader, the ROP units, and possibly rasterizing a whole 2x2 quad or more for just a single pixel. With imageLoad/imageStore you have greater flexibility and finer control of where you read and write, including atomics, barriers, etc... Since you skip the ROP and give up the API-order guarantee, such direct writes might be faster even for filling triangles.

† I'm not sure about this last point, but since the screen-space derivatives are still available in the fragment shader, and point primitives are typically used for larger sprites, it means that the implementations are more likely to just go the typical rasterization route used for lines and triangles.


The documentation quickly sum up the idea with:

The idea with image load/store is that the user can bind one of the images in a Texture to a number of image binding points (which are separate from texture image units). Shaders can read information from these images and write information to them, in ways that they cannot with textures.

Aside for the simplicity of usage, from An introduction to OpenGL 4.2 | Daniel Rákos Blog at the section ARB_shader_image_load_store you can perform more complex operations and algorithms in GLSL to a single level of a texture (which is called an image) and from any shader stage.

I am also curious about the implementation of the example with FBO since I don't understand why you cannot write to a specific pixel coordinate too.


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.