diff options
Diffstat (limited to 'Build/source/libs/pixman/pixman-src/pixman/pixman-bits-image.c')
-rw-r--r-- | Build/source/libs/pixman/pixman-src/pixman/pixman-bits-image.c | 177 |
1 files changed, 161 insertions, 16 deletions
diff --git a/Build/source/libs/pixman/pixman-src/pixman/pixman-bits-image.c b/Build/source/libs/pixman/pixman-src/pixman/pixman-bits-image.c index 564789e9c68..4cfabe318ae 100644 --- a/Build/source/libs/pixman/pixman-src/pixman/pixman-bits-image.c +++ b/Build/source/libs/pixman/pixman-src/pixman/pixman-bits-image.c @@ -35,6 +35,7 @@ #include "pixman-private.h" #include "pixman-combine32.h" #include "pixman-inlines.h" +#include "dither/blue-noise-64x64.h" /* Fetch functions */ @@ -190,8 +191,8 @@ bits_image_fetch_pixel_bilinear_float (bits_image_t *image, *ret = bilinear_interpolation_float (tl, tr, bl, br, distx, disty); } -static force_inline void accum_32(int *satot, int *srtot, - int *sgtot, int *sbtot, +static force_inline void accum_32(unsigned int *satot, unsigned int *srtot, + unsigned int *sgtot, unsigned int *sbtot, const void *p, pixman_fixed_t f) { uint32_t pixel = *(uint32_t *)p; @@ -202,8 +203,9 @@ static force_inline void accum_32(int *satot, int *srtot, *satot += (int)ALPHA_8 (pixel) * f; } -static force_inline void reduce_32(int satot, int srtot, - int sgtot, int sbtot, void *p) +static force_inline void reduce_32(unsigned int satot, unsigned int srtot, + unsigned int sgtot, unsigned int sbtot, + void *p) { uint32_t *ret = p; @@ -220,8 +222,8 @@ static force_inline void reduce_32(int satot, int srtot, *ret = ((satot << 24) | (srtot << 16) | (sgtot << 8) | (sbtot)); } -static force_inline void accum_float(int *satot, int *srtot, - int *sgtot, int *sbtot, +static force_inline void accum_float(unsigned int *satot, unsigned int *srtot, + unsigned int *sgtot, unsigned int *sbtot, const void *p, pixman_fixed_t f) { const argb_t *pixel = p; @@ -232,8 +234,8 @@ static force_inline void accum_float(int *satot, int *srtot, *sbtot += pixel->b * f; } -static force_inline void reduce_float(int satot, int srtot, - int sgtot, int sbtot, +static force_inline void reduce_float(unsigned int satot, unsigned int srtot, + unsigned int sgtot, unsigned int sbtot, void *p) { argb_t *ret = p; @@ -244,12 +246,13 @@ static force_inline void reduce_float(int satot, int srtot, ret->b = CLIP (sbtot / 65536.f, 0.f, 1.f); } -typedef void (* accumulate_pixel_t) (int *satot, int *srtot, - int *sgtot, int *sbtot, +typedef void (* accumulate_pixel_t) (unsigned int *satot, unsigned int *srtot, + unsigned int *sgtot, unsigned int *sbtot, const void *pixel, pixman_fixed_t f); -typedef void (* reduce_pixel_t) (int satot, int srtot, - int sgtot, int sbtot, void *out); +typedef void (* reduce_pixel_t) (unsigned int satot, unsigned int srtot, + unsigned int sgtot, unsigned int sbtot, + void *out); static force_inline void bits_image_fetch_pixel_convolution (bits_image_t *image, @@ -269,7 +272,7 @@ bits_image_fetch_pixel_convolution (bits_image_t *image, pixman_repeat_t repeat_mode = image->common.repeat; int width = image->width; int height = image->height; - int srtot, sgtot, sbtot, satot; + unsigned int srtot, sgtot, sbtot, satot; params += 2; @@ -338,7 +341,7 @@ bits_image_fetch_pixel_separable_convolution (bits_image_t *image, int x_off = ((cwidth << 16) - pixman_fixed_1) >> 1; int y_off = ((cheight << 16) - pixman_fixed_1) >> 1; pixman_fixed_t *y_params; - int srtot, sgtot, sbtot, satot; + unsigned int srtot, sgtot, sbtot, satot; int32_t x1, x2, y1, y2; int32_t px, py; int i, j; @@ -432,29 +435,38 @@ bits_image_fetch_pixel_filtered (bits_image_t *image, case PIXMAN_FILTER_CONVOLUTION: if (wide) + { bits_image_fetch_pixel_convolution (image, x, y, get_pixel, out, accum_float, reduce_float); + } else + { bits_image_fetch_pixel_convolution (image, x, y, get_pixel, out, accum_32, reduce_32); + } break; case PIXMAN_FILTER_SEPARABLE_CONVOLUTION: if (wide) + { bits_image_fetch_pixel_separable_convolution (image, x, y, get_pixel, out, accum_float, reduce_float); + } else + { bits_image_fetch_pixel_separable_convolution (image, x, y, get_pixel, out, accum_32, reduce_32); + } break; default: + assert (0); break; } } @@ -662,8 +674,8 @@ __bits_image_fetch_general (pixman_iter_t *iter, { if (w != 0) { - x0 = ((pixman_fixed_48_16_t)x << 16) / w; - y0 = ((pixman_fixed_48_16_t)y << 16) / w; + x0 = ((uint64_t)x << 16) / w; + y0 = ((uint64_t)y << 16) / w; } else { @@ -1039,6 +1051,119 @@ dest_write_back_narrow (pixman_iter_t *iter) iter->y++; } +static const float +dither_factor_blue_noise_64 (int x, int y) +{ + float m = dither_blue_noise_64x64[((y & 0x3f) << 6) | (x & 0x3f)]; + return m * (1. / 4096.f) + (1. / 8192.f); +} + +static const float +dither_factor_bayer_8 (int x, int y) +{ + uint32_t m; + + y ^= x; + + /* Compute reverse(interleave(xor(x mod n, y mod n), x mod n)) + * Here n = 8 and `mod n` is the bottom 3 bits. + */ + m = ((y & 0x1) << 5) | ((x & 0x1) << 4) | + ((y & 0x2) << 2) | ((x & 0x2) << 1) | + ((y & 0x4) >> 1) | ((x & 0x4) >> 2); + + /* m is in range [0, 63]. We scale it to [0, 63.0f/64.0f], then + * shift it to to [1.0f/128.0f, 127.0f/128.0f] so that 0 < d < 1. + * This ensures exact values are not changed by dithering. + */ + return (float)(m) * (1 / 64.0f) + (1.0f / 128.0f); +} + +typedef float (* dither_factor_t)(int x, int y); + +static force_inline float +dither_apply_channel (float f, float d, float s) +{ + /* float_to_unorm splits the [0, 1] segment in (1 << n_bits) + * subsections of equal length; however unorm_to_float does not + * map to the center of those sections. In fact, pixel value u is + * mapped to: + * + * u u u 1 + * -------------- = ---------- + -------------- * ---------- + * 2^n_bits - 1 2^n_bits 2^n_bits - 1 2^n_bits + * + * Hence if f = u / (2^n_bits - 1) is exactly representable on a + * n_bits palette, all the numbers between + * + * u + * ---------- = f - f * 2^n_bits = f + (0 - f) * 2^n_bits + * 2^n_bits + * + * and + * + * u + 1 + * ---------- = f - (f - 1) * 2^n_bits = f + (1 - f) * 2^n_bits + * 2^n_bits + * + * are also mapped back to u. + * + * Hence the following calculation ensures that we add as much + * noise as possible without perturbing values which are exactly + * representable in the target colorspace. Note that this corresponds to + * mixing the original color with noise with a ratio of `1 / 2^n_bits`. + */ + return f + (d - f) * s; +} + +static force_inline float +dither_compute_scale (int n_bits) +{ + // No dithering for wide formats + if (n_bits == 0 || n_bits >= 32) + return 0.f; + + return 1.f / (float)(1 << n_bits); +} + +static const uint32_t * +dither_apply_ordered (pixman_iter_t *iter, dither_factor_t factor) +{ + bits_image_t *image = &iter->image->bits; + int x = iter->x + image->dither_offset_x; + int y = iter->y + image->dither_offset_y; + int width = iter->width; + argb_t *buffer = (argb_t *)iter->buffer; + + pixman_format_code_t format = image->format; + int a_size = PIXMAN_FORMAT_A (format); + int r_size = PIXMAN_FORMAT_R (format); + int g_size = PIXMAN_FORMAT_G (format); + int b_size = PIXMAN_FORMAT_B (format); + + float a_scale = dither_compute_scale (a_size); + float r_scale = dither_compute_scale (r_size); + float g_scale = dither_compute_scale (g_size); + float b_scale = dither_compute_scale (b_size); + + int i; + float d; + + for (i = 0; i < width; ++i) + { + d = factor (x + i, y); + + buffer->a = dither_apply_channel (buffer->a, d, a_scale); + buffer->r = dither_apply_channel (buffer->r, d, r_scale); + buffer->g = dither_apply_channel (buffer->g, d, g_scale); + buffer->b = dither_apply_channel (buffer->b, d, b_scale); + + buffer++; + } + + return iter->buffer; +} + static void dest_write_back_wide (pixman_iter_t *iter) { @@ -1048,6 +1173,23 @@ dest_write_back_wide (pixman_iter_t *iter) int width = iter->width; const uint32_t *buffer = iter->buffer; + switch (image->dither) + { + case PIXMAN_DITHER_NONE: + break; + + case PIXMAN_DITHER_GOOD: + case PIXMAN_DITHER_BEST: + case PIXMAN_DITHER_ORDERED_BLUE_NOISE_64: + buffer = dither_apply_ordered (iter, dither_factor_blue_noise_64); + break; + + case PIXMAN_DITHER_FAST: + case PIXMAN_DITHER_ORDERED_BAYER_8: + buffer = dither_apply_ordered (iter, dither_factor_bayer_8); + break; + } + image->store_scanline_float (image, x, y, width, buffer); if (image->common.alpha_map) @@ -1163,6 +1305,9 @@ _pixman_bits_image_init (pixman_image_t * image, image->bits.height = height; image->bits.bits = bits; image->bits.free_me = free_me; + image->bits.dither = PIXMAN_DITHER_NONE; + image->bits.dither_offset_x = 0; + image->bits.dither_offset_y = 0; image->bits.read_func = NULL; image->bits.write_func = NULL; image->bits.rowstride = rowstride; |