]> git.sesse.net Git - vlc/blob - modules/video_output/opengl.c
opengl.c: don't use fixed pipeline with glsl shader code, one step closer for opengl...
[vlc] / modules / video_output / opengl.c
1 /*****************************************************************************
2  * opengl.c: OpenGL and OpenGL ES output common code
3  *****************************************************************************
4  * Copyright (C) 2004-2012 VLC authors and VideoLAN
5  * Copyright (C) 2009, 2011 Laurent Aimar
6  *
7  * Authors: Cyril Deguet <asmax@videolan.org>
8  *          Gildas Bazin <gbazin@videolan.org>
9  *          Eric Petit <titer@m0k.org>
10  *          Cedric Cocquebert <cedric.cocquebert@supelec.fr>
11  *          Laurent Aimar <fenrir _AT_ videolan _DOT_ org>
12  *          Ilkka Ollakka <ileoo@videolan.org>
13  *
14  * This program is free software; you can redistribute it and/or modify
15  * it under the terms of the GNU General Public License as published by
16  * the Free Software Foundation; either version 2 of the License, or
17  * (at your option) any later version.
18  *
19  * This program is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License
25  * along with this program; if not, write to the Free Software
26  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
27  *****************************************************************************/
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31
32 #include <vlc_common.h>
33 #include <vlc_picture_pool.h>
34 #include <vlc_subpicture.h>
35 #include <vlc_opengl.h>
36
37 #include "opengl.h"
38
39 #ifndef GL_CLAMP_TO_EDGE
40 # define GL_CLAMP_TO_EDGE 0x812F
41 #endif
42
43 #ifdef __APPLE__
44 #   define PFNGLGENBUFFERSPROC               typeof(glGenBuffers)*
45 #   define PFNGLBINDBUFFERPROC               typeof(glBindBuffer)*
46 #   define PFNGLDELETEBUFFERSPROC            typeof(glDeleteBuffers)*
47 #   define PFNGLBUFFERSUBDATAPROC            typeof(glBufferSubData)*
48 #   define PFNGLBUFFERDATAPROC               typeof(glBufferData)*
49 #   define PFNGLGETPROGRAMIVPROC             typeof(glGetProgramiv)*
50 #   define PFNGLGETPROGRAMINFOLOGPROC        typeof(glGetProgramInfoLog)*
51 #   define PFNGLGETSHADERIVPROC              typeof(glGetShaderiv)*
52 #   define PFNGLGETSHADERINFOLOGPROC         typeof(glGetShaderInfoLog)*
53 #   define PFNGLGETUNIFORMLOCATIONPROC       typeof(glGetUniformLocation)*
54 #   define PFNGLGETATTRIBLOCATIONPROC        typeof(glGetAttribLocation)*
55 #   define PFNGLVERTEXATTRIBLOCATIONPROC     typeof(glVertexAttribPointer)*
56 #   define PFNGLENABLEVERTEXATTRIBARRAYPROC  typeof(glEnableVertexAttribArray)*
57 #   define PFNGLUNIFORM4FVPROC               typeof(glUniform4fv)*
58 #   define PFNGLUNIFORM4FPROC                typeof(glUniform4f)*
59 #   define PFNGLUNIFORM3IPROC                typeof(glUniform3i)*
60 #   define PFNGLUNIFORM1IPROC                typeof(glUniform1i)*
61 #   define PFNGLCREATESHADERPROC             typeof(glCreateShader)*
62 #   define PFNGLSHADERSOURCEPROC             typeof(glShaderSource)*
63 #   define PFNGLCOMPILESHADERPROC            typeof(glCompileShader)*
64 #   define PFNGLDETACHSHADERPROC             typeof(glDetachShader)*
65 #   define PFNGLDELETESHADERPROC             typeof(glDeleteShader)*
66 #   define PFNGLCREATEPROGRAMPROC            typeof(glCreateProgram)*
67 #   define PFNGLLINKPROGRAMPROC              typeof(glLinkProgram)*
68 #   define PFNGLUSEPROGRAMPROC               typeof(glUseProgram)*
69 #   define PFNGLDELETEPROGRAMPROC            typeof(glDeleteProgram)*
70 #   define PFNGLATTACHSHADERPROC             typeof(glAttachShader)*
71 #   define PFNGLACTIVETEXTUREPROC            typeof(glActiveTexture)*
72 #   define PFNGLCLIENTACTIVETEXTUREPROC      typeof(glClientActiveTexture)*
73 #if USE_OPENGL_ES
74 #   define GL_UNPACK_ROW_LENGTH 0
75 #   import <CoreFoundation/CoreFoundation.h>
76 #endif
77 #endif
78
79 #if USE_OPENGL_ES
80 #   define VLCGL_TEXTURE_COUNT 1
81 #   define VLCGL_PICTURE_MAX 1
82 #else
83 #   define VLCGL_TEXTURE_COUNT 1
84 #   define VLCGL_PICTURE_MAX 128
85 #endif
86
87 static const vlc_fourcc_t gl_subpicture_chromas[] = {
88     VLC_CODEC_RGBA,
89     0
90 };
91
92 typedef struct {
93     GLuint   texture;
94     unsigned format;
95     unsigned type;
96     unsigned width;
97     unsigned height;
98
99     float    alpha;
100
101     float    top;
102     float    left;
103     float    bottom;
104     float    right;
105 } gl_region_t;
106
107 struct vout_display_opengl_t {
108
109     vlc_gl_t   *gl;
110
111     video_format_t fmt;
112     const vlc_chroma_description_t *chroma;
113
114     int        tex_target;
115     int        tex_format;
116     int        tex_internal;
117     int        tex_type;
118
119     int        tex_width[PICTURE_PLANE_MAX];
120     int        tex_height[PICTURE_PLANE_MAX];
121
122     GLuint     texture[VLCGL_TEXTURE_COUNT][PICTURE_PLANE_MAX];
123
124     int         region_count;
125     gl_region_t *region;
126
127
128     picture_pool_t *pool;
129
130     /* index 0 for normal and 1 for subtitle overlay */
131     GLuint     program[2];
132     GLint      shader[3]; //3. is for the common vertex shader
133     int        local_count;
134     GLfloat    local_value[16];
135
136     /* Buffer commands */
137     PFNGLGENBUFFERSPROC   GenBuffers;
138     PFNGLBINDBUFFERPROC   BindBuffer;
139     PFNGLDELETEBUFFERSPROC DeleteBuffers;
140     PFNGLBUFFERSUBDATAPROC BufferSubData;
141
142     PFNGLBUFFERDATAPROC   BufferData;
143
144     /* Shader variables commands*/
145
146     PFNGLGETUNIFORMLOCATIONPROC      GetUniformLocation;
147     PFNGLGETATTRIBLOCATIONPROC       GetAttribLocation;
148     PFNGLVERTEXATTRIBPOINTERPROC     VertexAttribPointer;
149     PFNGLENABLEVERTEXATTRIBARRAYPROC EnableVertexAttribArray;
150
151     PFNGLUNIFORM4FVPROC   Uniform4fv;
152     PFNGLUNIFORM4FPROC    Uniform4f;
153     PFNGLUNIFORM3IPROC    Uniform3i;
154     PFNGLUNIFORM1IPROC    Uniform1i;
155
156     /* Shader command */
157     PFNGLCREATESHADERPROC CreateShader;
158     PFNGLSHADERSOURCEPROC ShaderSource;
159     PFNGLCOMPILESHADERPROC CompileShader;
160     PFNGLDETACHSHADERPROC   DetachShader;
161     PFNGLDELETESHADERPROC   DeleteShader;
162
163     PFNGLCREATEPROGRAMPROC CreateProgram;
164     PFNGLLINKPROGRAMPROC   LinkProgram;
165     PFNGLUSEPROGRAMPROC    UseProgram;
166     PFNGLDELETEPROGRAMPROC DeleteProgram;
167
168     PFNGLATTACHSHADERPROC  AttachShader;
169
170     /* Shader log commands */
171     PFNGLGETPROGRAMIVPROC  GetProgramiv;
172     PFNGLGETPROGRAMINFOLOGPROC GetProgramInfoLog;
173     PFNGLGETSHADERIVPROC   GetShaderiv;
174     PFNGLGETSHADERINFOLOGPROC GetShaderInfoLog;
175
176
177     /* multitexture */
178     PFNGLACTIVETEXTUREPROC  ActiveTexture;
179     PFNGLCLIENTACTIVETEXTUREPROC  ClientActiveTexture;
180     bool use_multitexture;
181
182     /* Non-power-of-2 texture size support */
183     bool supports_npot;
184 };
185
186 static inline int GetAlignedSize(unsigned size)
187 {
188     /* Return the smallest larger or equal power of 2 */
189     unsigned align = 1 << (8 * sizeof (unsigned) - clz(size));
190     return ((align >> 1) == size) ? size : align;
191 }
192
193 #if !USE_OPENGL_ES
194 static bool IsLuminance16Supported(int target)
195 {
196 #if defined(MACOS_OPENGL)
197     /* OpenGL 1.x on OS X does _not_ support 16bit shaders, but pretends to.
198      * That's why we enforce return false here, even though the actual code below
199      * would return true.
200      * This fixes playback of 10bit content on the Intel GMA 950 chipset, which is
201      * the only "GPU" supported by 10.6 and 10.7 with just an OpenGL 1.4 driver.
202      *
203      * Presumely, this also improves playback on the GMA 3100, GeForce FX 5200,
204      * GeForce4 Ti, GeForce3, GeForce2 MX/4 MX and the Radeon 8500 when
205      * running OS X 10.5. */
206     const GLubyte * p_glversion;
207     float f_glversion;
208     p_glversion = glGetString (GL_VERSION);
209     sscanf((char *)p_glversion, "%f", &f_glversion);
210     if (f_glversion < 2)
211         return false;
212 #endif
213
214     GLuint texture;
215
216     glGenTextures(1, &texture);
217     glBindTexture(target, texture);
218     glTexImage2D(target, 0, GL_LUMINANCE16,
219                  64, 64, 0, GL_LUMINANCE, GL_UNSIGNED_SHORT, NULL);
220     GLint size = 0;
221     glGetTexLevelParameteriv(target, 0, GL_TEXTURE_LUMINANCE_SIZE, &size);
222
223     glDeleteTextures(1, &texture);
224
225     return size == 16;
226 }
227 #endif
228
229 vout_display_opengl_t *vout_display_opengl_New(video_format_t *fmt,
230                                                const vlc_fourcc_t **subpicture_chromas,
231                                                vlc_gl_t *gl)
232 {
233     vout_display_opengl_t *vgl = calloc(1, sizeof(*vgl));
234     if (!vgl)
235         return NULL;
236
237     vgl->gl = gl;
238     if (vlc_gl_Lock(vgl->gl)) {
239         free(vgl);
240         return NULL;
241     }
242
243     if( vgl->gl->getProcAddress == NULL )
244     {
245         fprintf(stderr, "getProcAddress not implemented, bailing out\n");
246         free( vgl );
247         return NULL;
248     }
249
250     const char *extensions = (const char *)glGetString(GL_EXTENSIONS);
251 #if !USE_OPENGL_ES
252     const unsigned char *ogl_version = glGetString(GL_VERSION);
253     bool supports_shaders = strverscmp((const char *)ogl_version, "2.0") >= 0;
254 #else
255     bool supports_shaders = false;
256 #ifdef __APPLE__
257     if( kCFCoreFoundationVersionNumber >= 786. )
258          supports_shaders = true;
259 #endif
260 #endif
261
262     GLint max_texture_units = 0;
263     glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &max_texture_units);
264
265     /* Initialize with default chroma */
266     vgl->fmt = *fmt;
267     vgl->fmt.i_chroma = VLC_CODEC_RGB32;
268 #   if defined(WORDS_BIGENDIAN)
269     vgl->fmt.i_rmask  = 0xff000000;
270     vgl->fmt.i_gmask  = 0x00ff0000;
271     vgl->fmt.i_bmask  = 0x0000ff00;
272 #   else
273     vgl->fmt.i_rmask  = 0x000000ff;
274     vgl->fmt.i_gmask  = 0x0000ff00;
275     vgl->fmt.i_bmask  = 0x00ff0000;
276 #   endif
277     vgl->tex_target   = GL_TEXTURE_2D;
278     vgl->tex_format   = GL_RGBA;
279     vgl->tex_internal = GL_RGBA;
280     vgl->tex_type     = GL_UNSIGNED_BYTE;
281     /* Use YUV if possible and needed */
282     bool need_fs_yuv = false;
283     float yuv_range_correction = 1.0;
284     if ( max_texture_units >= 3 && supports_shaders &&
285         vlc_fourcc_IsYUV(fmt->i_chroma) && !vlc_fourcc_IsYUV(vgl->fmt.i_chroma)) {
286         const vlc_fourcc_t *list = vlc_fourcc_GetYUVFallback(fmt->i_chroma);
287         while (*list) {
288             const vlc_chroma_description_t *dsc = vlc_fourcc_GetChromaDescription(*list);
289             if (dsc && dsc->plane_count == 3 && dsc->pixel_size == 1) {
290                 need_fs_yuv       = true;
291                 vgl->fmt          = *fmt;
292                 vgl->fmt.i_chroma = *list;
293                 vgl->tex_format   = GL_LUMINANCE;
294                 vgl->tex_internal = GL_LUMINANCE;
295                 vgl->tex_type     = GL_UNSIGNED_BYTE;
296                 yuv_range_correction = 1.0;
297                 break;
298 #if !USE_OPENGL_ES
299             } else if (dsc && dsc->plane_count == 3 && dsc->pixel_size == 2 &&
300                        IsLuminance16Supported(vgl->tex_target)) {
301                 need_fs_yuv       = true;
302                 vgl->fmt          = *fmt;
303                 vgl->fmt.i_chroma = *list;
304                 vgl->tex_format   = GL_LUMINANCE;
305                 vgl->tex_internal = GL_LUMINANCE16;
306                 vgl->tex_type     = GL_UNSIGNED_SHORT;
307                 yuv_range_correction = (float)((1 << 16) - 1) / ((1 << dsc->pixel_bits) - 1);
308                 break;
309 #endif
310             }
311             list++;
312         }
313     }
314 #if (defined (__ppc__) || defined (__ppc64__) || defined (__powerpc__)) && defined (__APPLE__)
315     /* This is a work-around for dated PowerPC-based Macs, which run OpenGL 1.3 only and don't
316      * support the GL_ARB_fragment_program extension.
317      * Affected devices are all Macs built between 2002 and 2005 with an ATI Radeon 7500,
318      * an ATI Radeon 9200 or a NVIDIA GeForceFX 5200 Ultra. */
319     else
320     {
321         vgl->tex_format   = GL_YCBCR_422_APPLE;
322         vgl->tex_type     = GL_UNSIGNED_SHORT_8_8_APPLE;
323         vgl->fmt.i_chroma = VLC_CODEC_YUYV;
324     }
325 #endif
326
327     vgl->GenBuffers    = (PFNGLGENBUFFERSPROC)vlc_gl_GetProcAddress(vgl->gl, "glGenBuffers");
328     vgl->BindBuffer    = (PFNGLBINDBUFFERPROC)vlc_gl_GetProcAddress(vgl->gl, "glBindBuffer");
329     vgl->BufferData    = (PFNGLBUFFERDATAPROC)vlc_gl_GetProcAddress(vgl->gl, "glBufferData");
330     vgl->BufferSubData = (PFNGLBUFFERSUBDATAPROC)vlc_gl_GetProcAddress(vgl->gl, "glBufferSubData");
331     vgl->DeleteBuffers = (PFNGLDELETEBUFFERSPROC)vlc_gl_GetProcAddress(vgl->gl, "glDeleteBuffers");
332
333     vgl->CreateShader  = (PFNGLCREATESHADERPROC)vlc_gl_GetProcAddress(vgl->gl, "glCreateShader");
334     vgl->ShaderSource  = (PFNGLSHADERSOURCEPROC)vlc_gl_GetProcAddress(vgl->gl, "glShaderSource");
335     vgl->CompileShader = (PFNGLCOMPILESHADERPROC)vlc_gl_GetProcAddress(vgl->gl, "glCompileShader");
336     vgl->AttachShader  = (PFNGLATTACHSHADERPROC)vlc_gl_GetProcAddress(vgl->gl, "glAttachShader");
337
338     vgl->GetProgramiv  = (PFNGLGETPROGRAMIVPROC)vlc_gl_GetProcAddress(vgl->gl, "glGetProgramiv");
339     vgl->GetShaderiv   = (PFNGLGETSHADERIVPROC)vlc_gl_GetProcAddress(vgl->gl, "glGetShaderiv");
340     vgl->GetProgramInfoLog  = (PFNGLGETPROGRAMINFOLOGPROC)vlc_gl_GetProcAddress(vgl->gl, "glGetProgramInfoLog");
341     vgl->GetShaderInfoLog   = (PFNGLGETSHADERINFOLOGPROC)vlc_gl_GetProcAddress(vgl->gl, "glGetShaderInfoLog");
342
343     vgl->DetachShader  = (PFNGLDETACHSHADERPROC)vlc_gl_GetProcAddress(vgl->gl, "glDetachShader");
344     vgl->DeleteShader  = (PFNGLDELETESHADERPROC)vlc_gl_GetProcAddress(vgl->gl, "glDeleteShader");
345
346     vgl->GetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC)vlc_gl_GetProcAddress(vgl->gl, "glGetUniformLocation");
347     vgl->GetAttribLocation  = (PFNGLGETATTRIBLOCATIONPROC)vlc_gl_GetProcAddress(vgl->gl, "glGetAttribLocation");
348     vgl->VertexAttribPointer= (PFNGLVERTEXATTRIBPOINTERPROC)vlc_gl_GetProcAddress(vgl->gl, "glVertexAttribPointer");
349     vgl->EnableVertexAttribArray = (PFNGLENABLEVERTEXATTRIBARRAYPROC)vlc_gl_GetProcAddress(vgl->gl, "glEnableVertexAttribArray");
350     vgl->Uniform4fv    = (PFNGLUNIFORM4FVPROC)vlc_gl_GetProcAddress(vgl->gl,"glUniform4fv");
351     vgl->Uniform4f     = (PFNGLUNIFORM4FPROC)vlc_gl_GetProcAddress(vgl->gl,"glUniform4f");
352     vgl->Uniform3i     = (PFNGLUNIFORM3IPROC)vlc_gl_GetProcAddress(vgl->gl,"glUniform3i");
353     vgl->Uniform1i     = (PFNGLUNIFORM1IPROC)vlc_gl_GetProcAddress(vgl->gl,"glUniform1i");
354
355     vgl->CreateProgram = (PFNGLCREATEPROGRAMPROC)vlc_gl_GetProcAddress(vgl->gl, "glCreateProgram");
356     vgl->LinkProgram   = (PFNGLLINKPROGRAMPROC)vlc_gl_GetProcAddress(vgl->gl, "glLinkProgram");
357     vgl->UseProgram    = (PFNGLUSEPROGRAMPROC)vlc_gl_GetProcAddress(vgl->gl, "glUseProgram");
358     vgl->DeleteProgram = (PFNGLDELETEPROGRAMPROC)vlc_gl_GetProcAddress(vgl->gl, "glDeleteProgram");
359     vgl->ActiveTexture = (PFNGLACTIVETEXTUREPROC)vlc_gl_GetProcAddress(vgl->gl, "glActiveTexture");
360     vgl->ClientActiveTexture = (PFNGLCLIENTACTIVETEXTUREPROC)vlc_gl_GetProcAddress(vgl->gl, "glClientActiveTexture");
361
362     vgl->chroma = vlc_fourcc_GetChromaDescription(vgl->fmt.i_chroma);
363     vgl->use_multitexture = vgl->chroma->plane_count > 1;
364     vgl->supports_npot = HasExtension( extensions, "GL_ARB_texture_non_power_of_two" ) ||
365                          HasExtension( extensions, "GL_APPLE_texture_2D_limited_npot" );
366
367     if( !vgl->CreateShader || !vgl->ShaderSource || !vgl->CreateProgram )
368     {
369         fprintf(stderr, "Looks like you don't have all the opengl we need. Driver is %s, giving up\n", glGetString(GL_VERSION));
370         free( vgl );
371         return NULL;
372     }
373
374
375     /* Texture size */
376     for (unsigned j = 0; j < vgl->chroma->plane_count; j++) {
377         int w = vgl->fmt.i_width  * vgl->chroma->p[j].w.num / vgl->chroma->p[j].w.den;
378         int h = vgl->fmt.i_height * vgl->chroma->p[j].h.num / vgl->chroma->p[j].h.den;
379         if( vgl->supports_npot )
380         {
381             vgl->tex_width[j]  = w;
382             vgl->tex_height[j] = h;
383         } else {
384             vgl->tex_width[j]  = GetAlignedSize(w);
385             vgl->tex_height[j] = GetAlignedSize(h);
386         }
387     }
388
389     /* Build fragment program if needed */
390     vgl->program[0] = 0;
391     vgl->program[1] = 0;
392     vgl->local_count = 0;
393     vgl->shader[0] = vgl->shader[1] = vgl->shader[2] = -1;
394     if (supports_shaders) {
395         char *code = NULL;
396
397             /* [R/G/B][Y U V O] from TV range to full range
398              * XXX we could also do hue/brightness/constrast/gamma
399              * by simply changing the coefficients
400              */
401             const float matrix_bt601_tv2full[12] = {
402                  1.164383561643836,  0.0000,             1.596026785714286, -0.874202217873451 ,
403                  1.164383561643836, -0.391762290094914, -0.812967647237771,  0.531667823499146 ,
404                  1.164383561643836,  2.017232142857142,  0.0000,            -1.085630789302022 ,
405             };
406             const float matrix_bt709_tv2full[12] = {
407                  1.164383561643836,  0.0000,             1.792741071428571, -0.972945075016308 ,
408                  1.164383561643836, -0.21324861427373,  -0.532909328559444,  0.301482665475862 ,
409                  1.164383561643836,  2.112401785714286,  0.0000,            -1.133402217873451 ,
410             };
411             const float (*matrix) = fmt->i_height > 576 ? matrix_bt709_tv2full
412                                                            : matrix_bt601_tv2full;
413
414             /* Basic linear YUV -> RGB conversion using bilinear interpolation */
415             const char *template_glsl_yuv =
416                 "#version 120\n"
417                 "uniform sampler2D Texture[3];"
418                 "uniform vec4      coefficient[4];"
419                 "varying vec4      TexCoord0,TexCoord1,TexCoord2;"
420
421                 "void main(void) {"
422                 " vec4 x,y,z,result;"
423                 " x  = texture2D(Texture[0], TexCoord0.st);"
424                 " %c = texture2D(Texture[1], TexCoord1.st);"
425                 " %c = texture2D(Texture[2], TexCoord2.st);"
426
427                 " result = x * coefficient[0] + coefficient[3];"
428                 " result = (y * coefficient[1]) + result;"
429                 " result = (z * coefficient[2]) + result;"
430                 " gl_FragColor = result;"
431                 "}";
432             bool swap_uv = vgl->fmt.i_chroma == VLC_CODEC_YV12 ||
433                            vgl->fmt.i_chroma == VLC_CODEC_YV9;
434             if (asprintf(&code, template_glsl_yuv,
435                          swap_uv ? 'z' : 'y',
436                          swap_uv ? 'y' : 'z') < 0)
437                 code = NULL;
438
439             for (int i = 0; i < 4; i++) {
440                 float correction = i < 3 ? yuv_range_correction : 1.0;
441                 /* We place coefficient values for coefficient[4] in one array from matrix values.
442                    Notice that we fill values from top down instead of left to right.*/
443                 for( int j = 0; j < 4; j++ )
444                     vgl->local_value[vgl->local_count + i*4+j] = j < 3 ? correction * matrix[j*4+i] : 0.0 ;
445             }
446             vgl->local_count += 4;
447
448             // Basic vertex shader that we use in both cases
449             const char *vertexShader =
450             "#version 120\n"
451             "varying   vec4 TexCoord0,TexCoord1, TexCoord2;"
452             "attribute vec4 MultiTexCoord0,MultiTexCoord1,MultiTexCoord2;"
453             "attribute vec4 vertex_position;"
454             "void main() {"
455             " TexCoord0 = MultiTexCoord0;"
456             " TexCoord1 = MultiTexCoord1;"
457             " TexCoord2 = MultiTexCoord2;"
458             " gl_Position = vertex_position; }";
459
460             // Dummy shader for text overlay
461             const char *helloShader =
462             "#version 120\n"
463             "uniform sampler2D Texture[3];"
464             "uniform vec4 fillColor;"
465             "varying vec4 TexCoord0,TexCoord1,TexCoord2;"
466             "void main()"
467             "{ "
468             "  gl_FragColor = texture2D(Texture[0], TexCoord0.st)*fillColor;}";
469
470             vgl->shader[2] = vgl->CreateShader( GL_VERTEX_SHADER );
471             vgl->ShaderSource( vgl->shader[2], 1, (const GLchar **)&vertexShader, NULL);
472             vgl->CompileShader( vgl->shader[2] );
473
474             /* Create 'dummy' shader that handles subpicture overlay for now*/
475             vgl->shader[1] = vgl->CreateShader( GL_FRAGMENT_SHADER );
476             vgl->ShaderSource( vgl->shader[1], 1, &helloShader, NULL);
477             vgl->CompileShader( vgl->shader[1] );
478             vgl->program[1] = vgl->CreateProgram();
479             vgl->AttachShader( vgl->program[1], vgl->shader[1]);
480             vgl->AttachShader( vgl->program[1], vgl->shader[2]);
481             vgl->LinkProgram( vgl->program[1] );
482
483             // Create shader from code
484             vgl->shader[0] = vgl->CreateShader( GL_FRAGMENT_SHADER );
485             vgl->program[0] = vgl->CreateProgram();
486             if( need_fs_yuv )
487             {
488                 vgl->ShaderSource( vgl->shader[0], 1, (const GLchar **)&code, NULL );
489                 vgl->CompileShader( vgl->shader[0]);
490                 vgl->AttachShader( vgl->program[0], vgl->shader[0] );
491             } else {
492                 /* Use simpler shader if we don't need to to yuv -> rgb,
493                    for example when input is allready rgb (.bmp image).*/
494                 vgl->AttachShader( vgl->program[0], vgl->shader[1] );
495             }
496             vgl->AttachShader( vgl->program[0], vgl->shader[2]);
497
498             vgl->LinkProgram( vgl->program[0] );
499
500             free(code);
501             for( GLuint i = 0; i < 2; i++ )
502             {
503                 int infoLength = 0;
504                 int charsWritten = 0;
505                 char *infolog;
506                 vgl->GetProgramiv( vgl->program[i], GL_INFO_LOG_LENGTH, &infoLength );
507                 if( infoLength > 1 )
508                 {
509                     /* If there is some message, better to check linking is ok */
510                     GLint link_status = GL_TRUE;
511                     vgl->GetProgramiv( vgl->program[i], GL_LINK_STATUS, &link_status );
512
513                     infolog = (char *)malloc(infoLength);
514                     vgl->GetProgramInfoLog( vgl->program[i], infoLength, &charsWritten, infolog );
515                     fprintf(stderr, "shader program %d:%s %d\n",i,infolog,infoLength);
516                     free(infolog);
517
518                     /* Check shaders messages too */
519                     for( GLuint j = 0; j < 2; j++ )
520                     {
521                         vgl->GetShaderiv( vgl->shader[j], GL_INFO_LOG_LENGTH, &infoLength );
522                         if( infoLength > 1 )
523                         {
524                             infolog = (char *)malloc(infoLength);
525                             vgl->GetShaderInfoLog( vgl->shader[j], infoLength, &charsWritten, infolog );
526                             fprintf(stderr, "shader %d: %s\n",j,infolog );
527                             free( infolog );
528                         }
529                     }
530
531                     if( link_status == GL_FALSE )
532                     {
533                         fprintf( stderr, "Unable to use program %d\n", i );
534                         free( vgl );
535                         return NULL;
536                     }
537                 }
538             }
539     }
540
541     /* */
542     glDisable(GL_BLEND);
543     glDisable(GL_DEPTH_TEST);
544     glDepthMask(GL_FALSE);
545     glDisable(GL_CULL_FACE);
546     glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
547     glClear(GL_COLOR_BUFFER_BIT);
548
549     vlc_gl_Unlock(vgl->gl);
550
551     /* */
552     for (int i = 0; i < VLCGL_TEXTURE_COUNT; i++) {
553         for (int j = 0; j < PICTURE_PLANE_MAX; j++)
554             vgl->texture[i][j] = 0;
555     }
556     vgl->region_count = 0;
557     vgl->region = NULL;
558     vgl->pool = NULL;
559
560     *fmt = vgl->fmt;
561     if (subpicture_chromas) {
562         *subpicture_chromas = gl_subpicture_chromas;
563     }
564     return vgl;
565 }
566
567 void vout_display_opengl_Delete(vout_display_opengl_t *vgl)
568 {
569     /* */
570     if (!vlc_gl_Lock(vgl->gl)) {
571
572         glFinish();
573         glFlush();
574         for (int i = 0; i < VLCGL_TEXTURE_COUNT; i++)
575             glDeleteTextures(vgl->chroma->plane_count, vgl->texture[i]);
576         for (int i = 0; i < vgl->region_count; i++) {
577             if (vgl->region[i].texture)
578                 glDeleteTextures(1, &vgl->region[i].texture);
579         }
580         free(vgl->region);
581
582         if (vgl->program[0])
583         {
584             for( int i = 0; i < 2; i++ )
585                 vgl->DeleteProgram( vgl->program[i] );
586             for( int i = 0; i < 3; i++ )
587                 vgl->DeleteShader( vgl->shader[i] );
588         }
589
590         vlc_gl_Unlock(vgl->gl);
591     }
592     if (vgl->pool)
593         picture_pool_Delete(vgl->pool);
594     free(vgl);
595 }
596
597 picture_pool_t *vout_display_opengl_GetPool(vout_display_opengl_t *vgl, unsigned requested_count)
598 {
599     if (vgl->pool)
600         return vgl->pool;
601
602     /* Allocate our pictures */
603     picture_t *picture[VLCGL_PICTURE_MAX] = {NULL, };
604     unsigned count = 0;
605
606     for (count = 0; count < __MIN(VLCGL_PICTURE_MAX, requested_count); count++) {
607         picture[count] = picture_NewFromFormat(&vgl->fmt);
608         if (!picture[count])
609             break;
610     }
611     if (count <= 0)
612         return NULL;
613
614     /* Wrap the pictures into a pool */
615     picture_pool_configuration_t cfg;
616     memset(&cfg, 0, sizeof(cfg));
617     cfg.picture_count = count;
618     cfg.picture       = picture;
619     vgl->pool = picture_pool_NewExtended(&cfg);
620     if (!vgl->pool)
621         goto error;
622
623     /* Allocates our textures */
624     if (vlc_gl_Lock(vgl->gl))
625         return vgl->pool;
626
627     for (int i = 0; i < VLCGL_TEXTURE_COUNT; i++) {
628         glGenTextures(vgl->chroma->plane_count, vgl->texture[i]);
629         for (unsigned j = 0; j < vgl->chroma->plane_count; j++) {
630             if (vgl->use_multitexture)
631             {
632                 vgl->ActiveTexture(GL_TEXTURE0 + j);
633                 vgl->ClientActiveTexture(GL_TEXTURE0 + j);
634             }
635             glBindTexture(vgl->tex_target, vgl->texture[i][j]);
636
637 #if !USE_OPENGL_ES
638             /* Set the texture parameters */
639             glTexParameterf(vgl->tex_target, GL_TEXTURE_PRIORITY, 1.0);
640             glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
641 #endif
642
643             glTexParameteri(vgl->tex_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
644             glTexParameteri(vgl->tex_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
645             glTexParameteri(vgl->tex_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
646             glTexParameteri(vgl->tex_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
647
648             /* Call glTexImage2D only once, and use glTexSubImage2D later */
649             glTexImage2D(vgl->tex_target, 0,
650                          vgl->tex_internal, vgl->tex_width[j], vgl->tex_height[j],
651                          0, vgl->tex_format, vgl->tex_type, NULL);
652         }
653     }
654
655     vlc_gl_Unlock(vgl->gl);
656
657     return vgl->pool;
658
659 error:
660     for (unsigned i = 0; i < count; i++)
661         picture_Release(picture[i]);
662     return NULL;
663 }
664
665 int vout_display_opengl_Prepare(vout_display_opengl_t *vgl,
666                                 picture_t *picture, subpicture_t *subpicture)
667 {
668     /* On Win32/GLX, we do this the usual way:
669        + Fill the buffer with new content,
670        + Reload the texture,
671        + Use the texture.
672
673        On OS X with VRAM or AGP texturing, the order has to be:
674        + Reload the texture,
675        + Fill the buffer with new content,
676        + Use the texture.
677
678        (Thanks to gcc from the Arstechnica forums for the tip)
679
680        Therefore on OSX, we have to use two buffers and textures and use a
681        lock(/unlock) managed picture pool.
682      */
683
684     if (vlc_gl_Lock(vgl->gl))
685         return VLC_EGENERIC;
686
687     /* Update the texture */
688     for (unsigned j = 0; j < vgl->chroma->plane_count; j++) {
689         if (vgl->use_multitexture)
690         {
691             vgl->ActiveTexture(GL_TEXTURE0 + j);
692             vgl->ClientActiveTexture(GL_TEXTURE0 + j);
693         }
694         glBindTexture(vgl->tex_target, vgl->texture[0][j]);
695         glPixelStorei(GL_UNPACK_ROW_LENGTH, picture->p[j].i_pitch / picture->p[j].i_pixel_pitch);
696         glTexSubImage2D(vgl->tex_target, 0,
697                         0, 0,
698                         vgl->fmt.i_width  * vgl->chroma->p[j].w.num / vgl->chroma->p[j].w.den,
699                         vgl->fmt.i_height * vgl->chroma->p[j].h.num / vgl->chroma->p[j].h.den,
700                         vgl->tex_format, vgl->tex_type, picture->p[j].p_pixels);
701     }
702
703     int         last_count = vgl->region_count;
704     gl_region_t *last = vgl->region;
705
706     vgl->region_count = 0;
707     vgl->region       = NULL;
708
709     if (subpicture) {
710
711         int count = 0;
712         for (subpicture_region_t *r = subpicture->p_region; r; r = r->p_next)
713             count++;
714
715         vgl->region_count = count;
716         vgl->region       = calloc(count, sizeof(*vgl->region));
717
718         if (vgl->use_multitexture)
719         {
720             vgl->ActiveTexture(GL_TEXTURE0 + 0);
721             vgl->ClientActiveTexture(GL_TEXTURE0 + 0);
722         }
723         int i = 0;
724         for (subpicture_region_t *r = subpicture->p_region; r; r = r->p_next, i++) {
725             gl_region_t *glr = &vgl->region[i];
726
727             glr->format = GL_RGBA;
728             glr->type   = GL_UNSIGNED_BYTE;
729             glr->width  = r->fmt.i_visible_width;
730             glr->height = r->fmt.i_visible_height;
731             if(!vgl->supports_npot )
732             {
733                 glr->width  = GetAlignedSize( glr->width );
734                 glr->height = GetAlignedSize( glr->height );
735             }
736             glr->alpha  = (float)subpicture->i_alpha * r->i_alpha / 255 / 255;
737             glr->left   =  2.0 * (r->i_x                          ) / subpicture->i_original_picture_width  - 1.0;
738             glr->top    = -2.0 * (r->i_y                          ) / subpicture->i_original_picture_height + 1.0;
739             glr->right  =  2.0 * (r->i_x + r->fmt.i_visible_width ) / subpicture->i_original_picture_width  - 1.0;
740             glr->bottom = -2.0 * (r->i_y + r->fmt.i_visible_height) / subpicture->i_original_picture_height + 1.0;
741
742             glr->texture = 0;
743             for (int j = 0; j < last_count; j++) {
744                 if (last[j].texture &&
745                     last[j].width  == glr->width &&
746                     last[j].height == glr->height &&
747                     last[j].format == glr->format &&
748                     last[j].type   == glr->type) {
749                     glr->texture = last[j].texture;
750                     memset(&last[j], 0, sizeof(last[j]));
751                     break;
752                 }
753             }
754
755             const int pixels_offset = r->fmt.i_y_offset * r->p_picture->p->i_pitch +
756                                       r->fmt.i_x_offset * r->p_picture->p->i_pixel_pitch;
757             if (glr->texture) {
758                 glBindTexture(GL_TEXTURE_2D, glr->texture);
759                 /* TODO set GL_UNPACK_ALIGNMENT */
760                 glPixelStorei(GL_UNPACK_ROW_LENGTH, r->p_picture->p->i_pitch / r->p_picture->p->i_pixel_pitch);
761                 glTexSubImage2D(GL_TEXTURE_2D, 0,
762                                 0, 0, glr->width, glr->height,
763                                 glr->format, glr->type, &r->p_picture->p->p_pixels[pixels_offset]);
764             } else {
765                 glGenTextures(1, &glr->texture);
766                 glBindTexture(GL_TEXTURE_2D, glr->texture);
767 #if !USE_OPENGL_ES
768                 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_PRIORITY, 1.0);
769                 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
770 #endif
771                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
772                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
773                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
774                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
775                 /* TODO set GL_UNPACK_ALIGNMENT */
776                 glPixelStorei(GL_UNPACK_ROW_LENGTH, r->p_picture->p->i_pitch / r->p_picture->p->i_pixel_pitch);
777                 glTexImage2D(GL_TEXTURE_2D, 0, glr->format,
778                              glr->width, glr->height, 0, glr->format, glr->type,
779                              &r->p_picture->p->p_pixels[pixels_offset]);
780             }
781         }
782     }
783     for (int i = 0; i < last_count; i++) {
784         if (last[i].texture)
785             glDeleteTextures(1, &last[i].texture);
786     }
787     free(last);
788
789     vlc_gl_Unlock(vgl->gl);
790     VLC_UNUSED(subpicture);
791     return VLC_SUCCESS;
792 }
793
794 static void draw_without_shaders( vout_display_opengl_t *vgl, float *left, float *top, float *right, float *bottom )
795 {
796     static const GLfloat vertexCoord[] = {
797         -1.0f, -1.0f,
798          1.0f, -1.0f,
799         -1.0f,  1.0f,
800          1.0f,  1.0f,
801     };
802
803     const GLfloat textureCoord[8] = {
804         left[0],  bottom[0],
805         right[0], bottom[0],
806         left[0],  top[0],
807         right[0], top[0]
808     };
809
810     for (unsigned j = 0; j < vgl->chroma->plane_count; j++) {
811        vgl->ActiveTexture( GL_TEXTURE0 + j );
812        vgl->ClientActiveTexture( GL_TEXTURE0 + j );
813
814        glEnableClientState(GL_VERTEX_ARRAY);
815        glEnableClientState(GL_TEXTURE_COORD_ARRAY);
816
817        glEnable(vgl->tex_target);
818
819        glBindTexture(vgl->tex_target, vgl->texture[0][j]);
820        glTexCoordPointer(2, GL_FLOAT, 0, textureCoord);
821     }
822     vgl->ActiveTexture( GL_TEXTURE0 );
823     vgl->ClientActiveTexture( GL_TEXTURE0 );
824
825     glVertexPointer(2, GL_FLOAT, 0, vertexCoord);
826
827     glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
828
829     for (unsigned j = 0; j < vgl->chroma->plane_count; j++) {
830        vgl->ActiveTexture( GL_TEXTURE0 + j );
831        vgl->ClientActiveTexture( GL_TEXTURE0 + j );
832        glDisable(vgl->tex_target);
833        glDisableClientState(GL_TEXTURE_COORD_ARRAY);
834        glDisableClientState(GL_VERTEX_ARRAY);
835     }
836     vgl->ActiveTexture( GL_TEXTURE0 );
837     vgl->ClientActiveTexture( GL_TEXTURE0 );
838 }
839
840 static void draw_with_shaders( vout_display_opengl_t *vgl, float *left, float *top, float *right, float *bottom )
841 {
842
843     const GLfloat vertexCoord[] = {
844         -1.0, 1.0,
845         -1.0, -1.0,
846         1.0, 1.0,
847         1.0, -1.0,
848     };
849
850     for( unsigned j = 0; j < vgl->chroma->plane_count; j++)
851     {
852         char *attribute = NULL;
853         const GLfloat texCoord[] = {
854             left[j], top[j],
855             left[j], bottom[j],
856             right[j], top[j],
857             right[j], bottom[j],
858         };
859         vgl->ActiveTexture( GL_TEXTURE0+j);
860         vgl->ClientActiveTexture( GL_TEXTURE0+j);
861         glEnable(vgl->tex_target);
862         glBindTexture(vgl->tex_target, vgl->texture[0][j]);
863         if(asprintf( &attribute, "MultiTexCoord%1d", j ) == -1 )
864             return;
865
866         vgl->EnableVertexAttribArray( vgl->GetAttribLocation(vgl->program[0], attribute ) );
867         vgl->VertexAttribPointer( vgl->GetAttribLocation( vgl->program[0], attribute ), 2, GL_FLOAT, 0, 0, texCoord);
868         free( attribute );
869         attribute = NULL;
870     }
871     vgl->ActiveTexture(GL_TEXTURE0 + 0);
872     vgl->ClientActiveTexture(GL_TEXTURE0 + 0);
873     vgl->EnableVertexAttribArray( vgl->GetAttribLocation( vgl->program[0], "vertex_position"));
874     vgl->VertexAttribPointer( vgl->GetAttribLocation( vgl->program[0], "vertex_position"), 2, GL_FLOAT, 0, 0, vertexCoord);
875
876     glDrawArrays( GL_TRIANGLE_STRIP, 0, 4);
877 }
878
879 int vout_display_opengl_Display(vout_display_opengl_t *vgl,
880                                 const video_format_t *source)
881 {
882     if (vlc_gl_Lock(vgl->gl))
883         return VLC_EGENERIC;
884
885     /* glTexCoord works differently with GL_TEXTURE_2D and
886        GL_TEXTURE_RECTANGLE_EXT */
887     float left[PICTURE_PLANE_MAX];
888     float top[PICTURE_PLANE_MAX];
889     float right[PICTURE_PLANE_MAX];
890     float bottom[PICTURE_PLANE_MAX];
891     for (unsigned j = 0; j < vgl->chroma->plane_count; j++) {
892         float scale_w, scale_h;
893         if (vgl->tex_target == GL_TEXTURE_2D) {
894             scale_w = (float)vgl->chroma->p[j].w.num / vgl->chroma->p[j].w.den / vgl->tex_width[j];
895             scale_h = (float)vgl->chroma->p[j].h.num / vgl->chroma->p[j].h.den / vgl->tex_height[j];
896
897         } else {
898             scale_w = 1.0;
899             scale_h = 1.0;
900         }
901         left[j]   = (source->i_x_offset +                       0 ) * scale_w;
902         top[j]    = (source->i_y_offset +                       0 ) * scale_h;
903         right[j]  = (source->i_x_offset + source->i_visible_width ) * scale_w;
904         bottom[j] = (source->i_y_offset + source->i_visible_height) * scale_h;
905     }
906
907
908     /* Why drawing here and not in Render()? Because this way, the
909        OpenGL providers can call vout_display_opengl_Display to force redraw.i
910        Currently, the OS X provider uses it to get a smooth window resizing */
911
912     glClear(GL_COLOR_BUFFER_BIT);
913
914
915     if( vgl->program[0] )
916     {
917         vgl->UseProgram(vgl->program[0]);
918         vgl->Uniform4fv( vgl->GetUniformLocation( vgl->program[0], "coefficient" ), 4, vgl->local_value);
919         vgl->Uniform1i( vgl->GetUniformLocation( vgl->program[0], "Texture[0]" ), 0);
920         vgl->Uniform1i( vgl->GetUniformLocation( vgl->program[0], "Texture[1]" ), 1);
921         vgl->Uniform1i( vgl->GetUniformLocation( vgl->program[0], "Texture[2]" ), 2);
922         draw_with_shaders( vgl, left, top ,right, bottom );
923         // Change the program for overlays
924         vgl->UseProgram(vgl->program[1]);
925         vgl->Uniform1i( vgl->GetUniformLocation( vgl->program[1], "Texture[0]" ), 0);
926     } else {
927         draw_without_shaders( vgl, left, top, right, bottom );
928     }
929
930     vgl->ActiveTexture(GL_TEXTURE0 + 0);
931     vgl->ClientActiveTexture(GL_TEXTURE0 + 0);
932     glEnable(GL_TEXTURE_2D);
933     glEnable(GL_BLEND);
934     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
935
936     for (int i = 0; i < vgl->region_count; i++) {
937         gl_region_t *glr = &vgl->region[i];
938         const GLfloat vertexCoord[] = {
939             glr->left, glr->top,
940             glr->left, glr->bottom,
941             glr->right, glr->top,
942             glr->right,glr->bottom,
943         };
944         static const GLfloat textureCoord[] = {
945             0.0, 0.0,
946             0.0, 1.0,
947             1.0, 0.0,
948             1.0, 1.0,
949         };
950
951         glBindTexture(GL_TEXTURE_2D, glr->texture);
952         if( vgl->program[0] )
953         {
954             vgl->Uniform4f( vgl->GetUniformLocation( vgl->program[1], "fillColor"), 1.0f, 1.0f, 1.0f, glr->alpha);
955             vgl->EnableVertexAttribArray( vgl->GetAttribLocation( vgl->program[1], "MultiTexCoord0") );
956             vgl->VertexAttribPointer( vgl->GetAttribLocation( vgl->program[1], "MultiTexCoord0"), 2, GL_FLOAT, 0, 0, textureCoord);
957             vgl->EnableVertexAttribArray( vgl->GetAttribLocation( vgl->program[1], "vertex_position"));
958             vgl->VertexAttribPointer( vgl->GetAttribLocation( vgl->program[1], "vertex_position"), 2, GL_FLOAT, 0, 0, vertexCoord);
959         }
960         else
961         {
962             glEnableClientState(GL_VERTEX_ARRAY);
963             glColor4f( 1.0f, 1.0f, 1.0f, glr->alpha );
964             glEnable(GL_TEXTURE_COORD_ARRAY);
965             glEnable(GL_VERTEX_ARRAY);
966             glTexCoordPointer(2, GL_FLOAT, 0, textureCoord);
967             glEnableClientState(GL_TEXTURE_COORD_ARRAY);
968             glVertexPointer(2, GL_FLOAT, 0, vertexCoord);
969         }
970
971         glDrawArrays( GL_TRIANGLE_STRIP, 0, 4 );
972
973         if( !vgl->program[0] )
974         {
975             glDisableClientState(GL_TEXTURE_COORD_ARRAY);
976             glDisableClientState(GL_VERTEX_ARRAY);
977         }
978     }
979     glDisable(GL_BLEND);
980     glDisable(GL_TEXTURE_2D);
981
982     vlc_gl_Swap(vgl->gl);
983
984     vlc_gl_Unlock(vgl->gl);
985     return VLC_SUCCESS;
986 }
987