From f705cd2a092c0f41603f0d4d619f72dbde476212 Mon Sep 17 00:00:00 2001 From: "Steinar H. Gunderson" Date: Wed, 16 Sep 2015 22:33:09 +0200 Subject: [PATCH] Support multi-texture FBOs in ResourcePool. --- resource_pool.cpp | 66 +++++++++++++++++++++++++++++++++++++---------- resource_pool.h | 12 ++++++--- version.h | 2 +- 3 files changed, 63 insertions(+), 17 deletions(-) diff --git a/resource_pool.cpp b/resource_pool.cpp index 152793c..f82996e 100644 --- a/resource_pool.cpp +++ b/resource_pool.cpp @@ -312,18 +312,29 @@ void ResourcePool::release_2d_texture(GLuint texture_num) for (map, FBO>::iterator format_it = fbo_formats.begin(); format_it != fbo_formats.end(); ++format_it) { - if (format_it->second.texture_num == free_texture_num) { - format_it->second.texture_num = 0; + for (unsigned i = 0; i < num_fbo_attachments; ++i) { + if (format_it->second.texture_num[i] == free_texture_num) { + format_it->second.texture_num[i] = GL_INVALID_INDEX; + } } } } pthread_mutex_unlock(&lock); } -GLuint ResourcePool::create_fbo(GLuint texture_num) +GLuint ResourcePool::create_fbo(GLuint texture0_num, GLuint texture1_num, GLuint texture2_num, GLuint texture3_num) { void *context = get_gl_context_identifier(); + // Make sure we are filled from the bottom. + assert(texture0_num != 0); + if (texture1_num == 0) { + assert(texture2_num == 0); + } + if (texture2_num == 0) { + assert(texture3_num == 0); + } + pthread_mutex_lock(&lock); if (fbo_freelist.count(context) != 0) { // See if there's an FBO on the freelist we can use. @@ -334,7 +345,10 @@ GLuint ResourcePool::create_fbo(GLuint texture_num) map, FBO>::const_iterator format_it = fbo_formats.find(make_pair(context, fbo_num)); assert(format_it != fbo_formats.end()); - if (format_it->second.texture_num == texture_num) { + if (format_it->second.texture_num[0] == texture0_num && + format_it->second.texture_num[1] == texture1_num && + format_it->second.texture_num[2] == texture2_num && + format_it->second.texture_num[3] == texture3_num) { fbo_freelist[context].erase(freelist_it); pthread_mutex_unlock(&lock); return fbo_num; @@ -343,25 +357,42 @@ GLuint ResourcePool::create_fbo(GLuint texture_num) } // Create a new one. + FBO fbo_format; + fbo_format.texture_num[0] = texture0_num; + fbo_format.texture_num[1] = texture1_num; + fbo_format.texture_num[2] = texture2_num; + fbo_format.texture_num[3] = texture3_num; + GLuint fbo_num; glGenFramebuffers(1, &fbo_num); check_error(); glBindFramebuffer(GL_FRAMEBUFFER, fbo_num); check_error(); - glFramebufferTexture2D( - GL_FRAMEBUFFER, - GL_COLOR_ATTACHMENT0, - GL_TEXTURE_2D, - texture_num, - 0); + + GLenum bufs[num_fbo_attachments]; + unsigned num_active_attachments = 0; + for (unsigned i = 0; i < num_fbo_attachments; ++i, ++num_active_attachments) { + if (fbo_format.texture_num[i] == 0) { + break; + } + glFramebufferTexture2D( + GL_FRAMEBUFFER, + GL_COLOR_ATTACHMENT0 + i, + GL_TEXTURE_2D, + fbo_format.texture_num[i], + 0); + check_error(); + bufs[i] = GL_COLOR_ATTACHMENT0 + i; + } + + glDrawBuffers(num_active_attachments, bufs); check_error(); + GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); assert(status == GL_FRAMEBUFFER_COMPLETE); glBindFramebuffer(GL_FRAMEBUFFER, 0); check_error(); - FBO fbo_format; - fbo_format.texture_num = texture_num; pair key(context, fbo_num); assert(fbo_formats.count(key) == 0); fbo_formats.insert(make_pair(key, fbo_format)); @@ -403,7 +434,16 @@ void ResourcePool::cleanup_unlinked_fbos(void *context) GLuint fbo_num = *freelist_it; pair key(context, fbo_num); assert(fbo_formats.count(key) != 0); - if (fbo_formats[key].texture_num == 0) { + + bool all_unlinked = true; + for (unsigned i = 0; i < num_fbo_attachments; ++i) { + if (fbo_formats[key].texture_num[i] != 0 && + fbo_formats[key].texture_num[i] != GL_INVALID_INDEX) { + all_unlinked = false; + break; + } + } + if (all_unlinked) { fbo_formats.erase(key); glDeleteFramebuffers(1, &fbo_num); check_error(); diff --git a/resource_pool.h b/resource_pool.h index a331f4f..b218d7a 100644 --- a/resource_pool.h +++ b/resource_pool.h @@ -66,7 +66,7 @@ public: GLuint create_2d_texture(GLint internal_format, GLsizei width, GLsizei height); void release_2d_texture(GLuint texture_num); - // Allocate an FBO with the the given texture bound as a framebuffer attachment, + // Allocate an FBO with the the given texture(s) bound as framebuffer attachment(s), // or fetch a previous used if possible. Unbinds GL_FRAMEBUFFER afterwards. // Keeps ownership of the FBO; you must call release_fbo() of deleting // it when you no longer want it. @@ -77,7 +77,10 @@ public: // in particular on NVidia cards. Also, keep in mind that FBOs are not // shareable across contexts, so you must have the context that's supposed // to own the FBO current when you create or release it. - GLuint create_fbo(GLuint texture_num); + GLuint create_fbo(GLuint texture0_num, + GLuint texture1_num = 0, + GLuint texture2_num = 0, + GLuint texture3_num = 0); void release_fbo(GLuint fbo_num); // Informs the ResourcePool that the current context is going away soon, @@ -138,8 +141,11 @@ private: std::list texture_freelist; size_t texture_freelist_bytes; + static const unsigned num_fbo_attachments = 4; struct FBO { - GLuint texture_num; // 0 means associated to a texture that has since been deleted. + // GL_INVALID_INDEX means associated to a texture that has since been deleted. + // 0 means the output isn't bound. + GLuint texture_num[num_fbo_attachments]; }; // For each context, a mapping from FBO number to format details. This is diff --git a/version.h b/version.h index 616c4be..4d645f4 100644 --- a/version.h +++ b/version.h @@ -5,6 +5,6 @@ // changes, even within git versions. There is no specific version // documentation outside the regular changelogs, though. -#define MOVIT_VERSION 2 +#define MOVIT_VERSION 3 #endif // !defined(_MOVIT_VERSION_H) -- 2.39.2