Remove fast path lookup code from pixman-general
[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 #if defined(USE_SSE2) && defined(__GNUC__) && !defined(__x86_64__) && !defined(__amd64__)
357
358 /*
359  * Work around GCC bug causing crashes in Mozilla with SSE2
360  * 
361  * When using SSE2 intrinsics, gcc assumes that the stack is 16 byte
362  * aligned. Unfortunately some code, such as Mozilla and Mono contain
363  * code that aligns the stack to 4 bytes.
364  *
365  * The __force_align_arg_pointer__ makes gcc generate a prologue that
366  * realigns the stack pointer to 16 bytes.
367  *
368  * On x86-64 this is not necessary because the standard ABI already
369  * calls for a 16 byte aligned stack.
370  *
371  * See https://bugs.freedesktop.org/show_bug.cgi?id=15693
372  */
373
374 __attribute__((__force_align_arg_pointer__))
375 #endif
376 static void
377 general_composite (pixman_implementation_t *    imp,
378                    pixman_op_t                  op,
379                    pixman_image_t *             src,
380                    pixman_image_t *             mask,
381                    pixman_image_t *             dest,
382                    int32_t                      src_x,
383                    int32_t                      src_y,
384                    int32_t                      mask_x,
385                    int32_t                      mask_y,
386                    int32_t                      dest_x,
387                    int32_t                      dest_y,
388                    int32_t                      width,
389                    int32_t                      height)
390 {
391     pixman_bool_t srcRepeat = src->type == BITS && src->common.repeat == PIXMAN_REPEAT_NORMAL;
392     pixman_bool_t maskRepeat = FALSE;
393     pixman_bool_t srcTransform = src->common.transform != NULL;
394     pixman_bool_t maskTransform = FALSE;
395     pixman_composite_func_t func = NULL;
396
397 #ifdef USE_MMX
398     fbComposeSetupMMX();
399 #endif
400
401 #ifdef USE_VMX
402     fbComposeSetupVMX();
403 #endif
404
405 #ifdef USE_SSE2
406     fbComposeSetupSSE2();
407 #endif
408
409     if (srcRepeat && srcTransform &&
410         src->bits.width == 1 &&
411         src->bits.height == 1)
412     {
413         srcTransform = FALSE;
414     }
415
416     if (mask && mask->type == BITS)
417     {
418         maskRepeat = mask->common.repeat == PIXMAN_REPEAT_NORMAL;
419
420         maskTransform = mask->common.transform != 0;
421         if (mask->common.filter == PIXMAN_FILTER_CONVOLUTION)
422             maskTransform = TRUE;
423
424         if (maskRepeat && maskTransform &&
425             mask->bits.width == 1 &&
426             mask->bits.height == 1)
427         {
428             maskTransform = FALSE;
429         }
430     }
431     
432 #ifdef USE_SSE2
433     if (!func)
434         func = _pixman_lookup_fast_path (sse2_fast_paths, op, src, mask, dest, src_x, src_y, mask_x, mask_y);
435 #endif
436
437 #ifdef USE_MMX
438     if (!func)
439         func = _pixman_lookup_fast_path (mmx_fast_paths, op, src, mask, dest, src_x, src_y, mask_x, mask_y);
440 #endif
441
442 #ifdef USE_VMX
443     if (!func)
444         func = _pixman_lookup_fast_path (vmx_fast_paths, op, src, mask, dest, src_x, src_y, mask_x, mask_y);
445 #endif
446
447 #ifdef USE_ARM_NEON
448     if (!func && pixman_have_arm_neon())
449         func = _pixman_lookup_fast_path (arm_neon_fast_paths, op, src, mask, dest, src_x, src_y, mask_x, mask_y);
450 #endif
451
452 #ifdef USE_ARM_SIMD
453     if (!func && pixman_have_arm_simd())
454         func = _pixman_lookup_fast_path (arm_neon_fast_paths, op, src, mask, dest, src_x, src_y, mask_x, mask_y);
455 #endif
456
457     if (!func)
458         func = _pixman_lookup_fast_path (c_fast_paths, op, src, mask, dest, src_x, src_y, mask_x, mask_y);
459
460     if (!func)
461     {
462         func = pixman_image_composite_rect;
463
464         /* CompositeGeneral optimizes 1x1 repeating images itself */
465         if (src->type == BITS &&
466             src->bits.width == 1 && src->bits.height == 1)
467         {
468             srcRepeat = FALSE;
469         }
470
471         if (mask && mask->type == BITS &&
472             mask->bits.width == 1 && mask->bits.height == 1)
473         {
474             maskRepeat = FALSE;
475         }
476
477         /* if we are transforming, repeats are handled in fbFetchTransformed */
478         if (srcTransform)
479             srcRepeat = FALSE;
480
481         if (maskTransform)
482             maskRepeat = FALSE;
483     }
484
485     _pixman_walk_composite_region (imp, op, src, mask, dest, src_x, src_y,
486                                   mask_x, mask_y, dest_x, dest_y, width, height,
487                                   srcRepeat, maskRepeat, func);
488 }
489
490 pixman_implementation_t *
491 _pixman_implementation_create_general (pixman_implementation_t *toplevel)
492 {
493     pixman_implementation_t *imp = _pixman_implementation_create (toplevel, NULL);
494     int i;
495
496     imp->composite = general_composite;
497     
498     for (i = 0; i < PIXMAN_OP_LAST; ++i)
499     {
500         imp->combine_32[i] = general_combine_32;
501         imp->combine_32_ca[i] = general_combine_32_ca;
502         imp->combine_64[i] = general_combine_64;
503         imp->combine_64_ca[i] = general_combine_64_ca;
504     }
505
506     return imp;
507 }