pixman-general.c revision 317c648b
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#include <config.h> 29#include <stdlib.h> 30#include <string.h> 31#include <math.h> 32#include <assert.h> 33#include <limits.h> 34#include <stdio.h> 35#include <stdlib.h> 36#include <string.h> 37#include "pixman-private.h" 38#include "pixman-combine32.h" 39#include "pixman-private.h" 40 41#define SCANLINE_BUFFER_LENGTH 8192 42 43static void 44general_composite_rect (pixman_implementation_t *imp, 45 pixman_op_t op, 46 pixman_image_t *src, 47 pixman_image_t *mask, 48 pixman_image_t *dest, 49 int32_t src_x, 50 int32_t src_y, 51 int32_t mask_x, 52 int32_t mask_y, 53 int32_t dest_x, 54 int32_t dest_y, 55 int32_t width, 56 int32_t height) 57{ 58 return_if_fail (src != NULL); 59 return_if_fail (dest != NULL); 60 61 uint8_t stack_scanline_buffer[SCANLINE_BUFFER_LENGTH * 3]; 62 const pixman_format_code_t srcFormat = src->type == BITS ? src->bits.format : 0; 63 const pixman_format_code_t maskFormat = mask && mask->type == BITS ? mask->bits.format : 0; 64 const pixman_format_code_t destFormat = dest->type == BITS ? dest->bits.format : 0; 65 const int srcWide = PIXMAN_FORMAT_16BPC(srcFormat); 66 const int maskWide = mask && PIXMAN_FORMAT_16BPC(maskFormat); 67 const int destWide = PIXMAN_FORMAT_16BPC(destFormat); 68 const int wide = srcWide || maskWide || destWide; 69 const int Bpp = wide ? 8 : 4; 70 uint8_t *scanline_buffer = stack_scanline_buffer; 71 uint8_t *src_buffer, *mask_buffer, *dest_buffer; 72 scanFetchProc fetchSrc = NULL, fetchMask = NULL, fetchDest = NULL; 73 pixman_combine_32_func_t compose; 74 scanStoreProc store; 75 source_pict_class_t srcClass, maskClass; 76 pixman_bool_t component_alpha; 77 uint32_t *bits; 78 int32_t stride; 79 int i; 80 81 if (width * Bpp > SCANLINE_BUFFER_LENGTH) 82 { 83 scanline_buffer = pixman_malloc_abc (width, 3, Bpp); 84 85 if (!scanline_buffer) 86 return; 87 } 88 89 src_buffer = scanline_buffer; 90 mask_buffer = src_buffer + width * Bpp; 91 dest_buffer = mask_buffer + width * Bpp; 92 93 srcClass = _pixman_image_classify (src, 94 src_x, src_y, 95 width, height); 96 97 maskClass = SOURCE_IMAGE_CLASS_UNKNOWN; 98 if (mask) 99 { 100 maskClass = _pixman_image_classify (mask, 101 src_x, src_y, 102 width, height); 103 } 104 105 if (op == PIXMAN_OP_CLEAR) 106 fetchSrc = NULL; 107 else if (wide) 108 fetchSrc = _pixman_image_get_scanline_64; 109 else 110 fetchSrc = _pixman_image_get_scanline_32; 111 112 if (!mask || op == PIXMAN_OP_CLEAR) 113 fetchMask = NULL; 114 else if (wide) 115 fetchMask = _pixman_image_get_scanline_64; 116 else 117 fetchMask = _pixman_image_get_scanline_32; 118 119 if (op == PIXMAN_OP_CLEAR || op == PIXMAN_OP_SRC) 120 fetchDest = NULL; 121 else if (wide) 122 fetchDest = _pixman_image_get_scanline_64; 123 else 124 fetchDest = _pixman_image_get_scanline_32; 125 126 if (wide) 127 store = _pixman_image_store_scanline_64; 128 else 129 store = _pixman_image_store_scanline_32; 130 131 /* Skip the store step and composite directly into the 132 * destination if the output format of the compose func matches 133 * the destination format. 134 */ 135 if (!wide && 136 !dest->common.alpha_map && 137 !dest->common.write_func && 138 (op == PIXMAN_OP_ADD || op == PIXMAN_OP_OVER) && 139 (dest->bits.format == PIXMAN_a8r8g8b8 || 140 dest->bits.format == PIXMAN_x8r8g8b8)) 141 { 142 store = NULL; 143 } 144 145 if (!store) 146 { 147 bits = dest->bits.bits; 148 stride = dest->bits.rowstride; 149 } 150 else 151 { 152 bits = NULL; 153 stride = 0; 154 } 155 156 component_alpha = 157 fetchSrc && 158 fetchMask && 159 mask && 160 mask->common.type == BITS && 161 mask->common.component_alpha && 162 PIXMAN_FORMAT_RGB (mask->bits.format); 163 164 if (wide) 165 { 166 if (component_alpha) 167 compose = (pixman_combine_32_func_t)_pixman_implementation_combine_64_ca; 168 else 169 compose = (pixman_combine_32_func_t)_pixman_implementation_combine_64; 170 } 171 else 172 { 173 if (component_alpha) 174 compose = _pixman_implementation_combine_32_ca; 175 else 176 compose = _pixman_implementation_combine_32; 177 } 178 179 if (!compose) 180 return; 181 182 if (!fetchMask) 183 mask_buffer = NULL; 184 185 for (i = 0; i < height; ++i) 186 { 187 /* fill first half of scanline with source */ 188 if (fetchSrc) 189 { 190 if (fetchMask) 191 { 192 /* fetch mask before source so that fetching of 193 source can be optimized */ 194 fetchMask (mask, mask_x, mask_y + i, 195 width, (void *)mask_buffer, 0, 0); 196 197 if (maskClass == SOURCE_IMAGE_CLASS_HORIZONTAL) 198 fetchMask = NULL; 199 } 200 201 if (srcClass == SOURCE_IMAGE_CLASS_HORIZONTAL) 202 { 203 fetchSrc (src, src_x, src_y + i, 204 width, (void *)src_buffer, 0, 0); 205 fetchSrc = NULL; 206 } 207 else 208 { 209 fetchSrc (src, src_x, src_y + i, 210 width, (void *)src_buffer, (void *)mask_buffer, 211 0xffffffff); 212 } 213 } 214 else if (fetchMask) 215 { 216 fetchMask (mask, mask_x, mask_y + i, 217 width, (void *)mask_buffer, 0, 0); 218 } 219 220 if (store) 221 { 222 /* fill dest into second half of scanline */ 223 if (fetchDest) 224 fetchDest (dest, dest_x, dest_y + i, 225 width, (void *)dest_buffer, 0, 0); 226 227 /* blend */ 228 compose (imp->toplevel, op, (void *)dest_buffer, (void *)src_buffer, (void *)mask_buffer, width); 229 230 /* write back */ 231 store (&(dest->bits), dest_x, dest_y + i, width, 232 (void *)dest_buffer); 233 } 234 else 235 { 236 /* blend */ 237 compose (imp->toplevel, op, bits + (dest_y + i) * stride + 238 dest_x, 239 (void *)src_buffer, (void *)mask_buffer, width); 240 } 241 } 242 243 if (scanline_buffer != stack_scanline_buffer) 244 free (scanline_buffer); 245} 246 247static void 248general_composite (pixman_implementation_t * imp, 249 pixman_op_t op, 250 pixman_image_t * src, 251 pixman_image_t * mask, 252 pixman_image_t * dest, 253 int32_t src_x, 254 int32_t src_y, 255 int32_t mask_x, 256 int32_t mask_y, 257 int32_t dest_x, 258 int32_t dest_y, 259 int32_t width, 260 int32_t height) 261{ 262 pixman_bool_t srcRepeat = src->type == BITS && src->common.repeat == PIXMAN_REPEAT_NORMAL; 263 pixman_bool_t maskRepeat = FALSE; 264 pixman_bool_t srcTransform = src->common.transform != NULL; 265 pixman_bool_t maskTransform = FALSE; 266 267 if (srcRepeat && srcTransform && 268 src->bits.width == 1 && 269 src->bits.height == 1) 270 { 271 srcTransform = FALSE; 272 } 273 274 if (mask && mask->type == BITS) 275 { 276 maskRepeat = mask->common.repeat == PIXMAN_REPEAT_NORMAL; 277 278 maskTransform = mask->common.transform != 0; 279 if (mask->common.filter == PIXMAN_FILTER_CONVOLUTION) 280 maskTransform = TRUE; 281 282 if (maskRepeat && maskTransform && 283 mask->bits.width == 1 && 284 mask->bits.height == 1) 285 { 286 maskTransform = FALSE; 287 } 288 } 289 290 /* CompositeGeneral optimizes 1x1 repeating images itself */ 291 if (src->type == BITS && 292 src->bits.width == 1 && src->bits.height == 1) 293 { 294 srcRepeat = FALSE; 295 } 296 297 if (mask && mask->type == BITS && 298 mask->bits.width == 1 && mask->bits.height == 1) 299 { 300 maskRepeat = FALSE; 301 } 302 303 /* if we are transforming, repeats are handled in fbFetchTransformed */ 304 if (srcTransform) 305 srcRepeat = FALSE; 306 307 if (maskTransform) 308 maskRepeat = FALSE; 309 310 _pixman_walk_composite_region (imp, op, src, mask, dest, src_x, src_y, 311 mask_x, mask_y, dest_x, dest_y, width, height, 312 srcRepeat, maskRepeat, general_composite_rect); 313} 314 315static pixman_bool_t 316general_blt (pixman_implementation_t *imp, 317 uint32_t *src_bits, 318 uint32_t *dst_bits, 319 int src_stride, 320 int dst_stride, 321 int src_bpp, 322 int dst_bpp, 323 int src_x, int src_y, 324 int dst_x, int dst_y, 325 int width, int height) 326{ 327 /* We can't blit unless we have sse2 or mmx */ 328 329 return FALSE; 330} 331 332static pixman_bool_t 333general_fill (pixman_implementation_t *imp, 334 uint32_t *bits, 335 int stride, 336 int bpp, 337 int x, 338 int y, 339 int width, 340 int height, 341 uint32_t xor) 342{ 343 return FALSE; 344} 345 346pixman_implementation_t * 347_pixman_implementation_create_general (void) 348{ 349 pixman_implementation_t *imp = _pixman_implementation_create (NULL); 350 351 _pixman_setup_combiner_functions_32 (imp); 352 _pixman_setup_combiner_functions_64 (imp); 353 354 imp->composite = general_composite; 355 imp->blt = general_blt; 356 imp->fill = general_fill; 357 358 return imp; 359} 360