From d71a1adff253aa75a3474723209c35831bb3f048 Mon Sep 17 00:00:00 2001 From: Iago Toral Quiroga Date: Wed, 29 Oct 2014 13:32:43 +0100 Subject: [PATCH] mesa: Add RGBA to Luminance conversion helpers For glReadPixels with a Luminance destination format we compute luminance values from RGBA as L=R+G+B. This, however, requires ad-hoc implementation, since pack/unpack functions or _mesa_swizzle_and_convert won't do this (and thus, neither will _mesa_format_convert). This patch adds helpers to do this computation so they can be used to support conversion to luminance formats. The current implementation of glReadPixels does this computation as part of the span functions in pack.c (see _mesa_pack_rgba_span_float), that do this together with other things like type conversion, etc. We do not want to use these functions but use _mesa_format_convert instead (later patches will remove the color span functions), so we need to extract this functionality as helpers. Reviewed-by: Jason Ekstrand --- src/mesa/main/pack.c | 214 +++++++++++++++++++++++++++++++++++++++++++ src/mesa/main/pack.h | 10 ++ 2 files changed, 224 insertions(+) diff --git a/src/mesa/main/pack.c b/src/mesa/main/pack.c index de6ab2717cb..140ba29e4fa 100644 --- a/src/mesa/main/pack.c +++ b/src/mesa/main/pack.c @@ -4334,4 +4334,218 @@ _mesa_rebase_rgba_uint(GLuint n, GLuint rgba[][4], GLenum baseFormat) } } +void +_mesa_pack_luminance_from_rgba_float(GLuint n, GLfloat rgba[][4], + GLvoid *dstAddr, GLenum dst_format, + GLbitfield transferOps) +{ + int i; + GLfloat *dst = (GLfloat *) dstAddr; + + switch (dst_format) { + case GL_LUMINANCE: + if (transferOps & IMAGE_CLAMP_BIT) { + for (i = 0; i < n; i++) { + GLfloat sum = rgba[i][RCOMP] + rgba[i][GCOMP] + rgba[i][BCOMP]; + dst[i] = CLAMP(sum, 0.0F, 1.0F); + } + } else { + for (i = 0; i < n; i++) { + dst[i] = rgba[i][RCOMP] + rgba[i][GCOMP] + rgba[i][BCOMP]; + } + } + return; + case GL_LUMINANCE_ALPHA: + if (transferOps & IMAGE_CLAMP_BIT) { + for (i = 0; i < n; i++) { + GLfloat sum = rgba[i][RCOMP] + rgba[i][GCOMP] + rgba[i][BCOMP]; + dst[2*i] = CLAMP(sum, 0.0F, 1.0F); + dst[2*i+1] = rgba[i][ACOMP]; + } + } else { + for (i = 0; i < n; i++) { + dst[2*i] = rgba[i][RCOMP] + rgba[i][GCOMP] + rgba[i][BCOMP]; + dst[2*i+1] = rgba[i][ACOMP]; + } + } + return; + default: + assert(!"Unsupported format"); + } +} + +static int32_t +clamp_sint64_to_sint32(int64_t src) +{ + return CLAMP(src, INT32_MIN, INT32_MAX); +} + +static int32_t +clamp_sint64_to_uint32(int64_t src) +{ + return CLAMP(src, 0, UINT32_MAX); +} + +static int32_t +clamp_uint64_to_uint32(uint64_t src) +{ + return MIN2(src, UINT32_MAX); +} + +static int32_t +clamp_uint64_to_sint32(uint64_t src) +{ + return MIN2(src, INT32_MAX); +} + +static int32_t +convert_integer_luminance64(int64_t src64, int bits, + bool dst_is_signed, bool src_is_signed) +{ + int32_t src32; + + /* Clamp Luminance value from 64-bit to 32-bit. Consider if we need + * any signed<->unsigned conversion too. + */ + if (src_is_signed && dst_is_signed) + src32 = clamp_sint64_to_sint32(src64); + else if (src_is_signed && !dst_is_signed) + src32 = clamp_sint64_to_uint32(src64); + else if (!src_is_signed && dst_is_signed) + src32 = clamp_uint64_to_sint32(src64); + else + src32 = clamp_uint64_to_uint32(src64); + + /* If the dst type is < 32-bit, we need an extra clamp */ + if (bits == 32) { + return src32; + } else { + if (dst_is_signed) + return _mesa_signed_to_signed(src32, bits); + else + return _mesa_unsigned_to_unsigned(src32, bits); + } +} + +static int32_t +convert_integer(int32_t src, int bits, bool dst_is_signed, bool src_is_signed) +{ + if (src_is_signed && dst_is_signed) + return _mesa_signed_to_signed(src, bits); + else if (src_is_signed && !dst_is_signed) + return _mesa_signed_to_unsigned(src, bits); + else if (!src_is_signed && dst_is_signed) + return _mesa_unsigned_to_signed(src, bits); + else + return _mesa_unsigned_to_unsigned(src, bits); +} + +void +_mesa_pack_luminance_from_rgba_integer(GLuint n, + GLuint rgba[][4], bool rgba_is_signed, + GLvoid *dstAddr, + GLenum dst_format, + GLenum dst_type) +{ + assert(dst_format == GL_LUMINANCE_INTEGER_EXT || + dst_format == GL_LUMINANCE_ALPHA_INTEGER_EXT); + + int i; + int64_t lum64; + int32_t lum32, alpha; + bool dst_is_signed; + int dst_bits; + + /* We first compute luminance values as a 64-bit addition of the + * 32-bit R,G,B components, then we clamp the result to the dst type size. + * + * Notice that this operation involves casting the 32-bit R,G,B components + * to 64-bit before the addition. Since rgba is defined as a GLuint array + * we need to be careful when rgba packs signed data and make sure + * that we cast to a 32-bit signed integer values before casting them to + * 64-bit signed integers. + */ + dst_is_signed = (dst_type == GL_BYTE || dst_type == GL_SHORT || + dst_type == GL_INT); + + dst_bits = _mesa_sizeof_type(dst_type) * 8; + assert(dst_bits > 0); + + switch (dst_format) { + case GL_LUMINANCE_INTEGER_EXT: + for (i = 0; i < n; i++) { + if (!rgba_is_signed) { + lum64 = (uint64_t) rgba[i][RCOMP] + + (uint64_t) rgba[i][GCOMP] + + (uint64_t) rgba[i][BCOMP]; + } else { + lum64 = (int64_t) ((int32_t) rgba[i][RCOMP]) + + (int64_t) ((int32_t) rgba[i][GCOMP]) + + (int64_t) ((int32_t) rgba[i][BCOMP]); + } + lum32 = convert_integer_luminance64(lum64, dst_bits, + dst_is_signed, rgba_is_signed); + switch (dst_type) { + case GL_BYTE: + case GL_UNSIGNED_BYTE: { + GLbyte *dst = (GLbyte *) dstAddr; + dst[i] = lum32; + } + break; + case GL_SHORT: + case GL_UNSIGNED_SHORT: { + GLshort *dst = (GLshort *) dstAddr; + dst[i] = lum32; + } + break; + case GL_INT: + case GL_UNSIGNED_INT: { + GLint *dst = (GLint *) dstAddr; + dst[i] = lum32; + } + break; + } + } + return; + case GL_LUMINANCE_ALPHA_INTEGER_EXT: + for (i = 0; i < n; i++) { + if (!rgba_is_signed) { + lum64 = (uint64_t) rgba[i][RCOMP] + + (uint64_t) rgba[i][GCOMP] + + (uint64_t) rgba[i][BCOMP]; + } else { + lum64 = (int64_t) ((int32_t) rgba[i][RCOMP]) + + (int64_t) ((int32_t) rgba[i][GCOMP]) + + (int64_t) ((int32_t) rgba[i][BCOMP]); + } + lum32 = convert_integer_luminance64(lum64, dst_bits, + dst_is_signed, rgba_is_signed); + alpha = convert_integer(rgba[i][ACOMP], dst_bits, + dst_is_signed, rgba_is_signed); + switch (dst_type) { + case GL_BYTE: + case GL_UNSIGNED_BYTE: { + GLbyte *dst = (GLbyte *) dstAddr; + dst[2*i] = lum32; + dst[2*i+1] = alpha; + } + case GL_SHORT: + case GL_UNSIGNED_SHORT: { + GLshort *dst = (GLshort *) dstAddr; + dst[i] = lum32; + dst[2*i+1] = alpha; + } + break; + case GL_INT: + case GL_UNSIGNED_INT: { + GLint *dst = (GLint *) dstAddr; + dst[i] = lum32; + dst[2*i+1] = alpha; + } + break; + } + } + return; + } +} diff --git a/src/mesa/main/pack.h b/src/mesa/main/pack.h index 2173b652e75..9988bea4fd1 100644 --- a/src/mesa/main/pack.h +++ b/src/mesa/main/pack.h @@ -155,4 +155,14 @@ _mesa_rebase_rgba_float(GLuint n, GLfloat rgba[][4], GLenum baseFormat); extern void _mesa_rebase_rgba_uint(GLuint n, GLuint rgba[][4], GLenum baseFormat); +extern void +_mesa_pack_luminance_from_rgba_float(GLuint n, GLfloat rgba[][4], + GLvoid *dstAddr, GLenum dst_format, + GLbitfield transferOps); + +extern void +_mesa_pack_luminance_from_rgba_integer(GLuint n, GLuint rgba[][4], bool rgba_is_signed, + GLvoid *dstAddr, GLenum dst_format, + GLenum dst_type); + #endif -- 2.30.2