[AD] Conserving OpenGL FBOs

[ Thread Index | Date Index | More lists.liballeg.org/allegro-developers Archives ]


I've got a patch that is supposed to use fbos from a pool (of 8 right
now). I don't get any slowdown in ex_bitmap_target, and my game, which
was getting an X error about out of resources, is working now... so I
think this patch is at least partially right. I'd like to have someone
review it if possible before I commit it though. It's attached. Would
appreciate any comments.

Thanks,
Trent
Index: include/allegro5/internal/aintern_opengl.h
===================================================================
--- include/allegro5/internal/aintern_opengl.h	(revision 14537)
+++ include/allegro5/internal/aintern_opengl.h	(working copy)
@@ -23,7 +23,18 @@
    _ALLEGRO_OPENGL_VERSION_4_0   = 0x04000000
 };
 
+#define ALLEGRO_MAX_OPENGL_FBOS 8
 
+struct ALLEGRO_BITMAP_OGL;
+
+typedef struct ALLEGRO_FBO_INFO
+{
+   bool used;
+   GLuint fbo;
+   struct ALLEGRO_BITMAP_OGL *owner;
+   double creation_time;
+} ALLEGRO_FBO_INFO;
+
 typedef struct ALLEGRO_BITMAP_OGL
 {
    ALLEGRO_BITMAP bitmap; /* This must be the first member. */
@@ -41,7 +52,7 @@
    NativeWindowType pbuf_native_wnd;
    bool changed;
 #else
-   GLuint fbo; /* 0 means, no fbo yet. */
+   ALLEGRO_FBO_INFO *fbo_info;
 #endif
 
    unsigned char *lock_buffer;
@@ -81,6 +92,8 @@
    /* True if display resources are shared among displays. */
    bool is_shared;
 
+   ALLEGRO_FBO_INFO fbos[ALLEGRO_MAX_OPENGL_FBOS];
+
    GLuint program_object; // Shader object
 
    /* Shader variable addresses. If the user is using the programmable pipeline,
Index: src/opengl/ogl_display.c
===================================================================
--- src/opengl/ogl_display.c	(revision 14537)
+++ src/opengl/ogl_display.c	(working copy)
@@ -28,34 +28,56 @@
 #include "allegro5/internal/aintern_iphone.h"
 #endif
 
+#include <float.h>
+
 ALLEGRO_DEBUG_CHANNEL("opengl")
 
+static ALLEGRO_FBO_INFO *ogl_find_unused_fbo(ALLEGRO_DISPLAY *display)
+{
+	ALLEGRO_OGL_EXTRAS *extras = display->ogl_extras;
+	double min_time = DBL_MAX;
+	int min_time_index = -1;
+	int i;
+
+	for (i = 0; i < ALLEGRO_MAX_OPENGL_FBOS; i++) {
+		if (!extras->fbos[i].used)
+			return &extras->fbos[i];
+		if (extras->fbos[i].creation_time < min_time) {
+			min_time = extras->fbos[i].creation_time;
+			min_time_index = i;
+		}
+	}
+
+	return &extras->fbos[min_time_index];
+}
+
 static void setup_fbo(ALLEGRO_DISPLAY *display, ALLEGRO_BITMAP *bitmap)
 {
    ALLEGRO_BITMAP_OGL *ogl_bitmap;
+   ALLEGRO_FBO_INFO *info;
+   GLuint delete_fbo = 0;
    
+   #ifdef ALLEGRO_IPHONE
+   #define glGenFramebuffersEXT glGenFramebuffersOES
+   #define glBindFramebufferEXT glBindFramebufferOES
+   #define GL_FRAMEBUFFER_EXT GL_FRAMEBUFFER_OES
+   #define GL_COLOR_ATTACHMENT0_EXT GL_COLOR_ATTACHMENT0_OES
+   #define glCheckFramebufferStatusEXT glCheckFramebufferStatusOES
+   #define glFramebufferTexture2DEXT glFramebufferTexture2DOES
+   #define GL_FRAMEBUFFER_COMPLETE_EXT GL_FRAMEBUFFER_COMPLETE_OES
+   #define glDeleteFramebuffersEXT glDeleteFramebuffersOES
+   #define glOrtho glOrthof
+   #endif
+
    if (bitmap->parent) bitmap = bitmap->parent;
    ogl_bitmap = (void *)bitmap;
 
 #if !defined ALLEGRO_GP2XWIZ
    if (!ogl_bitmap->is_backbuffer) {
        
-      // FIXME: ...
-      #ifdef ALLEGRO_IPHONE
-      #define glGenFramebuffersEXT glGenFramebuffersOES
-      #define glBindFramebufferEXT glBindFramebufferOES
-      #define GL_FRAMEBUFFER_EXT GL_FRAMEBUFFER_OES
-      #define GL_COLOR_ATTACHMENT0_EXT GL_COLOR_ATTACHMENT0_OES
-      #define glCheckFramebufferStatusEXT glCheckFramebufferStatusOES
-      #define glFramebufferTexture2DEXT glFramebufferTexture2DOES
-      #define GL_FRAMEBUFFER_COMPLETE_EXT GL_FRAMEBUFFER_COMPLETE_OES
-      #define glDeleteFramebuffersEXT glDeleteFramebuffersOES
-      #define glOrtho glOrthof
-      #endif
-
       /* When a bitmap is set as target bitmap, we try to create an FBO for it.
        */
-      if (ogl_bitmap->fbo == 0 && !(bitmap->flags & ALLEGRO_FORCE_LOCKING)) {
+      if (ogl_bitmap->fbo_info == NULL && !(bitmap->flags & ALLEGRO_FORCE_LOCKING)) {
       
    /* FIXME This is quite a hack but I don't know how the Allegro extension
     * manager works to fix this properly (getting extensions properly reported
@@ -67,18 +89,33 @@
          if (al_get_opengl_extension_list()->ALLEGRO_GL_EXT_framebuffer_object ||
             al_get_opengl_extension_list()->ALLEGRO_GL_OES_framebuffer_object) {
 #endif
-            glGenFramebuffersEXT(1, &ogl_bitmap->fbo);
+            info = ogl_find_unused_fbo(display);
+            if (info->used) {
+               info->owner->fbo_info = NULL;
+               delete_fbo = info->fbo;
+               memset(info, 0, sizeof(*info));
+            }
+
+            glGenFramebuffersEXT(1, &info->fbo);
          }
       }
+      else {
+         info = ogl_bitmap->fbo_info;
+      }
 
-      if (ogl_bitmap->fbo) {
+      if (info && info->fbo) {
          /* Bind to the FBO. */
 #ifndef ALLEGRO_IPHONE
          ASSERT(display->ogl_extras->extension_list->ALLEGRO_GL_EXT_framebuffer_object ||
          display->ogl_extras->extension_list->ALLEGRO_GL_OES_framebuffer_object);
 #endif
-         glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, ogl_bitmap->fbo);
+         info->used = true;
+         info->owner = ogl_bitmap;
+         info->creation_time = al_get_time();
+         ogl_bitmap->fbo_info = info;
 
+         glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, info->fbo);
+
          /* Attach the texture. */
          glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
             GL_TEXTURE_2D, ogl_bitmap->texture, 0);
@@ -92,8 +129,9 @@
                _al_format_name(bitmap->format));
             ALLEGRO_ERROR("*** SWITCHING TO SOFTWARE MODE ***\n");
             glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
-            glDeleteFramebuffersEXT(1, &ogl_bitmap->fbo);
-            ogl_bitmap->fbo = 0;
+            glDeleteFramebuffersEXT(1, &info->fbo);
+            memset(info, 0, sizeof(*info));
+            ogl_bitmap->fbo_info = NULL;
          }
          else {
             display->ogl_extras->opengl_target = ogl_bitmap;
@@ -163,6 +201,10 @@
       glOrtho(0, display->w, display->h, 0, -1, 1);
    }
 #endif
+
+   if (delete_fbo != 0) {
+      glDeleteFramebuffersEXT(1, &delete_fbo);
+   }
 }
 
 void _al_ogl_set_target_bitmap(ALLEGRO_DISPLAY *display, ALLEGRO_BITMAP *bitmap)
Index: src/opengl/ogl_bitmap.c
===================================================================
--- src/opengl/ogl_bitmap.c	(revision 14537)
+++ src/opengl/ogl_bitmap.c	(working copy)
@@ -346,7 +346,7 @@
             /* In general, we can't modify the texture while it's
              * FBO bound - so we temporarily disable the FBO.
              */
-            if (ogl_target->fbo)
+            if (ogl_target->fbo_info)
                _al_ogl_set_target_bitmap(disp, bitmap);
             
             /* We need to do clipping because glCopyTexSubImage2D
@@ -378,7 +378,7 @@
                 sx, bitmap->h - sy - sh,
                 sw, sh);
             /* Fix up FBO again after the copy. */
-            if (ogl_target->fbo)
+            if (ogl_target->fbo_info)
                _al_ogl_set_target_bitmap(disp, target);
             return;
          }
@@ -679,7 +679,7 @@
             GLint current_fbo;
 
             /* Create an FBO if there isn't one. */
-            if (!ogl_bitmap->fbo) {
+            if (!ogl_bitmap->fbo_info) {
                ALLEGRO_STATE state;
                al_store_state(&state, ALLEGRO_STATE_TARGET_BITMAP);
                bitmap->locked = false; // hack :(
@@ -689,7 +689,7 @@
             }
 
             glGetIntegerv(GL_FRAMEBUFFER_BINDING_OES, &current_fbo);
-            glBindFramebufferOES(GL_FRAMEBUFFER_OES, ogl_bitmap->fbo);
+            glBindFramebufferOES(GL_FRAMEBUFFER_OES, ogl_bitmap->fbo_info->fbo);
 
             pitch = ogl_pitch(w, pixel_size);
             ogl_bitmap->lock_buffer = al_malloc(pitch * h);
@@ -999,17 +999,16 @@
       _al_set_current_display_only(bitmap->display);
    }
 
+   if (ogl_bitmap->fbo_info) {
+      if (ogl_bitmap->fbo_info->fbo) {
 #if !defined ALLEGRO_GP2XWIZ && !defined ALLEGRO_IPHONE
-   if (ogl_bitmap->fbo) {
-      glDeleteFramebuffersEXT(1, &ogl_bitmap->fbo);
-      ogl_bitmap->fbo = 0;
-   }
+         glDeleteFramebuffersEXT(1, &ogl_bitmap->fbo_info->fbo);
 #elif defined ALLEGRO_IPHONE
-   if (ogl_bitmap->fbo) {
-      glDeleteFramebuffersOES(1, &ogl_bitmap->fbo);
-      ogl_bitmap->fbo = 0;
+         glDeleteFramebuffersOES(1, &ogl_bitmap->fbo_info->fbo);
+#endif
+      }
+      memset(ogl_bitmap->fbo_info, 0, sizeof(ALLEGRO_FBO_INFO));
    }
-#endif
 
    if (ogl_bitmap->texture) {
       glDeleteTextures(1, &ogl_bitmap->texture);
@@ -1149,7 +1148,7 @@
    ogl_bmp->texture = ogl_parent->texture;
 
 #if !defined ALLEGRO_GP2XWIZ
-   ogl_bmp->fbo = ogl_parent->fbo;
+   ogl_bmp->fbo_info = ogl_parent->fbo_info;
 #endif
 
    ogl_bmp->left = x / (float)ogl_parent->true_w;
@@ -1182,9 +1181,10 @@
 #if !defined ALLEGRO_GP2XWIZ && !defined ALLEGRO_IPHONE
    ALLEGRO_BITMAP_OGL *ogl_bitmap = (void *)bitmap;
    if (!(bitmap->flags & _ALLEGRO_INTERNAL_OPENGL)) return;
-   if (ogl_bitmap->fbo) {
-      glDeleteFramebuffersEXT(1, &ogl_bitmap->fbo);
-      ogl_bitmap->fbo = 0;
+   if (ogl_bitmap->fbo_info) {
+      glDeleteFramebuffersEXT(1, &ogl_bitmap->fbo_info->fbo);
+      memset(ogl_bitmap->fbo_info, 0, sizeof(ALLEGRO_FBO_INFO));
+      ogl_bitmap->fbo_info = NULL;
    }
 #else
    (void)bitmap;
@@ -1198,7 +1198,7 @@
 #if !defined ALLEGRO_GP2XWIZ
    ALLEGRO_BITMAP_OGL *ogl_bitmap = (void *)bitmap;
    if (!(bitmap->flags & _ALLEGRO_INTERNAL_OPENGL)) return 0;
-   return ogl_bitmap->fbo;
+   return ogl_bitmap->fbo_info == NULL ? 0 : ogl_bitmap->fbo_info->fbo;
 #else
    (void)bitmap;
    return 0;


Mail converted by MHonArc 2.6.19+ http://listengine.tuxfamily.org/