I’m implementing picking by rendering integer IDs into a framebuffer (FBO). As the buffer format, I’m using GL_RGBA32UI, which is an INTEGER format. My shaders correctly write the integer IDs into the buffer and I can read them back with glReadPixels. However, the problem is clearing the buffer with non-zero integer numbers using glClearBuffer. When I clear with 1, I would expect to read back 1. On NVIDIA cards clearing works as expected. However, on AMD, when I clear with 1, I read back 1065353216. Interestingly, bit-wise speaking 1065353216 INT corresponds to 1.0 FLOAT.
In any case, when I clear a buffer with 1 INT, I expect to read back 1 INT (and neither 1065353216 INT nor 1.0 FLOAT).
- What is the correct way to clear an integer framebuffer?
- Is the behavior on AMD cards a driver problem?
A corresponding test case is below. Tests have been made on Windows 7 and Ubuntu 12.10. It works correctly on NVIDIA, but fails on AMD.
#include <stdio.h>
#include <GL/glew.h>
#include <GL/freeglut.h>
GLuint fbo = 0;
void Display()
{
// Clear buffer
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
GLuint in[4] = {0, 1, 2, 3};
glClearBufferuiv(GL_COLOR, 0, in);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
// Read back from the buffer, expect to find the same values as used for clearing
glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo);
unsigned int out[4] = {0, 0, 0, 0};
glReadBuffer(GL_COLOR_ATTACHMENT0);
glReadPixels(0, 0, 1, 1, GL_RGBA_INTEGER, GL_UNSIGNED_INT, &out);
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
printf("IN %d %d %d %d
", in[0], in[1], in[2], in[3]);
printf("OUT %d %d %d %d
", out[0], out[1], out[2], out[3]);
glutSwapBuffers();
}
int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGBA|GLUT_DEPTH);
glutInitWindowSize(1024, 768);
glutInitWindowPosition(100, 100);
glutCreateWindow("OpenGL");
glutDisplayFunc(Display);
GLenum status = glewInit();
if (status != GLEW_OK) {
printf("Error: %s
", glewGetErrorString(status));
return EXIT_FAILURE;
}
// Create the FBO
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
GLuint tex = 0;
// Create a texture object for the picking buffer
glGenTextures(1, &tex);
glBindTexture(GL_TEXTURE_2D, tex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32UI, 1024, 768, 0, GL_RGBA_INTEGER, GL_UNSIGNED_INT, NULL);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0);
// Create a texture object for the depth buffer
glGenTextures(1, &tex);
glBindTexture(GL_TEXTURE_2D, tex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, 1024, 768, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, tex, 0);
// Verify that the FBO is correct
status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE) {
printf("Error: status 0x%x
", status);
return EXIT_FAILURE;
}
// Restore the default framebuffer
glBindTexture(GL_TEXTURE_2D, 0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glutMainLoop();
return 0;
}