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