Fix conversion of 24bpp bitmaps to 32bpp fb when
authorPavel Tsekov <ptsekov@open.bg>
Wed, 13 Aug 2014 21:31:15 +0000 (00:31 +0300)
committerPavel Tsekov <ptsekov@open.bg>
Wed, 13 Aug 2014 21:31:15 +0000 (00:31 +0300)
CLRCONV_INVERT and/or CLRCONV_ALPHA is set.
* include/freerdp/codec/color.h (RGB32_to_BGR32): New inline function.
* libfreerdp/codec/color.c:
(freerdp_image_convert_24bpp): Fix CLRCONV_ALPHA and CLRCONV_INVERT
processing for 32bpp destination.
Unroll the conversion loop to process four pixels in one go using
32-bit load and store operations.

include/freerdp/codec/color.h
libfreerdp/codec/color.c

index c0c6f1b..47c6126 100644 (file)
@@ -373,6 +373,14 @@ typedef CLRCONV* HCLRCONV;
 
 typedef BYTE* (*p_freerdp_image_convert)(BYTE* srcData, BYTE* dstData, int width, int height, int srcBpp, int dstBpp, HCLRCONV clrconv);
 
+static INLINE UINT32 RGB32_to_BGR32(UINT32 pixel)
+{
+       UINT32 temp;
+
+       temp = (pixel ^ (pixel >> 16)) & ((1 << 8) - 1);
+       return (pixel ^ (temp | (temp << 16)));
+}
+
 FREERDP_API int freerdp_get_pixel(BYTE* data, int x, int y, int width, int height, int bpp);
 FREERDP_API void freerdp_set_pixel(BYTE* data, int x, int y, int width, int height, int bpp, int pixel);
 
index 305801d..365bdde 100644 (file)
@@ -705,7 +705,9 @@ BYTE* freerdp_image_convert_24bpp(BYTE* srcData, BYTE* dstData, int width, int h
 
        if (dstBpp == 32)
        {
-               BYTE* dstp;
+               UINT32 pixel, alpha_mask, temp;
+               UINT32* srcp;
+               UINT32* dstp;
 
                if (!dstData)
                        dstData = (BYTE*) _aligned_malloc(width * height * 4, 16);
@@ -713,14 +715,81 @@ BYTE* freerdp_image_convert_24bpp(BYTE* srcData, BYTE* dstData, int width, int h
                if (!dstData)
                        return NULL;
 
-               dstp = dstData;
+               alpha_mask = clrconv->alpha ? 0xFF000000 : 0;
 
-               for (i = width * height; i > 0; i--)
+               srcp = (UINT32*) srcData;
+               dstp = (UINT32*) dstData;
+
+               if (clrconv->invert)
                {
-                       *(dstp++) = *(srcData++);
-                       *(dstp++) = *(srcData++);
-                       *(dstp++) = *(srcData++);
-                       *(dstp++) = 0xFF;
+                       /* Each iteration handles four pixels using 32-bit load and
+                          store operations. */
+                       for (i = ((width * height) / 4); i > 0; i--)
+                       {
+                               temp = 0;
+
+                               pixel = temp;
+                               temp = *srcp++;
+                               pixel |= temp & 0x00FFFFFF;
+                               temp = temp >> 24;
+                               *dstp++ = alpha_mask | RGB32_to_BGR32(pixel);
+
+                               pixel = temp;
+                               temp = *srcp++;
+                               pixel |= (temp & 0x0000FFFF) << 8;
+                               temp = temp >> 16;
+                               *dstp++ = alpha_mask | RGB32_to_BGR32(pixel);
+
+                               pixel = temp;
+                               temp = *srcp++;
+                               pixel |= (temp & 0x000000FF) << 16;
+                               temp = temp >> 8;
+                               *dstp++ = alpha_mask | RGB32_to_BGR32(pixel);
+
+                               *dstp++ = alpha_mask | RGB32_to_BGR32(temp);
+                       }
+
+                       /* Handle any remainder. */
+                       for (i = (width * height) % 4; i > 0; i--)
+                       {
+                               pixel = ABGR32(alpha_mask, srcData[2], srcData[1], srcData[0]);
+                               *dstp++ = pixel;
+                               srcData += 3;
+                       }
+               }
+               else
+               {
+                       for (i = ((width * height) / 4); i > 0; i--)
+                       {
+                               temp = 0;
+
+                               pixel = temp;
+                               temp = *srcp++;
+                               pixel |= temp & 0x00FFFFFF;
+                               temp = temp >> 24;
+                               *dstp++ = alpha_mask | pixel;
+
+                               pixel = temp;
+                               temp = *srcp++;
+                               pixel |= (temp & 0x0000FFFF) << 8;
+                               temp = temp >> 16;
+                               *dstp++ = alpha_mask | pixel;
+
+                               pixel = temp;
+                               temp = *srcp++;
+                               pixel |= (temp & 0x000000FF) << 16;
+                               temp = temp >> 8;
+                               *dstp++ = alpha_mask | pixel;
+
+                               *dstp++ = alpha_mask | temp;
+                       }
+
+                       for (i = (width * height) % 4; i > 0; i--)
+                       {
+                               pixel = ARGB32(alpha_mask, srcData[2], srcData[1], srcData[0]);
+                               *dstp++ = pixel;
+                               srcData += 3;
+                       }
                }
 
                return dstData;