Support multi-texture FBOs in ResourcePool.
authorSteinar H. Gunderson <sgunderson@bigfoot.com>
Wed, 16 Sep 2015 20:33:09 +0000 (22:33 +0200)
committerSteinar H. Gunderson <sgunderson@bigfoot.com>
Wed, 16 Sep 2015 20:44:09 +0000 (22:44 +0200)
resource_pool.cpp
resource_pool.h
version.h

index 152793c..f82996e 100644 (file)
@@ -312,18 +312,29 @@ void ResourcePool::release_2d_texture(GLuint texture_num)
                for (map<pair<void *, GLuint>, 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<pair<void *, GLuint>, 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<void *, GLuint> 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<void *, GLuint> 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();
index a331f4f..b218d7a 100644 (file)
@@ -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<GLuint> 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
index 616c4be..4d645f4 100644 (file)
--- 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)