[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