Merge "Sligh speedup for pixel conversion routines with Duff's device."
diff --git a/android/skin/window.c b/android/skin/window.c
index 018c184..e32a51f 100644
--- a/android/skin/window.c
+++ b/android/skin/window.c
@@ -15,6 +15,7 @@
 #include "android/charmap.h"
 #include "android/utils/debug.h"
 #include "android/utils/system.h"
+#include "android/utils/duff.h"
 #include "android/ui-core-protocol.h"
 #include <SDL_syswm.h>
 #include "user-events.h"
@@ -313,9 +314,9 @@
 
         for ( ; h > 0; h-- ) {
             unsigned*  line = (unsigned*) pixels;
-            int        nn;
+            int        nn   = 0;
 
-            for (nn = 0; nn < w; nn++) {
+            DUFF4(w, {
                 unsigned  c  = line[nn];
                 unsigned  ag = (c >> 8) & 0x00ff00ff;
                 unsigned  rb = (c)      & 0x00ff00ff;
@@ -324,7 +325,8 @@
                 rb = ((rb*alpha) >> 8) & 0x00ff00ff;
 
                 line[nn] = (unsigned)(ag | rb);
-            }
+                nn++;
+            });
             pixels += pitch;
         }
     }
@@ -339,9 +341,9 @@
 
         for ( ; h > 0; h-- ) {
             unsigned*  line = (unsigned*) pixels;
-            int        nn;
+            int        nn   = 0;
 
-            for (nn = 0; nn < w; nn++) {
+            DUFF4(w, {
                 unsigned  c  = line[nn];
                 unsigned  ag = (c >> 8) & 0x00ff00ff;
                 unsigned  rb = (c)      & 0x00ff00ff;
@@ -351,7 +353,8 @@
                 rb = ((rb*ialpha + 0x00ff00ff*alpha) >> 8) & 0x00ff00ff;
 
                 line[nn] = (unsigned)(ag | rb);
-            }
+                nn++;
+            });
             pixels += pitch;
         }
     }
@@ -399,9 +402,11 @@
             uint32_t*  dst = (uint32_t*)dst_line;
             uint16_t*  src = (uint16_t*)src_line;
 
-            for (xx = 0; xx < w; xx++) {
+            xx = 0;
+            DUFF4(w, {
                 dst[xx] = rgb565_to_argb32(src[xx]);
-            }
+                xx++;
+            });
             src_line += src_pitch;
             dst_line += dst_pitch;
         }
@@ -415,12 +420,11 @@
             uint32_t*  dst = (uint32_t*)dst_line;
             uint8_t*   src = src_line;
 
-            for (xx = w; xx > 0; xx--)
-            {
+            DUFF4(w, {
                 dst[0] = rgb565_to_argb32(((uint16_t*)src)[0]);
                 src -= src_pitch;
                 dst += 1;
-            }
+            });
             src_line += 2;
             dst_line += dst_pitch;
         }
@@ -434,12 +438,11 @@
             uint16_t*  src = (uint16_t*)src_line;
             uint32_t*  dst = (uint32_t*)dst_line;
 
-            for (xx = w; xx > 0; xx--) {
+            DUFF4(w, {
                 dst[0] = rgb565_to_argb32(src[0]);
                 src -= 1;
                 dst += 1;
-            }
-
+            });
             src_line -= src_pitch;
             dst_line += dst_pitch;
     }
@@ -453,11 +456,11 @@
             uint32_t*  dst = (uint32_t*)dst_line;
             uint8_t*   src = src_line;
 
-            for (xx = w; xx > 0; xx--) {
+            DUFF4(w, {
                 dst[0] = rgb565_to_argb32(((uint16_t*)src)[0]);
                 dst   += 1;
                 src   += src_pitch;
-            }
+            });
             src_line -= 2;
             dst_line += dst_pitch;
         }
@@ -477,7 +480,7 @@
     uint8_t*      dst_line  = (uint8_t*)surface->pixels + rect->pos.x*4 + rect->pos.y*dst_pitch;
     int           src_pitch = disp->datasize.w*4;
     uint8_t*      src_line  = (uint8_t*)disp->data;
-    int           yy, xx;
+    int           yy;
 
     switch ( disp->rotation & 3 )
     {
@@ -488,9 +491,11 @@
             uint32_t*  src = (uint32_t*)src_line;
             uint32_t*  dst = (uint32_t*)dst_line;
 
-            for (xx = 0; xx < w; xx++) {
-                dst[xx] = xbgr_to_argb32(src[xx]);
-            }
+            DUFF4(w, {
+                dst[0] = xbgr_to_argb32(src[0]);
+                dst++;
+                src++;
+            });
             src_line += src_pitch;
             dst_line += dst_pitch;
         }
@@ -504,12 +509,11 @@
             uint32_t*  dst = (uint32_t*)dst_line;
             uint8_t*   src = src_line;
 
-            for (xx = w; xx > 0; xx--)
-            {
+            DUFF4(w, {
                 dst[0] = xbgr_to_argb32(*(uint32_t*)src);
                 src -= src_pitch;
                 dst += 1;
-            }
+            });
             src_line += 4;
             dst_line += dst_pitch;
         }
@@ -523,12 +527,11 @@
             uint32_t*  src = (uint32_t*)src_line;
             uint32_t*  dst = (uint32_t*)dst_line;
 
-            for (xx = w; xx > 0; xx--) {
+            DUFF4(w, {
                 dst[0] = xbgr_to_argb32(src[0]);
                 src -= 1;
                 dst += 1;
-            }
-
+            });
             src_line -= src_pitch;
             dst_line += dst_pitch;
     }
@@ -542,11 +545,11 @@
             uint32_t*  dst = (uint32_t*)dst_line;
             uint8_t*   src = src_line;
 
-            for (xx = w; xx > 0; xx--) {
+            DUFF4(w, {
                 dst[0] = xbgr_to_argb32(*(uint32_t*)src);
                 dst   += 1;
                 src   += src_pitch;
-            }
+            });
             src_line -= 4;
             dst_line += dst_pitch;
         }
diff --git a/android/utils/duff.h b/android/utils/duff.h
new file mode 100644
index 0000000..a00768c
--- /dev/null
+++ b/android/utils/duff.h
@@ -0,0 +1,71 @@
+/* Copyright (C) 2011 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+** GNU General Public License for more details.
+*/
+#ifndef ANDROID_UTILS_DUFF_H
+#define ANDROID_UTILS_DUFF_H
+
+/*********************************************************************
+ *********************************************************************
+ *****
+ *****    DUFF'S DEVICES
+ *****
+ *****/
+
+#define  DUFF1(_count,_stmnt) \
+    do { \
+        int __n = (_count); \
+        do { \
+            _stmnt; \
+        } while (--__n > 0); \
+    } while (0);
+
+#define  DUFF2(_count,_stmnt)  \
+    ({ \
+        int   __count = (_count); \
+        int   __n     = (__count +1)/2; \
+        switch (__count & 1) { \
+        case 0: do { _stmnt; \
+        case 1:      _stmnt; \
+                } while (--__n > 0); \
+        } \
+    })
+
+#define  DUFF4(_count,_stmnt)  \
+    ({ \
+        int   __count = (_count); \
+        int   __n     = (__count +3)/4; \
+        switch (__count & 3) { \
+        case 0: do { _stmnt; \
+        case 3:      _stmnt; \
+        case 2:      _stmnt; \
+        case 1:      _stmnt; \
+                } while (--__n > 0); \
+        } \
+    })
+
+#define  DUFF8(_count,_stmnt)  \
+    ({ \
+        int   __count = (_count); \
+        int   __n     = (__count+7)/8; \
+        switch (__count & 7) { \
+        case 0: do { _stmnt; \
+        case 7:      _stmnt; \
+        case 6:      _stmnt; \
+        case 5:      _stmnt; \
+        case 4:      _stmnt; \
+        case 3:      _stmnt; \
+        case 2:      _stmnt; \
+        case 1:      _stmnt; \
+                } while (--__n > 0); \
+        } \
+    })
+
+#endif /* ANDROID_UTILS_DUFF_H */
diff --git a/hw/goldfish_fb.c b/hw/goldfish_fb.c
index 72352fa..d74d797 100644
--- a/hw/goldfish_fb.c
+++ b/hw/goldfish_fb.c
@@ -12,6 +12,7 @@
 #include "qemu_file.h"
 #include "android/android.h"
 #include "android/utils/debug.h"
+#include "android/utils/duff.h"
 #include "goldfish_device.h"
 #include "console.h"
 
@@ -316,26 +317,29 @@
             const uint16_t* src = (const uint16_t*) src_line;
             uint16_t*       dst = (uint16_t*) dst_line;
 
-            for (xx1 = 0; xx1 < width; xx1++) {
-                if (src[xx1] != dst[xx1]) {
+            xx1 = 0;
+            DUFF4(width, {
+                if (src[xx1] != dst[xx1])
                     break;
-                }
-            }
+                xx1++;
+            });
             if (xx1 == width) {
                 break;
             }
-            for (xx2 = width-1; xx2 > xx1; xx2--) {
-                if (src[xx2] != dst[xx2]) {
+            xx2 = width-1;
+            DUFF4(xx2-xx1, {
+                if (src[xx2] != dst[xx2])
                     break;
-                }
-            }
+                xx2--;
+            });
 #if HOST_WORDS_BIGENDIAN
             /* Convert the guest little-endian pixels into big-endian ones */
             int xx = xx1;
-            for ( ; xx <= xx2; xx++ ) {
+            DUFF4(xx2-xx1+1,{
                 unsigned   spix = src[xx];
                 dst[xx] = (uint16_t)((spix << 8) | (spix >> 8));
-            }
+                xx++;
+            });
 #else
             memcpy( dst+xx1, src+xx1, (xx2-xx1+1)*2 );
 #endif
@@ -344,25 +348,29 @@
 
         case 3:
         {
-            for (xx1 = 0; xx1 < width; xx1 += 1) {
+            xx1 = 0;
+            DUFF4(width, {
                 int xx = xx1*3;
                 if (src_line[xx+0] != dst_line[xx+0] ||
                     src_line[xx+1] != dst_line[xx+1] ||
                     src_line[xx+2] != dst_line[xx+2]) {
                     break;
                 }
-            }
+                xx1 ++;
+            });
             if (xx1 == width) {
                 break;
             }
-            for (xx2 = width-1; xx2 > xx1; xx2--) {
+            xx2 = width-1;
+            DUFF4(xx2-xx1,{
                 int xx = xx2*3;
                 if (src_line[xx+0] != dst_line[xx+0] ||
                     src_line[xx+1] != dst_line[xx+1] ||
                     src_line[xx+2] != dst_line[xx+2]) {
                     break;
                 }
-            }
+                xx2--;
+            });
             memcpy( dst_line+xx1*3, src_line+xx1*3, (xx2-xx1+1)*3 );
             break;
         }
@@ -372,28 +380,33 @@
             const uint32_t* src = (const uint32_t*) src_line;
             uint32_t*       dst = (uint32_t*) dst_line;
 
-            for (xx1 = 0; xx1 < width; xx1++) {
+            xx1 = 0;
+            DUFF4(width, {
                 if (src[xx1] != dst[xx1]) {
                     break;
                 }
-            }
+                xx1++;
+            });
             if (xx1 == width) {
                 break;
             }
-            for (xx2 = width-1; xx2 > xx1; xx2--) {
+            xx2 = width-1;
+            DUFF4(xx2-xx1,{
                 if (src[xx2] != dst[xx2]) {
                     break;
                 }
-            }
+                xx2--;
+            });
 #if HOST_WORDS_BIGENDIAN
             /* Convert the guest little-endian pixels into big-endian ones */
             int xx = xx1;
-            for ( ; xx <= xx2; xx++ ) {
+            DUFF4(xx2-xx1+1,{
                 uint32_t   spix = src[xx];
                 spix = (spix << 16) | (spix >> 16);
                 spix = ((spix << 8) & 0xff00ff00) | ((spix >> 8) & 0x00ff00ff);
                 dst[xx] = spix;
-            }
+                xx++;
+            })
 #else
             memcpy( dst+xx1, src+xx1, (xx2-xx1+1)*4 );
 #endif