mesa: Add RGBA to Luminance conversion helpers
authorIago Toral Quiroga <itoral@igalia.com>
Wed, 29 Oct 2014 12:32:43 +0000 (13:32 +0100)
committerIago Toral Quiroga <itoral@igalia.com>
Mon, 12 Jan 2015 10:20:29 +0000 (11:20 +0100)
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 <jason.ekstrand@intel.com>
src/mesa/main/pack.c
src/mesa/main/pack.h

index de6ab2717cbd8e5886b0af2d97fa69bb44aaebab..140ba29e4fa10c5ab7c3926624babbd73500212b 100644 (file)
@@ -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;
+   }
+}
 
index 2173b652e7580e93cfc3ad15154b2048a689ef17..9988bea4fd1314dcd37b7e358675c3e2cc554eef 100644 (file)
@@ -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