pixman-general.c revision a450e446
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#ifdef HAVE_CONFIG_H
29#include <config.h>
30#endif
31#include <stdlib.h>
32#include <string.h>
33#include <math.h>
34#include <limits.h>
35#include <stdio.h>
36#include <stdlib.h>
37#include <string.h>
38#include "pixman-private.h"
39#include "pixman-combine32.h"
40#include "pixman-private.h"
41
42#define SCANLINE_BUFFER_LENGTH 8192
43
44static void
45general_composite_rect  (pixman_implementation_t *imp,
46                         pixman_op_t              op,
47                         pixman_image_t *         src,
48                         pixman_image_t *         mask,
49                         pixman_image_t *         dest,
50                         int32_t                  src_x,
51                         int32_t                  src_y,
52                         int32_t                  mask_x,
53                         int32_t                  mask_y,
54                         int32_t                  dest_x,
55                         int32_t                  dest_y,
56                         int32_t                  width,
57                         int32_t                  height)
58{
59    uint8_t stack_scanline_buffer[SCANLINE_BUFFER_LENGTH * 3];
60    const pixman_format_code_t src_format =
61	src->type == BITS ? src->bits.format : 0;
62    const pixman_format_code_t mask_format =
63	mask && mask->type == BITS ? mask->bits.format : 0;
64    const pixman_format_code_t dest_format =
65	dest->type == BITS ? dest->bits.format : 0;
66    const int src_wide = PIXMAN_FORMAT_IS_WIDE (src_format);
67    const int mask_wide = mask && PIXMAN_FORMAT_IS_WIDE (mask_format);
68    const int dest_wide = PIXMAN_FORMAT_IS_WIDE (dest_format);
69    const int wide = src_wide || mask_wide || dest_wide;
70    const int Bpp = wide ? 8 : 4;
71    uint8_t *scanline_buffer = stack_scanline_buffer;
72    uint8_t *src_buffer, *mask_buffer, *dest_buffer;
73    fetch_scanline_t fetch_src = NULL, fetch_mask = NULL, fetch_dest = NULL;
74    pixman_combine_32_func_t compose;
75    store_scanline_t store;
76    source_image_class_t src_class, mask_class;
77    pixman_bool_t component_alpha;
78    uint32_t *bits;
79    int32_t stride;
80    int i;
81
82    if (width * Bpp > SCANLINE_BUFFER_LENGTH)
83    {
84	scanline_buffer = pixman_malloc_abc (width, 3, Bpp);
85
86	if (!scanline_buffer)
87	    return;
88    }
89
90    src_buffer = scanline_buffer;
91    mask_buffer = src_buffer + width * Bpp;
92    dest_buffer = mask_buffer + width * Bpp;
93
94    src_class = _pixman_image_classify (src,
95                                        src_x, src_y,
96                                        width, height);
97
98    mask_class = SOURCE_IMAGE_CLASS_UNKNOWN;
99
100    if (mask)
101    {
102	mask_class = _pixman_image_classify (mask,
103	                                     src_x, src_y,
104	                                     width, height);
105    }
106
107    if (op == PIXMAN_OP_CLEAR)
108	fetch_src = NULL;
109    else if (wide)
110	fetch_src = _pixman_image_get_scanline_64;
111    else
112	fetch_src = _pixman_image_get_scanline_32;
113
114    if (!mask || op == PIXMAN_OP_CLEAR)
115	fetch_mask = NULL;
116    else if (wide)
117	fetch_mask = _pixman_image_get_scanline_64;
118    else
119	fetch_mask = _pixman_image_get_scanline_32;
120
121    if (op == PIXMAN_OP_CLEAR || op == PIXMAN_OP_SRC)
122	fetch_dest = NULL;
123    else if (wide)
124	fetch_dest = _pixman_image_get_scanline_64;
125    else
126	fetch_dest = _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->bits.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        fetch_src                       &&
160        fetch_mask                      &&
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 (!fetch_mask)
185	mask_buffer = NULL;
186
187    for (i = 0; i < height; ++i)
188    {
189	/* fill first half of scanline with source */
190	if (fetch_src)
191	{
192	    if (fetch_mask)
193	    {
194		/* fetch mask before source so that fetching of
195		   source can be optimized */
196		fetch_mask (mask, mask_x, mask_y + i,
197		            width, (void *)mask_buffer, 0, 0);
198
199		if (mask_class == SOURCE_IMAGE_CLASS_HORIZONTAL)
200		    fetch_mask = NULL;
201	    }
202
203	    if (src_class == SOURCE_IMAGE_CLASS_HORIZONTAL)
204	    {
205		fetch_src (src, src_x, src_y + i,
206		           width, (void *)src_buffer, 0, 0);
207		fetch_src = NULL;
208	    }
209	    else
210	    {
211		fetch_src (src, src_x, src_y + i,
212		           width, (void *)src_buffer, (void *)mask_buffer,
213		           0xffffffff);
214	    }
215	}
216	else if (fetch_mask)
217	{
218	    fetch_mask (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 (fetch_dest)
226	    {
227		fetch_dest (dest, dest_x, dest_y + i,
228		            width, (void *)dest_buffer, 0, 0);
229	    }
230
231	    /* blend */
232	    compose (imp->toplevel, op,
233		     (void *)dest_buffer,
234		     (void *)src_buffer,
235		     (void *)mask_buffer,
236		     width);
237
238	    /* write back */
239	    store (&(dest->bits), dest_x, dest_y + i, width,
240	           (void *)dest_buffer);
241	}
242	else
243	{
244	    /* blend */
245	    compose (imp->toplevel, op,
246		     bits + (dest_y + i) * stride + dest_x,
247	             (void *)src_buffer, (void *)mask_buffer, width);
248	}
249    }
250
251    if (scanline_buffer != stack_scanline_buffer)
252	free (scanline_buffer);
253}
254
255static void
256general_composite (pixman_implementation_t * imp,
257                   pixman_op_t               op,
258                   pixman_image_t *          src,
259                   pixman_image_t *          mask,
260                   pixman_image_t *          dest,
261                   int32_t                   src_x,
262                   int32_t                   src_y,
263                   int32_t                   mask_x,
264                   int32_t                   mask_y,
265                   int32_t                   dest_x,
266                   int32_t                   dest_y,
267                   int32_t                   width,
268                   int32_t                   height)
269{
270    _pixman_walk_composite_region (imp, op, src, mask, dest, src_x, src_y,
271                                   mask_x, mask_y, dest_x, dest_y,
272				   width, height,
273                                   general_composite_rect);
274}
275
276static pixman_bool_t
277general_blt (pixman_implementation_t *imp,
278             uint32_t *               src_bits,
279             uint32_t *               dst_bits,
280             int                      src_stride,
281             int                      dst_stride,
282             int                      src_bpp,
283             int                      dst_bpp,
284             int                      src_x,
285             int                      src_y,
286             int                      dst_x,
287             int                      dst_y,
288             int                      width,
289             int                      height)
290{
291    /* We can't blit unless we have sse2 or mmx */
292
293    return FALSE;
294}
295
296static pixman_bool_t
297general_fill (pixman_implementation_t *imp,
298              uint32_t *               bits,
299              int                      stride,
300              int                      bpp,
301              int                      x,
302              int                      y,
303              int                      width,
304              int                      height,
305              uint32_t xor)
306{
307    return FALSE;
308}
309
310pixman_implementation_t *
311_pixman_implementation_create_general (void)
312{
313    pixman_implementation_t *imp = _pixman_implementation_create (NULL);
314
315    _pixman_setup_combiner_functions_32 (imp);
316    _pixman_setup_combiner_functions_64 (imp);
317
318    imp->composite = general_composite;
319    imp->blt = general_blt;
320    imp->fill = general_fill;
321
322    return imp;
323}
324
325