[AD] Deferred bitmap drawing diff

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


So, I implemented the aforementioned deferred bitmap drawing feature for the OpenGL driver. The diff for it is attached. I temporarily modified the ex_ttf example to have the option of using it for drawing the fonts. Press space to turn it on/off. I'm curious what improvement you all can see with it. For me, the FPS increases from ~700 to ~1050. If it's a significant improvement, then I figure I can go ahead and do some more serious tests to make sure I broke nothing, and commit it, so any comments on how I implemented it are very welcome too.

Keep in mind that this only works for OpenGL at this time, so if you're on Windows, you'll need fiddle with the configuration file accordingly.

-SiegeLord


      
Index: include/allegro5/internal/aintern_opengl.h
===================================================================
--- include/allegro5/internal/aintern_opengl.h	(revision 12717)
+++ include/allegro5/internal/aintern_opengl.h	(working copy)
@@ -63,7 +63,12 @@
 
 } ALLEGRO_OGL_EXTRAS;
 
+typedef struct ALLEGRO_OGL_BITMAP_VERTEX{
+   float x, y;
+   float tx, ty;
+} ALLEGRO_OGL_BITMAP_VERTEX;
 
+
 /* extensions */
 int  _al_ogl_look_for_an_extension(AL_CONST char *name, AL_CONST GLubyte *extensions);
 void _al_ogl_set_extensions(ALLEGRO_OGL_EXT_API *ext);
Index: include/allegro5/internal/aintern_display.h
===================================================================
--- include/allegro5/internal/aintern_display.h	(revision 12717)
+++ include/allegro5/internal/aintern_display.h	(working copy)
@@ -64,6 +64,9 @@
    void (*get_window_position)(ALLEGRO_DISPLAY *display, int *x, int *y);
    void (*toggle_frame)(ALLEGRO_DISPLAY *display, bool onoff);
    void (*set_window_title)(ALLEGRO_DISPLAY *display, AL_CONST char *title);
+   
+   void (*flush_vertex_cache)(ALLEGRO_DISPLAY *d);
+   void* (*prepare_vertex_cache)(ALLEGRO_DISPLAY *d, int num_new_vertices);
 
    void (*shutdown)(void);
 };
@@ -99,6 +102,12 @@
    struct ALLEGRO_OGL_EXTRAS *ogl_extras;
 
    _AL_VECTOR bitmaps; /* A list of bitmaps created for this display. */
+   
+   int num_cache_vertices;
+   bool cache_enabled;
+   int vertex_cache_size;
+   void* vertex_cache;
+   unsigned int cache_texture;
 };
 
 int  _al_score_display_settings(ALLEGRO_EXTRA_DISPLAY_SETTINGS *eds, ALLEGRO_EXTRA_DISPLAY_SETTINGS *ref);
Index: include/allegro5/display_new.h
===================================================================
--- include/allegro5/display_new.h	(revision 12717)
+++ include/allegro5/display_new.h	(working copy)
@@ -158,7 +158,10 @@
 AL_FUNC(int, al_get_display_format_option, (int i, int option));
 AL_FUNC(void, al_set_new_display_format, (int i));
 
+/*Deferred drawing*/
+AL_FUNC(void, al_hold_bitmap_drawing, (bool hold));
 
+
 #ifdef __cplusplus
    }
 #endif
Index: src/opengl/ogl_draw.c
===================================================================
--- src/opengl/ogl_draw.c	(revision 12717)
+++ src/opengl/ogl_draw.c	(working copy)
@@ -17,9 +17,9 @@
 #include "allegro5/allegro_opengl.h"
 #include "allegro5/internal/aintern_display.h"
 #include "allegro5/internal/aintern_opengl.h"
+#include "allegro5/internal/aintern_memory.h"
 
 
-
 static bool set_opengl_blending(ALLEGRO_DISPLAY *d,
    ALLEGRO_COLOR *color)
 {
@@ -121,13 +121,74 @@
    glDisableClientState(GL_VERTEX_ARRAY);
 }
 
+static void* ogl_prepare_vertex_cache(ALLEGRO_DISPLAY* disp, 
+                                      int num_new_vertices)
+{
+   disp->num_cache_vertices += num_new_vertices;
+   if(!disp->vertex_cache) {  
+      disp->vertex_cache = _AL_MALLOC(num_new_vertices * sizeof(ALLEGRO_OGL_BITMAP_VERTEX));
+      
+      disp->vertex_cache_size = num_new_vertices;
+   } else if (disp->num_cache_vertices > disp->vertex_cache_size) {
+      disp->vertex_cache = _AL_REALLOC(disp->vertex_cache, 
+                              2 * disp->num_cache_vertices * sizeof(ALLEGRO_OGL_BITMAP_VERTEX));
+                              
+      disp->vertex_cache_size = 2 * disp->num_cache_vertices;
+   }
+   return (ALLEGRO_OGL_BITMAP_VERTEX*)disp->vertex_cache + 
+         (disp->num_cache_vertices - num_new_vertices);
+}
 
+static void ogl_flush_vertex_cache(ALLEGRO_DISPLAY* disp)
+{
+   ALLEGRO_COLOR *bc;
+   GLboolean on;
+   GLuint current_texture;
+   if(!disp->vertex_cache)
+      return;
+   if(disp->num_cache_vertices == 0)
+      return;
+   
+   glGetBooleanv(GL_TEXTURE_2D, &on);
+   if (!on) {
+      glEnable(GL_TEXTURE_2D);
+   }
+   
+   glGetIntegerv(GL_TEXTURE_BINDING_2D, (GLint*)&current_texture);
+   if (current_texture != disp->cache_texture) {
+      glBindTexture(GL_TEXTURE_2D, disp->cache_texture);
+   }
+      
+   bc = _al_get_blend_color();
+   glColor4f(bc->r, bc->g, bc->b, bc->a);
 
+   glEnableClientState(GL_VERTEX_ARRAY);
+   glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+   glDisableClientState(GL_COLOR_ARRAY);
+   
+   glVertexPointer(2, GL_FLOAT, sizeof(ALLEGRO_OGL_BITMAP_VERTEX), disp->vertex_cache);
+   glTexCoordPointer(2, GL_FLOAT, sizeof(ALLEGRO_OGL_BITMAP_VERTEX), 
+                  (char*)(disp->vertex_cache) + offsetof(ALLEGRO_OGL_BITMAP_VERTEX, tx));
+
+   glDrawArrays(GL_TRIANGLES, 0, disp->num_cache_vertices);
+
+   glDisableClientState(GL_VERTEX_ARRAY);
+   glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+   
+   disp->num_cache_vertices = 0;
+   if (!on) {
+      glDisable(GL_TEXTURE_2D);
+   }
+}
+
 /* Add drawing commands to the vtable. */
 void _al_ogl_add_drawing_functions(ALLEGRO_DISPLAY_INTERFACE *vt)
 {
    vt->clear = ogl_clear;
    vt->draw_pixel = ogl_draw_pixel;
+   
+   vt->flush_vertex_cache = ogl_flush_vertex_cache;
+   vt->prepare_vertex_cache = ogl_prepare_vertex_cache;
 }
 
 /* vim: set sts=3 sw=3 et: */
Index: src/opengl/ogl_bitmap.c
===================================================================
--- src/opengl/ogl_bitmap.c	(revision 12717)
+++ src/opengl/ogl_bitmap.c	(working copy)
@@ -23,6 +23,8 @@
 #include "allegro5/internal/aintern_memory.h"
 #include "allegro5/internal/aintern_opengl.h"
 #include "allegro5/internal/aintern_pixels.h"
+#include "allegro5/internal/aintern_display.h"
+#include <math.h>
 
 #if defined ALLEGRO_GP2XWIZ
 #include "allegro5/internal/aintern_gp2xwiz.h"
@@ -190,9 +192,24 @@
    return true;
 }
 
-/* Helper function to draw a bitmap with an internal OpenGL texture as
- * a textured OpenGL quad.
- */
+static INLINE void transform_vertex(float cx, float cy, float dx, float dy, 
+    float xscale, float yscale, float angle, float* x, float* y)
+{
+   if(angle == 0) {
+      *x = xscale * (*x - dx - cx) + dx;
+      *y = yscale * (*y - dy - cy) + dy;
+   } else {
+      float c, s, t;
+      *x = xscale * (*x - dx - cx);
+      *y = yscale * (*y - dy - cy);
+      c = cosf(angle);
+      s = sinf(angle);
+      t = *x;
+      *x = c * *x - s * *y + dx;
+      *y = s * t + c * *y + dy;
+   }
+}
+
 static void draw_quad(ALLEGRO_BITMAP *bitmap,
     float sx, float sy, float sw, float sh,
     float cx, float cy, float dx, float dy, float dw, float dh,
@@ -200,30 +217,16 @@
 {
    float tex_l, tex_t, tex_r, tex_b, w, h, tex_w, tex_h;
    ALLEGRO_BITMAP_OGL *ogl_bitmap = (void *)bitmap;
-   GLboolean on;
-   GLuint current_texture;
-   ALLEGRO_COLOR *bc;
+   ALLEGRO_OGL_BITMAP_VERTEX* verts;
+   ALLEGRO_DISPLAY* disp = al_get_current_display();
 
-   GLfloat verts[2*4];
-   GLfloat texcoords[2*4];
-
-   glGetBooleanv(GL_TEXTURE_2D, &on);
-   if (!on) {
-      glEnable(GL_TEXTURE_2D);
+   if (disp->num_cache_vertices != 0 && ogl_bitmap->texture != disp->cache_texture) {
+      disp->vt->flush_vertex_cache(disp);
    }
-
-#if !defined ALLEGRO_GP2XWIZ && !defined ALLEGRO_IPHONE
-   glGetIntegerv(GL_TEXTURE_2D_BINDING_EXT, (GLint*)&current_texture);
-   if (current_texture != ogl_bitmap->texture) {
-      glBindTexture(GL_TEXTURE_2D, ogl_bitmap->texture);
-   }
-#else
-   glGetIntegerv(GL_TEXTURE_BINDING_2D, (GLint*)&current_texture);
-   if (current_texture != ogl_bitmap->texture) {
-      glBindTexture(GL_TEXTURE_2D, ogl_bitmap->texture);
-   }
-#endif
+   disp->cache_texture = ogl_bitmap->texture;
    
+   verts = disp->vt->prepare_vertex_cache(disp, 6);
+   
    tex_l = ogl_bitmap->left;
    tex_r = ogl_bitmap->right;
    tex_t = ogl_bitmap->top;
@@ -245,41 +248,36 @@
    if (flags & ALLEGRO_FLIP_VERTICAL)
       SWAP(float, tex_t, tex_b);
 
-   bc = _al_get_blend_color();
-   glColor4f(bc->r, bc->g, bc->b, bc->a);
-
-   glPushMatrix();
-   glTranslatef(dx, dy, 0);
-   glRotatef(-(angle * 180 / ALLEGRO_PI), 0, 0, -1);
-   glScalef(xscale, yscale, 1);
-   glTranslatef(-dx - cx, -dy - cy, 0);
-
-   verts[0] = dx; verts[1] = dy+dh;
-   verts[2] = dx; verts[3] = dy;
-   verts[4] = dx+dw; verts[5] = dy+dh;
-   verts[6] = dx+dw; verts[7] = dy;
-   texcoords[0] = tex_l; texcoords[1] = tex_b;
-   texcoords[2] = tex_l; texcoords[3] = tex_t;
-   texcoords[4] = tex_r; texcoords[5] = tex_b;
-   texcoords[6] = tex_r; texcoords[7] = tex_t;
-
-   glEnableClientState(GL_VERTEX_ARRAY);
-   glEnableClientState(GL_TEXTURE_COORD_ARRAY);
-   glDisableClientState(GL_COLOR_ARRAY);
-
-   glVertexPointer(2, GL_FLOAT, 0, verts);
-   glTexCoordPointer(2, GL_FLOAT, 0, texcoords);
-
-   glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
-
-   glDisableClientState(GL_VERTEX_ARRAY);
-   glDisableClientState(GL_TEXTURE_COORD_ARRAY);
-
-   glPopMatrix();
-
-   if (!on) {
-      glDisable(GL_TEXTURE_2D);
-   }
+   verts[0].x = dx;
+   verts[0].y = dy+dh;
+   verts[0].tx = tex_l;
+   verts[0].ty = tex_b;
+   
+   verts[1].x = dx;
+   verts[1].y = dy;
+   verts[1].tx = tex_l;
+   verts[1].ty = tex_t;
+   
+   verts[2].x = dx+dw;
+   verts[2].y = dy+dh;
+   verts[2].tx = tex_r;
+   verts[2].ty = tex_b;
+   
+   verts[4].x = dx+dw;
+   verts[4].y = dy;
+   verts[4].tx = tex_r;
+   verts[4].ty = tex_t;
+   
+   transform_vertex(cx, cy, dx, dy, xscale, yscale, angle, &verts[0].x, &verts[0].y);
+   transform_vertex(cx, cy, dx, dy, xscale, yscale, angle, &verts[1].x, &verts[1].y);
+   transform_vertex(cx, cy, dx, dy, xscale, yscale, angle, &verts[2].x, &verts[2].y);
+   transform_vertex(cx, cy, dx, dy, xscale, yscale, angle, &verts[4].x, &verts[4].y);
+   
+   verts[3] = verts[1];
+   verts[5] = verts[2];
+   
+   if(!disp->cache_enabled)
+      disp->vt->flush_vertex_cache(disp);
 }
 #undef SWAP
 
Index: src/macosx/osxgl.m
===================================================================
--- src/macosx/osxgl.m	(revision 12717)
+++ src/macosx/osxgl.m	(working copy)
@@ -1024,6 +1024,7 @@
    else
       al_set_current_display(NULL);
 
+   _AL_FREE(d->vertex_cache);
    _AL_FREE(d);
 }
 /* create_display:
Index: src/win/wgl_disp.c
===================================================================
--- src/win/wgl_disp.c	(revision 12717)
+++ src/win/wgl_disp.c	(working copy)
@@ -1098,6 +1098,7 @@
    if (old_disp != disp)
       al_set_current_display(old_disp);
 
+   _AL_FREE(wgl_disp->vertex_cache);
    _AL_FREE(wgl_disp);
 }
 
Index: src/win/d3d_disp.cpp
===================================================================
--- src/win/d3d_disp.cpp	(revision 12717)
+++ src/win/d3d_disp.cpp	(working copy)
@@ -1162,6 +1162,7 @@
    }
 
    _al_vector_free(&display->bitmaps);
+   _AL_FREE(display->vertex_cache);
    _AL_FREE(display);
 }
 
@@ -2544,6 +2545,9 @@
    vt->toggle_frame = d3d_toggle_frame;
    vt->set_window_title = _al_win_set_window_title;
    vt->shutdown = d3d_shutdown;
+   
+   vt->flush_vertex_cache = 0;
+   vt->prepare_vertex_cache = 0;
 
    return vt;
 }
Index: src/display_new.c
===================================================================
--- src/display_new.c	(revision 12717)
+++ src/display_new.c	(working copy)
@@ -58,6 +58,13 @@
    system = al_get_system_driver();
    driver = system->vt->get_display_driver();
    display = driver->create_display(w, h);
+   
+   display->vertex_cache = 0;
+   display->num_cache_vertices = 0;
+   display->cache_enabled = false;
+   display->vertex_cache_size = 0;
+   display->cache_texture = 0;
+   
    if (!display) {
       ALLEGRO_DEBUG("Failed to create display (NULL)\n");
       return NULL;
@@ -573,5 +580,15 @@
    return &display->es;
 }
 
+/* Function: al_hold_bitmap_drawing
+ */
+void al_hold_bitmap_drawing(bool hold)
+{
+   ALLEGRO_DISPLAY *current_display = al_get_current_display();
+   current_display->cache_enabled = hold;
+   if(!hold && current_display->vt->flush_vertex_cache)
+      current_display->vt->flush_vertex_cache(current_display);
+}
 
+
 /* vim: set sts=3 sw=3 et: */
Index: src/gp2xwiz/wiz_display_opengl.c
===================================================================
--- src/gp2xwiz/wiz_display_opengl.c	(revision 12717)
+++ src/gp2xwiz/wiz_display_opengl.c	(working copy)
@@ -164,6 +164,7 @@
    _al_event_source_free(&d->es);
 
    _AL_FREE(d->ogl_extras);
+   _AL_FREE(d->vertex_cache);
    _AL_FREE(d);
 
    set_gfx_mode = false;
Index: src/gp2xwiz/wiz_display_fb.c
===================================================================
--- src/gp2xwiz/wiz_display_fb.c	(revision 12717)
+++ src/gp2xwiz/wiz_display_fb.c	(working copy)
@@ -87,7 +87,8 @@
 
    wiz_disp->backbuffer->memory = wiz_disp->screen_mem;
    al_destroy_bitmap(wiz_disp->backbuffer);
-
+   
+   _AL_FREE(d->vertex_cache);
    _AL_FREE(d);
 
    set_gfx_mode = false;
Index: examples/ex_ttf.c
===================================================================
--- examples/ex_ttf.c	(revision 12717)
+++ examples/ex_ttf.c	(working copy)
@@ -6,6 +6,7 @@
 
 struct Example
 {
+    bool hold;
     double fps;
     ALLEGRO_FONT *f1, *f2, *f3, *f4;
 } ex;
@@ -25,21 +26,31 @@
 
     al_set_blender(ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA, black);
 
+    al_hold_bitmap_drawing(ex.hold);
+   
     al_draw_textf(ex.f1, 50,  50, 0, "Tulip (kerning)");
     al_draw_textf(ex.f2, 50, 100, 0, "Tulip (no kerning)");
     al_draw_textf(ex.f3, 50, 200, 0, "This font has a size of 12 pixels, "
         "the one above has 48 pixels.");
 
+    al_hold_bitmap_drawing(false);
+    al_hold_bitmap_drawing(ex.hold);
+
     al_set_blender(ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA, red);
     al_draw_textf(ex.f3, 50, 220, 0, "The color can be changed simply "
         "by using a different blender.");
         
+    al_hold_bitmap_drawing(false);
+    al_hold_bitmap_drawing(ex.hold);
+        
     al_set_blender(ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA, green);
     al_draw_textf(ex.f3, 50, 240, 0, "Some unicode symbols:");
     al_draw_textf(ex.f3, 50, 260, 0, "������������������");
     al_draw_textf(ex.f3, 50, 280, 0, "â?²â?³â?´â?µâ?¶â?·â?¸â?¹â?ºâ?»â?¼â?½â?¾â?¿â??â??â??â??â??â??â??â??â??â??â??");
     al_draw_textf(ex.f3, 50, 300, 0, "â??â??â??â??â??â??â??â??â??â??â??â??â??â??â??");
 
+    
+
    #define OFF(x) al_ustr_offset(u, x)
    #define SUB(x, y) al_ref_ustr(&sub_info, u, OFF(x), OFF(y))
     u = al_ref_cstr(&info, "«Thís»|you");
@@ -51,6 +62,8 @@
     u = al_ref_cstr(&info, "réstrïçteÄ?â?¦|this.");
     al_draw_ustr(ex.f3, 50, 380, 0, SUB(0, 11));
     
+    al_hold_bitmap_drawing(false);
+    
     xpos = al_get_display_width() - 10;
     ypos = al_get_display_height() - 10;
     al_get_text_dimensions(ex.f4, "Allegro", &x, &y, &w, &h, &as, &de);
@@ -63,11 +76,23 @@
     al_draw_line(x, y + as, x + w, y + as, black, 0);
     al_draw_line(x, y + as + de, x + w, y + as + de, black, 0);
     al_set_blender(ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA, blue);
+    
+    al_hold_bitmap_drawing(ex.hold);
     al_draw_textf(ex.f4, xpos, ypos, 0, "Allegro");
+    al_hold_bitmap_drawing(false);
 
     al_set_blender(ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA, black);
+    
+    al_hold_bitmap_drawing(ex.hold);
+    
+    if(ex.hold)
     al_draw_textf(ex.f3, al_get_display_width(), 0, ALLEGRO_ALIGN_RIGHT,
-       "%.1f FPS", ex.fps);
+       "Using deferred drawing - %.1f FPS", ex.fps);
+    else
+    al_draw_textf(ex.f3, al_get_display_width(), 0, ALLEGRO_ALIGN_RIGHT,
+       "Not using deferred drawing - %.1f FPS", ex.fps);
+       
+    al_hold_bitmap_drawing(false);
 }
 
 int main(int argc, const char *argv[])
@@ -102,6 +127,7 @@
      * in pixels, not the usual font size.
      */
     ex.f4 = al_load_font(font_file, -140, 0);
+    ex.hold = false;
 
     if (!ex.f1 || !ex.f2 || !ex.f3 || !ex.f4) {
         fprintf(stderr, "Could not load font: %s\n", font_file);
@@ -125,6 +151,10 @@
                 event.keyboard.keycode == ALLEGRO_KEY_ESCAPE) {
             break;
         }
+        if (event.type == ALLEGRO_EVENT_KEY_DOWN &&
+                event.keyboard.keycode == ALLEGRO_KEY_SPACE) {
+            ex.hold = !ex.hold;
+        }
         if (event.type == ALLEGRO_EVENT_TIMER)
             redraw++;
 


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