From: Brian Paul Date: Thu, 27 Aug 2009 15:10:34 +0000 (-0600) Subject: gallium/util: added support for SRGB formats X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=32f95f8c173155ca30e77c345a68b0d3336ddbed;p=mesa.git gallium/util: added support for SRGB formats Fixes glean/texture_srgb failure, bug #23449. --- diff --git a/src/gallium/auxiliary/util/u_tile.c b/src/gallium/auxiliary/util/u_tile.c index 422bc76003a..aa16fe771fe 100644 --- a/src/gallium/auxiliary/util/u_tile.c +++ b/src/gallium/auxiliary/util/u_tile.c @@ -596,6 +596,184 @@ r16g16b16a16_put_tile_rgba(short *dst, } +/*** PIPE_FORMAT_R8G8B8A8_SRGB ***/ + +/** + * Convert an 8-bit sRGB value from non-linear space to a + * linear RGB value in [0, 1]. + * Implemented with a 256-entry lookup table. + */ +static INLINE float +srgb_to_linear(ubyte cs8) +{ + static float table[256]; + static boolean tableReady = FALSE; + if (!tableReady) { + /* compute lookup table now */ + uint i; + for (i = 0; i < 256; i++) { + const float cs = ubyte_to_float(i); + if (cs <= 0.04045) { + table[i] = cs / 12.92f; + } + else { + table[i] = (float) powf((cs + 0.055) / 1.055, 2.4); + } + } + tableReady = TRUE; + } + return table[cs8]; +} + + +/** + * Convert linear float in [0,1] to an srgb ubyte value in [0,255]. + * XXX this hasn't been tested (render to srgb surface). + * XXX this needs optimization. + */ +static INLINE ubyte +linear_to_srgb(float cl) +{ + if (cl >= 1.0F) + return 255; + else if (cl >= 0.0031308F) + return float_to_ubyte(1.055F * powf(cl, 0.41666F) - 0.055F); + else if (cl > 0.0F) + return float_to_ubyte(12.92F * cl); + else + return 0.0; +} + + +static void +a8r8g8b8_srgb_get_tile_rgba(const unsigned *src, + unsigned w, unsigned h, + float *p, + unsigned dst_stride) +{ + unsigned i, j; + + for (i = 0; i < h; i++) { + float *pRow = p; + for (j = 0; j < w; j++, pRow += 4) { + const unsigned pixel = *src++; + pRow[0] = srgb_to_linear((pixel >> 16) & 0xff); + pRow[1] = srgb_to_linear((pixel >> 8) & 0xff); + pRow[2] = srgb_to_linear((pixel >> 0) & 0xff); + pRow[3] = ubyte_to_float((pixel >> 24) & 0xff); + } + p += dst_stride; + } +} + +static void +a8r8g8b8_srgb_put_tile_rgba(unsigned *dst, + unsigned w, unsigned h, + const float *p, + unsigned src_stride) +{ + unsigned i, j; + + for (i = 0; i < h; i++) { + const float *pRow = p; + for (j = 0; j < w; j++, pRow += 4) { + unsigned r, g, b, a; + r = linear_to_srgb(pRow[0]); + g = linear_to_srgb(pRow[1]); + b = linear_to_srgb(pRow[2]); + a = float_to_ubyte(pRow[3]); + *dst++ = (a << 24) | (r << 16) | (g << 8) | b; + } + p += src_stride; + } +} + + +/*** PIPE_FORMAT_A8L8_SRGB ***/ + +static void +a8l8_srgb_get_tile_rgba(const ushort *src, + unsigned w, unsigned h, + float *p, + unsigned dst_stride) +{ + unsigned i, j; + + for (i = 0; i < h; i++) { + float *pRow = p; + for (j = 0; j < w; j++, pRow += 4) { + ushort p = *src++; + pRow[0] = + pRow[1] = + pRow[2] = srgb_to_linear(p & 0xff); + pRow[3] = ubyte_to_float(p >> 8); + } + p += dst_stride; + } +} + +static void +a8l8_srgb_put_tile_rgba(ushort *dst, + unsigned w, unsigned h, + const float *p, + unsigned src_stride) +{ + unsigned i, j; + + for (i = 0; i < h; i++) { + const float *pRow = p; + for (j = 0; j < w; j++, pRow += 4) { + unsigned r, a; + r = linear_to_srgb(pRow[0]); + a = float_to_ubyte(pRow[3]); + *dst++ = (a << 8) | r; + } + p += src_stride; + } +} + + +/*** PIPE_FORMAT_L8_SRGB ***/ + +static void +l8_srgb_get_tile_rgba(const ubyte *src, + unsigned w, unsigned h, + float *p, + unsigned dst_stride) +{ + unsigned i, j; + + for (i = 0; i < h; i++) { + float *pRow = p; + for (j = 0; j < w; j++, src++, pRow += 4) { + pRow[0] = + pRow[1] = + pRow[2] = srgb_to_linear(*src); + pRow[3] = 1.0; + } + p += dst_stride; + } +} + +static void +l8_srgb_put_tile_rgba(ubyte *dst, + unsigned w, unsigned h, + const float *p, + unsigned src_stride) +{ + unsigned i, j; + + for (i = 0; i < h; i++) { + const float *pRow = p; + for (j = 0; j < w; j++, pRow += 4) { + unsigned r; + r = linear_to_srgb(pRow[0]); + *dst++ = (ubyte) r; + } + p += src_stride; + } +} + /*** PIPE_FORMAT_I8_UNORM ***/ @@ -946,6 +1124,15 @@ pipe_tile_raw_to_rgba(enum pipe_format format, case PIPE_FORMAT_R16G16B16A16_SNORM: r16g16b16a16_get_tile_rgba((short *) src, w, h, dst, dst_stride); break; + case PIPE_FORMAT_A8R8G8B8_SRGB: + a8r8g8b8_srgb_get_tile_rgba((unsigned *) src, w, h, dst, dst_stride); + break; + case PIPE_FORMAT_A8L8_SRGB: + a8l8_srgb_get_tile_rgba((ushort *) src, w, h, dst, dst_stride); + break; + case PIPE_FORMAT_L8_SRGB: + l8_srgb_get_tile_rgba((ubyte *) src, w, h, dst, dst_stride); + break; case PIPE_FORMAT_Z16_UNORM: z16_get_tile_rgba((ushort *) src, w, h, dst, dst_stride); break; @@ -1059,6 +1246,15 @@ pipe_put_tile_rgba(struct pipe_transfer *pt, case PIPE_FORMAT_R16G16B16A16_SNORM: r16g16b16a16_put_tile_rgba((short *) packed, w, h, p, src_stride); break; + case PIPE_FORMAT_A8R8G8B8_SRGB: + a8r8g8b8_srgb_put_tile_rgba((unsigned *) packed, w, h, p, src_stride); + break; + case PIPE_FORMAT_A8L8_SRGB: + a8l8_srgb_put_tile_rgba((ushort *) packed, w, h, p, src_stride); + break; + case PIPE_FORMAT_L8_SRGB: + l8_srgb_put_tile_rgba((ubyte *) packed, w, h, p, src_stride); + break; case PIPE_FORMAT_Z16_UNORM: /*z16_put_tile_rgba((ushort *) packed, w, h, p, src_stride);*/ break;