Set up combiner functions for an implementation directly in combine.inc.
[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  * Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc.
6  *             2005 Lars Knoll & Zack Rusin, Trolltech
7  *             2008 Aaron Plattner, NVIDIA Corporation
8  *
9  * Permission to use, copy, modify, distribute, and sell this software and its
10  * documentation for any purpose is hereby granted without fee, provided that
11  * the above copyright notice appear in all copies and that both that
12  * copyright notice and this permission notice appear in supporting
13  * documentation, and that the name of Red Hat not be used in advertising or
14  * publicity pertaining to distribution of the software without specific,
15  * written prior permission.  Red Hat makes no representations about the
16  * suitability of this software for any purpose.  It is provided "as is"
17  * without express or implied warranty.
18  *
19  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
20  * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
21  * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
22  * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
23  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
24  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
25  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
26  * SOFTWARE.
27  */
28 #include <config.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <math.h>
32 #include <assert.h>
33 #include <limits.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include "pixman-private.h"
38 #include "pixman-vmx.h"
39 #include "pixman-arm-simd.h"
40 #include "pixman-combine32.h"
41 #include "pixman-private.h"
42
43 #define SCANLINE_BUFFER_LENGTH 8192
44
45 static void
46 general_composite_rect  (pixman_implementation_t *imp,
47                          pixman_op_t              op,
48                          pixman_image_t          *src,
49                          pixman_image_t          *mask,
50                          pixman_image_t          *dest,
51                          int32_t                  src_x,
52                          int32_t                  src_y,
53                          int32_t                  mask_x,
54                          int32_t                  mask_y,
55                          int32_t                  dest_x,
56                          int32_t                  dest_y,
57                          int32_t                  width,
58                          int32_t                  height)
59 {
60     return_if_fail (src != NULL);
61     return_if_fail (dest != NULL);
62     
63     uint8_t stack_scanline_buffer[SCANLINE_BUFFER_LENGTH * 3];
64     const pixman_format_code_t srcFormat = src->type == BITS ? src->bits.format : 0;
65     const pixman_format_code_t maskFormat = mask && mask->type == BITS ? mask->bits.format : 0;
66     const pixman_format_code_t destFormat = dest->type == BITS ? dest->bits.format : 0;
67     const int srcWide = PIXMAN_FORMAT_16BPC(srcFormat);
68     const int maskWide = mask && PIXMAN_FORMAT_16BPC(maskFormat);
69     const int destWide = PIXMAN_FORMAT_16BPC(destFormat);
70     const int wide = srcWide || maskWide || destWide;
71     const int Bpp = wide ? 8 : 4;
72     uint8_t *scanline_buffer = stack_scanline_buffer;
73     uint8_t *src_buffer, *mask_buffer, *dest_buffer;
74     scanFetchProc fetchSrc = NULL, fetchMask = NULL, fetchDest = NULL;
75     pixman_combine_32_func_t compose;
76     scanStoreProc store;
77     source_pict_class_t srcClass, maskClass;
78     pixman_bool_t component_alpha;
79     uint32_t *bits;
80     int32_t stride;
81     int i;
82     
83     if (width * Bpp > SCANLINE_BUFFER_LENGTH)
84     {
85         scanline_buffer = pixman_malloc_abc (width, 3, Bpp);
86         
87         if (!scanline_buffer)
88             return;
89     }
90     
91     src_buffer = scanline_buffer;
92     mask_buffer = src_buffer + width * Bpp;
93     dest_buffer = mask_buffer + width * Bpp;
94     
95     srcClass = _pixman_image_classify (src,
96                                        src_x, src_y,
97                                        width, height);
98     
99     maskClass = SOURCE_IMAGE_CLASS_UNKNOWN;
100     if (mask)
101     {
102         maskClass = _pixman_image_classify (mask,
103                                             src_x, src_y,
104                                             width, height);
105     }
106     
107     if (op == PIXMAN_OP_CLEAR)
108         fetchSrc = NULL;
109     else if (wide)
110         fetchSrc = _pixman_image_get_scanline_64;
111     else
112         fetchSrc = _pixman_image_get_scanline_32;
113     
114     if (!mask || op == PIXMAN_OP_CLEAR)
115         fetchMask = NULL;
116     else if (wide)
117         fetchMask = _pixman_image_get_scanline_64;
118     else
119         fetchMask = _pixman_image_get_scanline_32;
120     
121     if (op == PIXMAN_OP_CLEAR || op == PIXMAN_OP_SRC)
122         fetchDest = NULL;
123     else if (wide)
124         fetchDest = _pixman_image_get_scanline_64;
125     else
126         fetchDest = _pixman_image_get_scanline_32;
127
128     if (wide)
129         store = _pixman_image_store_scanline_64;
130     else
131         store = _pixman_image_store_scanline_32;
132
133     /* Skip the store step and composite directly into the
134      * destination if the output format of the compose func matches
135      * the destination format.
136      */
137     if (!wide &&
138         !dest->common.alpha_map &&
139         !dest->common.write_func && 
140         (op == PIXMAN_OP_ADD || op == PIXMAN_OP_OVER) &&
141         (dest->bits.format == PIXMAN_a8r8g8b8 ||
142          dest->bits.format == PIXMAN_x8r8g8b8))
143     {
144         store = NULL;
145     }
146     
147     if (!store)
148     {
149         bits = dest->bits.bits;
150         stride = dest->bits.rowstride;
151     }
152     else
153     {
154         bits = NULL;
155         stride = 0;
156     }
157     
158     component_alpha =
159         fetchSrc                        &&
160         fetchMask                       &&
161         mask                            &&
162         mask->common.type == BITS       &&
163         mask->common.component_alpha    &&
164         PIXMAN_FORMAT_RGB (mask->bits.format);
165     
166     if (wide)
167     {
168         if (component_alpha)
169             compose = (pixman_combine_32_func_t)_pixman_implementation_combine_64_ca;
170         else
171             compose = (pixman_combine_32_func_t)_pixman_implementation_combine_64;
172     }
173     else
174     {
175         if (component_alpha)
176             compose = _pixman_implementation_combine_32_ca;
177         else
178             compose = _pixman_implementation_combine_32;
179     }
180     
181     if (!compose)
182         return;
183     
184     if (!fetchMask)
185         mask_buffer = NULL;
186     
187     for (i = 0; i < height; ++i)
188     {
189         /* fill first half of scanline with source */
190         if (fetchSrc)
191         {
192             if (fetchMask)
193             {
194                 /* fetch mask before source so that fetching of
195                    source can be optimized */
196                 fetchMask (mask, mask_x, mask_y + i,
197                            width, (void *)mask_buffer, 0, 0);
198                 
199                 if (maskClass == SOURCE_IMAGE_CLASS_HORIZONTAL)
200                     fetchMask = NULL;
201             }
202             
203             if (srcClass == SOURCE_IMAGE_CLASS_HORIZONTAL)
204             {
205                 fetchSrc (src, src_x, src_y + i,
206                           width, (void *)src_buffer, 0, 0);
207                 fetchSrc = NULL;
208             }
209             else
210             {
211                 fetchSrc (src, src_x, src_y + i,
212                           width, (void *)src_buffer, (void *)mask_buffer,
213                           0xffffffff);
214             }
215         }
216         else if (fetchMask)
217         {
218             fetchMask (mask, mask_x, mask_y + i,
219                        width, (void *)mask_buffer, 0, 0);
220         }
221         
222         if (store)
223         {
224             /* fill dest into second half of scanline */
225             if (fetchDest)
226                 fetchDest (dest, dest_x, dest_y + i,
227                            width, (void *)dest_buffer, 0, 0);
228             
229             /* blend */
230             compose (imp, op, (void *)dest_buffer, (void *)src_buffer, (void *)mask_buffer, width);
231             
232             /* write back */
233             store (&(dest->bits), dest_x, dest_y + i, width,
234                    (void *)dest_buffer);
235         }
236         else
237         {
238             /* blend */
239             compose (imp, op, bits + (dest_y + i) * stride +
240                      dest_x,
241                      (void *)src_buffer, (void *)mask_buffer, width);
242         }
243     }
244     
245     if (scanline_buffer != stack_scanline_buffer)
246         free (scanline_buffer);
247 }
248
249 static void
250 general_composite (pixman_implementation_t *    imp,
251                    pixman_op_t                  op,
252                    pixman_image_t *             src,
253                    pixman_image_t *             mask,
254                    pixman_image_t *             dest,
255                    int32_t                      src_x,
256                    int32_t                      src_y,
257                    int32_t                      mask_x,
258                    int32_t                      mask_y,
259                    int32_t                      dest_x,
260                    int32_t                      dest_y,
261                    int32_t                      width,
262                    int32_t                      height)
263 {
264     pixman_bool_t srcRepeat = src->type == BITS && src->common.repeat == PIXMAN_REPEAT_NORMAL;
265     pixman_bool_t maskRepeat = FALSE;
266     pixman_bool_t srcTransform = src->common.transform != NULL;
267     pixman_bool_t maskTransform = FALSE;
268     
269 #ifdef USE_VMX
270     fbComposeSetupVMX();
271 #endif
272     
273     if (srcRepeat && srcTransform &&
274         src->bits.width == 1 &&
275         src->bits.height == 1)
276     {
277         srcTransform = FALSE;
278     }
279     
280     if (mask && mask->type == BITS)
281     {
282         maskRepeat = mask->common.repeat == PIXMAN_REPEAT_NORMAL;
283         
284         maskTransform = mask->common.transform != 0;
285         if (mask->common.filter == PIXMAN_FILTER_CONVOLUTION)
286             maskTransform = TRUE;
287         
288         if (maskRepeat && maskTransform &&
289             mask->bits.width == 1 &&
290             mask->bits.height == 1)
291         {
292             maskTransform = FALSE;
293         }
294     }
295     
296 #ifdef USE_VMX
297     if (_pixman_run_fast_path (vmx_fast_paths, imp,
298                                op, src, mask, dest,
299                                src_x, src_y,
300                                mask_x, mask_y,
301                                dest_x, dest_y,
302                                width, height))
303         return;
304 #endif
305     
306 #ifdef USE_ARM_NEON
307     if (pixman_have_arm_neon() && _pixman_run_fast_path (arm_neon_fast_paths, imp,
308                                                          op, src, mask, dest,
309                                                          src_x, src_y,
310                                                          mask_x, mask_y,
311                                                          dest_x, dest_y,
312                                                          width, height))
313         return;
314 #endif
315     
316 #ifdef USE_ARM_SIMD
317     if (pixman_have_arm_simd() && _pixman_run_fast_path (arm_simd_fast_paths, imp,
318                                                          op, src, mask, dest,
319                                                          src_x, src_y,
320                                                          mask_x, mask_y,
321                                                          dest_x, dest_y,
322                                                          width, height))
323         return;
324 #endif
325     
326     /* CompositeGeneral optimizes 1x1 repeating images itself */
327     if (src->type == BITS &&
328         src->bits.width == 1 && src->bits.height == 1)
329     {
330         srcRepeat = FALSE;
331     }
332     
333     if (mask && mask->type == BITS &&
334         mask->bits.width == 1 && mask->bits.height == 1)
335     {
336         maskRepeat = FALSE;
337     }
338     
339     /* if we are transforming, repeats are handled in fbFetchTransformed */
340     if (srcTransform)
341         srcRepeat = FALSE;
342     
343     if (maskTransform)
344         maskRepeat = FALSE;
345     
346     _pixman_walk_composite_region (imp, op, src, mask, dest, src_x, src_y,
347                                    mask_x, mask_y, dest_x, dest_y, width, height,
348                                    srcRepeat, maskRepeat, general_composite_rect);
349 }
350
351 static pixman_bool_t
352 general_blt (pixman_implementation_t *imp,
353              uint32_t *src_bits,
354              uint32_t *dst_bits,
355              int src_stride,
356              int dst_stride,
357              int src_bpp,
358              int dst_bpp,
359              int src_x, int src_y,
360              int dst_x, int dst_y,
361              int width, int height)
362 {
363     /* We can't blit unless we have sse2 or mmx */
364     
365     return FALSE;
366 }
367
368 static pixman_bool_t
369 general_fill (pixman_implementation_t *imp,
370               uint32_t *bits,
371               int stride,
372               int bpp,
373               int x,
374               int y,
375               int width,
376               int height,
377               uint32_t xor)
378 {
379     return FALSE;
380 }
381
382 pixman_implementation_t *
383 _pixman_implementation_create_general (pixman_implementation_t *toplevel)
384 {
385     pixman_implementation_t *imp = _pixman_implementation_create (toplevel, NULL);
386
387     _pixman_setup_combiner_functions_32 (imp);
388     _pixman_setup_combiner_functions_64 (imp);
389     
390     imp->composite = general_composite;
391     imp->blt = general_blt;
392     imp->fill = general_fill;
393     
394     return imp;
395 }