Consolidate the general implementation into one function
[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
44 static void
45 general_combine_32 (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.combineU[op];
50     
51     f (dest, src, mask, width);
52 }
53
54 static void
55 general_combine_32_ca (pixman_implementation_t *imp, pixman_op_t op,
56                        uint32_t *dest, const uint32_t *src, const uint32_t *mask,
57                        int width)
58 {
59     CombineFunc32 f = pixman_composeFunctions.combineC[op];
60     
61     f (dest, src, mask, width);
62 }
63
64 static void
65 general_combine_64 (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.combineU[op];
70     
71     f (dest, src, mask, width);
72 }
73
74 static void
75 general_combine_64_ca (pixman_implementation_t *imp, pixman_op_t op,
76                        uint64_t *dest, const uint64_t *src, const uint64_t *mask,
77                        int width)
78 {
79     CombineFunc64 f = pixman_composeFunctions64.combineC[op];
80     
81     f (dest, src, mask, width);
82 }
83
84 #define SCANLINE_BUFFER_LENGTH 8192
85
86 static void
87 general_composite_rect  (pixman_implementation_t *imp,
88                          pixman_op_t              op,
89                          pixman_image_t          *src,
90                          pixman_image_t          *mask,
91                          pixman_image_t          *dest,
92                          int32_t                  src_x,
93                          int32_t                  src_y,
94                          int32_t                  mask_x,
95                          int32_t                  mask_y,
96                          int32_t                  dest_x,
97                          int32_t                  dest_y,
98                          int32_t                  width,
99                          int32_t                  height)
100 {
101     return_if_fail (src != NULL);
102     return_if_fail (dest != NULL);
103     
104     uint8_t stack_scanline_buffer[SCANLINE_BUFFER_LENGTH * 3];
105     const pixman_format_code_t srcFormat = src->type == BITS ? src->bits.format : 0;
106     const pixman_format_code_t maskFormat = mask && mask->type == BITS ? mask->bits.format : 0;
107     const pixman_format_code_t destFormat = dest->type == BITS ? dest->bits.format : 0;
108     const int srcWide = PIXMAN_FORMAT_16BPC(srcFormat);
109     const int maskWide = mask && PIXMAN_FORMAT_16BPC(maskFormat);
110     const int destWide = PIXMAN_FORMAT_16BPC(destFormat);
111     const int wide = srcWide || maskWide || destWide;
112     const int Bpp = wide ? 8 : 4;
113     uint8_t *scanline_buffer = stack_scanline_buffer;
114     uint8_t *src_buffer, *mask_buffer, *dest_buffer;
115     scanFetchProc fetchSrc = NULL, fetchMask = NULL, fetchDest = NULL;
116     pixman_combine_32_func_t compose;
117     scanStoreProc store;
118     source_pict_class_t srcClass, maskClass;
119     pixman_bool_t component_alpha;
120     uint32_t *bits;
121     int32_t stride;
122     int i;
123     
124     if (width * Bpp > SCANLINE_BUFFER_LENGTH)
125     {
126         scanline_buffer = pixman_malloc_abc (width, 3, Bpp);
127         
128         if (!scanline_buffer)
129             return;
130     }
131     
132     src_buffer = scanline_buffer;
133     mask_buffer = src_buffer + width * Bpp;
134     dest_buffer = mask_buffer + width * Bpp;
135     
136     srcClass = _pixman_image_classify (src,
137                                        src_x, src_y,
138                                        width, height);
139     
140     maskClass = SOURCE_IMAGE_CLASS_UNKNOWN;
141     if (mask)
142     {
143         maskClass = _pixman_image_classify (mask,
144                                             src_x, src_y,
145                                             width, height);
146     }
147     
148     if (op == PIXMAN_OP_CLEAR)
149         fetchSrc = NULL;
150     else if (wide)
151         fetchSrc = _pixman_image_get_scanline_64;
152     else
153         fetchSrc = _pixman_image_get_scanline_32;
154     
155     if (!mask || op == PIXMAN_OP_CLEAR)
156         fetchMask = NULL;
157     else if (wide)
158         fetchMask = _pixman_image_get_scanline_64;
159     else
160         fetchMask = _pixman_image_get_scanline_32;
161     
162     if (op == PIXMAN_OP_CLEAR || op == PIXMAN_OP_SRC)
163         fetchDest = NULL;
164     else if (wide)
165         fetchDest = _pixman_image_get_scanline_64;
166     else
167         fetchDest = _pixman_image_get_scanline_32;
168
169     if (wide)
170         store = _pixman_image_store_scanline_64;
171     else
172         store = _pixman_image_store_scanline_32;
173
174     /* Skip the store step and composite directly into the
175      * destination if the output format of the compose func matches
176      * the destination format.
177      */
178     if (!wide &&
179         !dest->common.alpha_map &&
180         !dest->common.write_func && 
181         (op == PIXMAN_OP_ADD || op == PIXMAN_OP_OVER) &&
182         (dest->bits.format == PIXMAN_a8r8g8b8 ||
183          dest->bits.format == PIXMAN_x8r8g8b8))
184     {
185         store = NULL;
186     }
187     
188     if (!store)
189     {
190         bits = dest->bits.bits;
191         stride = dest->bits.rowstride;
192     }
193     else
194     {
195         bits = NULL;
196         stride = 0;
197     }
198     
199     component_alpha =
200         fetchSrc                   &&
201         fetchMask                  &&
202         mask               &&
203         mask->common.type == BITS &&
204         mask->common.component_alpha &&
205         PIXMAN_FORMAT_RGB (mask->bits.format);
206     
207     if (wide)
208     {
209         if (component_alpha)
210             compose = (pixman_combine_32_func_t)_pixman_implementation_combine_64_ca;
211         else
212             compose = (pixman_combine_32_func_t)_pixman_implementation_combine_64;
213     }
214     else
215     {
216         if (component_alpha)
217             compose = _pixman_implementation_combine_32_ca;
218         else
219             compose = _pixman_implementation_combine_32;
220     }
221     
222     if (!compose)
223         return;
224     
225     if (!fetchMask)
226         mask_buffer = NULL;
227     
228     for (i = 0; i < height; ++i)
229     {
230         /* fill first half of scanline with source */
231         if (fetchSrc)
232         {
233             if (fetchMask)
234             {
235                 /* fetch mask before source so that fetching of
236                    source can be optimized */
237                 fetchMask (mask, mask_x, mask_y + i,
238                            width, (void *)mask_buffer, 0, 0);
239                 
240                 if (maskClass == SOURCE_IMAGE_CLASS_HORIZONTAL)
241                     fetchMask = NULL;
242             }
243             
244             if (srcClass == SOURCE_IMAGE_CLASS_HORIZONTAL)
245             {
246                 fetchSrc (src, src_x, src_y + i,
247                           width, (void *)src_buffer, 0, 0);
248                 fetchSrc = NULL;
249             }
250             else
251             {
252                 fetchSrc (src, src_x, src_y + i,
253                           width, (void *)src_buffer, (void *)mask_buffer,
254                           0xffffffff);
255             }
256         }
257         else if (fetchMask)
258         {
259             fetchMask (mask, mask_x, mask_y + i,
260                        width, (void *)mask_buffer, 0, 0);
261         }
262         
263         if (store)
264         {
265             /* fill dest into second half of scanline */
266             if (fetchDest)
267                 fetchDest (dest, dest_x, dest_y + i,
268                            width, (void *)dest_buffer, 0, 0);
269             
270             /* blend */
271             compose (imp, op, (void *)dest_buffer, (void *)src_buffer, (void *)mask_buffer, width);
272             
273             /* write back */
274             store (&(dest->bits), dest_x, dest_y + i, width,
275                    (void *)dest_buffer);
276         }
277         else
278         {
279             /* blend */
280             compose (imp, op, bits + (dest_y + i) * stride +
281                      dest_x,
282                      (void *)src_buffer, (void *)mask_buffer, width);
283         }
284     }
285     
286     if (scanline_buffer != stack_scanline_buffer)
287         free (scanline_buffer);
288 }
289
290 static void
291 general_composite (pixman_implementation_t *    imp,
292                    pixman_op_t                  op,
293                    pixman_image_t *             src,
294                    pixman_image_t *             mask,
295                    pixman_image_t *             dest,
296                    int32_t                      src_x,
297                    int32_t                      src_y,
298                    int32_t                      mask_x,
299                    int32_t                      mask_y,
300                    int32_t                      dest_x,
301                    int32_t                      dest_y,
302                    int32_t                      width,
303                    int32_t                      height)
304 {
305     pixman_bool_t srcRepeat = src->type == BITS && src->common.repeat == PIXMAN_REPEAT_NORMAL;
306     pixman_bool_t maskRepeat = FALSE;
307     pixman_bool_t srcTransform = src->common.transform != NULL;
308     pixman_bool_t maskTransform = FALSE;
309     
310 #ifdef USE_VMX
311     fbComposeSetupVMX();
312 #endif
313     
314     if (srcRepeat && srcTransform &&
315         src->bits.width == 1 &&
316         src->bits.height == 1)
317     {
318         srcTransform = FALSE;
319     }
320     
321     if (mask && mask->type == BITS)
322     {
323         maskRepeat = mask->common.repeat == PIXMAN_REPEAT_NORMAL;
324         
325         maskTransform = mask->common.transform != 0;
326         if (mask->common.filter == PIXMAN_FILTER_CONVOLUTION)
327             maskTransform = TRUE;
328         
329         if (maskRepeat && maskTransform &&
330             mask->bits.width == 1 &&
331             mask->bits.height == 1)
332         {
333             maskTransform = FALSE;
334         }
335     }
336     
337 #ifdef USE_VMX
338     if (_pixman_run_fast_path (vmx_fast_paths, imp,
339                                op, src, mask, dest,
340                                src_x, src_y,
341                                mask_x, mask_y,
342                                dest_x, dest_y,
343                                width, height))
344         return;
345 #endif
346     
347 #ifdef USE_ARM_NEON
348     if (pixman_have_arm_neon() && _pixman_run_fast_path (arm_neon_fast_paths, imp,
349                                                          op, src, mask, dest,
350                                                          src_x, src_y,
351                                                          mask_x, mask_y,
352                                                          dest_x, dest_y,
353                                                          width, height))
354         return;
355 #endif
356     
357 #ifdef USE_ARM_SIMD
358     if (pixman_have_arm_simd() && _pixman_run_fast_path (arm_simd_fast_paths, imp,
359                                                          op, src, mask, dest,
360                                                          src_x, src_y,
361                                                          mask_x, mask_y,
362                                                          dest_x, dest_y,
363                                                          width, height))
364         return;
365 #endif
366     
367     /* CompositeGeneral optimizes 1x1 repeating images itself */
368     if (src->type == BITS &&
369         src->bits.width == 1 && src->bits.height == 1)
370     {
371         srcRepeat = FALSE;
372     }
373     
374     if (mask && mask->type == BITS &&
375         mask->bits.width == 1 && mask->bits.height == 1)
376     {
377         maskRepeat = FALSE;
378     }
379     
380     /* if we are transforming, repeats are handled in fbFetchTransformed */
381     if (srcTransform)
382         srcRepeat = FALSE;
383     
384     if (maskTransform)
385         maskRepeat = FALSE;
386     
387     _pixman_walk_composite_region (imp, op, src, mask, dest, src_x, src_y,
388                                    mask_x, mask_y, dest_x, dest_y, width, height,
389                                    srcRepeat, maskRepeat, general_composite_rect);
390 }
391
392 static pixman_bool_t
393 general_blt (pixman_implementation_t *imp,
394              uint32_t *src_bits,
395              uint32_t *dst_bits,
396              int src_stride,
397              int dst_stride,
398              int src_bpp,
399              int dst_bpp,
400              int src_x, int src_y,
401              int dst_x, int dst_y,
402              int width, int height)
403 {
404     /* We can't blit unless we have sse2 or mmx */
405     
406     return FALSE;
407 }
408
409 static pixman_bool_t
410 general_fill (pixman_implementation_t *imp,
411               uint32_t *bits,
412               int stride,
413               int bpp,
414               int x,
415               int y,
416               int width,
417               int height,
418               uint32_t xor)
419 {
420     return FALSE;
421 }
422
423 pixman_implementation_t *
424 _pixman_implementation_create_general (pixman_implementation_t *toplevel)
425 {
426     pixman_implementation_t *imp = _pixman_implementation_create (toplevel, NULL);
427     int i;
428     
429     for (i = 0; i < PIXMAN_OP_LAST; ++i)
430     {
431         imp->combine_32[i] = general_combine_32;
432         imp->combine_32_ca[i] = general_combine_32_ca;
433         imp->combine_64[i] = general_combine_64;
434         imp->combine_64_ca[i] = general_combine_64_ca;
435     }
436     imp->composite = general_composite;
437     imp->blt = general_blt;
438     imp->fill = general_fill;
439     
440     return imp;
441 }