pixman-implementation.c revision 6ca29ff0
1317c648bSmrg/*
2317c648bSmrg * Copyright © 2009 Red Hat, Inc.
3317c648bSmrg *
4317c648bSmrg * Permission to use, copy, modify, distribute, and sell this software and its
5317c648bSmrg * documentation for any purpose is hereby granted without fee, provided that
6317c648bSmrg * the above copyright notice appear in all copies and that both that
7317c648bSmrg * copyright notice and this permission notice appear in supporting
8317c648bSmrg * documentation, and that the name of Red Hat not be used in advertising or
9317c648bSmrg * publicity pertaining to distribution of the software without specific,
10317c648bSmrg * written prior permission.  Red Hat makes no representations about the
11317c648bSmrg * suitability of this software for any purpose.  It is provided "as is"
12317c648bSmrg * without express or implied warranty.
13317c648bSmrg *
14317c648bSmrg * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
15317c648bSmrg * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
16317c648bSmrg * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
17317c648bSmrg * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
18317c648bSmrg * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
19317c648bSmrg * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
20317c648bSmrg * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
21317c648bSmrg * SOFTWARE.
22317c648bSmrg */
23317c648bSmrg
24a450e446Smrg#ifdef HAVE_CONFIG_H
25317c648bSmrg#include <config.h>
26a450e446Smrg#endif
27317c648bSmrg#include <stdlib.h>
28317c648bSmrg#include "pixman-private.h"
29317c648bSmrg
309ad247e8Sjmcneillpixman_implementation_t *
319ad247e8Sjmcneill_pixman_implementation_create (pixman_implementation_t *fallback,
329ad247e8Sjmcneill			       const pixman_fast_path_t *fast_paths)
33317c648bSmrg{
349ad247e8Sjmcneill    pixman_implementation_t *imp;
35317c648bSmrg
369ad247e8Sjmcneill    assert (fast_paths);
37317c648bSmrg
389ad247e8Sjmcneill    if ((imp = malloc (sizeof (pixman_implementation_t))))
399ad247e8Sjmcneill    {
409ad247e8Sjmcneill	pixman_implementation_t *d;
41317c648bSmrg
429ad247e8Sjmcneill	memset (imp, 0, sizeof *imp);
43317c648bSmrg
449ad247e8Sjmcneill	imp->fallback = fallback;
459ad247e8Sjmcneill	imp->fast_paths = fast_paths;
469ad247e8Sjmcneill
479ad247e8Sjmcneill	/* Make sure the whole fallback chain has the right toplevel */
489ad247e8Sjmcneill	for (d = imp; d != NULL; d = d->fallback)
499ad247e8Sjmcneill	    d->toplevel = imp;
509ad247e8Sjmcneill    }
51317c648bSmrg
529ad247e8Sjmcneill    return imp;
53317c648bSmrg}
54317c648bSmrg
559ad247e8Sjmcneill#define N_CACHED_FAST_PATHS 8
56953d7d37Smrg
579ad247e8Sjmcneilltypedef struct
58953d7d37Smrg{
599ad247e8Sjmcneill    struct
609ad247e8Sjmcneill    {
619ad247e8Sjmcneill	pixman_implementation_t *	imp;
629ad247e8Sjmcneill	pixman_fast_path_t		fast_path;
639ad247e8Sjmcneill    } cache [N_CACHED_FAST_PATHS];
649ad247e8Sjmcneill} cache_t;
65953d7d37Smrg
669ad247e8SjmcneillPIXMAN_DEFINE_THREAD_LOCAL (cache_t, fast_path_cache);
679ad247e8Sjmcneill
68f4f78bb6Smrgstatic void
69f4f78bb6Smrgdummy_composite_rect (pixman_implementation_t *imp,
70f4f78bb6Smrg		      pixman_composite_info_t *info)
71f4f78bb6Smrg{
72f4f78bb6Smrg}
73f4f78bb6Smrg
74f4f78bb6Smrgvoid
759ad247e8Sjmcneill_pixman_implementation_lookup_composite (pixman_implementation_t  *toplevel,
769ad247e8Sjmcneill					 pixman_op_t               op,
779ad247e8Sjmcneill					 pixman_format_code_t      src_format,
789ad247e8Sjmcneill					 uint32_t                  src_flags,
799ad247e8Sjmcneill					 pixman_format_code_t      mask_format,
809ad247e8Sjmcneill					 uint32_t                  mask_flags,
819ad247e8Sjmcneill					 pixman_format_code_t      dest_format,
829ad247e8Sjmcneill					 uint32_t                  dest_flags,
839ad247e8Sjmcneill					 pixman_implementation_t **out_imp,
849ad247e8Sjmcneill					 pixman_composite_func_t  *out_func)
85317c648bSmrg{
869ad247e8Sjmcneill    pixman_implementation_t *imp;
879ad247e8Sjmcneill    cache_t *cache;
88317c648bSmrg    int i;
89d0321353Smrg
909ad247e8Sjmcneill    /* Check cache for fast paths */
919ad247e8Sjmcneill    cache = PIXMAN_GET_THREAD_LOCAL (fast_path_cache);
92317c648bSmrg
939ad247e8Sjmcneill    for (i = 0; i < N_CACHED_FAST_PATHS; ++i)
949ad247e8Sjmcneill    {
959ad247e8Sjmcneill	const pixman_fast_path_t *info = &(cache->cache[i].fast_path);
96952204abSmrg
979ad247e8Sjmcneill	/* Note that we check for equality here, not whether
989ad247e8Sjmcneill	 * the cached fast path matches. This is to prevent
999ad247e8Sjmcneill	 * us from selecting an overly general fast path
1009ad247e8Sjmcneill	 * when a more specific one would work.
1019ad247e8Sjmcneill	 */
1029ad247e8Sjmcneill	if (info->op == op			&&
1039ad247e8Sjmcneill	    info->src_format == src_format	&&
1049ad247e8Sjmcneill	    info->mask_format == mask_format	&&
1059ad247e8Sjmcneill	    info->dest_format == dest_format	&&
1069ad247e8Sjmcneill	    info->src_flags == src_flags	&&
1079ad247e8Sjmcneill	    info->mask_flags == mask_flags	&&
1089ad247e8Sjmcneill	    info->dest_flags == dest_flags	&&
1099ad247e8Sjmcneill	    info->func)
1109ad247e8Sjmcneill	{
1119ad247e8Sjmcneill	    *out_imp = cache->cache[i].imp;
1129ad247e8Sjmcneill	    *out_func = cache->cache[i].fast_path.func;
113317c648bSmrg
1149ad247e8Sjmcneill	    goto update_cache;
1159ad247e8Sjmcneill	}
1169ad247e8Sjmcneill    }
117d0321353Smrg
1189ad247e8Sjmcneill    for (imp = toplevel; imp != NULL; imp = imp->fallback)
119317c648bSmrg    {
1209ad247e8Sjmcneill	const pixman_fast_path_t *info = imp->fast_paths;
1219ad247e8Sjmcneill
1229ad247e8Sjmcneill	while (info->op != PIXMAN_OP_NONE)
1239ad247e8Sjmcneill	{
1249ad247e8Sjmcneill	    if ((info->op == op || info->op == PIXMAN_OP_any)		&&
1259ad247e8Sjmcneill		/* Formats */
1269ad247e8Sjmcneill		((info->src_format == src_format) ||
1279ad247e8Sjmcneill		 (info->src_format == PIXMAN_any))			&&
1289ad247e8Sjmcneill		((info->mask_format == mask_format) ||
1299ad247e8Sjmcneill		 (info->mask_format == PIXMAN_any))			&&
1309ad247e8Sjmcneill		((info->dest_format == dest_format) ||
1319ad247e8Sjmcneill		 (info->dest_format == PIXMAN_any))			&&
1329ad247e8Sjmcneill		/* Flags */
1339ad247e8Sjmcneill		(info->src_flags & src_flags) == info->src_flags	&&
1349ad247e8Sjmcneill		(info->mask_flags & mask_flags) == info->mask_flags	&&
1359ad247e8Sjmcneill		(info->dest_flags & dest_flags) == info->dest_flags)
1369ad247e8Sjmcneill	    {
1379ad247e8Sjmcneill		*out_imp = imp;
1389ad247e8Sjmcneill		*out_func = info->func;
1399ad247e8Sjmcneill
1409ad247e8Sjmcneill		/* Set i to the last spot in the cache so that the
1419ad247e8Sjmcneill		 * move-to-front code below will work
1429ad247e8Sjmcneill		 */
1439ad247e8Sjmcneill		i = N_CACHED_FAST_PATHS - 1;
1449ad247e8Sjmcneill
1459ad247e8Sjmcneill		goto update_cache;
1469ad247e8Sjmcneill	    }
1479ad247e8Sjmcneill
1489ad247e8Sjmcneill	    ++info;
1499ad247e8Sjmcneill	}
150317c648bSmrg    }
151f4f78bb6Smrg
152f4f78bb6Smrg    /* We should never reach this point */
153f4f78bb6Smrg    _pixman_log_error (
154f4f78bb6Smrg        FUNC,
155f4f78bb6Smrg        "No composite function found\n"
156f4f78bb6Smrg        "\n"
157f4f78bb6Smrg        "The most likely cause of this is that this system has issues with\n"
158f4f78bb6Smrg        "thread local storage\n");
159f4f78bb6Smrg
160f4f78bb6Smrg    *out_imp = NULL;
161f4f78bb6Smrg    *out_func = dummy_composite_rect;
162f4f78bb6Smrg    return;
163d0321353Smrg
1649ad247e8Sjmcneillupdate_cache:
1659ad247e8Sjmcneill    if (i)
1669ad247e8Sjmcneill    {
1679ad247e8Sjmcneill	while (i--)
1689ad247e8Sjmcneill	    cache->cache[i + 1] = cache->cache[i];
169953d7d37Smrg
1709ad247e8Sjmcneill	cache->cache[0].imp = *out_imp;
1719ad247e8Sjmcneill	cache->cache[0].fast_path.op = op;
1729ad247e8Sjmcneill	cache->cache[0].fast_path.src_format = src_format;
1739ad247e8Sjmcneill	cache->cache[0].fast_path.src_flags = src_flags;
1749ad247e8Sjmcneill	cache->cache[0].fast_path.mask_format = mask_format;
1759ad247e8Sjmcneill	cache->cache[0].fast_path.mask_flags = mask_flags;
1769ad247e8Sjmcneill	cache->cache[0].fast_path.dest_format = dest_format;
1779ad247e8Sjmcneill	cache->cache[0].fast_path.dest_flags = dest_flags;
1789ad247e8Sjmcneill	cache->cache[0].fast_path.func = *out_func;
1799ad247e8Sjmcneill    }
180f4f78bb6Smrg}
181317c648bSmrg
182f4f78bb6Smrgstatic void
183f4f78bb6Smrgdummy_combine (pixman_implementation_t *imp,
184f4f78bb6Smrg	       pixman_op_t              op,
185f4f78bb6Smrg	       uint32_t *               pd,
186f4f78bb6Smrg	       const uint32_t *         ps,
187f4f78bb6Smrg	       const uint32_t *         pm,
188f4f78bb6Smrg	       int                      w)
189f4f78bb6Smrg{
190317c648bSmrg}
191317c648bSmrg
1929ad247e8Sjmcneillpixman_combine_32_func_t
1939ad247e8Sjmcneill_pixman_implementation_lookup_combiner (pixman_implementation_t *imp,
1949ad247e8Sjmcneill					pixman_op_t		 op,
1959ad247e8Sjmcneill					pixman_bool_t		 component_alpha,
1969ad247e8Sjmcneill					pixman_bool_t		 narrow)
197317c648bSmrg{
1989ad247e8Sjmcneill    while (imp)
1999ad247e8Sjmcneill    {
2009ad247e8Sjmcneill	pixman_combine_32_func_t f = NULL;
201317c648bSmrg
2029ad247e8Sjmcneill	switch ((narrow << 1) | component_alpha)
2039ad247e8Sjmcneill	{
2049ad247e8Sjmcneill	case 0: /* not narrow, not component alpha */
2059ad247e8Sjmcneill	    f = (pixman_combine_32_func_t)imp->combine_float[op];
2069ad247e8Sjmcneill	    break;
2079ad247e8Sjmcneill
2089ad247e8Sjmcneill	case 1: /* not narrow, component_alpha */
2099ad247e8Sjmcneill	    f = (pixman_combine_32_func_t)imp->combine_float_ca[op];
2109ad247e8Sjmcneill	    break;
211317c648bSmrg
2129ad247e8Sjmcneill	case 2: /* narrow, not component alpha */
2139ad247e8Sjmcneill	    f = imp->combine_32[op];
2149ad247e8Sjmcneill	    break;
2159ad247e8Sjmcneill
2169ad247e8Sjmcneill	case 3: /* narrow, component_alpha */
2179ad247e8Sjmcneill	    f = imp->combine_32_ca[op];
2189ad247e8Sjmcneill	    break;
2199ad247e8Sjmcneill	}
2209ad247e8Sjmcneill
2219ad247e8Sjmcneill	if (f)
2229ad247e8Sjmcneill	    return f;
2239ad247e8Sjmcneill
2249ad247e8Sjmcneill	imp = imp->fallback;
2259ad247e8Sjmcneill    }
2269ad247e8Sjmcneill
227f4f78bb6Smrg    /* We should never reach this point */
228f4f78bb6Smrg    _pixman_log_error (FUNC, "No known combine function\n");
229f4f78bb6Smrg    return dummy_combine;
230317c648bSmrg}
231317c648bSmrg
232317c648bSmrgpixman_bool_t
233d0321353Smrg_pixman_implementation_blt (pixman_implementation_t * imp,
234d0321353Smrg                            uint32_t *                src_bits,
235d0321353Smrg                            uint32_t *                dst_bits,
236d0321353Smrg                            int                       src_stride,
237d0321353Smrg                            int                       dst_stride,
238d0321353Smrg                            int                       src_bpp,
239d0321353Smrg                            int                       dst_bpp,
240d0321353Smrg                            int                       src_x,
241d0321353Smrg                            int                       src_y,
2426ba797d6Smrg                            int                       dest_x,
2436ba797d6Smrg                            int                       dest_y,
244d0321353Smrg                            int                       width,
245d0321353Smrg                            int                       height)
246317c648bSmrg{
2479ad247e8Sjmcneill    while (imp)
2489ad247e8Sjmcneill    {
2499ad247e8Sjmcneill	if (imp->blt &&
2509ad247e8Sjmcneill	    (*imp->blt) (imp, src_bits, dst_bits, src_stride, dst_stride,
2519ad247e8Sjmcneill			 src_bpp, dst_bpp, src_x, src_y, dest_x, dest_y,
2529ad247e8Sjmcneill			 width, height))
2539ad247e8Sjmcneill	{
2549ad247e8Sjmcneill	    return TRUE;
2559ad247e8Sjmcneill	}
2569ad247e8Sjmcneill
2579ad247e8Sjmcneill	imp = imp->fallback;
2589ad247e8Sjmcneill    }
2599ad247e8Sjmcneill
2609ad247e8Sjmcneill    return FALSE;
261317c648bSmrg}
262317c648bSmrg
263317c648bSmrgpixman_bool_t
264317c648bSmrg_pixman_implementation_fill (pixman_implementation_t *imp,
265d0321353Smrg                             uint32_t *               bits,
266d0321353Smrg                             int                      stride,
267d0321353Smrg                             int                      bpp,
268d0321353Smrg                             int                      x,
269d0321353Smrg                             int                      y,
270d0321353Smrg                             int                      width,
271d0321353Smrg                             int                      height,
272f4f78bb6Smrg                             uint32_t                 filler)
273317c648bSmrg{
2749ad247e8Sjmcneill    while (imp)
2759ad247e8Sjmcneill    {
2769ad247e8Sjmcneill	if (imp->fill &&
277f4f78bb6Smrg	    ((*imp->fill) (imp, bits, stride, bpp, x, y, width, height, filler)))
2789ad247e8Sjmcneill	{
2799ad247e8Sjmcneill	    return TRUE;
2809ad247e8Sjmcneill	}
2819ad247e8Sjmcneill
2829ad247e8Sjmcneill	imp = imp->fallback;
2839ad247e8Sjmcneill    }
2849ad247e8Sjmcneill
2859ad247e8Sjmcneill    return FALSE;
286317c648bSmrg}
287d0321353Smrg
288de17ff4aSmrgstatic uint32_t *
289de17ff4aSmrgget_scanline_null (pixman_iter_t *iter, const uint32_t *mask)
290953d7d37Smrg{
291de17ff4aSmrg    return NULL;
292de17ff4aSmrg}
293de17ff4aSmrg
294de17ff4aSmrgvoid
295de17ff4aSmrg_pixman_implementation_iter_init (pixman_implementation_t *imp,
296de17ff4aSmrg                                  pixman_iter_t           *iter,
297de17ff4aSmrg                                  pixman_image_t          *image,
298de17ff4aSmrg                                  int                      x,
299de17ff4aSmrg                                  int                      y,
300de17ff4aSmrg                                  int                      width,
301de17ff4aSmrg                                  int                      height,
302de17ff4aSmrg                                  uint8_t                 *buffer,
303de17ff4aSmrg                                  iter_flags_t             iter_flags,
304de17ff4aSmrg                                  uint32_t                 image_flags)
305de17ff4aSmrg{
306de17ff4aSmrg    pixman_format_code_t format;
307de17ff4aSmrg
3086ba797d6Smrg    iter->image = image;
3096ba797d6Smrg    iter->buffer = (uint32_t *)buffer;
3106ba797d6Smrg    iter->x = x;
3116ba797d6Smrg    iter->y = y;
3126ba797d6Smrg    iter->width = width;
3136ba797d6Smrg    iter->height = height;
3149ad247e8Sjmcneill    iter->iter_flags = iter_flags;
3159ad247e8Sjmcneill    iter->image_flags = image_flags;
316de17ff4aSmrg    iter->fini = NULL;
3179ad247e8Sjmcneill
318de17ff4aSmrg    if (!iter->image)
3199ad247e8Sjmcneill    {
320de17ff4aSmrg	iter->get_scanline = get_scanline_null;
321de17ff4aSmrg	return;
3229ad247e8Sjmcneill    }
3236ba797d6Smrg
324de17ff4aSmrg    format = iter->image->common.extended_format_code;
3259ad247e8Sjmcneill
3269ad247e8Sjmcneill    while (imp)
3279ad247e8Sjmcneill    {
328de17ff4aSmrg        if (imp->iter_info)
329de17ff4aSmrg        {
330de17ff4aSmrg            const pixman_iter_info_t *info;
331de17ff4aSmrg
332de17ff4aSmrg            for (info = imp->iter_info; info->format != PIXMAN_null; ++info)
333de17ff4aSmrg            {
334de17ff4aSmrg                if ((info->format == PIXMAN_any || info->format == format) &&
335de17ff4aSmrg                    (info->image_flags & image_flags) == info->image_flags &&
336de17ff4aSmrg                    (info->iter_flags & iter_flags) == info->iter_flags)
337de17ff4aSmrg                {
338de17ff4aSmrg                    iter->get_scanline = info->get_scanline;
339de17ff4aSmrg                    iter->write_back = info->write_back;
340de17ff4aSmrg
341de17ff4aSmrg                    if (info->initializer)
342de17ff4aSmrg                        info->initializer (iter, info);
343de17ff4aSmrg                    return;
344de17ff4aSmrg                }
345de17ff4aSmrg            }
346de17ff4aSmrg        }
347de17ff4aSmrg
348de17ff4aSmrg        imp = imp->fallback;
3499ad247e8Sjmcneill    }
3509ad247e8Sjmcneill}
3519ad247e8Sjmcneill
3529ad247e8Sjmcneillpixman_bool_t
3539ad247e8Sjmcneill_pixman_disabled (const char *name)
3549ad247e8Sjmcneill{
3559ad247e8Sjmcneill    const char *env;
3569ad247e8Sjmcneill
3579ad247e8Sjmcneill    if ((env = getenv ("PIXMAN_DISABLE")))
3589ad247e8Sjmcneill    {
3599ad247e8Sjmcneill	do
3609ad247e8Sjmcneill	{
3619ad247e8Sjmcneill	    const char *end;
3629ad247e8Sjmcneill	    int len;
3639ad247e8Sjmcneill
3649ad247e8Sjmcneill	    if ((end = strchr (env, ' ')))
3659ad247e8Sjmcneill		len = end - env;
3669ad247e8Sjmcneill	    else
3679ad247e8Sjmcneill		len = strlen (env);
3689ad247e8Sjmcneill
3699ad247e8Sjmcneill	    if (strlen (name) == len && strncmp (name, env, len) == 0)
3709ad247e8Sjmcneill	    {
3719ad247e8Sjmcneill		printf ("pixman: Disabled %s implementation\n", name);
3729ad247e8Sjmcneill		return TRUE;
3739ad247e8Sjmcneill	    }
3749ad247e8Sjmcneill
3759ad247e8Sjmcneill	    env += len;
3769ad247e8Sjmcneill	}
3779ad247e8Sjmcneill	while (*env++);
3789ad247e8Sjmcneill    }
3799ad247e8Sjmcneill
3809ad247e8Sjmcneill    return FALSE;
3819ad247e8Sjmcneill}
3829ad247e8Sjmcneill
3836ca29ff0Smrgstatic const pixman_fast_path_t empty_fast_path[] =
3846ca29ff0Smrg{
3856ca29ff0Smrg    { PIXMAN_OP_NONE }
3866ca29ff0Smrg};
3876ca29ff0Smrg
3889ad247e8Sjmcneillpixman_implementation_t *
3899ad247e8Sjmcneill_pixman_choose_implementation (void)
3909ad247e8Sjmcneill{
3919ad247e8Sjmcneill    pixman_implementation_t *imp;
3929ad247e8Sjmcneill
3939ad247e8Sjmcneill    imp = _pixman_implementation_create_general();
3949ad247e8Sjmcneill
3959ad247e8Sjmcneill    if (!_pixman_disabled ("fast"))
3969ad247e8Sjmcneill	imp = _pixman_implementation_create_fast_path (imp);
3979ad247e8Sjmcneill
3989ad247e8Sjmcneill    imp = _pixman_x86_get_implementations (imp);
3999ad247e8Sjmcneill    imp = _pixman_arm_get_implementations (imp);
4009ad247e8Sjmcneill    imp = _pixman_ppc_get_implementations (imp);
4019ad247e8Sjmcneill    imp = _pixman_mips_get_implementations (imp);
4029ad247e8Sjmcneill
4039ad247e8Sjmcneill    imp = _pixman_implementation_create_noop (imp);
4049ad247e8Sjmcneill
4056ca29ff0Smrg    if (_pixman_disabled ("wholeops"))
4066ca29ff0Smrg    {
4076ca29ff0Smrg        pixman_implementation_t *cur;
4086ca29ff0Smrg
4096ca29ff0Smrg        /* Disable all whole-operation paths except the general one,
4106ca29ff0Smrg         * so that optimized iterators are used as much as possible.
4116ca29ff0Smrg         */
4126ca29ff0Smrg        for (cur = imp; cur->fallback; cur = cur->fallback)
4136ca29ff0Smrg            cur->fast_paths = empty_fast_path;
4146ca29ff0Smrg    }
4156ca29ff0Smrg
4169ad247e8Sjmcneill    return imp;
417953d7d37Smrg}
418