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
39 #if !defined (__APPLE__)
40 # if USE_OPENGL_ES == 2
41 # include <GLES2/gl2ext.h>
42 # elif USE_OPENGL_ES == 1
43 # include <GLES/glext.h>
45 # include <GL/glext.h>
48 # if USE_OPENGL_ES == 2
49 # include <OpenGLES/ES2/gl.h>
50 # elif USE_OPENGL_ES == 1
51 # include <OpenGLES/ES1/gl.h>
54 # include <OpenGL/glext.h>
59 #ifndef GL_UNSIGNED_SHORT_5_6_5
60 # define GL_UNSIGNED_SHORT_5_6_5 0x8363
62 #ifndef GL_CLAMP_TO_EDGE
63 # define GL_CLAMP_TO_EDGE 0x812F
67 # define VLCGL_TEXTURE_COUNT 1
68 # define VLCGL_PICTURE_MAX 1
69 #elif defined(MACOS_OPENGL)
70 # define VLCGL_TEXTURE_COUNT 2
71 # define VLCGL_PICTURE_MAX 2
73 # define VLCGL_TEXTURE_COUNT 1
74 # define VLCGL_PICTURE_MAX 128
77 static const vlc_fourcc_t gl_subpicture_chromas[] = {
97 struct vout_display_opengl_t {
101 const vlc_chroma_description_t *chroma;
107 int tex_width[PICTURE_PLANE_MAX];
108 int tex_height[PICTURE_PLANE_MAX];
110 GLuint texture[VLCGL_TEXTURE_COUNT][PICTURE_PLANE_MAX];
116 picture_pool_t *pool;
120 GLfloat local_value[16][4];
122 /* fragment_program */
123 void (*GenProgramsARB)(GLsizei, GLuint *);
124 void (*BindProgramARB)(GLenum, GLuint);
125 void (*ProgramStringARB)(GLenum, GLenum, GLsizei, const GLvoid *);
126 void (*DeleteProgramsARB)(GLsizei, const GLuint *);
127 void (*ProgramLocalParameter4fvARB)(GLenum, GLuint, const GLfloat *);
130 bool use_multitexture;
131 void (*ActiveTextureARB)(GLenum);
132 void (*MultiTexCoord2fARB)(GLenum, GLfloat, GLfloat);
135 static inline int GetAlignedSize(unsigned size)
137 /* Return the smallest larger or equal power of 2 */
138 unsigned align = 1 << (8 * sizeof (unsigned) - clz(size));
139 return ((align >> 1) == size) ? size : align;
142 vout_display_opengl_t *vout_display_opengl_New(video_format_t *fmt,
143 const vlc_fourcc_t **subpicture_chromas,
146 vout_display_opengl_t *vgl = calloc(1, sizeof(*vgl));
151 if (vlc_gl_Lock(vgl->gl)) {
156 const char *extensions = (const char *)glGetString(GL_EXTENSIONS);
160 /* Load extensions */
161 bool supports_fp = false;
162 if (strstr(extensions, "GL_ARB_fragment_program")) {
163 vgl->GenProgramsARB = (void (*)(GLsizei, GLuint *))vlc_gl_GetProcAddress(vgl->gl, "glGenProgramsARB");
164 vgl->BindProgramARB = (void (*)(GLenum, GLuint))vlc_gl_GetProcAddress(vgl->gl, "glBindProgramARB");
165 vgl->ProgramStringARB = (void (*)(GLenum, GLenum, GLsizei, const GLvoid *))vlc_gl_GetProcAddress(vgl->gl, "glProgramStringARB");
166 vgl->DeleteProgramsARB = (void (*)(GLsizei, const GLuint *))vlc_gl_GetProcAddress(vgl->gl, "glDeleteProgramsARB");
167 vgl->ProgramLocalParameter4fvARB = (void (*)(GLenum, GLuint, const GLfloat *))vlc_gl_GetProcAddress(vgl->gl, "glProgramLocalParameter4fvARB");
169 supports_fp = vgl->GenProgramsARB &&
170 vgl->BindProgramARB &&
171 vgl->ProgramStringARB &&
172 vgl->DeleteProgramsARB &&
173 vgl->ProgramLocalParameter4fvARB;
175 bool supports_multitexture = false;
176 if (strstr(extensions, "GL_ARB_multitexture")) {
177 vgl->ActiveTextureARB = (void (*)(GLenum))vlc_gl_GetProcAddress(vgl->gl, "glActiveTextureARB");
178 vgl->MultiTexCoord2fARB = (void (*)(GLenum, GLfloat, GLfloat))vlc_gl_GetProcAddress(vgl->gl, "glMultiTexCoord2fARB");
180 supports_multitexture = vgl->ActiveTextureARB &&
181 vgl->MultiTexCoord2fARB;
184 /* Initialize with default chroma */
187 vgl->fmt.i_chroma = VLC_CODEC_RGB16;
188 # if defined(WORDS_BIGENDIAN)
189 vgl->fmt.i_rmask = 0x001f;
190 vgl->fmt.i_gmask = 0x07e0;
191 vgl->fmt.i_bmask = 0xf800;
193 vgl->fmt.i_rmask = 0xf800;
194 vgl->fmt.i_gmask = 0x07e0;
195 vgl->fmt.i_bmask = 0x001f;
197 vgl->tex_target = GL_TEXTURE_2D;
198 vgl->tex_format = GL_RGB;
199 vgl->tex_type = GL_UNSIGNED_SHORT_5_6_5;
200 #elif defined(MACOS_OPENGL)
201 # if defined(WORDS_BIGENDIAN)
202 vgl->fmt.i_chroma = VLC_CODEC_YUYV;
204 vgl->fmt.i_chroma = VLC_CODEC_UYVY;
206 vgl->tex_target = GL_TEXTURE_RECTANGLE_EXT;
207 vgl->tex_format = GL_YCBCR_422_APPLE;
208 vgl->tex_type = GL_UNSIGNED_SHORT_8_8_APPLE;
210 vgl->fmt.i_chroma = VLC_CODEC_RGB32;
211 # if defined(WORDS_BIGENDIAN)
212 vgl->fmt.i_rmask = 0xff000000;
213 vgl->fmt.i_gmask = 0x00ff0000;
214 vgl->fmt.i_bmask = 0x0000ff00;
216 vgl->fmt.i_rmask = 0x000000ff;
217 vgl->fmt.i_gmask = 0x0000ff00;
218 vgl->fmt.i_bmask = 0x00ff0000;
220 vgl->tex_target = GL_TEXTURE_2D;
221 vgl->tex_format = GL_RGBA;
222 vgl->tex_type = GL_UNSIGNED_BYTE;
224 /* Use YUV if possible and needed */
225 bool need_fs_yuv = false;
226 if (supports_fp && supports_multitexture &&
227 vlc_fourcc_IsYUV(fmt->i_chroma) && !vlc_fourcc_IsYUV(vgl->fmt.i_chroma)) {
228 const vlc_fourcc_t *list = vlc_fourcc_GetYUVFallback(fmt->i_chroma);
230 const vlc_chroma_description_t *dsc = vlc_fourcc_GetChromaDescription(*list);
231 if (dsc && dsc->plane_count == 3 && dsc->pixel_size == 1) {
234 vgl->fmt.i_chroma = *list;
235 vgl->tex_format = GL_LUMINANCE;
236 vgl->tex_type = GL_UNSIGNED_BYTE;
243 vgl->chroma = vlc_fourcc_GetChromaDescription(vgl->fmt.i_chroma);
244 vgl->use_multitexture = vgl->chroma->plane_count > 1;
246 bool supports_npot = false;
247 #if USE_OPENGL_ES == 2
248 supports_npot = true;
249 #elif defined(MACOS_OPENGL)
250 supports_npot = true;
252 supports_npot |= strstr(extensions, "GL_APPLE_texture_2D_limited_npot") != NULL ||
253 strstr(extensions, "GL_ARB_texture_non_power_of_two");
257 for (unsigned j = 0; j < vgl->chroma->plane_count; j++) {
258 int w = vgl->fmt.i_width * vgl->chroma->p[j].w.num / vgl->chroma->p[j].w.den;
259 int h = vgl->fmt.i_height * vgl->chroma->p[j].h.num / vgl->chroma->p[j].h.den;
261 vgl->tex_width[j] = w;
262 vgl->tex_height[j] = h;
265 /* A texture must have a size aligned on a power of 2 */
266 vgl->tex_width[j] = GetAlignedSize(w);
267 vgl->tex_height[j] = GetAlignedSize(h);
271 /* Build fragment program if needed */
273 vgl->local_count = 0;
278 /* [R/G/B][Y U V O] from TV range to full range
279 * XXX we could also do hue/brightness/constrast/gamma
280 * by simply changing the coefficients
282 const float matrix_bt601_tv2full[3][4] = {
283 { 1.1640, 0.0000, 1.4030, -0.7773 },
284 { 1.1640, -0.3440, -0.7140, 0.4580 },
285 { 1.1640, 1.7730, 0.0000, -0.9630 },
287 const float matrix_bt709_tv2full[3][4] = {
288 { 1.1640, 0.0000, 1.5701, -0.8612 },
289 { 1.1640, -0.1870, -0.4664, 0.2549 },
290 { 1.1640, 1.8556, 0.0000, -1.0045 },
292 const float (*matrix)[4] = fmt->i_height > 576 ? matrix_bt709_tv2full
293 : matrix_bt601_tv2full;
295 /* Basic linear YUV -> RGB conversion using bilinear interpolation */
296 const char *template_yuv =
298 "OPTION ARB_precision_hint_fastest;"
301 "TEX src.x, fragment.texcoord[0], texture[0], 2D;"
302 "TEX src.%c, fragment.texcoord[1], texture[1], 2D;"
303 "TEX src.%c, fragment.texcoord[2], texture[2], 2D;"
305 "PARAM coefficient[4] = { program.local[0..3] };"
308 "MAD tmp.rgb, src.xxxx, coefficient[0], coefficient[3];"
309 "MAD tmp.rgb, src.yyyy, coefficient[1], tmp;"
310 "MAD result.color.rgb, src.zzzz, coefficient[2], tmp;"
312 bool swap_uv = vgl->fmt.i_chroma == VLC_CODEC_YV12 ||
313 vgl->fmt.i_chroma == VLC_CODEC_YV9;
314 if (asprintf(&code, template_yuv,
316 swap_uv ? 'y' : 'z') < 0)
319 for (int i = 0; i < 4; i++)
320 for (int j = 0; j < 4; j++)
321 vgl->local_value[vgl->local_count + i][j] = j < 3 ? matrix[j][i] : 0.0;
322 vgl->local_count += 4;
325 vgl->GenProgramsARB(1, &vgl->program);
326 vgl->BindProgramARB(GL_FRAGMENT_PROGRAM_ARB, vgl->program);
327 vgl->ProgramStringARB(GL_FRAGMENT_PROGRAM_ARB,
328 GL_PROGRAM_FORMAT_ASCII_ARB,
329 strlen(code), (const GLbyte*)code);
330 if (glGetError() == GL_INVALID_OPERATION) {
331 /* FIXME if the program was needed for YUV, the video will be broken */
334 glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &position);
336 const char *msg = (const char *)glGetString(GL_PROGRAM_ERROR_STRING_ARB);
337 fprintf(stderr, "GL_INVALID_OPERATION: error at %d: %s\n", position, msg);
339 vgl->DeleteProgramsARB(1, &vgl->program);
348 glDisable(GL_DEPTH_TEST);
349 glDepthMask(GL_FALSE);
350 glDisable(GL_CULL_FACE);
351 glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
352 glClear(GL_COLOR_BUFFER_BIT);
354 vlc_gl_Unlock(vgl->gl);
357 for (int i = 0; i < VLCGL_TEXTURE_COUNT; i++) {
358 for (int j = 0; j < PICTURE_PLANE_MAX; j++)
359 vgl->texture[i][j] = 0;
361 vgl->region_count = 0;
366 if (subpicture_chromas) {
367 *subpicture_chromas = NULL;
368 #if !defined(MACOS_OPENGL) && !USE_OPENGL_ES
370 *subpicture_chromas = gl_subpicture_chromas;
376 void vout_display_opengl_Delete(vout_display_opengl_t *vgl)
379 if (!vlc_gl_Lock(vgl->gl)) {
383 for (int i = 0; i < VLCGL_TEXTURE_COUNT; i++)
384 glDeleteTextures(vgl->chroma->plane_count, vgl->texture[i]);
387 vgl->DeleteProgramsARB(1, &vgl->program);
389 vlc_gl_Unlock(vgl->gl);
392 picture_pool_Delete(vgl->pool);
397 struct picture_sys_t {
398 vout_display_opengl_t *vgl;
403 static inline GLuint PictureGetTexture(picture_t *picture)
405 return *picture->p_sys->texture;
408 static int PictureLock(picture_t *picture)
413 vout_display_opengl_t *vgl = picture->p_sys->vgl;
414 if (!vlc_gl_Lock(vgl->gl)) {
415 glBindTexture(vgl->tex_target, PictureGetTexture(picture));
416 glTexSubImage2D(vgl->tex_target, 0,
417 0, 0, vgl->fmt.i_width, vgl->fmt.i_height,
418 vgl->tex_format, vgl->tex_type, picture->p[0].p_pixels);
420 vlc_gl_Unlock(vgl->gl);
425 static void PictureUnlock(picture_t *picture)
431 picture_pool_t *vout_display_opengl_GetPool(vout_display_opengl_t *vgl, unsigned requested_count)
436 /* Allocate our pictures */
437 picture_t *picture[VLCGL_PICTURE_MAX] = {NULL, };
440 for (count = 0; count < __MIN(VLCGL_PICTURE_MAX, requested_count); count++) {
441 picture[count] = picture_NewFromFormat(&vgl->fmt);
446 picture_sys_t *sys = picture[count]->p_sys = malloc(sizeof(*sys));
449 sys->texture = vgl->texture[count];
456 /* Wrap the pictures into a pool */
457 picture_pool_configuration_t cfg;
458 memset(&cfg, 0, sizeof(cfg));
459 cfg.picture_count = count;
460 cfg.picture = picture;
462 cfg.lock = PictureLock;
463 cfg.unlock = PictureUnlock;
465 vgl->pool = picture_pool_NewExtended(&cfg);
469 /* Allocates our textures */
470 if (vlc_gl_Lock(vgl->gl))
473 for (int i = 0; i < VLCGL_TEXTURE_COUNT; i++) {
474 glGenTextures(vgl->chroma->plane_count, vgl->texture[i]);
475 for (unsigned j = 0; j < vgl->chroma->plane_count; j++) {
476 if (vgl->use_multitexture)
477 vgl->ActiveTextureARB(GL_TEXTURE0_ARB + j);
478 glBindTexture(vgl->tex_target, vgl->texture[i][j]);
481 /* Set the texture parameters */
482 glTexParameterf(vgl->tex_target, GL_TEXTURE_PRIORITY, 1.0);
483 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
486 glTexParameteri(vgl->tex_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
487 glTexParameteri(vgl->tex_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
488 glTexParameteri(vgl->tex_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
489 glTexParameteri(vgl->tex_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
492 /* Tell the driver not to make a copy of the texture but to use
494 glEnable(GL_UNPACK_CLIENT_STORAGE_APPLE);
495 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
497 /* Use AGP texturing */
498 glTexParameteri(vgl->tex_target, GL_TEXTURE_STORAGE_HINT_APPLE,
499 GL_STORAGE_SHARED_APPLE);
502 /* Call glTexImage2D only once, and use glTexSubImage2D later */
503 glTexImage2D(vgl->tex_target, 0,
504 vgl->tex_format, vgl->tex_width[j], vgl->tex_height[j],
505 0, vgl->tex_format, vgl->tex_type, NULL);
509 vlc_gl_Unlock(vgl->gl);
514 for (unsigned i = 0; i < count; i++)
515 picture_Delete(picture[i]);
519 int vout_display_opengl_Prepare(vout_display_opengl_t *vgl,
520 picture_t *picture, subpicture_t *subpicture)
522 /* On Win32/GLX, we do this the usual way:
523 + Fill the buffer with new content,
524 + Reload the texture,
527 On OS X with VRAM or AGP texturing, the order has to be:
528 + Reload the texture,
529 + Fill the buffer with new content,
532 (Thanks to gcc from the Arstechnica forums for the tip)
534 Therefore on OSX, we have to use two buffers and textures and use a
535 lock(/unlock) managed picture pool.
538 if (vlc_gl_Lock(vgl->gl))
542 /* Bind to the texture for drawing */
543 glBindTexture(vgl->tex_target, PictureGetTexture(picture));
545 /* Update the texture */
546 for (unsigned j = 0; j < vgl->chroma->plane_count; j++) {
547 if (vgl->use_multitexture)
548 vgl->ActiveTextureARB(GL_TEXTURE0_ARB + j);
549 glBindTexture(vgl->tex_target, vgl->texture[0][j]);
550 glPixelStorei(GL_UNPACK_ROW_LENGTH, picture->p[j].i_pitch / picture->p[j].i_pixel_pitch);
551 glTexSubImage2D(vgl->tex_target, 0,
553 vgl->fmt.i_width * vgl->chroma->p[j].w.num / vgl->chroma->p[j].w.den,
554 vgl->fmt.i_height * vgl->chroma->p[j].h.num / vgl->chroma->p[j].h.den,
555 vgl->tex_format, vgl->tex_type, picture->p[j].p_pixels);
559 int last_count = vgl->region_count;
560 gl_region_t *last = vgl->region;
562 vgl->region_count = 0;
568 for (subpicture_region_t *r = subpicture->p_region; r; r = r->p_next)
571 vgl->region_count = count;
572 vgl->region = calloc(count, sizeof(*vgl->region));
574 if (vgl->use_multitexture)
575 vgl->ActiveTextureARB(GL_TEXTURE0_ARB + 0);
577 for (subpicture_region_t *r = subpicture->p_region; r; r = r->p_next, i++) {
578 gl_region_t *glr = &vgl->region[i];
580 glr->format = GL_RGBA;
581 glr->type = GL_UNSIGNED_BYTE;
582 glr->width = r->fmt.i_visible_width;
583 glr->height = r->fmt.i_visible_height;
584 glr->alpha = (float)subpicture->i_alpha * r->i_alpha / 255 / 255;
585 glr->left = 2.0 * (r->i_x ) / subpicture->i_original_picture_width - 1.0;
586 glr->top = -2.0 * (r->i_y ) / subpicture->i_original_picture_height + 1.0;
587 glr->right = 2.0 * (r->i_x + r->fmt.i_visible_width ) / subpicture->i_original_picture_width - 1.0;
588 glr->bottom = -2.0 * (r->i_y + r->fmt.i_visible_height) / subpicture->i_original_picture_height + 1.0;
591 for (int j = 0; j < last_count; j++) {
592 if (last[i].texture &&
593 last[i].width == glr->width &&
594 last[i].height == glr->height &&
595 last[i].format == glr->format &&
596 last[i].type == glr->type) {
597 glr->texture = last[i].texture;
598 memset(&last[i], 0, sizeof(last[i]));
604 glBindTexture(GL_TEXTURE_2D, glr->texture);
605 /* TODO set GL_UNPACK_ALIGNMENT */
606 glPixelStorei(GL_UNPACK_ROW_LENGTH, r->p_picture->p->i_pitch / r->p_picture->p->i_pixel_pitch);
607 glTexSubImage2D(GL_TEXTURE_2D, 0,
608 0, 0, glr->width, glr->height,
609 glr->format, glr->type, r->p_picture->p->p_pixels);
611 glGenTextures(1, &glr->texture);
612 glBindTexture(GL_TEXTURE_2D, glr->texture);
613 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_PRIORITY, 1.0);
614 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
615 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
616 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
617 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
618 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
619 /* TODO set GL_UNPACK_ALIGNMENT */
620 glPixelStorei(GL_UNPACK_ROW_LENGTH, r->p_picture->p->i_pitch / r->p_picture->p->i_pixel_pitch);
621 glTexImage2D(GL_TEXTURE_2D, 0, glr->format,
622 glr->width, glr->height, 0, glr->format, glr->type,
623 r->p_picture->p->p_pixels);
627 for (int i = 0; i < last_count; i++) {
629 glDeleteTextures(1, &last[i].texture);
633 vlc_gl_Unlock(vgl->gl);
634 VLC_UNUSED(subpicture);
638 int vout_display_opengl_Display(vout_display_opengl_t *vgl,
639 const video_format_t *source)
641 if (vlc_gl_Lock(vgl->gl))
644 /* glTexCoord works differently with GL_TEXTURE_2D and
645 GL_TEXTURE_RECTANGLE_EXT */
646 float left[PICTURE_PLANE_MAX];
647 float top[PICTURE_PLANE_MAX];
648 float right[PICTURE_PLANE_MAX];
649 float bottom[PICTURE_PLANE_MAX];
650 for (unsigned j = 0; j < vgl->chroma->plane_count; j++) {
651 float scale_w, scale_h;
652 if (vgl->tex_target == GL_TEXTURE_2D) {
653 scale_w = (float)vgl->chroma->p[j].w.num / vgl->chroma->p[j].w.den / vgl->tex_width[j];
654 scale_h = (float)vgl->chroma->p[j].h.num / vgl->chroma->p[j].h.den / vgl->tex_height[j];
660 left[j] = (source->i_x_offset + 0 ) * scale_w;
661 top[j] = (source->i_y_offset + 0 ) * scale_h;
662 right[j] = (source->i_x_offset + source->i_visible_width ) * scale_w;
663 bottom[j] = (source->i_y_offset + source->i_visible_height) * scale_h;
667 /* Why drawing here and not in Render()? Because this way, the
668 OpenGL providers can call vout_display_opengl_Display to force redraw.i
669 Currently, the OS X provider uses it to get a smooth window resizing */
671 glClear(GL_COLOR_BUFFER_BIT);
674 glEnable(GL_FRAGMENT_PROGRAM_ARB);
675 for (int i = 0; i < vgl->local_count; i++)
676 vgl->ProgramLocalParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, i, vgl->local_value[i]);
678 glEnable(vgl->tex_target);
682 static const GLfloat vertexCoord[] = {
689 const GLfloat textureCoord[8] = {
696 glEnableClientState(GL_VERTEX_ARRAY);
697 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
698 glVertexPointer(2, GL_FLOAT, 0, vertexCoord);
699 glTexCoordPointer(2, GL_FLOAT, 0, textureCoord);
701 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
703 #if !defined(MACOS_OPENGL)
704 for (unsigned j = 0; j < vgl->chroma->plane_count; j++) {
705 if (vgl->use_multitexture)
706 vgl->ActiveTextureARB(GL_TEXTURE0_ARB + j);
707 glBindTexture(vgl->tex_target, vgl->texture[0][j]);
712 glTexCoord2f(left[0], top[0]);
713 for (unsigned j = 1; j < vgl->chroma->plane_count; j++)
714 vgl->MultiTexCoord2fARB(GL_TEXTURE0_ARB + j, left[j], top[j]);
715 glVertex2f(-1.0, 1.0);
717 glTexCoord2f(right[0], top[0]);
718 for (unsigned j = 1; j < vgl->chroma->plane_count; j++)
719 vgl->MultiTexCoord2fARB(GL_TEXTURE0_ARB + j, right[j], top[j]);
720 glVertex2f( 1.0, 1.0);
722 glTexCoord2f(right[0], bottom[0]);
723 for (unsigned j = 1; j < vgl->chroma->plane_count; j++)
724 vgl->MultiTexCoord2fARB(GL_TEXTURE0_ARB + j, right[j], bottom[j]);
725 glVertex2f( 1.0, -1.0);
727 glTexCoord2f(left[0], bottom[0]);
728 for (unsigned j = 1; j < vgl->chroma->plane_count; j++)
729 vgl->MultiTexCoord2fARB(GL_TEXTURE0_ARB + j, left[j], bottom[j]);
730 glVertex2f(-1.0, -1.0);
736 glDisable(GL_FRAGMENT_PROGRAM_ARB);
738 glDisable(vgl->tex_target);
741 if (vgl->use_multitexture)
742 vgl->ActiveTextureARB(GL_TEXTURE0_ARB + 0);
743 glEnable(GL_TEXTURE_2D);
745 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
746 for (int i = 0; i < vgl->region_count; i++) {
747 gl_region_t *glr = &vgl->region[i];
749 glBindTexture(GL_TEXTURE_2D, glr->texture);
753 glColor4f(1.0, 1.0, 1.0, glr->alpha);
755 glTexCoord2f(0.0, 0.0);
756 glVertex2f(glr->left, glr->top);
758 glTexCoord2f(1.0, 0.0);
759 glVertex2f(glr->right, glr->top);
761 glTexCoord2f(1.0, 1.0);
762 glVertex2f(glr->right, glr->bottom);
764 glTexCoord2f(0.0, 1.0);
765 glVertex2f(glr->left, glr->bottom);
770 glDisable(GL_TEXTURE_2D);
773 vlc_gl_Swap(vgl->gl);
775 vlc_gl_Unlock(vgl->gl);