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