Mesa (master): gallivm: Code generate YUV format unpacking.

Jose Fonseca jrfonseca at kemper.freedesktop.org
Fri Jul 2 10:50:27 UTC 2010


Module: Mesa
Branch: master
Commit: 3cc4301c146e2a6e680939456ea3df4ec2d12e3e
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=3cc4301c146e2a6e680939456ea3df4ec2d12e3e

Author: José Fonseca <jfonseca at vmware.com>
Date:   Fri Jul  2 11:40:22 2010 +0100

gallivm: Code generate YUV format unpacking.

---

 src/gallium/auxiliary/Makefile                    |    1 +
 src/gallium/auxiliary/SConscript                  |    1 +
 src/gallium/auxiliary/gallivm/lp_bld_format.h     |   12 +
 src/gallium/auxiliary/gallivm/lp_bld_format_aos.c |   22 ++
 src/gallium/auxiliary/gallivm/lp_bld_format_yuv.c |  395 +++++++++++++++++++++
 5 files changed, 431 insertions(+), 0 deletions(-)

diff --git a/src/gallium/auxiliary/Makefile b/src/gallium/auxiliary/Makefile
index 103d1d6..36a46ae 100644
--- a/src/gallium/auxiliary/Makefile
+++ b/src/gallium/auxiliary/Makefile
@@ -154,6 +154,7 @@ GALLIVM_SOURCES = \
         gallivm/lp_bld_flow.c \
         gallivm/lp_bld_format_aos.c \
         gallivm/lp_bld_format_soa.c \
+        gallivm/lp_bld_format_yuv.c \
         gallivm/lp_bld_init.c \
         gallivm/lp_bld_intr.c \
         gallivm/lp_bld_logic.c \
diff --git a/src/gallium/auxiliary/SConscript b/src/gallium/auxiliary/SConscript
index 1f40057..0b19444 100644
--- a/src/gallium/auxiliary/SConscript
+++ b/src/gallium/auxiliary/SConscript
@@ -203,6 +203,7 @@ if env['llvm']:
     'gallivm/lp_bld_flow.c',
     'gallivm/lp_bld_format_aos.c',
     'gallivm/lp_bld_format_soa.c',
+    'gallivm/lp_bld_format_yuv.c',
     'gallivm/lp_bld_intr.c',
     'gallivm/lp_bld_logic.c',
     'gallivm/lp_bld_init.c',
diff --git a/src/gallium/auxiliary/gallivm/lp_bld_format.h b/src/gallium/auxiliary/gallivm/lp_bld_format.h
index c335ca4..a853d7c 100644
--- a/src/gallium/auxiliary/gallivm/lp_bld_format.h
+++ b/src/gallium/auxiliary/gallivm/lp_bld_format.h
@@ -94,5 +94,17 @@ lp_build_fetch_rgba_soa(LLVMBuilderRef builder,
                         LLVMValueRef j,
                         LLVMValueRef rgba_out[4]);
 
+/*
+ * YUV
+ */
+
+
+LLVMValueRef
+lp_build_unpack_subsampled_to_rgba_aos(LLVMBuilderRef builder,
+                                       const struct util_format_description *format_desc,
+                                       unsigned n,
+                                       LLVMValueRef packed,
+                                       LLVMValueRef i,
+                                       LLVMValueRef j);
 
 #endif /* !LP_BLD_FORMAT_H */
diff --git a/src/gallium/auxiliary/gallivm/lp_bld_format_aos.c b/src/gallium/auxiliary/gallivm/lp_bld_format_aos.c
index bec2a80..cc72a31 100644
--- a/src/gallium/auxiliary/gallivm/lp_bld_format_aos.c
+++ b/src/gallium/auxiliary/gallivm/lp_bld_format_aos.c
@@ -366,6 +366,8 @@ lp_build_pack_rgba_aos(LLVMBuilderRef builder,
 }
 
 
+
+
 /**
  * Fetch a pixel into a 4 float AoS.
  *
@@ -429,6 +431,26 @@ lp_build_fetch_rgba_aos(LLVMBuilderRef builder,
          return lp_build_unpack_rgba_aos(format_desc, &bld, packed);
       }
    }
+   else if (format_desc->layout == UTIL_FORMAT_LAYOUT_SUBSAMPLED) {
+      LLVMValueRef packed;
+      LLVMValueRef rgba;
+
+      ptr = LLVMBuildBitCast(builder, ptr,
+                             LLVMPointerType(LLVMInt32Type(), 0),
+                             "packed_ptr");
+
+      packed = LLVMBuildLoad(builder, ptr, "packed");
+
+      rgba = lp_build_unpack_subsampled_to_rgba_aos(builder, format_desc,
+                                                    1, packed, i, j);
+
+      lp_build_conv(builder,
+                    lp_unorm8_vec4_type(),
+                    type,
+                    &rgba, 1, &rgba, 1);
+
+      return rgba;
+   }
    else if (format_desc->fetch_rgba_float) {
       /*
        * Fallback to calling util_format_description::fetch_rgba_float.
diff --git a/src/gallium/auxiliary/gallivm/lp_bld_format_yuv.c b/src/gallium/auxiliary/gallivm/lp_bld_format_yuv.c
new file mode 100644
index 0000000..5fe2ab6
--- /dev/null
+++ b/src/gallium/auxiliary/gallivm/lp_bld_format_yuv.c
@@ -0,0 +1,395 @@
+/**************************************************************************
+ *
+ * Copyright 2010 VMware, Inc.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ **************************************************************************/
+
+
+/**
+ * @file
+ * YUV pixel format manipulation.
+ *
+ * @author Jose Fonseca <jfonseca at vmware.com>
+ */
+
+
+#include "util/u_format.h"
+#include "util/u_memory.h"
+#include "util/u_math.h"
+#include "util/u_string.h"
+
+#include "lp_bld_arit.h"
+#include "lp_bld_init.h"
+#include "lp_bld_type.h"
+#include "lp_bld_const.h"
+#include "lp_bld_conv.h"
+#include "lp_bld_format.h"
+
+
+/**
+ * Extract Y, U, V channels from packed UYVY.
+ * @param packed  is a <n x i32> vector with the packed UYVY blocks
+ * @param i  is a <n x i32> vector with the x pixel coordinate (0 or 1)
+ */
+static void
+uyvy_to_yuv_soa(LLVMBuilderRef builder,
+                unsigned n,
+                LLVMValueRef packed,
+                LLVMValueRef i,
+                LLVMValueRef *y,
+                LLVMValueRef *u,
+                LLVMValueRef *v)
+{
+   struct lp_type type;
+   LLVMValueRef shift, mask;
+
+   memset(&type, 0, sizeof type);
+   type.width = 32;
+   type.length = n;
+
+   assert(lp_check_value(type, packed));
+   assert(lp_check_value(type, i));
+
+   /*
+    * y = (uyvy >> 16*i) & 0xff
+    * u = (uyvy        ) & 0xff
+    * v = (uyvy >> 16  ) & 0xff
+    */
+
+   shift = LLVMBuildMul(builder, i, lp_build_const_int_vec(type, 16), "");
+   shift = LLVMBuildAdd(builder, shift, lp_build_const_int_vec(type, 8), "");
+   *y = LLVMBuildLShr(builder, packed, shift, "");
+   *u = packed;
+   *v = LLVMBuildLShr(builder, packed, lp_build_const_int_vec(type, 16), "");
+
+   mask = lp_build_const_int_vec(type, 0xff);
+
+   *y = LLVMBuildAnd(builder, *y, mask, "y");
+   *u = LLVMBuildAnd(builder, *u, mask, "u");
+   *v = LLVMBuildAnd(builder, *v, mask, "v");
+}
+
+
+/**
+ * Extract Y, U, V channels from packed YUYV.
+ * @param packed  is a <n x i32> vector with the packed YUYV blocks
+ * @param i  is a <n x i32> vector with the x pixel coordinate (0 or 1)
+ */
+static void
+yuyv_to_yuv_soa(LLVMBuilderRef builder,
+                unsigned n,
+                LLVMValueRef packed,
+                LLVMValueRef i,
+                LLVMValueRef *y,
+                LLVMValueRef *u,
+                LLVMValueRef *v)
+{
+   struct lp_type type;
+   LLVMValueRef shift, mask;
+
+   memset(&type, 0, sizeof type);
+   type.width = 32;
+   type.length = n;
+
+   assert(lp_check_value(type, packed));
+   assert(lp_check_value(type, i));
+
+   /*
+    * y = (yuyv >> 16*i) & 0xff
+    * u = (yuyv >> 8   ) & 0xff
+    * v = (yuyv >> 24  ) & 0xff
+    */
+
+   shift = LLVMBuildMul(builder, i, lp_build_const_int_vec(type, 16), "");
+   *y = LLVMBuildLShr(builder, packed, shift, "");
+   *u = LLVMBuildLShr(builder, packed, lp_build_const_int_vec(type, 8), "");
+   *v = LLVMBuildLShr(builder, packed, lp_build_const_int_vec(type, 24), "");
+
+   mask = lp_build_const_int_vec(type, 0xff);
+
+   *y = LLVMBuildAnd(builder, *y, mask, "y");
+   *u = LLVMBuildAnd(builder, *u, mask, "u");
+   *v = LLVMBuildAnd(builder, *v, mask, "v");
+}
+
+
+static INLINE void
+yuv_to_rgb_soa(LLVMBuilderRef builder,
+               unsigned n,
+               LLVMValueRef y, LLVMValueRef u, LLVMValueRef v,
+               LLVMValueRef *r, LLVMValueRef *g, LLVMValueRef *b)
+{
+   struct lp_type type;
+   struct lp_build_context bld;
+
+   LLVMValueRef c0;
+   LLVMValueRef c8;
+   LLVMValueRef c16;
+   LLVMValueRef c128;
+   LLVMValueRef c255;
+
+   LLVMValueRef cy;
+   LLVMValueRef cug;
+   LLVMValueRef cub;
+   LLVMValueRef cvr;
+   LLVMValueRef cvg;
+
+   memset(&type, 0, sizeof type);
+   type.sign = TRUE;
+   type.width = 32;
+   type.length = n;
+
+   lp_build_context_init(&bld, builder, type);
+
+   assert(lp_check_value(type, y));
+   assert(lp_check_value(type, u));
+   assert(lp_check_value(type, v));
+
+   /*
+    * Constants
+    */
+
+   c0   = lp_build_const_int_vec(type,   0);
+   c8   = lp_build_const_int_vec(type,   8);
+   c16  = lp_build_const_int_vec(type,  16);
+   c128 = lp_build_const_int_vec(type, 128);
+   c255 = lp_build_const_int_vec(type, 255);
+
+   cy  = lp_build_const_int_vec(type,  298);
+   cug = lp_build_const_int_vec(type, -100);
+   cub = lp_build_const_int_vec(type,  516);
+   cvr = lp_build_const_int_vec(type,  409);
+   cvg = lp_build_const_int_vec(type, -208);
+
+   /*
+    *  y -= 16;
+    *  u -= 128;
+    *  v -= 128;
+    */
+
+   y = LLVMBuildSub(builder, y, c16, "");
+   u = LLVMBuildSub(builder, u, c128, "");
+   v = LLVMBuildSub(builder, v, c128, "");
+
+   /*
+    * r = 298 * _y            + 409 * _v + 128;
+    * g = 298 * _y - 100 * _u - 208 * _v + 128;
+    * b = 298 * _y + 516 * _u            + 128;
+    */
+
+   y = LLVMBuildMul(builder, y, cy, "");
+   y = LLVMBuildAdd(builder, y, c128, "");
+
+   *r = LLVMBuildMul(builder, v, cvr, "");
+   *g = LLVMBuildAdd(builder,
+                     LLVMBuildMul(builder, u, cug, ""),
+                     LLVMBuildMul(builder, v, cvg, ""),
+                     "");
+   *b = LLVMBuildMul(builder, u, cub, "");
+
+   *r = LLVMBuildAdd(builder, *r, y, "");
+   *g = LLVMBuildAdd(builder, *g, y, "");
+   *b = LLVMBuildAdd(builder, *b, y, "");
+
+   /*
+    * r >>= 8;
+    * g >>= 8;
+    * b >>= 8;
+    */
+
+   *r = LLVMBuildAShr(builder, *r, c8, "r");
+   *g = LLVMBuildAShr(builder, *g, c8, "g");
+   *b = LLVMBuildAShr(builder, *b, c8, "b");
+
+   /*
+    * Clamp
+    */
+
+   *r = lp_build_clamp(&bld, *r, c0, c255);
+   *g = lp_build_clamp(&bld, *g, c0, c255);
+   *b = lp_build_clamp(&bld, *b, c0, c255);
+}
+
+
+static LLVMValueRef
+rgb_to_rgba_aos(LLVMBuilderRef builder,
+                unsigned n,
+                LLVMValueRef r, LLVMValueRef g, LLVMValueRef b)
+{
+   struct lp_type type;
+   LLVMValueRef a;
+   LLVMValueRef rgba;
+
+   memset(&type, 0, sizeof type);
+   type.sign = TRUE;
+   type.width = 32;
+   type.length = n;
+
+   assert(lp_check_value(type, r));
+   assert(lp_check_value(type, g));
+   assert(lp_check_value(type, b));
+
+   /*
+    * Make a 4 x unorm8 vector
+    */
+
+   r = r;
+   g = LLVMBuildShl(builder, g, lp_build_const_int_vec(type, 8), "");
+   b = LLVMBuildShl(builder, b, lp_build_const_int_vec(type, 16), "");
+   a = lp_build_const_int_vec(type, 0xff000000);
+
+   rgba = r;
+   rgba = LLVMBuildOr(builder, rgba, g, "");
+   rgba = LLVMBuildOr(builder, rgba, b, "");
+   rgba = LLVMBuildOr(builder, rgba, a, "");
+
+   rgba = LLVMBuildBitCast(builder, rgba,
+                           LLVMVectorType(LLVMInt8Type(), 4*n), "");
+
+   return rgba;
+}
+
+
+/**
+ * Convert from <n x i32> packed UYVY to <4n x i8> RGBA AoS
+ */
+static LLVMValueRef
+uyvy_to_rgba_aos(LLVMBuilderRef builder,
+                 unsigned n,
+                 LLVMValueRef packed,
+                 LLVMValueRef i)
+{
+   LLVMValueRef y, u, v;
+   LLVMValueRef r, g, b;
+   LLVMValueRef rgba;
+
+   uyvy_to_yuv_soa(builder, n, packed, i, &y, &u, &v);
+   yuv_to_rgb_soa(builder, n, y, u, v, &r, &g, &b);
+   rgba = rgb_to_rgba_aos(builder, n, r, g, b);
+
+   return rgba;
+}
+
+
+/**
+ * Convert from <n x i32> packed YUYV to <4n x i8> RGBA AoS
+ */
+static LLVMValueRef
+yuyv_to_rgba_aos(LLVMBuilderRef builder,
+                 unsigned n,
+                 LLVMValueRef packed,
+                 LLVMValueRef i)
+{
+   LLVMValueRef y, u, v;
+   LLVMValueRef r, g, b;
+   LLVMValueRef rgba;
+
+   yuyv_to_yuv_soa(builder, n, packed, i, &y, &u, &v);
+   yuv_to_rgb_soa(builder, n, y, u, v, &r, &g, &b);
+   rgba = rgb_to_rgba_aos(builder, n, r, g, b);
+
+   return rgba;
+}
+
+
+/**
+ * Convert from <n x i32> packed RG_BG to <4n x i8> RGBA AoS
+ */
+static LLVMValueRef
+rgbg_to_rgba_aos(LLVMBuilderRef builder,
+                 unsigned n,
+                 LLVMValueRef packed,
+                 LLVMValueRef i)
+{
+   LLVMValueRef r, g, b;
+   LLVMValueRef rgba;
+
+   uyvy_to_yuv_soa(builder, n, packed, i, &g, &r, &b);
+   rgba = rgb_to_rgba_aos(builder, n, r, g, b);
+
+   return rgba;
+}
+
+
+/**
+ * Convert from <n x i32> packed GR_GB to <4n x i8> RGBA AoS
+ */
+static LLVMValueRef
+grgb_to_rgba_aos(LLVMBuilderRef builder,
+                 unsigned n,
+                 LLVMValueRef packed,
+                 LLVMValueRef i)
+{
+   LLVMValueRef r, g, b;
+   LLVMValueRef rgba;
+
+   yuyv_to_yuv_soa(builder, n, packed, i, &g, &r, &b);
+   rgba = rgb_to_rgba_aos(builder, n, r, g, b);
+
+   return rgba;
+}
+
+
+/**
+ * @param n  is the number of pixels processed
+ * @param packed  is a <n x i32> vector with the packed YUYV blocks
+ * @param i  is a <n x i32> vector with the x pixel coordinate (0 or 1)
+ * @return  a <4*n x i8> vector with the pixel RGBA values in AoS
+ */
+LLVMValueRef
+lp_build_unpack_subsampled_to_rgba_aos(LLVMBuilderRef builder,
+                                       const struct util_format_description *format_desc,
+                                       unsigned n,
+                                       LLVMValueRef packed,
+                                       LLVMValueRef i,
+                                       LLVMValueRef j)
+{
+   LLVMValueRef rgba;
+
+   assert(format_desc->layout == UTIL_FORMAT_LAYOUT_SUBSAMPLED);
+
+   (void)j;
+
+   switch (format_desc->format) {
+   case PIPE_FORMAT_UYVY:
+      rgba = uyvy_to_rgba_aos(builder, n, packed, i);
+      break;
+   case PIPE_FORMAT_YUYV:
+      rgba = yuyv_to_rgba_aos(builder, n, packed, i);
+      break;
+   case PIPE_FORMAT_R8G8_B8G8_UNORM:
+      rgba = rgbg_to_rgba_aos(builder, n, packed, i);
+      break;
+   case PIPE_FORMAT_G8R8_G8B8_UNORM:
+      rgba = grgb_to_rgba_aos(builder, n, packed, i);
+      break;
+   default:
+      assert(0);
+      rgba =  LLVMGetUndef(LLVMVectorType(LLVMInt8Type(), 4*n));
+      break;
+   }
+
+   return rgba;
+}
+




More information about the mesa-commit mailing list