pixman-general.c revision 952204ab
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 the destination format is a8r8g8b8 then we can always do
138     * this. If it is x8r8g8b8, then we can only do it if the
139     * operator doesn't make use of destination alpha.
140     */
141    if ((dest->bits.format == PIXMAN_a8r8g8b8)	||
142	(dest->bits.format == PIXMAN_x8r8g8b8	&&
143	 (op == PIXMAN_OP_OVER		||
144	  op == PIXMAN_OP_ADD		||
145	  op == PIXMAN_OP_SRC		||
146	  op == PIXMAN_OP_CLEAR		||
147	  op == PIXMAN_OP_IN_REVERSE	||
148	  op == PIXMAN_OP_OUT_REVERSE	||
149	  op == PIXMAN_OP_DST)))
150    {
151	if (!wide &&
152	    !dest->common.alpha_map &&
153	    !dest->bits.write_func)
154	{
155	    store = NULL;
156	}
157    }
158
159    if (!store)
160    {
161	bits = dest->bits.bits;
162	stride = dest->bits.rowstride;
163    }
164    else
165    {
166	bits = NULL;
167	stride = 0;
168    }
169
170    component_alpha =
171        fetch_src                       &&
172        fetch_mask                      &&
173        mask                            &&
174        mask->common.type == BITS       &&
175        mask->common.component_alpha    &&
176        PIXMAN_FORMAT_RGB (mask->bits.format);
177
178    if (wide)
179    {
180	if (component_alpha)
181	    compose = (pixman_combine_32_func_t)_pixman_implementation_combine_64_ca;
182	else
183	    compose = (pixman_combine_32_func_t)_pixman_implementation_combine_64;
184    }
185    else
186    {
187	if (component_alpha)
188	    compose = _pixman_implementation_combine_32_ca;
189	else
190	    compose = _pixman_implementation_combine_32;
191    }
192
193    if (!compose)
194	return;
195
196    if (!fetch_mask)
197	mask_buffer = NULL;
198
199    for (i = 0; i < height; ++i)
200    {
201	/* fill first half of scanline with source */
202	if (fetch_src)
203	{
204	    if (fetch_mask)
205	    {
206		/* fetch mask before source so that fetching of
207		   source can be optimized */
208		fetch_mask (mask, mask_x, mask_y + i,
209		            width, (void *)mask_buffer, 0, 0);
210
211		if (mask_class == SOURCE_IMAGE_CLASS_HORIZONTAL)
212		    fetch_mask = NULL;
213	    }
214
215	    if (src_class == SOURCE_IMAGE_CLASS_HORIZONTAL)
216	    {
217		fetch_src (src, src_x, src_y + i,
218		           width, (void *)src_buffer, 0, 0);
219		fetch_src = NULL;
220	    }
221	    else
222	    {
223		fetch_src (src, src_x, src_y + i,
224		           width, (void *)src_buffer, (void *)mask_buffer,
225		           0xffffffff);
226	    }
227	}
228	else if (fetch_mask)
229	{
230	    fetch_mask (mask, mask_x, mask_y + i,
231	                width, (void *)mask_buffer, 0, 0);
232	}
233
234	if (store)
235	{
236	    /* fill dest into second half of scanline */
237	    if (fetch_dest)
238	    {
239		fetch_dest (dest, dest_x, dest_y + i,
240		            width, (void *)dest_buffer, 0, 0);
241	    }
242
243	    /* blend */
244	    compose (imp->toplevel, op,
245		     (void *)dest_buffer,
246		     (void *)src_buffer,
247		     (void *)mask_buffer,
248		     width);
249
250	    /* write back */
251	    store (&(dest->bits), dest_x, dest_y + i, width,
252	           (void *)dest_buffer);
253	}
254	else
255	{
256	    /* blend */
257	    compose (imp->toplevel, op,
258		     bits + (dest_y + i) * stride + dest_x,
259	             (void *)src_buffer, (void *)mask_buffer, width);
260	}
261    }
262
263    if (scanline_buffer != stack_scanline_buffer)
264	free (scanline_buffer);
265}
266
267static const pixman_fast_path_t general_fast_path[] =
268{
269    { PIXMAN_OP_any, PIXMAN_any, 0, PIXMAN_any,	0, PIXMAN_any, 0, general_composite_rect },
270    { PIXMAN_OP_NONE }
271};
272
273static pixman_bool_t
274general_blt (pixman_implementation_t *imp,
275             uint32_t *               src_bits,
276             uint32_t *               dst_bits,
277             int                      src_stride,
278             int                      dst_stride,
279             int                      src_bpp,
280             int                      dst_bpp,
281             int                      src_x,
282             int                      src_y,
283             int                      dst_x,
284             int                      dst_y,
285             int                      width,
286             int                      height)
287{
288    /* We can't blit unless we have sse2 or mmx */
289
290    return FALSE;
291}
292
293static pixman_bool_t
294general_fill (pixman_implementation_t *imp,
295              uint32_t *               bits,
296              int                      stride,
297              int                      bpp,
298              int                      x,
299              int                      y,
300              int                      width,
301              int                      height,
302              uint32_t xor)
303{
304    return FALSE;
305}
306
307pixman_implementation_t *
308_pixman_implementation_create_general (void)
309{
310    pixman_implementation_t *imp = _pixman_implementation_create (NULL, general_fast_path);
311
312    _pixman_setup_combiner_functions_32 (imp);
313    _pixman_setup_combiner_functions_64 (imp);
314
315    imp->blt = general_blt;
316    imp->fill = general_fill;
317
318    return imp;
319}
320
321