[vlc-devel] [PATCH 1/3] opengl: Use GLSL 1.2 shaders instead of arb extension

Ilkka Ollakka ileoo at videolan.org
Sat May 5 11:37:06 CEST 2012


Use VBO/VAO as most of the coordinates we use, are static and no need to push them
again in every frame.

OpenGL and OpenGL ES 2.0 support vbo/vao and GLSL shaders, so we can use same
shader codes in both and we can cope with just using core specifications without
extensions.

Use uniform in shaders instead of glColor for transparency

Currently problematic case is unsupported ROW_UNPACK_LENGTH in ES 2.0, which is
used to unpack YUV to separated texture planes. This can be worked around, but
have not yet tested it yet. GLSL 1.2 is used in shader code, which should work in most
reasonably modern linux distributions and in ES 2.0
---
 modules/video_output/opengl.c |  618 +++++++++++++++++++++++++----------------
 modules/video_output/opengl.h |    1 +
 2 files changed, 386 insertions(+), 233 deletions(-)

diff --git a/modules/video_output/opengl.c b/modules/video_output/opengl.c
index 1b5384b..edfa1e1 100644
--- a/modules/video_output/opengl.c
+++ b/modules/video_output/opengl.c
@@ -36,16 +36,6 @@
 #include "opengl.h"
 // Define USE_OPENGL_ES to the GL ES Version you want to select
 
-#ifdef __APPLE__
-# define PFNGLGENPROGRAMSARBPROC              typeof(glGenProgramsARB)*
-# define PFNGLBINDPROGRAMARBPROC              typeof(glBindProgramARB)*
-# define PFNGLPROGRAMSTRINGARBPROC            typeof(glProgramStringARB)*
-# define PFNGLDELETEPROGRAMSARBPROC           typeof(glDeleteProgramsARB)*
-# define PFNGLPROGRAMLOCALPARAMETER4FVARBPROC typeof(glProgramLocalParameter4fvARB)*
-# define PFNGLACTIVETEXTUREPROC               typeof(glActiveTexture)*
-# define PFNGLCLIENTACTIVETEXTUREPROC         typeof(glClientActiveTexture)*
-#endif
-
 /* RV16 */
 #ifndef GL_UNSIGNED_SHORT_5_6_5
 # define GL_UNSIGNED_SHORT_5_6_5 0x8363
@@ -54,6 +44,42 @@
 # define GL_CLAMP_TO_EDGE 0x812F
 #endif
 
+#ifdef __APPLE__
+#   define PFNGLBINDVERTEXARRAYPROC          typeof(glBindVertexArrayAPPLE)*
+#   define PFNGLDELETEVERTEXARRAYSPROC       typeof(glDeleteVertexArraysAPPLE)*
+#   define PFNGLGENVERTEXARRAYSPROC          typeof(glGenVertexArraysAPPLE)*
+#   define PFNGLGENBUFFERSPROC               typeof(glGenBuffers)*
+#   define PFNGLBINDBUFFERPROC               typeof(glBindBuffer)*
+#   define PFNGLDELETEBUFFERSPROC            typeof(glDeleteBuffers)*
+#   define PFNGLBUFFERSUBDATAPROC            typeof(glBufferSubData)*
+#   define PFNGLBUFFERDATAPROC               typeof(glBufferData)*
+#   define PFNGLENABLEVERTEXATTRIBARRAYPROC  typeof(glEnableVertexAttribArray)*
+#   define PFNGLVERTEXATTRIBPOINTERPROC      typeof(glVertexAttribPointer)*
+#   define PFNGLGETPROGRAMIVPROC             typeof(glGetProgramiv)*
+#   define PFNGLGETPROGRAMINFOLOGPROC        typeof(glGetProgramInfoLog)*
+#   define PFNGLGETSHADERIVPROC              typeof(glGetShaderiv)*
+#   define PFNGLGETSHADERINFOLOGPROC         typeof(glGetShaderInfoLog)*
+#   define PFNGLGETUNIFORMLOCATIONPROC       typeof(glGetUniformLocation)*
+#   define PFNGLGETATTRIBLOCATIONPROC        typeof(glGetAttribLocation)*
+#   define PFNGLUNIFORM4FVPROC               typeof(glUniform4fv)*
+#   define PFNGLUNIFORM4FPROC                typeof(glUniform4f)*
+#   define PFNGLUNIFORM1IVPROC               typeof(glUniform1iv)*
+#   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 PFNGLUSEPROGRAMPROC               typeof(glUseProgram)*
+#   define PFNGLDELETEPROGRAMPROC            typeof(glDeleteProgram)*
+#   define PFNGLATTACHSHADERPROC             typeof(glAttachShader)*
+#elif USE_OPENGL_ES
+#   define PFNGLBINDVERTEXARRAYPROC          typeof(glBindVertexArrayOES)*
+#   define PFNGLDELETEVERTEXARRAYSPROC       typeof(glDeleteVertexArraysEOS)*
+#   define PFNGLGENVERTEXARRAYSPROC          typeof(glGenVertexArraysEOS)*
+#endif
+
 #if USE_OPENGL_ES
 #   define VLCGL_TEXTURE_COUNT 1
 #   define VLCGL_PICTURE_MAX 1
@@ -104,21 +130,60 @@ struct vout_display_opengl_t {
 
     picture_pool_t *pool;
 
-    GLuint     program;
+    /* index 0 for normal and 1 for subtitle overlay */
+    GLuint     program[2];
+    GLuint     shader[2];
+    GLuint     vao[2];
+    GLuint     buffers[2][2];
     int        local_count;
-    GLfloat    local_value[16][4];
+    GLfloat    local_value[16];
+
+    /* VAO stuff in opengl ES 2.0 are behind OES mandatory extension */
+    PFNGLBINDVERTEXARRAYPROC   BindVertexArray;
+    PFNGLGENVERTEXARRAYSPROC    GenVertexArrays;
+    PFNGLDELETEVERTEXARRAYSPROC DeleteVertexArrays;
+
+    /* Buffer commands */
+    PFNGLGENBUFFERSPROC   GenBuffers;
+    PFNGLBINDBUFFERPROC   BindBuffer;
+    PFNGLDELETEBUFFERSPROC DeleteBuffers;
+    PFNGLBUFFERSUBDATAPROC BufferSubData;
+
+    PFNGLBUFFERDATAPROC   BufferData;
+
+    /* Vertex Array commands*/
+    PFNGLENABLEVERTEXATTRIBARRAYPROC EnableVertexAttribArray;
+    PFNGLVERTEXATTRIBPOINTERPROC VertexAttribPointer;
+
+    PFNGLGETPROGRAMIVPROC  GetProgramiv;
+    PFNGLGETPROGRAMINFOLOGPROC GetProgramInfoLog;
+    PFNGLGETSHADERIVPROC   GetShaderiv;
+    PFNGLGETSHADERINFOLOGPROC GetShaderInfoLog;
+
+    PFNGLGETUNIFORMLOCATIONPROC GetUniformLocation;
+    PFNGLGETATTRIBLOCATIONPROC  GetAttribLocation;
+
+    PFNGLUNIFORM4FVPROC   Uniform4fv;
+    PFNGLUNIFORM4FPROC    Uniform4f;
+    PFNGLUNIFORM1IVPROC   Uniform1iv;
+
+    /* Shader command */
+    PFNGLCREATESHADERPROC CreateShader;
+    PFNGLSHADERSOURCEPROC ShaderSource;
+    PFNGLCOMPILESHADERPROC CompileShader;
+    PFNGLDETACHSHADERPROC   DetachShader;
+    PFNGLDELETESHADERPROC   DeleteShader;
+
+    PFNGLCREATEPROGRAMPROC CreateProgram;
+    PFNGLLINKPROGRAMPROC   LinkProgram;
+    PFNGLUSEPROGRAMPROC    UseProgram;
+    PFNGLDELETEPROGRAMPROC DeleteProgram;
+
+    PFNGLATTACHSHADERPROC  AttachShader;
 
-    /* fragment_program */
-    PFNGLGENPROGRAMSARBPROC              GenProgramsARB;
-    PFNGLBINDPROGRAMARBPROC              BindProgramARB;
-    PFNGLPROGRAMSTRINGARBPROC            ProgramStringARB;
-    PFNGLDELETEPROGRAMSARBPROC           DeleteProgramsARB;
-    PFNGLPROGRAMLOCALPARAMETER4FVARBPROC ProgramLocalParameter4fvARB;
 
     /* multitexture */
     bool use_multitexture;
-    PFNGLACTIVETEXTUREPROC   ActiveTexture;
-    PFNGLCLIENTACTIVETEXTUREPROC ClientActiveTexture;
 };
 
 static inline int GetAlignedSize(unsigned size)
@@ -158,46 +223,10 @@ vout_display_opengl_t *vout_display_opengl_New(video_format_t *fmt,
         return NULL;
     }
 
-    const char *extensions = (const char *)glGetString(GL_EXTENSIONS);
-
     /* Load extensions */
-    bool supports_fp = false;
-    if (HasExtension(extensions, "GL_ARB_fragment_program")) {
-#if !defined(MACOS_OPENGL)
-        vgl->GenProgramsARB    = (PFNGLGENPROGRAMSARBPROC)vlc_gl_GetProcAddress(vgl->gl, "glGenProgramsARB");
-        vgl->BindProgramARB    = (PFNGLBINDPROGRAMARBPROC)vlc_gl_GetProcAddress(vgl->gl, "glBindProgramARB");
-        vgl->ProgramStringARB  = (PFNGLPROGRAMSTRINGARBPROC)vlc_gl_GetProcAddress(vgl->gl, "glProgramStringARB");
-        vgl->DeleteProgramsARB = (PFNGLDELETEPROGRAMSARBPROC)vlc_gl_GetProcAddress(vgl->gl, "glDeleteProgramsARB");
-        vgl->ProgramLocalParameter4fvARB = (PFNGLPROGRAMLOCALPARAMETER4FVARBPROC)vlc_gl_GetProcAddress(vgl->gl, "glProgramLocalParameter4fvARB");
-#else
-        vgl->GenProgramsARB = glGenProgramsARB;
-        vgl->BindProgramARB = glBindProgramARB;
-        vgl->ProgramStringARB = glProgramStringARB;
-        vgl->DeleteProgramsARB = glDeleteProgramsARB;
-        vgl->ProgramLocalParameter4fvARB = glProgramLocalParameter4fvARB;
-#endif
-        supports_fp = vgl->GenProgramsARB &&
-                      vgl->BindProgramARB &&
-                      vgl->ProgramStringARB &&
-                      vgl->DeleteProgramsARB &&
-                      vgl->ProgramLocalParameter4fvARB;
-    }
-
-    bool supports_multitexture = false;
+    bool supports_fp = true;
     GLint max_texture_units = 0;
-    if (HasExtension(extensions, "GL_ARB_multitexture")) {
-#if !defined(MACOS_OPENGL)
-        vgl->ActiveTexture   = (PFNGLACTIVETEXTUREPROC)vlc_gl_GetProcAddress(vgl->gl, "glActiveTexture");
-        vgl->ClientActiveTexture = (PFNGLCLIENTACTIVETEXTUREPROC)vlc_gl_GetProcAddress(vgl->gl, "glClientActiveTexture");
-#else
-        vgl->ActiveTexture = glActiveTexture;
-        vgl->ClientActiveTexture = glClientActiveTexture;
-#endif
-        supports_multitexture = vgl->ActiveTexture &&
-                                vgl->ClientActiveTexture;
-        if (supports_multitexture)
-            glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &max_texture_units);
-    }
+    glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &max_texture_units);
 
     /* Initialize with default chroma */
     vgl->fmt = *fmt;
@@ -235,7 +264,7 @@ 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 (supports_fp && supports_multitexture && max_texture_units >= 3 &&
+    if ( max_texture_units >= 3 &&
         vlc_fourcc_IsYUV(fmt->i_chroma) && !vlc_fourcc_IsYUV(vgl->fmt.i_chroma)) {
         const vlc_fourcc_t *list = vlc_fourcc_GetYUVFallback(fmt->i_chroma);
         while (*list) {
@@ -264,111 +293,288 @@ vout_display_opengl_t *vout_display_opengl_New(video_format_t *fmt,
         }
     }
 
+/*
+#if USE_OPENGL_ES
+    vgl->BindVertexArray   = (PFNGLBINDVERTEXARRAYPROC)vlc_gl_GetProcAddress(vgl->gl, "glBindVertexArrayOES");
+    vgl->GenVertexArrays    = (PFNGLGENVERTEXARRAYSPROC)vlc_gl_GetProcAddress(vgl->gl, "glGenVertexArraysOES");
+    vgl->DeleteVertexArrays = (PFNGLDELETEVERTEXARRAYSPROC)vlc_gl_GetProcAddress(vgl->gl, "glDeleteVertexArraysOES");
+    */
+#ifdef __APPLE__
+    vgl->BindVertexArray   = (PFNGLBINDVERTEXARRAYPROC)vlc_gl_GetProcAddress(vgl->gl, "glBindVertexArrayAPPLE");
+    vgl->GenVertexArrays    = (PFNGLGENVERTEXARRAYSPROC)vlc_gl_GetProcAddress(vgl->gl, "glGenVertexArraysAPPLE");
+    vgl->DeleteVertexArrays = (PFNGLDELETEVERTEXARRAYSPROC)vlc_gl_GetProcAddress(vgl->gl, "glDeleteVertexArraysAPPLE");
+#else
+    vgl->BindVertexArray   = (PFNGLBINDVERTEXARRAYPROC)vlc_gl_GetProcAddress(vgl->gl, "glBindVertexArray");
+    vgl->GenVertexArrays    = (PFNGLGENVERTEXARRAYSPROC)vlc_gl_GetProcAddress(vgl->gl, "glGenVertexArrays");
+    vgl->DeleteVertexArrays = (PFNGLDELETEVERTEXARRAYSPROC)vlc_gl_GetProcAddress(vgl->gl, "glDeleteVertexArrays");
+#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->EnableVertexAttribArray = (PFNGLENABLEVERTEXATTRIBARRAYPROC)vlc_gl_GetProcAddress(vgl->gl, "glEnableVertexAttribArray");
+    vgl->VertexAttribPointer = (PFNGLVERTEXATTRIBPOINTERPROC)vlc_gl_GetProcAddress(vgl->gl, "glVertexAttribPointer");
+
+    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");
+    vgl->AttachShader  = (PFNGLATTACHSHADERPROC)vlc_gl_GetProcAddress(vgl->gl, "glAttachShader");
+    vgl->GetProgramiv   = (PFNGLGETPROGRAMIVPROC)vlc_gl_GetProcAddress(vgl->gl, "glGetProgramiv");
+    vgl->GetProgramInfoLog   = (PFNGLGETPROGRAMINFOLOGPROC)vlc_gl_GetProcAddress(vgl->gl, "glGetProgramInfoLog");
+    vgl->GetShaderiv   = (PFNGLGETSHADERIVPROC)vlc_gl_GetProcAddress(vgl->gl, "glGetShaderiv");
+    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");
+    vgl->GetAttribLocation  = (PFNGLGETATTRIBLOCATIONPROC)vlc_gl_GetProcAddress(vgl->gl, "glGetAttribLocation");
+    vgl->Uniform4fv    = (PFNGLUNIFORM4FVPROC)vlc_gl_GetProcAddress(vgl->gl,"glUniform4fv");
+    vgl->Uniform4f     = (PFNGLUNIFORM4FPROC)vlc_gl_GetProcAddress(vgl->gl,"glUniform4f");
+    vgl->Uniform1iv    = (PFNGLUNIFORM1IVPROC)vlc_gl_GetProcAddress(vgl->gl,"glUniform1iv");
+
+    vgl->CreateProgram = (PFNGLCREATEPROGRAMPROC)vlc_gl_GetProcAddress(vgl->gl, "glCreateProgram");
+    vgl->LinkProgram = (PFNGLLINKPROGRAMPROC)vlc_gl_GetProcAddress(vgl->gl, "glLinkProgram");
+    vgl->UseProgram = (PFNGLUSEPROGRAMPROC)vlc_gl_GetProcAddress(vgl->gl, "glUseProgram");
+    vgl->DeleteProgram = (PFNGLDELETEPROGRAMPROC)vlc_gl_GetProcAddress(vgl->gl, "glDeleteProgram");
+
     vgl->chroma = vlc_fourcc_GetChromaDescription(vgl->fmt.i_chroma);
     vgl->use_multitexture = vgl->chroma->plane_count > 1;
 
-    bool supports_npot = false;
-#if USE_OPENGL_ES == 2
-    supports_npot = true;
-#else
-    supports_npot |= HasExtension(extensions, "GL_APPLE_texture_2D_limited_npot") ||
-                     HasExtension(extensions, "GL_ARB_texture_non_power_of_two");
-#endif
 
     /* Texture size */
     for (unsigned j = 0; j < vgl->chroma->plane_count; j++) {
         int w = vgl->fmt.i_width  * vgl->chroma->p[j].w.num / vgl->chroma->p[j].w.den;
         int h = vgl->fmt.i_height * vgl->chroma->p[j].h.num / vgl->chroma->p[j].h.den;
-        if (supports_npot) {
-            vgl->tex_width[j]  = w;
-            vgl->tex_height[j] = h;
-        }
-        else {
-            /* A texture must have a size aligned on a power of 2 */
-            vgl->tex_width[j]  = GetAlignedSize(w);
-            vgl->tex_height[j] = GetAlignedSize(h);
-        }
+        vgl->tex_width[j]  = w;
+        vgl->tex_height[j] = h;
     }
 
     /* Build fragment program if needed */
-    vgl->program = 0;
+    vgl->program[0] = 0;
+    vgl->program[1] = 0;
     vgl->local_count = 0;
     if (supports_fp) {
         char *code = NULL;
 
-        if (need_fs_yuv) {
             /* [R/G/B][Y U V O] from TV range to full range
              * XXX we could also do hue/brightness/constrast/gamma
              * by simply changing the coefficients
              */
-            const float matrix_bt601_tv2full[3][4] = {
-                { 1.164383561643836,  0.0000,             1.596026785714286, -0.874202217873451 },
-                { 1.164383561643836, -0.391762290094914, -0.812967647237771,  0.531667823499146 },
-                { 1.164383561643836,  2.017232142857142,  0.0000,            -1.085630789302022 },
+            const float matrix_bt601_tv2full[12] = {
+                 1.164383561643836,  0.0000,             1.596026785714286, -0.874202217873451 ,
+                 1.164383561643836, -0.391762290094914, -0.812967647237771,  0.531667823499146 ,
+                 1.164383561643836,  2.017232142857142,  0.0000,            -1.085630789302022 ,
             };
-            const float matrix_bt709_tv2full[3][4] = {
-                { 1.164383561643836,  0.0000,             1.792741071428571, -0.972945075016308 },
-                { 1.164383561643836, -0.21324861427373,  -0.532909328559444,  0.301482665475862 },
-                { 1.164383561643836,  2.112401785714286,  0.0000,            -1.133402217873451 },
+            const float matrix_bt709_tv2full[12] = {
+                 1.164383561643836,  0.0000,             1.792741071428571, -0.972945075016308 ,
+                 1.164383561643836, -0.21324861427373,  -0.532909328559444,  0.301482665475862 ,
+                 1.164383561643836,  2.112401785714286,  0.0000,            -1.133402217873451 ,
             };
-            const float (*matrix)[4] = fmt->i_height > 576 ? matrix_bt709_tv2full
+            const float (*matrix) = fmt->i_height > 576 ? matrix_bt709_tv2full
                                                            : matrix_bt601_tv2full;
 
             /* Basic linear YUV -> RGB conversion using bilinear interpolation */
-            const char *template_yuv =
-                "!!ARBfp1.0"
-                "OPTION ARB_precision_hint_fastest;"
-
-                "TEMP src;"
-                "TEX src.x,  fragment.texcoord[0], texture[0], 2D;"
-                "TEX src.%c, fragment.texcoord[1], texture[1], 2D;"
-                "TEX src.%c, fragment.texcoord[2], texture[2], 2D;"
-
-                "PARAM coefficient[4] = { program.local[0..3] };"
-
-                "TEMP tmp;"
-                "MAD  tmp.rgb,          src.xxxx, coefficient[0], coefficient[3];"
-                "MAD  tmp.rgb,          src.yyyy, coefficient[1], tmp;"
-                "MAD  result.color.rgb, src.zzzz, coefficient[2], tmp;"
-                "END";
+            const char *template_glsl_yuv =
+                "#version 120\n"
+                "uniform sampler2D Texture[3];"
+                "uniform vec4      coefficient[4];"
+                "varying vec4 textureCoordinates0;"
+                "varying vec4 textureCoordinates1;"
+                "varying vec4 textureCoordinates2;"
+
+                "void main(void) {"
+                " vec4 x,y,z,result;"
+                " x  = texture2D(Texture[0], textureCoordinates0.st);"
+                " %c = texture2D(Texture[1], textureCoordinates1.st);"
+                " %c = texture2D(Texture[2], textureCoordinates2.st);"
+
+                " result = x * coefficient[0] + coefficient[3];"
+                " result = (y * coefficient[1]) + result;"
+                " result = (z * coefficient[2]) + result;"
+                " gl_FragColor = result;"
+                "}";
             bool swap_uv = vgl->fmt.i_chroma == VLC_CODEC_YV12 ||
                            vgl->fmt.i_chroma == VLC_CODEC_YV9;
-            if (asprintf(&code, template_yuv,
+            if (asprintf(&code, template_glsl_yuv,
                          swap_uv ? 'z' : 'y',
                          swap_uv ? 'y' : 'z') < 0)
                 code = NULL;
 
             for (int i = 0; i < 4; i++) {
                 float correction = i < 3 ? yuv_range_correction : 1.0;
-                for (int j = 0; j < 4; j++) {
-                    vgl->local_value[vgl->local_count + i][j] = j < 3 ? correction * matrix[j][i] : 0.0;
-                }
+                /* We place coefficient values for coefficient[4] in one array from matrix values.
+                   Notice that we fill values from top down instead of left to right.*/
+                for( int j = 0; j < 4; j++ )
+                    vgl->local_value[vgl->local_count + i*4+j] = j < 3 ? correction * matrix[j*4+i] : 0.0 ;
             }
             vgl->local_count += 4;
-        }
-        if (code) {
-        // Here you have shaders
-            vgl->GenProgramsARB(1, &vgl->program);
-            vgl->BindProgramARB(GL_FRAGMENT_PROGRAM_ARB, vgl->program);
-            vgl->ProgramStringARB(GL_FRAGMENT_PROGRAM_ARB,
-                                  GL_PROGRAM_FORMAT_ASCII_ARB,
-                                  strlen(code), (const GLbyte*)code);
-            if (glGetError() == GL_INVALID_OPERATION) {
-                /* FIXME if the program was needed for YUV, the video will be broken */
-#if 0
-                GLint position;
-                glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &position);
-
-                const char *msg = (const char *)glGetString(GL_PROGRAM_ERROR_STRING_ARB);
-                fprintf(stderr, "GL_INVALID_OPERATION: error at %d: %s\n", position, msg);
-#endif
-                vgl->DeleteProgramsARB(1, &vgl->program);
-                vgl->program = 0;
+
+            // Basic vertex shader that we use in both cases
+            const char *vertexShader =
+            "#version 120\n"
+            "varying vec4 textureCoordinates0;"
+            "varying vec4 textureCoordinates1;"
+            "varying vec4 textureCoordinates2;"
+            "attribute vec4 textureC0;"
+            "attribute vec4 textureC1;"
+            "attribute vec4 textureC2;"
+            "attribute vec4 positionCoordinate;"
+            "void main() {"
+            " textureCoordinates0 = textureC0;"
+            " textureCoordinates1 = textureC1;"
+            " textureCoordinates2 = textureC2;"
+            " gl_Position = positionCoordinate; }";
+
+            // Dummy shader for text overlay
+            const char *helloShader =
+            "#version 120\n"
+            "uniform sampler2D Texture;"
+            "uniform vec4 fillColor;"
+            "varying vec4 textureCoordinates0;"
+            "varying vec4 textureCoordinates1;"
+            "varying vec4 textureCoordinates2;"
+            "void main()"
+            "{ vec4 dummy = textureCoordinates1*textureCoordinates2;"
+            "  gl_FragColor = texture2D(Texture, textureCoordinates0.st)*fillColor;}";
+
+            GLint vertexShaderId = vgl->CreateShader( GL_VERTEX_SHADER );
+            vgl->ShaderSource( vertexShaderId, 1, (const GLchar **)&vertexShader, NULL);
+            vgl->CompileShader( vertexShaderId );
+
+            /* Create 'dummy' shader that handles subpicture overlay for now*/
+            vgl->shader[1] = vgl->CreateShader( GL_FRAGMENT_SHADER );
+            vgl->ShaderSource( vgl->shader[1], 1, &helloShader, NULL);
+            vgl->CompileShader( vgl->shader[1] );
+            vgl->program[1] = vgl->CreateProgram();
+            vgl->AttachShader( vgl->program[1], vgl->shader[1]);
+            vgl->AttachShader( vgl->program[1], vertexShaderId );
+            vgl->LinkProgram( vgl->program[1] );
+
+            // Create shader from code
+            vgl->shader[0] = vgl->CreateShader( GL_FRAGMENT_SHADER );
+            vgl->program[0] = vgl->CreateProgram();
+            if( need_fs_yuv )
+            {
+                vgl->ShaderSource( vgl->shader[0], 1, (const GLchar **)&code, NULL );
+                vgl->CompileShader( vgl->shader[0]);
+                vgl->AttachShader( vgl->program[0], vgl->shader[0] );
+            } else {
+                /* Use simpler shader if we don't need to to yuv -> rgb,
+                   for example when input is allready rgb (.bmp image).*/
+                vgl->AttachShader( vgl->program[0], vgl->shader[1] );
             }
+            vgl->AttachShader( vgl->program[0], vertexShaderId );
+
+            vgl->LinkProgram( vgl->program[0] );
+
             free(code);
-        }
+
+
+            for( GLuint i = 0; i < 2; i++ )
+            {
+                int infoLength = 0;
+                int charsWritten = 0;
+                char *infolog;
+                vgl->GetProgramiv( vgl->program[i], GL_INFO_LOG_LENGTH, &infoLength );
+                if( infoLength > 1 )
+                {
+                    /* If there is some message, better to check linking is ok */
+                    GLint link_status = GL_TRUE;
+                    vgl->GetProgramiv( vgl->program[i], GL_LINK_STATUS, &link_status );
+
+                    infolog = (char *)malloc(infoLength);
+                    vgl->GetProgramInfoLog( vgl->program[i], infoLength, &charsWritten, infolog );
+                    msg_Dbg( vgl->gl, "shader program %d:%s %d",i,infolog,infoLength);
+                    free(infolog);
+
+                    /* Check shaders messages too */
+                    for( GLuint j = 0; j < 2; j++ )
+                    {
+                        vgl->GetShaderiv( vgl->shader[j], GL_INFO_LOG_LENGTH, &infoLength );
+                        if( infoLength > 1 )
+                        {
+                            infolog = (char *)malloc(infoLength);
+                            vgl->GetShaderInfoLog( vgl->shader[j], infoLength, &charsWritten, infolog );
+                            msg_Dbg( vgl->gl, "shader %d: %s\n",j,infolog );
+                            free( infolog );
+                        }
+                    }
+
+                    if( link_status == GL_FALSE )
+                    {
+                        msg_Err( vgl->gl, "Unable to use program %d", i );
+                        free( vgl );
+                        return NULL;
+                    }
+                }
+            }
+
+            vgl->UseProgram( vgl->program[0] );
+
+            // Generate VAO
+            vgl->GenVertexArrays(2, vgl->vao );
+            vgl->BindVertexArray( vgl->vao[0] );
+
+            //Bind coefficient values to shader doing yuv->rgb
+            GLint dataLocation = vgl->GetUniformLocation( vgl->program[0], "coefficient" );
+            vgl->Uniform4fv( dataLocation, vgl->local_count, vgl->local_value );
+
+            // Tell shader to use textureUnits 0,1,2
+            GLint texturelocation = vgl->GetUniformLocation( vgl->program[0], "Texture");
+            const GLint textureUnits[] = {0,1,2};
+            vgl->Uniform1iv( texturelocation, 3, textureUnits );
+
+            //0 for vertex coordinates and 1 for texture coordinates
+            vgl->GenBuffers(2, vgl->buffers[0] );
+
+             const GLfloat vertexCoord[] = {
+                 -1.0, 1.0,
+                 -1.0, -1.0,
+                  1.0, 1.0,
+                  1.0, -1.0,
+             };
+
+            vgl->BindBuffer( GL_ARRAY_BUFFER, vgl->buffers[0][0]);
+            vgl->BufferData( GL_ARRAY_BUFFER, sizeof(vertexCoord), vertexCoord, GL_STATIC_DRAW );
+            GLint vertexlocation = vgl->GetAttribLocation( vgl->program[0], "positionCoordinate");
+            vgl->EnableVertexAttribArray( vertexlocation ); //In vertex shader location 0 is vertex coordinates
+            vgl->VertexAttribPointer(vertexlocation, 2, GL_FLOAT, 0, 0, NULL);
+
+            vgl->BindBuffer( GL_ARRAY_BUFFER, vgl->buffers[0][1]); // Make room for texture coordinates
+            vgl->BufferData( GL_ARRAY_BUFFER, sizeof(vertexCoord)*3, NULL, GL_STREAM_DRAW );
+            vgl->EnableVertexAttribArray( vgl->GetAttribLocation( vgl->program[0], "textureC0"));
+            vgl->EnableVertexAttribArray( vgl->GetAttribLocation( vgl->program[0], "textureC1"));
+            vgl->EnableVertexAttribArray( vgl->GetAttribLocation( vgl->program[0], "textureC2"));
+            vgl->VertexAttribPointer( vgl->GetAttribLocation( vgl->program[0], "textureC0"), 2, GL_FLOAT, 0, 0, NULL);
+            vgl->VertexAttribPointer( vgl->GetAttribLocation( vgl->program[0], "textureC1"), 2, GL_FLOAT, 0, 0, (void *)sizeof(vertexCoord));
+            vgl->VertexAttribPointer( vgl->GetAttribLocation( vgl->program[0], "textureC2"), 2, GL_FLOAT, 0, 0, (void *)(2*sizeof(vertexCoord)));
+
+            vgl->BindVertexArray( vgl->vao[1] );
+            vgl->GenBuffers(2, vgl->buffers[1] );
+
+            vgl->BindBuffer( GL_ARRAY_BUFFER, vgl->buffers[1][1]);
+
+            const GLfloat textureCoord[] = {
+                 0.0, 0.0,
+                 0.0, 1.0,
+                 1.0, 0.0,
+                 1.0, 1.0,
+            };
+
+            vgl->BufferData( GL_ARRAY_BUFFER, sizeof(textureCoord), textureCoord, GL_STATIC_DRAW );
+            vgl->EnableVertexAttribArray( vgl->GetAttribLocation( vgl->program[1], "textureC0") );
+            vgl->VertexAttribPointer( vgl->GetAttribLocation( vgl->program[1], "textureC0"), 2, GL_FLOAT, 0, 0, NULL);
+
+            vgl->BindBuffer( GL_ARRAY_BUFFER, vgl->buffers[1][0] );
+            vgl->BufferData( GL_ARRAY_BUFFER, sizeof(textureCoord), NULL, GL_STREAM_DRAW );
+            vgl->EnableVertexAttribArray( vgl->GetAttribLocation( vgl->program[1], "positionCoordinate") );
+            vgl->VertexAttribPointer( vgl->GetAttribLocation( vgl->program[1], "positionCoordinate") , 2, GL_FLOAT, 0, 0, NULL);
     }
 
+
     /* */
     glDisable(GL_BLEND);
     glDisable(GL_DEPTH_TEST);
@@ -390,11 +596,7 @@ vout_display_opengl_t *vout_display_opengl_New(video_format_t *fmt,
 
     *fmt = vgl->fmt;
     if (subpicture_chromas) {
-        *subpicture_chromas = NULL;
-#if !USE_OPENGL_ES
-        if (supports_npot)
-            *subpicture_chromas = gl_subpicture_chromas;
-#endif
+        *subpicture_chromas = gl_subpicture_chromas;
     }
     return vgl;
 }
@@ -414,8 +616,17 @@ void vout_display_opengl_Delete(vout_display_opengl_t *vgl)
         }
         free(vgl->region);
 
-        if (vgl->program)
-            vgl->DeleteProgramsARB(1, &vgl->program);
+        if (vgl->program[0])
+        {
+            for( int i = 0; i < 2; i++ )
+            {
+                vgl->DetachShader( vgl->program[i], vgl->shader[i] );
+                vgl->DeleteShader( vgl->shader[i] );
+                vgl->DeleteProgram( vgl->program[i] );
+                vgl->DeleteBuffers(2, vgl->buffers[i]);
+            }
+            vgl->DeleteVertexArrays(2, vgl->vao );
+        }
 
         vlc_gl_Unlock(vgl->gl);
     }
@@ -454,19 +665,15 @@ picture_pool_t *vout_display_opengl_GetPool(vout_display_opengl_t *vgl, unsigned
     if (vlc_gl_Lock(vgl->gl))
         return vgl->pool;
 
+
+
     for (int i = 0; i < VLCGL_TEXTURE_COUNT; i++) {
         glGenTextures(vgl->chroma->plane_count, vgl->texture[i]);
         for (unsigned j = 0; j < vgl->chroma->plane_count; j++) {
             if (vgl->use_multitexture)
-                vgl->ActiveTexture(GL_TEXTURE0 + j);
+                glActiveTexture(GL_TEXTURE0 + j);
             glBindTexture(vgl->tex_target, vgl->texture[i][j]);
 
-#if !USE_OPENGL_ES
-            /* Set the texture parameters */
-            glTexParameterf(vgl->tex_target, GL_TEXTURE_PRIORITY, 1.0);
-            glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
-#endif
-
             glTexParameteri(vgl->tex_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
             glTexParameteri(vgl->tex_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
             glTexParameteri(vgl->tex_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
@@ -514,7 +721,7 @@ int vout_display_opengl_Prepare(vout_display_opengl_t *vgl,
     /* Update the texture */
     for (unsigned j = 0; j < vgl->chroma->plane_count; j++) {
         if (vgl->use_multitexture)
-            vgl->ActiveTexture(GL_TEXTURE0 + j);
+            glActiveTexture(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,
@@ -540,7 +747,7 @@ int vout_display_opengl_Prepare(vout_display_opengl_t *vgl,
         vgl->region       = calloc(count, sizeof(*vgl->region));
 
         if (vgl->use_multitexture)
-            vgl->ActiveTexture(GL_TEXTURE0 + 0);
+            glActiveTexture(GL_TEXTURE0 + 0);
         int i = 0;
         for (subpicture_region_t *r = subpicture->p_region; r; r = r->p_next, i++) {
             gl_region_t *glr = &vgl->region[i];
@@ -640,48 +847,11 @@ int vout_display_opengl_Display(vout_display_opengl_t *vgl,
 
     glClear(GL_COLOR_BUFFER_BIT);
 
-    if (vgl->program) {
-        glEnable(GL_FRAGMENT_PROGRAM_ARB);
-        for (int i = 0; i < vgl->local_count; i++)
-            vgl->ProgramLocalParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, i, vgl->local_value[i]);
-    } else {
-        glEnable(vgl->tex_target);
-    }
-
-#if USE_OPENGL_ES
-    static const GLfloat vertexCoord[] = {
-        -1.0f, -1.0f,
-         1.0f, -1.0f,
-        -1.0f,  1.0f,
-         1.0f,  1.0f,
-    };
-
-    const GLfloat textureCoord[8] = {
-        left[0],  bottom[0],
-        right[0], bottom[0],
-        left[0],  top[0],
-        right[0], top[0]
-    };
-
-    glEnableClientState(GL_VERTEX_ARRAY);
-    glEnableClientState(GL_TEXTURE_COORD_ARRAY);
-    glVertexPointer(2, GL_FLOAT, 0, vertexCoord);
-    glTexCoordPointer(2, GL_FLOAT, 0, textureCoord);
-
-    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
-
-    glDisableClientState(GL_TEXTURE_COORD_ARRAY);
-    glDisableClientState(GL_VERTEX_ARRAY);
-    glDisable(vgl->tex_target);
-#else
-
-    const GLfloat vertexCoord[] = {
-        -1.0, 1.0,
-        -1.0, -1.0,
-        1.0, 1.0,
-        1.0, -1.0,
-    };
+    /* Program 0 is for yuv2rgb translation */
+    vgl->UseProgram( vgl->program[0] );
+    vgl->BindVertexArray( vgl->vao[0] );
 
+    vgl->BindBuffer( GL_ARRAY_BUFFER, vgl->buffers[0][1] );
     for( unsigned j = 0; j < vgl->chroma->plane_count; j++)
     {
         const GLfloat texCoord[] = {
@@ -690,64 +860,46 @@ int vout_display_opengl_Display(vout_display_opengl_t *vgl,
             right[j], top[j],
             right[j], bottom[j],
         };
-        vgl->ActiveTexture( GL_TEXTURE0+j);
-        vgl->ClientActiveTexture( GL_TEXTURE0+j);
-        glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+        glActiveTexture( GL_TEXTURE0+j);
         glBindTexture(vgl->tex_target, vgl->texture[0][j]);
-        glTexCoordPointer(2, GL_FLOAT, 0, texCoord);
+        /* We use one buffer for texture coordinates for all textures */
+        vgl->BufferSubData( GL_ARRAY_BUFFER, sizeof(texCoord)*j, sizeof(texCoord), texCoord);
     }
-    glEnableClientState(GL_VERTEX_ARRAY);
-    glVertexPointer(2, GL_FLOAT, 0, vertexCoord);
+    /* Switch back to texture 0 and do the drawing */
+    glActiveTexture( GL_TEXTURE0);
+
     glDrawArrays( GL_TRIANGLE_STRIP, 0, 4);
-    glDisableClientState(GL_VERTEX_ARRAY);
 
-    for( int j = vgl->chroma->plane_count; j >= 0;j--)
+    if(vgl->region_count )
     {
-        vgl->ActiveTexture( GL_TEXTURE0+j);
-        vgl->ClientActiveTexture( GL_TEXTURE0+j);
-        glDisableClientState(GL_TEXTURE_COORD_ARRAY);
-    }
+        /* If we need to draw subpictures, use simpler program */
+        vgl->UseProgram( vgl->program[1] );
 
+        vgl->BindVertexArray( vgl->vao[1] );
 
+        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+        glEnable(GL_BLEND);
 
-    if (vgl->program)
-        glDisable(GL_FRAGMENT_PROGRAM_ARB);
-    else
-        glDisable(vgl->tex_target);
-
-    if (vgl->use_multitexture)
-        vgl->ActiveTexture(GL_TEXTURE0 + 0);
-    glEnable(GL_TEXTURE_2D);
-    glEnable(GL_BLEND);
-    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-    glEnableClientState(GL_VERTEX_ARRAY);
-    const GLfloat textureCoord[] = {
-        0.0, 0.0,
-        0.0, 1.0,
-        1.0, 0.0,
-        1.0, 1.0,
-    };
-    for (int i = 0; i < vgl->region_count; i++) {
-        gl_region_t *glr = &vgl->region[i];
-        const GLfloat vertexCoord[] = {
-            glr->left, glr->top,
-            glr->left, glr->bottom,
-            glr->right, glr->top,
-            glr->right,glr->bottom,
-        };
-        glColor4f(1.0f, 1.0f, 1.0f, glr->alpha);
-        glEnableClientState(GL_TEXTURE_COORD_ARRAY);
-
-        glBindTexture(GL_TEXTURE_2D, glr->texture);
-        glVertexPointer(2, GL_FLOAT, 0, vertexCoord);
-        glTexCoordPointer(2, GL_FLOAT, 0, textureCoord);
-        glDrawArrays( GL_TRIANGLE_STRIP, 0, 4 );
-        glDisableClientState(GL_TEXTURE_COORD_ARRAY);
-    }
-    glDisableClientState(GL_VERTEX_ARRAY);
-    glDisable(GL_BLEND);
-    glDisable(GL_TEXTURE_2D);
-#endif
+        for (int i = 0; i < vgl->region_count; i++) {
+
+            gl_region_t *glr = &vgl->region[i];
+            const GLfloat vertexCoord[] = {
+                glr->left, glr->top,
+                glr->left, glr->bottom,
+                glr->right, glr->top,
+                glr->right,glr->bottom,
+            };
+
+            /* We only have one texture plane, so we can use just one buffer for it */
+            vgl->BindBuffer( GL_ARRAY_BUFFER, vgl->buffers[1][0] );
+            vgl->BufferData( GL_ARRAY_BUFFER, sizeof(vertexCoord), vertexCoord, GL_STREAM_DRAW );
+            vgl->Uniform4f( vgl->GetUniformLocation( vgl->program[1],"fillColor"), 1.0f,1.0f,1.0f,glr->alpha);
+
+            glBindTexture(vgl->tex_target, glr->texture);
+            glDrawArrays( GL_TRIANGLE_STRIP, 0, 4 );
+        }
+        glDisable(GL_BLEND);
+   }
 
     vlc_gl_Swap(vgl->gl);
 
diff --git a/modules/video_output/opengl.h b/modules/video_output/opengl.h
index 7a118df..bdd5729 100644
--- a/modules/video_output/opengl.h
+++ b/modules/video_output/opengl.h
@@ -43,6 +43,7 @@
 #  ifdef WIN32
 #   include <GL/glew.h>
 #  endif
+#  include <GL/glx.h>
 #  include <GL/gl.h>
 # endif
 #else
-- 
1.7.9.2




More information about the vlc-devel mailing list