1 /* 2 * Copyright 2009 Red Hat, Inc. 3 * 4 * Permission to use, copy, modify, distribute, and sell this software and its 5 * documentation for any purpose is hereby granted without fee, provided that 6 * the above copyright notice appear in all copies and that both that 7 * copyright notice and this permission notice appear in supporting 8 * documentation, and that the name of Red Hat not be used in advertising or 9 * publicity pertaining to distribution of the software without specific, 10 * written prior permission. Red Hat makes no representations about the 11 * suitability of this software for any purpose. It is provided "as is" 12 * without express or implied warranty. 13 * 14 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS 15 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND 16 * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY 17 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 18 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN 19 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 20 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 21 * SOFTWARE. 22 */ 23 24 #ifdef HAVE_CONFIG_H 25 #include <config.h> 26 #endif 27 #include <stdlib.h> 28 #include "pixman-private.h" 29 30 pixman_implementation_t * 31 _pixman_implementation_create (pixman_implementation_t *fallback, 32 const pixman_fast_path_t *fast_paths) 33 { 34 pixman_implementation_t *imp; 35 36 assert (fast_paths); 37 38 if ((imp = malloc (sizeof (pixman_implementation_t)))) 39 { 40 pixman_implementation_t *d; 41 42 memset (imp, 0, sizeof *imp); 43 44 imp->fallback = fallback; 45 imp->fast_paths = fast_paths; 46 47 /* Make sure the whole fallback chain has the right toplevel */ 48 for (d = imp; d != NULL; d = d->fallback) 49 d->toplevel = imp; 50 } 51 52 return imp; 53 } 54 55 #define N_CACHED_FAST_PATHS 8 56 57 typedef struct 58 { 59 struct 60 { 61 pixman_implementation_t * imp; 62 pixman_fast_path_t fast_path; 63 } cache [N_CACHED_FAST_PATHS]; 64 } cache_t; 65 66 PIXMAN_DEFINE_THREAD_LOCAL (cache_t, fast_path_cache); 67 68 static void 69 dummy_composite_rect (pixman_implementation_t *imp, 70 pixman_composite_info_t *info) 71 { 72 } 73 74 void 75 _pixman_implementation_lookup_composite (pixman_implementation_t *toplevel, 76 pixman_op_t op, 77 pixman_format_code_t src_format, 78 uint32_t src_flags, 79 pixman_format_code_t mask_format, 80 uint32_t mask_flags, 81 pixman_format_code_t dest_format, 82 uint32_t dest_flags, 83 pixman_implementation_t **out_imp, 84 pixman_composite_func_t *out_func) 85 { 86 pixman_implementation_t *imp; 87 cache_t *cache; 88 int i; 89 90 /* Check cache for fast paths */ 91 cache = PIXMAN_GET_THREAD_LOCAL (fast_path_cache); 92 93 for (i = 0; i < N_CACHED_FAST_PATHS; ++i) 94 { 95 const pixman_fast_path_t *info = &(cache->cache[i].fast_path); 96 97 /* Note that we check for equality here, not whether 98 * the cached fast path matches. This is to prevent 99 * us from selecting an overly general fast path 100 * when a more specific one would work. 101 */ 102 if (info->op == op && 103 info->src_format == src_format && 104 info->mask_format == mask_format && 105 info->dest_format == dest_format && 106 info->src_flags == src_flags && 107 info->mask_flags == mask_flags && 108 info->dest_flags == dest_flags && 109 info->func) 110 { 111 *out_imp = cache->cache[i].imp; 112 *out_func = cache->cache[i].fast_path.func; 113 114 goto update_cache; 115 } 116 } 117 118 for (imp = toplevel; imp != NULL; imp = imp->fallback) 119 { 120 const pixman_fast_path_t *info = imp->fast_paths; 121 122 while (info->op != PIXMAN_OP_NONE) 123 { 124 if ((info->op == op || info->op == PIXMAN_OP_any) && 125 /* Formats */ 126 ((info->src_format == src_format) || 127 (info->src_format == PIXMAN_any)) && 128 ((info->mask_format == mask_format) || 129 (info->mask_format == PIXMAN_any)) && 130 ((info->dest_format == dest_format) || 131 (info->dest_format == PIXMAN_any)) && 132 /* Flags */ 133 (info->src_flags & src_flags) == info->src_flags && 134 (info->mask_flags & mask_flags) == info->mask_flags && 135 (info->dest_flags & dest_flags) == info->dest_flags) 136 { 137 *out_imp = imp; 138 *out_func = info->func; 139 140 /* Set i to the last spot in the cache so that the 141 * move-to-front code below will work 142 */ 143 i = N_CACHED_FAST_PATHS - 1; 144 145 goto update_cache; 146 } 147 148 ++info; 149 } 150 } 151 152 /* We should never reach this point */ 153 _pixman_log_error ( 154 FUNC, 155 "No composite function found\n" 156 "\n" 157 "The most likely cause of this is that this system has issues with\n" 158 "thread local storage\n"); 159 160 *out_imp = NULL; 161 *out_func = dummy_composite_rect; 162 return; 163 164 update_cache: 165 if (i) 166 { 167 while (i--) 168 cache->cache[i + 1] = cache->cache[i]; 169 170 cache->cache[0].imp = *out_imp; 171 cache->cache[0].fast_path.op = op; 172 cache->cache[0].fast_path.src_format = src_format; 173 cache->cache[0].fast_path.src_flags = src_flags; 174 cache->cache[0].fast_path.mask_format = mask_format; 175 cache->cache[0].fast_path.mask_flags = mask_flags; 176 cache->cache[0].fast_path.dest_format = dest_format; 177 cache->cache[0].fast_path.dest_flags = dest_flags; 178 cache->cache[0].fast_path.func = *out_func; 179 } 180 } 181 182 static void 183 dummy_combine (pixman_implementation_t *imp, 184 pixman_op_t op, 185 uint32_t * pd, 186 const uint32_t * ps, 187 const uint32_t * pm, 188 int w) 189 { 190 } 191 192 pixman_combine_32_func_t 193 _pixman_implementation_lookup_combiner (pixman_implementation_t *imp, 194 pixman_op_t op, 195 pixman_bool_t component_alpha, 196 pixman_bool_t narrow) 197 { 198 while (imp) 199 { 200 pixman_combine_32_func_t f = NULL; 201 202 switch ((narrow << 1) | component_alpha) 203 { 204 case 0: /* not narrow, not component alpha */ 205 f = (pixman_combine_32_func_t)imp->combine_float[op]; 206 break; 207 208 case 1: /* not narrow, component_alpha */ 209 f = (pixman_combine_32_func_t)imp->combine_float_ca[op]; 210 break; 211 212 case 2: /* narrow, not component alpha */ 213 f = imp->combine_32[op]; 214 break; 215 216 case 3: /* narrow, component_alpha */ 217 f = imp->combine_32_ca[op]; 218 break; 219 } 220 221 if (f) 222 return f; 223 224 imp = imp->fallback; 225 } 226 227 /* We should never reach this point */ 228 _pixman_log_error (FUNC, "No known combine function\n"); 229 return dummy_combine; 230 } 231 232 pixman_bool_t 233 _pixman_implementation_blt (pixman_implementation_t * imp, 234 uint32_t * src_bits, 235 uint32_t * dst_bits, 236 int src_stride, 237 int dst_stride, 238 int src_bpp, 239 int dst_bpp, 240 int src_x, 241 int src_y, 242 int dest_x, 243 int dest_y, 244 int width, 245 int height) 246 { 247 while (imp) 248 { 249 if (imp->blt && 250 (*imp->blt) (imp, src_bits, dst_bits, src_stride, dst_stride, 251 src_bpp, dst_bpp, src_x, src_y, dest_x, dest_y, 252 width, height)) 253 { 254 return TRUE; 255 } 256 257 imp = imp->fallback; 258 } 259 260 return FALSE; 261 } 262 263 pixman_bool_t 264 _pixman_implementation_fill (pixman_implementation_t *imp, 265 uint32_t * bits, 266 int stride, 267 int bpp, 268 int x, 269 int y, 270 int width, 271 int height, 272 uint32_t filler) 273 { 274 while (imp) 275 { 276 if (imp->fill && 277 ((*imp->fill) (imp, bits, stride, bpp, x, y, width, height, filler))) 278 { 279 return TRUE; 280 } 281 282 imp = imp->fallback; 283 } 284 285 return FALSE; 286 } 287 288 pixman_bool_t 289 _pixman_implementation_src_iter_init (pixman_implementation_t *imp, 290 pixman_iter_t *iter, 291 pixman_image_t *image, 292 int x, 293 int y, 294 int width, 295 int height, 296 uint8_t *buffer, 297 iter_flags_t iter_flags, 298 uint32_t image_flags) 299 { 300 iter->image = image; 301 iter->buffer = (uint32_t *)buffer; 302 iter->x = x; 303 iter->y = y; 304 iter->width = width; 305 iter->height = height; 306 iter->iter_flags = iter_flags; 307 iter->image_flags = image_flags; 308 309 while (imp) 310 { 311 if (imp->src_iter_init && (*imp->src_iter_init) (imp, iter)) 312 return TRUE; 313 314 imp = imp->fallback; 315 } 316 317 return FALSE; 318 } 319 320 pixman_bool_t 321 _pixman_implementation_dest_iter_init (pixman_implementation_t *imp, 322 pixman_iter_t *iter, 323 pixman_image_t *image, 324 int x, 325 int y, 326 int width, 327 int height, 328 uint8_t *buffer, 329 iter_flags_t iter_flags, 330 uint32_t image_flags) 331 { 332 iter->image = image; 333 iter->buffer = (uint32_t *)buffer; 334 iter->x = x; 335 iter->y = y; 336 iter->width = width; 337 iter->height = height; 338 iter->iter_flags = iter_flags; 339 iter->image_flags = image_flags; 340 341 while (imp) 342 { 343 if (imp->dest_iter_init && (*imp->dest_iter_init) (imp, iter)) 344 return TRUE; 345 346 imp = imp->fallback; 347 } 348 349 return FALSE; 350 } 351 352 pixman_bool_t 353 _pixman_disabled (const char *name) 354 { 355 const char *env; 356 357 if ((env = getenv ("PIXMAN_DISABLE"))) 358 { 359 do 360 { 361 const char *end; 362 int len; 363 364 if ((end = strchr (env, ' '))) 365 len = end - env; 366 else 367 len = strlen (env); 368 369 if (strlen (name) == len && strncmp (name, env, len) == 0) 370 { 371 printf ("pixman: Disabled %s implementation\n", name); 372 return TRUE; 373 } 374 375 env += len; 376 } 377 while (*env++); 378 } 379 380 return FALSE; 381 } 382 383 pixman_implementation_t * 384 _pixman_choose_implementation (void) 385 { 386 pixman_implementation_t *imp; 387 388 imp = _pixman_implementation_create_general(); 389 390 if (!_pixman_disabled ("fast")) 391 imp = _pixman_implementation_create_fast_path (imp); 392 393 imp = _pixman_x86_get_implementations (imp); 394 imp = _pixman_arm_get_implementations (imp); 395 imp = _pixman_ppc_get_implementations (imp); 396 imp = _pixman_mips_get_implementations (imp); 397 398 imp = _pixman_implementation_create_noop (imp); 399 400 return imp; 401 } 402