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
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>
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.
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.
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 *****************************************************************************/
31 #include <vlc_common.h>
32 #include <vlc_picture_pool.h>
33 #include <vlc_subpicture.h>
34 #include <vlc_opengl.h>
37 // Define USE_OPENGL_ES to the GL ES Version you want to select
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)*
50 #ifndef GL_UNSIGNED_SHORT_5_6_5
51 # define GL_UNSIGNED_SHORT_5_6_5 0x8363
53 #ifndef GL_CLAMP_TO_EDGE
54 # define GL_CLAMP_TO_EDGE 0x812F
58 # define VLCGL_TEXTURE_COUNT 1
59 # define VLCGL_PICTURE_MAX 1
61 # define VLCGL_TEXTURE_COUNT 1
62 # define VLCGL_PICTURE_MAX 128
65 static const vlc_fourcc_t gl_subpicture_chromas[] = {
85 struct vout_display_opengl_t {
89 const vlc_chroma_description_t *chroma;
96 int tex_width[PICTURE_PLANE_MAX];
97 int tex_height[PICTURE_PLANE_MAX];
99 GLuint texture[VLCGL_TEXTURE_COUNT][PICTURE_PLANE_MAX];
105 picture_pool_t *pool;
109 GLfloat local_value[16][4];
111 /* fragment_program */
112 PFNGLGENPROGRAMSARBPROC GenProgramsARB;
113 PFNGLBINDPROGRAMARBPROC BindProgramARB;
114 PFNGLPROGRAMSTRINGARBPROC ProgramStringARB;
115 PFNGLDELETEPROGRAMSARBPROC DeleteProgramsARB;
116 PFNGLPROGRAMLOCALPARAMETER4FVARBPROC ProgramLocalParameter4fvARB;
119 bool use_multitexture;
120 PFNGLACTIVETEXTUREARBPROC ActiveTextureARB;
121 PFNGLMULTITEXCOORD2FARBPROC MultiTexCoord2fARB;
124 static inline int GetAlignedSize(unsigned size)
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;
131 static bool IsLuminance16Supported(int target)
135 glGenTextures(1, &texture);
136 glBindTexture(target, texture);
137 glTexImage2D(target, 0, GL_LUMINANCE16,
138 64, 64, 0, GL_LUMINANCE, GL_UNSIGNED_SHORT, NULL);
140 glGetTexLevelParameteriv(target, 0, GL_TEXTURE_LUMINANCE_SIZE, &size);
142 glDeleteTextures(1, &texture);
147 vout_display_opengl_t *vout_display_opengl_New(video_format_t *fmt,
148 const vlc_fourcc_t **subpicture_chromas,
151 vout_display_opengl_t *vgl = calloc(1, sizeof(*vgl));
156 if (vlc_gl_Lock(vgl->gl)) {
161 const char *extensions = (const char *)glGetString(GL_EXTENSIONS);
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");
173 vgl->GenProgramsARB = glGenProgramsARB;
174 vgl->BindProgramARB = glBindProgramARB;
175 vgl->ProgramStringARB = glProgramStringARB;
176 vgl->DeleteProgramsARB = glDeleteProgramsARB;
177 vgl->ProgramLocalParameter4fvARB = glProgramLocalParameter4fvARB;
179 supports_fp = vgl->GenProgramsARB &&
180 vgl->BindProgramARB &&
181 vgl->ProgramStringARB &&
182 vgl->DeleteProgramsARB &&
183 vgl->ProgramLocalParameter4fvARB;
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");
193 vgl->ActiveTextureARB = glActiveTextureARB;
194 vgl->MultiTexCoord2fARB = glMultiTexCoord2fARB;
196 supports_multitexture = vgl->ActiveTextureARB &&
197 vgl->MultiTexCoord2fARB;
198 if (supports_multitexture)
199 glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &max_texture_units);
202 /* Initialize with default chroma */
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;
211 vgl->fmt.i_rmask = 0xf800;
212 vgl->fmt.i_gmask = 0x07e0;
213 vgl->fmt.i_bmask = 0x001f;
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;
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;
226 vgl->fmt.i_rmask = 0x000000ff;
227 vgl->fmt.i_gmask = 0x0000ff00;
228 vgl->fmt.i_bmask = 0x00ff0000;
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;
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);
242 const vlc_chroma_description_t *dsc = vlc_fourcc_GetChromaDescription(*list);
243 if (dsc && dsc->plane_count == 3 && dsc->pixel_size == 1) {
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;
252 } else if (dsc && dsc->plane_count == 3 && dsc->pixel_size == 2 &&
253 IsLuminance16Supported(vgl->tex_target)) {
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);
267 vgl->chroma = vlc_fourcc_GetChromaDescription(vgl->fmt.i_chroma);
268 vgl->use_multitexture = vgl->chroma->plane_count > 1;
270 bool supports_npot = false;
271 #if USE_OPENGL_ES == 2
272 supports_npot = true;
274 supports_npot |= HasExtension(extensions, "GL_APPLE_texture_2D_limited_npot") ||
275 HasExtension(extensions, "GL_ARB_texture_non_power_of_two");
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;
283 vgl->tex_width[j] = w;
284 vgl->tex_height[j] = h;
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);
293 /* Build fragment program if needed */
295 vgl->local_count = 0;
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
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 },
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 },
314 const float (*matrix)[4] = fmt->i_height > 576 ? matrix_bt709_tv2full
315 : matrix_bt601_tv2full;
317 /* Basic linear YUV -> RGB conversion using bilinear interpolation */
318 const char *template_yuv =
320 "OPTION ARB_precision_hint_fastest;"
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;"
327 "PARAM coefficient[4] = { program.local[0..3] };"
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;"
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,
338 swap_uv ? 'y' : 'z') < 0)
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;
347 vgl->local_count += 4;
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 */
360 glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &position);
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);
365 vgl->DeleteProgramsARB(1, &vgl->program);
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);
380 vlc_gl_Unlock(vgl->gl);
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;
387 vgl->region_count = 0;
392 if (subpicture_chromas) {
393 *subpicture_chromas = NULL;
396 *subpicture_chromas = gl_subpicture_chromas;
402 void vout_display_opengl_Delete(vout_display_opengl_t *vgl)
405 if (!vlc_gl_Lock(vgl->gl)) {
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);
418 vgl->DeleteProgramsARB(1, &vgl->program);
420 vlc_gl_Unlock(vgl->gl);
423 picture_pool_Delete(vgl->pool);
427 picture_pool_t *vout_display_opengl_GetPool(vout_display_opengl_t *vgl, unsigned requested_count)
432 /* Allocate our pictures */
433 picture_t *picture[VLCGL_PICTURE_MAX] = {NULL, };
436 for (count = 0; count < __MIN(VLCGL_PICTURE_MAX, requested_count); count++) {
437 picture[count] = picture_NewFromFormat(&vgl->fmt);
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);
453 /* Allocates our textures */
454 if (vlc_gl_Lock(vgl->gl))
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]);
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);
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);
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);
482 vlc_gl_Unlock(vgl->gl);
487 for (unsigned i = 0; i < count; i++)
488 picture_Release(picture[i]);
492 int vout_display_opengl_Prepare(vout_display_opengl_t *vgl,
493 picture_t *picture, subpicture_t *subpicture)
495 /* On Win32/GLX, we do this the usual way:
496 + Fill the buffer with new content,
497 + Reload the texture,
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,
505 (Thanks to gcc from the Arstechnica forums for the tip)
507 Therefore on OSX, we have to use two buffers and textures and use a
508 lock(/unlock) managed picture pool.
511 if (vlc_gl_Lock(vgl->gl))
514 /* Update the texture */
515 for (unsigned j = 0; j < vgl->chroma->plane_count; j++) {
516 if (vgl->use_multitexture)
517 vgl->ActiveTextureARB(GL_TEXTURE0_ARB + j);
518 glBindTexture(vgl->tex_target, vgl->texture[0][j]);
519 glPixelStorei(GL_UNPACK_ROW_LENGTH, picture->p[j].i_pitch / picture->p[j].i_pixel_pitch);
520 glTexSubImage2D(vgl->tex_target, 0,
522 vgl->fmt.i_width * vgl->chroma->p[j].w.num / vgl->chroma->p[j].w.den,
523 vgl->fmt.i_height * vgl->chroma->p[j].h.num / vgl->chroma->p[j].h.den,
524 vgl->tex_format, vgl->tex_type, picture->p[j].p_pixels);
527 int last_count = vgl->region_count;
528 gl_region_t *last = vgl->region;
530 vgl->region_count = 0;
536 for (subpicture_region_t *r = subpicture->p_region; r; r = r->p_next)
539 vgl->region_count = count;
540 vgl->region = calloc(count, sizeof(*vgl->region));
542 if (vgl->use_multitexture)
543 vgl->ActiveTextureARB(GL_TEXTURE0_ARB + 0);
545 for (subpicture_region_t *r = subpicture->p_region; r; r = r->p_next, i++) {
546 gl_region_t *glr = &vgl->region[i];
548 glr->format = GL_RGBA;
549 glr->type = GL_UNSIGNED_BYTE;
550 glr->width = r->fmt.i_visible_width;
551 glr->height = r->fmt.i_visible_height;
552 glr->alpha = (float)subpicture->i_alpha * r->i_alpha / 255 / 255;
553 glr->left = 2.0 * (r->i_x ) / subpicture->i_original_picture_width - 1.0;
554 glr->top = -2.0 * (r->i_y ) / subpicture->i_original_picture_height + 1.0;
555 glr->right = 2.0 * (r->i_x + r->fmt.i_visible_width ) / subpicture->i_original_picture_width - 1.0;
556 glr->bottom = -2.0 * (r->i_y + r->fmt.i_visible_height) / subpicture->i_original_picture_height + 1.0;
559 for (int j = 0; j < last_count; j++) {
560 if (last[j].texture &&
561 last[j].width == glr->width &&
562 last[j].height == glr->height &&
563 last[j].format == glr->format &&
564 last[j].type == glr->type) {
565 glr->texture = last[j].texture;
566 memset(&last[j], 0, sizeof(last[j]));
571 const int pixels_offset = r->fmt.i_y_offset * r->p_picture->p->i_pitch +
572 r->fmt.i_x_offset * r->p_picture->p->i_pixel_pitch;
574 glBindTexture(GL_TEXTURE_2D, glr->texture);
575 /* TODO set GL_UNPACK_ALIGNMENT */
576 glPixelStorei(GL_UNPACK_ROW_LENGTH, r->p_picture->p->i_pitch / r->p_picture->p->i_pixel_pitch);
577 glTexSubImage2D(GL_TEXTURE_2D, 0,
578 0, 0, glr->width, glr->height,
579 glr->format, glr->type, &r->p_picture->p->p_pixels[pixels_offset]);
581 glGenTextures(1, &glr->texture);
582 glBindTexture(GL_TEXTURE_2D, glr->texture);
583 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_PRIORITY, 1.0);
584 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
585 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
586 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
587 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
588 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
589 /* TODO set GL_UNPACK_ALIGNMENT */
590 glPixelStorei(GL_UNPACK_ROW_LENGTH, r->p_picture->p->i_pitch / r->p_picture->p->i_pixel_pitch);
591 glTexImage2D(GL_TEXTURE_2D, 0, glr->format,
592 glr->width, glr->height, 0, glr->format, glr->type,
593 &r->p_picture->p->p_pixels[pixels_offset]);
597 for (int i = 0; i < last_count; i++) {
599 glDeleteTextures(1, &last[i].texture);
603 vlc_gl_Unlock(vgl->gl);
604 VLC_UNUSED(subpicture);
608 int vout_display_opengl_Display(vout_display_opengl_t *vgl,
609 const video_format_t *source)
611 if (vlc_gl_Lock(vgl->gl))
614 /* glTexCoord works differently with GL_TEXTURE_2D and
615 GL_TEXTURE_RECTANGLE_EXT */
616 float left[PICTURE_PLANE_MAX];
617 float top[PICTURE_PLANE_MAX];
618 float right[PICTURE_PLANE_MAX];
619 float bottom[PICTURE_PLANE_MAX];
620 for (unsigned j = 0; j < vgl->chroma->plane_count; j++) {
621 float scale_w, scale_h;
622 if (vgl->tex_target == GL_TEXTURE_2D) {
623 scale_w = (float)vgl->chroma->p[j].w.num / vgl->chroma->p[j].w.den / vgl->tex_width[j];
624 scale_h = (float)vgl->chroma->p[j].h.num / vgl->chroma->p[j].h.den / vgl->tex_height[j];
630 left[j] = (source->i_x_offset + 0 ) * scale_w;
631 top[j] = (source->i_y_offset + 0 ) * scale_h;
632 right[j] = (source->i_x_offset + source->i_visible_width ) * scale_w;
633 bottom[j] = (source->i_y_offset + source->i_visible_height) * scale_h;
637 /* Why drawing here and not in Render()? Because this way, the
638 OpenGL providers can call vout_display_opengl_Display to force redraw.i
639 Currently, the OS X provider uses it to get a smooth window resizing */
641 glClear(GL_COLOR_BUFFER_BIT);
644 glEnable(GL_FRAGMENT_PROGRAM_ARB);
645 for (int i = 0; i < vgl->local_count; i++)
646 vgl->ProgramLocalParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, i, vgl->local_value[i]);
648 glEnable(vgl->tex_target);
652 static const GLfloat vertexCoord[] = {
659 const GLfloat textureCoord[8] = {
666 glEnableClientState(GL_VERTEX_ARRAY);
667 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
668 glVertexPointer(2, GL_FLOAT, 0, vertexCoord);
669 glTexCoordPointer(2, GL_FLOAT, 0, textureCoord);
671 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
673 for (unsigned j = 0; j < vgl->chroma->plane_count; j++) {
674 if (vgl->use_multitexture)
675 vgl->ActiveTextureARB(GL_TEXTURE0_ARB + j);
676 glBindTexture(vgl->tex_target, vgl->texture[0][j]);
680 glTexCoord2f(left[0], top[0]);
681 for (unsigned j = 1; j < vgl->chroma->plane_count; j++)
682 vgl->MultiTexCoord2fARB(GL_TEXTURE0_ARB + j, left[j], top[j]);
683 glVertex2f(-1.0, 1.0);
685 glTexCoord2f(right[0], top[0]);
686 for (unsigned j = 1; j < vgl->chroma->plane_count; j++)
687 vgl->MultiTexCoord2fARB(GL_TEXTURE0_ARB + j, right[j], top[j]);
688 glVertex2f( 1.0, 1.0);
690 glTexCoord2f(right[0], bottom[0]);
691 for (unsigned j = 1; j < vgl->chroma->plane_count; j++)
692 vgl->MultiTexCoord2fARB(GL_TEXTURE0_ARB + j, right[j], bottom[j]);
693 glVertex2f( 1.0, -1.0);
695 glTexCoord2f(left[0], bottom[0]);
696 for (unsigned j = 1; j < vgl->chroma->plane_count; j++)
697 vgl->MultiTexCoord2fARB(GL_TEXTURE0_ARB + j, left[j], bottom[j]);
698 glVertex2f(-1.0, -1.0);
704 glDisable(GL_FRAGMENT_PROGRAM_ARB);
706 glDisable(vgl->tex_target);
709 if (vgl->use_multitexture)
710 vgl->ActiveTextureARB(GL_TEXTURE0_ARB + 0);
711 glEnable(GL_TEXTURE_2D);
713 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
714 for (int i = 0; i < vgl->region_count; i++) {
715 gl_region_t *glr = &vgl->region[i];
717 glBindTexture(GL_TEXTURE_2D, glr->texture);
721 glColor4f(1.0, 1.0, 1.0, glr->alpha);
723 glTexCoord2f(0.0, 0.0);
724 glVertex2f(glr->left, glr->top);
726 glTexCoord2f(1.0, 0.0);
727 glVertex2f(glr->right, glr->top);
729 glTexCoord2f(1.0, 1.0);
730 glVertex2f(glr->right, glr->bottom);
732 glTexCoord2f(0.0, 1.0);
733 glVertex2f(glr->left, glr->bottom);
738 glDisable(GL_TEXTURE_2D);
741 vlc_gl_Swap(vgl->gl);
743 vlc_gl_Unlock(vgl->gl);