pixman-general.c revision de17ff4a
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 void 113general_composite_rect (pixman_implementation_t *imp, 114 pixman_composite_info_t *info) 115{ 116 PIXMAN_COMPOSITE_ARGS (info); 117 uint8_t stack_scanline_buffer[3 * SCANLINE_BUFFER_LENGTH]; 118 uint8_t *scanline_buffer = (uint8_t *) stack_scanline_buffer; 119 uint8_t *src_buffer, *mask_buffer, *dest_buffer; 120 pixman_iter_t src_iter, mask_iter, dest_iter; 121 pixman_combine_32_func_t compose; 122 pixman_bool_t component_alpha; 123 iter_flags_t width_flag, src_iter_flags; 124 int Bpp; 125 int i; 126 127 if ((src_image->common.flags & FAST_PATH_NARROW_FORMAT) && 128 (!mask_image || mask_image->common.flags & FAST_PATH_NARROW_FORMAT) && 129 (dest_image->common.flags & FAST_PATH_NARROW_FORMAT)) 130 { 131 width_flag = ITER_NARROW; 132 Bpp = 4; 133 } 134 else 135 { 136 width_flag = ITER_WIDE; 137 Bpp = 16; 138 } 139 140#define ALIGN(addr) \ 141 ((uint8_t *)((((uintptr_t)(addr)) + 15) & (~15))) 142 143 src_buffer = ALIGN (scanline_buffer); 144 mask_buffer = ALIGN (src_buffer + width * Bpp); 145 dest_buffer = ALIGN (mask_buffer + width * Bpp); 146 147 if (ALIGN (dest_buffer + width * Bpp) > 148 scanline_buffer + sizeof (stack_scanline_buffer)) 149 { 150 scanline_buffer = pixman_malloc_ab_plus_c (width, Bpp * 3, 32 * 3); 151 152 if (!scanline_buffer) 153 return; 154 155 src_buffer = ALIGN (scanline_buffer); 156 mask_buffer = ALIGN (src_buffer + width * Bpp); 157 dest_buffer = ALIGN (mask_buffer + width * Bpp); 158 } 159 160 if (width_flag == ITER_WIDE) 161 { 162 /* To make sure there aren't any NANs in the buffers */ 163 memset (src_buffer, 0, width * Bpp); 164 memset (mask_buffer, 0, width * Bpp); 165 memset (dest_buffer, 0, width * Bpp); 166 } 167 168 /* src iter */ 169 src_iter_flags = width_flag | op_flags[op].src | ITER_SRC; 170 171 _pixman_implementation_iter_init (imp->toplevel, &src_iter, src_image, 172 src_x, src_y, width, height, 173 src_buffer, src_iter_flags, 174 info->src_flags); 175 176 /* mask iter */ 177 if ((src_iter_flags & (ITER_IGNORE_ALPHA | ITER_IGNORE_RGB)) == 178 (ITER_IGNORE_ALPHA | ITER_IGNORE_RGB)) 179 { 180 /* If it doesn't matter what the source is, then it doesn't matter 181 * what the mask is 182 */ 183 mask_image = NULL; 184 } 185 186 component_alpha = 187 mask_image && 188 mask_image->common.type == BITS && 189 mask_image->common.component_alpha && 190 PIXMAN_FORMAT_RGB (mask_image->bits.format); 191 192 _pixman_implementation_iter_init ( 193 imp->toplevel, &mask_iter, 194 mask_image, mask_x, mask_y, width, height, mask_buffer, 195 ITER_SRC | width_flag | (component_alpha? 0 : ITER_IGNORE_RGB), 196 info->mask_flags); 197 198 /* dest iter */ 199 _pixman_implementation_iter_init ( 200 imp->toplevel, &dest_iter, dest_image, dest_x, dest_y, width, height, 201 dest_buffer, ITER_DEST | width_flag | op_flags[op].dst, info->dest_flags); 202 203 compose = _pixman_implementation_lookup_combiner ( 204 imp->toplevel, op, component_alpha, width_flag != ITER_WIDE); 205 206 for (i = 0; i < height; ++i) 207 { 208 uint32_t *s, *m, *d; 209 210 m = mask_iter.get_scanline (&mask_iter, NULL); 211 s = src_iter.get_scanline (&src_iter, m); 212 d = dest_iter.get_scanline (&dest_iter, NULL); 213 214 compose (imp->toplevel, op, d, s, m, width); 215 216 dest_iter.write_back (&dest_iter); 217 } 218 219 if (src_iter.fini) 220 src_iter.fini (&src_iter); 221 if (mask_iter.fini) 222 mask_iter.fini (&mask_iter); 223 if (dest_iter.fini) 224 dest_iter.fini (&dest_iter); 225 226 if (scanline_buffer != (uint8_t *) stack_scanline_buffer) 227 free (scanline_buffer); 228} 229 230static const pixman_fast_path_t general_fast_path[] = 231{ 232 { PIXMAN_OP_any, PIXMAN_any, 0, PIXMAN_any, 0, PIXMAN_any, 0, general_composite_rect }, 233 { PIXMAN_OP_NONE } 234}; 235 236pixman_implementation_t * 237_pixman_implementation_create_general (void) 238{ 239 pixman_implementation_t *imp = _pixman_implementation_create (NULL, general_fast_path); 240 241 _pixman_setup_combiner_functions_32 (imp); 242 _pixman_setup_combiner_functions_float (imp); 243 244 imp->iter_info = general_iters; 245 246 return imp; 247} 248 249