diff options
Diffstat (limited to 'pixman')
-rw-r--r-- | pixman/.gitignore | 2 | ||||
-rw-r--r-- | pixman/demos/Makefile.am | 2 | ||||
-rw-r--r-- | pixman/demos/linear-gradient.c | 50 | ||||
-rw-r--r-- | pixman/pixman/pixman-combine-float.c | 34 | ||||
-rw-r--r-- | pixman/pixman/pixman-gradient-walker.c | 106 | ||||
-rw-r--r-- | pixman/pixman/pixman-private.h | 13 | ||||
-rw-r--r-- | pixman/test/Makefile.sources | 3 | ||||
-rw-r--r-- | pixman/test/radial-perf-test.c | 58 |
8 files changed, 206 insertions, 62 deletions
diff --git a/pixman/.gitignore b/pixman/.gitignore index 648699bf2..0f114966c 100644 --- a/pixman/.gitignore +++ b/pixman/.gitignore @@ -34,6 +34,7 @@ demos/composite-test demos/conical-test demos/convolution-test demos/gradient-test +demos/linear-gradient demos/quad2quad demos/radial-test demos/scale @@ -66,6 +67,7 @@ test/lowlevel-blt-bench test/oob-test test/pdf-op-test test/prng-test +test/radial-perf-test test/region-contains-test test/region-test test/region-translate diff --git a/pixman/demos/Makefile.am b/pixman/demos/Makefile.am index 5f53407b0..9be9ab670 100644 --- a/pixman/demos/Makefile.am +++ b/pixman/demos/Makefile.am @@ -15,6 +15,7 @@ DEMOS = \ composite-test \ gradient-test \ radial-test \ + linear-gradient \ conical-test \ alpha-test \ screen-test \ @@ -38,6 +39,7 @@ trap_test_SOURCES = trap-test.c $(GTK_UTILS) screen_test_SOURCES = screen-test.c $(GTK_UTILS) convolution_test_SOURCES = convolution-test.c $(GTK_UTILS) radial_test_SOURCES = radial-test.c $(GTK_UTILS) +linear_gradient_SOURCES = linear-gradient.c $(GTK_UTILS) conical_test_SOURCES = conical-test.c $(GTK_UTILS) tri_test_SOURCES = tri-test.c $(GTK_UTILS) checkerboard_SOURCES = checkerboard.c $(GTK_UTILS) diff --git a/pixman/demos/linear-gradient.c b/pixman/demos/linear-gradient.c new file mode 100644 index 000000000..46433a6e5 --- /dev/null +++ b/pixman/demos/linear-gradient.c @@ -0,0 +1,50 @@ +#include "../test/utils.h" +#include "gtk-utils.h" + +#define WIDTH 1024 +#define HEIGHT 640 + +int +main (int argc, char **argv) +{ + pixman_image_t *src_img, *dest_img; + pixman_gradient_stop_t stops[] = { + { 0x00000, { 0x0000, 0x0000, 0x4444, 0xdddd } }, + { 0x10000, { 0xeeee, 0xeeee, 0x8888, 0xdddd } }, +#if 0 + /* These colors make it very obvious that dithering + * is useful even for 8-bit gradients + */ + { 0x00000, { 0x6666, 0x3333, 0x3333, 0xffff } }, + { 0x10000, { 0x3333, 0x6666, 0x6666, 0xffff } }, +#endif + }; + pixman_point_fixed_t p1, p2; + + enable_divbyzero_exceptions (); + + dest_img = pixman_image_create_bits (PIXMAN_x8r8g8b8, + WIDTH, HEIGHT, + NULL, 0); + + p1.x = p1.y = 0x0000; + p2.x = WIDTH << 16; + p2.y = HEIGHT << 16; + + src_img = pixman_image_create_linear_gradient (&p1, &p2, stops, ARRAY_LENGTH (stops)); + + pixman_image_composite32 (PIXMAN_OP_OVER, + src_img, + NULL, + dest_img, + 0, 0, + 0, 0, + 0, 0, + WIDTH, HEIGHT); + + show_image (dest_img); + + pixman_image_unref (dest_img); + + return 0; +} diff --git a/pixman/pixman/pixman-combine-float.c b/pixman/pixman/pixman-combine-float.c index 06ce2037e..5ea739f76 100644 --- a/pixman/pixman/pixman-combine-float.c +++ b/pixman/pixman/pixman-combine-float.c @@ -42,8 +42,6 @@ #define force_inline __inline__ #endif -#define IS_ZERO(f) (-FLT_MIN < (f) && (f) < FLT_MIN) - typedef float (* combine_channel_t) (float sa, float s, float da, float d); static force_inline void @@ -203,56 +201,56 @@ get_factor (combine_factor_t factor, float sa, float da) break; case SA_OVER_DA: - if (IS_ZERO (da)) + if (FLOAT_IS_ZERO (da)) f = 1.0f; else f = CLAMP (sa / da); break; case DA_OVER_SA: - if (IS_ZERO (sa)) + if (FLOAT_IS_ZERO (sa)) f = 1.0f; else f = CLAMP (da / sa); break; case INV_SA_OVER_DA: - if (IS_ZERO (da)) + if (FLOAT_IS_ZERO (da)) f = 1.0f; else f = CLAMP ((1.0f - sa) / da); break; case INV_DA_OVER_SA: - if (IS_ZERO (sa)) + if (FLOAT_IS_ZERO (sa)) f = 1.0f; else f = CLAMP ((1.0f - da) / sa); break; case ONE_MINUS_SA_OVER_DA: - if (IS_ZERO (da)) + if (FLOAT_IS_ZERO (da)) f = 0.0f; else f = CLAMP (1.0f - sa / da); break; case ONE_MINUS_DA_OVER_SA: - if (IS_ZERO (sa)) + if (FLOAT_IS_ZERO (sa)) f = 0.0f; else f = CLAMP (1.0f - da / sa); break; case ONE_MINUS_INV_DA_OVER_SA: - if (IS_ZERO (sa)) + if (FLOAT_IS_ZERO (sa)) f = 0.0f; else f = CLAMP (1.0f - (1.0f - da) / sa); break; case ONE_MINUS_INV_SA_OVER_DA: - if (IS_ZERO (da)) + if (FLOAT_IS_ZERO (da)) f = 0.0f; else f = CLAMP (1.0f - (1.0f - sa) / da); @@ -405,11 +403,11 @@ blend_lighten (float sa, float s, float da, float d) static force_inline float blend_color_dodge (float sa, float s, float da, float d) { - if (IS_ZERO (d)) + if (FLOAT_IS_ZERO (d)) return 0.0f; else if (d * sa >= sa * da - s * da) return sa * da; - else if (IS_ZERO (sa - s)) + else if (FLOAT_IS_ZERO (sa - s)) return sa * da; else return sa * sa * d / (sa - s); @@ -422,7 +420,7 @@ blend_color_burn (float sa, float s, float da, float d) return sa * da; else if (sa * (da - d) >= s * da) return 0.0f; - else if (IS_ZERO (s)) + else if (FLOAT_IS_ZERO (s)) return 0.0f; else return sa * (da - sa * (da - d) / s); @@ -442,14 +440,14 @@ blend_soft_light (float sa, float s, float da, float d) { if (2 * s < sa) { - if (IS_ZERO (da)) + if (FLOAT_IS_ZERO (da)) return d * sa; else return d * sa - d * (da - d) * (sa - 2 * s) / da; } else { - if (IS_ZERO (da)) + if (FLOAT_IS_ZERO (da)) { return 0.0f; } @@ -658,7 +656,7 @@ clip_color (rgb_t *color, float a) if (n < 0.0f) { t = l - n; - if (IS_ZERO (t)) + if (FLOAT_IS_ZERO (t)) { color->r = 0.0f; color->g = 0.0f; @@ -674,7 +672,7 @@ clip_color (rgb_t *color, float a) if (x > a) { t = x - l; - if (IS_ZERO (t)) + if (FLOAT_IS_ZERO (t)) { color->r = a; color->g = a; @@ -758,7 +756,7 @@ set_sat (rgb_t *src, float sat) t = *max - *min; - if (IS_ZERO (t)) + if (FLOAT_IS_ZERO (t)) { *mid = *max = 0.0f; } diff --git a/pixman/pixman/pixman-gradient-walker.c b/pixman/pixman/pixman-gradient-walker.c index e7e724fa6..5944a559a 100644 --- a/pixman/pixman/pixman-gradient-walker.c +++ b/pixman/pixman/pixman-gradient-walker.c @@ -37,11 +37,14 @@ _pixman_gradient_walker_init (pixman_gradient_walker_t *walker, walker->stops = gradient->stops; walker->left_x = 0; walker->right_x = 0x10000; - walker->stepper = 0; - walker->left_ag = 0; - walker->left_rb = 0; - walker->right_ag = 0; - walker->right_rb = 0; + walker->a_s = 0.0f; + walker->a_b = 0.0f; + walker->r_s = 0.0f; + walker->r_b = 0.0f; + walker->g_s = 0.0f; + walker->g_b = 0.0f; + walker->b_s = 0.0f; + walker->b_b = 0.0f; walker->repeat = repeat; walker->need_reset = TRUE; @@ -55,6 +58,9 @@ gradient_walker_reset (pixman_gradient_walker_t *walker, pixman_color_t *left_c, *right_c; int n, count = walker->num_stops; pixman_gradient_stop_t *stops = walker->stops; + float la, lr, lg, lb; + float ra, rr, rg, rb; + float lx, rx; if (walker->repeat == PIXMAN_REPEAT_NORMAL) { @@ -116,24 +122,49 @@ gradient_walker_reset (pixman_gradient_walker_t *walker, left_c = right_c; } - walker->left_x = left_x; - walker->right_x = right_x; - walker->left_ag = ((left_c->alpha >> 8) << 16) | (left_c->green >> 8); - walker->left_rb = ((left_c->red & 0xff00) << 8) | (left_c->blue >> 8); - walker->right_ag = ((right_c->alpha >> 8) << 16) | (right_c->green >> 8); - walker->right_rb = ((right_c->red & 0xff00) << 8) | (right_c->blue >> 8); - - if (walker->left_x == walker->right_x || - (walker->left_ag == walker->right_ag && - walker->left_rb == walker->right_rb)) + /* The alpha channel is scaled to be in the [0, 255] interval, + * and the red/green/blue channels are scaled to be in [0, 1]. + * This ensures that after premultiplication all channels will + * be in the [0, 255] interval. + */ + la = (left_c->alpha * (1.0f/257.0f)); + lr = (left_c->red * (1.0f/257.0f)); + lg = (left_c->green * (1.0f/257.0f)); + lb = (left_c->blue * (1.0f/257.0f)); + + ra = (right_c->alpha * (1.0f/257.0f)); + rr = (right_c->red * (1.0f/257.0f)); + rg = (right_c->green * (1.0f/257.0f)); + rb = (right_c->blue * (1.0f/257.0f)); + + lx = left_x * (1.0f/65536.0f); + rx = right_x * (1.0f/65536.0f); + + if (FLOAT_IS_ZERO (rx - lx) || left_x == INT32_MIN || right_x == INT32_MAX) { - walker->stepper = 0; + walker->a_s = walker->r_s = walker->g_s = walker->b_s = 0.0f; + walker->a_b = (la + ra) / 2.0f; + walker->r_b = (lr + rr) / 510.0f; + walker->g_b = (lg + rg) / 510.0f; + walker->b_b = (lb + rb) / 510.0f; } else { - int32_t width = right_x - left_x; - walker->stepper = ((1 << 24) + width / 2) / width; + float w_rec = 1.0f / (rx - lx); + + walker->a_b = (la * rx - ra * lx) * w_rec; + walker->r_b = (lr * rx - rr * lx) * w_rec * (1.0f/255.0f); + walker->g_b = (lg * rx - rg * lx) * w_rec * (1.0f/255.0f); + walker->b_b = (lb * rx - rb * lx) * w_rec * (1.0f/255.0f); + + walker->a_s = (ra - la) * w_rec; + walker->r_s = (rr - lr) * w_rec * (1.0f/255.0f); + walker->g_s = (rg - lg) * w_rec * (1.0f/255.0f); + walker->b_s = (rb - lb) * w_rec * (1.0f/255.0f); } + + walker->left_x = left_x; + walker->right_x = right_x; walker->need_reset = FALSE; } @@ -142,31 +173,30 @@ uint32_t _pixman_gradient_walker_pixel (pixman_gradient_walker_t *walker, pixman_fixed_48_16_t x) { - int dist, idist; - uint32_t t1, t2, a, color; + float a, r, g, b; + uint8_t a8, r8, g8, b8; + uint32_t v; + float y; if (walker->need_reset || x < walker->left_x || x >= walker->right_x) - gradient_walker_reset (walker, x); - - dist = ((int)(x - walker->left_x) * walker->stepper) >> 16; - idist = 256 - dist; + gradient_walker_reset (walker, x); - /* combined INTERPOLATE and premultiply */ - t1 = walker->left_rb * idist + walker->right_rb * dist; - t1 = (t1 >> 8) & 0xff00ff; + y = x * (1.0f / 65536.0f); - t2 = walker->left_ag * idist + walker->right_ag * dist; - t2 &= 0xff00ff00; + a = walker->a_s * y + walker->a_b; + r = a * (walker->r_s * y + walker->r_b); + g = a * (walker->g_s * y + walker->g_b); + b = a * (walker->b_s * y + walker->b_b); - color = t2 & 0xff000000; - a = t2 >> 24; + a8 = a + 0.5f; + r8 = r + 0.5f; + g8 = g + 0.5f; + b8 = b + 0.5f; - t1 = t1 * a + 0x800080; - t1 = (t1 + ((t1 >> 8) & 0xff00ff)) >> 8; + v = ((a8 << 24) & 0xff000000) | + ((r8 << 16) & 0x00ff0000) | + ((g8 << 8) & 0x0000ff00) | + ((b8 >> 0) & 0x000000ff); - t2 = (t2 >> 8) * a + 0x800080; - t2 = (t2 + ((t2 >> 8) & 0xff00ff)); - - return (color | (t1 & 0xff00ff) | (t2 & 0xff00)); + return v; } - diff --git a/pixman/pixman/pixman-private.h b/pixman/pixman/pixman-private.h index 181ab5c35..6d9c05321 100644 --- a/pixman/pixman/pixman-private.h +++ b/pixman/pixman/pixman-private.h @@ -1,3 +1,5 @@ +#include <float.h> + #ifndef PIXMAN_PRIVATE_H #define PIXMAN_PRIVATE_H @@ -317,13 +319,12 @@ _pixman_image_validate (pixman_image_t *image); */ typedef struct { - uint32_t left_ag; - uint32_t left_rb; - uint32_t right_ag; - uint32_t right_rb; + float a_s, a_b; + float r_s, r_b; + float g_s, g_b; + float b_s, b_b; pixman_fixed_t left_x; pixman_fixed_t right_x; - pixman_fixed_t stepper; pixman_gradient_stop_t *stops; int num_stops; @@ -879,6 +880,8 @@ pixman_list_move_to_front (pixman_list_t *list, pixman_link_t *link) #define CLIP(v, low, high) ((v) < (low) ? (low) : ((v) > (high) ? (high) : (v))) +#define FLOAT_IS_ZERO(f) (-FLT_MIN < (f) && (f) < FLT_MIN) + /* Conversion between 8888 and 0565 */ static force_inline uint16_t diff --git a/pixman/test/Makefile.sources b/pixman/test/Makefile.sources index 5b30970b9..b5fc740f3 100644 --- a/pixman/test/Makefile.sources +++ b/pixman/test/Makefile.sources @@ -28,9 +28,10 @@ TESTPROGRAMS = \ composite \ $(NULL) -# Benchmarks +# Other programs OTHERPROGRAMS = \ lowlevel-blt-bench \ + radial-perf-test \ check-formats \ $(NULL) diff --git a/pixman/test/radial-perf-test.c b/pixman/test/radial-perf-test.c new file mode 100644 index 000000000..71092e27b --- /dev/null +++ b/pixman/test/radial-perf-test.c @@ -0,0 +1,58 @@ +#include "utils.h" +#include <stdio.h> + +int +main () +{ + static const pixman_point_fixed_t inner = { 0x0000, 0x0000 }; + static const pixman_point_fixed_t outer = { 0x0000, 0x0000 }; + static const pixman_fixed_t r_inner = 0; + static const pixman_fixed_t r_outer = 64 << 16; + static const pixman_gradient_stop_t stops[] = { + { 0x00000, { 0x6666, 0x6666, 0x6666, 0xffff } }, + { 0x10000, { 0x0000, 0x0000, 0x0000, 0xffff } } + }; + static const pixman_transform_t transform = { + { { 0x0, 0x26ee, 0x0}, + { 0xffffeeef, 0x0, 0x0}, + { 0x0, 0x0, 0x10000} + } + }; + static const pixman_color_t z = { 0x0000, 0x0000, 0x0000, 0x0000 }; + pixman_image_t *dest, *radial, *zero; + int i; + double before, after; + + dest = pixman_image_create_bits ( + PIXMAN_x8r8g8b8, 640, 429, NULL, -1); + zero = pixman_image_create_solid_fill (&z); + radial = pixman_image_create_radial_gradient ( + &inner, &outer, r_inner, r_outer, stops, ARRAY_LENGTH (stops)); + pixman_image_set_transform (radial, &transform); + pixman_image_set_repeat (radial, PIXMAN_REPEAT_PAD); + +#define N_COMPOSITE 500 + + before = gettime(); + for (i = 0; i < N_COMPOSITE; ++i) + { + before -= gettime(); + + pixman_image_composite ( + PIXMAN_OP_SRC, zero, NULL, dest, + 0, 0, 0, 0, 0, 0, 640, 429); + + before += gettime(); + + pixman_image_composite32 ( + PIXMAN_OP_OVER, radial, NULL, dest, + - 150, -158, 0, 0, 0, 0, 640, 361); + } + + after = gettime(); + + write_png (dest, "radial.png"); + + printf ("Average time to composite: %f\n", (after - before) / N_COMPOSITE); + return 0; +} |