1 /*****************************************************************************
2 * opengl.c: OpenGL and OpenGL ES output common code
3 *****************************************************************************
4 * Copyright (C) 2004 the VideoLAN team
5 * Copyright (C) 2009 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
60 #elif defined(MACOS_OPENGL)
61 # define VLCGL_TEXTURE_COUNT 2
62 # define VLCGL_PICTURE_MAX 2
64 # define VLCGL_TEXTURE_COUNT 1
65 # define VLCGL_PICTURE_MAX 128
68 static const vlc_fourcc_t gl_subpicture_chromas[] = {
88 struct vout_display_opengl_t {
92 const vlc_chroma_description_t *chroma;
99 int tex_width[PICTURE_PLANE_MAX];
100 int tex_height[PICTURE_PLANE_MAX];
102 GLuint texture[VLCGL_TEXTURE_COUNT][PICTURE_PLANE_MAX];
108 picture_pool_t *pool;
112 GLfloat local_value[16][4];
114 /* fragment_program */
115 PFNGLGENPROGRAMSARBPROC GenProgramsARB;
116 PFNGLBINDPROGRAMARBPROC BindProgramARB;
117 PFNGLPROGRAMSTRINGARBPROC ProgramStringARB;
118 PFNGLDELETEPROGRAMSARBPROC DeleteProgramsARB;
119 PFNGLPROGRAMLOCALPARAMETER4FVARBPROC ProgramLocalParameter4fvARB;
122 bool use_multitexture;
123 PFNGLACTIVETEXTUREARBPROC ActiveTextureARB;
124 PFNGLMULTITEXCOORD2FARBPROC MultiTexCoord2fARB;
127 static inline int GetAlignedSize(unsigned size)
129 /* Return the smallest larger or equal power of 2 */
130 unsigned align = 1 << (8 * sizeof (unsigned) - clz(size));
131 return ((align >> 1) == size) ? size : align;
134 static bool IsLuminance16Supported(int target)
138 glGenTextures(1, &texture);
139 glBindTexture(target, texture);
140 glTexImage2D(target, 0, GL_LUMINANCE16,
141 64, 64, 0, GL_LUMINANCE, GL_UNSIGNED_SHORT, NULL);
143 glGetTexLevelParameteriv(target, 0, GL_TEXTURE_LUMINANCE_SIZE, &size);
145 glDeleteTextures(1, &texture);
150 vout_display_opengl_t *vout_display_opengl_New(video_format_t *fmt,
151 const vlc_fourcc_t **subpicture_chromas,
154 vout_display_opengl_t *vgl = calloc(1, sizeof(*vgl));
159 if (vlc_gl_Lock(vgl->gl)) {
164 const char *extensions = (const char *)glGetString(GL_EXTENSIONS);
166 /* Load extensions */
167 bool supports_fp = false;
168 if (HasExtension(extensions, "GL_ARB_fragment_program")) {
169 #if !defined(MACOS_OPENGL)
170 vgl->GenProgramsARB = (PFNGLGENPROGRAMSARBPROC)vlc_gl_GetProcAddress(vgl->gl, "glGenProgramsARB");
171 vgl->BindProgramARB = (PFNGLBINDPROGRAMARBPROC)vlc_gl_GetProcAddress(vgl->gl, "glBindProgramARB");
172 vgl->ProgramStringARB = (PFNGLPROGRAMSTRINGARBPROC)vlc_gl_GetProcAddress(vgl->gl, "glProgramStringARB");
173 vgl->DeleteProgramsARB = (PFNGLDELETEPROGRAMSARBPROC)vlc_gl_GetProcAddress(vgl->gl, "glDeleteProgramsARB");
174 vgl->ProgramLocalParameter4fvARB = (PFNGLPROGRAMLOCALPARAMETER4FVARBPROC)vlc_gl_GetProcAddress(vgl->gl, "glProgramLocalParameter4fvARB");
176 vgl->GenProgramsARB = glGenProgramsARB;
177 vgl->BindProgramARB = glBindProgramARB;
178 vgl->ProgramStringARB = glProgramStringARB;
179 vgl->DeleteProgramsARB = glDeleteProgramsARB;
180 vgl->ProgramLocalParameter4fvARB = glProgramLocalParameter4fvARB;
182 supports_fp = vgl->GenProgramsARB &&
183 vgl->BindProgramARB &&
184 vgl->ProgramStringARB &&
185 vgl->DeleteProgramsARB &&
186 vgl->ProgramLocalParameter4fvARB;
189 bool supports_multitexture = false;
190 GLint max_texture_units = 0;
191 if (HasExtension(extensions, "GL_ARB_multitexture")) {
192 #if !defined(MACOS_OPENGL)
193 vgl->ActiveTextureARB = (PFNGLACTIVETEXTUREARBPROC)vlc_gl_GetProcAddress(vgl->gl, "glActiveTextureARB");
194 vgl->MultiTexCoord2fARB = (PFNGLMULTITEXCOORD2FARBPROC)vlc_gl_GetProcAddress(vgl->gl, "glMultiTexCoord2fARB");
196 vgl->ActiveTextureARB = glActiveTextureARB;
197 vgl->MultiTexCoord2fARB = glMultiTexCoord2fARB;
199 supports_multitexture = vgl->ActiveTextureARB &&
200 vgl->MultiTexCoord2fARB;
201 if (supports_multitexture)
202 glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &max_texture_units);
205 /* Initialize with default chroma */
208 vgl->fmt.i_chroma = VLC_CODEC_RGB16;
209 # if defined(WORDS_BIGENDIAN)
210 vgl->fmt.i_rmask = 0x001f;
211 vgl->fmt.i_gmask = 0x07e0;
212 vgl->fmt.i_bmask = 0xf800;
214 vgl->fmt.i_rmask = 0xf800;
215 vgl->fmt.i_gmask = 0x07e0;
216 vgl->fmt.i_bmask = 0x001f;
218 vgl->tex_target = GL_TEXTURE_2D;
219 vgl->tex_format = GL_RGB;
220 vgl->tex_internal = GL_RGB;
221 vgl->tex_type = GL_UNSIGNED_SHORT_5_6_5;
223 vgl->fmt.i_chroma = VLC_CODEC_RGB32;
224 # if defined(WORDS_BIGENDIAN)
225 vgl->fmt.i_rmask = 0xff000000;
226 vgl->fmt.i_gmask = 0x00ff0000;
227 vgl->fmt.i_bmask = 0x0000ff00;
229 vgl->fmt.i_rmask = 0x000000ff;
230 vgl->fmt.i_gmask = 0x0000ff00;
231 vgl->fmt.i_bmask = 0x00ff0000;
233 vgl->tex_target = GL_TEXTURE_2D;
234 vgl->tex_format = GL_RGBA;
235 vgl->tex_internal = GL_RGBA;
236 vgl->tex_type = GL_UNSIGNED_BYTE;
238 /* Use YUV if possible and needed */
239 bool need_fs_yuv = false;
240 float yuv_range_correction = 1.0;
241 if (supports_fp && supports_multitexture && max_texture_units >= 3 &&
242 vlc_fourcc_IsYUV(fmt->i_chroma) && !vlc_fourcc_IsYUV(vgl->fmt.i_chroma)) {
243 const vlc_fourcc_t *list = vlc_fourcc_GetYUVFallback(fmt->i_chroma);
245 const vlc_chroma_description_t *dsc = vlc_fourcc_GetChromaDescription(*list);
246 if (dsc && dsc->plane_count == 3 && dsc->pixel_size == 1) {
249 vgl->fmt.i_chroma = *list;
250 vgl->tex_format = GL_LUMINANCE;
251 vgl->tex_internal = GL_LUMINANCE;
252 vgl->tex_type = GL_UNSIGNED_BYTE;
253 yuv_range_correction = 1.0;
255 } else if (dsc && dsc->plane_count == 3 && dsc->pixel_size == 2 &&
256 IsLuminance16Supported(vgl->tex_target)) {
259 vgl->fmt.i_chroma = *list;
260 vgl->tex_format = GL_LUMINANCE;
261 vgl->tex_internal = GL_LUMINANCE16;
262 vgl->tex_type = GL_UNSIGNED_SHORT;
263 yuv_range_correction = (float)((1 << 16) - 1) / ((1 << dsc->pixel_bits) - 1);
270 vgl->chroma = vlc_fourcc_GetChromaDescription(vgl->fmt.i_chroma);
271 vgl->use_multitexture = vgl->chroma->plane_count > 1;
273 bool supports_npot = false;
274 #if USE_OPENGL_ES == 2
275 supports_npot = true;
277 supports_npot |= HasExtension(extensions, "GL_APPLE_texture_2D_limited_npot") ||
278 HasExtension(extensions, "GL_ARB_texture_non_power_of_two");
282 for (unsigned j = 0; j < vgl->chroma->plane_count; j++) {
283 int w = vgl->fmt.i_width * vgl->chroma->p[j].w.num / vgl->chroma->p[j].w.den;
284 int h = vgl->fmt.i_height * vgl->chroma->p[j].h.num / vgl->chroma->p[j].h.den;
286 vgl->tex_width[j] = w;
287 vgl->tex_height[j] = h;
290 /* A texture must have a size aligned on a power of 2 */
291 vgl->tex_width[j] = GetAlignedSize(w);
292 vgl->tex_height[j] = GetAlignedSize(h);
296 /* Build fragment program if needed */
298 vgl->local_count = 0;
303 /* [R/G/B][Y U V O] from TV range to full range
304 * XXX we could also do hue/brightness/constrast/gamma
305 * by simply changing the coefficients
307 const float matrix_bt601_tv2full[3][4] = {
308 { 1.1640, 0.0000, 1.4030, -0.7773 },
309 { 1.1640, -0.3440, -0.7140, 0.4580 },
310 { 1.1640, 1.7730, 0.0000, -0.9630 },
312 const float matrix_bt709_tv2full[3][4] = {
313 { 1.1640, 0.0000, 1.5701, -0.8612 },
314 { 1.1640, -0.1870, -0.4664, 0.2549 },
315 { 1.1640, 1.8556, 0.0000, -1.0045 },
317 const float (*matrix)[4] = fmt->i_height > 576 ? matrix_bt709_tv2full
318 : matrix_bt601_tv2full;
320 /* Basic linear YUV -> RGB conversion using bilinear interpolation */
321 const char *template_yuv =
323 "OPTION ARB_precision_hint_fastest;"
326 "TEX src.x, fragment.texcoord[0], texture[0], 2D;"
327 "TEX src.%c, fragment.texcoord[1], texture[1], 2D;"
328 "TEX src.%c, fragment.texcoord[2], texture[2], 2D;"
330 "PARAM coefficient[4] = { program.local[0..3] };"
333 "MAD tmp.rgb, src.xxxx, coefficient[0], coefficient[3];"
334 "MAD tmp.rgb, src.yyyy, coefficient[1], tmp;"
335 "MAD result.color.rgb, src.zzzz, coefficient[2], tmp;"
337 bool swap_uv = vgl->fmt.i_chroma == VLC_CODEC_YV12 ||
338 vgl->fmt.i_chroma == VLC_CODEC_YV9;
339 if (asprintf(&code, template_yuv,
341 swap_uv ? 'y' : 'z') < 0)
344 for (int i = 0; i < 4; i++) {
345 float correction = i < 3 ? yuv_range_correction : 1.0;
346 for (int j = 0; j < 4; j++) {
347 vgl->local_value[vgl->local_count + i][j] = j < 3 ? correction * matrix[j][i] : 0.0;
350 vgl->local_count += 4;
353 // Here you have shaders
354 vgl->GenProgramsARB(1, &vgl->program);
355 vgl->BindProgramARB(GL_FRAGMENT_PROGRAM_ARB, vgl->program);
356 vgl->ProgramStringARB(GL_FRAGMENT_PROGRAM_ARB,
357 GL_PROGRAM_FORMAT_ASCII_ARB,
358 strlen(code), (const GLbyte*)code);
359 if (glGetError() == GL_INVALID_OPERATION) {
360 /* FIXME if the program was needed for YUV, the video will be broken */
363 glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &position);
365 const char *msg = (const char *)glGetString(GL_PROGRAM_ERROR_STRING_ARB);
366 fprintf(stderr, "GL_INVALID_OPERATION: error at %d: %s\n", position, msg);
368 vgl->DeleteProgramsARB(1, &vgl->program);
377 glDisable(GL_DEPTH_TEST);
378 glDepthMask(GL_FALSE);
379 glDisable(GL_CULL_FACE);
380 glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
381 glClear(GL_COLOR_BUFFER_BIT);
383 vlc_gl_Unlock(vgl->gl);
386 for (int i = 0; i < VLCGL_TEXTURE_COUNT; i++) {
387 for (int j = 0; j < PICTURE_PLANE_MAX; j++)
388 vgl->texture[i][j] = 0;
390 vgl->region_count = 0;
395 if (subpicture_chromas) {
396 *subpicture_chromas = NULL;
399 *subpicture_chromas = gl_subpicture_chromas;
405 void vout_display_opengl_Delete(vout_display_opengl_t *vgl)
408 if (!vlc_gl_Lock(vgl->gl)) {
412 for (int i = 0; i < VLCGL_TEXTURE_COUNT; i++)
413 glDeleteTextures(vgl->chroma->plane_count, vgl->texture[i]);
414 for (int i = 0; i < vgl->region_count; i++) {
415 if (vgl->region[i].texture)
416 glDeleteTextures(1, &vgl->region[i].texture);
421 vgl->DeleteProgramsARB(1, &vgl->program);
423 vlc_gl_Unlock(vgl->gl);
426 picture_pool_Delete(vgl->pool);
430 picture_pool_t *vout_display_opengl_GetPool(vout_display_opengl_t *vgl, unsigned requested_count)
435 /* Allocate our pictures */
436 picture_t *picture[VLCGL_PICTURE_MAX] = {NULL, };
439 for (count = 0; count < __MIN(VLCGL_PICTURE_MAX, requested_count); count++) {
440 picture[count] = picture_NewFromFormat(&vgl->fmt);
447 /* Wrap the pictures into a pool */
448 picture_pool_configuration_t cfg;
449 memset(&cfg, 0, sizeof(cfg));
450 cfg.picture_count = count;
451 cfg.picture = picture;
452 vgl->pool = picture_pool_NewExtended(&cfg);
456 /* Allocates our textures */
457 if (vlc_gl_Lock(vgl->gl))
460 for (int i = 0; i < VLCGL_TEXTURE_COUNT; i++) {
461 glGenTextures(vgl->chroma->plane_count, vgl->texture[i]);
462 for (unsigned j = 0; j < vgl->chroma->plane_count; j++) {
463 if (vgl->use_multitexture)
464 vgl->ActiveTextureARB(GL_TEXTURE0_ARB + j);
465 glBindTexture(vgl->tex_target, vgl->texture[i][j]);
468 /* Set the texture parameters */
469 glTexParameterf(vgl->tex_target, GL_TEXTURE_PRIORITY, 1.0);
470 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
473 glTexParameteri(vgl->tex_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
474 glTexParameteri(vgl->tex_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
475 glTexParameteri(vgl->tex_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
476 glTexParameteri(vgl->tex_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
478 /* Call glTexImage2D only once, and use glTexSubImage2D later */
479 glTexImage2D(vgl->tex_target, 0,
480 vgl->tex_internal, vgl->tex_width[j], vgl->tex_height[j],
481 0, vgl->tex_format, vgl->tex_type, NULL);
485 vlc_gl_Unlock(vgl->gl);
490 for (unsigned i = 0; i < count; i++)
491 picture_Delete(picture[i]);
495 int vout_display_opengl_Prepare(vout_display_opengl_t *vgl,
496 picture_t *picture, subpicture_t *subpicture)
498 /* On Win32/GLX, we do this the usual way:
499 + Fill the buffer with new content,
500 + Reload the texture,
503 On OS X with VRAM or AGP texturing, the order has to be:
504 + Reload the texture,
505 + Fill the buffer with new content,
508 (Thanks to gcc from the Arstechnica forums for the tip)
510 Therefore on OSX, we have to use two buffers and textures and use a
511 lock(/unlock) managed picture pool.
514 if (vlc_gl_Lock(vgl->gl))
517 /* Update the texture */
518 for (unsigned j = 0; j < vgl->chroma->plane_count; j++) {
519 const int plane = vgl->fmt.i_chroma == VLC_CODEC_YV12 && j > 0 ? (3 - j) : j;
520 if (vgl->use_multitexture)
521 vgl->ActiveTextureARB(GL_TEXTURE0_ARB + j);
522 glBindTexture(vgl->tex_target, vgl->texture[0][j]);
523 glPixelStorei(GL_UNPACK_ROW_LENGTH, picture->p[plane].i_pitch / picture->p[plane].i_pixel_pitch);
524 glTexSubImage2D(vgl->tex_target, 0,
526 vgl->fmt.i_width * vgl->chroma->p[plane].w.num / vgl->chroma->p[plane].w.den,
527 vgl->fmt.i_height * vgl->chroma->p[plane].h.num / vgl->chroma->p[plane].h.den,
528 vgl->tex_format, vgl->tex_type, picture->p[plane].p_pixels);
531 int last_count = vgl->region_count;
532 gl_region_t *last = vgl->region;
534 vgl->region_count = 0;
540 for (subpicture_region_t *r = subpicture->p_region; r; r = r->p_next)
543 vgl->region_count = count;
544 vgl->region = calloc(count, sizeof(*vgl->region));
546 if (vgl->use_multitexture)
547 vgl->ActiveTextureARB(GL_TEXTURE0_ARB + 0);
549 for (subpicture_region_t *r = subpicture->p_region; r; r = r->p_next, i++) {
550 gl_region_t *glr = &vgl->region[i];
552 glr->format = GL_RGBA;
553 glr->type = GL_UNSIGNED_BYTE;
554 glr->width = r->fmt.i_visible_width;
555 glr->height = r->fmt.i_visible_height;
556 glr->alpha = (float)subpicture->i_alpha * r->i_alpha / 255 / 255;
557 glr->left = 2.0 * (r->i_x ) / subpicture->i_original_picture_width - 1.0;
558 glr->top = -2.0 * (r->i_y ) / subpicture->i_original_picture_height + 1.0;
559 glr->right = 2.0 * (r->i_x + r->fmt.i_visible_width ) / subpicture->i_original_picture_width - 1.0;
560 glr->bottom = -2.0 * (r->i_y + r->fmt.i_visible_height) / subpicture->i_original_picture_height + 1.0;
563 for (int j = 0; j < last_count; j++) {
564 if (last[j].texture &&
565 last[j].width == glr->width &&
566 last[j].height == glr->height &&
567 last[j].format == glr->format &&
568 last[j].type == glr->type) {
569 glr->texture = last[j].texture;
570 memset(&last[j], 0, sizeof(last[j]));
576 glBindTexture(GL_TEXTURE_2D, glr->texture);
577 /* TODO set GL_UNPACK_ALIGNMENT */
578 glPixelStorei(GL_UNPACK_ROW_LENGTH, r->p_picture->p->i_pitch / r->p_picture->p->i_pixel_pitch);
579 glTexSubImage2D(GL_TEXTURE_2D, 0,
580 0, 0, glr->width, glr->height,
581 glr->format, glr->type, r->p_picture->p->p_pixels);
583 glGenTextures(1, &glr->texture);
584 glBindTexture(GL_TEXTURE_2D, glr->texture);
585 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_PRIORITY, 1.0);
586 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
587 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
588 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
589 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
590 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
591 /* TODO set GL_UNPACK_ALIGNMENT */
592 glPixelStorei(GL_UNPACK_ROW_LENGTH, r->p_picture->p->i_pitch / r->p_picture->p->i_pixel_pitch);
593 glTexImage2D(GL_TEXTURE_2D, 0, glr->format,
594 glr->width, glr->height, 0, glr->format, glr->type,
595 r->p_picture->p->p_pixels);
599 for (int i = 0; i < last_count; i++) {
601 glDeleteTextures(1, &last[i].texture);
605 vlc_gl_Unlock(vgl->gl);
606 VLC_UNUSED(subpicture);
610 int vout_display_opengl_Display(vout_display_opengl_t *vgl,
611 const video_format_t *source)
613 if (vlc_gl_Lock(vgl->gl))
616 /* glTexCoord works differently with GL_TEXTURE_2D and
617 GL_TEXTURE_RECTANGLE_EXT */
618 float left[PICTURE_PLANE_MAX];
619 float top[PICTURE_PLANE_MAX];
620 float right[PICTURE_PLANE_MAX];
621 float bottom[PICTURE_PLANE_MAX];
622 for (unsigned j = 0; j < vgl->chroma->plane_count; j++) {
623 float scale_w, scale_h;
624 if (vgl->tex_target == GL_TEXTURE_2D) {
625 scale_w = (float)vgl->chroma->p[j].w.num / vgl->chroma->p[j].w.den / vgl->tex_width[j];
626 scale_h = (float)vgl->chroma->p[j].h.num / vgl->chroma->p[j].h.den / vgl->tex_height[j];
632 left[j] = (source->i_x_offset + 0 ) * scale_w;
633 top[j] = (source->i_y_offset + 0 ) * scale_h;
634 right[j] = (source->i_x_offset + source->i_visible_width ) * scale_w;
635 bottom[j] = (source->i_y_offset + source->i_visible_height) * scale_h;
639 /* Why drawing here and not in Render()? Because this way, the
640 OpenGL providers can call vout_display_opengl_Display to force redraw.i
641 Currently, the OS X provider uses it to get a smooth window resizing */
643 glClear(GL_COLOR_BUFFER_BIT);
646 glEnable(GL_FRAGMENT_PROGRAM_ARB);
647 for (int i = 0; i < vgl->local_count; i++)
648 vgl->ProgramLocalParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, i, vgl->local_value[i]);
650 glEnable(vgl->tex_target);
654 static const GLfloat vertexCoord[] = {
661 const GLfloat textureCoord[8] = {
668 glEnableClientState(GL_VERTEX_ARRAY);
669 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
670 glVertexPointer(2, GL_FLOAT, 0, vertexCoord);
671 glTexCoordPointer(2, GL_FLOAT, 0, textureCoord);
673 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
675 for (unsigned j = 0; j < vgl->chroma->plane_count; j++) {
676 if (vgl->use_multitexture)
677 vgl->ActiveTextureARB(GL_TEXTURE0_ARB + j);
678 glBindTexture(vgl->tex_target, vgl->texture[0][j]);
682 glTexCoord2f(left[0], top[0]);
683 for (unsigned j = 1; j < vgl->chroma->plane_count; j++)
684 vgl->MultiTexCoord2fARB(GL_TEXTURE0_ARB + j, left[j], top[j]);
685 glVertex2f(-1.0, 1.0);
687 glTexCoord2f(right[0], top[0]);
688 for (unsigned j = 1; j < vgl->chroma->plane_count; j++)
689 vgl->MultiTexCoord2fARB(GL_TEXTURE0_ARB + j, right[j], top[j]);
690 glVertex2f( 1.0, 1.0);
692 glTexCoord2f(right[0], bottom[0]);
693 for (unsigned j = 1; j < vgl->chroma->plane_count; j++)
694 vgl->MultiTexCoord2fARB(GL_TEXTURE0_ARB + j, right[j], bottom[j]);
695 glVertex2f( 1.0, -1.0);
697 glTexCoord2f(left[0], bottom[0]);
698 for (unsigned j = 1; j < vgl->chroma->plane_count; j++)
699 vgl->MultiTexCoord2fARB(GL_TEXTURE0_ARB + j, left[j], bottom[j]);
700 glVertex2f(-1.0, -1.0);
706 glDisable(GL_FRAGMENT_PROGRAM_ARB);
708 glDisable(vgl->tex_target);
711 if (vgl->use_multitexture)
712 vgl->ActiveTextureARB(GL_TEXTURE0_ARB + 0);
713 glEnable(GL_TEXTURE_2D);
715 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
716 for (int i = 0; i < vgl->region_count; i++) {
717 gl_region_t *glr = &vgl->region[i];
719 glBindTexture(GL_TEXTURE_2D, glr->texture);
723 glColor4f(1.0, 1.0, 1.0, glr->alpha);
725 glTexCoord2f(0.0, 0.0);
726 glVertex2f(glr->left, glr->top);
728 glTexCoord2f(1.0, 0.0);
729 glVertex2f(glr->right, glr->top);
731 glTexCoord2f(1.0, 1.0);
732 glVertex2f(glr->right, glr->bottom);
734 glTexCoord2f(0.0, 1.0);
735 glVertex2f(glr->left, glr->bottom);
740 glDisable(GL_TEXTURE_2D);
743 vlc_gl_Swap(vgl->gl);
745 vlc_gl_Unlock(vgl->gl);