|
1 /* |
|
2 * Copyright © 2009 Red Hat, Inc. |
|
3 * |
|
4 * Permission to use, copy, modify, distribute, and sell this software and its |
|
5 * documentation for any purpose is hereby granted without fee, provided that |
|
6 * the above copyright notice appear in all copies and that both that |
|
7 * copyright notice and this permission notice appear in supporting |
|
8 * documentation, and that the name of Red Hat not be used in advertising or |
|
9 * publicity pertaining to distribution of the software without specific, |
|
10 * written prior permission. Red Hat makes no representations about the |
|
11 * suitability of this software for any purpose. It is provided "as is" |
|
12 * without express or implied warranty. |
|
13 * |
|
14 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS |
|
15 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND |
|
16 * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY |
|
17 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
|
18 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN |
|
19 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING |
|
20 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS |
|
21 * SOFTWARE. |
|
22 */ |
|
23 |
|
24 #ifdef HAVE_CONFIG_H |
|
25 #include <config.h> |
|
26 #endif |
|
27 #include <stdlib.h> |
|
28 #include "pixman-private.h" |
|
29 |
|
30 pixman_implementation_t * |
|
31 _pixman_implementation_create (pixman_implementation_t *fallback, |
|
32 const pixman_fast_path_t *fast_paths) |
|
33 { |
|
34 pixman_implementation_t *imp; |
|
35 |
|
36 assert (fast_paths); |
|
37 |
|
38 if ((imp = malloc (sizeof (pixman_implementation_t)))) |
|
39 { |
|
40 pixman_implementation_t *d; |
|
41 |
|
42 memset (imp, 0, sizeof *imp); |
|
43 |
|
44 imp->fallback = fallback; |
|
45 imp->fast_paths = fast_paths; |
|
46 |
|
47 /* Make sure the whole fallback chain has the right toplevel */ |
|
48 for (d = imp; d != NULL; d = d->fallback) |
|
49 d->toplevel = imp; |
|
50 } |
|
51 |
|
52 return imp; |
|
53 } |
|
54 |
|
55 #define N_CACHED_FAST_PATHS 8 |
|
56 |
|
57 typedef struct |
|
58 { |
|
59 struct |
|
60 { |
|
61 pixman_implementation_t * imp; |
|
62 pixman_fast_path_t fast_path; |
|
63 } cache [N_CACHED_FAST_PATHS]; |
|
64 } cache_t; |
|
65 |
|
66 PIXMAN_DEFINE_THREAD_LOCAL (cache_t, fast_path_cache); |
|
67 |
|
68 static void |
|
69 dummy_composite_rect (pixman_implementation_t *imp, |
|
70 pixman_composite_info_t *info) |
|
71 { |
|
72 } |
|
73 |
|
74 void |
|
75 _pixman_implementation_lookup_composite (pixman_implementation_t *toplevel, |
|
76 pixman_op_t op, |
|
77 pixman_format_code_t src_format, |
|
78 uint32_t src_flags, |
|
79 pixman_format_code_t mask_format, |
|
80 uint32_t mask_flags, |
|
81 pixman_format_code_t dest_format, |
|
82 uint32_t dest_flags, |
|
83 pixman_implementation_t **out_imp, |
|
84 pixman_composite_func_t *out_func) |
|
85 { |
|
86 pixman_implementation_t *imp; |
|
87 cache_t *cache; |
|
88 int i; |
|
89 |
|
90 /* Check cache for fast paths */ |
|
91 cache = PIXMAN_GET_THREAD_LOCAL (fast_path_cache); |
|
92 |
|
93 for (i = 0; i < N_CACHED_FAST_PATHS; ++i) |
|
94 { |
|
95 const pixman_fast_path_t *info = &(cache->cache[i].fast_path); |
|
96 |
|
97 /* Note that we check for equality here, not whether |
|
98 * the cached fast path matches. This is to prevent |
|
99 * us from selecting an overly general fast path |
|
100 * when a more specific one would work. |
|
101 */ |
|
102 if (info->op == op && |
|
103 info->src_format == src_format && |
|
104 info->mask_format == mask_format && |
|
105 info->dest_format == dest_format && |
|
106 info->src_flags == src_flags && |
|
107 info->mask_flags == mask_flags && |
|
108 info->dest_flags == dest_flags && |
|
109 info->func) |
|
110 { |
|
111 *out_imp = cache->cache[i].imp; |
|
112 *out_func = cache->cache[i].fast_path.func; |
|
113 |
|
114 goto update_cache; |
|
115 } |
|
116 } |
|
117 |
|
118 for (imp = toplevel; imp != NULL; imp = imp->fallback) |
|
119 { |
|
120 const pixman_fast_path_t *info = imp->fast_paths; |
|
121 |
|
122 while (info->op != PIXMAN_OP_NONE) |
|
123 { |
|
124 if ((info->op == op || info->op == PIXMAN_OP_any) && |
|
125 /* Formats */ |
|
126 ((info->src_format == src_format) || |
|
127 (info->src_format == PIXMAN_any)) && |
|
128 ((info->mask_format == mask_format) || |
|
129 (info->mask_format == PIXMAN_any)) && |
|
130 ((info->dest_format == dest_format) || |
|
131 (info->dest_format == PIXMAN_any)) && |
|
132 /* Flags */ |
|
133 (info->src_flags & src_flags) == info->src_flags && |
|
134 (info->mask_flags & mask_flags) == info->mask_flags && |
|
135 (info->dest_flags & dest_flags) == info->dest_flags) |
|
136 { |
|
137 *out_imp = imp; |
|
138 *out_func = info->func; |
|
139 |
|
140 /* Set i to the last spot in the cache so that the |
|
141 * move-to-front code below will work |
|
142 */ |
|
143 i = N_CACHED_FAST_PATHS - 1; |
|
144 |
|
145 goto update_cache; |
|
146 } |
|
147 |
|
148 ++info; |
|
149 } |
|
150 } |
|
151 |
|
152 /* We should never reach this point */ |
|
153 _pixman_log_error (FUNC, "No known composite function\n"); |
|
154 *out_imp = NULL; |
|
155 *out_func = dummy_composite_rect; |
|
156 |
|
157 update_cache: |
|
158 if (i) |
|
159 { |
|
160 while (i--) |
|
161 cache->cache[i + 1] = cache->cache[i]; |
|
162 |
|
163 cache->cache[0].imp = *out_imp; |
|
164 cache->cache[0].fast_path.op = op; |
|
165 cache->cache[0].fast_path.src_format = src_format; |
|
166 cache->cache[0].fast_path.src_flags = src_flags; |
|
167 cache->cache[0].fast_path.mask_format = mask_format; |
|
168 cache->cache[0].fast_path.mask_flags = mask_flags; |
|
169 cache->cache[0].fast_path.dest_format = dest_format; |
|
170 cache->cache[0].fast_path.dest_flags = dest_flags; |
|
171 cache->cache[0].fast_path.func = *out_func; |
|
172 } |
|
173 } |
|
174 |
|
175 static void |
|
176 dummy_combine (pixman_implementation_t *imp, |
|
177 pixman_op_t op, |
|
178 uint32_t * pd, |
|
179 const uint32_t * ps, |
|
180 const uint32_t * pm, |
|
181 int w) |
|
182 { |
|
183 } |
|
184 |
|
185 pixman_combine_32_func_t |
|
186 _pixman_implementation_lookup_combiner (pixman_implementation_t *imp, |
|
187 pixman_op_t op, |
|
188 pixman_bool_t component_alpha, |
|
189 pixman_bool_t narrow, |
|
190 pixman_bool_t rgb16) |
|
191 { |
|
192 while (imp) |
|
193 { |
|
194 pixman_combine_32_func_t f = NULL; |
|
195 |
|
196 switch ((narrow << 1) | component_alpha) |
|
197 { |
|
198 case 0: /* not narrow, not component alpha */ |
|
199 f = (pixman_combine_32_func_t)imp->combine_float[op]; |
|
200 break; |
|
201 |
|
202 case 1: /* not narrow, component_alpha */ |
|
203 f = (pixman_combine_32_func_t)imp->combine_float_ca[op]; |
|
204 break; |
|
205 |
|
206 case 2: /* narrow, not component alpha */ |
|
207 f = imp->combine_32[op]; |
|
208 break; |
|
209 |
|
210 case 3: /* narrow, component_alpha */ |
|
211 f = imp->combine_32_ca[op]; |
|
212 break; |
|
213 } |
|
214 if (rgb16) |
|
215 f = (pixman_combine_32_func_t *)imp->combine_16[op]; |
|
216 |
|
217 if (f) |
|
218 return f; |
|
219 |
|
220 imp = imp->fallback; |
|
221 } |
|
222 |
|
223 /* We should never reach this point */ |
|
224 _pixman_log_error (FUNC, "No known combine function\n"); |
|
225 return dummy_combine; |
|
226 } |
|
227 |
|
228 pixman_bool_t |
|
229 _pixman_implementation_blt (pixman_implementation_t * imp, |
|
230 uint32_t * src_bits, |
|
231 uint32_t * dst_bits, |
|
232 int src_stride, |
|
233 int dst_stride, |
|
234 int src_bpp, |
|
235 int dst_bpp, |
|
236 int src_x, |
|
237 int src_y, |
|
238 int dest_x, |
|
239 int dest_y, |
|
240 int width, |
|
241 int height) |
|
242 { |
|
243 while (imp) |
|
244 { |
|
245 if (imp->blt && |
|
246 (*imp->blt) (imp, src_bits, dst_bits, src_stride, dst_stride, |
|
247 src_bpp, dst_bpp, src_x, src_y, dest_x, dest_y, |
|
248 width, height)) |
|
249 { |
|
250 return TRUE; |
|
251 } |
|
252 |
|
253 imp = imp->fallback; |
|
254 } |
|
255 |
|
256 return FALSE; |
|
257 } |
|
258 |
|
259 pixman_bool_t |
|
260 _pixman_implementation_fill (pixman_implementation_t *imp, |
|
261 uint32_t * bits, |
|
262 int stride, |
|
263 int bpp, |
|
264 int x, |
|
265 int y, |
|
266 int width, |
|
267 int height, |
|
268 uint32_t filler) |
|
269 { |
|
270 while (imp) |
|
271 { |
|
272 if (imp->fill && |
|
273 ((*imp->fill) (imp, bits, stride, bpp, x, y, width, height, filler))) |
|
274 { |
|
275 return TRUE; |
|
276 } |
|
277 |
|
278 imp = imp->fallback; |
|
279 } |
|
280 |
|
281 return FALSE; |
|
282 } |
|
283 |
|
284 pixman_bool_t |
|
285 _pixman_implementation_src_iter_init (pixman_implementation_t *imp, |
|
286 pixman_iter_t *iter, |
|
287 pixman_image_t *image, |
|
288 int x, |
|
289 int y, |
|
290 int width, |
|
291 int height, |
|
292 uint8_t *buffer, |
|
293 iter_flags_t iter_flags, |
|
294 uint32_t image_flags) |
|
295 { |
|
296 iter->image = image; |
|
297 iter->buffer = (uint32_t *)buffer; |
|
298 iter->x = x; |
|
299 iter->y = y; |
|
300 iter->width = width; |
|
301 iter->height = height; |
|
302 iter->iter_flags = iter_flags; |
|
303 iter->image_flags = image_flags; |
|
304 |
|
305 while (imp) |
|
306 { |
|
307 if (imp->src_iter_init && (*imp->src_iter_init) (imp, iter)) |
|
308 return TRUE; |
|
309 |
|
310 imp = imp->fallback; |
|
311 } |
|
312 |
|
313 return FALSE; |
|
314 } |
|
315 |
|
316 pixman_bool_t |
|
317 _pixman_implementation_dest_iter_init (pixman_implementation_t *imp, |
|
318 pixman_iter_t *iter, |
|
319 pixman_image_t *image, |
|
320 int x, |
|
321 int y, |
|
322 int width, |
|
323 int height, |
|
324 uint8_t *buffer, |
|
325 iter_flags_t iter_flags, |
|
326 uint32_t image_flags) |
|
327 { |
|
328 iter->image = image; |
|
329 iter->buffer = (uint32_t *)buffer; |
|
330 iter->x = x; |
|
331 iter->y = y; |
|
332 iter->width = width; |
|
333 iter->height = height; |
|
334 iter->iter_flags = iter_flags; |
|
335 iter->image_flags = image_flags; |
|
336 |
|
337 while (imp) |
|
338 { |
|
339 if (imp->dest_iter_init && (*imp->dest_iter_init) (imp, iter)) |
|
340 return TRUE; |
|
341 |
|
342 imp = imp->fallback; |
|
343 } |
|
344 |
|
345 return FALSE; |
|
346 } |
|
347 |
|
348 pixman_bool_t |
|
349 _pixman_disabled (const char *name) |
|
350 { |
|
351 const char *env; |
|
352 |
|
353 if ((env = getenv ("PIXMAN_DISABLE"))) |
|
354 { |
|
355 do |
|
356 { |
|
357 const char *end; |
|
358 int len; |
|
359 |
|
360 if ((end = strchr (env, ' '))) |
|
361 len = end - env; |
|
362 else |
|
363 len = strlen (env); |
|
364 |
|
365 if (strlen (name) == len && strncmp (name, env, len) == 0) |
|
366 { |
|
367 printf ("pixman: Disabled %s implementation\n", name); |
|
368 return TRUE; |
|
369 } |
|
370 |
|
371 env += len; |
|
372 } |
|
373 while (*env++); |
|
374 } |
|
375 |
|
376 return FALSE; |
|
377 } |
|
378 |
|
379 pixman_implementation_t * |
|
380 _pixman_choose_implementation (void) |
|
381 { |
|
382 pixman_implementation_t *imp; |
|
383 |
|
384 imp = _pixman_implementation_create_general(); |
|
385 |
|
386 if (!_pixman_disabled ("fast")) |
|
387 imp = _pixman_implementation_create_fast_path (imp); |
|
388 |
|
389 imp = _pixman_x86_get_implementations (imp); |
|
390 imp = _pixman_arm_get_implementations (imp); |
|
391 imp = _pixman_ppc_get_implementations (imp); |
|
392 imp = _pixman_mips_get_implementations (imp); |
|
393 |
|
394 imp = _pixman_implementation_create_noop (imp); |
|
395 |
|
396 return imp; |
|
397 } |