1

I'm having a problem reading the depth buffer of a offscreen framebuffer rendering pass. When using OpenGL 4.5 it works as intended, but on OpenGL ES 2.0 (Angle) I get an error on my glReadPixels(0, 0, width, height, GL_DEPTH_COMPONENT, GL_FLOAT, depthBuffer) call. The error is 0x502, which is a GL_INVALID_OPERATION error code.

Some more background. I'm working in a Qt environment, which has a main rendering routine and now I'm doing some offscreen rendering. Usually we use the opengl desktop implementation, but on some machine, we are experiencing some problems with bad opengl versions. Therefore I'm current working on making the whole setup more robust. One thing I did is to use angle instead. So I'm just trying to get angle to work, which SHOULD correspond to using OpenGL ES 2.0.

Well here the framebuffer creation:

glGenFramebuffers(1, &fboId);
glBindFramebuffer(GL_FRAMEBUFFER, fboId);
glGenRenderbuffers(1, &cboId);
glBindRenderbuffer(GL_RENDERBUFFER, cboId);
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, width, height);    
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, cboId);    
glGenRenderbuffers(1, &dboId);
glBindRenderbuffer(GL_RENDERBUFFER, dboId);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, width, height);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, dboId);

The framebuffer is complete and no error is thrown. The code between the previous and the following final piece does not throw any errors aswell.

glBindFramebuffer(GL_FRAMEBUFFER, fboId);
glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, colorData);
//No error up to this point
glReadPixels(0, 0, width, height, GL_DEPTH_COMPONENT, GL_FLOAT, depthData));
//This call throws 0x502 (GL_INVALID_OPERATION)

Usually I use GL_DEPTH_COMPONENT24, which is not working for some reason. So I used GL_DEPTH_COMPONENT16 instead. Maybe that's a hint what is wrong. FYI the main framebuffer is using a 24bit Depth and 8bit stencil. (I tried using the GL_DEPTH24_STENCIL8 format aswell with no success on the glReadPixels call).

Using a texture instead or a pbuffer is not working, because the needed functions for this workaround (glGetTexImage(...), glMapBuffer(...)) are not implemented in the GL version I'm stuck with.

genpfault
  • 51,148
  • 11
  • 85
  • 139
xeed
  • 925
  • 8
  • 22

2 Answers2

1

According to Khronos specification:

format Specifies the format of the pixel data. The following symbolic values are accepted: GL_ALPHA, GL_RGB, and GL_RGBA.

type Specifies the data type of the pixel data. Must be one of GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT_5_6_5, GL_UNSIGNED_SHORT_4_4_4_4, or GL_UNSIGNED_SHORT_5_5_5_1.

GL_INVALID_OPERATION is generated if type is GL_UNSIGNED_SHORT_5_6_5 and format is not GL_RGB.

GL_INVALID_OPERATION is generated if type is GL_UNSIGNED_SHORT_4_4_4_4 or GL_UNSIGNED_SHORT_5_5_5_1 and format is not GL_RGBA.

GL_INVALID_OPERATION is generated if format and type are neither GL_RGBA and GL_UNSIGNED_BYTE, respectively, nor the format/type pair returned by querying GL_IMPLEMENTATION_COLOR_READ_FORMAT and GL_IMPLEMENTATION_COLOR_READ_TYPE.

Neither format nor type in your code qualify for this requirements.

Reaper
  • 747
  • 1
  • 5
  • 15
  • @Rabbid76 There's no clearly stated question there actually. – Reaper Sep 27 '17 at 22:05
  • 1
    Okay, that's actually quite helpful already. It answers the "why". Is there another way of accessing the depth buffer besides glReadPixels, PBuffers and textures? – xeed Sep 28 '17 at 17:14
0

As @xeed has already pointed out, @Reaper has answered the "why" part of the question. As to the "how" of getting depth information in OpenGL ES, after a lot of searching online, as well as talking to some peers, I have only seen two methods proposed:

  1. (ES 3+ only) Attach a depth texture to the framebuffer you render your scene in. Then render a "full-screen" quad, sample the depth texture in the fragment shader for this quad, and output the depth texture values as your colour values, e.g. in your red channel. Finally, use glReadPixels on this colour information to get the depth values back. See: https://stackoverflow.com/a/35041374/11295586

  2. Get the values with gl_FragCoord.z. See: https://stackoverflow.com/a/6140714/11295586

I have tried both options, and both seem to work, though I still have a depth-inversion problem with the second that, while easy to fix (just subtract the value from 1.0f), I'm trying to decipher the cause of. Also, the details for the second option depends on when you need the values, and what colour information you need for your original scene. E.g. in my case, I can just put gl_FragCoord.z as my alpha channel value, because I'm not actually displaying my render result. If you do need the alpha channel of your original render intact, though, perhaps multiple render targets, one of which gets the gl_FragCoord.z value, would be the solution?

FilmCoder
  • 94
  • 5