pixman-general.c revision dc259aab
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 <limits.h>
33#include <stdio.h>
34#include <stdlib.h>
35#include <string.h>
36#include "pixman-private.h"
37#include "pixman-combine32.h"
38#include "pixman-private.h"
39
40#define SCANLINE_BUFFER_LENGTH 8192
41
42static void
43general_composite_rect  (pixman_implementation_t *imp,
44			 pixman_op_t              op,
45			 pixman_image_t          *src,
46			 pixman_image_t          *mask,
47			 pixman_image_t          *dest,
48			 int32_t                  src_x,
49			 int32_t                  src_y,
50			 int32_t                  mask_x,
51			 int32_t                  mask_y,
52			 int32_t                  dest_x,
53			 int32_t                  dest_y,
54			 int32_t                  width,
55			 int32_t                  height)
56{
57    uint8_t stack_scanline_buffer[SCANLINE_BUFFER_LENGTH * 3];
58    const pixman_format_code_t srcFormat = src->type == BITS ? src->bits.format : 0;
59    const pixman_format_code_t maskFormat = mask && mask->type == BITS ? mask->bits.format : 0;
60    const pixman_format_code_t destFormat = dest->type == BITS ? dest->bits.format : 0;
61    const int srcWide = PIXMAN_FORMAT_IS_WIDE(srcFormat);
62    const int maskWide = mask && PIXMAN_FORMAT_IS_WIDE(maskFormat);
63    const int destWide = PIXMAN_FORMAT_IS_WIDE(destFormat);
64    const int wide = srcWide || maskWide || destWide;
65    const int Bpp = wide ? 8 : 4;
66    uint8_t *scanline_buffer = stack_scanline_buffer;
67    uint8_t *src_buffer, *mask_buffer, *dest_buffer;
68    fetch_scanline_t fetchSrc = NULL, fetchMask = NULL, fetchDest = NULL;
69    pixman_combine_32_func_t compose;
70    store_scanline_t store;
71    source_pict_class_t srcClass, maskClass;
72    pixman_bool_t component_alpha;
73    uint32_t *bits;
74    int32_t stride;
75    int i;
76
77    if (width * Bpp > SCANLINE_BUFFER_LENGTH)
78    {
79	scanline_buffer = pixman_malloc_abc (width, 3, Bpp);
80
81	if (!scanline_buffer)
82	    return;
83    }
84
85    src_buffer = scanline_buffer;
86    mask_buffer = src_buffer + width * Bpp;
87    dest_buffer = mask_buffer + width * Bpp;
88
89    srcClass = _pixman_image_classify (src,
90				       src_x, src_y,
91				       width, height);
92
93    maskClass = SOURCE_IMAGE_CLASS_UNKNOWN;
94    if (mask)
95    {
96	maskClass = _pixman_image_classify (mask,
97					    src_x, src_y,
98					    width, height);
99    }
100
101    if (op == PIXMAN_OP_CLEAR)
102        fetchSrc = NULL;
103    else if (wide)
104	fetchSrc = _pixman_image_get_scanline_64;
105    else
106	fetchSrc = _pixman_image_get_scanline_32;
107
108    if (!mask || op == PIXMAN_OP_CLEAR)
109	fetchMask = NULL;
110    else if (wide)
111	fetchMask = _pixman_image_get_scanline_64;
112    else
113	fetchMask = _pixman_image_get_scanline_32;
114
115    if (op == PIXMAN_OP_CLEAR || op == PIXMAN_OP_SRC)
116	fetchDest = NULL;
117    else if (wide)
118	fetchDest = _pixman_image_get_scanline_64;
119    else
120	fetchDest = _pixman_image_get_scanline_32;
121
122    if (wide)
123	store = _pixman_image_store_scanline_64;
124    else
125	store = _pixman_image_store_scanline_32;
126
127    /* Skip the store step and composite directly into the
128     * destination if the output format of the compose func matches
129     * the destination format.
130     */
131    if (!wide &&
132	!dest->common.alpha_map &&
133	!dest->common.write_func &&
134	(op == PIXMAN_OP_ADD || op == PIXMAN_OP_OVER) &&
135	(dest->bits.format == PIXMAN_a8r8g8b8 ||
136	 dest->bits.format == PIXMAN_x8r8g8b8))
137    {
138	store = NULL;
139    }
140
141    if (!store)
142    {
143	bits = dest->bits.bits;
144	stride = dest->bits.rowstride;
145    }
146    else
147    {
148	bits = NULL;
149	stride = 0;
150    }
151
152    component_alpha =
153	fetchSrc			&&
154	fetchMask			&&
155	mask				&&
156	mask->common.type == BITS	&&
157	mask->common.component_alpha	&&
158	PIXMAN_FORMAT_RGB (mask->bits.format);
159
160    if (wide)
161    {
162	if (component_alpha)
163	    compose = (pixman_combine_32_func_t)_pixman_implementation_combine_64_ca;
164	else
165	    compose = (pixman_combine_32_func_t)_pixman_implementation_combine_64;
166    }
167    else
168    {
169	if (component_alpha)
170	    compose = _pixman_implementation_combine_32_ca;
171	else
172	    compose = _pixman_implementation_combine_32;
173    }
174
175    if (!compose)
176	return;
177
178    if (!fetchMask)
179	mask_buffer = NULL;
180
181    for (i = 0; i < height; ++i)
182    {
183	/* fill first half of scanline with source */
184	if (fetchSrc)
185	{
186	    if (fetchMask)
187	    {
188		/* fetch mask before source so that fetching of
189		   source can be optimized */
190		fetchMask (mask, mask_x, mask_y + i,
191			   width, (void *)mask_buffer, 0, 0);
192
193		if (maskClass == SOURCE_IMAGE_CLASS_HORIZONTAL)
194		    fetchMask = NULL;
195	    }
196
197	    if (srcClass == SOURCE_IMAGE_CLASS_HORIZONTAL)
198	    {
199		fetchSrc (src, src_x, src_y + i,
200			  width, (void *)src_buffer, 0, 0);
201		fetchSrc = NULL;
202	    }
203	    else
204	    {
205		fetchSrc (src, src_x, src_y + i,
206			  width, (void *)src_buffer, (void *)mask_buffer,
207			  0xffffffff);
208	    }
209	}
210	else if (fetchMask)
211	{
212	    fetchMask (mask, mask_x, mask_y + i,
213		       width, (void *)mask_buffer, 0, 0);
214	}
215
216	if (store)
217	{
218	    /* fill dest into second half of scanline */
219	    if (fetchDest)
220		fetchDest (dest, dest_x, dest_y + i,
221			   width, (void *)dest_buffer, 0, 0);
222
223	    /* blend */
224	    compose (imp->toplevel, op, (void *)dest_buffer, (void *)src_buffer, (void *)mask_buffer, width);
225
226	    /* write back */
227	    store (&(dest->bits), dest_x, dest_y + i, width,
228		   (void *)dest_buffer);
229	}
230	else
231	{
232	    /* blend */
233	    compose (imp->toplevel, op, bits + (dest_y + i) * stride +
234		     dest_x,
235		     (void *)src_buffer, (void *)mask_buffer, width);
236	}
237    }
238
239    if (scanline_buffer != stack_scanline_buffer)
240	free (scanline_buffer);
241}
242
243static void
244general_composite (pixman_implementation_t *	imp,
245		   pixman_op_t			op,
246		   pixman_image_t *		src,
247		   pixman_image_t *		mask,
248		   pixman_image_t *		dest,
249		   int32_t			src_x,
250		   int32_t			src_y,
251		   int32_t			mask_x,
252		   int32_t			mask_y,
253		   int32_t			dest_x,
254		   int32_t			dest_y,
255		   int32_t			width,
256		   int32_t			height)
257{
258    _pixman_walk_composite_region (imp, op, src, mask, dest, src_x, src_y,
259				   mask_x, mask_y, dest_x, dest_y, width, height,
260				   general_composite_rect);
261}
262
263static pixman_bool_t
264general_blt (pixman_implementation_t *imp,
265	     uint32_t *src_bits,
266	     uint32_t *dst_bits,
267	     int src_stride,
268	     int dst_stride,
269	     int src_bpp,
270	     int dst_bpp,
271	     int src_x, int src_y,
272	     int dst_x, int dst_y,
273	     int width, int height)
274{
275    /* We can't blit unless we have sse2 or mmx */
276
277    return FALSE;
278}
279
280static pixman_bool_t
281general_fill (pixman_implementation_t *imp,
282	      uint32_t *bits,
283	      int stride,
284	      int bpp,
285	      int x,
286	      int y,
287	      int width,
288	      int height,
289	      uint32_t xor)
290{
291    return FALSE;
292}
293
294pixman_implementation_t *
295_pixman_implementation_create_general (void)
296{
297    pixman_implementation_t *imp = _pixman_implementation_create (NULL);
298
299    _pixman_setup_combiner_functions_32 (imp);
300    _pixman_setup_combiner_functions_64 (imp);
301
302    imp->composite = general_composite;
303    imp->blt = general_blt;
304    imp->fill = general_fill;
305
306    return imp;
307}
308