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