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 2514b11b2bSmrg#include <pixman-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 6614b11b2bSmrgPIXMAN_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); 40214b11b2bSmrg imp = _pixman_riscv_get_implementations (imp); 4039ad247e8Sjmcneill 4049ad247e8Sjmcneill imp = _pixman_implementation_create_noop (imp); 4059ad247e8Sjmcneill 4066ca29ff0Smrg if (_pixman_disabled ("wholeops")) 4076ca29ff0Smrg { 4086ca29ff0Smrg pixman_implementation_t *cur; 4096ca29ff0Smrg 4106ca29ff0Smrg /* Disable all whole-operation paths except the general one, 4116ca29ff0Smrg * so that optimized iterators are used as much as possible. 4126ca29ff0Smrg */ 4136ca29ff0Smrg for (cur = imp; cur->fallback; cur = cur->fallback) 4146ca29ff0Smrg cur->fast_paths = empty_fast_path; 4156ca29ff0Smrg } 4166ca29ff0Smrg 4179ad247e8Sjmcneill return imp; 418953d7d37Smrg} 419