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