Programming an UWP app using Angle to run OpenGL ES, I am facing an issue with the basic operation of reading from a frame buffer object with glReadPixels
.
Starting from the Visual Studio Template "OpenglES2 Application (Android,iOS,Windows Universal)", I can retrieve the default scene rendering into a memory buffer.
Initialization :
void SimpleRenderer::InitFbo()
{
int buf_size = tex_height*tex_width * 4;
mReadBuf = new char[buf_size];
memset(mReadBuf, 123, buf_size); // arbitrary value to detect changes
}
Draw function :
void SimpleRenderer::Draw()
{
// drawing calls here
// (...)
glReadPixels(0, 0, tex_width, tex_height, GL_RGBA, GL_UNSIGNED_BYTE, mReadBuf);
// success : mReadBuf is updated with pixel values
}
But if I just create a frame buffer object, try to draw in there and retrieve the result, glReadPixels
doesn't return any value, and glError
returns INVALID_FRAMEBUFFER_OPERATION
.
Initialization :
void SimpleRenderer::InitFbo()
{
glGenFramebuffers(1, &mRenderFbo);
glGenTextures(1, &mRenderTexture);
int buf_size = tex_height*tex_width * 4;
char*buf = new char[buf_size];
memset(buf, 255, buf_size);
glBindTexture(GL_TEXTURE_2D, mRenderTexture);
glTexImage2D(GL_TEXTURE_2D, 0, 4,
tex_width,
tex_height,
0, GL_RGBA, GL_UNSIGNED_BYTE,
buf);
glBindFramebuffer(GL_FRAMEBUFFER, mRenderFbo);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
mRenderTexture, 0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
delete[] buf;
mReadBuf = new char[buf_size];
memset(mReadBuf, 123, buf_size);
}
Draw function :
void SimpleRenderer::Draw()
{
glBindFramebuffer(GL_FRAMEBUFFER, mRenderFbo);
// drawing calls here
// (...)
glReadPixels(0, 0, tex_width, tex_height, GL_RGBA, GL_UNSIGNED_BYTE, mReadBuf);
// failure : mReadBuf is unchanged
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
*edit - solved thanks to the comment below. Correct initialization of the texture is
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
tex_width,
tex_height,
0, GL_RGBA, GL_UNSIGNED_BYTE,
buf);
For the record, before it got resolved I was checking the framebuffer status with glCheckFramebufferStatus
, which returned GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT
.
The 3rd parameter of the OpenGL function glTexImage2D
specifies the internal format of the texture buffer.
In the method SimpleRenderer::InitFbo
you pass 4
to the internal format, which is not a valid parameter. Use GL_RGBA
instead:
glTexImage2D(GL_TEXTURE_2D, 0,
GL_RGBA, // <-----------------------
tex_width,
tex_height,
0, GL_RGBA, GL_UNSIGNED_BYTE,
buf);
Note, valide parameters for the internal format (in OpenGL ES 2.0) are GL_ALPHA
, GL_LUMINANCE
, GL_LUMINANCE_ALPHA
, GL_RGB
, GL_RGBA
.
If you use glGetError
after the call of glTexImage2D
you will get GL_INVALID_VALUE
which is generated if internal format is not an accepted format. In addition, this causes an GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT
error (when checking with glCheckFramebufferStatus
), if the texture is attached to a frame buffer and glReadPixels
causes a INVALID_FRAMEBUFFER_OPERATION
error.