gallium: implement ycbcr->rgba tile conversion
authorBrian <brian.paul@tungstengraphics.com>
Thu, 3 Apr 2008 22:36:07 +0000 (16:36 -0600)
committerBrian <brian.paul@tungstengraphics.com>
Thu, 3 Apr 2008 22:36:07 +0000 (16:36 -0600)
src/gallium/auxiliary/util/p_tile.c

index 287d7839812fc6b4bce175d9a199d5442540a5a4..c9a9c8f4f716bd755b9f2b5cfe0632606aee42c3 100644 (file)
@@ -560,6 +560,69 @@ z24s8_get_tile_rgba(unsigned *src,
 }
 
 
+/*** PIPE_FORMAT_YCBCR / PIPE_FORMAT_YCBCR_REV ***/
+
+/**
+ * Convert YCbCr (or YCrCb) to RGBA.
+ */
+static void
+ycbcr_get_tile_rgba(ushort *src,
+                    unsigned w, unsigned h,
+                    float *p,
+                    unsigned dst_stride,
+                    boolean rev)
+{
+   const float scale = 1.0f / 255.0f;
+   unsigned i, j;
+
+   /* we're assuming we're being asked for an even number of texels */
+   assert((w & 1) == 0);
+
+   for (i = 0; i < h; i++) {
+      float *pRow = p;
+      /* do two texels at a time */
+      for (j = 0; j < w; j += 2, src += 2) {
+         const ushort t0 = src[0];
+         const ushort t1 = src[1];
+         const ubyte y0 = (t0 >> 8) & 0xff;  /* luminance */
+         const ubyte y1 = (t1 >> 8) & 0xff;  /* luminance */
+         ubyte cb, cr;
+         if (rev) {
+            cb = t1 & 0xff;         /* chroma U */
+            cr = t0 & 0xff;         /* chroma V */
+         }
+         else {
+            cb = t0 & 0xff;         /* chroma U */
+            cr = t1 & 0xff;         /* chroma V */
+         }
+         float r, g, b;
+
+         /* even pixel: y0,cr,cb */
+         r = 1.164 * (y0-16) + 1.596 * (cr-128);
+         g = 1.164 * (y0-16) - 0.813 * (cr-128) - 0.391 * (cb-128);
+         b = 1.164 * (y0-16) + 2.018 * (cb-128);
+         pRow[0] = r * scale;
+         pRow[1] = g * scale;
+         pRow[2] = b * scale;
+         pRow[3] = 1.0f;
+         pRow += 4;
+
+         /* odd pixel: use y1,cr,cb */
+         r = 1.164 * (y1-16) + 1.596 * (cr-128);
+         g = 1.164 * (y1-16) - 0.813 * (cr-128) - 0.391 * (cb-128);
+         b = 1.164 * (y1-16) + 2.018 * (cb-128);
+         pRow[0] = r * scale;
+         pRow[1] = g * scale;
+         pRow[2] = b * scale;
+         pRow[3] = 1.0f;
+         pRow += 4;
+
+      }
+      p += dst_stride;
+   }
+}
+
+
 void
 pipe_get_tile_rgba(struct pipe_context *pipe,
                    struct pipe_surface *ps,
@@ -622,6 +685,14 @@ pipe_get_tile_rgba(struct pipe_context *pipe,
    case PIPE_FORMAT_Z24S8_UNORM:
       z24s8_get_tile_rgba((unsigned *) packed, w, h, p, dst_stride);
       break;
+   case PIPE_FORMAT_YCBCR:
+      assert((x & 1) == 0);
+      ycbcr_get_tile_rgba((ushort *) packed, w, h, p, dst_stride, FALSE);
+      break;
+   case PIPE_FORMAT_YCBCR_REV:
+      assert((x & 1) == 0);
+      ycbcr_get_tile_rgba((ushort *) packed, w, h, p, dst_stride, TRUE);
+      break;
    default:
       assert(0);
    }