Re: [Pixman] [PATCH 2/2] pixman: Use maximum precision for pixman-bits-image

2019-01-03 Thread Maarten Lankhorst
Oops, missing commit description..

pixman-bits-image's wide helpers first obtains the 8-bits image,
then converts it to float. This destroys all the precision that
the wide path was offering.

Fix this by making get_pixel() take a pointer instead of returning
a value. Floating point will fill in a argb_t, while the 8-bits path
will fill a 32-bits ARGB value. This also requires writing a floating
point bilinear interpolator. With this change pixman can use the full
floating point precision internally in all paths.

Op 03-01-2019 om 12:18 schreef Maarten Lankhorst:
> Signed-off-by: Maarten Lankhorst 
> ---
>  pixman/pixman-bits-image.c | 478 ++---
>  pixman/pixman-inlines.h|  25 ++
>  2 files changed, 418 insertions(+), 85 deletions(-)
>
> diff --git a/pixman/pixman-bits-image.c b/pixman/pixman-bits-image.c
> index 9fb91ff5831d..cb1c5ce12d46 100644
> --- a/pixman/pixman-bits-image.c
> +++ b/pixman/pixman-bits-image.c
> @@ -36,43 +36,45 @@
>  #include "pixman-combine32.h"
>  #include "pixman-inlines.h"
>  
> -static uint32_t *
> -_pixman_image_get_scanline_generic_float (pixman_iter_t * iter,
> -   const uint32_t *mask)
> -{
> -pixman_iter_get_scanline_t fetch_32 = iter->data;
> -uint32_t *buffer = iter->buffer;
> -
> -fetch_32 (iter, NULL);
> +/* Fetch functions */
>  
> -pixman_expand_to_float ((argb_t *)buffer, buffer, PIXMAN_a8r8g8b8, 
> iter->width);
> +static force_inline void
> +fetch_pixel_no_alpha_32 (bits_image_t *image,
> +  int x, int y, pixman_bool_t check_bounds,
> +  void *out)
> +{
> +uint32_t *ret = out;
>  
> -return iter->buffer;
> +if (check_bounds &&
> + (x < 0 || x >= image->width || y < 0 || y >= image->height))
> + *ret = 0;
> +else
> + *ret = image->fetch_pixel_32 (image, x, y);
>  }
>  
> -/* Fetch functions */
> -
> -static force_inline uint32_t
> -fetch_pixel_no_alpha (bits_image_t *image,
> -   int x, int y, pixman_bool_t check_bounds)
> +static force_inline void
> +fetch_pixel_no_alpha_float (bits_image_t *image,
> + int x, int y, pixman_bool_t check_bounds,
> + void *out)
>  {
> +argb_t *ret = out;
> +
>  if (check_bounds &&
>   (x < 0 || x >= image->width || y < 0 || y >= image->height))
> -{
> - return 0;
> -}
> -
> -return image->fetch_pixel_32 (image, x, y);
> + ret->a = ret->r = ret->g = ret->b = 0.f;
> +else
> + *ret = image->fetch_pixel_float (image, x, y);
>  }
>  
> -typedef uint32_t (* get_pixel_t) (bits_image_t *image,
> -   int x, int y, pixman_bool_t check_bounds);
> +typedef void (* get_pixel_t) (bits_image_t *image,
> +   int x, int y, pixman_bool_t check_bounds, void 
> *out);
>  
> -static force_inline uint32_t
> +static force_inline void
>  bits_image_fetch_pixel_nearest (bits_image_t   *image,
>   pixman_fixed_t  x,
>   pixman_fixed_t  y,
> - get_pixel_t get_pixel)
> + get_pixel_t get_pixel,
> + void   *out)
>  {
>  int x0 = pixman_fixed_to_int (x - pixman_fixed_e);
>  int y0 = pixman_fixed_to_int (y - pixman_fixed_e);
> @@ -82,19 +84,20 @@ bits_image_fetch_pixel_nearest (bits_image_t   *image,
>   repeat (image->common.repeat, , image->width);
>   repeat (image->common.repeat, , image->height);
>  
> - return get_pixel (image, x0, y0, FALSE);
> + get_pixel (image, x0, y0, FALSE, out);
>  }
>  else
>  {
> - return get_pixel (image, x0, y0, TRUE);
> + get_pixel (image, x0, y0, TRUE, out);
>  }
>  }
>  
> -static force_inline uint32_t
> -bits_image_fetch_pixel_bilinear (bits_image_t   *image,
> -  pixman_fixed_t  x,
> -  pixman_fixed_t  y,
> -  get_pixel_t get_pixel)
> +static force_inline void
> +bits_image_fetch_pixel_bilinear_32 (bits_image_t   *image,
> + pixman_fixed_t  x,
> + pixman_fixed_t  y,
> + get_pixel_t get_pixel,
> + void   *out)
>  {
>  pixman_repeat_t repeat_mode = image->common.repeat;
>  int width = image->width;
> @@ -102,6 +105,7 @@ bits_image_fetch_pixel_bilinear (bits_image_t   *image,
>  int x1, y1, x2, y2;
>  uint32_t tl, tr, bl, br;
>  int32_t distx, disty;
> +uint32_t *ret = out;
>  
>  x1 = x - pixman_fixed_1 / 2;
>  y1 = y - pixman_fixed_1 / 2;
> @@ -121,27 +125,77 @@ bits_image_fetch_pixel_bilinear (bits_image_t   *image,
>   repeat (repeat_mode, , width);
>   repeat (repeat_mode, , height);
>  
> - tl = get_pixel (image, x1, y1, FALSE);
> - bl = 

[Pixman] [PATCH 1/2] Implement floating point gradient computation

2019-01-03 Thread Maarten Lankhorst
From: Basile Clement 

This patch modifies the gradient walker to be able to generate floating
point values directly in addition to a8r8g8b8 32 bit values.  This is
then used by the various gradient implementations to render in floating
point when asked to do so, instead of rendering to a8r8g8b8 and then
expanding to floating point as they were doing previously.

Signed-off-by: Maarten Lankhorst 
---
 pixman/pixman-conical-gradient.c |  36 ++
 pixman/pixman-gradient-walker.c  |  92 ++---
 pixman/pixman-linear-gradient.c  |  49 --
 pixman/pixman-private.h  |  65 ++
 pixman/pixman-radial-gradient.c  | 112 ++-
 5 files changed, 234 insertions(+), 120 deletions(-)

diff --git a/pixman/pixman-conical-gradient.c b/pixman/pixman-conical-gradient.c
index 8bb46aecdcab..a39e20c4eb68 100644
--- a/pixman/pixman-conical-gradient.c
+++ b/pixman/pixman-conical-gradient.c
@@ -51,7 +51,10 @@ coordinates_to_parameter (double x, double y, double angle)
 }
 
 static uint32_t *
-conical_get_scanline_narrow (pixman_iter_t *iter, const uint32_t *mask)
+conical_get_scanline (pixman_iter_t *iter,
+ const uint32_t*mask,
+ intBpp,
+ pixman_gradient_walker_write_t write_pixel)
 {
 pixman_image_t *image = iter->image;
 int x = iter->x;
@@ -61,7 +64,7 @@ conical_get_scanline_narrow (pixman_iter_t *iter, const 
uint32_t *mask)
 
 gradient_t *gradient = (gradient_t *)image;
 conical_gradient_t *conical = (conical_gradient_t *)image;
-uint32_t   *end = buffer + width;
+uint32_t   *end = buffer + width * (Bpp / 4);
 pixman_gradient_walker_t walker;
 pixman_bool_t affine = TRUE;
 double cx = 1.;
@@ -109,11 +112,12 @@ conical_get_scanline_narrow (pixman_iter_t *iter, const 
uint32_t *mask)
{
double t = coordinates_to_parameter (rx, ry, conical->angle);
 
-   *buffer = _pixman_gradient_walker_pixel (
-   , (pixman_fixed_48_16_t)pixman_double_to_fixed (t));
+   write_pixel (,
+(pixman_fixed_48_16_t)pixman_double_to_fixed (t),
+buffer);
}
 
-   ++buffer;
+   buffer += (Bpp / 4);
 
rx += cx;
ry += cy;
@@ -144,11 +148,12 @@ conical_get_scanline_narrow (pixman_iter_t *iter, const 
uint32_t *mask)
 
t = coordinates_to_parameter (x, y, conical->angle);
 
-   *buffer = _pixman_gradient_walker_pixel (
-   , (pixman_fixed_48_16_t)pixman_double_to_fixed (t));
+   write_pixel (,
+(pixman_fixed_48_16_t)pixman_double_to_fixed (t),
+buffer);
}
 
-   ++buffer;
+   buffer += (Bpp / 4);
 
rx += cx;
ry += cy;
@@ -161,14 +166,17 @@ conical_get_scanline_narrow (pixman_iter_t *iter, const 
uint32_t *mask)
 }
 
 static uint32_t *
-conical_get_scanline_wide (pixman_iter_t *iter, const uint32_t *mask)
+conical_get_scanline_narrow (pixman_iter_t *iter, const uint32_t *mask)
 {
-uint32_t *buffer = conical_get_scanline_narrow (iter, NULL);
-
-pixman_expand_to_float (
-   (argb_t *)buffer, buffer, PIXMAN_a8r8g8b8, iter->width);
+return conical_get_scanline (iter, mask, 4,
+_pixman_gradient_walker_write_narrow);
+}
 
-return buffer;
+static uint32_t *
+conical_get_scanline_wide (pixman_iter_t *iter, const uint32_t *mask)
+{
+return conical_get_scanline (iter, NULL, 16,
+_pixman_gradient_walker_write_wide);
 }
 
 void
diff --git a/pixman/pixman-gradient-walker.c b/pixman/pixman-gradient-walker.c
index 822f8e62bae7..9f11cf450e25 100644
--- a/pixman/pixman-gradient-walker.c
+++ b/pixman/pixman-gradient-walker.c
@@ -122,10 +122,10 @@ gradient_walker_reset (pixman_gradient_walker_t *walker,
left_c = right_c;
 }
 
-/* The alpha channel is scaled to be in the [0, 255] interval,
+/* The alpha channel is scaled to be in the [0, 1] 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.
+ * be in the [0, 1] interval.
  */
 la = (left_c->alpha * (1.0f/257.0f));
 lr = (left_c->red * (1.0f/257.0f));
@@ -143,7 +143,7 @@ gradient_walker_reset (pixman_gradient_walker_t *walker,
 if (FLOAT_IS_ZERO (rx - lx) || left_x == INT32_MIN || right_x == INT32_MAX)
 {
walker->a_s = walker->r_s = walker->g_s = walker->b_s = 0.0f;
-   walker->a_b = (la + ra) / 2.0f;
+   walker->a_b = (la + ra) / 510.0f;
walker->r_b = (lr + rr) / 510.0f;
walker->g_b = (lg + rg) / 510.0f;
walker->b_b = (lb + rb) / 510.0f;
@@ -152,12 

[Pixman] [PATCH 2/2] pixman: Use maximum precision for pixman-bits-image

2019-01-03 Thread Maarten Lankhorst
Signed-off-by: Maarten Lankhorst 
---
 pixman/pixman-bits-image.c | 478 ++---
 pixman/pixman-inlines.h|  25 ++
 2 files changed, 418 insertions(+), 85 deletions(-)

diff --git a/pixman/pixman-bits-image.c b/pixman/pixman-bits-image.c
index 9fb91ff5831d..cb1c5ce12d46 100644
--- a/pixman/pixman-bits-image.c
+++ b/pixman/pixman-bits-image.c
@@ -36,43 +36,45 @@
 #include "pixman-combine32.h"
 #include "pixman-inlines.h"
 
-static uint32_t *
-_pixman_image_get_scanline_generic_float (pixman_iter_t * iter,
- const uint32_t *mask)
-{
-pixman_iter_get_scanline_t fetch_32 = iter->data;
-uint32_t *buffer = iter->buffer;
-
-fetch_32 (iter, NULL);
+/* Fetch functions */
 
-pixman_expand_to_float ((argb_t *)buffer, buffer, PIXMAN_a8r8g8b8, 
iter->width);
+static force_inline void
+fetch_pixel_no_alpha_32 (bits_image_t *image,
+int x, int y, pixman_bool_t check_bounds,
+void *out)
+{
+uint32_t *ret = out;
 
-return iter->buffer;
+if (check_bounds &&
+   (x < 0 || x >= image->width || y < 0 || y >= image->height))
+   *ret = 0;
+else
+   *ret = image->fetch_pixel_32 (image, x, y);
 }
 
-/* Fetch functions */
-
-static force_inline uint32_t
-fetch_pixel_no_alpha (bits_image_t *image,
- int x, int y, pixman_bool_t check_bounds)
+static force_inline void
+fetch_pixel_no_alpha_float (bits_image_t *image,
+   int x, int y, pixman_bool_t check_bounds,
+   void *out)
 {
+argb_t *ret = out;
+
 if (check_bounds &&
(x < 0 || x >= image->width || y < 0 || y >= image->height))
-{
-   return 0;
-}
-
-return image->fetch_pixel_32 (image, x, y);
+   ret->a = ret->r = ret->g = ret->b = 0.f;
+else
+   *ret = image->fetch_pixel_float (image, x, y);
 }
 
-typedef uint32_t (* get_pixel_t) (bits_image_t *image,
- int x, int y, pixman_bool_t check_bounds);
+typedef void (* get_pixel_t) (bits_image_t *image,
+ int x, int y, pixman_bool_t check_bounds, void 
*out);
 
-static force_inline uint32_t
+static force_inline void
 bits_image_fetch_pixel_nearest (bits_image_t   *image,
pixman_fixed_t  x,
pixman_fixed_t  y,
-   get_pixel_t get_pixel)
+   get_pixel_t get_pixel,
+   void   *out)
 {
 int x0 = pixman_fixed_to_int (x - pixman_fixed_e);
 int y0 = pixman_fixed_to_int (y - pixman_fixed_e);
@@ -82,19 +84,20 @@ bits_image_fetch_pixel_nearest (bits_image_t   *image,
repeat (image->common.repeat, , image->width);
repeat (image->common.repeat, , image->height);
 
-   return get_pixel (image, x0, y0, FALSE);
+   get_pixel (image, x0, y0, FALSE, out);
 }
 else
 {
-   return get_pixel (image, x0, y0, TRUE);
+   get_pixel (image, x0, y0, TRUE, out);
 }
 }
 
-static force_inline uint32_t
-bits_image_fetch_pixel_bilinear (bits_image_t   *image,
-pixman_fixed_t  x,
-pixman_fixed_t  y,
-get_pixel_t get_pixel)
+static force_inline void
+bits_image_fetch_pixel_bilinear_32 (bits_image_t   *image,
+   pixman_fixed_t  x,
+   pixman_fixed_t  y,
+   get_pixel_t get_pixel,
+   void   *out)
 {
 pixman_repeat_t repeat_mode = image->common.repeat;
 int width = image->width;
@@ -102,6 +105,7 @@ bits_image_fetch_pixel_bilinear (bits_image_t   *image,
 int x1, y1, x2, y2;
 uint32_t tl, tr, bl, br;
 int32_t distx, disty;
+uint32_t *ret = out;
 
 x1 = x - pixman_fixed_1 / 2;
 y1 = y - pixman_fixed_1 / 2;
@@ -121,27 +125,77 @@ bits_image_fetch_pixel_bilinear (bits_image_t   *image,
repeat (repeat_mode, , width);
repeat (repeat_mode, , height);
 
-   tl = get_pixel (image, x1, y1, FALSE);
-   bl = get_pixel (image, x1, y2, FALSE);
-   tr = get_pixel (image, x2, y1, FALSE);
-   br = get_pixel (image, x2, y2, FALSE);
+   get_pixel (image, x1, y1, FALSE, );
+   get_pixel (image, x2, y1, FALSE, );
+   get_pixel (image, x1, y2, FALSE, );
+   get_pixel (image, x2, y2, FALSE, );
 }
 else
 {
-   tl = get_pixel (image, x1, y1, TRUE);
-   tr = get_pixel (image, x2, y1, TRUE);
-   bl = get_pixel (image, x1, y2, TRUE);
-   br = get_pixel (image, x2, y2, TRUE);
+   get_pixel (image, x1, y1, TRUE, );
+   get_pixel (image, x2, y1, TRUE, );
+   get_pixel (image, x1, y2, TRUE, );
+   get_pixel (image, x2, y2, TRUE, );
 }
 
-return bilinear_interpolation (tl, tr, bl, br, distx,