From deef1daf5896062f47fa61b94e1e77c7c0041820 Mon Sep 17 00:00:00 2001 From: Siarhei Siamashka Date: Fri, 04 Dec 2009 16:49:19 +0000 Subject: A copy-paste version of 16bpp bilinear scanline fetcher --- diff --git a/pixman/pixman-bits-image.c b/pixman/pixman-bits-image.c index 3d78ff0..1656975 100644 --- a/pixman/pixman-bits-image.c +++ b/pixman/pixman-bits-image.c @@ -535,6 +535,212 @@ bits_image_fetch_bilinear_no_repeat_8888 (pixman_image_t * ima, *buffer++ = 0; } +static void +bits_image_fetch_bilinear_no_repeat_0565 (pixman_image_t * ima, + int offset, + int line, + int width, + uint32_t * buffer, + const uint32_t * mask, + uint32_t mask_bits) +{ + bits_image_t *bits = &ima->bits; + pixman_fixed_t x_top, x_bottom, x; + pixman_fixed_t ux_top, ux_bottom, ux; + pixman_vector_t v; + uint32_t top_mask, bottom_mask; + uint16_t *top_row; + uint16_t *bottom_row; + uint32_t *end; + uint16_t zero[2] = { 0, 0 }; + int y, y1, y2; + int disty; + int mask_inc; + int w; + + /* reference point is the center of the pixel */ + v.vector[0] = pixman_int_to_fixed (offset) + pixman_fixed_1 / 2; + v.vector[1] = pixman_int_to_fixed (line) + pixman_fixed_1 / 2; + v.vector[2] = pixman_fixed_1; + + if (!pixman_transform_point_3d (bits->common.transform, &v)) + return; + + ux = ux_top = ux_bottom = bits->common.transform->matrix[0][0]; + x = x_top = x_bottom = v.vector[0] - pixman_fixed_1/2; + + y = v.vector[1] - pixman_fixed_1/2; + disty = (y >> 8) & 0xff; + + /* Load the pointers to the first and second lines from the source + * image that bilinear code must read. + * + * The main trick in this code is about the check if any line are + * outside of the image; + * + * When I realize that a line (any one) is outside, I change + * the pointer to a dummy area with zeros. Once I change this, I + * must be sure the pointer will not change, so I set the + * variables to each pointer increments inside the loop. + */ + y1 = pixman_fixed_to_int (y); + y2 = y1 + 1; + + if (y1 < 0 || y1 >= bits->height) + { + top_row = zero; + x_top = 0; + ux_top = 0; + } + else + { + top_row = bits->bits + y1 * bits->rowstride; + x_top = x; + ux_top = ux; + } + + if (y2 < 0 || y2 >= bits->height) + { + bottom_row = zero; + x_bottom = 0; + ux_bottom = 0; + } + else + { + bottom_row = bits->bits + y2 * bits->rowstride; + x_bottom = x; + ux_bottom = ux; + } + + /* Instead of checking whether the operation uses the mast in + * each loop iteration, verify this only once and prepare the + * variables to make the code smaller inside the loop. + */ + if (!mask) + { + mask_inc = 0; + mask_bits = 1; + mask = &mask_bits; + } + else + { + /* If have a mask, prepare the variables to check it */ + mask_inc = 1; + } + + /* If both are zero, then the whole thing is zero */ + if (top_row == zero && bottom_row == zero) + { + memset (buffer, 0, width * sizeof (uint32_t)); + return; + } + else + { + if (top_row == zero) + { + top_mask = 0; + bottom_mask = 0xff000000; + } + else if (bottom_row == zero) + { + top_mask = 0xff000000; + bottom_mask = 0; + } + else + { + top_mask = 0xff000000; + bottom_mask = 0xff000000; + } + } + + end = buffer + width; + + /* Zero fill to the left of the image */ + while (buffer < end && x < pixman_fixed_minus_1) + { + *buffer++ = 0; + x += ux; + x_top += ux_top; + x_bottom += ux_bottom; + mask += mask_inc; + } + + /* Left edge + */ + while (buffer < end && x < 0) + { + uint32_t tr, br; + int32_t distx; + + tr = CONVERT_0565_TO_0888 (top_row[pixman_fixed_to_int (x_top) + 1]) | top_mask; + br = CONVERT_0565_TO_0888 (bottom_row[pixman_fixed_to_int (x_bottom) + 1]) | bottom_mask; + + distx = (x >> 8) & 0xff; + + *buffer++ = bilinear_interpolation (0, tr, 0, br, distx, disty); + + x += ux; + x_top += ux_top; + x_bottom += ux_bottom; + mask += mask_inc; + } + + /* Main part */ + w = pixman_int_to_fixed (bits->width - 1); + + while (buffer < end && x < w) + { + if (*mask) + { + uint32_t tl, tr, bl, br; + int32_t distx; + + tl = CONVERT_0565_TO_0888 (top_row [pixman_fixed_to_int (x_top)]) | top_mask; + tr = CONVERT_0565_TO_0888 (top_row [pixman_fixed_to_int (x_top) + 1]) | top_mask; + bl = CONVERT_0565_TO_0888 (bottom_row [pixman_fixed_to_int (x_bottom)]) | bottom_mask; + br = CONVERT_0565_TO_0888 (bottom_row [pixman_fixed_to_int (x_bottom) + 1]) | bottom_mask; + + distx = (x >> 8) & 0xff; + + *buffer = bilinear_interpolation (tl, tr, bl, br, distx, disty); + } + + buffer++; + x += ux; + x_top += ux_top; + x_bottom += ux_bottom; + mask += mask_inc; + } + + /* Right Edge */ + w = pixman_int_to_fixed (bits->width); + while (buffer < end && x < w) + { + if (*mask) + { + uint32_t tl, bl; + int32_t distx; + + tl = CONVERT_0565_TO_0888 (top_row [pixman_fixed_to_int (x_top)]) | top_mask; + bl = CONVERT_0565_TO_0888 (bottom_row [pixman_fixed_to_int (x_bottom)]) | bottom_mask; + + distx = (x >> 8) & 0xff; + + *buffer = bilinear_interpolation (tl, 0, bl, 0, distx, disty); + } + + buffer++; + x += ux; + x_top += ux_top; + x_bottom += ux_bottom; + mask += mask_inc; + } + + /* Zero fill to the left of the image */ + while (buffer < end) + *buffer++ = 0; +} + static force_inline uint32_t bits_image_fetch_pixel_convolution (bits_image_t *image, pixman_fixed_t x, @@ -917,14 +1123,26 @@ bits_image_property_changed (pixman_image_t *image) (bits->common.filter == PIXMAN_FILTER_BILINEAR || bits->common.filter == PIXMAN_FILTER_GOOD || bits->common.filter == PIXMAN_FILTER_BEST) && - bits->common.repeat == PIXMAN_REPEAT_NONE && - (bits->format == PIXMAN_a8r8g8b8 || - bits->format == PIXMAN_x8r8g8b8)) + bits->common.repeat == PIXMAN_REPEAT_NONE) { image->common.get_scanline_64 = _pixman_image_get_scanline_generic_64; - image->common.get_scanline_32 = - bits_image_fetch_bilinear_no_repeat_8888; + + if (bits->format == PIXMAN_a8r8g8b8 || bits->format == PIXMAN_x8r8g8b8) + { + image->common.get_scanline_32 = + bits_image_fetch_bilinear_no_repeat_8888; + } + else if (bits->format == PIXMAN_r5g6b5) + { + image->common.get_scanline_32 = + bits_image_fetch_bilinear_no_repeat_0565; + } + else + { + image->common.get_scanline_32 = + bits_image_fetch_transformed; + } } else { -- cgit v0.8.3-6-g21f6