src/gui/painting/qdrawhelper_neon.cpp
changeset 30 5dc02b23752f
parent 18 2f34d5167611
child 33 3e2da88830cd
--- a/src/gui/painting/qdrawhelper_neon.cpp	Wed Jun 23 19:07:03 2010 +0300
+++ b/src/gui/painting/qdrawhelper_neon.cpp	Tue Jul 06 15:10:48 2010 +0300
@@ -40,10 +40,13 @@
 ****************************************************************************/
 
 #include <private/qdrawhelper_p.h>
+#include <private/qblendfunctions_p.h>
+#include <private/qmath_p.h>
 
 #ifdef QT_HAVE_NEON
 
 #include <private/qdrawhelper_neon_p.h>
+#include <private/qpaintengine_raster_p.h>
 #include <arm_neon.h>
 
 QT_BEGIN_NAMESPACE
@@ -87,6 +90,131 @@
     return vaddq_u16(src16, qvbyte_mul_u16(dst16, alpha16, half));
 }
 
+extern "C" void
+pixman_composite_over_8888_0565_asm_neon (int32_t   w,
+                                          int32_t   h,
+                                          uint16_t *dst,
+                                          int32_t   dst_stride,
+                                          uint32_t *src,
+                                          int32_t   src_stride);
+
+extern "C" void
+pixman_composite_over_8888_8888_asm_neon (int32_t   w,
+                                          int32_t   h,
+                                          uint32_t *dst,
+                                          int32_t   dst_stride,
+                                          uint32_t *src,
+                                          int32_t   src_stride);
+
+extern "C" void
+pixman_composite_src_0565_8888_asm_neon (int32_t   w,
+                                         int32_t   h,
+                                         uint32_t *dst,
+                                         int32_t   dst_stride,
+                                         uint16_t *src,
+                                         int32_t   src_stride);
+
+extern "C" void
+pixman_composite_over_n_8_0565_asm_neon (int32_t    w,
+                                         int32_t    h,
+                                         uint16_t  *dst,
+                                         int32_t    dst_stride,
+                                         uint32_t   src,
+                                         int32_t    unused,
+                                         uint8_t   *mask,
+                                         int32_t    mask_stride);
+
+extern "C" void
+pixman_composite_scanline_over_asm_neon (int32_t         w,
+                                         const uint32_t *dst,
+                                         const uint32_t *src);
+
+// qblendfunctions.cpp
+void qt_blend_argb32_on_rgb16_const_alpha(uchar *destPixels, int dbpl,
+                                          const uchar *srcPixels, int sbpl,
+                                          int w, int h,
+                                          int const_alpha);
+
+void qt_blend_rgb16_on_argb32_neon(uchar *destPixels, int dbpl,
+                                   const uchar *srcPixels, int sbpl,
+                                   int w, int h,
+                                   int const_alpha)
+{
+    dbpl /= 4;
+    sbpl /= 2;
+
+    quint32 *dst = (quint32 *) destPixels;
+    quint16 *src = (quint16 *) srcPixels;
+
+    if (const_alpha != 256) {
+        quint8 a = (255 * const_alpha) >> 8;
+        quint8 ia = 255 - a;
+
+        while (h--) {
+            for (int x=0; x<w; ++x)
+                dst[x] = INTERPOLATE_PIXEL_255(qt_colorConvert(src[x], dst[x]), a, dst[x], ia);
+            dst += dbpl;
+            src += sbpl;
+        }
+        return;
+    }
+
+    pixman_composite_src_0565_8888_asm_neon(w, h, dst, dbpl, src, sbpl);
+}
+
+extern "C" void blend_8_pixels_argb32_on_rgb16_neon(quint16 *dst, const quint32 *src, int const_alpha);
+
+void qt_blend_argb32_on_rgb16_neon(uchar *destPixels, int dbpl,
+                                   const uchar *srcPixels, int sbpl,
+                                   int w, int h,
+                                   int const_alpha)
+{
+    quint16 *dst = (quint16 *) destPixels;
+    quint32 *src = (quint32 *) srcPixels;
+
+    if (const_alpha != 256) {
+        for (int y=0; y<h; ++y) {
+            int i = 0;
+            for (; i < w-7; i += 8)
+                blend_8_pixels_argb32_on_rgb16_neon(&dst[i], &src[i], const_alpha);
+
+            if (i < w) {
+                int tail = w - i;
+
+                quint16 dstBuffer[8];
+                quint32 srcBuffer[8];
+
+                for (int j = 0; j < tail; ++j) {
+                    dstBuffer[j] = dst[i + j];
+                    srcBuffer[j] = src[i + j];
+                }
+
+                blend_8_pixels_argb32_on_rgb16_neon(dstBuffer, srcBuffer, const_alpha);
+
+                for (int j = 0; j < tail; ++j) {
+                    dst[i + j] = dstBuffer[j];
+                    src[i + j] = srcBuffer[j];
+                }
+            }
+
+            dst = (quint16 *)(((uchar *) dst) + dbpl);
+            src = (quint32 *)(((uchar *) src) + sbpl);
+        }
+        return;
+    }
+
+    pixman_composite_over_8888_0565_asm_neon(w, h, dst, dbpl / 2, src, sbpl / 4);
+}
+
+void qt_blend_argb32_on_argb32_scanline_neon(uint *dest, const uint *src, int length, uint const_alpha)
+{
+    if (const_alpha == 255) {
+        pixman_composite_scanline_over_asm_neon(length, dest, src);
+    } else {
+        qt_blend_argb32_on_argb32_neon((uchar *)dest, 4 * length, (uchar *)src, 4 * length, length, 1, (const_alpha * 256) / 255);
+    }
+}
+
 void qt_blend_argb32_on_argb32_neon(uchar *destPixels, int dbpl,
                                     const uchar *srcPixels, int sbpl,
                                     int w, int h,
@@ -97,50 +225,7 @@
     uint16x8_t half = vdupq_n_u16(0x80);
     uint16x8_t full = vdupq_n_u16(0xff);
     if (const_alpha == 256) {
-        for (int y = 0; y < h; ++y) {
-            int x = 0;
-            for (; x < w-3; x += 4) {
-                uint32x4_t src32 = vld1q_u32((uint32_t *)&src[x]);
-                if ((src[x] & src[x+1] & src[x+2] & src[x+3]) >= 0xff000000) {
-                    // all opaque
-                    vst1q_u32((uint32_t *)&dst[x], src32);
-                } else if (src[x] | src[x+1] | src[x+2] | src[x+3]) {
-                    uint32x4_t dst32 = vld1q_u32((uint32_t *)&dst[x]);
-
-                    const uint8x16_t src8 = vreinterpretq_u8_u32(src32);
-                    const uint8x16_t dst8 = vreinterpretq_u8_u32(dst32);
-
-                    const uint8x8_t src8_low = vget_low_u8(src8);
-                    const uint8x8_t dst8_low = vget_low_u8(dst8);
-
-                    const uint8x8_t src8_high = vget_high_u8(src8);
-                    const uint8x8_t dst8_high = vget_high_u8(dst8);
-
-                    const uint16x8_t src16_low = vmovl_u8(src8_low);
-                    const uint16x8_t dst16_low = vmovl_u8(dst8_low);
-
-                    const uint16x8_t src16_high = vmovl_u8(src8_high);
-                    const uint16x8_t dst16_high = vmovl_u8(dst8_high);
-
-                    const uint16x8_t result16_low = qvsource_over_u16(src16_low, dst16_low, half, full);
-                    const uint16x8_t result16_high = qvsource_over_u16(src16_high, dst16_high, half, full);
-
-                    const uint32x2_t result32_low = vreinterpret_u32_u8(vmovn_u16(result16_low));
-                    const uint32x2_t result32_high = vreinterpret_u32_u8(vmovn_u16(result16_high));
-
-                    vst1q_u32((uint32_t *)&dst[x], vcombine_u32(result32_low, result32_high));
-                }
-            }
-            for (; x<w; ++x) {
-                uint s = src[x];
-                if (s >= 0xff000000)
-                    dst[x] = s;
-                else if (s != 0)
-                    dst[x] = s + BYTE_MUL(dst[x], qAlpha(~s));
-            }
-            dst = (quint32 *)(((uchar *) dst) + dbpl);
-            src = (const quint32 *)(((const uchar *) src) + sbpl);
-        }
+        pixman_composite_over_8888_8888_asm_neon(w, h, (uint32_t *)destPixels, dbpl / 4, (uint32_t *)srcPixels, sbpl / 4);
     } else if (const_alpha != 0) {
         const_alpha = (const_alpha * 255) >> 8;
         uint16x8_t const_alpha16 = vdupq_n_u16(const_alpha);
@@ -254,6 +339,246 @@
     }
 }
 
+void qt_alphamapblit_quint16_neon(QRasterBuffer *rasterBuffer,
+                                  int x, int y, quint32 color,
+                                  const uchar *bitmap,
+                                  int mapWidth, int mapHeight, int mapStride,
+                                  const QClipData *)
+{
+    quint16 *dest = reinterpret_cast<quint16*>(rasterBuffer->scanLine(y)) + x;
+    const int destStride = rasterBuffer->bytesPerLine() / sizeof(quint16);
+
+    uchar *mask = const_cast<uchar *>(bitmap);
+
+    pixman_composite_over_n_8_0565_asm_neon(mapWidth, mapHeight, dest, destStride, color, 0, mask, mapStride);
+}
+
+extern "C" void blend_8_pixels_rgb16_on_rgb16_neon(quint16 *dst, const quint16 *src, int const_alpha);
+
+template <typename SRC, typename BlendFunc>
+struct Blend_on_RGB16_SourceAndConstAlpha_Neon {
+    Blend_on_RGB16_SourceAndConstAlpha_Neon(BlendFunc blender, int const_alpha)
+        : m_index(0)
+        , m_blender(blender)
+        , m_const_alpha(const_alpha)
+    {
+    }
+
+    inline void write(quint16 *dst, quint32 src)
+    {
+        srcBuffer[m_index++] = src;
+
+        if (m_index == 8) {
+            m_blender(dst - 7, srcBuffer, m_const_alpha);
+            m_index = 0;
+        }
+    }
+
+    inline void flush(quint16 *dst)
+    {
+        if (m_index > 0) {
+            quint16 dstBuffer[8];
+            for (int i = 0; i < m_index; ++i)
+                dstBuffer[i] = dst[i - m_index];
+
+            m_blender(dstBuffer, srcBuffer, m_const_alpha);
+
+            for (int i = 0; i < m_index; ++i)
+                dst[i - m_index] = dstBuffer[i];
+
+            m_index = 0;
+        }
+    }
+
+    SRC srcBuffer[8];
+
+    int m_index;
+    BlendFunc m_blender;
+    int m_const_alpha;
+};
+
+template <typename SRC, typename BlendFunc>
+Blend_on_RGB16_SourceAndConstAlpha_Neon<SRC, BlendFunc>
+Blend_on_RGB16_SourceAndConstAlpha_Neon_create(BlendFunc blender, int const_alpha)
+{
+    return Blend_on_RGB16_SourceAndConstAlpha_Neon<SRC, BlendFunc>(blender, const_alpha);
+}
+
+void qt_scale_image_argb32_on_rgb16_neon(uchar *destPixels, int dbpl,
+                                         const uchar *srcPixels, int sbpl,
+                                         const QRectF &targetRect,
+                                         const QRectF &sourceRect,
+                                         const QRect &clip,
+                                         int const_alpha)
+{
+    if (const_alpha == 0)
+        return;
+
+    qt_scale_image_16bit<quint32>(destPixels, dbpl, srcPixels, sbpl, targetRect, sourceRect, clip,
+        Blend_on_RGB16_SourceAndConstAlpha_Neon_create<quint32>(blend_8_pixels_argb32_on_rgb16_neon, const_alpha));
+}
+
+void qt_scale_image_rgb16_on_rgb16(uchar *destPixels, int dbpl,
+                                   const uchar *srcPixels, int sbpl,
+                                   const QRectF &targetRect,
+                                   const QRectF &sourceRect,
+                                   const QRect &clip,
+                                   int const_alpha);
+
+void qt_scale_image_rgb16_on_rgb16_neon(uchar *destPixels, int dbpl,
+                                        const uchar *srcPixels, int sbpl,
+                                        const QRectF &targetRect,
+                                        const QRectF &sourceRect,
+                                        const QRect &clip,
+                                        int const_alpha)
+{
+    if (const_alpha == 0)
+        return;
+
+    if (const_alpha == 256) {
+        qt_scale_image_rgb16_on_rgb16(destPixels, dbpl, srcPixels, sbpl, targetRect, sourceRect, clip, const_alpha);
+        return;
+    }
+
+    qt_scale_image_16bit<quint16>(destPixels, dbpl, srcPixels, sbpl, targetRect, sourceRect, clip,
+        Blend_on_RGB16_SourceAndConstAlpha_Neon_create<quint16>(blend_8_pixels_rgb16_on_rgb16_neon, const_alpha));
+}
+
+extern void qt_transform_image_rgb16_on_rgb16(uchar *destPixels, int dbpl,
+                                              const uchar *srcPixels, int sbpl,
+                                              const QRectF &targetRect,
+                                              const QRectF &sourceRect,
+                                              const QRect &clip,
+                                              const QTransform &targetRectTransform,
+                                              int const_alpha);
+
+void qt_transform_image_rgb16_on_rgb16_neon(uchar *destPixels, int dbpl,
+                                            const uchar *srcPixels, int sbpl,
+                                            const QRectF &targetRect,
+                                            const QRectF &sourceRect,
+                                            const QRect &clip,
+                                            const QTransform &targetRectTransform,
+                                            int const_alpha)
+{
+    if (const_alpha == 0)
+        return;
+
+    if (const_alpha == 256) {
+        qt_transform_image_rgb16_on_rgb16(destPixels, dbpl, srcPixels, sbpl, targetRect, sourceRect, clip, targetRectTransform, const_alpha);
+        return;
+    }
+
+    qt_transform_image(reinterpret_cast<quint16 *>(destPixels), dbpl,
+                       reinterpret_cast<const quint16 *>(srcPixels), sbpl, targetRect, sourceRect, clip, targetRectTransform,
+        Blend_on_RGB16_SourceAndConstAlpha_Neon_create<quint16>(blend_8_pixels_rgb16_on_rgb16_neon, const_alpha));
+}
+
+void qt_transform_image_argb32_on_rgb16_neon(uchar *destPixels, int dbpl,
+                                             const uchar *srcPixels, int sbpl,
+                                             const QRectF &targetRect,
+                                             const QRectF &sourceRect,
+                                             const QRect &clip,
+                                             const QTransform &targetRectTransform,
+                                             int const_alpha)
+{
+    if (const_alpha == 0)
+        return;
+
+    qt_transform_image(reinterpret_cast<quint16 *>(destPixels), dbpl,
+                       reinterpret_cast<const quint32 *>(srcPixels), sbpl, targetRect, sourceRect, clip, targetRectTransform,
+        Blend_on_RGB16_SourceAndConstAlpha_Neon_create<quint32>(blend_8_pixels_argb32_on_rgb16_neon, const_alpha));
+}
+
+static inline void convert_8_pixels_rgb16_to_argb32(quint32 *dst, const quint16 *src)
+{
+    asm volatile (
+        "vld1.16     { d0, d1 }, [%[SRC]]\n\t"
+
+        /* convert 8 r5g6b5 pixel data from {d0, d1} to planar 8-bit format
+           and put data into d4 - red, d3 - green, d2 - blue */
+        "vshrn.u16   d4,  q0,  #8\n\t"
+        "vshrn.u16   d3,  q0,  #3\n\t"
+        "vsli.u16    q0,  q0,  #5\n\t"
+        "vsri.u8     d4,  d4,  #5\n\t"
+        "vsri.u8     d3,  d3,  #6\n\t"
+        "vshrn.u16   d2,  q0,  #2\n\t"
+
+        /* fill d5 - alpha with 0xff */
+        "mov         r2, #255\n\t"
+        "vdup.8      d5, r2\n\t"
+
+        "vst4.8      { d2, d3, d4, d5 }, [%[DST]]"
+        : : [DST]"r" (dst), [SRC]"r" (src)
+        : "memory", "r2", "d0", "d1", "d2", "d3", "d4", "d5"
+    );
+}
+
+uint * QT_FASTCALL qt_destFetchRGB16_neon(uint *buffer, QRasterBuffer *rasterBuffer, int x, int y, int length)
+{
+    const ushort *data = (const ushort *)rasterBuffer->scanLine(y) + x;
+
+    int i = 0;
+    for (; i < length - 7; i += 8)
+        convert_8_pixels_rgb16_to_argb32(&buffer[i], &data[i]);
+
+    if (i < length) {
+        quint16 srcBuffer[8];
+        quint32 dstBuffer[8];
+
+        int tail = length - i;
+        for (int j = 0; j < tail; ++j)
+            srcBuffer[j] = data[i + j];
+
+        convert_8_pixels_rgb16_to_argb32(dstBuffer, srcBuffer);
+
+        for (int j = 0; j < tail; ++j)
+            buffer[i + j] = dstBuffer[j];
+    }
+
+    return buffer;
+}
+
+static inline void convert_8_pixels_argb32_to_rgb16(quint16 *dst, const quint32 *src)
+{
+    asm volatile (
+        "vld4.8      { d0, d1, d2, d3 }, [%[SRC]]\n\t"
+
+        /* convert to r5g6b5 and store it into {d28, d29} */
+        "vshll.u8    q14, d2, #8\n\t"
+        "vshll.u8    q8,  d1, #8\n\t"
+        "vshll.u8    q9,  d0, #8\n\t"
+        "vsri.u16    q14, q8, #5\n\t"
+        "vsri.u16    q14, q9, #11\n\t"
+
+        "vst1.16     { d28, d29 }, [%[DST]]"
+        : : [DST]"r" (dst), [SRC]"r" (src)
+        : "memory", "d0", "d1", "d2", "d3", "d16", "d17", "d18", "d19", "d28", "d29"
+    );
+}
+
+void QT_FASTCALL qt_destStoreRGB16_neon(QRasterBuffer *rasterBuffer, int x, int y, const uint *buffer, int length)
+{
+    quint16 *data = (quint16*)rasterBuffer->scanLine(y) + x;
+
+    int i = 0;
+    for (; i < length - 7; i += 8)
+        convert_8_pixels_argb32_to_rgb16(&data[i], &buffer[i]);
+
+    if (i < length) {
+        quint32 srcBuffer[8];
+        quint16 dstBuffer[8];
+
+        int tail = length - i;
+        for (int j = 0; j < tail; ++j)
+            srcBuffer[j] = buffer[i + j];
+
+        convert_8_pixels_argb32_to_rgb16(dstBuffer, srcBuffer);
+
+        for (int j = 0; j < tail; ++j)
+            data[i + j] = dstBuffer[j];
+    }
+}
+
 QT_END_NAMESPACE
 
 #endif // QT_HAVE_NEON