Hi,
I have problems with layered framebuffers and cube maps.
After succesfully attaching a cube map texture to a framebuffer with glFramebufferTexture and performing a rendering, it turns out that only the first face is actually written.
On the other hand, layered rendering works as expected with a texture 2D array with 6 layers.
I tried with several formats, always obtaining a complete framebuffer but also with the same issue.
I prepared two small test cases that use 1x1 cube map and 2D array. They initialize the face/layers with some values, attach them, execute just a clear to black, an then read back the result.
As you will see, the only difference between the two tests is just the attached resource. 2D array gives the expected results (black texels in all layers), while cube map fails in all faces but X+.
Here is the code (you can copy & paste it in whichever GL application after glew initialization):
void checkGLError(const char * msg)
{
const GLenum err = glGetError();
if (err == GL_NO_ERROR) return;
printf("%s: GL ERROR %d
", msg, int(err));
}
void testLayeredCubeMap(void)
{
glGetError(); // flush error
const GLubyte colors[6][4] =
{
{ 255, 0, 0, 255 }, // red
{ 0, 255, 0, 255 }, // green
{ 0, 0, 255, 255 }, // blue
{ 255, 255, 0, 255 }, // yellow
{ 0, 255, 255, 255 }, // cyan
{ 255, 0, 255, 255 } // magenta
};
// create cubemap texture
GLuint tex = 0;
glGenTextures(1, &tex);
glBindTexture(GL_TEXTURE_CUBE_MAP, tex);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
for (int face=0; face<6; ++face)
{
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, 0, GL_RGBA8, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, colors[face]);
}
glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
checkGLError("CubeMap - Texture Creation");
// create layered framebuffer
GLuint fbo = 0;
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
glFramebufferTexture(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex, 0);
glDrawBuffer(GL_COLOR_ATTACHMENT0);
checkGLError("CubeMap - Framebuffer Creation");
if (glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
{
printf("CubeMap - Framebuffer Not Complete.
");
return;
}
// clear
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT);
checkGLError("CubeMap - Framebuffer Clear");
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
glGetError(); // flush error
// readback and test
GLubyte texel[4];
glBindTexture(GL_TEXTURE_CUBE_MAP, tex);
for (int face=0; face<6; ++face)
{
glGetTexImage(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, 0, GL_RGBA, GL_UNSIGNED_BYTE, texel);
printf("CubeMap Face %d: [%.3d, %.3d, %.3d, %.3d]
", face, int(texel[0]), int(texel[1]), int(texel[2]), int(texel[3]));
}
glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
checkGLError("CubeMap - Texture Readback");
// clear resources
glDeleteFramebuffers(1, &fbo);
glDeleteTextures(1, &tex);
checkGLError("CubeMap - Resources Destruction");
}
void testLayered2DArray(void)
{
glGetError(); // flush error
const GLubyte colors[6][4] =
{
{ 255, 0, 0, 255 }, // red
{ 0, 255, 0, 255 }, // green
{ 0, 0, 255, 255 }, // blue
{ 255, 255, 0, 255 }, // yellow
{ 0, 255, 255, 255 }, // cyan
{ 255, 0, 255, 255 } // magenta
};
// create 2D array texture
GLuint tex = 0;
glGenTextures(1, &tex);
glBindTexture(GL_TEXTURE_2D_ARRAY, tex);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, 1, 1, 6, 0, GL_RGBA, GL_UNSIGNED_BYTE, colors);
glBindTexture(GL_TEXTURE_2D_ARRAY, 0);
checkGLError("2D Array - Texture Creation");
// create layered framebuffer
GLuint fbo = 0;
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
glFramebufferTexture(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex, 0);
glDrawBuffer(GL_COLOR_ATTACHMENT0);
checkGLError("2D Array - Framebuffer Creation");
if (glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
{
printf("2D Array - Framebuffer Not Complete.
");
return;
}
// clear
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT);
checkGLError("2D Array - Framebuffer Clear");
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
glGetError(); // flush error
// readback and test
GLubyte texels[6][4];
glBindTexture(GL_TEXTURE_2D_ARRAY, tex);
glGetTexImage(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA, GL_UNSIGNED_BYTE, texels);
glBindTexture(GL_TEXTURE_2D_ARRAY, 0);
for (int layer=0; layer<6; ++layer)
{
printf("2D Array Layer %d: [%.3d, %.3d, %.3d, %.3d]
", layer, int(texels[layer][0]), int(texels[layer][1]), int(texels[layer][2]), int(texels[layer][3]));
}
checkGLError("2D Array - Texture Readback");
// clear resources
glDeleteFramebuffers(1, &fbo);
glDeleteTextures(1, &tex);
checkGLError("2D Array - Resources Destruction");
}
Am I missing something?
After long time looking at the specs and searching the internet for proper sample code or similar problems (and I found someone with the same problem with no solution even in this forum, http://www.opengl.org/discussion_boards/ubbthreads.php?ubb=showflat&Number=295703), I am suspecting a driver bug.
The test fails with NVIDIA GTX 560, 275 and 260, 295.73 drivers on Windows 7 64 bits.
Thank you!
Marco.