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 *
_pixman_implementation_create(pixman_implementation_t * fallback,const pixman_fast_path_t * fast_paths)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
dummy_composite_rect(pixman_implementation_t * imp,pixman_composite_info_t * info)69 dummy_composite_rect (pixman_implementation_t *imp,
70 pixman_composite_info_t *info)
71 {
72 }
73
74 void
_pixman_implementation_lookup_composite(pixman_implementation_t * toplevel,pixman_op_t op,pixman_format_code_t src_format,uint32_t src_flags,pixman_format_code_t mask_format,uint32_t mask_flags,pixman_format_code_t dest_format,uint32_t dest_flags,pixman_implementation_t ** out_imp,pixman_composite_func_t * out_func)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 /* Bug 1324130 - For compatibility with Windows XP, we have to use Tls
94 * functions for the per-thread fast-path cache instead of the safer
95 * __declspec(thread) mechanism. If the Tls functions fail to set up
96 * the storage for some reason, cache will end up null here. As a
97 * temporary workaround, just check that cache is not null before
98 * using it. The implementation lookup will still function without the
99 * fast-path cache, however, it will incur a slow linear search.
100 */
101 if (cache) for (i = 0; i < N_CACHED_FAST_PATHS; ++i)
102 {
103 const pixman_fast_path_t *info = &(cache->cache[i].fast_path);
104
105 /* Note that we check for equality here, not whether
106 * the cached fast path matches. This is to prevent
107 * us from selecting an overly general fast path
108 * when a more specific one would work.
109 */
110 if (info->op == op &&
111 info->src_format == src_format &&
112 info->mask_format == mask_format &&
113 info->dest_format == dest_format &&
114 info->src_flags == src_flags &&
115 info->mask_flags == mask_flags &&
116 info->dest_flags == dest_flags &&
117 info->func)
118 {
119 *out_imp = cache->cache[i].imp;
120 *out_func = cache->cache[i].fast_path.func;
121
122 goto update_cache;
123 }
124 }
125
126 for (imp = toplevel; imp != NULL; imp = imp->fallback)
127 {
128 const pixman_fast_path_t *info = imp->fast_paths;
129
130 while (info->op != PIXMAN_OP_NONE)
131 {
132 if ((info->op == op || info->op == PIXMAN_OP_any) &&
133 /* Formats */
134 ((info->src_format == src_format) ||
135 (info->src_format == PIXMAN_any)) &&
136 ((info->mask_format == mask_format) ||
137 (info->mask_format == PIXMAN_any)) &&
138 ((info->dest_format == dest_format) ||
139 (info->dest_format == PIXMAN_any)) &&
140 /* Flags */
141 (info->src_flags & src_flags) == info->src_flags &&
142 (info->mask_flags & mask_flags) == info->mask_flags &&
143 (info->dest_flags & dest_flags) == info->dest_flags)
144 {
145 *out_imp = imp;
146 *out_func = info->func;
147
148 /* Set i to the last spot in the cache so that the
149 * move-to-front code below will work
150 */
151 i = N_CACHED_FAST_PATHS - 1;
152
153 goto update_cache;
154 }
155
156 ++info;
157 }
158 }
159
160 /* We should never reach this point */
161 _pixman_log_error (FUNC, "No known composite function\n");
162 *out_imp = NULL;
163 *out_func = dummy_composite_rect;
164
165 update_cache:
166 if (cache && i)
167 {
168 while (i--)
169 cache->cache[i + 1] = cache->cache[i];
170
171 cache->cache[0].imp = *out_imp;
172 cache->cache[0].fast_path.op = op;
173 cache->cache[0].fast_path.src_format = src_format;
174 cache->cache[0].fast_path.src_flags = src_flags;
175 cache->cache[0].fast_path.mask_format = mask_format;
176 cache->cache[0].fast_path.mask_flags = mask_flags;
177 cache->cache[0].fast_path.dest_format = dest_format;
178 cache->cache[0].fast_path.dest_flags = dest_flags;
179 cache->cache[0].fast_path.func = *out_func;
180 }
181 }
182
183 static void
dummy_combine(pixman_implementation_t * imp,pixman_op_t op,uint32_t * pd,const uint32_t * ps,const uint32_t * pm,int w)184 dummy_combine (pixman_implementation_t *imp,
185 pixman_op_t op,
186 uint32_t * pd,
187 const uint32_t * ps,
188 const uint32_t * pm,
189 int w)
190 {
191 }
192
193 pixman_combine_32_func_t
_pixman_implementation_lookup_combiner(pixman_implementation_t * imp,pixman_op_t op,pixman_bool_t component_alpha,pixman_bool_t narrow,pixman_bool_t rgb16)194 _pixman_implementation_lookup_combiner (pixman_implementation_t *imp,
195 pixman_op_t op,
196 pixman_bool_t component_alpha,
197 pixman_bool_t narrow,
198 pixman_bool_t rgb16)
199 {
200 while (imp)
201 {
202 pixman_combine_32_func_t f = NULL;
203
204 switch ((narrow << 1) | component_alpha)
205 {
206 case 0: /* not narrow, not component alpha */
207 f = (pixman_combine_32_func_t)imp->combine_float[op];
208 break;
209
210 case 1: /* not narrow, component_alpha */
211 f = (pixman_combine_32_func_t)imp->combine_float_ca[op];
212 break;
213
214 case 2: /* narrow, not component alpha */
215 f = imp->combine_32[op];
216 break;
217
218 case 3: /* narrow, component_alpha */
219 f = imp->combine_32_ca[op];
220 break;
221 }
222 if (rgb16)
223 f = (pixman_combine_32_func_t *)imp->combine_16[op];
224
225 if (f)
226 return f;
227
228 imp = imp->fallback;
229 }
230
231 /* We should never reach this point */
232 _pixman_log_error (FUNC, "No known combine function\n");
233 return dummy_combine;
234 }
235
236 pixman_bool_t
_pixman_implementation_blt(pixman_implementation_t * imp,uint32_t * src_bits,uint32_t * dst_bits,int src_stride,int dst_stride,int src_bpp,int dst_bpp,int src_x,int src_y,int dest_x,int dest_y,int width,int height)237 _pixman_implementation_blt (pixman_implementation_t * imp,
238 uint32_t * src_bits,
239 uint32_t * dst_bits,
240 int src_stride,
241 int dst_stride,
242 int src_bpp,
243 int dst_bpp,
244 int src_x,
245 int src_y,
246 int dest_x,
247 int dest_y,
248 int width,
249 int height)
250 {
251 while (imp)
252 {
253 if (imp->blt &&
254 (*imp->blt) (imp, src_bits, dst_bits, src_stride, dst_stride,
255 src_bpp, dst_bpp, src_x, src_y, dest_x, dest_y,
256 width, height))
257 {
258 return TRUE;
259 }
260
261 imp = imp->fallback;
262 }
263
264 return FALSE;
265 }
266
267 pixman_bool_t
_pixman_implementation_fill(pixman_implementation_t * imp,uint32_t * bits,int stride,int bpp,int x,int y,int width,int height,uint32_t filler)268 _pixman_implementation_fill (pixman_implementation_t *imp,
269 uint32_t * bits,
270 int stride,
271 int bpp,
272 int x,
273 int y,
274 int width,
275 int height,
276 uint32_t filler)
277 {
278 while (imp)
279 {
280 if (imp->fill &&
281 ((*imp->fill) (imp, bits, stride, bpp, x, y, width, height, filler)))
282 {
283 return TRUE;
284 }
285
286 imp = imp->fallback;
287 }
288
289 return FALSE;
290 }
291
292 pixman_bool_t
_pixman_implementation_src_iter_init(pixman_implementation_t * imp,pixman_iter_t * iter,pixman_image_t * image,int x,int y,int width,int height,uint8_t * buffer,iter_flags_t iter_flags,uint32_t image_flags)293 _pixman_implementation_src_iter_init (pixman_implementation_t *imp,
294 pixman_iter_t *iter,
295 pixman_image_t *image,
296 int x,
297 int y,
298 int width,
299 int height,
300 uint8_t *buffer,
301 iter_flags_t iter_flags,
302 uint32_t image_flags)
303 {
304 iter->image = image;
305 iter->buffer = (uint32_t *)buffer;
306 iter->x = x;
307 iter->y = y;
308 iter->width = width;
309 iter->height = height;
310 iter->iter_flags = iter_flags;
311 iter->image_flags = image_flags;
312
313 while (imp)
314 {
315 if (imp->src_iter_init && (*imp->src_iter_init) (imp, iter))
316 return TRUE;
317
318 imp = imp->fallback;
319 }
320
321 return FALSE;
322 }
323
324 pixman_bool_t
_pixman_implementation_dest_iter_init(pixman_implementation_t * imp,pixman_iter_t * iter,pixman_image_t * image,int x,int y,int width,int height,uint8_t * buffer,iter_flags_t iter_flags,uint32_t image_flags)325 _pixman_implementation_dest_iter_init (pixman_implementation_t *imp,
326 pixman_iter_t *iter,
327 pixman_image_t *image,
328 int x,
329 int y,
330 int width,
331 int height,
332 uint8_t *buffer,
333 iter_flags_t iter_flags,
334 uint32_t image_flags)
335 {
336 iter->image = image;
337 iter->buffer = (uint32_t *)buffer;
338 iter->x = x;
339 iter->y = y;
340 iter->width = width;
341 iter->height = height;
342 iter->iter_flags = iter_flags;
343 iter->image_flags = image_flags;
344
345 while (imp)
346 {
347 if (imp->dest_iter_init && (*imp->dest_iter_init) (imp, iter))
348 return TRUE;
349
350 imp = imp->fallback;
351 }
352
353 return FALSE;
354 }
355
356 pixman_bool_t
_pixman_disabled(const char * name)357 _pixman_disabled (const char *name)
358 {
359 const char *env;
360
361 if ((env = getenv ("PIXMAN_DISABLE")))
362 {
363 do
364 {
365 const char *end;
366 int len;
367
368 if ((end = strchr (env, ' ')))
369 len = end - env;
370 else
371 len = strlen (env);
372
373 if (strlen (name) == len && strncmp (name, env, len) == 0)
374 {
375 printf ("pixman: Disabled %s implementation\n", name);
376 return TRUE;
377 }
378
379 env += len;
380 }
381 while (*env++);
382 }
383
384 return FALSE;
385 }
386
387 pixman_implementation_t *
_pixman_choose_implementation(void)388 _pixman_choose_implementation (void)
389 {
390 pixman_implementation_t *imp;
391
392 imp = _pixman_implementation_create_general();
393
394 if (!_pixman_disabled ("fast"))
395 imp = _pixman_implementation_create_fast_path (imp);
396
397 imp = _pixman_x86_get_implementations (imp);
398 imp = _pixman_arm_get_implementations (imp);
399 imp = _pixman_ppc_get_implementations (imp);
400 imp = _pixman_mips_get_implementations (imp);
401
402 imp = _pixman_implementation_create_noop (imp);
403
404 return imp;
405 }
406