pixman: Branch 'master' - 3 commits

Søren Sandmann Pedersen sandmann at kemper.freedesktop.org
Mon Jul 30 12:46:30 PDT 2012


 .gitignore              |    2 
 demos/Makefile.am       |    4 +
 demos/srgb-test.c       |   96 ++++++++++++++++++++++++++++++++++
 pixman/Makefile.sources |    5 +
 pixman/make-srgb.pl     |  112 ++++++++++++++++++++++++++++++++++++++++
 pixman/pixman-access.c  |  134 +++++++++++++++++++++++++++++++++++++++++++++++-
 pixman/pixman-image.c   |    3 -
 pixman/pixman-private.h |   15 +++++
 pixman/pixman.c         |    1 
 pixman/pixman.h         |    4 +
 test/composite.c        |   67 ++++++++++++++++++++++--
 test/stress-test.c      |    1 
 test/utils.c            |   36 ++++++++++++
 test/utils.h            |    6 ++
 14 files changed, 476 insertions(+), 10 deletions(-)

New commits:
commit 72ba0b955504ecdc69f4cbf96a677b82be18b0cb
Author: Antti S. Lankila <alankila at bel.fi>
Date:   Sun Jul 29 22:14:34 2012 +0300

    Add tests to validate new sRGB behavior
    
    Composite checks random combinations of operations that now also have
    sRGB sources, masks and destinations, and stress-test validates the
    read/write primitives.

diff --git a/test/composite.c b/test/composite.c
index 81c416e..2930fb7 100644
--- a/test/composite.c
+++ b/test/composite.c
@@ -99,6 +99,9 @@ static const format_t formats[] =
     P(x2b10g10r10),
     P(a2r10g10b10),
     P(a2b10g10r10),
+    
+    /* sRGB formats */
+    P(a8r8g8b8_sRGB),
 
     /* 24 bpp formats */
     P(r8g8b8),
@@ -544,17 +547,56 @@ composite_test (image_t *dst,
     }
 
     tdst = *dst->color;
-    round_color (dst->format->format, &tdst);
-
     tsrc = *src->color;
-    if (src->size)
-	round_color (src->format->format, &tsrc);
 
     if (mask)
     {
 	tmsk = *mask->color;
-	if (mask->size)
+    }
+
+    /* It turns out that by construction all source, mask etc. colors are
+     * linear because they are made from fills, and fills are always in linear
+     * color space.  However, if they have been converted to bitmaps, we need
+     * to simulate the sRGB approximation to pass the test cases.
+     */
+    if (src->size)
+    {
+	if (PIXMAN_FORMAT_TYPE (src->format->format) == PIXMAN_TYPE_ARGB_SRGB)
+        {
+	    tsrc.r = convert_linear_to_srgb (tsrc.r);
+	    tsrc.g = convert_linear_to_srgb (tsrc.g);
+	    tsrc.b = convert_linear_to_srgb (tsrc.b);
+	    round_color (src->format->format, &tsrc);
+	    tsrc.r = convert_srgb_to_linear (tsrc.r);
+	    tsrc.g = convert_srgb_to_linear (tsrc.g);
+	    tsrc.b = convert_srgb_to_linear (tsrc.b);
+	}
+        else
+        {
+	    round_color (src->format->format, &tsrc);
+	}
+    }
+
+    if (mask && mask->size)
+    {
+	if (PIXMAN_FORMAT_TYPE (mask->format->format) == PIXMAN_TYPE_ARGB_SRGB)
+	{
+	    tmsk.r = convert_linear_to_srgb (tmsk.r);
+	    tmsk.g = convert_linear_to_srgb (tmsk.g);
+	    tmsk.b = convert_linear_to_srgb (tmsk.b);
 	    round_color (mask->format->format, &tmsk);
+	    tmsk.r = convert_srgb_to_linear (tmsk.r);
+	    tmsk.g = convert_srgb_to_linear (tmsk.g);
+	    tmsk.b = convert_srgb_to_linear (tmsk.b);
+	}
+	else
+	{
+	    round_color (mask->format->format, &tmsk);
+	}
+    }
+
+    if (mask)
+    {
 	if (component_alpha && PIXMAN_FORMAT_R (mask->format->format) == 0)
 	{
 	    /* Ax component-alpha masks expand alpha into
@@ -564,6 +606,21 @@ composite_test (image_t *dst,
 	}
     }
 
+    if (PIXMAN_FORMAT_TYPE (dst->format->format) == PIXMAN_TYPE_ARGB_SRGB)
+    {
+	tdst.r = convert_linear_to_srgb (tdst.r);
+	tdst.g = convert_linear_to_srgb (tdst.g);
+	tdst.b = convert_linear_to_srgb (tdst.b);
+    	round_color (dst->format->format, &tdst);
+	tdst.r = convert_srgb_to_linear (tdst.r);
+	tdst.g = convert_srgb_to_linear (tdst.g);
+	tdst.b = convert_srgb_to_linear (tdst.b);
+    }
+    else
+    {
+    	round_color (dst->format->format, &tdst);
+    }
+
     do_composite (op->op,
 		  &tsrc,
 		  mask? &tmsk : NULL,
diff --git a/test/stress-test.c b/test/stress-test.c
index 9280802..54ab1c5 100644
--- a/test/stress-test.c
+++ b/test/stress-test.c
@@ -25,6 +25,7 @@ static const pixman_format_code_t image_formats[] =
     PIXMAN_x14r6g6b6,
     PIXMAN_r8g8b8,
     PIXMAN_b8g8r8,
+    PIXMAN_a8r8g8b8_sRGB,
     PIXMAN_r5g6b5,
     PIXMAN_b5g6r5,
     PIXMAN_x2r10g10b10,
diff --git a/test/utils.c b/test/utils.c
index 563b33d..85b58d0 100644
--- a/test/utils.c
+++ b/test/utils.c
@@ -1,6 +1,7 @@
 #define _GNU_SOURCE
 
 #include "utils.h"
+#include <math.h>
 #include <signal.h>
 #include <stdlib.h>
 
@@ -765,6 +766,24 @@ aligned_malloc (size_t align, size_t size)
        (((c) >>  8) & 0xff) * 301 +					\
        (((c)      ) & 0xff) * 58) >> 2))
 
+double
+convert_srgb_to_linear (double c)
+{
+    if (c <= 0.04045)
+        return c / 12.92;
+    else
+        return powf ((c + 0.055) / 1.055, 2.4);
+}
+
+double
+convert_linear_to_srgb (double c)
+{
+    if (c <= 0.0031308)
+        return c * 12.92;
+    else
+        return 1.055 * powf (c, 1.0/2.4) - 0.055;
+}
+
 void
 initialize_palette (pixman_indexed_t *palette, uint32_t depth, int is_rgb)
 {
@@ -868,6 +887,7 @@ pixel_checker_init (pixel_checker_t *checker, pixman_format_code_t format)
 	break;
 
     case PIXMAN_TYPE_ARGB:
+    case PIXMAN_TYPE_ARGB_SRGB:
 	checker->bs = 0;
 	checker->gs = checker->bs + PIXMAN_FORMAT_B (format);
 	checker->rs = checker->gs + PIXMAN_FORMAT_G (format);
@@ -968,11 +988,25 @@ pixel_checker_get_min (const pixel_checker_t *checker, color_t *color,
 
 pixman_bool_t
 pixel_checker_check (const pixel_checker_t *checker, uint32_t pixel,
-		     color_t *color)
+		     color_t *color_in)
 {
     int32_t a_lo, a_hi, r_lo, r_hi, g_lo, g_hi, b_lo, b_hi;
     int32_t ai, ri, gi, bi;
     pixman_bool_t result;
+    color_t tmp, *color;
+
+    if (PIXMAN_FORMAT_TYPE (checker->format) == PIXMAN_TYPE_ARGB_SRGB)
+    {
+	tmp.a = color_in->a;
+	tmp.r = convert_linear_to_srgb (color_in->r);
+	tmp.g = convert_linear_to_srgb (color_in->g);
+	tmp.b = convert_linear_to_srgb (color_in->b);
+	color = &tmp;
+    }
+    else
+    {
+	color = color_in;
+    }
 
     pixel_checker_get_min (checker, color, &a_lo, &r_lo, &g_lo, &b_lo);
     pixel_checker_get_max (checker, color, &a_hi, &r_hi, &g_hi, &b_hi);
diff --git a/test/utils.h b/test/utils.h
index ac2decd..faf427f 100644
--- a/test/utils.h
+++ b/test/utils.h
@@ -163,6 +163,12 @@ write_png (pixman_image_t *image, const char *filename);
 void *
 aligned_malloc (size_t align, size_t size);
 
+double
+convert_srgb_to_linear (double component);
+
+double
+convert_linear_to_srgb (double component);
+
 void
 initialize_palette (pixman_indexed_t *palette, uint32_t depth, int is_rgb);
 
commit a161a6ba2394aed68148304de83b8f2c185f4c32
Author: Antti S. Lankila <alankila at bel.fi>
Date:   Sun Jul 29 21:56:18 2012 +0300

    Add sRGB blending demo program
    
    Simple sRGB color blender test can be used to determine if the sRGB processing
    works as expected. It blends alpha ramps of purple and green together such that
    at midpoint of image, 50 % blend of both is realized. At that point, sRGB-aware
    processing yields a result close to #bbb rather than #888, which is the linear
    light blending result.
    
    The demo also contains the sample computation for sRGB premultiplied alpha.

diff --git a/.gitignore b/.gitignore
index 3cdf3c1..a4d9f99 100644
--- a/.gitignore
+++ b/.gitignore
@@ -36,6 +36,7 @@ demos/gradient-test
 demos/quad2quad
 demos/radial-test
 demos/screen-test
+demos/srgb-test
 demos/trap-test
 demos/tri-test
 pixman/pixman-combine32.c
diff --git a/demos/Makefile.am b/demos/Makefile.am
index 9aac1f5..d8fb0da 100644
--- a/demos/Makefile.am
+++ b/demos/Makefile.am
@@ -20,7 +20,8 @@ DEMOS =				\
 	trap-test		\
 	tri-test		\
 	quad2quad		\
-	checkerboard
+	checkerboard		\
+	srgb-test
 
 EXTRA_DIST = parrot.c parrot.jpg
 
@@ -35,6 +36,7 @@ convolution_test_SOURCES = convolution-test.c $(GTK_UTILS)
 radial_test_SOURCES = radial-test.c $(GTK_UTILS)
 tri_test_SOURCES = tri-test.c $(GTK_UTILS)
 checkerboard_SOURCES = checkerboard.c $(GTK_UTILS)
+srgb_test_SOURCES = srgb-test.c $(GTK_UTILS)
 
 noinst_PROGRAMS = $(DEMOS)
 
diff --git a/demos/srgb-test.c b/demos/srgb-test.c
new file mode 100644
index 0000000..bc07349
--- /dev/null
+++ b/demos/srgb-test.c
@@ -0,0 +1,96 @@
+#include <math.h>
+
+#include "pixman.h"
+#include "gtk-utils.h"
+
+static uint32_t
+linear_argb_to_premult_argb (float a,
+			     float r,
+			     float g,
+			     float b)
+{
+    r *= a;
+    g *= a;
+    b *= a;
+    return (uint32_t) (a * 255.0f + 0.5f) << 24
+	 | (uint32_t) (r * 255.0f + 0.5f) << 16
+	 | (uint32_t) (g * 255.0f + 0.5f) <<  8
+	 | (uint32_t) (b * 255.0f + 0.5f) <<  0;
+}
+
+static float
+lin2srgb (float linear)
+{
+    if (linear < 0.0031308f)
+	return linear * 12.92f;
+    else
+	return 1.055f * powf (linear, 1.0f/2.4f) - 0.055f;
+}
+
+static uint32_t
+linear_argb_to_premult_srgb_argb (float a,
+				  float r,
+				  float g,
+				  float b)
+{
+    r = lin2srgb (r * a);
+    g = lin2srgb (g * a);
+    b = lin2srgb (b * a);
+    return (uint32_t) (a * 255.0f + 0.5f) << 24
+	 | (uint32_t) (r * 255.0f + 0.5f) << 16
+	 | (uint32_t) (g * 255.0f + 0.5f) <<  8
+	 | (uint32_t) (b * 255.0f + 0.5f) <<  0;
+}
+
+int
+main (int argc, char **argv)
+{
+#define WIDTH 400
+#define HEIGHT 200
+    int y, x, p;
+    float alpha;
+ 
+    uint32_t *dest = malloc (WIDTH * HEIGHT * 4);
+    uint32_t *src1 = malloc (WIDTH * HEIGHT * 4);
+    pixman_image_t *dest_img, *src1_img;
+   
+    dest_img = pixman_image_create_bits (PIXMAN_a8r8g8b8_sRGB,
+					 WIDTH, HEIGHT,
+					 dest,
+					 WIDTH * 4);
+    src1_img = pixman_image_create_bits (PIXMAN_a8r8g8b8,
+					 WIDTH, HEIGHT,
+					 src1,
+					 WIDTH * 4);
+
+    for (y = 0; y < HEIGHT; y ++)
+    {
+	p = WIDTH * y;
+	for (x = 0; x < WIDTH; x ++)
+	{
+	     alpha = (float) x / WIDTH;
+	     src1[p + x] = linear_argb_to_premult_argb (alpha, 1, 0, 1);
+	     dest[p + x] = linear_argb_to_premult_srgb_argb (1-alpha, 0, 1, 0);
+	}
+    }
+    
+    pixman_image_composite (PIXMAN_OP_ADD, src1_img, NULL, dest_img,
+			    0, 0, 0, 0, 0, 0, WIDTH, HEIGHT);
+    pixman_image_unref (src1_img);
+    free (src1);
+
+    pixman_image_unref (dest_img);
+
+    /* Now that the picture has been correctly constructed,
+     * we hand it over to our support library as argb which it
+     * knows how to handle (it doesn't understand _sRGB format). */
+    dest_img = pixman_image_create_bits (PIXMAN_a8r8g8b8,
+			 		 WIDTH, HEIGHT,
+					 dest,
+					 WIDTH * 4);
+    show_image (dest_img);
+    pixman_image_unref (dest_img);
+    free (dest);
+    
+    return 0;
+}
commit 7460457f80b1482338318f0ddcdf5311659fae7b
Author: Antti S. Lankila <alankila at bel.fi>
Date:   Sun Jul 29 21:46:58 2012 +0300

    Add support for sRGB surfaces
    
    sRGB format is defined as a new format type, PIXMAN_TYPE_ARGB_SRGB. One form of
    this type is provided, PIXMAN_a8r8g8b8_sRGB. Use of an sRGB format triggers
    wide processing, and the pixel fetch/store functions handle the relevant
    conversion between color spaces. Pixman itself is thought to compose in the
    linearized sRGB color space.
    
    sRGB conversion is tabularized. For sRGB to linear, we are using only 256
    values because the current source format uses 8 bits per component precision.
    For linear to sRGB, it turns out that only 4096 brightness levels are required
    to generate all of the 256 sRGB color values, and therefore only 12 bits per
    component are considered during store. As a special case, a no-op
    sRGB->linear->sRGB conversion is constructed to be lossless by adjusting the
    sRGB->linear conversion table where necessary.

diff --git a/.gitignore b/.gitignore
index b9853b1..3cdf3c1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -42,6 +42,7 @@ pixman/pixman-combine32.c
 pixman/pixman-combine32.h
 pixman/pixman-combine64.c
 pixman/pixman-combine64.h
+pixman/pixman-srgb.c
 pixman/pixman-version.h
 test/a1-trap-test
 test/affine-test
diff --git a/pixman/Makefile.sources b/pixman/Makefile.sources
index 6472994..cf7040f 100644
--- a/pixman/Makefile.sources
+++ b/pixman/Makefile.sources
@@ -25,6 +25,7 @@ libpixman_sources =			\
 	pixman-region16.c		\
 	pixman-region32.c		\
 	pixman-solid-fill.c		\
+	pixman-srgb.c			\
 	pixman-timer.c			\
 	pixman-trap.c			\
 	pixman-utils.c			\
@@ -46,8 +47,12 @@ BUILT_SOURCES =				\
 	pixman-combine32.h		\
 	pixman-combine64.c		\
 	pixman-combine64.h		\
+	pixman-srgb.c			\
 	$(NULL)
 
+pixman-srgb.c: make-srgb.pl
+	$(PERL) $< > $@ || ($(RM) $@; exit 1)
+
 pixman-combine32.c: pixman-combine.c.template make-combine.pl
 	$(PERL) $(lastword $+) 8 < $< > $@ || ($(RM) $@; exit 1)
 pixman-combine32.h: pixman-combine.h.template make-combine.pl
diff --git a/pixman/make-srgb.pl b/pixman/make-srgb.pl
new file mode 100644
index 0000000..ebde2ea
--- /dev/null
+++ b/pixman/make-srgb.pl
@@ -0,0 +1,112 @@
+#!/usr/bin/perl -w
+
+use strict;
+
+sub linear_to_srgb
+{
+    my ($c) = @_;
+
+    if ($c < 0.0031308)
+    {
+	return $c * 12.92;
+    }
+    else
+    {
+	return 1.055 * $c ** (1.0/2.4) - 0.055;
+    }
+}
+
+sub srgb_to_linear
+{
+    my ($c) = @_;
+
+    if ($c < 0.04045)
+    {
+	return $c / 12.92;
+    }
+    else
+    {
+	return (($c + 0.055) / 1.055) ** 2.4
+    }
+}
+
+my @linear_to_srgb;
+for my $linear (0 .. 4095)
+{
+    my $srgb = int(linear_to_srgb($linear / 4095.0) * 255.0 + 0.5);
+    push @linear_to_srgb, $srgb;
+}
+
+my @srgb_to_linear;
+for my $srgb (0 .. 255)
+{
+    my $linear = int(srgb_to_linear($srgb / 255.0) * 65535.0 + 0.5);
+    push @srgb_to_linear, $linear;
+}
+
+# Ensure that we have a lossless sRGB and back conversion loop.
+# some of the darkest shades need a little bias -- maximum is just
+# 5 increments out of 16. This gives us useful property with
+# least amount of error in the sRGB-to-linear table, and keeps the actual
+# table lookup in the other direction as simple as possible.
+for my $srgb (0 .. $#srgb_to_linear)
+{
+    my $add = 0;
+    while (1)
+    {
+	my $linear = $srgb_to_linear[$srgb];
+	my $srgb_lossy = $linear_to_srgb[$linear >> 4];
+	last if $srgb == $srgb_lossy;
+
+	# Add slight bias to this component until it rounds correctly
+	$srgb_to_linear[$srgb] ++;
+	$add ++;
+    }
+    die "Too many adds at $srgb" if $add > 5;
+}
+
+print <<"PROLOG";
+/* WARNING: This file is generated by $0.
+ * Please edit that file instead of this one.
+ */
+
+#include <stdint.h>
+
+#include "config.h"
+#include "pixman-private.h"
+
+PROLOG
+
+print "const uint8_t linear_to_srgb[" . @linear_to_srgb . "] =\n";
+print "{\n";
+for my $linear (0 .. $#linear_to_srgb)
+{
+    if (($linear % 10) == 0)
+    {
+	print "\t";
+    }
+    print sprintf("%d, ", $linear_to_srgb[$linear]);
+    if (($linear % 10) == 9)
+    {
+	print "\n";
+    }
+}
+print "\n};\n";
+print "\n";
+
+print "const uint16_t srgb_to_linear[" . @srgb_to_linear . "] =\n";
+print "{\n";
+for my $srgb (0 .. $#srgb_to_linear)
+{
+    if (($srgb % 10) == 0)
+    {
+	print "\t";
+    }
+    print sprintf("%d, ", $srgb_to_linear[$srgb]);
+    if (($srgb % 10) == 9)
+    {
+	print "\n";
+    }
+}
+print "\n};\n";
+
diff --git a/pixman/pixman-access.c b/pixman/pixman-access.c
index 6743887..9feafc4 100644
--- a/pixman/pixman-access.c
+++ b/pixman/pixman-access.c
@@ -32,8 +32,8 @@
 #include <string.h>
 #include <assert.h>
 
-#include "pixman-private.h"
 #include "pixman-accessor.h"
+#include "pixman-private.h"
 
 #define CONVERT_RGB24_TO_Y15(s)						\
     (((((s) >> 16) & 0xff) * 153 +					\
@@ -210,6 +210,7 @@ get_shifts (pixman_format_code_t  format,
 	break;
 
     case PIXMAN_TYPE_ARGB:
+    case PIXMAN_TYPE_ARGB_SRGB:
 	*b = 0;
 	*g = *b + PIXMAN_FORMAT_B (format);
 	*r = *g + PIXMAN_FORMAT_G (format);
@@ -1027,6 +1028,130 @@ fetch_pixel_generic_64 (bits_image_t *image,
     return result;
 }
 
+/* The 32_sRGB paths should be deleted after narrow processing
+ * is no longer invoked for formats that are considered wide.
+ * (Also see fetch_pixel_generic_lossy_32) */
+static void
+fetch_scanline_a8r8g8b8_32_sRGB (pixman_image_t *image,
+                                 int             x,
+                                 int             y,
+                                 int             width,
+                                 uint32_t       *buffer,
+                                 const uint32_t *mask)
+{
+    const uint32_t *bits = image->bits.bits + y * image->bits.rowstride;
+    const uint32_t *pixel = (uint32_t *)bits + x;
+    const uint32_t *end = pixel + width;
+    uint32_t tmp;
+    
+    while (pixel < end)
+    {
+	tmp = READ (image, pixel++);
+	*buffer++ =                 (tmp >> 24)               << 24
+		  | (srgb_to_linear[(tmp >> 16) & 0xff] >> 8) << 16
+		  | (srgb_to_linear[(tmp >>  8) & 0xff] >> 8) <<  8
+		  | (srgb_to_linear[(tmp >>  0) & 0xff] >> 8) <<  0;
+    }
+}
+
+static void
+fetch_scanline_a8r8g8b8_64_sRGB (pixman_image_t *image,
+                                 int             x,
+                                 int             y,
+                                 int             width,
+                                 uint32_t       *b,
+                                 const uint32_t *mask)
+{
+    const uint32_t *bits = image->bits.bits + y * image->bits.rowstride;
+    const uint32_t *pixel = (uint32_t *)bits + x;
+    const uint32_t *end = pixel + width;
+    uint64_t *buffer = (uint64_t *)b;
+    uint32_t tmp;
+    
+    while (pixel < end)
+    {
+	tmp = READ (image, pixel++);
+	*buffer++ = (uint64_t)               ((tmp >> 24) * 257)  << 48
+		  | (uint64_t) srgb_to_linear[(tmp >> 16) & 0xff] << 32
+		  | (uint64_t) srgb_to_linear[(tmp >>  8) & 0xff] << 16
+		  | (uint64_t) srgb_to_linear[(tmp >>  0) & 0xff] <<  0;
+    }
+}
+
+static uint32_t
+fetch_pixel_a8r8g8b8_32_sRGB (bits_image_t *image,
+			      int           offset,
+			      int           line)
+{
+    uint32_t *bits = image->bits + line * image->rowstride;
+    uint32_t tmp = READ (image, bits + offset);
+    return                 (tmp >> 24)               << 24
+	 | (srgb_to_linear[(tmp >> 16) & 0xff] >> 8) << 16
+	 | (srgb_to_linear[(tmp >>  8) & 0xff] >> 8) <<  8
+	 | (srgb_to_linear[(tmp >>  0) & 0xff] >> 8) <<  0;
+}
+
+static uint64_t
+fetch_pixel_a8r8g8b8_64_sRGB (bits_image_t *image,
+			      int           offset,
+			      int	    line)
+{
+    uint32_t *bits = image->bits + line * image->rowstride;
+    uint32_t tmp = READ (image, bits + offset);
+    return (uint64_t)               ((tmp >> 24) * 257)  << 48
+	 | (uint64_t) srgb_to_linear[(tmp >> 16) & 0xff] << 32
+	 | (uint64_t) srgb_to_linear[(tmp >>  8) & 0xff] << 16
+	 | (uint64_t) srgb_to_linear[(tmp >>  0) & 0xff] <<  0;
+}
+
+static void
+store_scanline_a8r8g8b8_32_sRGB (bits_image_t   *image,
+                                 int             x,
+                                 int             y,
+                                 int             width,
+                                 const uint32_t *v)
+{
+    uint32_t *bits = image->bits + image->rowstride * y;
+    uint64_t *values = (uint64_t *)v;
+    uint32_t *pixel = bits + x;
+    uint64_t tmp;
+    int i;
+    
+    for (i = 0; i < width; ++i)
+    {
+	tmp = values[i];
+	WRITE (image, pixel++,
+		  ((uint32_t)     (tmp >> 24     )          << 24)
+		| (linear_to_srgb[(tmp >> 16 << 4) & 0xfff] << 16)
+		| (linear_to_srgb[(tmp >>  8 << 4) & 0xfff] <<  8)
+		| (linear_to_srgb[(tmp >>  0 << 4) & 0xfff] <<  0));
+    }
+}
+
+static void
+store_scanline_a8r8g8b8_64_sRGB (bits_image_t  *image,
+                                int             x,
+                                int             y,
+                                int             width,
+                                const uint32_t *v)
+{
+    uint32_t *bits = image->bits + image->rowstride * y;
+    uint64_t *values = (uint64_t *)v;
+    uint32_t *pixel = bits + x;
+    uint64_t tmp;
+    int i;
+    
+    for (i = 0; i < width; ++i)
+    {
+	tmp = values[i];
+	WRITE (image, pixel++,
+		  ((uint32_t)     (tmp >> 56)          << 24)
+		| (linear_to_srgb[(tmp >> 36) & 0xfff] << 16)
+		| (linear_to_srgb[(tmp >> 20) & 0xfff] <<  8)
+		| (linear_to_srgb[(tmp >>  4) & 0xfff] <<  0));
+    }
+}
+
 /*
  * XXX: The transformed fetch path only works at 32-bpp so far.  When all
  * paths have wide versions, this can be removed.
@@ -1079,6 +1204,13 @@ static const format_info_t accessors[] =
     FORMAT_INFO (r8g8b8x8),
     FORMAT_INFO (x14r6g6b6),
 
+/* sRGB formats */
+  { PIXMAN_a8r8g8b8_sRGB,
+    fetch_scanline_a8r8g8b8_32_sRGB,
+    fetch_scanline_a8r8g8b8_64_sRGB,
+    fetch_pixel_a8r8g8b8_32_sRGB, fetch_pixel_a8r8g8b8_64_sRGB,
+    store_scanline_a8r8g8b8_32_sRGB, store_scanline_a8r8g8b8_64_sRGB },
+
 /* 24bpp formats */
     FORMAT_INFO (r8g8b8),
     FORMAT_INFO (b8g8r8),
diff --git a/pixman/pixman-image.c b/pixman/pixman-image.c
index 8b634a7..15597bd 100644
--- a/pixman/pixman-image.c
+++ b/pixman/pixman-image.c
@@ -909,7 +909,8 @@ _pixman_image_get_solid (pixman_implementation_t *imp,
     }
 
     /* If necessary, convert RGB <--> BGR. */
-    if (PIXMAN_FORMAT_TYPE (format) != PIXMAN_TYPE_ARGB)
+    if (PIXMAN_FORMAT_TYPE (format) != PIXMAN_TYPE_ARGB
+	&& PIXMAN_FORMAT_TYPE (format) != PIXMAN_TYPE_ARGB_SRGB)
     {
 	result = (((result & 0xff000000) >>  0) |
 	          ((result & 0x00ff0000) >> 16) |
diff --git a/pixman/pixman-private.h b/pixman/pixman-private.h
index 4d8f64d..d5e6a72 100644
--- a/pixman/pixman-private.h
+++ b/pixman/pixman-private.h
@@ -887,7 +887,8 @@ pixman_list_move_to_front (pixman_list_t *list, pixman_link_t *link)
     (PIXMAN_FORMAT_A (f) > 8 ||						\
      PIXMAN_FORMAT_R (f) > 8 ||						\
      PIXMAN_FORMAT_G (f) > 8 ||						\
-     PIXMAN_FORMAT_B (f) > 8)
+     PIXMAN_FORMAT_B (f) > 8 ||						\
+     PIXMAN_FORMAT_TYPE (f) == PIXMAN_TYPE_ARGB_SRGB)
 
 #ifdef WORDS_BIGENDIAN
 #   define SCREEN_SHIFT_LEFT(x,n)	((x) << (n))
@@ -1083,6 +1084,18 @@ void pixman_timer_register (pixman_timer_t *timer);
 
 #endif /* PIXMAN_TIMERS */
 
+/* sRGB<->linear conversion tables. Linear color space is the same
+ * as sRGB but the components are in linear light (gamma 1.0).
+ *
+ * linear_to_srgb maps linear value from 0 to 4095 ([0.0, 1.0])
+ * and returns 8-bit sRGB value.
+ *
+ * srgb_to_linear maps 8-bit sRGB value to 16-bit linear value
+ * with range 0 to 65535 ([0.0, 1.0]).
+ */
+extern const uint8_t linear_to_srgb[4096];
+extern const uint16_t srgb_to_linear[256];
+
 #endif /* __ASSEMBLER__ */
 
 #endif /* PIXMAN_PRIVATE_H */
diff --git a/pixman/pixman.c b/pixman/pixman.c
index 0137c3c..994ef38 100644
--- a/pixman/pixman.c
+++ b/pixman/pixman.c
@@ -1017,6 +1017,7 @@ pixman_format_supported_source (pixman_format_code_t format)
     case PIXMAN_a2r10g10b10:
     case PIXMAN_x2r10g10b10:
     case PIXMAN_a8r8g8b8:
+    case PIXMAN_a8r8g8b8_sRGB:
     case PIXMAN_x8r8g8b8:
     case PIXMAN_a8b8g8r8:
     case PIXMAN_x8b8g8r8:
diff --git a/pixman/pixman.h b/pixman/pixman.h
index 7233ceb..e1cb90a 100644
--- a/pixman/pixman.h
+++ b/pixman/pixman.h
@@ -653,6 +653,7 @@ struct pixman_indexed
 #define PIXMAN_TYPE_YV12	7
 #define PIXMAN_TYPE_BGRA	8
 #define PIXMAN_TYPE_RGBA	9
+#define PIXMAN_TYPE_ARGB_SRGB	10
 
 #define PIXMAN_FORMAT_COLOR(f)				\
 	(PIXMAN_FORMAT_TYPE(f) == PIXMAN_TYPE_ARGB ||	\
@@ -676,6 +677,9 @@ typedef enum {
     PIXMAN_x2b10g10r10 = PIXMAN_FORMAT(32,PIXMAN_TYPE_ABGR,0,10,10,10),
     PIXMAN_a2b10g10r10 = PIXMAN_FORMAT(32,PIXMAN_TYPE_ABGR,2,10,10,10),
 
+/* sRGB formats */
+    PIXMAN_a8r8g8b8_sRGB = PIXMAN_FORMAT(32,PIXMAN_TYPE_ARGB_SRGB,8,8,8,8),
+
 /* 24bpp formats */
     PIXMAN_r8g8b8 =	 PIXMAN_FORMAT(24,PIXMAN_TYPE_ARGB,0,8,8,8),
     PIXMAN_b8g8r8 =	 PIXMAN_FORMAT(24,PIXMAN_TYPE_ABGR,0,8,8,8),


More information about the xorg-commit mailing list