Inertia's picture

GL.ReadPixels broken?

I'm toying with an implementation of the picking technique suggested here.

However it appears that this code will always return 4x zero, although the buffer was previously cleared with 4x 1f.

  // after bind FBO, draw obj, while FBO is bound and readbuffer set to correct color attachment:
  Byte4 Pixel = new Byte4();
  GL.ReadPixels<Byte4>(Mouse.X, FBO_height-Mouse.Y, 1, 1, PixelFormat.Rgba, PixelType.UnsignedByte, ref Pixel);
  uint SelectedTriangle = Pixel.ToUInt32();

this code does prove that there's neither a problem with the FBO nor the attachment:

  // after bind FBO, draw obj, unbind FBO 
  GL.Enable(EnableCap.Texture2D);
  GL.BindTexture(Target, ColorAttachment);
  Byte4[] Tex = new Byte4[FBO_width * FBO_height];
  GL.GetTexImage<Byte4>(Target, 0, PixelFormat.Rgba, PixelType.UnsignedByte, Tex);
  GL.BindTexture(Target, 0);
  GL.Disable(EnableCap.Texture2D);
  SelectedTriangle = Tex[(FBO_height-Mouse.Y)*FBO_width+Mouse.X].ToUInt32();

The later is a huge waste of memory (and prone to indexing out of array bounds) but it gives me the correct triangle index. GL.ReadPixels will never return any values besides zeros.

I've taken a look at svn and the ReadPixels pinning looks ok, besides that it should use "out" not "ref". Any ideas what's wrong with this?


Comments

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
the Fiddler's picture

ReadPixels is implemented pretty much identically to GetTexImage, GetBufferSubData and other functions that are known to work correctly. It's possible that some bug has crept in the implementation (lack of unit tests + haven't used it for a while), but as you said the implementation in SVN looks correct.

Some ideas:

  • Someone mentioned a similar issue on taoframework.com recently and mentioned that "- the glReadPixel read from the pixel-buffer and is NOT based on the viewport size". Just something to check.
  • Another possibility is that ReadPixels is affected by the current pixel transfer mode, while GetTexImage (AFAIK) isn't.
  • Finally, this could be a datatype mismatch - which I doubt, since GetTexImage works correctly. Still, you could try reading a Color4 value using PixelType.Float.

The parameter needs to beref - not out - because the user is responsible for allocating memory, rather than OpenGL.

Inertia's picture

I've looked into GL.PixelTransfer, GL.PixelStore and GL.PixelMap, but none of them appears to be the culprit. Requesting a Vector4 instead of Byte4 did not help either (it is my understanding that OpenGL will convert data to your requested format/type regardless of what internal representation it uses anyways).

Any help with this would be much appreciated, so far the best workaround I can think of is creating a 1x1 texture and copying the texel in question to it, then GL.GetTexImage the 1 texel for analysis. But I'd prefer to simply use GL.ReadPixels and drop FBO from the example application altogether.

Inertia's picture

(for completeness) This works:

unsafe { GL.ReadPixels(Mouse.X, FBO_height - Mouse.Y, 1, 1, PixelFormat.Rgba, PixelType.UnsignedByte, new IntPtr((void*)&Pixel.R)); }
the Fiddler's picture

Ok, your last post uncovered the cause. This is indeed a bug that was introduced along with the generic wrappers in version 0.9.6. The reason why it went unnoticed for so long is that it does not affect any generic array overloads (which are much more common than the generic ref/out overloads).

Edit: filed as issue #1240: Generic ref and out wrappers do not copy results to the reference parameter.

rathan001's picture

Is this issue exist still?