pixman-utils.c revision 317c648b
1b4b94579Smrg/* 2b4b94579Smrg * Copyright © 2000 SuSE, Inc. 3b4b94579Smrg * 4b4b94579Smrg * Permission to use, copy, modify, distribute, and sell this software and its 5b4b94579Smrg * documentation for any purpose is hereby granted without fee, provided that 6b4b94579Smrg * the above copyright notice appear in all copies and that both that 7b4b94579Smrg * copyright notice and this permission notice appear in supporting 8b4b94579Smrg * documentation, and that the name of SuSE not be used in advertising or 9b4b94579Smrg * publicity pertaining to distribution of the software without specific, 10b4b94579Smrg * written prior permission. SuSE makes no representations about the 11b4b94579Smrg * suitability of this software for any purpose. It is provided "as is" 12b4b94579Smrg * without express or implied warranty. 13b4b94579Smrg * 14b4b94579Smrg * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL 15b4b94579Smrg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE 16b4b94579Smrg * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 17b4b94579Smrg * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 18b4b94579Smrg * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 19b4b94579Smrg * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 20b4b94579Smrg * 21b4b94579Smrg * Author: Keith Packard, SuSE, Inc. 22b4b94579Smrg */ 23b4b94579Smrg 24b4b94579Smrg#ifdef HAVE_CONFIG_H 25b4b94579Smrg#include <config.h> 26b4b94579Smrg#endif 27b4b94579Smrg 28b4b94579Smrg#include <stdlib.h> 29b4b94579Smrg 30b4b94579Smrg#include "pixman-private.h" 31b4b94579Smrg 32b4b94579Smrg/* 33b4b94579Smrg * Compute the smallest value no less than y which is on a 34b4b94579Smrg * grid row 35b4b94579Smrg */ 36b4b94579Smrg 37b4b94579SmrgPIXMAN_EXPORT pixman_fixed_t 38b4b94579Smrgpixman_sample_ceil_y (pixman_fixed_t y, int n) 39b4b94579Smrg{ 40b4b94579Smrg pixman_fixed_t f = pixman_fixed_frac(y); 41b4b94579Smrg pixman_fixed_t i = pixman_fixed_floor(y); 42b4b94579Smrg 43b4b94579Smrg f = ((f + Y_FRAC_FIRST(n)) / STEP_Y_SMALL(n)) * STEP_Y_SMALL(n) + Y_FRAC_FIRST(n); 44b4b94579Smrg if (f > Y_FRAC_LAST(n)) 45b4b94579Smrg { 46317c648bSmrg if (pixman_fixed_to_int(i) == 0x7fff) 47317c648bSmrg { 48317c648bSmrg f = 0xffff; /* saturate */ 49317c648bSmrg } else { 50317c648bSmrg f = Y_FRAC_FIRST(n); 51317c648bSmrg i += pixman_fixed_1; 52317c648bSmrg } 53b4b94579Smrg } 54b4b94579Smrg return (i | f); 55b4b94579Smrg} 56b4b94579Smrg 57b4b94579Smrg#define _div(a,b) ((a) >= 0 ? (a) / (b) : -((-(a) + (b) - 1) / (b))) 58b4b94579Smrg 59b4b94579Smrg/* 60b4b94579Smrg * Compute the largest value no greater than y which is on a 61b4b94579Smrg * grid row 62b4b94579Smrg */ 63b4b94579SmrgPIXMAN_EXPORT pixman_fixed_t 64b4b94579Smrgpixman_sample_floor_y (pixman_fixed_t y, int n) 65b4b94579Smrg{ 66b4b94579Smrg pixman_fixed_t f = pixman_fixed_frac(y); 67b4b94579Smrg pixman_fixed_t i = pixman_fixed_floor (y); 68b4b94579Smrg 69b4b94579Smrg f = _div(f - Y_FRAC_FIRST(n), STEP_Y_SMALL(n)) * STEP_Y_SMALL(n) + Y_FRAC_FIRST(n); 70b4b94579Smrg if (f < Y_FRAC_FIRST(n)) 71b4b94579Smrg { 72317c648bSmrg if (pixman_fixed_to_int(i) == 0x8000) 73317c648bSmrg { 74317c648bSmrg f = 0; /* saturate */ 75317c648bSmrg } else { 76317c648bSmrg f = Y_FRAC_LAST(n); 77317c648bSmrg i -= pixman_fixed_1; 78317c648bSmrg } 79b4b94579Smrg } 80b4b94579Smrg return (i | f); 81b4b94579Smrg} 82b4b94579Smrg 83b4b94579Smrg/* 84b4b94579Smrg * Step an edge by any amount (including negative values) 85b4b94579Smrg */ 86b4b94579SmrgPIXMAN_EXPORT void 87b4b94579Smrgpixman_edge_step (pixman_edge_t *e, int n) 88b4b94579Smrg{ 89b4b94579Smrg pixman_fixed_48_16_t ne; 90b4b94579Smrg 91b4b94579Smrg e->x += n * e->stepx; 92b4b94579Smrg 93b4b94579Smrg ne = e->e + n * (pixman_fixed_48_16_t) e->dx; 94b4b94579Smrg 95b4b94579Smrg if (n >= 0) 96b4b94579Smrg { 97b4b94579Smrg if (ne > 0) 98b4b94579Smrg { 99b4b94579Smrg int nx = (ne + e->dy - 1) / e->dy; 100b4b94579Smrg e->e = ne - nx * (pixman_fixed_48_16_t) e->dy; 101b4b94579Smrg e->x += nx * e->signdx; 102b4b94579Smrg } 103b4b94579Smrg } 104b4b94579Smrg else 105b4b94579Smrg { 106b4b94579Smrg if (ne <= -e->dy) 107b4b94579Smrg { 108b4b94579Smrg int nx = (-ne) / e->dy; 109b4b94579Smrg e->e = ne + nx * (pixman_fixed_48_16_t) e->dy; 110b4b94579Smrg e->x -= nx * e->signdx; 111b4b94579Smrg } 112b4b94579Smrg } 113b4b94579Smrg} 114b4b94579Smrg 115b4b94579Smrg/* 116b4b94579Smrg * A private routine to initialize the multi-step 117b4b94579Smrg * elements of an edge structure 118b4b94579Smrg */ 119b4b94579Smrgstatic void 120317c648bSmrg_pixman_edge_multi_init (pixman_edge_t *e, int n, pixman_fixed_t *stepx_p, pixman_fixed_t *dx_p) 121b4b94579Smrg{ 122b4b94579Smrg pixman_fixed_t stepx; 123b4b94579Smrg pixman_fixed_48_16_t ne; 124b4b94579Smrg 125b4b94579Smrg ne = n * (pixman_fixed_48_16_t) e->dx; 126b4b94579Smrg stepx = n * e->stepx; 127b4b94579Smrg if (ne > 0) 128b4b94579Smrg { 129b4b94579Smrg int nx = ne / e->dy; 130b4b94579Smrg ne -= nx * e->dy; 131b4b94579Smrg stepx += nx * e->signdx; 132b4b94579Smrg } 133b4b94579Smrg *dx_p = ne; 134b4b94579Smrg *stepx_p = stepx; 135b4b94579Smrg} 136b4b94579Smrg 137b4b94579Smrg/* 138b4b94579Smrg * Initialize one edge structure given the line endpoints and a 139b4b94579Smrg * starting y value 140b4b94579Smrg */ 141b4b94579SmrgPIXMAN_EXPORT void 142b4b94579Smrgpixman_edge_init (pixman_edge_t *e, 143b4b94579Smrg int n, 144b4b94579Smrg pixman_fixed_t y_start, 145b4b94579Smrg pixman_fixed_t x_top, 146b4b94579Smrg pixman_fixed_t y_top, 147b4b94579Smrg pixman_fixed_t x_bot, 148b4b94579Smrg pixman_fixed_t y_bot) 149b4b94579Smrg{ 150b4b94579Smrg pixman_fixed_t dx, dy; 151b4b94579Smrg 152b4b94579Smrg e->x = x_top; 153b4b94579Smrg e->e = 0; 154b4b94579Smrg dx = x_bot - x_top; 155b4b94579Smrg dy = y_bot - y_top; 156b4b94579Smrg e->dy = dy; 157b4b94579Smrg e->dx = 0; 158b4b94579Smrg if (dy) 159b4b94579Smrg { 160b4b94579Smrg if (dx >= 0) 161b4b94579Smrg { 162b4b94579Smrg e->signdx = 1; 163b4b94579Smrg e->stepx = dx / dy; 164b4b94579Smrg e->dx = dx % dy; 165b4b94579Smrg e->e = -dy; 166b4b94579Smrg } 167b4b94579Smrg else 168b4b94579Smrg { 169b4b94579Smrg e->signdx = -1; 170b4b94579Smrg e->stepx = -(-dx / dy); 171b4b94579Smrg e->dx = -dx % dy; 172b4b94579Smrg e->e = 0; 173b4b94579Smrg } 174b4b94579Smrg 175317c648bSmrg _pixman_edge_multi_init (e, STEP_Y_SMALL(n), &e->stepx_small, &e->dx_small); 176317c648bSmrg _pixman_edge_multi_init (e, STEP_Y_BIG(n), &e->stepx_big, &e->dx_big); 177b4b94579Smrg } 178b4b94579Smrg pixman_edge_step (e, y_start - y_top); 179b4b94579Smrg} 180b4b94579Smrg 181b4b94579Smrg/* 182b4b94579Smrg * Initialize one edge structure given a line, starting y value 183b4b94579Smrg * and a pixel offset for the line 184b4b94579Smrg */ 185b4b94579SmrgPIXMAN_EXPORT void 186b4b94579Smrgpixman_line_fixed_edge_init (pixman_edge_t *e, 187b4b94579Smrg int n, 188b4b94579Smrg pixman_fixed_t y, 189b4b94579Smrg const pixman_line_fixed_t *line, 190b4b94579Smrg int x_off, 191b4b94579Smrg int y_off) 192b4b94579Smrg{ 193b4b94579Smrg pixman_fixed_t x_off_fixed = pixman_int_to_fixed(x_off); 194b4b94579Smrg pixman_fixed_t y_off_fixed = pixman_int_to_fixed(y_off); 195b4b94579Smrg const pixman_point_fixed_t *top, *bot; 196b4b94579Smrg 197b4b94579Smrg if (line->p1.y <= line->p2.y) 198b4b94579Smrg { 199b4b94579Smrg top = &line->p1; 200b4b94579Smrg bot = &line->p2; 201b4b94579Smrg } 202b4b94579Smrg else 203b4b94579Smrg { 204b4b94579Smrg top = &line->p2; 205b4b94579Smrg bot = &line->p1; 206b4b94579Smrg } 207b4b94579Smrg pixman_edge_init (e, n, y, 208b4b94579Smrg top->x + x_off_fixed, 209b4b94579Smrg top->y + y_off_fixed, 210b4b94579Smrg bot->x + x_off_fixed, 211b4b94579Smrg bot->y + y_off_fixed); 212b4b94579Smrg} 213b4b94579Smrg 214b4b94579Smrgpixman_bool_t 215b4b94579Smrgpixman_multiply_overflows_int (unsigned int a, 216b4b94579Smrg unsigned int b) 217b4b94579Smrg{ 218b4b94579Smrg return a >= INT32_MAX / b; 219b4b94579Smrg} 220b4b94579Smrg 221b4b94579Smrgpixman_bool_t 222b4b94579Smrgpixman_addition_overflows_int (unsigned int a, 223b4b94579Smrg unsigned int b) 224b4b94579Smrg{ 225b4b94579Smrg return a > INT32_MAX - b; 226b4b94579Smrg} 227b4b94579Smrg 228b4b94579Smrgvoid * 229b4b94579Smrgpixman_malloc_ab(unsigned int a, 230b4b94579Smrg unsigned int b) 231b4b94579Smrg{ 232b4b94579Smrg if (a >= INT32_MAX / b) 233b4b94579Smrg return NULL; 234b4b94579Smrg 235b4b94579Smrg return malloc (a * b); 236b4b94579Smrg} 237b4b94579Smrg 238b4b94579Smrgvoid * 239b4b94579Smrgpixman_malloc_abc (unsigned int a, 240b4b94579Smrg unsigned int b, 241b4b94579Smrg unsigned int c) 242b4b94579Smrg{ 243b4b94579Smrg if (a >= INT32_MAX / b) 244b4b94579Smrg return NULL; 245b4b94579Smrg else if (a * b >= INT32_MAX / c) 246b4b94579Smrg return NULL; 247b4b94579Smrg else 248b4b94579Smrg return malloc (a * b * c); 249b4b94579Smrg} 250b4b94579Smrg 251b4b94579Smrg 252b4b94579Smrg/** 253b4b94579Smrg * pixman_version: 254b4b94579Smrg * 255b4b94579Smrg * Returns the version of the pixman library encoded in a single 256b4b94579Smrg * integer as per %PIXMAN_VERSION_ENCODE. The encoding ensures that 257b4b94579Smrg * later versions compare greater than earlier versions. 258b4b94579Smrg * 259b4b94579Smrg * A run-time comparison to check that pixman's version is greater than 260b4b94579Smrg * or equal to version X.Y.Z could be performed as follows: 261b4b94579Smrg * 262b4b94579Smrg * <informalexample><programlisting> 263b4b94579Smrg * if (pixman_version() >= PIXMAN_VERSION_ENCODE(X,Y,Z)) {...} 264b4b94579Smrg * </programlisting></informalexample> 265b4b94579Smrg * 266b4b94579Smrg * See also pixman_version_string() as well as the compile-time 267b4b94579Smrg * equivalents %PIXMAN_VERSION and %PIXMAN_VERSION_STRING. 268b4b94579Smrg * 269b4b94579Smrg * Return value: the encoded version. 270b4b94579Smrg **/ 271b4b94579SmrgPIXMAN_EXPORT int 272b4b94579Smrgpixman_version (void) 273b4b94579Smrg{ 274b4b94579Smrg return PIXMAN_VERSION; 275b4b94579Smrg} 276b4b94579Smrg 277317c648bSmrg/* 278317c648bSmrg * Helper routine to expand a color component from 0 < n <= 8 bits to 16 bits by 279317c648bSmrg * replication. 280317c648bSmrg */ 281317c648bSmrgstatic inline uint64_t 282317c648bSmrgexpand16(const uint8_t val, int nbits) 283317c648bSmrg{ 284317c648bSmrg // Start out with the high bit of val in the high bit of result. 285317c648bSmrg uint16_t result = (uint16_t)val << (16 - nbits); 286317c648bSmrg 287317c648bSmrg if (nbits == 0) 288317c648bSmrg return 0; 289317c648bSmrg 290317c648bSmrg // Copy the bits in result, doubling the number of bits each time, until we 291317c648bSmrg // fill all 16 bits. 292317c648bSmrg while (nbits < 16) { 293317c648bSmrg result |= result >> nbits; 294317c648bSmrg nbits *= 2; 295317c648bSmrg } 296317c648bSmrg 297317c648bSmrg return result; 298317c648bSmrg} 299317c648bSmrg 300317c648bSmrg/* 301317c648bSmrg * This function expands images from ARGB8 format to ARGB16. To preserve 302317c648bSmrg * precision, it needs to know the original source format. For example, if the 303317c648bSmrg * source was PIXMAN_x1r5g5b5 and the red component contained bits 12345, then 304317c648bSmrg * the expanded value is 12345123. To correctly expand this to 16 bits, it 305317c648bSmrg * should be 1234512345123451 and not 1234512312345123. 306317c648bSmrg */ 307317c648bSmrgvoid 308317c648bSmrgpixman_expand(uint64_t *dst, const uint32_t *src, 309317c648bSmrg pixman_format_code_t format, int width) 310317c648bSmrg{ 311317c648bSmrg /* 312317c648bSmrg * Determine the sizes of each component and the masks and shifts required 313317c648bSmrg * to extract them from the source pixel. 314317c648bSmrg */ 315317c648bSmrg const int a_size = PIXMAN_FORMAT_A(format), 316317c648bSmrg r_size = PIXMAN_FORMAT_R(format), 317317c648bSmrg g_size = PIXMAN_FORMAT_G(format), 318317c648bSmrg b_size = PIXMAN_FORMAT_B(format); 319317c648bSmrg const int a_shift = 32 - a_size, 320317c648bSmrg r_shift = 24 - r_size, 321317c648bSmrg g_shift = 16 - g_size, 322317c648bSmrg b_shift = 8 - b_size; 323317c648bSmrg const uint8_t a_mask = ~(~0 << a_size), 324317c648bSmrg r_mask = ~(~0 << r_size), 325317c648bSmrg g_mask = ~(~0 << g_size), 326317c648bSmrg b_mask = ~(~0 << b_size); 327317c648bSmrg int i; 328317c648bSmrg 329317c648bSmrg /* Start at the end so that we can do the expansion in place when src == dst */ 330317c648bSmrg for (i = width - 1; i >= 0; i--) 331317c648bSmrg { 332317c648bSmrg const uint32_t pixel = src[i]; 333317c648bSmrg // Extract the components. 334317c648bSmrg const uint8_t a = (pixel >> a_shift) & a_mask, 335317c648bSmrg r = (pixel >> r_shift) & r_mask, 336317c648bSmrg g = (pixel >> g_shift) & g_mask, 337317c648bSmrg b = (pixel >> b_shift) & b_mask; 338317c648bSmrg const uint64_t a16 = a_size ? expand16(a, a_size) : 0xffff, 339317c648bSmrg r16 = expand16(r, r_size), 340317c648bSmrg g16 = expand16(g, g_size), 341317c648bSmrg b16 = expand16(b, b_size); 342317c648bSmrg 343317c648bSmrg dst[i] = a16 << 48 | r16 << 32 | g16 << 16 | b16; 344317c648bSmrg } 345317c648bSmrg} 346317c648bSmrg 347317c648bSmrg/* 348317c648bSmrg * Contracting is easier than expanding. We just need to truncate the 349317c648bSmrg * components. 350317c648bSmrg */ 351317c648bSmrgvoid 352317c648bSmrgpixman_contract(uint32_t *dst, const uint64_t *src, int width) 353317c648bSmrg{ 354317c648bSmrg int i; 355317c648bSmrg 356317c648bSmrg /* Start at the beginning so that we can do the contraction in place when 357317c648bSmrg * src == dst */ 358317c648bSmrg for (i = 0; i < width; i++) 359317c648bSmrg { 360317c648bSmrg const uint8_t a = src[i] >> 56, 361317c648bSmrg r = src[i] >> 40, 362317c648bSmrg g = src[i] >> 24, 363317c648bSmrg b = src[i] >> 8; 364317c648bSmrg dst[i] = a << 24 | r << 16 | g << 8 | b; 365317c648bSmrg } 366317c648bSmrg} 367317c648bSmrg 368b4b94579Smrg/** 369b4b94579Smrg * pixman_version_string: 370b4b94579Smrg * 371b4b94579Smrg * Returns the version of the pixman library as a human-readable string 372b4b94579Smrg * of the form "X.Y.Z". 373b4b94579Smrg * 374b4b94579Smrg * See also pixman_version() as well as the compile-time equivalents 375b4b94579Smrg * %PIXMAN_VERSION_STRING and %PIXMAN_VERSION. 376b4b94579Smrg * 377b4b94579Smrg * Return value: a string containing the version. 378b4b94579Smrg **/ 379b4b94579SmrgPIXMAN_EXPORT const char* 380b4b94579Smrgpixman_version_string (void) 381b4b94579Smrg{ 382b4b94579Smrg return PIXMAN_VERSION_STRING; 383b4b94579Smrg} 384b4b94579Smrg 385b4b94579Smrg/** 386b4b94579Smrg * pixman_format_supported_destination: 387b4b94579Smrg * @format: A pixman_format_code_t format 388b4b94579Smrg * 389b4b94579Smrg * Return value: whether the provided format code is a supported 390b4b94579Smrg * format for a pixman surface used as a destination in 391b4b94579Smrg * rendering. 392b4b94579Smrg * 393b4b94579Smrg * Currently, all pixman_format_code_t values are supported 394b4b94579Smrg * except for the YUV formats. 395b4b94579Smrg **/ 396b4b94579SmrgPIXMAN_EXPORT pixman_bool_t 397b4b94579Smrgpixman_format_supported_destination (pixman_format_code_t format) 398b4b94579Smrg{ 399b4b94579Smrg switch (format) { 400b4b94579Smrg /* 32 bpp formats */ 40127693ee9Sveego case PIXMAN_a2b10g10r10: 40227693ee9Sveego case PIXMAN_x2b10g10r10: 403b4b94579Smrg case PIXMAN_a8r8g8b8: 404b4b94579Smrg case PIXMAN_x8r8g8b8: 405b4b94579Smrg case PIXMAN_a8b8g8r8: 406b4b94579Smrg case PIXMAN_x8b8g8r8: 407317c648bSmrg case PIXMAN_b8g8r8a8: 408317c648bSmrg case PIXMAN_b8g8r8x8: 409b4b94579Smrg case PIXMAN_r8g8b8: 410b4b94579Smrg case PIXMAN_b8g8r8: 411b4b94579Smrg case PIXMAN_r5g6b5: 412b4b94579Smrg case PIXMAN_b5g6r5: 413b4b94579Smrg /* 16 bpp formats */ 414b4b94579Smrg case PIXMAN_a1r5g5b5: 415b4b94579Smrg case PIXMAN_x1r5g5b5: 416b4b94579Smrg case PIXMAN_a1b5g5r5: 417b4b94579Smrg case PIXMAN_x1b5g5r5: 418b4b94579Smrg case PIXMAN_a4r4g4b4: 419b4b94579Smrg case PIXMAN_x4r4g4b4: 420b4b94579Smrg case PIXMAN_a4b4g4r4: 421b4b94579Smrg case PIXMAN_x4b4g4r4: 422b4b94579Smrg /* 8bpp formats */ 423b4b94579Smrg case PIXMAN_a8: 424b4b94579Smrg case PIXMAN_r3g3b2: 425b4b94579Smrg case PIXMAN_b2g3r3: 426b4b94579Smrg case PIXMAN_a2r2g2b2: 427b4b94579Smrg case PIXMAN_a2b2g2r2: 428b4b94579Smrg case PIXMAN_c8: 429b4b94579Smrg case PIXMAN_g8: 430b4b94579Smrg case PIXMAN_x4a4: 431b4b94579Smrg /* Collides with PIXMAN_c8 432b4b94579Smrg case PIXMAN_x4c4: 433b4b94579Smrg */ 434b4b94579Smrg /* Collides with PIXMAN_g8 435b4b94579Smrg case PIXMAN_x4g4: 436b4b94579Smrg */ 437b4b94579Smrg /* 4bpp formats */ 438b4b94579Smrg case PIXMAN_a4: 439b4b94579Smrg case PIXMAN_r1g2b1: 440b4b94579Smrg case PIXMAN_b1g2r1: 441b4b94579Smrg case PIXMAN_a1r1g1b1: 442b4b94579Smrg case PIXMAN_a1b1g1r1: 443b4b94579Smrg case PIXMAN_c4: 444b4b94579Smrg case PIXMAN_g4: 445b4b94579Smrg /* 1bpp formats */ 446b4b94579Smrg case PIXMAN_a1: 447b4b94579Smrg case PIXMAN_g1: 448b4b94579Smrg return TRUE; 449b4b94579Smrg 450b4b94579Smrg /* YUV formats */ 451b4b94579Smrg case PIXMAN_yuy2: 452b4b94579Smrg case PIXMAN_yv12: 453b4b94579Smrg default: 454b4b94579Smrg return FALSE; 455b4b94579Smrg } 456b4b94579Smrg} 457b4b94579Smrg 458b4b94579Smrg/** 459b4b94579Smrg * pixman_format_supported_source: 460b4b94579Smrg * @format: A pixman_format_code_t format 461b4b94579Smrg * 462b4b94579Smrg * Return value: whether the provided format code is a supported 463b4b94579Smrg * format for a pixman surface used as a source in 464b4b94579Smrg * rendering. 465b4b94579Smrg * 466b4b94579Smrg * Currently, all pixman_format_code_t values are supported. 467b4b94579Smrg **/ 468b4b94579SmrgPIXMAN_EXPORT pixman_bool_t 469b4b94579Smrgpixman_format_supported_source (pixman_format_code_t format) 470b4b94579Smrg{ 471b4b94579Smrg switch (format) { 472b4b94579Smrg /* 32 bpp formats */ 47327693ee9Sveego case PIXMAN_a2b10g10r10: 47427693ee9Sveego case PIXMAN_x2b10g10r10: 475b4b94579Smrg case PIXMAN_a8r8g8b8: 476b4b94579Smrg case PIXMAN_x8r8g8b8: 477b4b94579Smrg case PIXMAN_a8b8g8r8: 478b4b94579Smrg case PIXMAN_x8b8g8r8: 479317c648bSmrg case PIXMAN_b8g8r8a8: 480317c648bSmrg case PIXMAN_b8g8r8x8: 481b4b94579Smrg case PIXMAN_r8g8b8: 482b4b94579Smrg case PIXMAN_b8g8r8: 483b4b94579Smrg case PIXMAN_r5g6b5: 484b4b94579Smrg case PIXMAN_b5g6r5: 485b4b94579Smrg /* 16 bpp formats */ 486b4b94579Smrg case PIXMAN_a1r5g5b5: 487b4b94579Smrg case PIXMAN_x1r5g5b5: 488b4b94579Smrg case PIXMAN_a1b5g5r5: 489b4b94579Smrg case PIXMAN_x1b5g5r5: 490b4b94579Smrg case PIXMAN_a4r4g4b4: 491b4b94579Smrg case PIXMAN_x4r4g4b4: 492b4b94579Smrg case PIXMAN_a4b4g4r4: 493b4b94579Smrg case PIXMAN_x4b4g4r4: 494b4b94579Smrg /* 8bpp formats */ 495b4b94579Smrg case PIXMAN_a8: 496b4b94579Smrg case PIXMAN_r3g3b2: 497b4b94579Smrg case PIXMAN_b2g3r3: 498b4b94579Smrg case PIXMAN_a2r2g2b2: 499b4b94579Smrg case PIXMAN_a2b2g2r2: 500b4b94579Smrg case PIXMAN_c8: 501b4b94579Smrg case PIXMAN_g8: 502b4b94579Smrg case PIXMAN_x4a4: 503b4b94579Smrg /* Collides with PIXMAN_c8 504b4b94579Smrg case PIXMAN_x4c4: 505b4b94579Smrg */ 506b4b94579Smrg /* Collides with PIXMAN_g8 507b4b94579Smrg case PIXMAN_x4g4: 508b4b94579Smrg */ 509b4b94579Smrg /* 4bpp formats */ 510b4b94579Smrg case PIXMAN_a4: 511b4b94579Smrg case PIXMAN_r1g2b1: 512b4b94579Smrg case PIXMAN_b1g2r1: 513b4b94579Smrg case PIXMAN_a1r1g1b1: 514b4b94579Smrg case PIXMAN_a1b1g1r1: 515b4b94579Smrg case PIXMAN_c4: 516b4b94579Smrg case PIXMAN_g4: 517b4b94579Smrg /* 1bpp formats */ 518b4b94579Smrg case PIXMAN_a1: 519b4b94579Smrg case PIXMAN_g1: 520b4b94579Smrg /* YUV formats */ 521b4b94579Smrg case PIXMAN_yuy2: 522b4b94579Smrg case PIXMAN_yv12: 523b4b94579Smrg return TRUE; 524b4b94579Smrg 525b4b94579Smrg default: 526b4b94579Smrg return FALSE; 527b4b94579Smrg } 528b4b94579Smrg} 529317c648bSmrg 530317c648bSmrgvoid 531317c648bSmrg_pixman_walk_composite_region (pixman_implementation_t *imp, 532317c648bSmrg pixman_op_t op, 533317c648bSmrg pixman_image_t * pSrc, 534317c648bSmrg pixman_image_t * pMask, 535317c648bSmrg pixman_image_t * pDst, 536317c648bSmrg int16_t xSrc, 537317c648bSmrg int16_t ySrc, 538317c648bSmrg int16_t xMask, 539317c648bSmrg int16_t yMask, 540317c648bSmrg int16_t xDst, 541317c648bSmrg int16_t yDst, 542317c648bSmrg uint16_t width, 543317c648bSmrg uint16_t height, 544317c648bSmrg pixman_bool_t srcRepeat, 545317c648bSmrg pixman_bool_t maskRepeat, 546317c648bSmrg pixman_composite_func_t compositeRect) 547317c648bSmrg{ 548317c648bSmrg int n; 549317c648bSmrg const pixman_box32_t *pbox; 550317c648bSmrg int w, h, w_this, h_this; 551317c648bSmrg int x_msk, y_msk, x_src, y_src, x_dst, y_dst; 552317c648bSmrg pixman_region32_t reg; 553317c648bSmrg pixman_region32_t *region; 554317c648bSmrg 555317c648bSmrg pixman_region32_init (®); 556317c648bSmrg if (!pixman_compute_composite_region32 (®, pSrc, pMask, pDst, 557317c648bSmrg xSrc, ySrc, xMask, yMask, xDst, yDst, width, height)) 558317c648bSmrg { 559317c648bSmrg return; 560317c648bSmrg } 561317c648bSmrg 562317c648bSmrg region = ® 563317c648bSmrg 564317c648bSmrg pbox = pixman_region32_rectangles (region, &n); 565317c648bSmrg while (n--) 566317c648bSmrg { 567317c648bSmrg h = pbox->y2 - pbox->y1; 568317c648bSmrg y_src = pbox->y1 - yDst + ySrc; 569317c648bSmrg y_msk = pbox->y1 - yDst + yMask; 570317c648bSmrg y_dst = pbox->y1; 571317c648bSmrg while (h) 572317c648bSmrg { 573317c648bSmrg h_this = h; 574317c648bSmrg w = pbox->x2 - pbox->x1; 575317c648bSmrg x_src = pbox->x1 - xDst + xSrc; 576317c648bSmrg x_msk = pbox->x1 - xDst + xMask; 577317c648bSmrg x_dst = pbox->x1; 578317c648bSmrg if (maskRepeat) 579317c648bSmrg { 580317c648bSmrg y_msk = MOD (y_msk, pMask->bits.height); 581317c648bSmrg if (h_this > pMask->bits.height - y_msk) 582317c648bSmrg h_this = pMask->bits.height - y_msk; 583317c648bSmrg } 584317c648bSmrg if (srcRepeat) 585317c648bSmrg { 586317c648bSmrg y_src = MOD (y_src, pSrc->bits.height); 587317c648bSmrg if (h_this > pSrc->bits.height - y_src) 588317c648bSmrg h_this = pSrc->bits.height - y_src; 589317c648bSmrg } 590317c648bSmrg while (w) 591317c648bSmrg { 592317c648bSmrg w_this = w; 593317c648bSmrg if (maskRepeat) 594317c648bSmrg { 595317c648bSmrg x_msk = MOD (x_msk, pMask->bits.width); 596317c648bSmrg if (w_this > pMask->bits.width - x_msk) 597317c648bSmrg w_this = pMask->bits.width - x_msk; 598317c648bSmrg } 599317c648bSmrg if (srcRepeat) 600317c648bSmrg { 601317c648bSmrg x_src = MOD (x_src, pSrc->bits.width); 602317c648bSmrg if (w_this > pSrc->bits.width - x_src) 603317c648bSmrg w_this = pSrc->bits.width - x_src; 604317c648bSmrg } 605317c648bSmrg (*compositeRect) (imp, 606317c648bSmrg op, pSrc, pMask, pDst, 607317c648bSmrg x_src, y_src, x_msk, y_msk, x_dst, y_dst, 608317c648bSmrg w_this, h_this); 609317c648bSmrg w -= w_this; 610317c648bSmrg x_src += w_this; 611317c648bSmrg x_msk += w_this; 612317c648bSmrg x_dst += w_this; 613317c648bSmrg } 614317c648bSmrg h -= h_this; 615317c648bSmrg y_src += h_this; 616317c648bSmrg y_msk += h_this; 617317c648bSmrg y_dst += h_this; 618317c648bSmrg } 619317c648bSmrg pbox++; 620317c648bSmrg } 621317c648bSmrg pixman_region32_fini (®); 622317c648bSmrg} 623317c648bSmrg 624317c648bSmrgstatic pixman_bool_t 625317c648bSmrgmask_is_solid (pixman_image_t *mask) 626317c648bSmrg{ 627317c648bSmrg if (mask->type == SOLID) 628317c648bSmrg return TRUE; 629317c648bSmrg 630317c648bSmrg if (mask->type == BITS && 631317c648bSmrg mask->common.repeat == PIXMAN_REPEAT_NORMAL && 632317c648bSmrg mask->bits.width == 1 && 633317c648bSmrg mask->bits.height == 1) 634317c648bSmrg { 635317c648bSmrg return TRUE; 636317c648bSmrg } 637317c648bSmrg 638317c648bSmrg return FALSE; 639317c648bSmrg} 640317c648bSmrg 641317c648bSmrgstatic const FastPathInfo * 642317c648bSmrgget_fast_path (const FastPathInfo *fast_paths, 643317c648bSmrg pixman_op_t op, 644317c648bSmrg pixman_image_t *pSrc, 645317c648bSmrg pixman_image_t *pMask, 646317c648bSmrg pixman_image_t *pDst, 647317c648bSmrg pixman_bool_t is_pixbuf) 648317c648bSmrg{ 649317c648bSmrg const FastPathInfo *info; 650317c648bSmrg 651317c648bSmrg for (info = fast_paths; info->op != PIXMAN_OP_NONE; info++) 652317c648bSmrg { 653317c648bSmrg pixman_bool_t valid_src = FALSE; 654317c648bSmrg pixman_bool_t valid_mask = FALSE; 655317c648bSmrg 656317c648bSmrg if (info->op != op) 657317c648bSmrg continue; 658317c648bSmrg 659317c648bSmrg if ((info->src_format == PIXMAN_solid && pixman_image_can_get_solid (pSrc)) || 660317c648bSmrg (pSrc->type == BITS && info->src_format == pSrc->bits.format)) 661317c648bSmrg { 662317c648bSmrg valid_src = TRUE; 663317c648bSmrg } 664317c648bSmrg 665317c648bSmrg if (!valid_src) 666317c648bSmrg continue; 667317c648bSmrg 668317c648bSmrg if ((info->mask_format == PIXMAN_null && !pMask) || 669317c648bSmrg (pMask && pMask->type == BITS && info->mask_format == pMask->bits.format)) 670317c648bSmrg { 671317c648bSmrg valid_mask = TRUE; 672317c648bSmrg 673317c648bSmrg if (info->flags & NEED_SOLID_MASK) 674317c648bSmrg { 675317c648bSmrg if (!pMask || !mask_is_solid (pMask)) 676317c648bSmrg valid_mask = FALSE; 677317c648bSmrg } 678317c648bSmrg 679317c648bSmrg if (info->flags & NEED_COMPONENT_ALPHA) 680317c648bSmrg { 681317c648bSmrg if (!pMask || !pMask->common.component_alpha) 682317c648bSmrg valid_mask = FALSE; 683317c648bSmrg } 684317c648bSmrg } 685317c648bSmrg 686317c648bSmrg if (!valid_mask) 687317c648bSmrg continue; 688317c648bSmrg 689317c648bSmrg if (info->dest_format != pDst->bits.format) 690317c648bSmrg continue; 691317c648bSmrg 692317c648bSmrg if ((info->flags & NEED_PIXBUF) && !is_pixbuf) 693317c648bSmrg continue; 694317c648bSmrg 695317c648bSmrg return info; 696317c648bSmrg } 697317c648bSmrg 698317c648bSmrg return NULL; 699317c648bSmrg} 700317c648bSmrg 701317c648bSmrgpixman_bool_t 702317c648bSmrg_pixman_run_fast_path (const FastPathInfo *paths, 703317c648bSmrg pixman_implementation_t *imp, 704317c648bSmrg pixman_op_t op, 705317c648bSmrg pixman_image_t *src, 706317c648bSmrg pixman_image_t *mask, 707317c648bSmrg pixman_image_t *dest, 708317c648bSmrg int32_t src_x, 709317c648bSmrg int32_t src_y, 710317c648bSmrg int32_t mask_x, 711317c648bSmrg int32_t mask_y, 712317c648bSmrg int32_t dest_x, 713317c648bSmrg int32_t dest_y, 714317c648bSmrg int32_t width, 715317c648bSmrg int32_t height) 716317c648bSmrg{ 717317c648bSmrg pixman_composite_func_t func = NULL; 718317c648bSmrg pixman_bool_t src_repeat = src->common.repeat == PIXMAN_REPEAT_NORMAL; 719317c648bSmrg pixman_bool_t mask_repeat = mask && mask->common.repeat == PIXMAN_REPEAT_NORMAL; 720317c648bSmrg 721317c648bSmrg if ((src->type == BITS || pixman_image_can_get_solid (src)) && 722317c648bSmrg (!mask || mask->type == BITS) 723317c648bSmrg && !src->common.transform && !(mask && mask->common.transform) 724317c648bSmrg && !(mask && mask->common.alpha_map) && !src->common.alpha_map && !dest->common.alpha_map 725317c648bSmrg && (src->common.filter != PIXMAN_FILTER_CONVOLUTION) 726317c648bSmrg && (src->common.repeat != PIXMAN_REPEAT_PAD) 727317c648bSmrg && (src->common.repeat != PIXMAN_REPEAT_REFLECT) 728317c648bSmrg && (!mask || (mask->common.filter != PIXMAN_FILTER_CONVOLUTION && 729317c648bSmrg mask->common.repeat != PIXMAN_REPEAT_PAD && 730317c648bSmrg mask->common.repeat != PIXMAN_REPEAT_REFLECT)) 731317c648bSmrg && !src->common.read_func && !src->common.write_func 732317c648bSmrg && !(mask && mask->common.read_func) 733317c648bSmrg && !(mask && mask->common.write_func) 734317c648bSmrg && !dest->common.read_func 735317c648bSmrg && !dest->common.write_func) 736317c648bSmrg { 737317c648bSmrg const FastPathInfo *info; 738317c648bSmrg pixman_bool_t pixbuf; 739317c648bSmrg 740317c648bSmrg pixbuf = 741317c648bSmrg src && src->type == BITS && 742317c648bSmrg mask && mask->type == BITS && 743317c648bSmrg src->bits.bits == mask->bits.bits && 744317c648bSmrg src_x == mask_x && 745317c648bSmrg src_y == mask_y && 746317c648bSmrg !mask->common.component_alpha && 747317c648bSmrg !mask_repeat; 748317c648bSmrg 749317c648bSmrg info = get_fast_path (paths, op, src, mask, dest, pixbuf); 750317c648bSmrg 751317c648bSmrg if (info) 752317c648bSmrg { 753317c648bSmrg func = info->func; 754317c648bSmrg 755317c648bSmrg if (info->src_format == PIXMAN_solid) 756317c648bSmrg src_repeat = FALSE; 757317c648bSmrg 758317c648bSmrg if (info->mask_format == PIXMAN_solid || info->flags & NEED_SOLID_MASK) 759317c648bSmrg mask_repeat = FALSE; 760317c648bSmrg 761317c648bSmrg if ((src_repeat && 762317c648bSmrg src->bits.width == 1 && 763317c648bSmrg src->bits.height == 1) || 764317c648bSmrg (mask_repeat && 765317c648bSmrg mask->bits.width == 1 && 766317c648bSmrg mask->bits.height == 1)) 767317c648bSmrg { 768317c648bSmrg /* If src or mask are repeating 1x1 images and src_repeat or 769317c648bSmrg * mask_repeat are still TRUE, it means the fast path we 770317c648bSmrg * selected does not actually handle repeating images. 771317c648bSmrg * 772317c648bSmrg * So rather than call the "fast path" with a zillion 773317c648bSmrg * 1x1 requests, we just fall back to the general code (which 774317c648bSmrg * does do something sensible with 1x1 repeating images). 775317c648bSmrg */ 776317c648bSmrg func = NULL; 777317c648bSmrg } 778317c648bSmrg } 779317c648bSmrg } 780317c648bSmrg 781317c648bSmrg if (func) 782317c648bSmrg { 783317c648bSmrg _pixman_walk_composite_region (imp, op, 784317c648bSmrg src, mask, dest, 785317c648bSmrg src_x, src_y, mask_x, mask_y, 786317c648bSmrg dest_x, dest_y, 787317c648bSmrg width, height, 788317c648bSmrg src_repeat, mask_repeat, 789317c648bSmrg func); 790317c648bSmrg return TRUE; 791317c648bSmrg } 792317c648bSmrg 793317c648bSmrg return FALSE; 794317c648bSmrg} 795