[AD] Optimized blitting between color depths

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


Hello,
The attached patch does two optimizations:
- Various small tricks to improve the speed of makecol15_dither() and makecol16_dither(). - The code in blit.c to convert between color depths with COLCONV_KEEP_TRANS was unnecessarily involved. I re-factored it to improve both readability and speed (and reduce code size).

On my AMD Athlon it gives roughly the following improvements depending on the color conversion and dithering flags set by set_color_conversion() (the time per call after the patch, in percent of the time per call before the patch, so small is good):

 45% for COLCONV_KEEP_TRANS
 68% for COLCONV_DITHERED | COLCONV_KEEP_TRANS
 94% for COLCONV_DITHERED

I put my test program, together with the test results on my computer, at http://user.it.uu.se/~svens/convert-blit.zip

/Sven
Index: src/blit.c
===================================================================
RCS file: /cvsroot/alleg/allegro/src/blit.c,v
retrieving revision 1.13
diff -u -r1.13 blit.c
--- src/blit.c	8 Apr 2004 19:26:20 -0000	1.13
+++ src/blit.c	31 Oct 2004 15:16:35 -0000
@@ -156,121 +156,46 @@
 
 
 
-/* makecol_trans:
- *  Helper function to convert pixel values with transparency preserving.
- */
-static int makecol_trans(BITMAP *src, BITMAP *dest, int c, int r, int g, int b)
-{
-   static int rc;
-   static BITMAP *rc_bmp = NULL;
-
-   if (c == bitmap_mask_color(src)) {
-      c = bitmap_mask_color(dest);
-      return c;
-   }
-
-   c = makecol_depth(bitmap_color_depth(dest), r, g, b);
-
-   if (c == bitmap_mask_color(dest)) {
-      if (dest != rc_bmp) {
-         rc = get_replacement_mask_color(dest);
-         rc_bmp = dest;
-      }
-      c = rc;
-   }
-
-   return c;
-}
-
-
-
-/* worker macro for converting between two color formats */
-#define CONVERT_BLIT(sbits, ssize, dbits, dsize)                             \
+/* worker macro for converting between two color formats, possibly with dithering */
+#define CONVERT_BLIT_EX(sbits, ssize, dbits, dsize, MAKECOL)                 \
 {                                                                            \
-   for (y=0; y<h; y++) {                                                     \
-      s = bmp_read_line(src, s_y+y) + s_x*ssize;                             \
-      d = bmp_write_line(dest, d_y+y) + d_x*dsize;                           \
-                                                                             \
-      if (_color_conv & COLORCONV_KEEP_TRANS) {                              \
-         for (x=0; x<w; x++) {                                               \
-            bmp_select(src);                                                 \
-            c = bmp_read##sbits(s);                                          \
-                                                                             \
-            r = getr##sbits(c);                                              \
-            g = getg##sbits(c);                                              \
-            b = getb##sbits(c);                                              \
-                                                                             \
-            bmp_select(dest);                                                \
-            bmp_write##dbits(d, makecol_trans(src, dest, c, r, g, b));       \
+   if (_color_conv & COLORCONV_KEEP_TRANS) {                                 \
+      int rc = get_replacement_mask_color(dest);                             \
+      int src_mask = bitmap_mask_color(src);                                 \
+      int dest_mask = bitmap_mask_color(dest);                               \
+                                                                             \
+      for (y=0; y<h; y++) {                                                  \
+	 s = bmp_read_line(src, s_y+y) + s_x*ssize;                          \
+	 d = bmp_write_line(dest, d_y+y) + d_x*dsize;                        \
                                                                              \
-            s += ssize;                                                      \
-            d += dsize;                                                      \
-         }                                                                   \
-      }                                                                      \
-      else {                                                                 \
          for (x=0; x<w; x++) {                                               \
             bmp_select(src);                                                 \
             c = bmp_read##sbits(s);                                          \
                                                                              \
-            r = getr##sbits(c);                                              \
-            g = getg##sbits(c);                                              \
-            b = getb##sbits(c);                                              \
+            if (c == src_mask)                                               \
+               c = dest_mask;                                                \
+            else {                                                           \
+	       r = getr##sbits(c);                                           \
+	       g = getg##sbits(c);                                           \
+	       b = getb##sbits(c);                                           \
+               c = MAKECOL;                                                  \
+               if (c == dest_mask)                                           \
+		 c = rc;			\
+            }                                                                \
                                                                              \
             bmp_select(dest);                                                \
-            bmp_write##dbits(d, makecol##dbits(r, g, b));                    \
+            bmp_write##dbits(d, c);                                          \
                                                                              \
             s += ssize;                                                      \
             d += dsize;                                                      \
          }                                                                   \
       }                                                                      \
    }                                                                         \
+   else {                                                                    \
+      for (y=0; y<h; y++) {                                                  \
+	 s = bmp_read_line(src, s_y+y) + s_x*ssize;                          \
+	 d = bmp_write_line(dest, d_y+y) + d_x*dsize;                        \
                                                                              \
-   bmp_unwrite_line(src);                                                    \
-   bmp_unwrite_line(dest);                                                   \
-}
-
-
-
-/* makecol_dither_trans:
- *  Helper function to convert pixel values with dithering and transparency preserving.
- */
-static int makecol_dither_trans(BITMAP *src, BITMAP *dest, int c, int r, int g, int b,
-                                                                         int x, int y)
-{
-   static int rc;
-   static BITMAP *rc_bmp = NULL;
-
-   if (c == bitmap_mask_color(src)) {
-      c = bitmap_mask_color(dest);
-      return c;
-   }
-
-   if (bitmap_color_depth(dest) == 15)
-      c = makecol15_dither(r, g, b, x, y);
-   else
-      c = makecol16_dither(r, g, b, x, y);
-
-   if (c == bitmap_mask_color(dest)) {
-      if (dest != rc_bmp) {
-         rc = get_replacement_mask_color(dest);
-         rc_bmp = dest;
-      }
-      c = rc;
-   }
-
-   return c;
-}
-
-
-
-/* worker macro for converting formats with dithering */
-#define CONVERT_DITHER_BLIT(sbits, ssize, dbits, dsize)                      \
-{                                                                            \
-   for (y=0; y<h; y++) {                                                     \
-      s = bmp_read_line(src, s_y+y) + s_x*ssize;                             \
-      d = bmp_write_line(dest, d_y+y) + d_x*dsize;                           \
-                                                                             \
-      if (_color_conv & COLORCONV_KEEP_TRANS) {                              \
          for (x=0; x<w; x++) {                                               \
             bmp_select(src);                                                 \
             c = bmp_read##sbits(s);                                          \
@@ -280,24 +205,7 @@
             b = getb##sbits(c);                                              \
                                                                              \
             bmp_select(dest);                                                \
-            bmp_write##dbits(d, makecol_dither_trans(src, dest, c, r, g, b,  \
-                                                                   x ,y ));  \
-                                                                             \
-            s += ssize;                                                      \
-            d += dsize;                                                      \
-         }                                                                   \
-      }                                                                      \
-      else {                                                                 \
-         for (x=0; x<w; x++) {                                               \
-            bmp_select(src);                                                 \
-            c = bmp_read##sbits(s);                                          \
-                                                                             \
-            r = getr##sbits(c);                                              \
-            g = getg##sbits(c);                                              \
-            b = getb##sbits(c);                                              \
-                                                                             \
-            bmp_select(dest);                                                \
-            bmp_write##dbits(d, makecol##dbits##_dither(r, g, b, x, y));     \
+            bmp_write##dbits(d, MAKECOL);                                    \
                                                                              \
             s += ssize;                                                      \
             d += dsize;                                                      \
@@ -309,6 +217,12 @@
    bmp_unwrite_line(dest);                                                   \
 }
 
+#define CONVERT_BLIT(sbits, ssize, dbits, dsize) \
+   CONVERT_BLIT_EX(sbits, ssize, dbits, dsize, makecol##dbits(r, g, b))
+#define CONVERT_DITHER_BLIT(sbits, ssize, dbits, dsize) \
+   CONVERT_BLIT_EX(sbits, ssize, dbits, dsize, \
+                   makecol##dbits##_dither(r, g, b, x, y))
+
 
 
 #if (defined ALLEGRO_COLOR8) || (defined GFX_MODEX)
Index: src/dither.c
===================================================================
RCS file: /cvsroot/alleg/allegro/src/dither.c,v
retrieving revision 1.2
diff -u -r1.2 dither.c
--- src/dither.c	24 May 2001 09:30:19 -0000	1.2
+++ src/dither.c	31 Oct 2004 15:16:35 -0000
@@ -20,7 +20,7 @@
 
 
 
-static unsigned char dither_table[7] = { 16, 68, 146, 170, 109, 187, 239 };
+static unsigned char dither_table[8] = { 0, 16, 68, 146, 170, 109, 187, 239 };
 static unsigned char dither_ytable[8] = { 1, 5, 2, 7, 4, 0, 6, 3 };
 
 
@@ -33,35 +33,24 @@
    int returned_r, returned_g, returned_b;
    int bpos;
 
-   returned_r = r/8;
-   returned_b = b/8;
-   returned_g = g/8;
+   returned_r = r>>3;
+   returned_g = g>>3;
+   returned_b = b>>3;
 
    y = dither_ytable[y&7];
 
-   if (r&7) {
-      bpos = (x+y)&7; 
-      returned_r += ((dither_table[((r&7)-1)]) & (1<<bpos)) >> bpos;
-   }
-
-   if (b&7) {
-      bpos = (x+y+3)&7; 
-      returned_b += ((dither_table[((b&7)-1)]) & (1<<bpos)) >> bpos;
-   }
-
-   if (g&7) {
-      bpos = (x+y+2)&7;
-      returned_g += ((dither_table[(g&7)-1]) & (1<<bpos)) >> bpos;
-   }
-
-   if (returned_r > 31)
-      returned_r = 31;
-
-   if (returned_b > 31) 
-      returned_b = 31;
-
-   if (returned_g > 31) 
-      returned_g = 31;
+   bpos = (x+y)&7; 
+   returned_r += (dither_table[r&7] >> bpos) & 1;
+   
+   bpos = (bpos+3)&7;
+   returned_b += (dither_table[b&7] >> bpos) & 1;
+
+   bpos = (bpos+7)&7;
+   returned_g += (dither_table[g&7] >> bpos) & 1;
+
+   returned_r -= returned_r>>5;
+   returned_g -= returned_g>>5;
+   returned_b -= returned_b>>5;
 
    return (returned_r<<_rgb_r_shift_15) | (returned_g<<_rgb_g_shift_15) | (returned_b<<_rgb_b_shift_15);
 }
@@ -76,35 +65,24 @@
    int returned_r, returned_g, returned_b;
    int bpos;
 
-   returned_r = r/8;
-   returned_b = b/8;
-   returned_g = g/4;
+   returned_r = r>>3;
+   returned_g = g>>2;
+   returned_b = b>>3;
 
    y = dither_ytable[y&7];
 
-   if (r&7) {
-      bpos = (x+y)&7; 
-      returned_r += ((dither_table[((r&7)-1)]) & (1<<bpos)) >> bpos;
-   }
-
-   if (b&7) {
-      bpos = (x+y+3)&7; 
-      returned_b += ((dither_table[((b&7)-1)]) & (1<<bpos)) >> bpos;
-   }
-
-   if (g&3) {
-      bpos = (x+y+2)&7;
-      returned_g += ((dither_table[(g&3)*2-1]) & (1<<bpos)) >> bpos;
-   }
-
-   if (returned_r > 31)
-      returned_r = 31;
-
-   if (returned_b > 31) 
-      returned_b = 31;
-
-   if (returned_g > 63) 
-      returned_g = 63;
+   bpos = (x+y)&7; 
+   returned_r += (dither_table[r&7] >> bpos) & 1;
+   
+   bpos = (bpos+3)&7;
+   returned_b += (dither_table[b&7] >> bpos) & 1;
+
+   bpos = (bpos+7)&7;
+   returned_g += (dither_table[(g&3)*2] >> bpos) & 1;
+
+   returned_r -= returned_r>>5;
+   returned_g -= returned_g>>6;
+   returned_b -= returned_b>>5;
 
    return (returned_r<<_rgb_r_shift_16) | (returned_g<<_rgb_g_shift_16) | (returned_b<<_rgb_b_shift_16);
 }


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