[MPlayer-dev-eng] [PATCH] ATI GPU YUV conversion

Reimar Döffinger Reimar.Doeffinger at stud.uni-karlsruhe.de
Thu Sep 29 18:30:15 CEST 2005


Hi,
the attached patch adds a new method for the hardware YUV->RGB conversion in
vo_gl and vo_gl2 (yuv=5 suboption) that should work for older ATI cards
as well. Please test if you have such hardware, since I don't.

Greetings,
Reimar Döffinger
-------------- next part --------------
Index: libvo/gl_common.c
===================================================================
RCS file: /cvsroot/mplayer/main/libvo/gl_common.c,v
retrieving revision 1.29
diff -u -r1.29 gl_common.c
--- libvo/gl_common.c	25 Sep 2005 16:41:28 -0000	1.29
+++ libvo/gl_common.c	27 Sep 2005 08:38:28 -0000
@@ -35,6 +35,15 @@
 void (APIENTRY *CombinerOutput)(GLenum, GLenum, GLenum, GLenum, GLenum,
                                 GLenum, GLenum, GLboolean, GLboolean,
                                 GLboolean);
+void (APIENTRY *BeginFragmentShader)(void);
+void (APIENTRY *EndFragmentShader)(void);
+void (APIENTRY *SampleMap)(GLuint, GLuint, GLenum);
+void (APIENTRY *ColorFragmentOp2)(GLenum, GLuint, GLuint, GLuint, GLuint,
+                                  GLuint, GLuint, GLuint, GLuint, GLuint);
+void (APIENTRY *ColorFragmentOp3)(GLenum, GLuint, GLuint, GLuint, GLuint,
+                                  GLuint, GLuint, GLuint, GLuint, GLuint,
+                                  GLuint, GLuint, GLuint);
+void (APIENTRY *SetFragmentShaderConstant)(GLuint, const GLfloat *);
 void (APIENTRY *ActiveTexture)(GLenum);
 void (APIENTRY *BindTexture)(GLenum, GLuint);
 void (APIENTRY *MultiTexCoord2f)(GLenum, GLfloat, GLfloat);
@@ -274,6 +283,12 @@
   CombinerOutput = getProcAddress("glCombinerOutput");
   if (!CombinerOutput)
     CombinerOutput = getProcAddress("glCombinerOutputNV");
+  BeginFragmentShader = getProcAddress("glBeginFragmentShaderATI");
+  EndFragmentShader = getProcAddress("glEndFragmentShaderATI");
+  SampleMap = getProcAddress("glSampleMapATI");
+  ColorFragmentOp2 = getProcAddress("glColorFragmentOp2ATI");
+  ColorFragmentOp3 = getProcAddress("glColorFragmentOp3ATI");
+  SetFragmentShaderConstant = getProcAddress("glSetFragmentShaderConstantATI");
   ActiveTexture = getProcAddress("glActiveTexture");
   if (!ActiveTexture)
     ActiveTexture = getProcAddress("glActiveTextureARB");
@@ -480,6 +495,28 @@
     glTexSubImage2D(target, 0, x, y, w, y_max - y, format, type, data);
 }
 
+static void fillUVcoeff(GLfloat *ucoef, GLfloat *vcoef,
+                        float uvcos, float uvsin) {
+  int i;
+  ucoef[0] = 0 * uvcos + 1.403 * uvsin;
+  vcoef[0] = 0 * uvsin + 1.403 * uvcos;
+  ucoef[1] = -0.344 * uvcos + -0.714 * uvsin;
+  vcoef[1] = -0.344 * uvsin + -0.714 * uvcos;
+  ucoef[2] = 1.770 * uvcos + 0 * uvsin;
+  vcoef[2] = 1.770 * uvsin + 0 * uvcos;
+  ucoef[3] = 0;
+  vcoef[3] = 0;
+  // Coefficients (probably) must be in [0, 1] range, whereas they originally
+  // are in [-2, 2] range, so here comes the trick:
+  // First put them in the [-0.5, 0.5] range, then add 0.5.
+  // This can be undone with the HALF_BIAS and SCALE_BY_FOUR arguments
+  // for CombinerInput and CombinerOutput (or the respective ATI variants)
+  for (i = 0; i < 4; i++) {
+    ucoef[i] = ucoef[i] * 0.25 + 0.5;
+    vcoef[i] = vcoef[i] * 0.25 + 0.5;
+  }
+}
+
 /**
  * \brief Setup register combiners for YUV to RGB conversion.
  * \param uvcos used for saturation and hue adjustment
@@ -502,23 +539,7 @@
     mp_msg(MSGT_VO, MSGL_FATAL, "[gl] Combiner functions missing!\n");
     return;
   }
-  ucoef[0] = 0 * uvcos + 1.403 * uvsin;
-  vcoef[0] = 0 * uvsin + 1.403 * uvcos;
-  ucoef[1] = -0.344 * uvcos + -0.714 * uvsin;
-  vcoef[1] = -0.344 * uvsin + -0.714 * uvcos;
-  ucoef[2] = 1.770 * uvcos + 0 * uvsin;
-  vcoef[2] = 1.770 * uvsin + 0 * uvcos;
-  ucoef[3] = 0;
-  vcoef[3] = 0;
-  // Coefficients (probably) must be in [0, 1] range, whereas they originally
-  // are in [-2, 2] range, so here comes the trick:
-  // First put them in the [-0.5, 0.5] range, then add 0.5.
-  // This can be undone with the HALF_BIAS and SCALE_BY_FOUR arguments
-  // for CombinerInput and CombinerOutput
-  for (i = 0; i < 4; i++) {
-    ucoef[i] = ucoef[i] * 0.25 + 0.5;
-    vcoef[i] = vcoef[i] * 0.25 + 0.5;
-  }
+  fillUVcoeff(ucoef, vcoef, uvcos, uvsin);
   CombinerParameterfv(GL_CONSTANT_COLOR0_NV, ucoef);
   CombinerParameterfv(GL_CONSTANT_COLOR1_NV, vcoef);
 
@@ -552,6 +573,52 @@
   CombinerParameteri(GL_NUM_GENERAL_COMBINERS_NV, 2);
 }
 
+/**
+ * \brief Setup ATI version of register combiners for YUV to RGB conversion.
+ * \param uvcos used for saturation and hue adjustment
+ * \param uvsin used for saturation and hue adjustment
+ *
+ * ATI called this fragment shader, but the name is confusing in the
+ * light of a very different OpenGL 2.0 extension with the same name
+ */
+static void glSetupYUVCombinersATI(float uvcos, float uvsin) {
+  GLfloat ucoef[4];
+  GLfloat vcoef[4];
+  GLint i;
+  glGetIntegerv(GL_NUM_FRAGMENT_REGISTERS_ATI, &i);
+  if (i < 3)
+    mp_msg(MSGT_VO, MSGL_ERR,
+           "[gl] 3 registers needed for YUV combiner (ATI) support (found %i)\n", i);
+  glGetIntegerv (GL_MAX_TEXTURE_UNITS, &i);
+  if (i < 3)
+    mp_msg(MSGT_VO, MSGL_ERR,
+           "[gl] 3 texture units needed for YUV combiner (ATI) support (found %i)\n", i);
+  if (!BeginFragmentShader || !EndFragmentShader ||
+      !SetFragmentShaderConstant || !SampleMap ||
+      !ColorFragmentOp2 || !ColorFragmentOp3) {
+    mp_msg(MSGT_VO, MSGL_FATAL, "[gl] Combiner (ATI) functions missing!\n");
+    return;
+  }
+  fillUVcoeff(ucoef, vcoef, uvcos, uvsin);
+  BeginFragmentShader();
+  SetFragmentShaderConstant(GL_CON_0_ATI, ucoef);
+  SetFragmentShaderConstant(GL_CON_1_ATI, vcoef);
+  SampleMap(GL_REG_0_ATI, GL_TEXTURE0, GL_SWIZZLE_STR_ATI);
+  SampleMap(GL_REG_1_ATI, GL_TEXTURE1, GL_SWIZZLE_STR_ATI);
+  SampleMap(GL_REG_2_ATI, GL_TEXTURE2, GL_SWIZZLE_STR_ATI);
+  // UV first, like this green component cannot overflow
+  ColorFragmentOp2(GL_MUL_ATI, GL_REG_1_ATI, GL_NONE, GL_NONE,
+                   GL_REG_1_ATI, GL_NONE, GL_BIAS_BIT_ATI,
+                   GL_CON_0_ATI, GL_NONE, GL_BIAS_BIT_ATI);
+  ColorFragmentOp3(GL_MAD_ATI, GL_REG_2_ATI, GL_NONE, GL_4X_BIT_ATI,
+                   GL_REG_2_ATI, GL_NONE, GL_BIAS_BIT_ATI,
+                   GL_CON_1_ATI, GL_NONE, GL_BIAS_BIT_ATI,
+                   GL_REG_1_ATI, GL_NONE, GL_NONE);
+  ColorFragmentOp2(GL_ADD_ATI, GL_REG_0_ATI, GL_NONE, GL_NONE,
+                   GL_REG_0_ATI, GL_NONE, GL_NONE,
+                   GL_REG_2_ATI, GL_NONE, GL_NONE);
+  EndFragmentShader();
+}
 static const char *yuv_prog_template =
   "!!ARBfp1.0\n"
   "OPTION ARB_precision_hint_fastest;"
@@ -713,6 +780,9 @@
     case YUV_CONVERSION_COMBINERS:
       glSetupYUVCombiners(uvcos, uvsin);
       break;
+    case YUV_CONVERSION_COMBINERS_ATI:
+      glSetupYUVCombinersATI(uvcos, uvsin);
+      break;
     case YUV_CONVERSION_FRAGMENT_LOOKUP:
       {
         unsigned char lookup_data[4 * LOOKUP_RES];
@@ -752,6 +822,14 @@
       ActiveTexture(GL_TEXTURE0);
       glEnable(GL_REGISTER_COMBINERS_NV);
       break;
+    case YUV_CONVERSION_COMBINERS_ATI:
+      ActiveTexture(GL_TEXTURE1);
+      glEnable(target);
+      ActiveTexture(GL_TEXTURE2);
+      glEnable(target);
+      ActiveTexture(GL_TEXTURE0);
+      glEnable(GL_FRAGMENT_SHADER_ATI);
+      break;
     case YUV_CONVERSION_FRAGMENT_LOOKUP:
     case YUV_CONVERSION_FRAGMENT_POW:
     case YUV_CONVERSION_FRAGMENT:
@@ -777,6 +855,14 @@
       ActiveTexture(GL_TEXTURE0);
       glDisable(GL_REGISTER_COMBINERS_NV);
       break;
+    case YUV_CONVERSION_COMBINERS_ATI:
+      ActiveTexture(GL_TEXTURE1);
+      glDisable(target);
+      ActiveTexture(GL_TEXTURE2);
+      glDisable(target);
+      ActiveTexture(GL_TEXTURE0);
+      glDisable(GL_FRAGMENT_SHADER_ATI);
+      break;
     case YUV_CONVERSION_FRAGMENT_LOOKUP:
     case YUV_CONVERSION_FRAGMENT_POW:
     case YUV_CONVERSION_FRAGMENT:
Index: libvo/gl_common.h
===================================================================
RCS file: /cvsroot/mplayer/main/libvo/gl_common.h,v
retrieving revision 1.20
diff -u -r1.20 gl_common.h
--- libvo/gl_common.h	27 Sep 2005 08:33:33 -0000	1.20
+++ libvo/gl_common.h	27 Sep 2005 08:38:28 -0000
@@ -76,6 +76,45 @@
 #ifndef GL_SPARE0_NV
 #define GL_SPARE0_NV 0x852E
 #endif
+#ifndef GL_FRAGMENT_SHADER_ATI
+#define GL_FRAGMENT_SHADER_ATI 0x8920
+#endif
+#ifndef GL_NUM_FRAGMENT_REGISTERS_ATI
+#define GL_NUM_FRAGMENT_REGISTERS_ATI 0x896E
+#endif
+#ifndef GL_REG_0_ATI
+#define GL_REG_0_ATI 0x8921
+#endif
+#ifndef GL_REG_1_ATI
+#define GL_REG_1_ATI 0x8922
+#endif
+#ifndef GL_REG_2_ATI
+#define GL_REG_2_ATI 0x8923
+#endif
+#ifndef GL_CON_0_ATI
+#define GL_CON_0_ATI 0x8941
+#endif
+#ifndef GL_CON_1_ATI
+#define GL_CON_1_ATI 0x8942
+#endif
+#ifndef GL_ADD_ATI
+#define GL_ADD_ATI 0x8963
+#endif
+#ifndef GL_MUL_ATI
+#define GL_MUL_ATI 0x8964
+#endif
+#ifndef GL_MAD_ATI
+#define GL_MAD_ATI 0x8968
+#endif
+#ifndef GL_SWIZZLE_STR_ATI
+#define GL_SWIZZLE_STR_ATI 0x8976
+#endif
+#ifndef GL_4X_BIT_ATI
+#define GL_4X_BIT_ATI 2
+#endif
+#ifndef GL_BIAS_BIT_ATI
+#define GL_BIAS_BIT_ATI 8
+#endif
 #ifndef GL_MAX_TEXTURE_UNITS
 #define GL_MAX_TEXTURE_UNITS 0x84E2
 #endif
@@ -171,6 +210,8 @@
 #define YUV_CONVERSION_FRAGMENT_POW 3
 //! use a fragment program with additional table lookup for YUV conversion
 #define YUV_CONVERSION_FRAGMENT_LOOKUP 4
+//! use ATI specific register combiners ("fragment program")
+#define YUV_CONVERSION_COMBINERS_ATI 5
 /** \} */
 void glSetupYUVConversion(GLenum target, int type,
                           float brightness, float contrast,
@@ -210,6 +251,15 @@
 extern void (APIENTRY *CombinerOutput)(GLenum, GLenum, GLenum, GLenum, GLenum,
                                        GLenum, GLenum, GLboolean, GLboolean,
                                        GLboolean);
+extern void (APIENTRY *BeginFragmentShader)(void);
+extern void (APIENTRY *EndFragmentShader)(void);
+extern void (APIENTRY *SampleMap)(GLuint, GLuint, GLenum);
+extern void (APIENTRY *ColorFragmentOp2)(GLenum, GLuint, GLuint, GLuint, GLuint,
+                                         GLuint, GLuint, GLuint, GLuint, GLuint);
+extern void (APIENTRY *ColorFragmentOp3)(GLenum, GLuint, GLuint, GLuint, GLuint,
+                                         GLuint, GLuint, GLuint, GLuint, GLuint,
+                                         GLuint, GLuint, GLuint);
+extern void (APIENTRY *SetFragmentShaderConstant)(GLuint, const GLfloat *);
 extern void (APIENTRY *ActiveTexture)(GLenum);
 extern void (APIENTRY *BindTexture)(GLenum, GLuint);
 extern void (APIENTRY *MultiTexCoord2f)(GLenum, GLfloat, GLfloat);


More information about the MPlayer-dev-eng mailing list