]> git.sesse.net Git - vlc/blobdiff - modules/video_output/opengl.c
Fix alignment and appearance of ISO standard equalizer centers in Qt GUI
[vlc] / modules / video_output / opengl.c
index 1ab7b7dbc4a72ebe73331e69b514f6e43b457047..c67cc1989b9c852080fe370d11f71b65a9b8bfbb 100644 (file)
@@ -1,15 +1,15 @@
 /*****************************************************************************
  * opengl.c: OpenGL and OpenGL ES output common code
  *****************************************************************************
- * Copyright (C) 2004-2012 VLC authors and VideoLAN
+ * Copyright (C) 2004-2013 VLC authors and VideoLAN
  * Copyright (C) 2009, 2011 Laurent Aimar
  *
- * Authors: Cyril Deguet <asmax@videolan.org>
- *          Gildas Bazin <gbazin@videolan.org>
- *          Eric Petit <titer@m0k.org>
- *          Cedric Cocquebert <cedric.cocquebert@supelec.fr>
- *          Laurent Aimar <fenrir _AT_ videolan _DOT_ org>
+ * Authors: Laurent Aimar <fenrir _AT_ videolan _DOT_ org>
  *          Ilkka Ollakka <ileoo@videolan.org>
+ *          Rémi Denis-Courmont
+ *          Adrien Maglo <magsoft at videolan dot org>
+ *          Felix Paul Kühne <fkuehne at videolan dot org>
+ *          Pierre d'Herbemont <pdherbemont at videolan dot org>
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as published by
 #endif
 
 #ifdef __APPLE__
-#   define PFNGLGENBUFFERSPROC               typeof(glGenBuffers)*
-#   define PFNGLBINDBUFFERPROC               typeof(glBindBuffer)*
-#   define PFNGLDELETEBUFFERSPROC            typeof(glDeleteBuffers)*
-#   define PFNGLBUFFERSUBDATAPROC            typeof(glBufferSubData)*
-#   define PFNGLBUFFERDATAPROC               typeof(glBufferData)*
 #   define PFNGLGETPROGRAMIVPROC             typeof(glGetProgramiv)*
 #   define PFNGLGETPROGRAMINFOLOGPROC        typeof(glGetProgramInfoLog)*
 #   define PFNGLGETSHADERIVPROC              typeof(glGetShaderiv)*
 #   define PFNGLENABLEVERTEXATTRIBARRAYPROC  typeof(glEnableVertexAttribArray)*
 #   define PFNGLUNIFORM4FVPROC               typeof(glUniform4fv)*
 #   define PFNGLUNIFORM4FPROC                typeof(glUniform4f)*
-#   define PFNGLUNIFORM3IPROC                typeof(glUniform3i)*
 #   define PFNGLUNIFORM1IPROC                typeof(glUniform1i)*
 #   define PFNGLCREATESHADERPROC             typeof(glCreateShader)*
 #   define PFNGLSHADERSOURCEPROC             typeof(glShaderSource)*
 #   define PFNGLCOMPILESHADERPROC            typeof(glCompileShader)*
-#   define PFNGLDETACHSHADERPROC             typeof(glDetachShader)*
 #   define PFNGLDELETESHADERPROC             typeof(glDeleteShader)*
 #   define PFNGLCREATEPROGRAMPROC            typeof(glCreateProgram)*
 #   define PFNGLLINKPROGRAMPROC              typeof(glLinkProgram)*
 #   define PFNGLDELETEPROGRAMPROC            typeof(glDeleteProgram)*
 #   define PFNGLATTACHSHADERPROC             typeof(glAttachShader)*
 #if USE_OPENGL_ES
-#   define GL_UNPACK_ROW_LENGTH 0
 #   import <CoreFoundation/CoreFoundation.h>
 #endif
 #endif
 
 #if USE_OPENGL_ES
+#   define GLSL_VERSION "100"
 #   define VLCGL_TEXTURE_COUNT 1
 #   define VLCGL_PICTURE_MAX 1
+#   define PRECISION "precision highp float;"
 #else
+#   define GLSL_VERSION "120"
 #   define VLCGL_TEXTURE_COUNT 1
 #   define VLCGL_PICTURE_MAX 128
+#   define PRECISION ""
 #endif
 
 static const vlc_fourcc_t gl_subpicture_chromas[] = {
@@ -131,16 +127,7 @@ struct vout_display_opengl_t {
     int        local_count;
     GLfloat    local_value[16];
 
-    /* Buffer commands */
-    PFNGLGENBUFFERSPROC   GenBuffers;
-    PFNGLBINDBUFFERPROC   BindBuffer;
-    PFNGLDELETEBUFFERSPROC DeleteBuffers;
-    PFNGLBUFFERSUBDATAPROC BufferSubData;
-
-    PFNGLBUFFERDATAPROC   BufferData;
-
     /* Shader variables commands*/
-
     PFNGLGETUNIFORMLOCATIONPROC      GetUniformLocation;
     PFNGLGETATTRIBLOCATIONPROC       GetAttribLocation;
     PFNGLVERTEXATTRIBPOINTERPROC     VertexAttribPointer;
@@ -148,14 +135,12 @@ struct vout_display_opengl_t {
 
     PFNGLUNIFORM4FVPROC   Uniform4fv;
     PFNGLUNIFORM4FPROC    Uniform4f;
-    PFNGLUNIFORM3IPROC    Uniform3i;
     PFNGLUNIFORM1IPROC    Uniform1i;
 
     /* Shader command */
     PFNGLCREATESHADERPROC CreateShader;
     PFNGLSHADERSOURCEPROC ShaderSource;
     PFNGLCOMPILESHADERPROC CompileShader;
-    PFNGLDETACHSHADERPROC   DetachShader;
     PFNGLDELETESHADERPROC   DeleteShader;
 
     PFNGLCREATEPROGRAMPROC CreateProgram;
@@ -209,8 +194,9 @@ static void BuildVertexShader(vout_display_opengl_t *vgl,
 {
     /* Basic vertex shader */
     const char *vertexShader =
-        "#version 120\n"
-        "varying   vec4 TexCoord0,TexCoord1, TexCoord2;"
+        "#version " GLSL_VERSION "\n"
+        PRECISION
+        "varying vec4 TexCoord0,TexCoord1, TexCoord2;"
         "attribute vec4 MultiTexCoord0,MultiTexCoord1,MultiTexCoord2;"
         "attribute vec4 VertexPosition;"
         "void main() {"
@@ -252,16 +238,19 @@ static void BuildYUVFragmentShader(vout_display_opengl_t *vgl,
 
     /* Basic linear YUV -> RGB conversion using bilinear interpolation */
     const char *template_glsl_yuv =
-        "#version 120\n"
-        "uniform sampler2D Texture[3];"
+        "#version " GLSL_VERSION "\n"
+        PRECISION
+        "uniform sampler2D Texture0;"
+        "uniform sampler2D Texture1;"
+        "uniform sampler2D Texture2;"
         "uniform vec4      Coefficient[4];"
         "varying vec4      TexCoord0,TexCoord1,TexCoord2;"
 
         "void main(void) {"
         " vec4 x,y,z,result;"
-        " x  = texture2D(Texture[0], TexCoord0.st);"
-        " %c = texture2D(Texture[1], TexCoord1.st);"
-        " %c = texture2D(Texture[2], TexCoord2.st);"
+        " x  = texture2D(Texture0, TexCoord0.st);"
+        " %c = texture2D(Texture1, TexCoord1.st);"
+        " %c = texture2D(Texture2, TexCoord2.st);"
 
         " result = x * Coefficient[0] + Coefficient[3];"
         " result = (y * Coefficient[1]) + result;"
@@ -295,12 +284,14 @@ static void BuildYUVFragmentShader(vout_display_opengl_t *vgl,
     free(code);
 }
 
+#if 0
 static void BuildRGBFragmentShader(vout_display_opengl_t *vgl,
                                    GLint *shader)
 {
     // Simple shader for RGB
     const char *code =
-        "#version 120\n"
+        "#version " GLSL_VERSION "\n"
+        PRECISION
         "uniform sampler2D Texture[3];"
         "varying vec4 TexCoord0,TexCoord1,TexCoord2;"
         "void main()"
@@ -311,13 +302,15 @@ static void BuildRGBFragmentShader(vout_display_opengl_t *vgl,
     vgl->ShaderSource(*shader, 1, &code, NULL);
     vgl->CompileShader(*shader);
 }
+#endif
 
 static void BuildRGBAFragmentShader(vout_display_opengl_t *vgl,
                                    GLint *shader)
 {
     // Simple shader for RGBA
     const char *code =
-        "#version 120\n"
+        "#version " GLSL_VERSION "\n"
+        PRECISION
         "uniform sampler2D Texture;"
         "uniform vec4 FillColor;"
         "varying vec4 TexCoord0;"
@@ -356,18 +349,8 @@ vout_display_opengl_t *vout_display_opengl_New(video_format_t *fmt,
     bool supports_shaders = strverscmp((const char *)ogl_version, "2.0") >= 0;
 #else
     bool supports_shaders = false;
-#ifdef __APPLE__
-    if (kCFCoreFoundationVersionNumber >= 786.)
-        supports_shaders = true;
-#endif
 #endif
 
-    vgl->GenBuffers    = (PFNGLGENBUFFERSPROC)vlc_gl_GetProcAddress(vgl->gl, "glGenBuffers");
-    vgl->BindBuffer    = (PFNGLBINDBUFFERPROC)vlc_gl_GetProcAddress(vgl->gl, "glBindBuffer");
-    vgl->BufferData    = (PFNGLBUFFERDATAPROC)vlc_gl_GetProcAddress(vgl->gl, "glBufferData");
-    vgl->BufferSubData = (PFNGLBUFFERSUBDATAPROC)vlc_gl_GetProcAddress(vgl->gl, "glBufferSubData");
-    vgl->DeleteBuffers = (PFNGLDELETEBUFFERSPROC)vlc_gl_GetProcAddress(vgl->gl, "glDeleteBuffers");
-
     vgl->CreateShader  = (PFNGLCREATESHADERPROC)vlc_gl_GetProcAddress(vgl->gl, "glCreateShader");
     vgl->ShaderSource  = (PFNGLSHADERSOURCEPROC)vlc_gl_GetProcAddress(vgl->gl, "glShaderSource");
     vgl->CompileShader = (PFNGLCOMPILESHADERPROC)vlc_gl_GetProcAddress(vgl->gl, "glCompileShader");
@@ -378,7 +361,6 @@ vout_display_opengl_t *vout_display_opengl_New(video_format_t *fmt,
     vgl->GetProgramInfoLog  = (PFNGLGETPROGRAMINFOLOGPROC)vlc_gl_GetProcAddress(vgl->gl, "glGetProgramInfoLog");
     vgl->GetShaderInfoLog   = (PFNGLGETSHADERINFOLOGPROC)vlc_gl_GetProcAddress(vgl->gl, "glGetShaderInfoLog");
 
-    vgl->DetachShader  = (PFNGLDETACHSHADERPROC)vlc_gl_GetProcAddress(vgl->gl, "glDetachShader");
     vgl->DeleteShader  = (PFNGLDELETESHADERPROC)vlc_gl_GetProcAddress(vgl->gl, "glDeleteShader");
 
     vgl->GetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC)vlc_gl_GetProcAddress(vgl->gl, "glGetUniformLocation");
@@ -387,7 +369,6 @@ vout_display_opengl_t *vout_display_opengl_New(video_format_t *fmt,
     vgl->EnableVertexAttribArray = (PFNGLENABLEVERTEXATTRIBARRAYPROC)vlc_gl_GetProcAddress(vgl->gl, "glEnableVertexAttribArray");
     vgl->Uniform4fv    = (PFNGLUNIFORM4FVPROC)vlc_gl_GetProcAddress(vgl->gl,"glUniform4fv");
     vgl->Uniform4f     = (PFNGLUNIFORM4FPROC)vlc_gl_GetProcAddress(vgl->gl,"glUniform4f");
-    vgl->Uniform3i     = (PFNGLUNIFORM3IPROC)vlc_gl_GetProcAddress(vgl->gl,"glUniform3i");
     vgl->Uniform1i     = (PFNGLUNIFORM1IPROC)vlc_gl_GetProcAddress(vgl->gl,"glUniform1i");
 
     vgl->CreateProgram = (PFNGLCREATEPROGRAMPROC)vlc_gl_GetProcAddress(vgl->gl, "glCreateProgram");
@@ -401,9 +382,26 @@ vout_display_opengl_t *vout_display_opengl_New(video_format_t *fmt,
     vgl->supports_npot = HasExtension(extensions, "GL_ARB_texture_non_power_of_two") ||
                          HasExtension(extensions, "GL_APPLE_texture_2D_limited_npot");
 
+#if USE_OPENGL_ES
+    /* OpenGL ES 2 includes support for non-power of 2 textures by specification
+     * so checks for extensions are bound to fail. Check for OpenGL ES version instead. */
+    const unsigned char *ogl_version = glGetString(GL_VERSION);
+    if (strverscmp((const char *)ogl_version, "2.0") >= 0)
+        vgl->supports_npot = true;
+#endif
+
     GLint max_texture_units = 0;
     glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &max_texture_units);
 
+#ifdef __APPLE__
+#if USE_OPENGL_ES
+    /* work-around an iOS 6 bug */
+    if (kCFCoreFoundationVersionNumber >= 786.)
+        max_texture_units = 8;
+    supports_shaders = true;
+#endif
+#endif
+
     /* Initialize with default chroma */
     vgl->fmt = *fmt;
     vgl->fmt.i_chroma = VLC_CODEC_RGB32;
@@ -423,8 +421,8 @@ vout_display_opengl_t *vout_display_opengl_New(video_format_t *fmt,
     /* Use YUV if possible and needed */
     bool need_fs_yuv = false;
     float yuv_range_correction = 1.0;
-    if (max_texture_units >= 3 && supports_shaders &&
-        vlc_fourcc_IsYUV(fmt->i_chroma) && !vlc_fourcc_IsYUV(vgl->fmt.i_chroma)) {
+
+    if (max_texture_units >= 3 && supports_shaders && vlc_fourcc_IsYUV(fmt->i_chroma)) {
         const vlc_fourcc_t *list = vlc_fourcc_GetYUVFallback(fmt->i_chroma);
         while (*list) {
             const vlc_chroma_description_t *dsc = vlc_fourcc_GetChromaDescription(*list);
@@ -477,14 +475,9 @@ vout_display_opengl_t *vout_display_opengl_New(video_format_t *fmt,
     vgl->shader[1] =
     vgl->shader[2] = -1;
     vgl->local_count = 0;
-    if (supports_shaders) {
-        if (need_fs_yuv)
-            BuildYUVFragmentShader(vgl, &vgl->shader[0],
-                                   &vgl->local_count,
-                                   vgl->local_value,
-                                   fmt, yuv_range_correction);
-        else
-            BuildRGBFragmentShader(vgl, &vgl->shader[0]);
+    if (supports_shaders && need_fs_yuv) {
+        BuildYUVFragmentShader(vgl, &vgl->shader[0], &vgl->local_count,
+                               vgl->local_value, fmt, yuv_range_correction);
         BuildRGBAFragmentShader(vgl, &vgl->shader[1]);
         BuildVertexShader(vgl, &vgl->shader[2]);
 
@@ -669,12 +662,39 @@ int vout_display_opengl_Prepare(vout_display_opengl_t *vgl,
             glClientActiveTexture(GL_TEXTURE0 + j);
         }
         glBindTexture(vgl->tex_target, vgl->texture[0][j]);
-        glPixelStorei(GL_UNPACK_ROW_LENGTH, picture->p[j].i_pitch / picture->p[j].i_pixel_pitch);
-        glTexSubImage2D(vgl->tex_target, 0,
-                        0, 0,
-                        vgl->fmt.i_width  * vgl->chroma->p[j].w.num / vgl->chroma->p[j].w.den,
-                        vgl->fmt.i_height * vgl->chroma->p[j].h.num / vgl->chroma->p[j].h.den,
-                        vgl->tex_format, vgl->tex_type, picture->p[j].p_pixels);
+
+#ifndef GL_UNPACK_ROW_LENGTH
+        if ( (picture->p[j].i_pitch / picture->p[j].i_pixel_pitch) != (unsigned int)
+             ( picture->format.i_visible_width * vgl->chroma->p[j].w.num / vgl->chroma->p[j].w.den ) )
+        {
+            uint8_t *new_plane = malloc( picture->format.i_visible_width * vgl->fmt.i_visible_height * vgl->chroma->p[j].h.num / (vgl->chroma->p[j].h.den *  vgl->chroma->p[j].w.den ) );
+            uint8_t *destination = new_plane;
+            const uint8_t *source = picture->p[j].p_pixels;
+
+            for( unsigned height = 0; height < (vgl->fmt.i_visible_height * vgl->chroma->p[j].h.num / vgl->chroma->p[j].h.den) ; height++ )
+            {
+                memcpy( destination, source, picture->format.i_visible_width * vgl->chroma->p[j].w.num / vgl->chroma->p[j].w.den );
+                source += picture->p[j].i_pitch / picture->p[j].i_pixel_pitch;
+                destination += picture->format.i_visible_width * vgl->chroma->p[j].w.num / vgl->chroma->p[j].w.den;
+            }
+            glTexSubImage2D( vgl->tex_target, 0,
+                             0, 0,
+                             picture->format.i_visible_width * vgl->chroma->p[j].w.num / vgl->chroma->p[j].w.den,
+                             vgl->fmt.i_height * vgl->chroma->p[j].h.num / vgl->chroma->p[j].h.den,
+                             vgl->tex_format, vgl->tex_type, new_plane );
+            free( new_plane );
+        } else {
+#else
+            glPixelStorei(GL_UNPACK_ROW_LENGTH, picture->p[j].i_pitch / picture->p[j].i_pixel_pitch);
+#endif
+            glTexSubImage2D(vgl->tex_target, 0,
+                            0, 0,
+                            vgl->fmt.i_width  * vgl->chroma->p[j].w.num / vgl->chroma->p[j].w.den,
+                            vgl->fmt.i_height * vgl->chroma->p[j].h.num / vgl->chroma->p[j].h.den,
+                            vgl->tex_format, vgl->tex_type, picture->p[j].p_pixels);
+#ifndef GL_UNPACK_ROW_LENGTH
+        }
+#endif
     }
 
     int         last_count = vgl->region_count;
@@ -732,7 +752,9 @@ int vout_display_opengl_Prepare(vout_display_opengl_t *vgl,
             if (glr->texture) {
                 glBindTexture(GL_TEXTURE_2D, glr->texture);
                 /* TODO set GL_UNPACK_ALIGNMENT */
+#ifdef GL_UNPACK_ROW_LENGTH
                 glPixelStorei(GL_UNPACK_ROW_LENGTH, r->p_picture->p->i_pitch / r->p_picture->p->i_pixel_pitch);
+#endif
                 glTexSubImage2D(GL_TEXTURE_2D, 0,
                                 0, 0, glr->width, glr->height,
                                 glr->format, glr->type, &r->p_picture->p->p_pixels[pixels_offset]);
@@ -748,7 +770,9 @@ int vout_display_opengl_Prepare(vout_display_opengl_t *vgl,
                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
                 /* TODO set GL_UNPACK_ALIGNMENT */
+#ifdef GL_UNPACK_ROW_LENGTH
                 glPixelStorei(GL_UNPACK_ROW_LENGTH, r->p_picture->p->i_pitch / r->p_picture->p->i_pixel_pitch);
+#endif
                 glTexImage2D(GL_TEXTURE_2D, 0, glr->format,
                              glr->width, glr->height, 0, glr->format, glr->type,
                              &r->p_picture->p->p_pixels[pixels_offset]);
@@ -807,9 +831,9 @@ static void DrawWithShaders(vout_display_opengl_t *vgl,
 {
     vgl->UseProgram(vgl->program[0]);
     vgl->Uniform4fv(vgl->GetUniformLocation(vgl->program[0], "Coefficient"), 4, vgl->local_value);
-    vgl->Uniform1i(vgl->GetUniformLocation(vgl->program[0], "Texture[0]"), 0);
-    vgl->Uniform1i(vgl->GetUniformLocation(vgl->program[0], "Texture[1]"), 1);
-    vgl->Uniform1i(vgl->GetUniformLocation(vgl->program[0], "Texture[2]"), 2);
+    vgl->Uniform1i(vgl->GetUniformLocation(vgl->program[0], "Texture0"), 0);
+    vgl->Uniform1i(vgl->GetUniformLocation(vgl->program[0], "Texture1"), 1);
+    vgl->Uniform1i(vgl->GetUniformLocation(vgl->program[0], "Texture2"), 2);
 
     static const GLfloat vertexCoord[] = {
         -1.0,  1.0,