changeset 36126:fd34a83228ca

Switch OpenGL ES renderer to 2.0. 1.0 is too limited to be really useful for video, and 2.0 is almost universally available anyway. This also adds support for YUV conversion in hardware, however this code is still very rough and limited in features. A lot of work, like being able to change the coefficients, supporting gamma, supporting EOSD (ASS rendering) still needs to be done for this to be really usable. Unfortunately development is difficult since almost no working implementations are available: MESA seems currently completely broken unless you use and Intel card _and_ force software rendering, Galaxy S2 still crashes regularly (certainly in part my fault for doing something weird, but still).
author reimar
date Sat, 04 May 2013 13:28:14 +0000
parents c4075d9e329d
children 18c289284727
files libvo/gl_common.c libvo/gl_common.h libvo/gl_compat.h
diffstat 3 files changed, 190 insertions(+), 37 deletions(-) [+]
line wrap: on
line diff
--- a/libvo/gl_common.c	Sat May 04 11:15:19 2013 +0000
+++ b/libvo/gl_common.c	Sat May 04 13:28:14 2013 +0000
@@ -50,7 +50,7 @@
 void (GLAPIENTRY *mpglViewport)(GLint, GLint, GLsizei, GLsizei);
 void (GLAPIENTRY *mpglMatrixMode)(GLenum);
 void (GLAPIENTRY *mpglLoadIdentity)(void);
-void (GLAPIENTRY *mpglLoadMatrixf)(float *);
+void (GLAPIENTRY *mpglLoadMatrixf)(const float *);
 void (GLAPIENTRY *mpglClear)(GLbitfield);
 GLuint (GLAPIENTRY *mpglGenLists)(GLsizei);
 void (GLAPIENTRY *mpglDeleteLists)(GLuint, GLsizei);
@@ -145,8 +145,28 @@
 void (GLAPIENTRY *mpglClientActiveTexture)(GLenum);
 void (GLAPIENTRY *mpglEnableClientState)(GLenum);
 void (GLAPIENTRY *mpglDisableClientState)(GLenum);
+
+void (GLAPIENTRY *mpglVertexAttribPointer)(GLuint, GLint, GLenum, GLboolean, GLsizei, const void *);
+void (GLAPIENTRY *mpglEnableVertexAttribArray)(GLuint);
 void (GLAPIENTRY *mpglDrawArrays)(GLenum, GLint, GLsizei);
 
+GLuint (GLAPIENTRY *mpglCreateProgram)(void);
+GLuint (GLAPIENTRY *mpglCreateShader)(GLenum);
+void (GLAPIENTRY *mpglShaderSource)(GLuint, GLsizei, const char **, const GLint *);
+void (GLAPIENTRY *mpglCompileShader)(GLuint);
+void (GLAPIENTRY *mpglGetShaderiv)(GLuint, GLenum, GLint *);
+void (GLAPIENTRY *mpglGetShaderInfoLog)(GLuint, GLsizei, GLsizei *, char *);
+void (GLAPIENTRY *mpglAttachShader)(GLuint, GLuint);
+void (GLAPIENTRY *mpglDetachShader)(GLuint, GLuint);
+void (GLAPIENTRY *mpglDeleteShader)(GLuint);
+void (GLAPIENTRY *mpglBindAttribLocation)(GLuint, GLuint, const char *);
+void (GLAPIENTRY *mpglLinkProgram)(GLuint);
+void (GLAPIENTRY *mpglGetProgramInfoLog)(GLuint, GLsizei, GLsizei *, char *);
+void (GLAPIENTRY *mpglUseProgram)(GLuint);
+GLint (GLAPIENTRY *mpglGetUniformLocation)(GLuint, const char *);
+void (GLAPIENTRY *mpglUniform1iv)(GLint, GLsizei, const GLint *);
+void (GLAPIENTRY *mpglUniformMatrix4fv)(GLint, GLsizei, GLboolean, const float *);
+
 //! \defgroup glgeneral OpenGL general helper functions
 
 //! \defgroup glcontext OpenGL context management helper functions
@@ -158,6 +178,10 @@
 static GLint hqtexfmt;
 static int use_depth_l16;
 static GLenum l16_format;
+static GLuint gpu_def_sl_program;
+static GLuint gpu_yuv_sl_program;
+static GLuint gpu_cur_sl_program;
+static float transform_matrix[16];
 
 /**
  * \brief adjusts the GL_UNPACK_ALIGNMENT to fit the stride.
@@ -501,7 +525,29 @@
   SIMPLE_FUNC_DESC(ClientActiveTexture),
   SIMPLE_FUNC_DESC(EnableClientState),
   SIMPLE_FUNC_DESC(DisableClientState),
+
+  SIMPLE_FUNC_DESC(VertexAttribPointer),
+  SIMPLE_FUNC_DESC(EnableVertexAttribArray),
   SIMPLE_FUNC_DESC(DrawArrays),
+
+
+  SIMPLE_FUNC_DESC(CreateProgram),
+  SIMPLE_FUNC_DESC(CreateShader),
+  SIMPLE_FUNC_DESC(ShaderSource),
+  SIMPLE_FUNC_DESC(CompileShader),
+  SIMPLE_FUNC_DESC(GetShaderiv),
+  SIMPLE_FUNC_DESC(GetShaderInfoLog),
+  SIMPLE_FUNC_DESC(AttachShader),
+  SIMPLE_FUNC_DESC(DetachShader),
+  SIMPLE_FUNC_DESC(DeleteShader),
+  SIMPLE_FUNC_DESC(BindAttribLocation),
+  SIMPLE_FUNC_DESC(LinkProgram),
+  SIMPLE_FUNC_DESC(GetProgramiv),
+  SIMPLE_FUNC_DESC(GetProgramInfoLog),
+  SIMPLE_FUNC_DESC(UseProgram),
+  SIMPLE_FUNC_DESC(GetUniformLocation),
+  SIMPLE_FUNC_DESC(Uniform1iv),
+  SIMPLE_FUNC_DESC(UniformMatrix4fv),
   {NULL}
 };
 
@@ -1543,6 +1589,105 @@
   free(yuv_prog);
 }
 
+static void print_result(int link, GLuint obj) {
+  char msgtmp[500];
+  GLint status;
+  (link ? mpglGetProgramiv : mpglGetShaderiv)(obj, link ? GL_LINK_STATUS : GL_COMPILE_STATUS, &status);
+  if (!status)
+    mp_msg(MSGT_VO, MSGL_ERR, "[gl] Shader %s failed.\n", link ? "linking" : "compilation");
+  msgtmp[0] = 0;
+  (link ? mpglGetProgramInfoLog : mpglGetShaderInfoLog)(obj, sizeof(msgtmp), NULL, msgtmp);
+  mp_msg(MSGT_VO, status ? MSGL_V : MSGL_ERR, "[gl] %s messages:\n%s\n", link ? "Linker" : "Compiler", msgtmp);
+}
+
+static GLuint compile_shader(GLenum type, const char *source) {
+  GLuint shader = mpglCreateShader(type);
+  mp_msg(MSGT_VO, MSGL_DBG2, "[gl] Compiling shader:\n%s\n", source);
+  mpglShaderSource(shader, 1, &source, NULL);
+  mpglCompileShader(shader);
+  print_result(0, shader);
+  return shader;
+}
+
+static const char vertex_shader[] =
+  "uniform mat4 matrix;\n"
+  "attribute vec4 vPos;\n"
+  "attribute vec2 tca, tca2, tca3;\n"
+  "varying vec2 tcv, tcv2, tcv3;\n"
+  "void main() {\n"
+  "  gl_Position = matrix * vPos;\n"
+  "  tcv = tca; tcv2 = tca2; tcv3 = tca3;\n"
+  "}\n";
+
+static GLuint new_gpu_program(void) {
+  GLuint program = mpglCreateProgram();
+  GLuint shader = compile_shader(GL_VERTEX_SHADER, vertex_shader);
+  mpglAttachShader(program, shader);
+  mpglDeleteShader(shader);
+  return program;
+}
+
+static const char def_frag_shader[] =
+  "precision mediump float;\n"
+  "uniform sampler2D texs[4];\n"
+  "varying vec2 tcv;\n"
+  "void main() {\n"
+  "  gl_FragColor = texture2D(texs[0], tcv);\n"
+  "}\n";
+
+static const char yuv_frag_shader[] =
+  "precision mediump float;\n"
+  "uniform sampler2D texs[4];\n"
+  "varying vec2 tcv, tcv2;\n"
+  "void main() {\n"
+  "  mat4 yuv_conv = mat4(\n"
+  "     1.164000e+00,  1.164000e+00,  1.164000e+00, 0,\n"
+  "     0.000000e+00, -3.910000e-01,  2.018000e+00, 0,\n"
+  "     1.596000e+00, -8.130000e-01,  0.000000e+00, 0,\n"
+  "    -8.741648e-01,  5.313256e-01, -1.085992e+00, 1\n"
+  "  );\n"
+  "  vec4 yuv = vec4(0.0, 0.5, 0.5, 1.0);\n"
+  "  yuv.r = texture2D(texs[0], tcv).r;\n"
+  "  yuv.g = texture2D(texs[1], tcv2).r;\n"
+  "  yuv.b = texture2D(texs[2], tcv2).r;\n"
+  "  gl_FragColor = yuv_conv * yuv;\n"
+  "}\n";
+
+static void set_frag_shader(GLuint prog, GLuint shader) {
+  mpglAttachShader(prog, shader);
+  mpglBindAttribLocation(prog, 0, "vPos");
+  mpglBindAttribLocation(prog, 1, "tca");
+  mpglBindAttribLocation(prog, 2, "tca2");
+  mpglBindAttribLocation(prog, 3, "tca3");
+  mpglLinkProgram(prog);
+  print_result(1, prog);
+}
+
+static void set_frag_src(GLuint prog, const char *src) {
+  GLuint shader = compile_shader(GL_FRAGMENT_SHADER, src);
+  set_frag_shader(prog, shader);
+  mpglDeleteShader(shader);
+}
+
+static void GLAPIENTRY matrix_uniform(const float *matrix)
+{
+  GLint loc;
+  if (matrix != transform_matrix)
+    memcpy(transform_matrix, matrix, sizeof(transform_matrix));
+  loc = mpglGetUniformLocation(gpu_cur_sl_program, "matrix");
+  mpglUniformMatrix4fv(loc, 1, GL_FALSE, transform_matrix);
+}
+
+static void use_program(GLuint prog) {
+  GLint loc;
+  static const GLint texs[] = {0, 1, 2, 3, 4};
+  mpglUseProgram(prog);
+  gpu_cur_sl_program = prog;
+  loc = mpglGetUniformLocation(prog, "texs");
+  mpglUniform1iv(loc, sizeof(texs)/sizeof(texs[0]), texs);
+  matrix_uniform(transform_matrix);
+}
+
 /**
  * \brief detect the best YUV->RGB conversion method available
  */
@@ -1551,6 +1696,8 @@
   const char *vendor     = mpglGetString(GL_VENDOR);
   // Imagination cannot parse floats in exponential representation (%e)
   int is_img = vendor && strstr(vendor, "Imagination") != NULL;
+  if (!mpglBegin)
+    return YUV_CONVERSION_SL_PROGRAM;
   if (!extensions || !mpglMultiTexCoord2f)
     return YUV_CONVERSION_NONE;
   if (strstr(extensions, "GL_ARB_fragment_program") && !is_img)
@@ -1589,6 +1736,8 @@
     case YUV_CONVERSION_FRAGMENT_POW:
       glSetupYUVFragprog(params);
       break;
+    case YUV_CONVERSION_SL_PROGRAM:
+      break;
     case YUV_CONVERSION_NONE:
       break;
     default:
@@ -1635,6 +1784,9 @@
     case YUV_CONVERSION_NONE:
       mpglEnable(GL_FRAGMENT_PROGRAM);
       break;
+    case YUV_CONVERSION_SL_PROGRAM:
+      use_program(gpu_yuv_sl_program);
+      break;
   }
 }
 
@@ -1681,6 +1833,9 @@
     case YUV_CONVERSION_NONE:
       mpglDisable(GL_FRAGMENT_PROGRAM);
       break;
+    case YUV_CONVERSION_SL_PROGRAM:
+      use_program(gpu_def_sl_program);
+      break;
   }
 }
 
@@ -1821,37 +1976,15 @@
   GLfloat texcoords3[8] = {vo_dx / 4.0, vo_dy / 4.0, vo_dx / 4.0, (vo_dy + vo_dheight) / 4.0, (vo_dx + vo_dwidth) / 4.0, vo_dy / 4.0, (vo_dx + vo_dwidth) / 4.0, (vo_dy + vo_dheight) / 4.0};
 
   if (!mpglBegin) {
-    mpglEnableClientState(GL_VERTEX_ARRAY);
-    mpglVertexPointer(2, GL_FLOAT, 0, vertices);
-    mpglEnableClientState(GL_TEXTURE_COORD_ARRAY);
-    mpglTexCoordPointer(2, GL_FLOAT, 0, texcoords);
-    if (use_stipple) {
-      mpglClientActiveTexture(GL_TEXTURE3);
-      mpglEnableClientState(GL_TEXTURE_COORD_ARRAY);
-      mpglTexCoordPointer(2, GL_FLOAT, 0, texcoords3);
-    }
-    if (is_yv12) {
-      mpglClientActiveTexture(GL_TEXTURE1);
-      mpglEnableClientState(GL_TEXTURE_COORD_ARRAY);
-      mpglTexCoordPointer(2, GL_FLOAT, 0, texcoords2);
-      mpglClientActiveTexture(GL_TEXTURE2);
-      mpglEnableClientState(GL_TEXTURE_COORD_ARRAY);
-      mpglTexCoordPointer(2, GL_FLOAT, 0, texcoords2);
-      mpglClientActiveTexture(GL_TEXTURE0);
-    }
+    mpglVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, vertices);
+    mpglEnableVertexAttribArray(0);
+    mpglVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, texcoords);
+    mpglEnableVertexAttribArray(1);
+    mpglVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 0, texcoords2);
+    mpglEnableVertexAttribArray(2);
+    mpglVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, 0, texcoords3);
+    mpglEnableVertexAttribArray(3);
     mpglDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
-    if (use_stipple) {
-      mpglClientActiveTexture(GL_TEXTURE3);
-      mpglDisableClientState(GL_TEXTURE_COORD_ARRAY);
-    }
-    if (is_yv12) {
-      mpglClientActiveTexture(GL_TEXTURE1);
-      mpglDisableClientState(GL_TEXTURE_COORD_ARRAY);
-      mpglClientActiveTexture(GL_TEXTURE2);
-      mpglDisableClientState(GL_TEXTURE_COORD_ARRAY);
-      mpglClientActiveTexture(GL_TEXTURE0);
-    }
-    mpglDisableClientState(GL_VERTEX_ARRAY);
     return;
   }
 
@@ -2218,9 +2351,9 @@
   void *res = eglGetProcAddress(name);
   if (!res) {
     static const char * const paths[] = {
-      "/usr/lib/libGLESv1_CM.so",
-      "/usr/lib/x86_64-linux-gnu/libGLESv1_CM.so",
-      "/usr/lib/i386-linux-gnu/libGLESv1_CM.so",
+      "/usr/lib/libGLESv2.so",
+      "/usr/lib/x86_64-linux-gnu/libGLESv2.so",
+      "/usr/lib/i386-linux-gnu/libGLESv2.so",
       NULL};
     int i;
     void *h = NULL;
@@ -2235,8 +2368,8 @@
 
 static int setGlWindow_egl(MPGLContext *ctx)
 {
-  static const EGLint cfg_attribs[] = { EGL_NONE };
-  static const EGLint ctx_attribs[] = { EGL_NONE };
+  static const EGLint cfg_attribs[] = { EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_NONE };
+  static const EGLint ctx_attribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
   EGLContext *context = &ctx->context.egl;
   EGLContext new_context = NULL;
   EGLConfig eglConfig;
@@ -2299,6 +2432,13 @@
   mpglBegin = NULL;
   mpglDrawBuffer = NULL;
 
+  gpu_def_sl_program = new_gpu_program();
+  gpu_yuv_sl_program = new_gpu_program();
+  set_frag_src(gpu_def_sl_program, def_frag_shader);
+  set_frag_src(gpu_yuv_sl_program, yuv_frag_shader);
+  mpglLoadMatrixf = matrix_uniform;
+  use_program(gpu_def_sl_program);
+
   // and inform that reinit is necessary
   return SET_WINDOW_REINIT;
 }
--- a/libvo/gl_common.h	Sat May 04 11:15:19 2013 +0000
+++ b/libvo/gl_common.h	Sat May 04 13:28:14 2013 +0000
@@ -94,6 +94,7 @@
 #define YUV_CONVERSION_FRAGMENT_LOOKUP3D 6
 //! use ATI specific "text" register combiners ("fragment program")
 #define YUV_CONVERSION_TEXT_FRAGMENT 7
+#define YUV_CONVERSION_SL_PROGRAM 8
 //! use normal bilinear scaling for textures
 #define YUV_SCALER_BILIN 0
 //! use higher quality bicubic scaling for textures
@@ -238,7 +239,7 @@
 extern void (GLAPIENTRY *mpglViewport)(GLint, GLint, GLsizei, GLsizei);
 extern void (GLAPIENTRY *mpglMatrixMode)(GLenum);
 extern void (GLAPIENTRY *mpglLoadIdentity)(void);
-extern void (GLAPIENTRY *mpglLoadMatrixf)(float *);
+extern void (GLAPIENTRY *mpglLoadMatrixf)(const float *);
 extern void (GLAPIENTRY *mpglClear)(GLbitfield);
 extern GLuint (GLAPIENTRY *mpglGenLists)(GLsizei);
 extern void (GLAPIENTRY *mpglDeleteLists)(GLuint, GLsizei);
--- a/libvo/gl_compat.h	Sat May 04 11:15:19 2013 +0000
+++ b/libvo/gl_compat.h	Sat May 04 13:28:14 2013 +0000
@@ -413,6 +413,18 @@
 #ifndef GL_PROGRAM_ERROR_STRING
 #define GL_PROGRAM_ERROR_STRING 0x8874
 #endif
+#ifndef GL_FRAGMENT_SHADER
+#define GL_FRAGMENT_SHADER 0x8B30
+#endif
+#ifndef GL_VERTEX_SHADER
+#define GL_VERTEX_SHADER 0x8B31
+#endif
+#ifndef GL_COMPILE_STATUS
+#define GL_COMPILE_STATUS 0x8B81
+#endif
+#ifndef GL_LINK_STATUS
+#define GL_LINK_STATUS 0x8B82
+#endif
 /** \} */ // end of glextdefines group
 
 #endif /* MPLAYER_GL_COMPAT_H */