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
30pixman_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
57typedef 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
66PIXMAN_DEFINE_THREAD_LOCAL (cache_t, fast_path_cache);
67
68static void
69dummy_composite_rect (pixman_implementation_t *imp,
70		      pixman_composite_info_t *info)
71{
72}
73
74void
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 (
154        FUNC,
155        "No composite function found\n"
156        "\n"
157        "The most likely cause of this is that this system has issues with\n"
158        "thread local storage\n");
159
160    *out_imp = NULL;
161    *out_func = dummy_composite_rect;
162    return;
163
164update_cache:
165    if (i)
166    {
167	while (i--)
168	    cache->cache[i + 1] = cache->cache[i];
169
170	cache->cache[0].imp = *out_imp;
171	cache->cache[0].fast_path.op = op;
172	cache->cache[0].fast_path.src_format = src_format;
173	cache->cache[0].fast_path.src_flags = src_flags;
174	cache->cache[0].fast_path.mask_format = mask_format;
175	cache->cache[0].fast_path.mask_flags = mask_flags;
176	cache->cache[0].fast_path.dest_format = dest_format;
177	cache->cache[0].fast_path.dest_flags = dest_flags;
178	cache->cache[0].fast_path.func = *out_func;
179    }
180}
181
182static void
183dummy_combine (pixman_implementation_t *imp,
184	       pixman_op_t              op,
185	       uint32_t *               pd,
186	       const uint32_t *         ps,
187	       const uint32_t *         pm,
188	       int                      w)
189{
190}
191
192pixman_combine_32_func_t
193_pixman_implementation_lookup_combiner (pixman_implementation_t *imp,
194					pixman_op_t		 op,
195					pixman_bool_t		 component_alpha,
196					pixman_bool_t		 narrow)
197{
198    while (imp)
199    {
200	pixman_combine_32_func_t f = NULL;
201
202	switch ((narrow << 1) | component_alpha)
203	{
204	case 0: /* not narrow, not component alpha */
205	    f = (pixman_combine_32_func_t)imp->combine_float[op];
206	    break;
207
208	case 1: /* not narrow, component_alpha */
209	    f = (pixman_combine_32_func_t)imp->combine_float_ca[op];
210	    break;
211
212	case 2: /* narrow, not component alpha */
213	    f = imp->combine_32[op];
214	    break;
215
216	case 3: /* narrow, component_alpha */
217	    f = imp->combine_32_ca[op];
218	    break;
219	}
220
221	if (f)
222	    return f;
223
224	imp = imp->fallback;
225    }
226
227    /* We should never reach this point */
228    _pixman_log_error (FUNC, "No known combine function\n");
229    return dummy_combine;
230}
231
232pixman_bool_t
233_pixman_implementation_blt (pixman_implementation_t * imp,
234                            uint32_t *                src_bits,
235                            uint32_t *                dst_bits,
236                            int                       src_stride,
237                            int                       dst_stride,
238                            int                       src_bpp,
239                            int                       dst_bpp,
240                            int                       src_x,
241                            int                       src_y,
242                            int                       dest_x,
243                            int                       dest_y,
244                            int                       width,
245                            int                       height)
246{
247    while (imp)
248    {
249	if (imp->blt &&
250	    (*imp->blt) (imp, src_bits, dst_bits, src_stride, dst_stride,
251			 src_bpp, dst_bpp, src_x, src_y, dest_x, dest_y,
252			 width, height))
253	{
254	    return TRUE;
255	}
256
257	imp = imp->fallback;
258    }
259
260    return FALSE;
261}
262
263pixman_bool_t
264_pixman_implementation_fill (pixman_implementation_t *imp,
265                             uint32_t *               bits,
266                             int                      stride,
267                             int                      bpp,
268                             int                      x,
269                             int                      y,
270                             int                      width,
271                             int                      height,
272                             uint32_t                 filler)
273{
274    while (imp)
275    {
276	if (imp->fill &&
277	    ((*imp->fill) (imp, bits, stride, bpp, x, y, width, height, filler)))
278	{
279	    return TRUE;
280	}
281
282	imp = imp->fallback;
283    }
284
285    return FALSE;
286}
287
288pixman_bool_t
289_pixman_implementation_src_iter_init (pixman_implementation_t	*imp,
290				      pixman_iter_t             *iter,
291				      pixman_image_t		*image,
292				      int			 x,
293				      int			 y,
294				      int			 width,
295				      int			 height,
296				      uint8_t			*buffer,
297				      iter_flags_t		 iter_flags,
298				      uint32_t                   image_flags)
299{
300    iter->image = image;
301    iter->buffer = (uint32_t *)buffer;
302    iter->x = x;
303    iter->y = y;
304    iter->width = width;
305    iter->height = height;
306    iter->iter_flags = iter_flags;
307    iter->image_flags = image_flags;
308
309    while (imp)
310    {
311	if (imp->src_iter_init && (*imp->src_iter_init) (imp, iter))
312	    return TRUE;
313
314	imp = imp->fallback;
315    }
316
317    return FALSE;
318}
319
320pixman_bool_t
321_pixman_implementation_dest_iter_init (pixman_implementation_t	*imp,
322				       pixman_iter_t            *iter,
323				       pixman_image_t		*image,
324				       int			 x,
325				       int			 y,
326				       int			 width,
327				       int			 height,
328				       uint8_t			*buffer,
329				       iter_flags_t		 iter_flags,
330				       uint32_t                  image_flags)
331{
332    iter->image = image;
333    iter->buffer = (uint32_t *)buffer;
334    iter->x = x;
335    iter->y = y;
336    iter->width = width;
337    iter->height = height;
338    iter->iter_flags = iter_flags;
339    iter->image_flags = image_flags;
340
341    while (imp)
342    {
343	if (imp->dest_iter_init && (*imp->dest_iter_init) (imp, iter))
344	    return TRUE;
345
346	imp = imp->fallback;
347    }
348
349    return FALSE;
350}
351
352pixman_bool_t
353_pixman_disabled (const char *name)
354{
355    const char *env;
356
357    if ((env = getenv ("PIXMAN_DISABLE")))
358    {
359	do
360	{
361	    const char *end;
362	    int len;
363
364	    if ((end = strchr (env, ' ')))
365		len = end - env;
366	    else
367		len = strlen (env);
368
369	    if (strlen (name) == len && strncmp (name, env, len) == 0)
370	    {
371		printf ("pixman: Disabled %s implementation\n", name);
372		return TRUE;
373	    }
374
375	    env += len;
376	}
377	while (*env++);
378    }
379
380    return FALSE;
381}
382
383pixman_implementation_t *
384_pixman_choose_implementation (void)
385{
386    pixman_implementation_t *imp;
387
388    imp = _pixman_implementation_create_general();
389
390    if (!_pixman_disabled ("fast"))
391	imp = _pixman_implementation_create_fast_path (imp);
392
393    imp = _pixman_x86_get_implementations (imp);
394    imp = _pixman_arm_get_implementations (imp);
395    imp = _pixman_ppc_get_implementations (imp);
396    imp = _pixman_mips_get_implementations (imp);
397
398    imp = _pixman_implementation_create_noop (imp);
399
400    return imp;
401}
402