|
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 |
|
40 static pixman_bool_t |
|
41 general_src_iter_init (pixman_implementation_t *imp, pixman_iter_t *iter) |
|
42 { |
|
43 pixman_image_t *image = iter->image; |
|
44 |
|
45 if (image->type == LINEAR) |
|
46 _pixman_linear_gradient_iter_init (image, iter); |
|
47 else if (image->type == RADIAL) |
|
48 _pixman_radial_gradient_iter_init (image, iter); |
|
49 else if (image->type == CONICAL) |
|
50 _pixman_conical_gradient_iter_init (image, iter); |
|
51 else if (image->type == BITS) |
|
52 _pixman_bits_image_src_iter_init (image, iter); |
|
53 else if (image->type == SOLID) |
|
54 _pixman_log_error (FUNC, "Solid image not handled by noop"); |
|
55 else |
|
56 _pixman_log_error (FUNC, "Pixman bug: unknown image type\n"); |
|
57 |
|
58 return TRUE; |
|
59 } |
|
60 |
|
61 static pixman_bool_t |
|
62 general_dest_iter_init (pixman_implementation_t *imp, pixman_iter_t *iter) |
|
63 { |
|
64 if (iter->image->type == BITS) |
|
65 { |
|
66 _pixman_bits_image_dest_iter_init (iter->image, iter); |
|
67 |
|
68 return TRUE; |
|
69 } |
|
70 else |
|
71 { |
|
72 _pixman_log_error (FUNC, "Trying to write to a non-writable image"); |
|
73 |
|
74 return FALSE; |
|
75 } |
|
76 } |
|
77 |
|
78 typedef struct op_info_t op_info_t; |
|
79 struct op_info_t |
|
80 { |
|
81 uint8_t src, dst; |
|
82 }; |
|
83 |
|
84 #define ITER_IGNORE_BOTH \ |
|
85 (ITER_IGNORE_ALPHA | ITER_IGNORE_RGB | ITER_LOCALIZED_ALPHA) |
|
86 |
|
87 static const op_info_t op_flags[PIXMAN_N_OPERATORS] = |
|
88 { |
|
89 /* Src Dst */ |
|
90 { ITER_IGNORE_BOTH, ITER_IGNORE_BOTH }, /* CLEAR */ |
|
91 { ITER_LOCALIZED_ALPHA, ITER_IGNORE_BOTH }, /* SRC */ |
|
92 { ITER_IGNORE_BOTH, ITER_LOCALIZED_ALPHA }, /* DST */ |
|
93 { 0, ITER_LOCALIZED_ALPHA }, /* OVER */ |
|
94 { ITER_LOCALIZED_ALPHA, 0 }, /* OVER_REVERSE */ |
|
95 { ITER_LOCALIZED_ALPHA, ITER_IGNORE_RGB }, /* IN */ |
|
96 { ITER_IGNORE_RGB, ITER_LOCALIZED_ALPHA }, /* IN_REVERSE */ |
|
97 { ITER_LOCALIZED_ALPHA, ITER_IGNORE_RGB }, /* OUT */ |
|
98 { ITER_IGNORE_RGB, ITER_LOCALIZED_ALPHA }, /* OUT_REVERSE */ |
|
99 { 0, 0 }, /* ATOP */ |
|
100 { 0, 0 }, /* ATOP_REVERSE */ |
|
101 { 0, 0 }, /* XOR */ |
|
102 { ITER_LOCALIZED_ALPHA, ITER_LOCALIZED_ALPHA }, /* ADD */ |
|
103 { 0, 0 }, /* SATURATE */ |
|
104 }; |
|
105 |
|
106 #define SCANLINE_BUFFER_LENGTH 8192 |
|
107 |
|
108 static void |
|
109 general_composite_rect (pixman_implementation_t *imp, |
|
110 pixman_composite_info_t *info) |
|
111 { |
|
112 PIXMAN_COMPOSITE_ARGS (info); |
|
113 uint64_t stack_scanline_buffer[(SCANLINE_BUFFER_LENGTH * 3 + 7) / 8]; |
|
114 uint8_t *scanline_buffer = (uint8_t *) stack_scanline_buffer; |
|
115 uint8_t *src_buffer, *mask_buffer, *dest_buffer; |
|
116 pixman_iter_t src_iter, mask_iter, dest_iter; |
|
117 pixman_combine_32_func_t compose; |
|
118 pixman_bool_t component_alpha; |
|
119 iter_flags_t narrow, src_iter_flags; |
|
120 iter_flags_t rgb16; |
|
121 int Bpp; |
|
122 int i; |
|
123 |
|
124 if ((src_image->common.flags & FAST_PATH_NARROW_FORMAT) && |
|
125 (!mask_image || mask_image->common.flags & FAST_PATH_NARROW_FORMAT) && |
|
126 (dest_image->common.flags & FAST_PATH_NARROW_FORMAT)) |
|
127 { |
|
128 narrow = ITER_NARROW; |
|
129 Bpp = 4; |
|
130 } |
|
131 else |
|
132 { |
|
133 narrow = 0; |
|
134 Bpp = 16; |
|
135 } |
|
136 |
|
137 // XXX: This special casing is bad. Ideally, we'd keep the general code general perhaps |
|
138 // by having it deal more specifically with different intermediate formats |
|
139 if ( |
|
140 (dest_image->common.flags & FAST_PATH_16_FORMAT && (src_image->type == LINEAR || src_image->type == RADIAL)) && |
|
141 ( op == PIXMAN_OP_SRC || |
|
142 (op == PIXMAN_OP_OVER && (src_image->common.flags & FAST_PATH_IS_OPAQUE)) |
|
143 ) |
|
144 ) { |
|
145 rgb16 = ITER_16; |
|
146 } else { |
|
147 rgb16 = 0; |
|
148 } |
|
149 |
|
150 |
|
151 if (width * Bpp > SCANLINE_BUFFER_LENGTH) |
|
152 { |
|
153 scanline_buffer = pixman_malloc_abc (width, 3, Bpp); |
|
154 |
|
155 if (!scanline_buffer) |
|
156 return; |
|
157 } |
|
158 |
|
159 src_buffer = scanline_buffer; |
|
160 mask_buffer = src_buffer + width * Bpp; |
|
161 dest_buffer = mask_buffer + width * Bpp; |
|
162 |
|
163 if (!narrow) |
|
164 { |
|
165 /* To make sure there aren't any NANs in the buffers */ |
|
166 memset (src_buffer, 0, width * Bpp); |
|
167 memset (mask_buffer, 0, width * Bpp); |
|
168 memset (dest_buffer, 0, width * Bpp); |
|
169 } |
|
170 |
|
171 /* src iter */ |
|
172 src_iter_flags = narrow | op_flags[op].src | rgb16; |
|
173 |
|
174 _pixman_implementation_src_iter_init (imp->toplevel, &src_iter, src_image, |
|
175 src_x, src_y, width, height, |
|
176 src_buffer, src_iter_flags, info->src_flags); |
|
177 |
|
178 /* mask iter */ |
|
179 if ((src_iter_flags & (ITER_IGNORE_ALPHA | ITER_IGNORE_RGB)) == |
|
180 (ITER_IGNORE_ALPHA | ITER_IGNORE_RGB)) |
|
181 { |
|
182 /* If it doesn't matter what the source is, then it doesn't matter |
|
183 * what the mask is |
|
184 */ |
|
185 mask_image = NULL; |
|
186 } |
|
187 |
|
188 component_alpha = |
|
189 mask_image && |
|
190 mask_image->common.type == BITS && |
|
191 mask_image->common.component_alpha && |
|
192 PIXMAN_FORMAT_RGB (mask_image->bits.format); |
|
193 |
|
194 _pixman_implementation_src_iter_init ( |
|
195 imp->toplevel, &mask_iter, mask_image, mask_x, mask_y, width, height, |
|
196 mask_buffer, narrow | (component_alpha? 0 : ITER_IGNORE_RGB), info->mask_flags); |
|
197 |
|
198 /* dest iter */ |
|
199 _pixman_implementation_dest_iter_init ( |
|
200 imp->toplevel, &dest_iter, dest_image, dest_x, dest_y, width, height, |
|
201 dest_buffer, narrow | op_flags[op].dst | rgb16, info->dest_flags); |
|
202 |
|
203 compose = _pixman_implementation_lookup_combiner ( |
|
204 imp->toplevel, op, component_alpha, narrow, !!rgb16); |
|
205 |
|
206 for (i = 0; i < height; ++i) |
|
207 { |
|
208 uint32_t *s, *m, *d; |
|
209 |
|
210 m = mask_iter.get_scanline (&mask_iter, NULL); |
|
211 s = src_iter.get_scanline (&src_iter, m); |
|
212 d = dest_iter.get_scanline (&dest_iter, NULL); |
|
213 |
|
214 compose (imp->toplevel, op, d, s, m, width); |
|
215 |
|
216 dest_iter.write_back (&dest_iter); |
|
217 } |
|
218 |
|
219 if (scanline_buffer != (uint8_t *) stack_scanline_buffer) |
|
220 free (scanline_buffer); |
|
221 } |
|
222 |
|
223 static const pixman_fast_path_t general_fast_path[] = |
|
224 { |
|
225 { PIXMAN_OP_any, PIXMAN_any, 0, PIXMAN_any, 0, PIXMAN_any, 0, general_composite_rect }, |
|
226 { PIXMAN_OP_NONE } |
|
227 }; |
|
228 |
|
229 pixman_implementation_t * |
|
230 _pixman_implementation_create_general (void) |
|
231 { |
|
232 pixman_implementation_t *imp = _pixman_implementation_create (NULL, general_fast_path); |
|
233 |
|
234 _pixman_setup_combiner_functions_16 (imp); |
|
235 _pixman_setup_combiner_functions_32 (imp); |
|
236 _pixman_setup_combiner_functions_float (imp); |
|
237 |
|
238 imp->src_iter_init = general_src_iter_init; |
|
239 imp->dest_iter_init = general_dest_iter_init; |
|
240 |
|
241 return imp; |
|
242 } |
|
243 |