]> git.sesse.net Git - vlc/blob - modules/video_output/opengl.c
OSX: disable SDL
[vlc] / modules / video_output / opengl.c
1 /*****************************************************************************
2  * opengl.c: OpenGL and OpenGL ES output common code
3  *****************************************************************************
4  * Copyright (C) 2004-2011 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  *
13  * This program is free software; you can redistribute it and/or modify
14  * it under the terms of the GNU General Public License as published by
15  * the Free Software Foundation; either version 2 of the License, or
16  * (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
26  *****************************************************************************/
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30
31 #include <vlc_common.h>
32 #include <vlc_picture_pool.h>
33 #include <vlc_subpicture.h>
34 #include <vlc_opengl.h>
35
36 #include "opengl.h"
37 // Define USE_OPENGL_ES to the GL ES Version you want to select
38
39 #ifdef __APPLE__
40 # define PFNGLGENPROGRAMSARBPROC              typeof(glGenProgramsARB)*
41 # define PFNGLBINDPROGRAMARBPROC              typeof(glBindProgramARB)*
42 # define PFNGLPROGRAMSTRINGARBPROC            typeof(glProgramStringARB)*
43 # define PFNGLDELETEPROGRAMSARBPROC           typeof(glDeleteProgramsARB)*
44 # define PFNGLPROGRAMLOCALPARAMETER4FVARBPROC typeof(glProgramLocalParameter4fvARB)*
45 # define PFNGLACTIVETEXTUREARBPROC            typeof(glActiveTextureARB)*
46 # define PFNGLMULTITEXCOORD2FARBPROC          typeof(glMultiTexCoord2fARB)*
47 #endif
48
49 /* RV16 */
50 #ifndef GL_UNSIGNED_SHORT_5_6_5
51 # define GL_UNSIGNED_SHORT_5_6_5 0x8363
52 #endif
53 #ifndef GL_CLAMP_TO_EDGE
54 # define GL_CLAMP_TO_EDGE 0x812F
55 #endif
56
57 #if USE_OPENGL_ES
58 #   define VLCGL_TEXTURE_COUNT 1
59 #   define VLCGL_PICTURE_MAX 1
60 #else
61 #   define VLCGL_TEXTURE_COUNT 1
62 #   define VLCGL_PICTURE_MAX 128
63 #endif
64
65 static const vlc_fourcc_t gl_subpicture_chromas[] = {
66     VLC_CODEC_RGBA,
67     0
68 };
69
70 typedef struct {
71     GLuint   texture;
72     unsigned format;
73     unsigned type;
74     unsigned width;
75     unsigned height;
76
77     float    alpha;
78
79     float    top;
80     float    left;
81     float    bottom;
82     float    right;
83 } gl_region_t;
84
85 struct vout_display_opengl_t {
86     vlc_gl_t   *gl;
87
88     video_format_t fmt;
89     const vlc_chroma_description_t *chroma;
90
91     int        tex_target;
92     int        tex_format;
93     int        tex_internal;
94     int        tex_type;
95
96     int        tex_width[PICTURE_PLANE_MAX];
97     int        tex_height[PICTURE_PLANE_MAX];
98
99     GLuint     texture[VLCGL_TEXTURE_COUNT][PICTURE_PLANE_MAX];
100
101     int         region_count;
102     gl_region_t *region;
103
104
105     picture_pool_t *pool;
106
107     GLuint     program;
108     int        local_count;
109     GLfloat    local_value[16][4];
110
111     /* fragment_program */
112     PFNGLGENPROGRAMSARBPROC              GenProgramsARB;
113     PFNGLBINDPROGRAMARBPROC              BindProgramARB;
114     PFNGLPROGRAMSTRINGARBPROC            ProgramStringARB;
115     PFNGLDELETEPROGRAMSARBPROC           DeleteProgramsARB;
116     PFNGLPROGRAMLOCALPARAMETER4FVARBPROC ProgramLocalParameter4fvARB;
117
118     /* multitexture */
119     bool use_multitexture;
120     PFNGLACTIVETEXTUREARBPROC   ActiveTextureARB;
121     PFNGLMULTITEXCOORD2FARBPROC MultiTexCoord2fARB;
122 };
123
124 static inline int GetAlignedSize(unsigned size)
125 {
126     /* Return the smallest larger or equal power of 2 */
127     unsigned align = 1 << (8 * sizeof (unsigned) - clz(size));
128     return ((align >> 1) == size) ? size : align;
129 }
130
131 static bool IsLuminance16Supported(int target)
132 {
133     GLuint texture;
134
135     glGenTextures(1, &texture);
136     glBindTexture(target, texture);
137     glTexImage2D(target, 0, GL_LUMINANCE16,
138                  64, 64, 0, GL_LUMINANCE, GL_UNSIGNED_SHORT, NULL);
139     GLint size = 0;
140     glGetTexLevelParameteriv(target, 0, GL_TEXTURE_LUMINANCE_SIZE, &size);
141
142     glDeleteTextures(1, &texture);
143
144     return size == 16;
145 }
146
147 vout_display_opengl_t *vout_display_opengl_New(video_format_t *fmt,
148                                                const vlc_fourcc_t **subpicture_chromas,
149                                                vlc_gl_t *gl)
150 {
151     vout_display_opengl_t *vgl = calloc(1, sizeof(*vgl));
152     if (!vgl)
153         return NULL;
154
155     vgl->gl = gl;
156     if (vlc_gl_Lock(vgl->gl)) {
157         free(vgl);
158         return NULL;
159     }
160
161     const char *extensions = (const char *)glGetString(GL_EXTENSIONS);
162
163     /* Load extensions */
164     bool supports_fp = false;
165     if (HasExtension(extensions, "GL_ARB_fragment_program")) {
166 #if !defined(MACOS_OPENGL)
167         vgl->GenProgramsARB    = (PFNGLGENPROGRAMSARBPROC)vlc_gl_GetProcAddress(vgl->gl, "glGenProgramsARB");
168         vgl->BindProgramARB    = (PFNGLBINDPROGRAMARBPROC)vlc_gl_GetProcAddress(vgl->gl, "glBindProgramARB");
169         vgl->ProgramStringARB  = (PFNGLPROGRAMSTRINGARBPROC)vlc_gl_GetProcAddress(vgl->gl, "glProgramStringARB");
170         vgl->DeleteProgramsARB = (PFNGLDELETEPROGRAMSARBPROC)vlc_gl_GetProcAddress(vgl->gl, "glDeleteProgramsARB");
171         vgl->ProgramLocalParameter4fvARB = (PFNGLPROGRAMLOCALPARAMETER4FVARBPROC)vlc_gl_GetProcAddress(vgl->gl, "glProgramLocalParameter4fvARB");
172 #else
173         vgl->GenProgramsARB = glGenProgramsARB;
174         vgl->BindProgramARB = glBindProgramARB;
175         vgl->ProgramStringARB = glProgramStringARB;
176         vgl->DeleteProgramsARB = glDeleteProgramsARB;
177         vgl->ProgramLocalParameter4fvARB = glProgramLocalParameter4fvARB;
178 #endif
179         supports_fp = vgl->GenProgramsARB &&
180                       vgl->BindProgramARB &&
181                       vgl->ProgramStringARB &&
182                       vgl->DeleteProgramsARB &&
183                       vgl->ProgramLocalParameter4fvARB;
184     }
185
186     bool supports_multitexture = false;
187     GLint max_texture_units = 0;
188     if (HasExtension(extensions, "GL_ARB_multitexture")) {
189 #if !defined(MACOS_OPENGL)
190         vgl->ActiveTextureARB   = (PFNGLACTIVETEXTUREARBPROC)vlc_gl_GetProcAddress(vgl->gl, "glActiveTextureARB");
191         vgl->MultiTexCoord2fARB = (PFNGLMULTITEXCOORD2FARBPROC)vlc_gl_GetProcAddress(vgl->gl, "glMultiTexCoord2fARB");
192 #else
193         vgl->ActiveTextureARB = glActiveTextureARB;
194         vgl->MultiTexCoord2fARB = glMultiTexCoord2fARB;
195 #endif
196         supports_multitexture = vgl->ActiveTextureARB &&
197                                 vgl->MultiTexCoord2fARB;
198         if (supports_multitexture)
199             glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &max_texture_units);
200     }
201
202     /* Initialize with default chroma */
203     vgl->fmt = *fmt;
204 #if USE_OPENGL_ES
205     vgl->fmt.i_chroma = VLC_CODEC_RGB16;
206 #   if defined(WORDS_BIGENDIAN)
207     vgl->fmt.i_rmask  = 0x001f;
208     vgl->fmt.i_gmask  = 0x07e0;
209     vgl->fmt.i_bmask  = 0xf800;
210 #   else
211     vgl->fmt.i_rmask  = 0xf800;
212     vgl->fmt.i_gmask  = 0x07e0;
213     vgl->fmt.i_bmask  = 0x001f;
214 #   endif
215     vgl->tex_target   = GL_TEXTURE_2D;
216     vgl->tex_format   = GL_RGB;
217     vgl->tex_internal = GL_RGB;
218     vgl->tex_type     = GL_UNSIGNED_SHORT_5_6_5;
219 #else
220     vgl->fmt.i_chroma = VLC_CODEC_RGB32;
221 #   if defined(WORDS_BIGENDIAN)
222     vgl->fmt.i_rmask  = 0xff000000;
223     vgl->fmt.i_gmask  = 0x00ff0000;
224     vgl->fmt.i_bmask  = 0x0000ff00;
225 #   else
226     vgl->fmt.i_rmask  = 0x000000ff;
227     vgl->fmt.i_gmask  = 0x0000ff00;
228     vgl->fmt.i_bmask  = 0x00ff0000;
229 #   endif
230     vgl->tex_target   = GL_TEXTURE_2D;
231     vgl->tex_format   = GL_RGBA;
232     vgl->tex_internal = GL_RGBA;
233     vgl->tex_type     = GL_UNSIGNED_BYTE;
234 #endif
235     /* Use YUV if possible and needed */
236     bool need_fs_yuv = false;
237     float yuv_range_correction = 1.0;
238     if (supports_fp && supports_multitexture && max_texture_units >= 3 &&
239         vlc_fourcc_IsYUV(fmt->i_chroma) && !vlc_fourcc_IsYUV(vgl->fmt.i_chroma)) {
240         const vlc_fourcc_t *list = vlc_fourcc_GetYUVFallback(fmt->i_chroma);
241         while (*list) {
242             const vlc_chroma_description_t *dsc = vlc_fourcc_GetChromaDescription(*list);
243             if (dsc && dsc->plane_count == 3 && dsc->pixel_size == 1) {
244                 need_fs_yuv       = true;
245                 vgl->fmt          = *fmt;
246                 vgl->fmt.i_chroma = *list;
247                 vgl->tex_format   = GL_LUMINANCE;
248                 vgl->tex_internal = GL_LUMINANCE;
249                 vgl->tex_type     = GL_UNSIGNED_BYTE;
250                 yuv_range_correction = 1.0;
251                 break;
252             } else if (dsc && dsc->plane_count == 3 && dsc->pixel_size == 2 &&
253                        IsLuminance16Supported(vgl->tex_target)) {
254                 need_fs_yuv       = true;
255                 vgl->fmt          = *fmt;
256                 vgl->fmt.i_chroma = *list;
257                 vgl->tex_format   = GL_LUMINANCE;
258                 vgl->tex_internal = GL_LUMINANCE16;
259                 vgl->tex_type     = GL_UNSIGNED_SHORT;
260                 yuv_range_correction = (float)((1 << 16) - 1) / ((1 << dsc->pixel_bits) - 1);
261                 break;
262             }
263             list++;
264         }
265     }
266
267     vgl->chroma = vlc_fourcc_GetChromaDescription(vgl->fmt.i_chroma);
268     vgl->use_multitexture = vgl->chroma->plane_count > 1;
269
270     bool supports_npot = false;
271 #if USE_OPENGL_ES == 2
272     supports_npot = true;
273 #else
274     supports_npot |= HasExtension(extensions, "GL_APPLE_texture_2D_limited_npot") ||
275                      HasExtension(extensions, "GL_ARB_texture_non_power_of_two");
276 #endif
277
278     /* Texture size */
279     for (unsigned j = 0; j < vgl->chroma->plane_count; j++) {
280         int w = vgl->fmt.i_width  * vgl->chroma->p[j].w.num / vgl->chroma->p[j].w.den;
281         int h = vgl->fmt.i_height * vgl->chroma->p[j].h.num / vgl->chroma->p[j].h.den;
282         if (supports_npot) {
283             vgl->tex_width[j]  = w;
284             vgl->tex_height[j] = h;
285         }
286         else {
287             /* A texture must have a size aligned on a power of 2 */
288             vgl->tex_width[j]  = GetAlignedSize(w);
289             vgl->tex_height[j] = GetAlignedSize(h);
290         }
291     }
292
293     /* Build fragment program if needed */
294     vgl->program = 0;
295     vgl->local_count = 0;
296     if (supports_fp) {
297         char *code = NULL;
298
299         if (need_fs_yuv) {
300             /* [R/G/B][Y U V O] from TV range to full range
301              * XXX we could also do hue/brightness/constrast/gamma
302              * by simply changing the coefficients
303              */
304             const float matrix_bt601_tv2full[3][4] = {
305                 { 1.1640,  0.0000,  1.4030, -0.7773 },
306                 { 1.1640, -0.3440, -0.7140,  0.4580 },
307                 { 1.1640,  1.7730,  0.0000, -0.9630 },
308             };
309             const float matrix_bt709_tv2full[3][4] = {
310                 { 1.1640,  0.0000,  1.5701, -0.8612 },
311                 { 1.1640, -0.1870, -0.4664,  0.2549 },
312                 { 1.1640,  1.8556,  0.0000, -1.0045 },
313             };
314             const float (*matrix)[4] = fmt->i_height > 576 ? matrix_bt709_tv2full
315                                                            : matrix_bt601_tv2full;
316
317             /* Basic linear YUV -> RGB conversion using bilinear interpolation */
318             const char *template_yuv =
319                 "!!ARBfp1.0"
320                 "OPTION ARB_precision_hint_fastest;"
321
322                 "TEMP src;"
323                 "TEX src.x,  fragment.texcoord[0], texture[0], 2D;"
324                 "TEX src.%c, fragment.texcoord[1], texture[1], 2D;"
325                 "TEX src.%c, fragment.texcoord[2], texture[2], 2D;"
326
327                 "PARAM coefficient[4] = { program.local[0..3] };"
328
329                 "TEMP tmp;"
330                 "MAD  tmp.rgb,          src.xxxx, coefficient[0], coefficient[3];"
331                 "MAD  tmp.rgb,          src.yyyy, coefficient[1], tmp;"
332                 "MAD  result.color.rgb, src.zzzz, coefficient[2], tmp;"
333                 "END";
334             bool swap_uv = vgl->fmt.i_chroma == VLC_CODEC_YV12 ||
335                            vgl->fmt.i_chroma == VLC_CODEC_YV9;
336             if (asprintf(&code, template_yuv,
337                          swap_uv ? 'z' : 'y',
338                          swap_uv ? 'y' : 'z') < 0)
339                 code = NULL;
340
341             for (int i = 0; i < 4; i++) {
342                 float correction = i < 3 ? yuv_range_correction : 1.0;
343                 for (int j = 0; j < 4; j++) {
344                     vgl->local_value[vgl->local_count + i][j] = j < 3 ? correction * matrix[j][i] : 0.0;
345                 }
346             }
347             vgl->local_count += 4;
348         }
349         if (code) {
350         // Here you have shaders
351             vgl->GenProgramsARB(1, &vgl->program);
352             vgl->BindProgramARB(GL_FRAGMENT_PROGRAM_ARB, vgl->program);
353             vgl->ProgramStringARB(GL_FRAGMENT_PROGRAM_ARB,
354                                   GL_PROGRAM_FORMAT_ASCII_ARB,
355                                   strlen(code), (const GLbyte*)code);
356             if (glGetError() == GL_INVALID_OPERATION) {
357                 /* FIXME if the program was needed for YUV, the video will be broken */
358 #if 0
359                 GLint position;
360                 glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &position);
361
362                 const char *msg = (const char *)glGetString(GL_PROGRAM_ERROR_STRING_ARB);
363                 fprintf(stderr, "GL_INVALID_OPERATION: error at %d: %s\n", position, msg);
364 #endif
365                 vgl->DeleteProgramsARB(1, &vgl->program);
366                 vgl->program = 0;
367             }
368             free(code);
369         }
370     }
371
372     /* */
373     glDisable(GL_BLEND);
374     glDisable(GL_DEPTH_TEST);
375     glDepthMask(GL_FALSE);
376     glDisable(GL_CULL_FACE);
377     glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
378     glClear(GL_COLOR_BUFFER_BIT);
379
380     vlc_gl_Unlock(vgl->gl);
381
382     /* */
383     for (int i = 0; i < VLCGL_TEXTURE_COUNT; i++) {
384         for (int j = 0; j < PICTURE_PLANE_MAX; j++)
385             vgl->texture[i][j] = 0;
386     }
387     vgl->region_count = 0;
388     vgl->region = NULL;
389     vgl->pool = NULL;
390
391     *fmt = vgl->fmt;
392     if (subpicture_chromas) {
393         *subpicture_chromas = NULL;
394 #if !USE_OPENGL_ES
395         if (supports_npot)
396             *subpicture_chromas = gl_subpicture_chromas;
397 #endif
398     }
399     return vgl;
400 }
401
402 void vout_display_opengl_Delete(vout_display_opengl_t *vgl)
403 {
404     /* */
405     if (!vlc_gl_Lock(vgl->gl)) {
406
407         glFinish();
408         glFlush();
409         for (int i = 0; i < VLCGL_TEXTURE_COUNT; i++)
410             glDeleteTextures(vgl->chroma->plane_count, vgl->texture[i]);
411         for (int i = 0; i < vgl->region_count; i++) {
412             if (vgl->region[i].texture)
413                 glDeleteTextures(1, &vgl->region[i].texture);
414         }
415         free(vgl->region);
416
417         if (vgl->program)
418             vgl->DeleteProgramsARB(1, &vgl->program);
419
420         vlc_gl_Unlock(vgl->gl);
421     }
422     if (vgl->pool)
423         picture_pool_Delete(vgl->pool);
424     free(vgl);
425 }
426
427 picture_pool_t *vout_display_opengl_GetPool(vout_display_opengl_t *vgl, unsigned requested_count)
428 {
429     if (vgl->pool)
430         return vgl->pool;
431
432     /* Allocate our pictures */
433     picture_t *picture[VLCGL_PICTURE_MAX] = {NULL, };
434     unsigned count = 0;
435
436     for (count = 0; count < __MIN(VLCGL_PICTURE_MAX, requested_count); count++) {
437         picture[count] = picture_NewFromFormat(&vgl->fmt);
438         if (!picture[count])
439             break;
440     }
441     if (count <= 0)
442         return NULL;
443
444     /* Wrap the pictures into a pool */
445     picture_pool_configuration_t cfg;
446     memset(&cfg, 0, sizeof(cfg));
447     cfg.picture_count = count;
448     cfg.picture       = picture;
449     vgl->pool = picture_pool_NewExtended(&cfg);
450     if (!vgl->pool)
451         goto error;
452
453     /* Allocates our textures */
454     if (vlc_gl_Lock(vgl->gl))
455         return vgl->pool;
456
457     for (int i = 0; i < VLCGL_TEXTURE_COUNT; i++) {
458         glGenTextures(vgl->chroma->plane_count, vgl->texture[i]);
459         for (unsigned j = 0; j < vgl->chroma->plane_count; j++) {
460             if (vgl->use_multitexture)
461                 vgl->ActiveTextureARB(GL_TEXTURE0_ARB + j);
462             glBindTexture(vgl->tex_target, vgl->texture[i][j]);
463
464 #if !USE_OPENGL_ES
465             /* Set the texture parameters */
466             glTexParameterf(vgl->tex_target, GL_TEXTURE_PRIORITY, 1.0);
467             glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
468 #endif
469
470             glTexParameteri(vgl->tex_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
471             glTexParameteri(vgl->tex_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
472             glTexParameteri(vgl->tex_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
473             glTexParameteri(vgl->tex_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
474
475             /* Call glTexImage2D only once, and use glTexSubImage2D later */
476             glTexImage2D(vgl->tex_target, 0,
477                          vgl->tex_internal, vgl->tex_width[j], vgl->tex_height[j],
478                          0, vgl->tex_format, vgl->tex_type, NULL);
479         }
480     }
481
482     vlc_gl_Unlock(vgl->gl);
483
484     return vgl->pool;
485
486 error:
487     for (unsigned i = 0; i < count; i++)
488         picture_Delete(picture[i]);
489     return NULL;
490 }
491
492 int vout_display_opengl_Prepare(vout_display_opengl_t *vgl,
493                                 picture_t *picture, subpicture_t *subpicture)
494 {
495     /* On Win32/GLX, we do this the usual way:
496        + Fill the buffer with new content,
497        + Reload the texture,
498        + Use the texture.
499
500        On OS X with VRAM or AGP texturing, the order has to be:
501        + Reload the texture,
502        + Fill the buffer with new content,
503        + Use the texture.
504
505        (Thanks to gcc from the Arstechnica forums for the tip)
506
507        Therefore on OSX, we have to use two buffers and textures and use a
508        lock(/unlock) managed picture pool.
509      */
510
511     if (vlc_gl_Lock(vgl->gl))
512         return VLC_EGENERIC;
513
514     /* Update the texture */
515     for (unsigned j = 0; j < vgl->chroma->plane_count; j++) {
516         const int plane = vgl->fmt.i_chroma == VLC_CODEC_YV12 && j > 0 ?  (3 - j) : j;
517         if (vgl->use_multitexture)
518             vgl->ActiveTextureARB(GL_TEXTURE0_ARB + j);
519         glBindTexture(vgl->tex_target, vgl->texture[0][j]);
520         glPixelStorei(GL_UNPACK_ROW_LENGTH, picture->p[plane].i_pitch / picture->p[plane].i_pixel_pitch);
521         glTexSubImage2D(vgl->tex_target, 0,
522                         0, 0,
523                         vgl->fmt.i_width  * vgl->chroma->p[plane].w.num / vgl->chroma->p[plane].w.den,
524                         vgl->fmt.i_height * vgl->chroma->p[plane].h.num / vgl->chroma->p[plane].h.den,
525                         vgl->tex_format, vgl->tex_type, picture->p[plane].p_pixels);
526     }
527
528     int         last_count = vgl->region_count;
529     gl_region_t *last = vgl->region;
530
531     vgl->region_count = 0;
532     vgl->region       = NULL;
533
534     if (subpicture) {
535
536         int count = 0;
537         for (subpicture_region_t *r = subpicture->p_region; r; r = r->p_next)
538             count++;
539
540         vgl->region_count = count;
541         vgl->region       = calloc(count, sizeof(*vgl->region));
542
543         if (vgl->use_multitexture)
544             vgl->ActiveTextureARB(GL_TEXTURE0_ARB + 0);
545         int i = 0;
546         for (subpicture_region_t *r = subpicture->p_region; r; r = r->p_next, i++) {
547             gl_region_t *glr = &vgl->region[i];
548
549             glr->format = GL_RGBA;
550             glr->type   = GL_UNSIGNED_BYTE;
551             glr->width  = r->fmt.i_visible_width;
552             glr->height = r->fmt.i_visible_height;
553             glr->alpha  = (float)subpicture->i_alpha * r->i_alpha / 255 / 255;
554             glr->left   =  2.0 * (r->i_x                          ) / subpicture->i_original_picture_width  - 1.0;
555             glr->top    = -2.0 * (r->i_y                          ) / subpicture->i_original_picture_height + 1.0;
556             glr->right  =  2.0 * (r->i_x + r->fmt.i_visible_width ) / subpicture->i_original_picture_width  - 1.0;
557             glr->bottom = -2.0 * (r->i_y + r->fmt.i_visible_height) / subpicture->i_original_picture_height + 1.0;
558
559             glr->texture = 0;
560             for (int j = 0; j < last_count; j++) {
561                 if (last[j].texture &&
562                     last[j].width  == glr->width &&
563                     last[j].height == glr->height &&
564                     last[j].format == glr->format &&
565                     last[j].type   == glr->type) {
566                     glr->texture = last[j].texture;
567                     memset(&last[j], 0, sizeof(last[j]));
568                     break;
569                 }
570             }
571
572             if (glr->texture) {
573                 glBindTexture(GL_TEXTURE_2D, glr->texture);
574                 /* TODO set GL_UNPACK_ALIGNMENT */
575                 glPixelStorei(GL_UNPACK_ROW_LENGTH, r->p_picture->p->i_pitch / r->p_picture->p->i_pixel_pitch);
576                 glTexSubImage2D(GL_TEXTURE_2D, 0,
577                                 0, 0, glr->width, glr->height,
578                                 glr->format, glr->type, r->p_picture->p->p_pixels);
579             } else {
580                 glGenTextures(1, &glr->texture);
581                 glBindTexture(GL_TEXTURE_2D, glr->texture);
582                 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_PRIORITY, 1.0);
583                 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
584                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
585                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
586                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
587                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
588                 /* TODO set GL_UNPACK_ALIGNMENT */
589                 glPixelStorei(GL_UNPACK_ROW_LENGTH, r->p_picture->p->i_pitch / r->p_picture->p->i_pixel_pitch);
590                 glTexImage2D(GL_TEXTURE_2D, 0, glr->format,
591                              glr->width, glr->height, 0, glr->format, glr->type,
592                              r->p_picture->p->p_pixels);
593             }
594         }
595     }
596     for (int i = 0; i < last_count; i++) {
597         if (last[i].texture)
598             glDeleteTextures(1, &last[i].texture);
599     }
600     free(last);
601
602     vlc_gl_Unlock(vgl->gl);
603     VLC_UNUSED(subpicture);
604     return VLC_SUCCESS;
605 }
606
607 int vout_display_opengl_Display(vout_display_opengl_t *vgl,
608                                 const video_format_t *source)
609 {
610     if (vlc_gl_Lock(vgl->gl))
611         return VLC_EGENERIC;
612
613     /* glTexCoord works differently with GL_TEXTURE_2D and
614        GL_TEXTURE_RECTANGLE_EXT */
615     float left[PICTURE_PLANE_MAX];
616     float top[PICTURE_PLANE_MAX];
617     float right[PICTURE_PLANE_MAX];
618     float bottom[PICTURE_PLANE_MAX];
619     for (unsigned j = 0; j < vgl->chroma->plane_count; j++) {
620         float scale_w, scale_h;
621         if (vgl->tex_target == GL_TEXTURE_2D) {
622             scale_w = (float)vgl->chroma->p[j].w.num / vgl->chroma->p[j].w.den / vgl->tex_width[j];
623             scale_h = (float)vgl->chroma->p[j].h.num / vgl->chroma->p[j].h.den / vgl->tex_height[j];
624
625         } else {
626             scale_w = 1.0;
627             scale_h = 1.0;
628         }
629         left[j]   = (source->i_x_offset +                       0 ) * scale_w;
630         top[j]    = (source->i_y_offset +                       0 ) * scale_h;
631         right[j]  = (source->i_x_offset + source->i_visible_width ) * scale_w;
632         bottom[j] = (source->i_y_offset + source->i_visible_height) * scale_h;
633     }
634
635
636     /* Why drawing here and not in Render()? Because this way, the
637        OpenGL providers can call vout_display_opengl_Display to force redraw.i
638        Currently, the OS X provider uses it to get a smooth window resizing */
639
640     glClear(GL_COLOR_BUFFER_BIT);
641
642     if (vgl->program) {
643         glEnable(GL_FRAGMENT_PROGRAM_ARB);
644         for (int i = 0; i < vgl->local_count; i++)
645             vgl->ProgramLocalParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, i, vgl->local_value[i]);
646     } else {
647         glEnable(vgl->tex_target);
648     }
649
650 #if USE_OPENGL_ES
651     static const GLfloat vertexCoord[] = {
652         -1.0f, -1.0f,
653          1.0f, -1.0f,
654         -1.0f,  1.0f,
655          1.0f,  1.0f,
656     };
657
658     const GLfloat textureCoord[8] = {
659         left[0],  bottom[0],
660         right[0], bottom[0],
661         left[0],  top[0],
662         right[0], top[0]
663     };
664
665     glEnableClientState(GL_VERTEX_ARRAY);
666     glEnableClientState(GL_TEXTURE_COORD_ARRAY);
667     glVertexPointer(2, GL_FLOAT, 0, vertexCoord);
668     glTexCoordPointer(2, GL_FLOAT, 0, textureCoord);
669
670     glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
671 #else
672     for (unsigned j = 0; j < vgl->chroma->plane_count; j++) {
673         if (vgl->use_multitexture)
674             vgl->ActiveTextureARB(GL_TEXTURE0_ARB + j);
675         glBindTexture(vgl->tex_target, vgl->texture[0][j]);
676     }
677     glBegin(GL_POLYGON);
678
679     glTexCoord2f(left[0],  top[0]);
680     for (unsigned j = 1; j < vgl->chroma->plane_count; j++)
681         vgl->MultiTexCoord2fARB(GL_TEXTURE0_ARB + j, left[j], top[j]);
682     glVertex2f(-1.0,  1.0);
683
684     glTexCoord2f(right[0], top[0]);
685     for (unsigned j = 1; j < vgl->chroma->plane_count; j++)
686         vgl->MultiTexCoord2fARB(GL_TEXTURE0_ARB + j, right[j], top[j]);
687     glVertex2f( 1.0,  1.0);
688
689     glTexCoord2f(right[0], bottom[0]);
690     for (unsigned j = 1; j < vgl->chroma->plane_count; j++)
691         vgl->MultiTexCoord2fARB(GL_TEXTURE0_ARB + j, right[j], bottom[j]);
692     glVertex2f( 1.0, -1.0);
693
694     glTexCoord2f(left[0],  bottom[0]);
695     for (unsigned j = 1; j < vgl->chroma->plane_count; j++)
696         vgl->MultiTexCoord2fARB(GL_TEXTURE0_ARB + j, left[j], bottom[j]);
697     glVertex2f(-1.0, -1.0);
698
699     glEnd();
700 #endif
701
702     if (vgl->program)
703         glDisable(GL_FRAGMENT_PROGRAM_ARB);
704     else
705         glDisable(vgl->tex_target);
706
707 #if !USE_OPENGL_ES
708     if (vgl->use_multitexture)
709         vgl->ActiveTextureARB(GL_TEXTURE0_ARB + 0);
710     glEnable(GL_TEXTURE_2D);
711     glEnable(GL_BLEND);
712     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
713     for (int i = 0; i < vgl->region_count; i++) {
714         gl_region_t *glr = &vgl->region[i];
715
716         glBindTexture(GL_TEXTURE_2D, glr->texture);
717
718         glBegin(GL_POLYGON);
719
720         glColor4f(1.0, 1.0, 1.0, glr->alpha);
721
722         glTexCoord2f(0.0, 0.0);
723         glVertex2f(glr->left, glr->top);
724
725         glTexCoord2f(1.0, 0.0);
726         glVertex2f(glr->right, glr->top);
727
728         glTexCoord2f(1.0, 1.0);
729         glVertex2f(glr->right, glr->bottom);
730
731         glTexCoord2f(0.0, 1.0);
732         glVertex2f(glr->left, glr->bottom);
733
734         glEnd();
735     }
736     glDisable(GL_BLEND);
737     glDisable(GL_TEXTURE_2D);
738 #endif
739
740     vlc_gl_Swap(vgl->gl);
741
742     vlc_gl_Unlock(vgl->gl);
743     return VLC_SUCCESS;
744 }
745