changeset 18619:106a0c366002

Reworked YUV2RGB fragment program setup in preparation for upcoming patches
author reimar
date Wed, 07 Jun 2006 13:24:54 +0000
parents 08a68a8f568f
children c51bd02b0904
files libvo/gl_common.c libvo/gl_common.h libvo/vo_gl.c libvo/vo_gl2.c
diffstat 4 files changed, 173 insertions(+), 91 deletions(-) [+]
line wrap: on
line diff
--- a/libvo/gl_common.c	Wed Jun 07 13:17:32 2006 +0000
+++ b/libvo/gl_common.c	Wed Jun 07 13:24:54 2006 +0000
@@ -607,65 +607,105 @@
   EndFragmentShader();
 }
 
+static const char *bilin_filt_template =
+  "TEX yuv.%c, fragment.texcoord[%c], texture[%c], %s;";
+
 static const char *yuv_prog_template =
-  "!!ARBfp1.0\n"
-  "OPTION ARB_precision_hint_fastest;"
+  "PARAM ycoef = {%.4f, %.4f, %.4f};"
+  "PARAM ucoef = {%.4f, %.4f, %.4f};"
+  "PARAM vcoef = {%.4f, %.4f, %.4f};"
+  "PARAM offsets = {%.4f, %.4f, %.4f};"
+  "TEMP res;"
+  "MAD res.rgb, yuv.rrrr, ycoef, offsets;"
+  "MAD res.rgb, yuv.gggg, ucoef, res;"
+  "MAD result.color.rgb, yuv.bbbb, vcoef, res;"
+  "END";
+
+static const char *yuv_pow_prog_template =
   "PARAM ycoef = {%.4f, %.4f, %.4f};"
   "PARAM ucoef = {%.4f, %.4f, %.4f};"
   "PARAM vcoef = {%.4f, %.4f, %.4f};"
   "PARAM offsets = {%.4f, %.4f, %.4f};"
   "PARAM gamma = {%.4f, %.4f, %.4f};"
-  "TEMP res, y, u, v;"
-  "TEX y, fragment.texcoord[0], texture[0], %s;"
-  "MAD res, y, ycoef, offsets;"
-  "TEX u, fragment.texcoord[1], texture[1], %s;"
-  "MAD res, u, ucoef, res;"
-  "TEX v, fragment.texcoord[2], texture[2], %s;"
-  "MAD result.color, v, vcoef, res;"
-  "END";
-
-static const char *yuv_pow_prog_template =
-  "!!ARBfp1.0\n"
-  "OPTION ARB_precision_hint_fastest;"
-  "PARAM ycoef = {%.4f, %.4f, %.4f};"
-  "PARAM ucoef = {%.4f, %.4f, %.4f};"
-  "PARAM vcoef = {%.4f, %.4f, %.4f};"
-  "PARAM offsets = {%.4f, %.4f, %.4f};"
-  "PARAM gamma = {%.4f, %.4f, %.4f};"
-  "TEMP res, y, u, v;"
-  "TEX y, fragment.texcoord[0], texture[0], %s;"
-  "MAD res, y, ycoef, offsets;"
-  "TEX u, fragment.texcoord[1], texture[1], %s;"
-  "MAD res, u, ucoef, res;"
-  "TEX v, fragment.texcoord[2], texture[2], %s;"
-  "MAD_SAT res, v, vcoef, res;"
+  "TEMP res;"
+  "MAD res.rgb, yuv.rrrr, ycoef, offsets;"
+  "MAD res.rgb, yuv.gggg, ucoef, res;"
+  "MAD_SAT res.rgb, yuv.bbbb, vcoef, res;"
   "POW result.color.r, res.r, gamma.r;"
   "POW result.color.g, res.g, gamma.g;"
   "POW result.color.b, res.b, gamma.b;"
   "END";
 
 static const char *yuv_lookup_prog_template =
-  "!!ARBfp1.0\n"
-  "OPTION ARB_precision_hint_fastest;"
   "PARAM ycoef = {%.4f, %.4f, %.4f, 0};"
   "PARAM ucoef = {%.4f, %.4f, %.4f, 0};"
   "PARAM vcoef = {%.4f, %.4f, %.4f, 0};"
   "PARAM offsets = {%.4f, %.4f, %.4f, 0.125};"
-  "PARAM gamma = {%.4f, %.4f, %.4f};"
-  "TEMP res, y, u, v;"
-  "TEX y, fragment.texcoord[0], texture[0], %s;"
-  "MAD res, y, ycoef, offsets;"
-  "TEX u, fragment.texcoord[1], texture[1], %s;"
-  "MAD res, u, ucoef, res;"
-  "TEX v, fragment.texcoord[2], texture[2], %s;"
-  "MAD res, v, vcoef, res;"
-  "TEX result.color.r, res.raaa, texture[3], 2D;"
+  "TEMP res;"
+  "MAD res, yuv.rrrr, ycoef, offsets;"
+  "MAD res.rgb, yuv.gggg, ucoef, res;"
+  "MAD res.rgb, yuv.bbbb, vcoef, res;"
+  "TEX result.color.r, res.raaa, texture[%c], 2D;"
+  "ADD res.a, res.a, 0.25;"
+  "TEX result.color.g, res.gaaa, texture[%c], 2D;"
   "ADD res.a, res.a, 0.25;"
-  "TEX result.color.g, res.gaaa, texture[3], 2D;"
-  "ADD res.a, res.a, 0.25;"
-  "TEX result.color.b, res.baaa, texture[3], 2D;"
+  "TEX result.color.b, res.baaa, texture[%c], 2D;"
   "END";
 
+static void create_scaler_textures(int scaler, int *texu, char *texs) {
+  switch (scaler) {
+    case YUV_SCALER_BILIN:
+      break;
+    default:
+      mp_msg(MSGT_VO, MSGL_ERR, "[gl] unknown scaler type %i\n", scaler);
+  }
+}
+
+static void gen_gamma_map(unsigned char *map, int size, float gamma);
+
+//! resolution of texture for gamma lookup table
+#define LOOKUP_RES 512
+static void create_conv_textures(int conv, int *texu, char *texs,
+              int brightness, int contrast, int uvcos, int uvsin,
+              int rgamma, int ggamma, int bgamma) {
+  unsigned char *lookup_data = NULL;
+  switch (conv) {
+    case YUV_CONVERSION_FRAGMENT:
+    case YUV_CONVERSION_FRAGMENT_POW:
+     break;
+    case YUV_CONVERSION_FRAGMENT_LOOKUP:
+      texs[0] = (*texu)++;
+      ActiveTexture(GL_TEXTURE0 + texs[0]);
+      lookup_data = malloc(4 * LOOKUP_RES);
+      gen_gamma_map(lookup_data, LOOKUP_RES, rgamma);
+      gen_gamma_map(&lookup_data[LOOKUP_RES], LOOKUP_RES, ggamma);
+      gen_gamma_map(&lookup_data[2 * LOOKUP_RES], LOOKUP_RES, bgamma);
+      glCreateClearTex(GL_TEXTURE_2D, GL_LUMINANCE8, GL_LINEAR,
+                       LOOKUP_RES, 4, 0);
+      glUploadTex(GL_TEXTURE_2D, GL_LUMINANCE, GL_UNSIGNED_BYTE, lookup_data,
+                  LOOKUP_RES, 0, 0, LOOKUP_RES, 4, 0);
+      ActiveTexture(GL_TEXTURE0);
+      texs[0] += '0';
+      break;
+    default:
+      mp_msg(MSGT_VO, MSGL_ERR, "[gl] unknown conversion type %i\n", conv);
+  }
+  if (lookup_data)
+    free(lookup_data);
+}
+
+static void add_scaler(int scaler, char **prog_pos, int *remain, char *texs,
+                    char in_tex, char out_comp, int rect, int texw, int texh) {
+  switch (scaler) {
+    case YUV_SCALER_BILIN:
+      snprintf(*prog_pos, *remain, bilin_filt_template, out_comp, in_tex,
+                 in_tex, rect ? "RECT" : "2D");
+      break;
+  }
+  *remain -= strlen(*prog_pos);
+  *prog_pos += strlen(*prog_pos);
+}
+
 /**
  * \brief setup a fragment program that will do YUV->RGB conversion
  * \param brightness brightness adjustment offset
@@ -677,37 +717,48 @@
  */
 static void glSetupYUVFragprog(float brightness, float contrast,
                         float uvcos, float uvsin, float rgamma,
-                        float ggamma, float bgamma, int type, int rect) {
-  char yuv_prog[1000];
-  const char *prog_template = yuv_prog_template;
-  char *tex_type = rect ? "RECT" : "2D";
-  int lookup = 0;
+                        float ggamma, float bgamma, int type, int rect,
+                        int texw, int texh) {
+  char yuv_prog[4000] =
+    "!!ARBfp1.0\n"
+    "OPTION ARB_precision_hint_fastest;"
+    // all scaler variables must go here so they aren't defined
+    // multiple times when the same scaler is used more than once
+    "TEMP yuv;";
+  int prog_remain = sizeof(yuv_prog) - strlen(yuv_prog);
+  char *prog_pos = &yuv_prog[strlen(yuv_prog)];
+  int cur_texu = 3;
+  char lum_scale_texs[1];
+  char chrom_scale_texs[1];
+  char conv_texs[1];
   GLint i;
   // this is the conversion matrix, with y, u, v factors
   // for red, green, blue and the constant offsets
   float ry, ru, rv, rc;
   float gy, gu, gv, gc;
   float by, bu, bv, bc;
-  switch (type) {
-    case YUV_CONVERSION_FRAGMENT_POW:
-      prog_template = yuv_pow_prog_template;
-      break;
-    case YUV_CONVERSION_FRAGMENT_LOOKUP:
-      prog_template = yuv_lookup_prog_template;
-      lookup = 1;
-      break;
-  }
-  glGetIntegerv (GL_MAX_TEXTURE_UNITS, &i);
-  if (i < 3)
+  create_scaler_textures(YUV_LUM_SCALER(type), &cur_texu, lum_scale_texs);
+  if (YUV_CHROM_SCALER(type) == YUV_LUM_SCALER(type))
+    memcpy(chrom_scale_texs, lum_scale_texs, sizeof(chrom_scale_texs));
+  else
+    create_scaler_textures(YUV_CHROM_SCALER(type), &cur_texu, chrom_scale_texs);
+  create_conv_textures(YUV_CONVERSION(type), &cur_texu, conv_texs,
+      brightness, contrast, uvcos, uvsin, rgamma, ggamma, bgamma);
+  glGetIntegerv(GL_MAX_TEXTURE_UNITS, &i);
+  if (i < cur_texu)
     mp_msg(MSGT_VO, MSGL_ERR,
-           "[gl] 3 texture units needed for YUV fragment support (found %i)\n", i);
-  if (lookup && i < 4)
-    mp_msg(MSGT_VO, MSGL_ERR,
-           "[gl] 4 texture units needed for YUV fragment support with lookup (found %i)\n", i);
+           "[gl] %i texture units needed for this type of YUV fragment support (found %i)\n",
+           cur_texu, i);
   if (!ProgramString) {
     mp_msg(MSGT_VO, MSGL_FATAL, "[gl] ProgramString function missing!\n");
     return;
   }
+  add_scaler(YUV_LUM_SCALER(type), &prog_pos, &prog_remain, lum_scale_texs,
+             '0', 'r', rect, texw, texh);
+  add_scaler(YUV_CHROM_SCALER(type), &prog_pos, &prog_remain, chrom_scale_texs,
+             '1', 'g', rect, texw / 2, texh / 2);
+  add_scaler(YUV_CHROM_SCALER(type), &prog_pos, &prog_remain, chrom_scale_texs,
+             '2', 'b', rect, texw / 2, texh / 2);
   ry = 1.164 * contrast;
   gy = 1.164 * contrast;
   by = 1.164 * contrast;
@@ -725,11 +776,26 @@
   rc += 0.5 - contrast / 2.0;
   gc += 0.5 - contrast / 2.0;
   bc += 0.5 - contrast / 2.0;
-  rgamma = 1.0 / rgamma;
-  ggamma = 1.0 / ggamma;
-  bgamma = 1.0 / bgamma;
-  snprintf(yuv_prog, 1000, prog_template, ry, gy, by, ru, gu, bu, rv, gv, bv,
-           rc, gc, bc, rgamma, bgamma, bgamma, tex_type, tex_type, tex_type);
+  switch (YUV_CONVERSION(type)) {
+    case YUV_CONVERSION_FRAGMENT:
+      snprintf(prog_pos, prog_remain, yuv_prog_template,
+               ry, gy, by, ru, gu, bu, rv, gv, bv, rc, gc, bc);
+      break;
+    case YUV_CONVERSION_FRAGMENT_POW:
+      snprintf(prog_pos, prog_remain, yuv_pow_prog_template,
+               ry, gy, by, ru, gu, bu, rv, gv, bv, rc, gc, bc,
+               (float)1.0 / rgamma, (float)1.0 / bgamma, (float)1.0 / bgamma);
+      break;
+    case YUV_CONVERSION_FRAGMENT_LOOKUP:
+      snprintf(prog_pos, prog_remain, yuv_lookup_prog_template,
+               ry, gy, by, ru, gu, bu, rv, gv, bv, rc, gc, bc,
+               conv_texs[0], conv_texs[0], conv_texs[0]);
+      break;
+    default:
+      mp_msg(MSGT_VO, MSGL_ERR, "[gl] unknown conversion type %i\n", YUV_CONVERSION(type));
+      break;
+  }
+  mp_msg(MSGT_VO, MSGL_V, "[gl] generated fragment program:\n%s\n", yuv_prog);
   ProgramString(GL_FRAGMENT_PROGRAM, GL_PROGRAM_FORMAT_ASCII,
                 strlen(yuv_prog), yuv_prog);
   glGetIntegerv(GL_PROGRAM_ERROR_POSITION, &i);
@@ -757,9 +823,6 @@
   }
 }
 
-//! resolution of texture for gamma lookup table
-#define LOOKUP_RES 512
-
 /**
  * \brief setup YUV->RGB conversion
  * \param target texture target for Y, U and V textures (e.g. GL_TEXTURE_2D)
@@ -776,10 +839,11 @@
 void glSetupYUVConversion(GLenum target, int type,
                           float brightness, float contrast,
                           float hue, float saturation,
-                          float rgamma, float ggamma, float bgamma) {
+                          float rgamma, float ggamma, float bgamma,
+                          int texw, int texh) {
   float uvcos = saturation * cos(hue);
   float uvsin = saturation * sin(hue);
-  switch (type) {
+  switch (YUV_CONVERSION(type)) {
     case YUV_CONVERSION_COMBINERS:
       glSetupYUVCombiners(uvcos, uvsin);
       break;
@@ -787,24 +851,15 @@
       glSetupYUVCombinersATI(uvcos, uvsin);
       break;
     case YUV_CONVERSION_FRAGMENT_LOOKUP:
-      {
-        unsigned char lookup_data[4 * LOOKUP_RES];
-        gen_gamma_map(lookup_data, LOOKUP_RES, rgamma);
-        gen_gamma_map(&lookup_data[LOOKUP_RES], LOOKUP_RES, ggamma);
-        gen_gamma_map(&lookup_data[2 * LOOKUP_RES], LOOKUP_RES, bgamma);
-        ActiveTexture(GL_TEXTURE3);
-        glCreateClearTex(GL_TEXTURE_2D, GL_LUMINANCE8, GL_LINEAR,
-                         LOOKUP_RES, 4, 0);
-        glUploadTex(GL_TEXTURE_2D, GL_LUMINANCE, GL_UNSIGNED_BYTE, lookup_data,
-                    LOOKUP_RES, 0, 0, LOOKUP_RES, 4, 0);
-        ActiveTexture(GL_TEXTURE0);
-      }
     case YUV_CONVERSION_FRAGMENT:
     case YUV_CONVERSION_FRAGMENT_POW:
       glSetupYUVFragprog(brightness, contrast, uvcos, uvsin,
                          rgamma, ggamma, bgamma, type,
-                         target == GL_TEXTURE_RECTANGLE);
+                         target == GL_TEXTURE_RECTANGLE,
+                         texw, texh);
       break;
+    default:
+      mp_msg(MSGT_VO, MSGL_ERR, "[gl] unknown conversion type %i\n", YUV_CONVERSION(type));
   }
 }
 
@@ -816,7 +871,7 @@
  */
 void glEnableYUVConversion(GLenum target, int type) {
   if (type <= 0) return;
-  switch (type) {
+  switch (YUV_CONVERSION(type)) {
     case YUV_CONVERSION_COMBINERS:
       ActiveTexture(GL_TEXTURE1);
       glEnable(target);
@@ -849,7 +904,7 @@
  */
 void glDisableYUVConversion(GLenum target, int type) {
   if (type <= 0) return;
-  switch (type) {
+  switch (YUV_CONVERSION(type)) {
     case YUV_CONVERSION_COMBINERS:
       ActiveTexture(GL_TEXTURE1);
       glDisable(target);
--- a/libvo/gl_common.h	Wed Jun 07 13:17:32 2006 +0000
+++ b/libvo/gl_common.h	Wed Jun 07 13:24:54 2006 +0000
@@ -223,11 +223,28 @@
 #define YUV_CONVERSION_FRAGMENT_LOOKUP 4
 //! use ATI specific register combiners ("fragment program")
 #define YUV_CONVERSION_COMBINERS_ATI 5
+//! use normal bilinear scaling for textures
+#define YUV_SCALER_BILIN 0
+//! mask for conversion type
+#define YUV_CONVERSION_MASK 0xF
+//! mask for scaler type
+#define YUV_SCALER_MASK 0xF
+//! shift value for luminance scaler type
+#define YUV_LUM_SCALER_SHIFT 8
+//! shift value for chrominance scaler type
+#define YUV_CHROM_SCALER_SHIFT 12
+//! extract conversion out of type
+#define YUV_CONVERSION(t) (t & YUV_CONVERSION_MASK)
+//! extract luminance scaler out of type
+#define YUV_LUM_SCALER(t) ((t >> YUV_LUM_SCALER_SHIFT) & YUV_SCALER_MASK)
+//! extract chrominance scaler out of type
+#define YUV_CHROM_SCALER(t) ((t >> YUV_CHROM_SCALER_SHIFT) & YUV_SCALER_MASK)
 /** \} */
 void glSetupYUVConversion(GLenum target, int type,
                           float brightness, float contrast,
                           float hue, float saturation,
-                          float rgamma, float ggamma, float bgamma);
+                          float rgamma, float ggamma, float bgamma,
+                          int texw, int texh);
 void glEnableYUVConversion(GLenum target, int type);
 void glDisableYUVConversion(GLenum target, int type);
 
--- a/libvo/vo_gl.c	Wed Jun 07 13:17:32 2006 +0000
+++ b/libvo/vo_gl.c	Wed Jun 07 13:24:54 2006 +0000
@@ -59,6 +59,9 @@
 
 static int use_aspect;
 static int use_yuv;
+static int lscale;
+static int cscale;
+static int yuvconvtype;
 static int use_rectangle;
 static int err_shown;
 static uint32_t image_width;
@@ -156,8 +159,9 @@
   float rgamma = exp(log(8.0) * eq_rgamma / 100.0);
   float ggamma = exp(log(8.0) * eq_ggamma / 100.0);
   float bgamma = exp(log(8.0) * eq_bgamma / 100.0);
-  glSetupYUVConversion(gl_target, use_yuv, bri, cont, hue, sat,
-                       rgamma, ggamma, bgamma);
+  glSetupYUVConversion(gl_target, yuvconvtype, bri, cont, hue, sat,
+                       rgamma, ggamma, bgamma,
+                       texture_width, texture_height);
   if (custom_prog) {
     FILE *f = fopen(custom_prog, "r");
     if (!f)
@@ -511,13 +515,13 @@
 
   glColor3f(1,1,1);
   if (image_format == IMGFMT_YV12)
-    glEnableYUVConversion(gl_target, use_yuv);
+    glEnableYUVConversion(gl_target, yuvconvtype);
   glDrawTex(0, 0, image_width, image_height,
             0, 0, image_width, image_height,
             texture_width, texture_height,
             use_rectangle == 1, image_format == IMGFMT_YV12, mpi_flipped);
   if (image_format == IMGFMT_YV12)
-    glDisableYUVConversion(gl_target, use_yuv);
+    glDisableYUVConversion(gl_target, yuvconvtype);
 
   if (osdtexCnt > 0) {
     // set special rendering parameters
@@ -685,6 +689,8 @@
   {"slice-height", OPT_ARG_INT,  &slice_height, (opt_test_f)int_non_neg},
   {"rectangle",    OPT_ARG_INT,  &use_rectangle,(opt_test_f)int_non_neg},
   {"yuv",          OPT_ARG_INT,  &use_yuv,      (opt_test_f)int_non_neg},
+  {"lscale",       OPT_ARG_INT,  &lscale,       (opt_test_f)int_non_neg},
+  {"cscale",       OPT_ARG_INT,  &cscale,       (opt_test_f)int_non_neg},
   {"glfinish",     OPT_ARG_BOOL, &use_glFinish, NULL},
   {"swapinterval", OPT_ARG_INT,  &swap_interval,NULL},
   {"customprog",   OPT_ARG_MSTRZ,&custom_prog,  NULL},
@@ -702,6 +708,8 @@
     scaled_osd = 0;
     use_aspect = 1;
     use_yuv = 0;
+    lscale = 0;
+    cscale = 0;
     use_rectangle = 0;
     use_glFinish = 0;
     swap_interval = 1;
@@ -757,6 +765,7 @@
       gl_target = GL_TEXTURE_2D;
     if (slice_height == -1)
       slice_height = use_yuv ? 16 : 4;
+    yuvconvtype = use_yuv | lscale << YUV_LUM_SCALER_SHIFT | cscale << YUV_CHROM_SCALER_SHIFT;
     if (many_fmts)
       mp_msg (MSGT_VO, MSGL_INFO, "[gl] using extended formats. "
                "Use -vo gl:nomanyfmts if playback fails.\n");
--- a/libvo/vo_gl2.c	Wed Jun 07 13:17:32 2006 +0000
+++ b/libvo/vo_gl2.c	Wed Jun 07 13:24:54 2006 +0000
@@ -773,7 +773,8 @@
         BindProgram(GL_FRAGMENT_PROGRAM, fragprog);
         break;
     }
-    glSetupYUVConversion(GL_TEXTURE_2D, use_yuv, 0.0, 1.0, 0.0, 1.0, 1.0, 1.0, 1.0);
+    glSetupYUVConversion(GL_TEXTURE_2D, use_yuv, 0.0, 1.0, 0.0, 1.0, 1.0, 1.0, 1.0,
+                         texture_width, texture_height);
   }
 
   gl_set_antialias(0);