Question

I have some OpenGL code that behaves inconsistently across different hardware. I've got some code that:

  1. Creates a render buffer and binds a texture to its color buffer (Texture A)
  2. Sets this render buffer as active, and adjusts the viewport, etc
  3. Activates a pixel shader (gaussian blur, in this instance).
  4. Draws a quad to full screen, with texture A on it.
  5. Unbinds the renderbuffer, etc.

On my development machine this works fine, and has the intended effect of blurring the texture "in place", however on other hardware this does not seem to work.

I've gotten it down to two possibilities.

A) Making a renderbuffer render to itself is not supposed to work, and only works on my development machine due to some sort of fluke.

Or

B) This approach should work, but something else is going wrong.

Any ideas? Honestly I have had a hard time finding specifics about this issue.

Was it helpful?

Solution

A) is the correct answer. Rendering into the same buffer while reading from it is undefined. It might work, it might not - which is exactly what is happening.

In OpenGL's case, framebuffer_object extension has section "4.4.3 Rendering When an Image of a Bound Texture Object is Also Attached to the Framebuffer" which tells what happens (basically, undefined). In Direct3D9, the debug runtime complains loudly if you use that setup (but it might work depending on hardware/driver). In D3D10 the runtime always unbinds the target that is used as destination, I think.

Why this is undefined? One of the reasons GPUs are so fast is that they can make a lot of assumptions. For example, they can assume that units that fetch pixels do not need to communicate with units that write pixels. So a surface can be read, N cycles later the read is completed, N cycles later the pixel shader ends it's execution, then it it put into some output merge buffers on the GPU, and finally at some point it is written to memory. On top of that, the GPUs rasterize in "undefined" order (one GPU might rasterize in rows, another in some cache-friendly order, another in totally another order), so you don't know which portions of the surface will be written to first.

So what you should do is create several buffers. In blur/glow case, two is usually enough - render into first, then read & blur that while writing into second. Repeat this process if needed in ping-pong way.

OTHER TIPS

In some special cases, even the backbuffer might be enough. You simply don't do a glClear, and what you have drawn previously is still there. The caveat is, of course, that you can't really read from the backbuffer. But for effects like fading in and out, this works.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top