Improved gradient table generation performance for two-stop gradients.
[profile/ivi/qtbase.git] / src / gui / painting / qdrawhelper_sse2.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the QtGui module of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
14 ** this package.
15 **
16 ** GNU Lesser General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 ** General Public License version 2.1 as published by the Free Software
19 ** Foundation and appearing in the file LICENSE.LGPL included in the
20 ** packaging of this file.  Please review the following information to
21 ** ensure the GNU Lesser General Public License version 2.1 requirements
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23 **
24 ** In addition, as a special exception, Nokia gives you certain additional
25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27 **
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
30 **
31 **
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include <private/qdrawhelper_x86_p.h>
43
44 #ifdef QT_HAVE_SSE2
45
46 #include <private/qdrawingprimitive_sse2_p.h>
47 #include <private/qpaintengine_raster_p.h>
48
49 QT_BEGIN_NAMESPACE
50
51 void qt_blend_argb32_on_argb32_sse2(uchar *destPixels, int dbpl,
52                                     const uchar *srcPixels, int sbpl,
53                                     int w, int h,
54                                     int const_alpha)
55 {
56     const quint32 *src = (const quint32 *) srcPixels;
57     quint32 *dst = (quint32 *) destPixels;
58     if (const_alpha == 256) {
59         const __m128i alphaMask = _mm_set1_epi32(0xff000000);
60         const __m128i nullVector = _mm_set1_epi32(0);
61         const __m128i half = _mm_set1_epi16(0x80);
62         const __m128i one = _mm_set1_epi16(0xff);
63         const __m128i colorMask = _mm_set1_epi32(0x00ff00ff);
64         for (int y = 0; y < h; ++y) {
65             BLEND_SOURCE_OVER_ARGB32_SSE2(dst, src, w, nullVector, half, one, colorMask, alphaMask);
66             dst = (quint32 *)(((uchar *) dst) + dbpl);
67             src = (const quint32 *)(((const uchar *) src) + sbpl);
68         }
69     } else if (const_alpha != 0) {
70         // dest = (s + d * sia) * ca + d * cia
71         //      = s * ca + d * (sia * ca + cia)
72         //      = s * ca + d * (1 - sa*ca)
73         const_alpha = (const_alpha * 255) >> 8;
74         const __m128i nullVector = _mm_set1_epi32(0);
75         const __m128i half = _mm_set1_epi16(0x80);
76         const __m128i one = _mm_set1_epi16(0xff);
77         const __m128i colorMask = _mm_set1_epi32(0x00ff00ff);
78         const __m128i constAlphaVector = _mm_set1_epi16(const_alpha);
79         for (int y = 0; y < h; ++y) {
80             BLEND_SOURCE_OVER_ARGB32_WITH_CONST_ALPHA_SSE2(dst, src, w, nullVector, half, one, colorMask, constAlphaVector)
81             dst = (quint32 *)(((uchar *) dst) + dbpl);
82             src = (const quint32 *)(((const uchar *) src) + sbpl);
83         }
84     }
85 }
86
87 // qblendfunctions.cpp
88 void qt_blend_rgb32_on_rgb32(uchar *destPixels, int dbpl,
89                              const uchar *srcPixels, int sbpl,
90                              int w, int h,
91                              int const_alpha);
92
93 void qt_blend_rgb32_on_rgb32_sse2(uchar *destPixels, int dbpl,
94                                  const uchar *srcPixels, int sbpl,
95                                  int w, int h,
96                                  int const_alpha)
97 {
98     const quint32 *src = (const quint32 *) srcPixels;
99     quint32 *dst = (quint32 *) destPixels;
100     if (const_alpha != 256) {
101         if (const_alpha != 0) {
102             const __m128i nullVector = _mm_set1_epi32(0);
103             const __m128i half = _mm_set1_epi16(0x80);
104             const __m128i colorMask = _mm_set1_epi32(0x00ff00ff);
105
106             const_alpha = (const_alpha * 255) >> 8;
107             int one_minus_const_alpha = 255 - const_alpha;
108             const __m128i constAlphaVector = _mm_set1_epi16(const_alpha);
109             const __m128i oneMinusConstAlpha =  _mm_set1_epi16(one_minus_const_alpha);
110             for (int y = 0; y < h; ++y) {
111                 int x = 0;
112
113                 // First, align dest to 16 bytes:
114                 ALIGNMENT_PROLOGUE_16BYTES(dst, x, w) {
115                     quint32 s = src[x];
116                     s = BYTE_MUL(s, const_alpha);
117                     dst[x] = INTERPOLATE_PIXEL_255(src[x], const_alpha, dst[x], one_minus_const_alpha);
118                 }
119
120                 for (; x < w-3; x += 4) {
121                     __m128i srcVector = _mm_loadu_si128((__m128i *)&src[x]);
122                     if (_mm_movemask_epi8(_mm_cmpeq_epi32(srcVector, nullVector)) != 0xffff) {
123                         const __m128i dstVector = _mm_load_si128((__m128i *)&dst[x]);
124                         __m128i result;
125                         INTERPOLATE_PIXEL_255_SSE2(result, srcVector, dstVector, constAlphaVector, oneMinusConstAlpha, colorMask, half);
126                         _mm_store_si128((__m128i *)&dst[x], result);
127                     }
128                 }
129                 for (; x<w; ++x) {
130                     quint32 s = src[x];
131                     s = BYTE_MUL(s, const_alpha);
132                     dst[x] = INTERPOLATE_PIXEL_255(src[x], const_alpha, dst[x], one_minus_const_alpha);
133                 }
134                 dst = (quint32 *)(((uchar *) dst) + dbpl);
135                 src = (const quint32 *)(((const uchar *) src) + sbpl);
136             }
137         }
138     } else {
139         qt_blend_rgb32_on_rgb32(destPixels, dbpl, srcPixels, sbpl, w, h, const_alpha);
140     }
141 }
142
143 void QT_FASTCALL comp_func_SourceOver_sse2(uint *destPixels, const uint *srcPixels, int length, uint const_alpha)
144 {
145     Q_ASSERT(const_alpha < 256);
146
147     const quint32 *src = (const quint32 *) srcPixels;
148     quint32 *dst = (quint32 *) destPixels;
149
150     const __m128i nullVector = _mm_set1_epi32(0);
151     const __m128i half = _mm_set1_epi16(0x80);
152     const __m128i one = _mm_set1_epi16(0xff);
153     const __m128i colorMask = _mm_set1_epi32(0x00ff00ff);
154     if (const_alpha == 255) {
155         const __m128i alphaMask = _mm_set1_epi32(0xff000000);
156         BLEND_SOURCE_OVER_ARGB32_SSE2(dst, src, length, nullVector, half, one, colorMask, alphaMask);
157     } else {
158         const __m128i constAlphaVector = _mm_set1_epi16(const_alpha);
159         BLEND_SOURCE_OVER_ARGB32_WITH_CONST_ALPHA_SSE2(dst, src, length, nullVector, half, one, colorMask, constAlphaVector);
160     }
161 }
162
163 void QT_FASTCALL comp_func_Plus_sse2(uint *dst, const uint *src, int length, uint const_alpha)
164 {
165     int x = 0;
166
167     if (const_alpha == 255) {
168         // 1) Prologue: align destination on 16 bytes
169         ALIGNMENT_PROLOGUE_16BYTES(dst, x, length)
170             dst[x] = comp_func_Plus_one_pixel(dst[x], src[x]);
171
172         // 2) composition with SSE2
173         for (; x < length - 3; x += 4) {
174             const __m128i srcVector = _mm_loadu_si128((__m128i *)&src[x]);
175             const __m128i dstVector = _mm_load_si128((__m128i *)&dst[x]);
176
177             const __m128i result = _mm_adds_epu8(srcVector, dstVector);
178             _mm_store_si128((__m128i *)&dst[x], result);
179         }
180
181         // 3) Epilogue:
182         for (; x < length; ++x)
183             dst[x] = comp_func_Plus_one_pixel(dst[x], src[x]);
184     } else {
185         const int one_minus_const_alpha = 255 - const_alpha;
186         const __m128i constAlphaVector = _mm_set1_epi16(const_alpha);
187         const __m128i oneMinusConstAlpha =  _mm_set1_epi16(one_minus_const_alpha);
188
189         // 1) Prologue: align destination on 16 bytes
190         ALIGNMENT_PROLOGUE_16BYTES(dst, x, length)
191             dst[x] = comp_func_Plus_one_pixel_const_alpha(dst[x], src[x], const_alpha, one_minus_const_alpha);
192
193         const __m128i half = _mm_set1_epi16(0x80);
194         const __m128i colorMask = _mm_set1_epi32(0x00ff00ff);
195         // 2) composition with SSE2
196         for (; x < length - 3; x += 4) {
197             const __m128i srcVector = _mm_loadu_si128((__m128i *)&src[x]);
198             const __m128i dstVector = _mm_load_si128((__m128i *)&dst[x]);
199
200             __m128i result = _mm_adds_epu8(srcVector, dstVector);
201             INTERPOLATE_PIXEL_255_SSE2(result, result, dstVector, constAlphaVector, oneMinusConstAlpha, colorMask, half)
202             _mm_store_si128((__m128i *)&dst[x], result);
203         }
204
205         // 3) Epilogue:
206         for (; x < length; ++x)
207             dst[x] = comp_func_Plus_one_pixel_const_alpha(dst[x], src[x], const_alpha, one_minus_const_alpha);
208     }
209 }
210
211 void QT_FASTCALL comp_func_Source_sse2(uint *dst, const uint *src, int length, uint const_alpha)
212 {
213     if (const_alpha == 255) {
214         ::memcpy(dst, src, length * sizeof(uint));
215     } else {
216         const int ialpha = 255 - const_alpha;
217
218         int x = 0;
219
220         // 1) prologue, align on 16 bytes
221         ALIGNMENT_PROLOGUE_16BYTES(dst, x, length)
222             dst[x] = INTERPOLATE_PIXEL_255(src[x], const_alpha, dst[x], ialpha);
223
224         // 2) interpolate pixels with SSE2
225         const __m128i half = _mm_set1_epi16(0x80);
226         const __m128i colorMask = _mm_set1_epi32(0x00ff00ff);
227         const __m128i constAlphaVector = _mm_set1_epi16(const_alpha);
228         const __m128i oneMinusConstAlpha =  _mm_set1_epi16(ialpha);
229         for (; x < length - 3; x += 4) {
230             const __m128i srcVector = _mm_loadu_si128((__m128i *)&src[x]);
231             __m128i dstVector = _mm_load_si128((__m128i *)&dst[x]);
232             INTERPOLATE_PIXEL_255_SSE2(dstVector, srcVector, dstVector, constAlphaVector, oneMinusConstAlpha, colorMask, half)
233             _mm_store_si128((__m128i *)&dst[x], dstVector);
234         }
235
236         // 3) Epilogue
237         for (; x < length; ++x)
238             dst[x] = INTERPOLATE_PIXEL_255(src[x], const_alpha, dst[x], ialpha);
239     }
240 }
241
242 void qt_memfill32_sse2(quint32 *dest, quint32 value, int count)
243 {
244     if (count < 7) {
245         switch (count) {
246         case 6: *dest++ = value;
247         case 5: *dest++ = value;
248         case 4: *dest++ = value;
249         case 3: *dest++ = value;
250         case 2: *dest++ = value;
251         case 1: *dest   = value;
252         }
253         return;
254     };
255
256     const int align = (quintptr)(dest) & 0xf;
257     switch (align) {
258     case 4:  *dest++ = value; --count;
259     case 8:  *dest++ = value; --count;
260     case 12: *dest++ = value; --count;
261     }
262
263     int count128 = count / 4;
264     __m128i *dst128 = reinterpret_cast<__m128i*>(dest);
265     const __m128i value128 = _mm_set_epi32(value, value, value, value);
266
267     int n = (count128 + 3) / 4;
268     switch (count128 & 0x3) {
269     case 0: do { _mm_stream_si128(dst128++, value128);
270     case 3:      _mm_stream_si128(dst128++, value128);
271     case 2:      _mm_stream_si128(dst128++, value128);
272     case 1:      _mm_stream_si128(dst128++, value128);
273     } while (--n > 0);
274     }
275
276     const int rest = count & 0x3;
277     if (rest) {
278         switch (rest) {
279         case 3: dest[count - 3] = value;
280         case 2: dest[count - 2] = value;
281         case 1: dest[count - 1] = value;
282         }
283     }
284 }
285
286 void QT_FASTCALL comp_func_solid_SourceOver_sse2(uint *destPixels, int length, uint color, uint const_alpha)
287 {
288     if ((const_alpha & qAlpha(color)) == 255) {
289         qt_memfill32_sse2(destPixels, color, length);
290     } else {
291         if (const_alpha != 255)
292             color = BYTE_MUL(color, const_alpha);
293
294         const quint32 minusAlphaOfColor = qAlpha(~color);
295         int x = 0;
296
297         quint32 *dst = (quint32 *) destPixels;
298         const __m128i colorVector = _mm_set1_epi32(color);
299         const __m128i colorMask = _mm_set1_epi32(0x00ff00ff);
300         const __m128i half = _mm_set1_epi16(0x80);
301         const __m128i minusAlphaOfColorVector = _mm_set1_epi16(minusAlphaOfColor);
302
303         ALIGNMENT_PROLOGUE_16BYTES(dst, x, length)
304             destPixels[x] = color + BYTE_MUL(destPixels[x], minusAlphaOfColor);
305
306         for (; x < length-3; x += 4) {
307             __m128i dstVector = _mm_load_si128((__m128i *)&dst[x]);
308             BYTE_MUL_SSE2(dstVector, dstVector, minusAlphaOfColorVector, colorMask, half);
309             dstVector = _mm_add_epi8(colorVector, dstVector);
310             _mm_store_si128((__m128i *)&dst[x], dstVector);
311         }
312         for (;x < length; ++x)
313             destPixels[x] = color + BYTE_MUL(destPixels[x], minusAlphaOfColor);
314     }
315 }
316
317 CompositionFunctionSolid qt_functionForModeSolid_onlySSE2[numCompositionFunctions] = {
318     comp_func_solid_SourceOver_sse2,
319     comp_func_solid_DestinationOver,
320     comp_func_solid_Clear,
321     comp_func_solid_Source,
322     comp_func_solid_Destination,
323     comp_func_solid_SourceIn,
324     comp_func_solid_DestinationIn,
325     comp_func_solid_SourceOut,
326     comp_func_solid_DestinationOut,
327     comp_func_solid_SourceAtop,
328     comp_func_solid_DestinationAtop,
329     comp_func_solid_XOR,
330     comp_func_solid_Plus,
331     comp_func_solid_Multiply,
332     comp_func_solid_Screen,
333     comp_func_solid_Overlay,
334     comp_func_solid_Darken,
335     comp_func_solid_Lighten,
336     comp_func_solid_ColorDodge,
337     comp_func_solid_ColorBurn,
338     comp_func_solid_HardLight,
339     comp_func_solid_SoftLight,
340     comp_func_solid_Difference,
341     comp_func_solid_Exclusion,
342     rasterop_solid_SourceOrDestination,
343     rasterop_solid_SourceAndDestination,
344     rasterop_solid_SourceXorDestination,
345     rasterop_solid_NotSourceAndNotDestination,
346     rasterop_solid_NotSourceOrNotDestination,
347     rasterop_solid_NotSourceXorDestination,
348     rasterop_solid_NotSource,
349     rasterop_solid_NotSourceAndDestination,
350     rasterop_solid_SourceAndNotDestination
351 };
352
353 CompositionFunction qt_functionForMode_onlySSE2[numCompositionFunctions] = {
354     comp_func_SourceOver_sse2,
355     comp_func_DestinationOver,
356     comp_func_Clear,
357     comp_func_Source_sse2,
358     comp_func_Destination,
359     comp_func_SourceIn,
360     comp_func_DestinationIn,
361     comp_func_SourceOut,
362     comp_func_DestinationOut,
363     comp_func_SourceAtop,
364     comp_func_DestinationAtop,
365     comp_func_XOR,
366     comp_func_Plus_sse2,
367     comp_func_Multiply,
368     comp_func_Screen,
369     comp_func_Overlay,
370     comp_func_Darken,
371     comp_func_Lighten,
372     comp_func_ColorDodge,
373     comp_func_ColorBurn,
374     comp_func_HardLight,
375     comp_func_SoftLight,
376     comp_func_Difference,
377     comp_func_Exclusion,
378     rasterop_SourceOrDestination,
379     rasterop_SourceAndDestination,
380     rasterop_SourceXorDestination,
381     rasterop_NotSourceAndNotDestination,
382     rasterop_NotSourceOrNotDestination,
383     rasterop_NotSourceXorDestination,
384     rasterop_NotSource,
385     rasterop_NotSourceAndDestination,
386     rasterop_SourceAndNotDestination
387 };
388
389 void qt_memfill16_sse2(quint16 *dest, quint16 value, int count)
390 {
391     if (count < 3) {
392         switch (count) {
393         case 2: *dest++ = value;
394         case 1: *dest = value;
395         }
396         return;
397     }
398
399     const int align = (quintptr)(dest) & 0x3;
400     switch (align) {
401     case 2: *dest++ = value; --count;
402     }
403
404     const quint32 value32 = (value << 16) | value;
405     qt_memfill32_sse2(reinterpret_cast<quint32*>(dest), value32, count / 2);
406
407     if (count & 0x1)
408         dest[count - 1] = value;
409 }
410
411 void qt_bitmapblit32_sse2(QRasterBuffer *rasterBuffer, int x, int y,
412                           quint32 color,
413                           const uchar *src, int width, int height, int stride)
414 {
415     quint32 *dest = reinterpret_cast<quint32*>(rasterBuffer->scanLine(y)) + x;
416     const int destStride = rasterBuffer->bytesPerLine() / sizeof(quint32);
417
418     const __m128i c128 = _mm_set1_epi32(color);
419     const __m128i maskmask1 = _mm_set_epi32(0x10101010, 0x20202020,
420                                             0x40404040, 0x80808080);
421     const __m128i maskadd1 = _mm_set_epi32(0x70707070, 0x60606060,
422                                            0x40404040, 0x00000000);
423
424     if (width > 4) {
425         const __m128i maskmask2 = _mm_set_epi32(0x01010101, 0x02020202,
426                                                 0x04040404, 0x08080808);
427         const __m128i maskadd2 = _mm_set_epi32(0x7f7f7f7f, 0x7e7e7e7e,
428                                                0x7c7c7c7c, 0x78787878);
429         while (height--) {
430             for (int x = 0; x < width; x += 8) {
431                 const quint8 s = src[x >> 3];
432                 if (!s)
433                     continue;
434                 __m128i mask1 = _mm_set1_epi8(s);
435                 __m128i mask2 = mask1;
436
437                 mask1 = _mm_and_si128(mask1, maskmask1);
438                 mask1 = _mm_add_epi8(mask1, maskadd1);
439                 _mm_maskmoveu_si128(c128, mask1, (char*)(dest + x));
440                 mask2 = _mm_and_si128(mask2, maskmask2);
441                 mask2 = _mm_add_epi8(mask2, maskadd2);
442                 _mm_maskmoveu_si128(c128, mask2, (char*)(dest + x + 4));
443             }
444             dest += destStride;
445             src += stride;
446         }
447     } else {
448         while (height--) {
449             const quint8 s = *src;
450             if (s) {
451                 __m128i mask1 = _mm_set1_epi8(s);
452                 mask1 = _mm_and_si128(mask1, maskmask1);
453                 mask1 = _mm_add_epi8(mask1, maskadd1);
454                 _mm_maskmoveu_si128(c128, mask1, (char*)(dest));
455             }
456             dest += destStride;
457             src += stride;
458         }
459     }
460 }
461
462 void qt_bitmapblit16_sse2(QRasterBuffer *rasterBuffer, int x, int y,
463                           quint32 color,
464                           const uchar *src, int width, int height, int stride)
465 {
466     const quint16 c = qt_colorConvert<quint16, quint32>(color, 0);
467     quint16 *dest = reinterpret_cast<quint16*>(rasterBuffer->scanLine(y)) + x;
468     const int destStride = rasterBuffer->bytesPerLine() / sizeof(quint16);
469
470     const __m128i c128 = _mm_set1_epi16(c);
471 #if defined(Q_CC_MSVC)
472 #  pragma warning(disable: 4309) // truncation of constant value
473 #endif
474     const __m128i maskmask = _mm_set_epi16(0x0101, 0x0202, 0x0404, 0x0808,
475                                            0x1010, 0x2020, 0x4040, 0x8080);
476     const __m128i maskadd = _mm_set_epi16(0x7f7f, 0x7e7e, 0x7c7c, 0x7878,
477                                           0x7070, 0x6060, 0x4040, 0x0000);
478
479     while (height--) {
480         for (int x = 0; x < width; x += 8) {
481             const quint8 s = src[x >> 3];
482             if (!s)
483                 continue;
484             __m128i mask = _mm_set1_epi8(s);
485             mask = _mm_and_si128(mask, maskmask);
486             mask = _mm_add_epi8(mask, maskadd);
487             _mm_maskmoveu_si128(c128, mask, (char*)(dest + x));
488         }
489         dest += destStride;
490         src += stride;
491     }
492 }
493
494 class QSimdSse2
495 {
496 public:
497     typedef __m128i Int32x4;
498     typedef __m128 Float32x4;
499
500     union Vect_buffer_i { Int32x4 v; int i[4]; };
501     union Vect_buffer_f { Float32x4 v; float f[4]; };
502
503     static inline Float32x4 v_dup(float x) { return _mm_set1_ps(x); }
504     static inline Float32x4 v_dup(double x) { return _mm_set1_ps(x); }
505     static inline Int32x4 v_dup(int x) { return _mm_set1_epi32(x); }
506     static inline Int32x4 v_dup(uint x) { return _mm_set1_epi32(x); }
507
508     static inline Float32x4 v_add(Float32x4 a, Float32x4 b) { return _mm_add_ps(a, b); }
509     static inline Int32x4 v_add(Int32x4 a, Int32x4 b) { return _mm_add_epi32(a, b); }
510
511     static inline Float32x4 v_max(Float32x4 a, Float32x4 b) { return _mm_max_ps(a, b); }
512     static inline Float32x4 v_min(Float32x4 a, Float32x4 b) { return _mm_min_ps(a, b); }
513     static inline Int32x4 v_min_16(Int32x4 a, Int32x4 b) { return _mm_min_epi16(a, b); }
514
515     static inline Int32x4 v_and(Int32x4 a, Int32x4 b) { return _mm_and_si128(a, b); }
516
517     static inline Float32x4 v_sub(Float32x4 a, Float32x4 b) { return _mm_sub_ps(a, b); }
518     static inline Int32x4 v_sub(Int32x4 a, Int32x4 b) { return _mm_sub_epi32(a, b); }
519
520     static inline Float32x4 v_mul(Float32x4 a, Float32x4 b) { return _mm_mul_ps(a, b); }
521
522     static inline Float32x4 v_sqrt(Float32x4 x) { return _mm_sqrt_ps(x); }
523
524     static inline Int32x4 v_toInt(Float32x4 x) { return _mm_cvttps_epi32(x); }
525 };
526
527 const uint * QT_FASTCALL qt_fetch_radial_gradient_sse2(uint *buffer, const Operator *op, const QSpanData *data,
528                                                        int y, int x, int length)
529 {
530     return qt_fetch_radial_gradient_template<QRadialFetchSimd<QSimdSse2> >(buffer, op, data, y, x, length);
531 }
532
533
534 QT_END_NAMESPACE
535
536 #endif // QT_HAVE_SSE2