g3dvl: Color space conv interface & vl impl.
authorYounes Manton <younes.m@gmail.com>
Fri, 2 Oct 2009 01:53:17 +0000 (21:53 -0400)
committerYounes Manton <younes.m@gmail.com>
Fri, 2 Oct 2009 02:52:59 +0000 (22:52 -0400)
Interface is pipe_video_context::set_csc_matrix().

vl_csc.h defines some helpers to generate CSC matrices based on one of
the color standard and a user defined ProcAmp (brightness, contrast,
saturation, hue).

src/gallium/auxiliary/vl/Makefile
src/gallium/auxiliary/vl/SConscript
src/gallium/auxiliary/vl/vl_compositor.c
src/gallium/auxiliary/vl/vl_compositor.h
src/gallium/auxiliary/vl/vl_csc.c [new file with mode: 0644]
src/gallium/auxiliary/vl/vl_csc.h [new file with mode: 0644]
src/gallium/drivers/softpipe/sp_video_context.c
src/gallium/include/pipe/p_video_context.h

index 71bfb937ad7343c95edcfed7869811404fb7bb10..4314c1e8d693cf118cac1c944a9aed70386547df 100644 (file)
@@ -7,6 +7,7 @@ C_SOURCES = \
        vl_bitstream_parser.c \
        vl_mpeg12_mc_renderer.c \
        vl_compositor.c \
+        vl_csc.c \
        vl_shader_build.c
 
 include ../../Makefile.template
index eb50940c3596cc4c1d44fdff1e436799c2df022a..aed69f5efedc613144e06561c3fd2fcc33d7f29d 100644 (file)
@@ -6,6 +6,7 @@ vl = env.ConvenienceLibrary(
                'vl_bitstream_parser.c',
                'vl_mpeg12_mc_renderer.c',
                'vl_compositor.c',
+                'vl_csc.c',
                'vl_shader_build.c',
        ])
 
index 6431da66110096c7001b1e202d48481af277d462..5d3458afd27451916b98e71d5f3c118ac88302ac 100644 (file)
@@ -5,6 +5,7 @@
 #include <tgsi/tgsi_parse.h>
 #include <tgsi/tgsi_build.h>
 #include <util/u_memory.h>
+#include "vl_csc.h"
 #include "vl_shader_build.h"
 
 struct vertex2f
@@ -27,7 +28,6 @@ struct vertex_shader_consts
 
 struct fragment_shader_consts
 {
-   struct vertex4f bias;
    float matrix[16];
 };
 
@@ -49,94 +49,6 @@ static const struct vertex2f surface_verts[4] =
  */
 static const struct vertex2f *surface_texcoords = surface_verts;
 
-/*
- * Identity color conversion constants, for debugging
- */
-static const struct fragment_shader_consts identity =
-{
-   {
-      0.0f, 0.0f, 0.0f, 0.0f
-   },
-   {
-      1.0f, 0.0f, 0.0f, 0.0f,
-      0.0f, 1.0f, 0.0f, 0.0f,
-      0.0f, 0.0f, 1.0f, 0.0f,
-      0.0f, 0.0f, 0.0f, 1.0f
-   }
-};
-
-/*
- * Converts ITU-R BT.601 YCbCr pixels to RGB pixels where:
- * Y is in [16,235], Cb and Cr are in [16,240]
- * R, G, and B are in [16,235]
- */
-static const struct fragment_shader_consts bt_601 =
-{
-   {
-      0.0f, 0.501960784f, 0.501960784f,        0.0f
-   },
-   {
-      1.0f, 0.0f,   1.371f,   0.0f,
-      1.0f, -0.336f, -0.698f, 0.0f,
-      1.0f, 1.732f, 0.0f,     0.0f,
-      0.0f, 0.0f,   0.0f,     1.0f
-   }
-};
-
-/*
- * Converts ITU-R BT.601 YCbCr pixels to RGB pixels where:
- * Y is in [16,235], Cb and Cr are in [16,240]
- * R, G, and B are in [0,255]
- */
-static const struct fragment_shader_consts bt_601_full =
-{
-   {
-      0.062745098f, 0.501960784f, 0.501960784f,        0.0f
-   },
-   {
-      1.164f, 0.0f,    1.596f,  0.0f,
-      1.164f, -0.391f, -0.813f, 0.0f,
-      1.164f, 2.018f,  0.0f,    0.0f,
-      0.0f,   0.0f,    0.0f,    1.0f
-   }
-};
-
-/*
- * Converts ITU-R BT.709 YCbCr pixels to RGB pixels where:
- * Y is in [16,235], Cb and Cr are in [16,240]
- * R, G, and B are in [16,235]
- */
-static const struct fragment_shader_consts bt_709 =
-{
-   {
-      0.0f, 0.501960784f, 0.501960784f,        0.0f
-   },
-   {
-      1.0f, 0.0f,    1.540f,  0.0f,
-      1.0f, -0.183f, -0.459f, 0.0f,
-      1.0f, 1.816f,  0.0f,    0.0f,
-      0.0f, 0.0f,    0.0f,    1.0f
-   }
-};
-
-/*
- * Converts ITU-R BT.709 YCbCr pixels to RGB pixels where:
- * Y is in [16,235], Cb and Cr are in [16,240]
- * R, G, and B are in [0,255]
- */
-const struct fragment_shader_consts bt_709_full =
-{
-   {
-      0.062745098f, 0.501960784f, 0.501960784f,        0.0f
-   },
-   {
-      1.164f, 0.0f,    1.793f,  0.0f,
-      1.164f, -0.213f, -0.534f,        0.0f,
-      1.164f, 2.115f,  0.0f,    0.0f,
-      0.0f,   0.0f,    0.0f,    1.0f
-   }
-};
-
 static void
 create_vert_shader(struct vl_compositor *c)
 {
@@ -245,10 +157,9 @@ create_frag_shader(struct vl_compositor *c)
    ti += tgsi_build_full_declaration(&decl, &tokens[ti], header, max_tokens - ti);
 
    /*
-    * decl c0             ; Bias vector for CSC
-    * decl c1-c4          ; CSC matrix c1-c4
+    * decl c0-c3          ; CSC matrix c0-c3
     */
-   decl = vl_decl_constants(TGSI_SEMANTIC_GENERIC, 0, 0, 4);
+   decl = vl_decl_constants(TGSI_SEMANTIC_GENERIC, 0, 0, 3);
    ti += tgsi_build_full_declaration(&decl, &tokens[ti], header, max_tokens - ti);
 
    /* decl o0             ; Fragment color */
@@ -267,17 +178,14 @@ create_frag_shader(struct vl_compositor *c)
    inst = vl_tex(TGSI_TEXTURE_2D, TGSI_FILE_TEMPORARY, 0, TGSI_FILE_INPUT, 0, TGSI_FILE_SAMPLER, 0);
    ti += tgsi_build_full_instruction(&inst, &tokens[ti], header, max_tokens - ti);
 
-   /* sub t0, t0, c0      ; Subtract bias vector from pixel */
-   inst = vl_inst3(TGSI_OPCODE_SUB, TGSI_FILE_TEMPORARY, 0, TGSI_FILE_TEMPORARY, 0, TGSI_FILE_CONSTANT, 0);
-   ti += tgsi_build_full_instruction(&inst, &tokens[ti], header, max_tokens - ti);
-
    /*
-    * dp4 o0.x, t0, c1    ; Multiply pixel by the color conversion matrix
-    * dp4 o0.y, t0, c2
-    * dp4 o0.z, t0, c3
+    * dp4 o0.x, t0, c0    ; Multiply pixel by the color conversion matrix
+    * dp4 o0.y, t0, c1
+    * dp4 o0.z, t0, c2
+    * dp4 o0.w, t0, c3
     */
-   for (i = 0; i < 3; ++i) {
-      inst = vl_inst3(TGSI_OPCODE_DP4, TGSI_FILE_OUTPUT, 0, TGSI_FILE_TEMPORARY, 0, TGSI_FILE_CONSTANT, i + 1);
+   for (i = 0; i < 4; ++i) {
+      inst = vl_inst3(TGSI_OPCODE_DP4, TGSI_FILE_OUTPUT, 0, TGSI_FILE_TEMPORARY, 0, TGSI_FILE_CONSTANT, i);
       inst.FullDstRegisters[0].DstRegister.WriteMask = TGSI_WRITEMASK_X << i;
       ti += tgsi_build_full_instruction(&inst, &tokens[ti], header, max_tokens - ti);
    }
@@ -352,6 +260,8 @@ static void cleanup_shaders(struct vl_compositor *c)
 static bool
 init_buffers(struct vl_compositor *c)
 {
+   struct fragment_shader_consts fsc;
+
    assert(c);
        
    /*
@@ -438,18 +348,9 @@ init_buffers(struct vl_compositor *c)
       sizeof(struct fragment_shader_consts)
    );
 
-   /*
-    * TODO: Refactor this into a seperate function,
-    * allow changing the CSC matrix at runtime to switch between regular & full versions
-    */
-   memcpy
-   (
-      pipe_buffer_map(c->pipe->screen, c->fs_const_buf.buffer, PIPE_BUFFER_USAGE_CPU_WRITE),
-      &bt_601_full,
-      sizeof(struct fragment_shader_consts)
-   );
+   vl_csc_get_matrix(VL_CSC_COLOR_STANDARD_IDENTITY, NULL, true, fsc.matrix);
 
-   pipe_buffer_unmap(c->pipe->screen, c->fs_const_buf.buffer);
+   vl_compositor_set_csc_matrix(c, fsc.matrix);
 
    return true;
 }
@@ -588,3 +489,17 @@ void vl_compositor_render(struct vl_compositor          *compositor,
 
    pipe_surface_reference(&compositor->fb_state.cbufs[0], NULL);
 }
+
+void vl_compositor_set_csc_matrix(struct vl_compositor *compositor, const float *mat)
+{
+   assert(compositor);
+
+   memcpy
+   (
+      pipe_buffer_map(compositor->pipe->screen, compositor->fs_const_buf.buffer, PIPE_BUFFER_USAGE_CPU_WRITE),
+      mat,
+      sizeof(struct fragment_shader_consts)
+   );
+
+   pipe_buffer_unmap(compositor->pipe->screen, compositor->fs_const_buf.buffer);
+}
index 19ad66d9c61c9d4f7e41d948c585f80ff281931f..975ea00bde0dd57ac013b545b964f07af96e0e20 100644 (file)
@@ -44,4 +44,6 @@ void vl_compositor_render(struct vl_compositor          *compositor,
                           struct pipe_video_rect        *layer_dst_areas,*/
                           struct pipe_fence_handle      **fence);
 
+void vl_compositor_set_csc_matrix(struct vl_compositor *compositor, const float *mat);
+
 #endif /* vl_compositor_h */
diff --git a/src/gallium/auxiliary/vl/vl_csc.c b/src/gallium/auxiliary/vl/vl_csc.c
new file mode 100644 (file)
index 0000000..828cebe
--- /dev/null
@@ -0,0 +1,179 @@
+#include "vl_csc.h"
+#include <util/u_math.h>
+#include <util/u_debug.h>
+
+/*
+ * Color space conversion formulas
+ *
+ * To convert YCbCr to RGB,
+ *    vec4  ycbcr, rgb
+ *    mat44 csc
+ *    rgb = csc * ycbcr
+ *
+ * To calculate the color space conversion matrix csc with ProcAmp adjustments,
+ *    mat44 csc, cstd, procamp, bias
+ *    csc = cstd * (procamp * bias)
+ *
+ * Where cstd is a matrix corresponding to one of the color standards (BT.601, BT.709, etc)
+ * adjusted for the kind of YCbCr -> RGB mapping wanted (1:1, full),
+ * bias is a matrix corresponding to the kind of YCbCr -> RGB mapping wanted (1:1, full)
+ *
+ * To calculate procamp,
+ *    mat44 procamp, hue, saturation, brightness, contrast
+ *    procamp = brightness * (saturation * (contrast * hue))
+ * Alternatively,
+ *    procamp = saturation * (brightness * (contrast * hue))
+ *
+ * contrast
+ * [ c, 0, 0, 0]
+ * [ 0, c, 0, 0]
+ * [ 0, 0, c, 0]
+ * [ 0, 0, 0, 1]
+ *
+ * brightness
+ * [ 1, 0, 0, b]
+ * [ 0, 1, 0, 0]
+ * [ 0, 0, 1, 0]
+ * [ 0, 0, 0, 1]
+ *
+ * saturation
+ * [ 1, 0, 0, 0]
+ * [ 0, s, 0, 0]
+ * [ 0, 0, s, 0]
+ * [ 0, 0, 0, 1]
+ *
+ * hue
+ * [ 1,       0,      0, 0]
+ * [ 0,  cos(h), sin(h), 0]
+ * [ 0, -sin(h), cos(h), 0]
+ * [ 0,       0,      0, 1]
+ *
+ * procamp
+ * [ c,           0,          0, b]
+ * [ 0,  c*s*cos(h), c*s*sin(h), 0]
+ * [ 0, -c*s*sin(h), c*s*cos(h), 0]
+ * [ 0,           0,          0, 1]
+ *
+ * bias
+ * [ 1, 0, 0,  ybias]
+ * [ 0, 1, 0, cbbias]
+ * [ 0, 0, 1, crbias]
+ * [ 0, 0, 0,      1]
+ *
+ * csc
+ * [ c*cstd[ 0], c*cstd[ 1]*s*cos(h) - c*cstd[ 2]*s*sin(h), c*cstd[ 2]*s*cos(h) + c*cstd[ 1]*s*sin(h), cstd[ 3] + cstd[ 0]*(b + c*ybias) + cstd[ 1]*(c*cbbias*s*cos(h) + c*crbias*s*sin(h)) + cstd[ 2]*(c*crbias*s*cos(h) - c*cbbias*s*sin(h))]
+ * [ c*cstd[ 4], c*cstd[ 5]*s*cos(h) - c*cstd[ 6]*s*sin(h), c*cstd[ 6]*s*cos(h) + c*cstd[ 5]*s*sin(h), cstd[ 7] + cstd[ 4]*(b + c*ybias) + cstd[ 5]*(c*cbbias*s*cos(h) + c*crbias*s*sin(h)) + cstd[ 6]*(c*crbias*s*cos(h) - c*cbbias*s*sin(h))]
+ * [ c*cstd[ 8], c*cstd[ 9]*s*cos(h) - c*cstd[10]*s*sin(h), c*cstd[10]*s*cos(h) + c*cstd[ 9]*s*sin(h), cstd[11] + cstd[ 8]*(b + c*ybias) + cstd[ 9]*(c*cbbias*s*cos(h) + c*crbias*s*sin(h)) + cstd[10]*(c*crbias*s*cos(h) - c*cbbias*s*sin(h))]
+ * [ c*cstd[12], c*cstd[13]*s*cos(h) - c*cstd[14]*s*sin(h), c*cstd[14]*s*cos(h) + c*cstd[13]*s*sin(h), cstd[15] + cstd[12]*(b + c*ybias) + cstd[13]*(c*cbbias*s*cos(h) + c*crbias*s*sin(h)) + cstd[14]*(c*crbias*s*cos(h) - c*cbbias*s*sin(h))]
+ */
+
+/*
+ * Converts ITU-R BT.601 YCbCr pixels to RGB pixels where:
+ * Y is in [16,235], Cb and Cr are in [16,240]
+ * R, G, and B are in [16,235]
+ */
+static const float bt_601[16] =
+{
+   1.0f,  0.0f,    1.371f, 0.0f,
+   1.0f, -0.336f, -0.698f, 0.0f,
+   1.0f,  1.732f,  0.0f,   0.0f,
+   0.0f,  0.0f,    0.0f,   1.0f
+};
+
+/*
+ * Converts ITU-R BT.601 YCbCr pixels to RGB pixels where:
+ * Y is in [16,235], Cb and Cr are in [16,240]
+ * R, G, and B are in [0,255]
+ */
+static const float bt_601_full[16] =
+{
+   1.164f,  0.0f,    1.596f, 0.0f,
+   1.164f, -0.391f, -0.813f, 0.0f,
+   1.164f,  2.018f,  0.0f,   0.0f,
+   0.0f,    0.0f,    0.0f,   1.0f
+};
+
+/*
+ * Converts ITU-R BT.709 YCbCr pixels to RGB pixels where:
+ * Y is in [16,235], Cb and Cr are in [16,240]
+ * R, G, and B are in [16,235]
+ */
+static const float bt_709[16] =
+{
+   1.0f,  0.0f,    1.540f, 0.0f,
+   1.0f, -0.183f, -0.459f, 0.0f,
+   1.0f,  1.816f,  0.0f,   0.0f,
+   0.0f,  0.0f,    0.0f,   1.0f
+};
+
+/*
+ * Converts ITU-R BT.709 YCbCr pixels to RGB pixels where:
+ * Y is in [16,235], Cb and Cr are in [16,240]
+ * R, G, and B are in [0,255]
+ */
+static const float bt_709_full[16] =
+{
+   1.164f,  0.0f,    1.793f, 0.0f,
+   1.164f, -0.213f, -0.534f, 0.0f,
+   1.164f,  2.115f,  0.0f,   0.0f,
+   0.0f,    0.0f,    0.0f,   1.0f
+};
+
+static const float identity[16] =
+{
+   1.0f, 0.0f, 0.0f, 0.0f,
+   0.0f, 1.0f, 0.0f, 0.0f,
+   0.0f, 0.0f, 1.0f, 0.0f,
+   0.0f, 0.0f, 0.0f, 1.0f
+};
+
+void vl_csc_get_matrix(enum VL_CSC_COLOR_STANDARD cs,
+                       struct vl_procamp *procamp,
+                       bool full_range,
+                       float *matrix)
+{
+   float ybias = full_range ? -16.0f/255.0f : 0.0f;
+   float cbbias = -128.0f/255.0f;
+   float crbias = -128.0f/255.0f;
+   float c = procamp ? procamp->contrast : 1.0f;
+   float s = procamp ? procamp->saturation : 1.0f;
+   float b = procamp ? procamp->brightness : 0.0f;
+   float h = procamp ? procamp->hue : 0.0f;
+   const float *cstd;
+
+   assert(matrix);
+
+   switch (cs) {
+      case VL_CSC_COLOR_STANDARD_BT_601:
+         cstd = full_range ? &bt_601_full[0] : &bt_601[0];
+         break;
+      case VL_CSC_COLOR_STANDARD_BT_709:
+         cstd = full_range ? &bt_709_full[0] : &bt_709[0];
+         break;
+      case VL_CSC_COLOR_STANDARD_IDENTITY:
+      default:
+         assert(cs == VL_CSC_COLOR_STANDARD_IDENTITY);
+         memcpy(matrix, &identity[0], sizeof(float) * 16);
+         return;
+   }
+
+   matrix[ 0] = c*cstd[ 0];
+   matrix[ 1] = c*cstd[ 1]*s*cosf(h) - c*cstd[ 2]*s*sinf(h);
+   matrix[ 2] = c*cstd[ 2]*s*cosf(h) + c*cstd[ 1]*s*sinf(h);
+   matrix[ 3] = cstd[ 3] + cstd[ 0]*(b + c*ybias) + cstd[ 1]*(c*cbbias*s*cosf(h) + c*crbias*s*sinf(h)) + cstd[ 2]*(c*crbias*s*cosf(h) - c*cbbias*s*sinf(h));
+
+   matrix[ 4] = c*cstd[ 4];
+   matrix[ 5] = c*cstd[ 5]*s*cosf(h) - c*cstd[ 6]*s*sinf(h);
+   matrix[ 6] = c*cstd[ 6]*s*cosf(h) + c*cstd[ 5]*s*sinf(h);
+   matrix[ 7] = cstd[ 7] + cstd[ 4]*(b + c*ybias) + cstd[ 5]*(c*cbbias*s*cosf(h) + c*crbias*s*sinf(h)) + cstd[ 6]*(c*crbias*s*cosf(h) - c*cbbias*s*sinf(h));
+
+   matrix[ 8] = c*cstd[ 8];
+   matrix[ 9] = c*cstd[ 9]*s*cosf(h) - c*cstd[10]*s*sinf(h);
+   matrix[10] = c*cstd[10]*s*cosf(h) + c*cstd[ 9]*s*sinf(h);
+   matrix[11] = cstd[11] + cstd[ 8]*(b + c*ybias) + cstd[ 9]*(c*cbbias*s*cosf(h) + c*crbias*s*sinf(h)) + cstd[10]*(c*crbias*s*cosf(h) - c*cbbias*s*sinf(h));
+
+   matrix[12] = c*cstd[12];
+   matrix[13] = c*cstd[13]*s*cos(h) - c*cstd[14]*s*sin(h);
+   matrix[14] = c*cstd[14]*s*cos(h) + c*cstd[13]*s*sin(h);
+   matrix[15] = cstd[15] + cstd[12]*(b + c*ybias) + cstd[13]*(c*cbbias*s*cos(h) + c*crbias*s*sin(h)) + cstd[14]*(c*crbias*s*cos(h) - c*cbbias*s*sin(h));
+}
diff --git a/src/gallium/auxiliary/vl/vl_csc.h b/src/gallium/auxiliary/vl/vl_csc.h
new file mode 100644 (file)
index 0000000..c3b87d2
--- /dev/null
@@ -0,0 +1,26 @@
+#ifndef vl_csc_h
+#define vl_csc_h
+
+#include <pipe/p_compiler.h>
+
+struct vl_procamp
+{
+   float brightness;
+   float contrast;
+   float saturation;
+   float hue;
+};
+
+enum VL_CSC_COLOR_STANDARD
+{
+   VL_CSC_COLOR_STANDARD_IDENTITY,
+   VL_CSC_COLOR_STANDARD_BT_601,
+   VL_CSC_COLOR_STANDARD_BT_709
+};
+
+void vl_csc_get_matrix(enum VL_CSC_COLOR_STANDARD cs,
+                       struct vl_procamp *procamp,
+                       bool full_range,
+                       float *matrix);
+
+#endif /* vl_csc_h */
index 7e9136d8e09fd96503820a12a1409b06cfa05cc1..00b4b7d5606f35ba5ed6bf95eb00a6a3baa36994 100644 (file)
@@ -109,6 +109,15 @@ sp_mpeg12_set_decode_target(struct pipe_video_context *vpipe,
    pipe_video_surface_reference(&ctx->decode_target, dt);
 }
 
+static void sp_mpeg12_set_csc_matrix(struct pipe_video_context *vpipe, const float *mat)
+{
+   struct sp_mpeg12_context *ctx = (struct sp_mpeg12_context*)vpipe;
+
+   assert(vpipe);
+
+   vl_compositor_set_csc_matrix(&ctx->compositor, mat);
+}
+
 static bool
 init_pipe_state(struct sp_mpeg12_context *ctx)
 {
@@ -211,6 +220,7 @@ sp_mpeg12_create(struct pipe_screen *screen, enum pipe_video_profile profile,
    ctx->base.clear_surface = sp_mpeg12_clear_surface;
    ctx->base.render_picture = sp_mpeg12_render_picture;
    ctx->base.set_decode_target = sp_mpeg12_set_decode_target;
+   ctx->base.set_csc_matrix = sp_mpeg12_set_csc_matrix;
 
    ctx->pipe = softpipe_create(screen);
    if (!ctx->pipe) {
index 937705ac50554fd7cc8b098e82013cc7e99e8c24..4d125fa4d597cdb3cfe6dc179ae330eb92a95487 100644 (file)
@@ -80,7 +80,9 @@ struct pipe_video_context
    void (*set_decode_target)(struct pipe_video_context *vpipe,
                              struct pipe_video_surface *dt);
 
-   /* TODO: Interface for CSC matrix, scaling modes, post-processing, etc. */
+   void (*set_csc_matrix)(struct pipe_video_context *vpipe, const float *mat);
+
+   /* TODO: Interface for scaling modes, post-processing, etc. */
    /*@}*/
 };