My voxel renderer app fails to create a framebuffer object only during launch / initial window resize event. It is an ERROR: GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT error. I'm working with the latest SDL version (building from the main branch), and I think that the initial render/launch of my app fails because it cannot create an OpenGL 3.0 framebuffer object until certain events occur like SDL_EVENT_WINDOW_RESIZED. The reason I think this is because once I move the window manually on screen during runtime the FBO is created without errors. The problem is that I don't want to make users have to manually reposition the window to render the voxel scene.
I create the FBO, RBO, and texture in a C++ lambda like this:
auto create_fbo = [](GLuint width, GLuint height)->tuple<GLuint, GLuint, GLuint> {
GLuint fbo, depthRenderbuffer, texture;
glGenFramebuffers(1, &fbo);
glGenRenderbuffers(1, &depthRenderbuffer);
glGenTextures(1, &texture);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glBindTexture(GL_TEXTURE_2D, texture);
glActiveTexture(GL_TEXTURE6);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
glBindRenderbuffer(GL_RENDERBUFFER, depthRenderbuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, depthRenderbuffer);
// Check for FBO initialization errors
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE) {
switch (status) {
case GL_FRAMEBUFFER_UNDEFINED:
SDL_LogError(SDL_LOG_CATEGORY_ERROR, "GL_FRAMEBUFFER_UNDEFINED\n");
break;
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
SDL_LogError(SDL_LOG_CATEGORY_ERROR, "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT\n");
break;
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
SDL_LogError(SDL_LOG_CATEGORY_ERROR, "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT\n");
break;
case GL_FRAMEBUFFER_UNSUPPORTED:
SDL_LogError(SDL_LOG_CATEGORY_ERROR, "GL_FRAMEBUFFER_UNSUPPORTED\n");
break;
case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE:
SDL_LogError(SDL_LOG_CATEGORY_ERROR, "GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE\n");
break;
#if !defined(__EMSCRIPTEN__)
case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER:
SDL_LogError(SDL_LOG_CATEGORY_ERROR, "GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER\n");
break;
case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER:
SDL_LogError(SDL_LOG_CATEGORY_ERROR, "GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER\n");
break;
#endif
default:
SDL_LogError(SDL_LOG_CATEGORY_ERROR, "Unknown FBO error\n");
break;
}
return {};
}
SDL_Log("Creating FBO with width: %d and height: %d\n", width, height);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
return {fbo, depthRenderbuffer, texture};
};
I call this function on SDL window resize events (which are handle in an SDL_PollEvent loop):
case SDL_EVENT_WINDOW_EXPOSED:
case SDL_EVENT_WINDOW_RESIZED: {
if (glIsTexture(get<2>(fbo_tuple))) {
glDeleteTextures(1, &get<2>(fbo_tuple));
glDeleteRenderbuffers(1, &get<1>(fbo_tuple));
glDeleteFramebuffers(1, &get<0>(fbo_tuple));
}
fbo_tuple = create_fbo(voxel_scene_w, voxel_scene_h);
}
break;
}
The FBO is used with get<0>(fbo_tuple) and it will render as expected, but to get the render to function properly I have to manually trigger the SDL_EVENT_WINDOW_RESIZED or SDL_EVENT_WINDOW_EXPOSED event. It throws the OpenGL error on launch / first resize event.