Move store logic into pixman-image.c
[profile/ivi/pixman.git] / pixman / pixman-compose.c
1 /*
2  *
3  * Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc.
4  *             2005 Lars Knoll & Zack Rusin, Trolltech
5  *             2008 Aaron Plattner, NVIDIA Corporation
6  *
7  * Permission to use, copy, modify, distribute, and sell this software and its
8  * documentation for any purpose is hereby granted without fee, provided that
9  * the above copyright notice appear in all copies and that both that
10  * copyright notice and this permission notice appear in supporting
11  * documentation, and that the name of Keith Packard not be used in
12  * advertising or publicity pertaining to distribution of the software without
13  * specific, written prior permission.  Keith Packard makes no
14  * representations about the suitability of this software for any purpose.  It
15  * is provided "as is" without express or implied warranty.
16  *
17  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
18  * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
19  * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
20  * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
21  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
22  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
23  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
24  * SOFTWARE.
25  */
26
27 #ifdef HAVE_CONFIG_H
28 #include <config.h>
29 #endif
30
31 #include <stdlib.h>
32 #include <string.h>
33 #include <math.h>
34 #include <assert.h>
35 #include <limits.h>
36
37 #include "pixman-private.h"
38
39 #ifdef PIXMAN_FB_ACCESSORS
40 #define PIXMAN_COMPOSITE_RECT_GENERAL pixman_composite_rect_general_accessors
41 #else
42 #define PIXMAN_COMPOSITE_RECT_GENERAL pixman_composite_rect_general_no_accessors
43 #endif
44
45 #ifndef PIXMAN_FB_ACCESSORS
46 static
47 #endif
48 void
49 PIXMAN_COMPOSITE_RECT_GENERAL (const FbComposeData *data,
50                                void *src_buffer, void *mask_buffer, 
51                                void *dest_buffer, const int wide)
52 {
53     int i;
54     scanStoreProc store;
55     scanFetchProc fetchSrc = NULL, fetchMask = NULL, fetchDest = NULL;
56     uint32_t *bits;
57     int32_t stride;
58     int xoff, yoff;
59     source_pict_class_t srcClass, maskClass;
60
61     srcClass = _pixman_image_classify (data->src,
62                                        data->xSrc, data->ySrc,
63                                        data->width, data->height);
64
65     maskClass = SOURCE_IMAGE_CLASS_UNKNOWN;
66     if (data->mask)
67     {
68         maskClass = _pixman_image_classify (data->mask,
69                                             data->xSrc, data->ySrc,
70                                             data->width, data->height);
71     }
72     
73     if (data->op == PIXMAN_OP_CLEAR)
74         fetchSrc = NULL;
75     else
76         fetchSrc = _pixman_image_get_fetcher (data->src, wide);
77
78     if (!data->mask || data->op == PIXMAN_OP_CLEAR)
79         fetchMask = NULL;
80     else
81         fetchMask = _pixman_image_get_fetcher (data->mask, wide);
82
83     if (data->op == PIXMAN_OP_CLEAR || data->op == PIXMAN_OP_SRC)
84         fetchDest = NULL;
85     else
86         fetchDest = _pixman_image_get_fetcher (data->dest, wide);
87
88     store = _pixman_image_get_storer (data->dest, wide);
89
90 #ifndef PIXMAN_FB_ACCESSORS
91     // Skip the store step and composite directly into the
92     // destination if the output format of the compose func matches
93     // the destination format.
94     if (!wide &&
95         !data->dest->common.alpha_map &&
96         (data->op == PIXMAN_OP_ADD || data->op == PIXMAN_OP_OVER) &&
97         (data->dest->bits.format == PIXMAN_a8r8g8b8 ||
98          data->dest->bits.format == PIXMAN_x8r8g8b8))
99     {
100         store = NULL;
101     }
102 #endif
103
104     if (!store)
105     {
106         bits = data->dest->bits.bits;
107         stride = data->dest->bits.rowstride;
108         xoff = yoff = 0;
109     }
110     else
111     {
112         bits = NULL;
113         stride = 0;
114         xoff = yoff = 0;
115     }
116
117     if (fetchSrc                   &&
118         fetchMask                  &&
119         data->mask                 &&
120         data->mask->common.type == BITS &&
121         data->mask->common.component_alpha &&
122         PIXMAN_FORMAT_RGB (data->mask->bits.format))
123     {
124         CombineFuncC32 compose =
125             wide ? (CombineFuncC32)pixman_composeFunctions64.combineC[data->op] :
126                    pixman_composeFunctions.combineC[data->op];
127         if (!compose)
128             return;
129
130         for (i = 0; i < data->height; ++i) {
131             /* fill first half of scanline with source */
132             if (fetchSrc)
133             {
134                 if (fetchMask)
135                 {
136                     /* fetch mask before source so that fetching of
137                        source can be optimized */
138                     fetchMask (data->mask, data->xMask, data->yMask + i,
139                                data->width, mask_buffer, 0, 0);
140
141                     if (maskClass == SOURCE_IMAGE_CLASS_HORIZONTAL)
142                         fetchMask = NULL;
143                 }
144
145                 if (srcClass == SOURCE_IMAGE_CLASS_HORIZONTAL)
146                 {
147                     fetchSrc (data->src, data->xSrc, data->ySrc + i,
148                               data->width, src_buffer, 0, 0);
149                     fetchSrc = NULL;
150                 }
151                 else
152                 {
153                     fetchSrc (data->src, data->xSrc, data->ySrc + i,
154                               data->width, src_buffer, mask_buffer,
155                               0xffffffff);
156                 }
157             }
158             else if (fetchMask)
159             {
160                 fetchMask (data->mask, data->xMask, data->yMask + i,
161                            data->width, mask_buffer, 0, 0);
162             }
163
164             if (store)
165             {
166                 /* fill dest into second half of scanline */
167                 if (fetchDest)
168                     fetchDest (data->dest, data->xDest, data->yDest + i,
169                                data->width, dest_buffer, 0, 0);
170
171                 /* blend */
172                 compose (dest_buffer, src_buffer, mask_buffer, data->width);
173
174                 /* write back */
175                 store (data->dest, data->xDest, data->yDest + i, data->width,
176                        dest_buffer);
177             }
178             else
179             {
180                 /* blend */
181                 compose (bits + (data->yDest + i+ yoff) * stride +
182                          data->xDest + xoff,
183                          src_buffer, mask_buffer, data->width);
184             }
185         }
186     }
187     else
188     {
189         void *src_mask_buffer = 0;
190         const int useMask = (fetchMask != NULL);
191         CombineFuncU32 compose =
192             wide ? (CombineFuncU32)pixman_composeFunctions64.combineU[data->op] :
193                    pixman_composeFunctions.combineU[data->op];
194         if (!compose)
195             return;
196
197         for (i = 0; i < data->height; ++i) {
198             /* fill first half of scanline with source */
199             if (fetchSrc)
200             {
201                 if (fetchMask)
202                 {
203                     /* fetch mask before source so that fetching of
204                        source can be optimized */
205                     fetchMask (data->mask, data->xMask, data->yMask + i,
206                                data->width, mask_buffer, 0, 0);
207
208                     if (maskClass == SOURCE_IMAGE_CLASS_HORIZONTAL)
209                         fetchMask = NULL;
210                 }
211
212                 if (srcClass == SOURCE_IMAGE_CLASS_HORIZONTAL)
213                 {
214                     fetchSrc (data->src, data->xSrc, data->ySrc + i,
215                               data->width, src_buffer, 0, 0);
216
217                     if (useMask)
218                     {
219                         if (wide)
220                             pixman_composeFunctions64.combineU[PIXMAN_OP_IN] (mask_buffer, src_buffer, data->width);
221                         else
222                             pixman_composeFunctions.combineU[PIXMAN_OP_IN] (mask_buffer, src_buffer, data->width);
223
224                         src_mask_buffer = mask_buffer;
225                     }
226                     else
227                         src_mask_buffer = src_buffer;
228
229                     fetchSrc = NULL;
230                 }
231                 else
232                 {
233                     fetchSrc (data->src, data->xSrc, data->ySrc + i,
234                               data->width, src_buffer,
235                               useMask ? mask_buffer : NULL, 0xff000000);
236
237                     if (useMask) {
238                         if (wide)
239                             pixman_composeFunctions64.combineMaskU (src_buffer,
240                                                                     mask_buffer,
241                                                                     data->width);
242                         else
243                             pixman_composeFunctions.combineMaskU (src_buffer,
244                                                                   mask_buffer,
245                                                                   data->width);
246                     }
247
248                     src_mask_buffer = src_buffer;
249                 }
250             }
251             else if (fetchMask)
252             {
253                 fetchMask (data->mask, data->xMask, data->yMask + i,
254                            data->width, mask_buffer, 0, 0);
255
256                 if (wide)
257                     pixman_composeFunctions64.combineU[PIXMAN_OP_IN] (mask_buffer, src_buffer, data->width);
258                 else
259                     pixman_composeFunctions.combineU[PIXMAN_OP_IN] (mask_buffer, src_buffer, data->width);
260
261                 src_mask_buffer = mask_buffer;
262             }
263
264             if (store)
265             {
266                 /* fill dest into second half of scanline */
267                 if (fetchDest)
268                     fetchDest (data->dest, data->xDest, data->yDest + i,
269                                data->width, dest_buffer, 0, 0);
270
271                 /* blend */
272                 compose (dest_buffer, src_mask_buffer, data->width);
273
274                 /* write back */
275                 store (data->dest, data->xDest, data->yDest + i, data->width,
276                        dest_buffer);
277             }
278             else
279             {
280                 /* blend */
281                 compose (bits + (data->yDest + i+ yoff) * stride +
282                          data->xDest + xoff,
283                          src_mask_buffer, data->width);
284             }
285         }
286     }
287 }
288
289 #ifndef PIXMAN_FB_ACCESSORS
290
291 #define SCANLINE_BUFFER_LENGTH 8192
292
293 void
294 pixman_composite_rect_general (const FbComposeData *data)
295 {
296     uint8_t stack_scanline_buffer[SCANLINE_BUFFER_LENGTH * 3];
297     const pixman_format_code_t srcFormat = data->src->type == BITS ? data->src->bits.format : 0;
298     const pixman_format_code_t maskFormat = data->mask && data->mask->type == BITS ? data->mask->bits.format : 0;
299     const pixman_format_code_t destFormat = data->dest->type == BITS ? data->dest->bits.format : 0;
300     const int srcWide = PIXMAN_FORMAT_16BPC(srcFormat);
301     const int maskWide = data->mask && PIXMAN_FORMAT_16BPC(maskFormat);
302     const int destWide = PIXMAN_FORMAT_16BPC(destFormat);
303     const int wide = srcWide || maskWide || destWide;
304     const int Bpp = wide ? 8 : 4;
305     uint8_t *scanline_buffer = stack_scanline_buffer;
306     uint8_t *src_buffer, *mask_buffer, *dest_buffer;
307
308     if (data->width * Bpp > SCANLINE_BUFFER_LENGTH)
309     {
310         scanline_buffer = pixman_malloc_abc (data->width, 3, Bpp);
311
312         if (!scanline_buffer)
313             return;
314     }
315
316     src_buffer = scanline_buffer;
317     mask_buffer = src_buffer + data->width * Bpp;
318     dest_buffer = mask_buffer + data->width * Bpp;
319
320     if (data->src->common.read_func                     ||
321         data->src->common.write_func                    ||
322         (data->mask && data->mask->common.read_func)    ||
323         (data->mask && data->mask->common.write_func)   ||
324         data->dest->common.read_func                    ||
325         data->dest->common.write_func)
326     {
327         pixman_composite_rect_general_accessors (data, src_buffer, mask_buffer,
328                                                  dest_buffer, wide);
329     }
330     else
331     {
332         pixman_composite_rect_general_no_accessors (data, src_buffer,
333                                                     mask_buffer, dest_buffer,
334                                                     wide);
335     }
336
337     if (scanline_buffer != stack_scanline_buffer)
338         free (scanline_buffer);
339 }
340
341 #endif