changeset 34338:4a507d3a039a

Add highly experimental support for OpenGL ES. It only supports EGL/X11, uses/supports only ES v1, will crash if certain features are used, compiling without desktop GL installed is not tested and possibly more caveats. However it is close enough to be able to display a video on a BeagleBoard via OpenGL. Performance could not be tested properly since I do not have a display that is compatible with the BeagleBoard output...
author reimar
date Sat, 10 Dec 2011 20:55:31 +0000
parents f8c523d09e5e
children f05c75392897
files configure libvo/gl_common.c libvo/gl_common.h libvo/vo_gl.c
diffstat 4 files changed, 197 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/configure	Sat Dec 10 20:21:50 2011 +0000
+++ b/configure	Sat Dec 10 20:55:31 2011 +0000
@@ -5064,6 +5064,10 @@
 // we allow SDL hacking our main() only on OSX
 #undef main
 #endif
+#elif defined(GL_EGL_X11)
+#include <GL/gl.h>
+#include <X11/Xlib.h>
+#include <EGL/egl.h>
 #else
 #include <GL/gl.h>
 #include <X11/Xlib.h>
@@ -5075,10 +5079,15 @@
   wglCreateContext(dc);
 #elif defined(GL_SDL)
   SDL_GL_SwapBuffers();
+#elif defined(GL_EGL_X11)
+  EGLDisplay eglDisplay = EGL_NO_DISPLAY;
+  eglInitialize(eglDisplay, NULL, NULL);
 #else
   glXCreateContext(NULL, NULL, NULL, True);
 #endif
+#ifndef GL_EGL_X11
   glFinish();
+#endif
   return 0;
 }
 EOF
@@ -5091,6 +5100,11 @@
       break
     fi
   done
+  if cc_check -DGL_EGL_X11 -lEGL ; then
+    _gl=yes
+    _gl_egl_x11=yes
+    libs_mplayer="$libs_mplayer -lEGL $ld_dl"
+  fi
   if cc_check -DGL_WIN32 -lopengl32 ; then
     _gl=yes
     _gl_win32=yes
@@ -5123,6 +5137,10 @@
     def_gl_x11='#define CONFIG_GL_X11 1'
     res_comment="$res_comment x11"
   fi
+  if test "$_gl_egl_x11" = yes ; then
+    def_gl_egl_x11='#define CONFIG_GL_EGL_X11 1'
+    res_comment="$res_comment egl_x11"
+  fi
   if test "$_gl_sdl" = yes ; then
     def_gl_sdl='#define CONFIG_GL_SDL 1'
     res_comment="$res_comment sdl"
@@ -5132,6 +5150,7 @@
   def_gl='#undef CONFIG_GL'
   def_gl_win32='#undef CONFIG_GL_WIN32'
   def_gl_x11='#undef CONFIG_GL_X11'
+  def_gl_egl_x11='#undef CONFIG_GL_EGL_X11'
   def_gl_sdl='#undef CONFIG_GL_SDL'
   novomodules="opengl $novomodules"
 fi
@@ -8030,6 +8049,7 @@
 GL = $_gl
 GL_WIN32 = $_gl_win32
 GL_X11 = $_gl_x11
+GL_EGL_X11 = $_gl_egl_x11
 GL_SDL = $_gl_sdl
 MATRIXVIEW = $matrixview
 GUI = $_gui
@@ -8569,6 +8589,7 @@
 $def_gl
 $def_gl_win32
 $def_gl_x11
+$def_gl_egl_x11
 $def_gl_sdl
 $def_matrixview
 $def_ivtv
--- a/libvo/gl_common.c	Sat Dec 10 20:21:50 2011 +0000
+++ b/libvo/gl_common.c	Sat Dec 10 20:55:31 2011 +0000
@@ -139,6 +139,14 @@
 void (GLAPIENTRY *mpglFreeMemoryMESA)(void *, int, void *);
 /** \} */ // end of glextfunctions group
 
+
+void (GLAPIENTRY *mpglVertexPointer)(GLint, GLenum, GLsizei, const GLvoid *);
+void (GLAPIENTRY *mpglTexCoordPointer)(GLint, GLenum, GLsizei, const GLvoid *);
+void (GLAPIENTRY *mpglClientActiveTexture)(GLenum);
+void (GLAPIENTRY *mpglEnableClientState)(GLenum);
+void (GLAPIENTRY *mpglDisableClientState)(GLenum);
+void (GLAPIENTRY *mpglDrawArrays)(GLenum, GLint, GLsizei);
+
 //! \defgroup glgeneral OpenGL general helper functions
 
 //! \defgroup glcontext OpenGL context management helper functions
@@ -384,7 +392,11 @@
   void *fallback;
 } extfunc_desc_t;
 
+#if !defined(CONFIG_GL_WIN32) && !defined(CONFIG_GL_X11)
+#define DEF_FUNC_DESC(name) {&mpgl##name, NULL, {"gl"#name, NULL}, NULL}
+#else
 #define DEF_FUNC_DESC(name) {&mpgl##name, NULL, {"gl"#name, NULL}, gl ##name}
+#endif
 static const extfunc_desc_t extfuncs[] = {
   // these aren't extension functions but we query them anyway to allow
   // different "backends" with one binary
@@ -466,6 +478,14 @@
   {&mpglTexImage3D, NULL, {"glTexImage3D", NULL}},
   {&mpglAllocateMemoryMESA, "GLX_MESA_allocate_memory", {"glXAllocateMemoryMESA", NULL}},
   {&mpglFreeMemoryMESA, "GLX_MESA_allocate_memory", {"glXFreeMemoryMESA", NULL}},
+
+  // Things needed to run on GLES
+  {&mpglVertexPointer, NULL, {"glVertexPointer", NULL}},
+  {&mpglTexCoordPointer, NULL, {"glTexCoordPointer", NULL}},
+  {&mpglClientActiveTexture, NULL, {"glClientActiveTexture", NULL}},
+  {&mpglEnableClientState, NULL, {"glEnableClientState", NULL}},
+  {&mpglDisableClientState, NULL, {"glDisableClientState", NULL}},
+  {&mpglDrawArrays, NULL, {"glDrawArrays", NULL}},
   {NULL}
 };
 
@@ -1685,6 +1705,36 @@
     y += h;
     h = -h;
   }
+
+  if (!mpglBegin) {
+    GLfloat vertices  [8] = { x,   y,   x,   y  +  h,   x  +  w,   y,   x  +  w,   y  +  h};
+    GLfloat texcoords [8] = {tx,  ty,  tx,  ty  + th,  tx  + tw,  ty,  tx  + tw,  ty  + th};
+    GLfloat texcoords2[8] = {tx2, ty2, tx2, ty2 + th2, tx2 + tw2, ty2, tx2 + tw2, ty2 + th2};
+    mpglEnableClientState(GL_VERTEX_ARRAY);
+    mpglVertexPointer(2, GL_FLOAT, 0, vertices);
+    mpglEnableClientState(GL_TEXTURE_COORD_ARRAY);
+    mpglTexCoordPointer(2, GL_FLOAT, 0, texcoords);
+    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);
+    }
+    mpglDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+    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;
+  }
+
   mpglBegin(GL_QUADS);
   mpglTexCoord2f(tx, ty);
   if (is_yv12) {
@@ -1957,7 +2007,9 @@
 static void swapGlBuffers_x11(MPGLContext *ctx) {
   glXSwapBuffers(mDisplay, vo_window);
 }
+#endif
 
+#if defined(CONFIG_GL_X11) || defined(CONFIG_GL_EGL_X11)
 static int x11_check_events(void) {
   return vo_x11_check_events(mDisplay);
 }
@@ -1997,6 +2049,99 @@
 
 #endif
 
+#ifdef CONFIG_GL_EGL_X11
+static EGLDisplay eglDisplay = EGL_NO_DISPLAY;
+static EGLSurface eglSurface = EGL_NO_SURFACE;
+
+/*
+ * Some genius thought it a good idea to make
+ * eglGetProcAddress not work for core functions.
+ * So we have to use a non-portable way that in addition
+ * might also return symbols from a different library
+ * that the one providing the current context, great job!
+ */
+static void *eglgpa(const GLubyte *name) {
+  void *res = eglGetProcAddress(name);
+  if (!res) {
+    void *h = dlopen("/usr/lib/libGLESv1_CM.so", RTLD_LAZY);
+    res = dlsym(h, name);
+    dlclose(h);
+  }
+  return res;
+}
+
+static int setGlWindow_egl(MPGLContext *ctx)
+{
+  static const EGLint cfg_attribs[] = { EGL_NONE };
+  static const EGLint ctx_attribs[] = { EGL_NONE };
+  EGLContext *context = &ctx->context.egl;
+  Window win = vo_window;
+  EGLContext new_context = NULL;
+  EGLConfig eglConfig;
+  int num_configs;
+  if (eglDisplay == EGL_NO_DISPLAY) {
+    eglDisplay = eglGetDisplay(mDisplay);
+    if (eglDisplay == EGL_NO_DISPLAY) {
+      mp_msg(MSGT_VO, MSGL_FATAL, "eglGetDisplay failed: 0x%x\n", eglGetError());
+      return SET_WINDOW_FAILED;
+    }
+    if (!eglInitialize(eglDisplay, NULL, NULL)) {
+      mp_msg(MSGT_VO, MSGL_FATAL, "eglInitialize failed: 0x%x\n", eglGetError());
+      return SET_WINDOW_FAILED;
+    }
+  }
+  if (*context != EGL_NO_CONTEXT) {
+    eglMakeCurrent(eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+    eglDestroyContext(eglDisplay, *context);
+    eglDestroySurface(eglDisplay, eglSurface);
+  }
+  if (!eglChooseConfig(eglDisplay, cfg_attribs, &eglConfig, 1, &num_configs) ||
+      num_configs != 1)
+    return SET_WINDOW_FAILED;
+  eglSurface = eglCreateWindowSurface(eglDisplay, eglConfig, win, NULL);
+  if (eglSurface == EGL_NO_SURFACE)
+    return SET_WINDOW_FAILED;
+
+  new_context = eglCreateContext(eglDisplay, eglConfig, EGL_NO_CONTEXT, ctx_attribs);
+  if (new_context == EGL_NO_CONTEXT)
+    return SET_WINDOW_FAILED;
+  if (!eglMakeCurrent(eglDisplay, eglSurface, eglSurface, new_context))
+    return SET_WINDOW_FAILED;
+
+  // set new values
+  vo_window = win;
+  vo_x11_update_geometry();
+  *context = new_context;
+
+  getFunctions(eglgpa, eglQueryString(eglDisplay, EGL_EXTENSIONS));
+  mpglBegin = NULL;
+  mpglDrawBuffer = NULL;
+
+  // and inform that reinit is necessary
+  return SET_WINDOW_REINIT;
+}
+
+/**
+ * \brief free the VisualInfo and GLXContext of an OpenGL context.
+ * \ingroup glcontext
+ */
+static void releaseGlContext_egl(MPGLContext *ctx) {
+  EGLContext *context = &ctx->context.egl;
+  if (*context != EGL_NO_CONTEXT)
+  {
+    mpglFinish();
+    eglMakeCurrent(eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+    eglDestroyContext(eglDisplay, *context);
+  }
+  *context = EGL_NO_CONTEXT;
+}
+
+static void swapGlBuffers_egl(MPGLContext *ctx) {
+  eglSwapBuffers(eglDisplay, eglSurface);
+}
+
+#endif
+
 static int setGlWindow_dummy(MPGLContext *ctx) {
   getFunctions(NULL, NULL);
   return SET_WINDOW_OK;
@@ -2026,6 +2171,8 @@
     res = init_mpglcontext(ctx, GLTYPE_X11);
     if (res) return res;
     res = init_mpglcontext(ctx, GLTYPE_SDL);
+    if (res) return res;
+    res = init_mpglcontext(ctx, GLTYPE_EGL_X11);
     return res;
   }
   memset(ctx, 0, sizeof(*ctx));
@@ -2068,6 +2215,18 @@
     ctx->fullscreen = vo_sdl_fullscreen;
     return vo_sdl_init();
 #endif
+#ifdef CONFIG_GL_EGL_X11
+  case GLTYPE_EGL_X11:
+    ctx->setGlWindow = setGlWindow_egl;
+    ctx->releaseGlContext = releaseGlContext_egl;
+    ctx->swapGlBuffers = swapGlBuffers_egl;
+    ctx->update_xinerama_info = update_xinerama_info;
+    ctx->border = vo_x11_border;
+    ctx->check_events = x11_check_events;
+    ctx->fullscreen = vo_x11_fullscreen;
+    ctx->ontop = vo_x11_ontop;
+    return vo_init();
+#endif
   default:
     return 0;
   }
--- a/libvo/gl_common.h	Sat Dec 10 20:21:50 2011 +0000
+++ b/libvo/gl_common.h	Sat Dec 10 20:55:31 2011 +0000
@@ -40,6 +40,10 @@
 #include <GL/glx.h>
 #include "x11_common.h"
 #endif
+#ifdef CONFIG_GL_EGL_X11
+#include <EGL/egl.h>
+#include "x11_common.h"
+#endif
 #include <GL/gl.h>
 
 // workaround for some gl.h headers
@@ -405,6 +409,7 @@
   GLTYPE_W32,
   GLTYPE_X11,
   GLTYPE_SDL,
+  GLTYPE_EGL_X11,
 };
 
 typedef struct MPGLContext {
@@ -422,6 +427,9 @@
 #ifdef CONFIG_GL_X11
     GLXContext x11;
 #endif
+#ifdef CONFIG_GL_EGL_X11
+    EGLContext egl;
+#endif
   } context;
   int (*setGlWindow)(struct MPGLContext *);
   void (*releaseGlContext)(struct MPGLContext *);
--- a/libvo/vo_gl.c	Sat Dec 10 20:21:50 2011 +0000
+++ b/libvo/vo_gl.c	Sat Dec 10 20:55:31 2011 +0000
@@ -547,7 +547,8 @@
   mpglDepthMask(GL_FALSE);
   mpglDisable(GL_CULL_FACE);
   mpglEnable(gl_target);
-  mpglDrawBuffer(vo_doublebuffering?GL_BACK:GL_FRONT);
+  if (mpglDrawBuffer)
+    mpglDrawBuffer(vo_doublebuffering?GL_BACK:GL_FRONT);
   mpglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
 
   mp_msg(MSGT_VO, MSGL_V, "[gl] Creating %dx%d texture...\n",
@@ -618,6 +619,13 @@
   if (glctx.type == GLTYPE_W32 && !vo_w32_config(d_width, d_height, flags))
     return -1;
 #endif
+#ifdef CONFIG_GL_EGL_X11
+  if (glctx.type == GLTYPE_EGL_X11) {
+    XVisualInfo vinfo = { .visual = CopyFromParent, .depth = CopyFromParent };
+    vo_x11_create_vo_window(&vinfo, vo_dx, vo_dy, d_width, d_height, flags,
+            CopyFromParent, "gl", title);
+  }
+#endif
 #ifdef CONFIG_GL_X11
   if (glctx.type == GLTYPE_X11) {
     static int default_glx_attribs[] = {