Initial fast path implementation
[profile/ivi/pixman.git] / pixman / pixman-general.c
1 /*
2  * Copyright © 2009 Red Hat, Inc.
3  * Copyright © 2000 SuSE, Inc.
4  * Copyright © 2007 Red Hat, Inc.
5  *
6  * Permission to use, copy, modify, distribute, and sell this software and its
7  * documentation for any purpose is hereby granted without fee, provided that
8  * the above copyright notice appear in all copies and that both that
9  * copyright notice and this permission notice appear in supporting
10  * documentation, and that the name of Red Hat not be used in advertising or
11  * publicity pertaining to distribution of the software without specific,
12  * written prior permission.  Red Hat makes no representations about the
13  * suitability of this software for any purpose.  It is provided "as is"
14  * without express or implied warranty.
15  *
16  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
17  * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
18  * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
19  * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
20  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
21  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
22  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
23  * SOFTWARE.
24  */
25 #include <config.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <math.h>
29 #include <assert.h>
30 #include <limits.h>
31 #include "pixman-private.h"
32
33
34 static void
35 general_combine_32 (pixman_implementation_t *imp, pixman_op_t op,
36                     uint32_t *dest, const uint32_t *src, const uint32_t *mask,
37                     int width)
38 {
39     CombineFunc32 f = pixman_composeFunctions.combineU[op];
40
41     f (dest, src, mask, width);
42 }
43
44 static void
45 general_combine_32_ca (pixman_implementation_t *imp, pixman_op_t op,
46                        uint32_t *dest, const uint32_t *src, const uint32_t *mask,
47                        int width)
48 {
49     CombineFunc32 f = pixman_composeFunctions.combineC[op];
50
51     f (dest, src, mask, width);
52 }
53
54 static void
55 general_combine_64 (pixman_implementation_t *imp, pixman_op_t op,
56                     uint64_t *dest, const uint64_t *src, const uint64_t *mask,
57                     int width)
58 {
59     CombineFunc64 f = pixman_composeFunctions64.combineU[op];
60
61     f (dest, src, mask, width);
62 }
63
64 static void
65 general_combine_64_ca (pixman_implementation_t *imp, pixman_op_t op,
66                        uint64_t *dest, const uint64_t *src, const uint64_t *mask,
67                        int width)
68 {
69     CombineFunc64 f = pixman_composeFunctions64.combineC[op];
70
71     f (dest, src, mask, width);
72 }
73
74 /*
75  *
76  * Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc.
77  *             2005 Lars Knoll & Zack Rusin, Trolltech
78  *             2008 Aaron Plattner, NVIDIA Corporation
79  *
80  * Permission to use, copy, modify, distribute, and sell this software and its
81  * documentation for any purpose is hereby granted without fee, provided that
82  * the above copyright notice appear in all copies and that both that
83  * copyright notice and this permission notice appear in supporting
84  * documentation, and that the name of Keith Packard not be used in
85  * advertising or publicity pertaining to distribution of the software without
86  * specific, written prior permission.  Keith Packard makes no
87  * representations about the suitability of this software for any purpose.  It
88  * is provided "as is" without express or implied warranty.
89  *
90  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
91  * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
92  * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
93  * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
94  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
95  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
96  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
97  * SOFTWARE.
98  */
99
100 #ifdef HAVE_CONFIG_H
101 #include <config.h>
102 #endif
103
104 static void
105 pixman_composite_rect_general_internal (const FbComposeData *data,
106                                         void *src_buffer, void *mask_buffer, 
107                                         void *dest_buffer, const int wide)
108 {
109     int i;
110     scanStoreProc store;
111     scanFetchProc fetchSrc = NULL, fetchMask = NULL, fetchDest = NULL;
112     uint32_t *bits;
113     int32_t stride;
114     source_pict_class_t srcClass, maskClass;
115     pixman_bool_t component_alpha;
116
117     srcClass = _pixman_image_classify (data->src,
118                                        data->xSrc, data->ySrc,
119                                        data->width, data->height);
120
121     maskClass = SOURCE_IMAGE_CLASS_UNKNOWN;
122     if (data->mask)
123     {
124         maskClass = _pixman_image_classify (data->mask,
125                                             data->xSrc, data->ySrc,
126                                             data->width, data->height);
127     }
128     
129     if (data->op == PIXMAN_OP_CLEAR)
130         fetchSrc = NULL;
131     else if (wide)
132         fetchSrc = _pixman_image_get_scanline_64;
133     else
134         fetchSrc = _pixman_image_get_scanline_32;
135
136     if (!data->mask || data->op == PIXMAN_OP_CLEAR)
137         fetchMask = NULL;
138     else if (wide)
139         fetchMask = _pixman_image_get_scanline_64;
140     else
141         fetchMask = _pixman_image_get_scanline_32;
142
143     if (data->op == PIXMAN_OP_CLEAR || data->op == PIXMAN_OP_SRC)
144         fetchDest = NULL;
145     else if (wide)
146         fetchDest = _pixman_image_get_scanline_64;
147     else
148         fetchDest = _pixman_image_get_scanline_32;
149
150     if (wide)
151         store = _pixman_image_store_scanline_64;
152     else
153         store = _pixman_image_store_scanline_32;
154
155     // Skip the store step and composite directly into the
156     // destination if the output format of the compose func matches
157     // the destination format.
158     if (!wide &&
159         !data->dest->common.alpha_map &&
160         !data->dest->common.write_func && 
161         (data->op == PIXMAN_OP_ADD || data->op == PIXMAN_OP_OVER) &&
162         (data->dest->bits.format == PIXMAN_a8r8g8b8 ||
163          data->dest->bits.format == PIXMAN_x8r8g8b8))
164     {
165         store = NULL;
166     }
167
168     if (!store)
169     {
170         bits = data->dest->bits.bits;
171         stride = data->dest->bits.rowstride;
172     }
173     else
174     {
175         bits = NULL;
176         stride = 0;
177     }
178
179     component_alpha =
180         fetchSrc                   &&
181         fetchMask                  &&
182         data->mask                 &&
183         data->mask->common.type == BITS &&
184         data->mask->common.component_alpha &&
185         PIXMAN_FORMAT_RGB (data->mask->bits.format);
186
187     {
188         CombineFunc32 compose;
189
190         if (wide)
191         {
192             if (component_alpha)
193                 compose = (CombineFunc32)pixman_composeFunctions64.combineC[data->op];
194             else
195                 compose = (CombineFunc32)pixman_composeFunctions64.combineU[data->op];
196         }
197         else
198         {
199             if (component_alpha)
200                 compose = pixman_composeFunctions.combineC[data->op];
201             else
202                 compose = pixman_composeFunctions.combineU[data->op];
203         }
204
205         if (!compose)
206             return;
207
208         if (!fetchMask)
209             mask_buffer = NULL;
210         
211         for (i = 0; i < data->height; ++i)
212         {
213             /* fill first half of scanline with source */
214             if (fetchSrc)
215             {
216                 if (fetchMask)
217                 {
218                     /* fetch mask before source so that fetching of
219                        source can be optimized */
220                     fetchMask (data->mask, data->xMask, data->yMask + i,
221                                data->width, mask_buffer, 0, 0);
222
223                     if (maskClass == SOURCE_IMAGE_CLASS_HORIZONTAL)
224                         fetchMask = NULL;
225                 }
226
227                 if (srcClass == SOURCE_IMAGE_CLASS_HORIZONTAL)
228                 {
229                     fetchSrc (data->src, data->xSrc, data->ySrc + i,
230                               data->width, src_buffer, 0, 0);
231                     fetchSrc = NULL;
232                 }
233                 else
234                 {
235                     fetchSrc (data->src, data->xSrc, data->ySrc + i,
236                               data->width, src_buffer, mask_buffer,
237                               0xffffffff);
238                 }
239             }
240             else if (fetchMask)
241             {
242                 fetchMask (data->mask, data->xMask, data->yMask + i,
243                            data->width, mask_buffer, 0, 0);
244             }
245
246             if (store)
247             {
248                 /* fill dest into second half of scanline */
249                 if (fetchDest)
250                     fetchDest (data->dest, data->xDest, data->yDest + i,
251                                data->width, dest_buffer, 0, 0);
252
253                 /* blend */
254                 compose (dest_buffer, src_buffer, mask_buffer, data->width);
255
256                 /* write back */
257                 store (&(data->dest->bits), data->xDest, data->yDest + i, data->width,
258                        dest_buffer);
259             }
260             else
261             {
262                 /* blend */
263                 compose (bits + (data->yDest + i) * stride +
264                          data->xDest,
265                          src_buffer, mask_buffer, data->width);
266             }
267         }
268     }
269 }
270
271 #define SCANLINE_BUFFER_LENGTH 8192
272
273 static void
274 general_composite_rect (const FbComposeData *data)
275 {
276     uint8_t stack_scanline_buffer[SCANLINE_BUFFER_LENGTH * 3];
277     const pixman_format_code_t srcFormat =
278         data->src->type == BITS ? data->src->bits.format : 0;
279     const pixman_format_code_t maskFormat =
280         data->mask && data->mask->type == BITS ? data->mask->bits.format : 0;
281     const pixman_format_code_t destFormat = data->dest->type == BITS ? data->dest->bits.format : 0;
282     const int srcWide = PIXMAN_FORMAT_16BPC(srcFormat);
283     const int maskWide = data->mask && PIXMAN_FORMAT_16BPC(maskFormat);
284     const int destWide = PIXMAN_FORMAT_16BPC(destFormat);
285     const int wide = srcWide || maskWide || destWide;
286     const int Bpp = wide ? 8 : 4;
287     uint8_t *scanline_buffer = stack_scanline_buffer;
288     uint8_t *src_buffer, *mask_buffer, *dest_buffer;
289     
290     if (data->width * Bpp > SCANLINE_BUFFER_LENGTH)
291     {
292         scanline_buffer = pixman_malloc_abc (data->width, 3, Bpp);
293
294         if (!scanline_buffer)
295             return;
296     }
297
298     src_buffer = scanline_buffer;
299     mask_buffer = src_buffer + data->width * Bpp;
300     dest_buffer = mask_buffer + data->width * Bpp;
301
302     pixman_composite_rect_general_internal (data, src_buffer,
303                                             mask_buffer, dest_buffer,
304                                             wide);
305
306     if (scanline_buffer != stack_scanline_buffer)
307         free (scanline_buffer);
308 }
309
310 #include <stdio.h>
311 #include <stdlib.h>
312 #include <string.h>
313 #include "pixman-private.h"
314 #include "pixman-mmx.h"
315 #include "pixman-vmx.h"
316 #include "pixman-sse2.h"
317 #include "pixman-arm-simd.h"
318 #include "pixman-combine32.h"
319
320 static void
321 pixman_image_composite_rect  (pixman_implementation_t *imp,
322                               pixman_op_t                   op,
323                               pixman_image_t               *src,
324                               pixman_image_t               *mask,
325                               pixman_image_t               *dest,
326                               int32_t                       src_x,
327                               int32_t                       src_y,
328                               int32_t                       mask_x,
329                               int32_t                       mask_y,
330                               int32_t                       dest_x,
331                               int32_t                       dest_y,
332                               int32_t                      width,
333                               int32_t                      height)
334 {
335     FbComposeData compose_data;
336
337     return_if_fail (src != NULL);
338     return_if_fail (dest != NULL);
339
340     compose_data.op = op;
341     compose_data.src = src;
342     compose_data.mask = mask;
343     compose_data.dest = dest;
344     compose_data.xSrc = src_x;
345     compose_data.ySrc = src_y;
346     compose_data.xMask = mask_x;
347     compose_data.yMask = mask_y;
348     compose_data.xDest = dest_x;
349     compose_data.yDest = dest_y;
350     compose_data.width = width;
351     compose_data.height = height;
352
353     general_composite_rect (&compose_data);
354 }
355
356 static pixman_bool_t
357 mask_is_solid (pixman_image_t *mask)
358 {
359     if (mask->type == SOLID)
360         return TRUE;
361
362     if (mask->type == BITS &&
363         mask->common.repeat == PIXMAN_REPEAT_NORMAL &&
364         mask->bits.width == 1 &&
365         mask->bits.height == 1)
366     {
367         return TRUE;
368     }
369
370     return FALSE;
371 }
372
373 static const FastPathInfo *
374 get_fast_path (const FastPathInfo *fast_paths,
375                pixman_op_t         op,
376                pixman_image_t     *pSrc,
377                pixman_image_t     *pMask,
378                pixman_image_t     *pDst,
379                pixman_bool_t       is_pixbuf)
380 {
381     const FastPathInfo *info;
382
383     for (info = fast_paths; info->op != PIXMAN_OP_NONE; info++)
384     {
385         pixman_bool_t valid_src         = FALSE;
386         pixman_bool_t valid_mask        = FALSE;
387
388         if (info->op != op)
389             continue;
390
391         if ((info->src_format == PIXMAN_solid && pixman_image_can_get_solid (pSrc))             ||
392             (pSrc->type == BITS && info->src_format == pSrc->bits.format))
393         {
394             valid_src = TRUE;
395         }
396
397         if (!valid_src)
398             continue;
399
400         if ((info->mask_format == PIXMAN_null && !pMask)                        ||
401             (pMask && pMask->type == BITS && info->mask_format == pMask->bits.format))
402         {
403             valid_mask = TRUE;
404
405             if (info->flags & NEED_SOLID_MASK)
406             {
407                 if (!pMask || !mask_is_solid (pMask))
408                     valid_mask = FALSE;
409             }
410
411             if (info->flags & NEED_COMPONENT_ALPHA)
412             {
413                 if (!pMask || !pMask->common.component_alpha)
414                     valid_mask = FALSE;
415             }
416         }
417
418         if (!valid_mask)
419             continue;
420         
421         if (info->dest_format != pDst->bits.format)
422             continue;
423
424         if ((info->flags & NEED_PIXBUF) && !is_pixbuf)
425             continue;
426
427         return info;
428     }
429
430     return NULL;
431 }
432
433 #if defined(USE_SSE2) && defined(__GNUC__) && !defined(__x86_64__) && !defined(__amd64__)
434
435 /*
436  * Work around GCC bug causing crashes in Mozilla with SSE2
437  * 
438  * When using SSE2 intrinsics, gcc assumes that the stack is 16 byte
439  * aligned. Unfortunately some code, such as Mozilla and Mono contain
440  * code that aligns the stack to 4 bytes.
441  *
442  * The __force_align_arg_pointer__ makes gcc generate a prologue that
443  * realigns the stack pointer to 16 bytes.
444  *
445  * On x86-64 this is not necessary because the standard ABI already
446  * calls for a 16 byte aligned stack.
447  *
448  * See https://bugs.freedesktop.org/show_bug.cgi?id=15693
449  */
450
451 __attribute__((__force_align_arg_pointer__))
452 #endif
453 static void
454 general_composite (pixman_implementation_t *    imp,
455                    pixman_op_t                  op,
456                    pixman_image_t *             src,
457                    pixman_image_t *             mask,
458                    pixman_image_t *             dest,
459                    int32_t                      src_x,
460                    int32_t                      src_y,
461                    int32_t                      mask_x,
462                    int32_t                      mask_y,
463                    int32_t                      dest_x,
464                    int32_t                      dest_y,
465                    int32_t                      width,
466                    int32_t                      height)
467 {
468     pixman_bool_t srcRepeat = src->type == BITS && src->common.repeat == PIXMAN_REPEAT_NORMAL;
469     pixman_bool_t maskRepeat = FALSE;
470     pixman_bool_t srcTransform = src->common.transform != NULL;
471     pixman_bool_t maskTransform = FALSE;
472     pixman_bool_t srcAlphaMap = src->common.alpha_map != NULL;
473     pixman_bool_t maskAlphaMap = FALSE;
474     pixman_bool_t dstAlphaMap = dest->common.alpha_map != NULL;
475     pixman_composite_func_t func = NULL;
476
477 #ifdef USE_MMX
478     fbComposeSetupMMX();
479 #endif
480
481 #ifdef USE_VMX
482     fbComposeSetupVMX();
483 #endif
484
485 #ifdef USE_SSE2
486     fbComposeSetupSSE2();
487 #endif
488
489     if (srcRepeat && srcTransform &&
490         src->bits.width == 1 &&
491         src->bits.height == 1)
492     {
493         srcTransform = FALSE;
494     }
495
496     if (mask && mask->type == BITS)
497     {
498         maskRepeat = mask->common.repeat == PIXMAN_REPEAT_NORMAL;
499
500         maskTransform = mask->common.transform != 0;
501         if (mask->common.filter == PIXMAN_FILTER_CONVOLUTION)
502             maskTransform = TRUE;
503
504         maskAlphaMap = mask->common.alpha_map != 0;
505
506         if (maskRepeat && maskTransform &&
507             mask->bits.width == 1 &&
508             mask->bits.height == 1)
509         {
510             maskTransform = FALSE;
511         }
512     }
513
514     if ((src->type == BITS || pixman_image_can_get_solid (src)) && (!mask || mask->type == BITS)
515         && !srcTransform && !maskTransform
516         && !maskAlphaMap && !srcAlphaMap && !dstAlphaMap
517         && (src->common.filter != PIXMAN_FILTER_CONVOLUTION)
518         && (src->common.repeat != PIXMAN_REPEAT_PAD)
519         && (src->common.repeat != PIXMAN_REPEAT_REFLECT)
520         && (!mask || (mask->common.filter != PIXMAN_FILTER_CONVOLUTION &&
521                 mask->common.repeat != PIXMAN_REPEAT_PAD && mask->common.repeat != PIXMAN_REPEAT_REFLECT))
522         && !src->common.read_func && !src->common.write_func
523         && !(mask && mask->common.read_func) && !(mask && mask->common.write_func)
524         && !dest->common.read_func && !dest->common.write_func)
525     {
526         const FastPathInfo *info;
527         pixman_bool_t pixbuf;
528
529         pixbuf =
530             src && src->type == BITS            &&
531             mask && mask->type == BITS  &&
532             src->bits.bits == mask->bits.bits &&
533             src_x == mask_x                     &&
534             src_y == mask_y                     &&
535             !mask->common.component_alpha       &&
536             !maskRepeat;
537         info = NULL;
538         
539 #ifdef USE_SSE2
540         if (pixman_have_sse2 ())
541             info = get_fast_path (sse2_fast_paths, op, src, mask, dest, pixbuf);
542 #endif
543
544 #ifdef USE_MMX
545         if (!info && pixman_have_mmx())
546             info = get_fast_path (mmx_fast_paths, op, src, mask, dest, pixbuf);
547 #endif
548
549 #ifdef USE_VMX
550
551         if (!info && pixman_have_vmx())
552             info = get_fast_path (vmx_fast_paths, op, src, mask, dest, pixbuf);
553 #endif
554
555 #ifdef USE_ARM_NEON
556         if (!info && pixman_have_arm_neon())
557             info = get_fast_path (arm_neon_fast_paths, op, src, mask, dest, pixbuf);
558 #endif
559
560 #ifdef USE_ARM_SIMD
561         if (!info && pixman_have_arm_simd())
562             info = get_fast_path (arm_simd_fast_paths, op, src, mask, dest, pixbuf);
563 #endif
564
565         if (!info)
566             info = get_fast_path (c_fast_paths, op, src, mask, dest, pixbuf);
567
568         if (info)
569         {
570             func = info->func;
571
572             if (info->src_format == PIXMAN_solid)
573                 srcRepeat = FALSE;
574
575             if (info->mask_format == PIXMAN_solid       ||
576                 info->flags & NEED_SOLID_MASK)
577             {
578                 maskRepeat = FALSE;
579             }
580         }
581     }
582     
583     if ((srcRepeat                      &&
584          src->bits.width == 1           &&
585          src->bits.height == 1) ||
586         (maskRepeat                     &&
587          mask->bits.width == 1          &&
588          mask->bits.height == 1))
589     {
590         /* If src or mask are repeating 1x1 images and srcRepeat or
591          * maskRepeat are still TRUE, it means the fast path we
592          * selected does not actually handle repeating images.
593          *
594          * So rather than call the "fast path" with a zillion
595          * 1x1 requests, we just use the general code (which does
596          * do something sensible with 1x1 repeating images).
597          */
598         func = NULL;
599     }
600
601     if (!func)
602     {
603         func = pixman_image_composite_rect;
604
605         /* CompositeGeneral optimizes 1x1 repeating images itself */
606         if (src->type == BITS &&
607             src->bits.width == 1 && src->bits.height == 1)
608         {
609             srcRepeat = FALSE;
610         }
611
612         if (mask && mask->type == BITS &&
613             mask->bits.width == 1 && mask->bits.height == 1)
614         {
615             maskRepeat = FALSE;
616         }
617
618         /* if we are transforming, repeats are handled in fbFetchTransformed */
619         if (srcTransform)
620             srcRepeat = FALSE;
621
622         if (maskTransform)
623             maskRepeat = FALSE;
624     }
625
626     _pixman_walk_composite_region (imp, op, src, mask, dest, src_x, src_y,
627                                   mask_x, mask_y, dest_x, dest_y, width, height,
628                                   srcRepeat, maskRepeat, func);
629 }
630
631 pixman_implementation_t *
632 _pixman_implementation_create_general (pixman_implementation_t *toplevel)
633 {
634     pixman_implementation_t *imp = _pixman_implementation_create (toplevel, NULL);
635     int i;
636
637     imp->composite = general_composite;
638     
639     for (i = 0; i < PIXMAN_OP_LAST; ++i)
640     {
641         imp->combine_32[i] = general_combine_32;
642         imp->combine_32_ca[i] = general_combine_32_ca;
643         imp->combine_64[i] = general_combine_64;
644         imp->combine_64_ca[i] = general_combine_64_ca;
645     }
646
647     return imp;
648 }