pixman-general.c revision 6ca29ff0
1/* 2 * Copyright © 2009 Red Hat, Inc. 3 * Copyright © 2000 SuSE, Inc. 4 * Copyright © 2007 Red Hat, Inc. 5 * Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc. 6 * 2005 Lars Knoll & Zack Rusin, Trolltech 7 * 2008 Aaron Plattner, NVIDIA Corporation 8 * 9 * Permission to use, copy, modify, distribute, and sell this software and its 10 * documentation for any purpose is hereby granted without fee, provided that 11 * the above copyright notice appear in all copies and that both that 12 * copyright notice and this permission notice appear in supporting 13 * documentation, and that the name of Red Hat not be used in advertising or 14 * publicity pertaining to distribution of the software without specific, 15 * written prior permission. Red Hat makes no representations about the 16 * suitability of this software for any purpose. It is provided "as is" 17 * without express or implied warranty. 18 * 19 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS 20 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND 21 * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 23 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN 24 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 25 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 26 * SOFTWARE. 27 */ 28#ifdef HAVE_CONFIG_H 29#include <config.h> 30#endif 31#include <stdlib.h> 32#include <string.h> 33#include <math.h> 34#include <limits.h> 35#include <stdio.h> 36#include <stdlib.h> 37#include <string.h> 38#include "pixman-private.h" 39 40static void 41general_iter_init (pixman_iter_t *iter, const pixman_iter_info_t *info) 42{ 43 pixman_image_t *image = iter->image; 44 45 switch (image->type) 46 { 47 case BITS: 48 if ((iter->iter_flags & ITER_SRC) == ITER_SRC) 49 _pixman_bits_image_src_iter_init (image, iter); 50 else 51 _pixman_bits_image_dest_iter_init (image, iter); 52 break; 53 54 case LINEAR: 55 _pixman_linear_gradient_iter_init (image, iter); 56 break; 57 58 case RADIAL: 59 _pixman_radial_gradient_iter_init (image, iter); 60 break; 61 62 case CONICAL: 63 _pixman_conical_gradient_iter_init (image, iter); 64 break; 65 66 case SOLID: 67 _pixman_log_error (FUNC, "Solid image not handled by noop"); 68 break; 69 70 default: 71 _pixman_log_error (FUNC, "Pixman bug: unknown image type\n"); 72 break; 73 } 74} 75 76static const pixman_iter_info_t general_iters[] = 77{ 78 { PIXMAN_any, 0, 0, general_iter_init, NULL, NULL }, 79 { PIXMAN_null }, 80}; 81 82typedef struct op_info_t op_info_t; 83struct op_info_t 84{ 85 uint8_t src, dst; 86}; 87 88#define ITER_IGNORE_BOTH \ 89 (ITER_IGNORE_ALPHA | ITER_IGNORE_RGB | ITER_LOCALIZED_ALPHA) 90 91static const op_info_t op_flags[PIXMAN_N_OPERATORS] = 92{ 93 /* Src Dst */ 94 { ITER_IGNORE_BOTH, ITER_IGNORE_BOTH }, /* CLEAR */ 95 { ITER_LOCALIZED_ALPHA, ITER_IGNORE_BOTH }, /* SRC */ 96 { ITER_IGNORE_BOTH, ITER_LOCALIZED_ALPHA }, /* DST */ 97 { 0, ITER_LOCALIZED_ALPHA }, /* OVER */ 98 { ITER_LOCALIZED_ALPHA, 0 }, /* OVER_REVERSE */ 99 { ITER_LOCALIZED_ALPHA, ITER_IGNORE_RGB }, /* IN */ 100 { ITER_IGNORE_RGB, ITER_LOCALIZED_ALPHA }, /* IN_REVERSE */ 101 { ITER_LOCALIZED_ALPHA, ITER_IGNORE_RGB }, /* OUT */ 102 { ITER_IGNORE_RGB, ITER_LOCALIZED_ALPHA }, /* OUT_REVERSE */ 103 { 0, 0 }, /* ATOP */ 104 { 0, 0 }, /* ATOP_REVERSE */ 105 { 0, 0 }, /* XOR */ 106 { ITER_LOCALIZED_ALPHA, ITER_LOCALIZED_ALPHA }, /* ADD */ 107 { 0, 0 }, /* SATURATE */ 108}; 109 110#define SCANLINE_BUFFER_LENGTH 8192 111 112static pixman_bool_t 113operator_needs_division (pixman_op_t op) 114{ 115 static const uint8_t needs_division[] = 116 { 117 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, /* SATURATE */ 118 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, /* DISJOINT */ 119 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, /* CONJOINT */ 120 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, /* blend ops */ 121 }; 122 123 return needs_division[op]; 124} 125 126static void 127general_composite_rect (pixman_implementation_t *imp, 128 pixman_composite_info_t *info) 129{ 130 PIXMAN_COMPOSITE_ARGS (info); 131 uint8_t stack_scanline_buffer[3 * SCANLINE_BUFFER_LENGTH]; 132 uint8_t *scanline_buffer = (uint8_t *) stack_scanline_buffer; 133 uint8_t *src_buffer, *mask_buffer, *dest_buffer; 134 pixman_iter_t src_iter, mask_iter, dest_iter; 135 pixman_combine_32_func_t compose; 136 pixman_bool_t component_alpha; 137 iter_flags_t width_flag, src_iter_flags; 138 int Bpp; 139 int i; 140 141 if ((src_image->common.flags & FAST_PATH_NARROW_FORMAT) && 142 (!mask_image || mask_image->common.flags & FAST_PATH_NARROW_FORMAT) && 143 (dest_image->common.flags & FAST_PATH_NARROW_FORMAT) && 144 !(operator_needs_division (op))) 145 { 146 width_flag = ITER_NARROW; 147 Bpp = 4; 148 } 149 else 150 { 151 width_flag = ITER_WIDE; 152 Bpp = 16; 153 } 154 155#define ALIGN(addr) \ 156 ((uint8_t *)((((uintptr_t)(addr)) + 15) & (~15))) 157 158 if (width <= 0 || _pixman_multiply_overflows_int (width, Bpp * 3)) 159 return; 160 161 if (width * Bpp * 3 > sizeof (stack_scanline_buffer) - 15 * 3) 162 { 163 scanline_buffer = pixman_malloc_ab_plus_c (width, Bpp * 3, 15 * 3); 164 165 if (!scanline_buffer) 166 return; 167 } 168 169 src_buffer = ALIGN (scanline_buffer); 170 mask_buffer = ALIGN (src_buffer + width * Bpp); 171 dest_buffer = ALIGN (mask_buffer + width * Bpp); 172 173 if (width_flag == ITER_WIDE) 174 { 175 /* To make sure there aren't any NANs in the buffers */ 176 memset (src_buffer, 0, width * Bpp); 177 memset (mask_buffer, 0, width * Bpp); 178 memset (dest_buffer, 0, width * Bpp); 179 } 180 181 /* src iter */ 182 src_iter_flags = width_flag | op_flags[op].src | ITER_SRC; 183 184 _pixman_implementation_iter_init (imp->toplevel, &src_iter, src_image, 185 src_x, src_y, width, height, 186 src_buffer, src_iter_flags, 187 info->src_flags); 188 189 /* mask iter */ 190 if ((src_iter_flags & (ITER_IGNORE_ALPHA | ITER_IGNORE_RGB)) == 191 (ITER_IGNORE_ALPHA | ITER_IGNORE_RGB)) 192 { 193 /* If it doesn't matter what the source is, then it doesn't matter 194 * what the mask is 195 */ 196 mask_image = NULL; 197 } 198 199 component_alpha = mask_image && mask_image->common.component_alpha; 200 201 _pixman_implementation_iter_init ( 202 imp->toplevel, &mask_iter, 203 mask_image, mask_x, mask_y, width, height, mask_buffer, 204 ITER_SRC | width_flag | (component_alpha? 0 : ITER_IGNORE_RGB), 205 info->mask_flags); 206 207 /* dest iter */ 208 _pixman_implementation_iter_init ( 209 imp->toplevel, &dest_iter, dest_image, dest_x, dest_y, width, height, 210 dest_buffer, ITER_DEST | width_flag | op_flags[op].dst, info->dest_flags); 211 212 compose = _pixman_implementation_lookup_combiner ( 213 imp->toplevel, op, component_alpha, width_flag != ITER_WIDE); 214 215 for (i = 0; i < height; ++i) 216 { 217 uint32_t *s, *m, *d; 218 219 m = mask_iter.get_scanline (&mask_iter, NULL); 220 s = src_iter.get_scanline (&src_iter, m); 221 d = dest_iter.get_scanline (&dest_iter, NULL); 222 223 compose (imp->toplevel, op, d, s, m, width); 224 225 dest_iter.write_back (&dest_iter); 226 } 227 228 if (src_iter.fini) 229 src_iter.fini (&src_iter); 230 if (mask_iter.fini) 231 mask_iter.fini (&mask_iter); 232 if (dest_iter.fini) 233 dest_iter.fini (&dest_iter); 234 235 if (scanline_buffer != (uint8_t *) stack_scanline_buffer) 236 free (scanline_buffer); 237} 238 239static const pixman_fast_path_t general_fast_path[] = 240{ 241 { PIXMAN_OP_any, PIXMAN_any, 0, PIXMAN_any, 0, PIXMAN_any, 0, general_composite_rect }, 242 { PIXMAN_OP_NONE } 243}; 244 245pixman_implementation_t * 246_pixman_implementation_create_general (void) 247{ 248 pixman_implementation_t *imp = _pixman_implementation_create (NULL, general_fast_path); 249 250 _pixman_setup_combiner_functions_32 (imp); 251 _pixman_setup_combiner_functions_float (imp); 252 253 imp->iter_info = general_iters; 254 255 return imp; 256} 257 258