Blame pixman/pixman-implementation.c

Packit 030a23
/*
Packit 030a23
 * Copyright © 2009 Red Hat, Inc.
Packit 030a23
 *
Packit 030a23
 * Permission to use, copy, modify, distribute, and sell this software and its
Packit 030a23
 * documentation for any purpose is hereby granted without fee, provided that
Packit 030a23
 * the above copyright notice appear in all copies and that both that
Packit 030a23
 * copyright notice and this permission notice appear in supporting
Packit 030a23
 * documentation, and that the name of Red Hat not be used in advertising or
Packit 030a23
 * publicity pertaining to distribution of the software without specific,
Packit 030a23
 * written prior permission.  Red Hat makes no representations about the
Packit 030a23
 * suitability of this software for any purpose.  It is provided "as is"
Packit 030a23
 * without express or implied warranty.
Packit 030a23
 *
Packit 030a23
 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
Packit 030a23
 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
Packit 030a23
 * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
Packit 030a23
 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
Packit 030a23
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
Packit 030a23
 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
Packit 030a23
 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
Packit 030a23
 * SOFTWARE.
Packit 030a23
 */
Packit 030a23
Packit 030a23
#ifdef HAVE_CONFIG_H
Packit 030a23
#include <config.h>
Packit 030a23
#endif
Packit 030a23
#include <stdlib.h>
Packit 030a23
#include "pixman-private.h"
Packit 030a23
Packit 030a23
pixman_implementation_t *
Packit 030a23
_pixman_implementation_create (pixman_implementation_t *fallback,
Packit 030a23
			       const pixman_fast_path_t *fast_paths)
Packit 030a23
{
Packit 030a23
    pixman_implementation_t *imp;
Packit 030a23
Packit 030a23
    assert (fast_paths);
Packit 030a23
Packit 030a23
    if ((imp = malloc (sizeof (pixman_implementation_t))))
Packit 030a23
    {
Packit 030a23
	pixman_implementation_t *d;
Packit 030a23
Packit 030a23
	memset (imp, 0, sizeof *imp);
Packit 030a23
Packit 030a23
	imp->fallback = fallback;
Packit 030a23
	imp->fast_paths = fast_paths;
Packit 030a23
	
Packit 030a23
	/* Make sure the whole fallback chain has the right toplevel */
Packit 030a23
	for (d = imp; d != NULL; d = d->fallback)
Packit 030a23
	    d->toplevel = imp;
Packit 030a23
    }
Packit 030a23
Packit 030a23
    return imp;
Packit 030a23
}
Packit 030a23
Packit 030a23
#define N_CACHED_FAST_PATHS 8
Packit 030a23
Packit 030a23
typedef struct
Packit 030a23
{
Packit 030a23
    struct
Packit 030a23
    {
Packit 030a23
	pixman_implementation_t *	imp;
Packit 030a23
	pixman_fast_path_t		fast_path;
Packit 030a23
    } cache [N_CACHED_FAST_PATHS];
Packit 030a23
} cache_t;
Packit 030a23
Packit 030a23
PIXMAN_DEFINE_THREAD_LOCAL (cache_t, fast_path_cache);
Packit 030a23
Packit 030a23
static void
Packit 030a23
dummy_composite_rect (pixman_implementation_t *imp,
Packit 030a23
		      pixman_composite_info_t *info)
Packit 030a23
{
Packit 030a23
}
Packit 030a23
Packit 030a23
void
Packit 030a23
_pixman_implementation_lookup_composite (pixman_implementation_t  *toplevel,
Packit 030a23
					 pixman_op_t               op,
Packit 030a23
					 pixman_format_code_t      src_format,
Packit 030a23
					 uint32_t                  src_flags,
Packit 030a23
					 pixman_format_code_t      mask_format,
Packit 030a23
					 uint32_t                  mask_flags,
Packit 030a23
					 pixman_format_code_t      dest_format,
Packit 030a23
					 uint32_t                  dest_flags,
Packit 030a23
					 pixman_implementation_t **out_imp,
Packit 030a23
					 pixman_composite_func_t  *out_func)
Packit 030a23
{
Packit 030a23
    pixman_implementation_t *imp;
Packit 030a23
    cache_t *cache;
Packit 030a23
    int i;
Packit 030a23
Packit 030a23
    /* Check cache for fast paths */
Packit 030a23
    cache = PIXMAN_GET_THREAD_LOCAL (fast_path_cache);
Packit 030a23
Packit 030a23
    for (i = 0; i < N_CACHED_FAST_PATHS; ++i)
Packit 030a23
    {
Packit 030a23
	const pixman_fast_path_t *info = &(cache->cache[i].fast_path);
Packit 030a23
Packit 030a23
	/* Note that we check for equality here, not whether
Packit 030a23
	 * the cached fast path matches. This is to prevent
Packit 030a23
	 * us from selecting an overly general fast path
Packit 030a23
	 * when a more specific one would work.
Packit 030a23
	 */
Packit 030a23
	if (info->op == op			&&
Packit 030a23
	    info->src_format == src_format	&&
Packit 030a23
	    info->mask_format == mask_format	&&
Packit 030a23
	    info->dest_format == dest_format	&&
Packit 030a23
	    info->src_flags == src_flags	&&
Packit 030a23
	    info->mask_flags == mask_flags	&&
Packit 030a23
	    info->dest_flags == dest_flags	&&
Packit 030a23
	    info->func)
Packit 030a23
	{
Packit 030a23
	    *out_imp = cache->cache[i].imp;
Packit 030a23
	    *out_func = cache->cache[i].fast_path.func;
Packit 030a23
Packit 030a23
	    goto update_cache;
Packit 030a23
	}
Packit 030a23
    }
Packit 030a23
Packit 030a23
    for (imp = toplevel; imp != NULL; imp = imp->fallback)
Packit 030a23
    {
Packit 030a23
	const pixman_fast_path_t *info = imp->fast_paths;
Packit 030a23
Packit 030a23
	while (info->op != PIXMAN_OP_NONE)
Packit 030a23
	{
Packit 030a23
	    if ((info->op == op || info->op == PIXMAN_OP_any)		&&
Packit 030a23
		/* Formats */
Packit 030a23
		((info->src_format == src_format) ||
Packit 030a23
		 (info->src_format == PIXMAN_any))			&&
Packit 030a23
		((info->mask_format == mask_format) ||
Packit 030a23
		 (info->mask_format == PIXMAN_any))			&&
Packit 030a23
		((info->dest_format == dest_format) ||
Packit 030a23
		 (info->dest_format == PIXMAN_any))			&&
Packit 030a23
		/* Flags */
Packit 030a23
		(info->src_flags & src_flags) == info->src_flags	&&
Packit 030a23
		(info->mask_flags & mask_flags) == info->mask_flags	&&
Packit 030a23
		(info->dest_flags & dest_flags) == info->dest_flags)
Packit 030a23
	    {
Packit 030a23
		*out_imp = imp;
Packit 030a23
		*out_func = info->func;
Packit 030a23
Packit 030a23
		/* Set i to the last spot in the cache so that the
Packit 030a23
		 * move-to-front code below will work
Packit 030a23
		 */
Packit 030a23
		i = N_CACHED_FAST_PATHS - 1;
Packit 030a23
Packit 030a23
		goto update_cache;
Packit 030a23
	    }
Packit 030a23
Packit 030a23
	    ++info;
Packit 030a23
	}
Packit 030a23
    }
Packit 030a23
Packit 030a23
    /* We should never reach this point */
Packit 030a23
    _pixman_log_error (
Packit 030a23
        FUNC,
Packit 030a23
        "No composite function found\n"
Packit 030a23
        "\n"
Packit 030a23
        "The most likely cause of this is that this system has issues with\n"
Packit 030a23
        "thread local storage\n");
Packit 030a23
Packit 030a23
    *out_imp = NULL;
Packit 030a23
    *out_func = dummy_composite_rect;
Packit 030a23
    return;
Packit 030a23
Packit 030a23
update_cache:
Packit 030a23
    if (i)
Packit 030a23
    {
Packit 030a23
	while (i--)
Packit 030a23
	    cache->cache[i + 1] = cache->cache[i];
Packit 030a23
Packit 030a23
	cache->cache[0].imp = *out_imp;
Packit 030a23
	cache->cache[0].fast_path.op = op;
Packit 030a23
	cache->cache[0].fast_path.src_format = src_format;
Packit 030a23
	cache->cache[0].fast_path.src_flags = src_flags;
Packit 030a23
	cache->cache[0].fast_path.mask_format = mask_format;
Packit 030a23
	cache->cache[0].fast_path.mask_flags = mask_flags;
Packit 030a23
	cache->cache[0].fast_path.dest_format = dest_format;
Packit 030a23
	cache->cache[0].fast_path.dest_flags = dest_flags;
Packit 030a23
	cache->cache[0].fast_path.func = *out_func;
Packit 030a23
    }
Packit 030a23
}
Packit 030a23
Packit 030a23
static void
Packit 030a23
dummy_combine (pixman_implementation_t *imp,
Packit 030a23
	       pixman_op_t              op,
Packit 030a23
	       uint32_t *               pd,
Packit 030a23
	       const uint32_t *         ps,
Packit 030a23
	       const uint32_t *         pm,
Packit 030a23
	       int                      w)
Packit 030a23
{
Packit 030a23
}
Packit 030a23
Packit 030a23
pixman_combine_32_func_t
Packit 030a23
_pixman_implementation_lookup_combiner (pixman_implementation_t *imp,
Packit 030a23
					pixman_op_t		 op,
Packit 030a23
					pixman_bool_t		 component_alpha,
Packit 030a23
					pixman_bool_t		 narrow)
Packit 030a23
{
Packit 030a23
    while (imp)
Packit 030a23
    {
Packit 030a23
	pixman_combine_32_func_t f = NULL;
Packit 030a23
Packit 030a23
	switch ((narrow << 1) | component_alpha)
Packit 030a23
	{
Packit 030a23
	case 0: /* not narrow, not component alpha */
Packit 030a23
	    f = (pixman_combine_32_func_t)imp->combine_float[op];
Packit 030a23
	    break;
Packit 030a23
	    
Packit 030a23
	case 1: /* not narrow, component_alpha */
Packit 030a23
	    f = (pixman_combine_32_func_t)imp->combine_float_ca[op];
Packit 030a23
	    break;
Packit 030a23
Packit 030a23
	case 2: /* narrow, not component alpha */
Packit 030a23
	    f = imp->combine_32[op];
Packit 030a23
	    break;
Packit 030a23
Packit 030a23
	case 3: /* narrow, component_alpha */
Packit 030a23
	    f = imp->combine_32_ca[op];
Packit 030a23
	    break;
Packit 030a23
	}
Packit 030a23
Packit 030a23
	if (f)
Packit 030a23
	    return f;
Packit 030a23
Packit 030a23
	imp = imp->fallback;
Packit 030a23
    }
Packit 030a23
Packit 030a23
    /* We should never reach this point */
Packit 030a23
    _pixman_log_error (FUNC, "No known combine function\n");
Packit 030a23
    return dummy_combine;
Packit 030a23
}
Packit 030a23
Packit 030a23
pixman_bool_t
Packit 030a23
_pixman_implementation_blt (pixman_implementation_t * imp,
Packit 030a23
                            uint32_t *                src_bits,
Packit 030a23
                            uint32_t *                dst_bits,
Packit 030a23
                            int                       src_stride,
Packit 030a23
                            int                       dst_stride,
Packit 030a23
                            int                       src_bpp,
Packit 030a23
                            int                       dst_bpp,
Packit 030a23
                            int                       src_x,
Packit 030a23
                            int                       src_y,
Packit 030a23
                            int                       dest_x,
Packit 030a23
                            int                       dest_y,
Packit 030a23
                            int                       width,
Packit 030a23
                            int                       height)
Packit 030a23
{
Packit 030a23
    while (imp)
Packit 030a23
    {
Packit 030a23
	if (imp->blt &&
Packit 030a23
	    (*imp->blt) (imp, src_bits, dst_bits, src_stride, dst_stride,
Packit 030a23
			 src_bpp, dst_bpp, src_x, src_y, dest_x, dest_y,
Packit 030a23
			 width, height))
Packit 030a23
	{
Packit 030a23
	    return TRUE;
Packit 030a23
	}
Packit 030a23
Packit 030a23
	imp = imp->fallback;
Packit 030a23
    }
Packit 030a23
Packit 030a23
    return FALSE;
Packit 030a23
}
Packit 030a23
Packit 030a23
pixman_bool_t
Packit 030a23
_pixman_implementation_fill (pixman_implementation_t *imp,
Packit 030a23
                             uint32_t *               bits,
Packit 030a23
                             int                      stride,
Packit 030a23
                             int                      bpp,
Packit 030a23
                             int                      x,
Packit 030a23
                             int                      y,
Packit 030a23
                             int                      width,
Packit 030a23
                             int                      height,
Packit 030a23
                             uint32_t                 filler)
Packit 030a23
{
Packit 030a23
    while (imp)
Packit 030a23
    {
Packit 030a23
	if (imp->fill &&
Packit 030a23
	    ((*imp->fill) (imp, bits, stride, bpp, x, y, width, height, filler)))
Packit 030a23
	{
Packit 030a23
	    return TRUE;
Packit 030a23
	}
Packit 030a23
Packit 030a23
	imp = imp->fallback;
Packit 030a23
    }
Packit 030a23
Packit 030a23
    return FALSE;
Packit 030a23
}
Packit 030a23
Packit 030a23
static uint32_t *
Packit 030a23
get_scanline_null (pixman_iter_t *iter, const uint32_t *mask)
Packit 030a23
{
Packit 030a23
    return NULL;
Packit 030a23
}
Packit 030a23
Packit 030a23
void
Packit 030a23
_pixman_implementation_iter_init (pixman_implementation_t *imp,
Packit 030a23
                                  pixman_iter_t           *iter,
Packit 030a23
                                  pixman_image_t          *image,
Packit 030a23
                                  int                      x,
Packit 030a23
                                  int                      y,
Packit 030a23
                                  int                      width,
Packit 030a23
                                  int                      height,
Packit 030a23
                                  uint8_t                 *buffer,
Packit 030a23
                                  iter_flags_t             iter_flags,
Packit 030a23
                                  uint32_t                 image_flags)
Packit 030a23
{
Packit 030a23
    pixman_format_code_t format;
Packit 030a23
Packit 030a23
    iter->image = image;
Packit 030a23
    iter->buffer = (uint32_t *)buffer;
Packit 030a23
    iter->x = x;
Packit 030a23
    iter->y = y;
Packit 030a23
    iter->width = width;
Packit 030a23
    iter->height = height;
Packit 030a23
    iter->iter_flags = iter_flags;
Packit 030a23
    iter->image_flags = image_flags;
Packit 030a23
    iter->fini = NULL;
Packit 030a23
Packit 030a23
    if (!iter->image)
Packit 030a23
    {
Packit 030a23
	iter->get_scanline = get_scanline_null;
Packit 030a23
	return;
Packit 030a23
    }
Packit 030a23
Packit 030a23
    format = iter->image->common.extended_format_code;
Packit 030a23
Packit 030a23
    while (imp)
Packit 030a23
    {
Packit 030a23
        if (imp->iter_info)
Packit 030a23
        {
Packit 030a23
            const pixman_iter_info_t *info;
Packit 030a23
Packit 030a23
            for (info = imp->iter_info; info->format != PIXMAN_null; ++info)
Packit 030a23
            {
Packit 030a23
                if ((info->format == PIXMAN_any || info->format == format) &&
Packit 030a23
                    (info->image_flags & image_flags) == info->image_flags &&
Packit 030a23
                    (info->iter_flags & iter_flags) == info->iter_flags)
Packit 030a23
                {
Packit 030a23
                    iter->get_scanline = info->get_scanline;
Packit 030a23
                    iter->write_back = info->write_back;
Packit 030a23
Packit 030a23
                    if (info->initializer)
Packit 030a23
                        info->initializer (iter, info);
Packit 030a23
                    return;
Packit 030a23
                }
Packit 030a23
            }
Packit 030a23
        }
Packit 030a23
Packit 030a23
        imp = imp->fallback;
Packit 030a23
    }
Packit 030a23
}
Packit 030a23
Packit 030a23
pixman_bool_t
Packit 030a23
_pixman_disabled (const char *name)
Packit 030a23
{
Packit 030a23
    const char *env;
Packit 030a23
Packit 030a23
    if ((env = getenv ("PIXMAN_DISABLE")))
Packit 030a23
    {
Packit 030a23
	do
Packit 030a23
	{
Packit 030a23
	    const char *end;
Packit 030a23
	    int len;
Packit 030a23
Packit 030a23
	    if ((end = strchr (env, ' ')))
Packit 030a23
		len = end - env;
Packit 030a23
	    else
Packit 030a23
		len = strlen (env);
Packit 030a23
Packit 030a23
	    if (strlen (name) == len && strncmp (name, env, len) == 0)
Packit 030a23
	    {
Packit 030a23
		printf ("pixman: Disabled %s implementation\n", name);
Packit 030a23
		return TRUE;
Packit 030a23
	    }
Packit 030a23
Packit 030a23
	    env += len;
Packit 030a23
	}
Packit 030a23
	while (*env++);
Packit 030a23
    }
Packit 030a23
Packit 030a23
    return FALSE;
Packit 030a23
}
Packit 030a23
Packit 030a23
static const pixman_fast_path_t empty_fast_path[] =
Packit 030a23
{
Packit 030a23
    { PIXMAN_OP_NONE }
Packit 030a23
};
Packit 030a23
Packit 030a23
pixman_implementation_t *
Packit 030a23
_pixman_choose_implementation (void)
Packit 030a23
{
Packit 030a23
    pixman_implementation_t *imp;
Packit 030a23
Packit 030a23
    imp = _pixman_implementation_create_general();
Packit 030a23
Packit 030a23
    if (!_pixman_disabled ("fast"))
Packit 030a23
	imp = _pixman_implementation_create_fast_path (imp);
Packit 030a23
Packit 030a23
    imp = _pixman_x86_get_implementations (imp);
Packit 030a23
    imp = _pixman_arm_get_implementations (imp);
Packit 030a23
    imp = _pixman_ppc_get_implementations (imp);
Packit 030a23
    imp = _pixman_mips_get_implementations (imp);
Packit 030a23
Packit 030a23
    imp = _pixman_implementation_create_noop (imp);
Packit 030a23
Packit 030a23
    if (_pixman_disabled ("wholeops"))
Packit 030a23
    {
Packit 030a23
        pixman_implementation_t *cur;
Packit 030a23
Packit 030a23
        /* Disable all whole-operation paths except the general one,
Packit 030a23
         * so that optimized iterators are used as much as possible.
Packit 030a23
         */
Packit 030a23
        for (cur = imp; cur->fallback; cur = cur->fallback)
Packit 030a23
            cur->fast_paths = empty_fast_path;
Packit 030a23
    }
Packit 030a23
Packit 030a23
    return imp;
Packit 030a23
}