]> 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 81fc6f51fca5f049b64a5df10e0a56bb0cf49d1c..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
@@ -62,7 +62,6 @@
 #   define PFNGLDELETEPROGRAMPROC            typeof(glDeleteProgram)*
 #   define PFNGLATTACHSHADERPROC             typeof(glAttachShader)*
 #if USE_OPENGL_ES
-#   define GL_UNPACK_ROW_LENGTH 0
 #   import <CoreFoundation/CoreFoundation.h>
 #endif
 #endif
 #   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[] = {
@@ -194,7 +195,8 @@ static void BuildVertexShader(vout_display_opengl_t *vgl,
     /* Basic vertex shader */
     const char *vertexShader =
         "#version " GLSL_VERSION "\n"
-        "varying   vec4 TexCoord0,TexCoord1, TexCoord2;"
+        PRECISION
+        "varying vec4 TexCoord0,TexCoord1, TexCoord2;"
         "attribute vec4 MultiTexCoord0,MultiTexCoord1,MultiTexCoord2;"
         "attribute vec4 VertexPosition;"
         "void main() {"
@@ -237,6 +239,7 @@ static void BuildYUVFragmentShader(vout_display_opengl_t *vgl,
     /* Basic linear YUV -> RGB conversion using bilinear interpolation */
     const char *template_glsl_yuv =
         "#version " GLSL_VERSION "\n"
+        PRECISION
         "uniform sampler2D Texture0;"
         "uniform sampler2D Texture1;"
         "uniform sampler2D Texture2;"
@@ -281,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 " GLSL_VERSION "\n"
+        PRECISION
         "uniform sampler2D Texture[3];"
         "varying vec4 TexCoord0,TexCoord1,TexCoord2;"
         "void main()"
@@ -297,6 +302,7 @@ 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)
@@ -304,6 +310,7 @@ static void BuildRGBAFragmentShader(vout_display_opengl_t *vgl,
     // Simple shader for RGBA
     const char *code =
         "#version " GLSL_VERSION "\n"
+        PRECISION
         "uniform sampler2D Texture;"
         "uniform vec4 FillColor;"
         "varying vec4 TexCoord0;"
@@ -342,10 +349,6 @@ 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->CreateShader  = (PFNGLCREATESHADERPROC)vlc_gl_GetProcAddress(vgl->gl, "glCreateShader");
@@ -379,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;
@@ -401,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);
@@ -455,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]);
 
@@ -647,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;
@@ -710,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]);
@@ -726,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]);