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 void (*ActiveTextureARB)(GLenum);
131 void (*MultiTexCoord2fARB)(GLenum, GLfloat, GLfloat);
134 static inline int GetAlignedSize(unsigned size)
136 /* Return the smallest larger or equal power of 2 */
137 unsigned align = 1 << (8 * sizeof (unsigned) - clz(size));
138 return ((align >> 1) == size) ? size : align;
141 vout_display_opengl_t *vout_display_opengl_New(video_format_t *fmt,
142 const vlc_fourcc_t **subpicture_chromas,
145 vout_display_opengl_t *vgl = calloc(1, sizeof(*vgl));
150 if (vlc_gl_Lock(vgl->gl)) {
155 const char *extensions = (const char *)glGetString(GL_EXTENSIONS);
159 /* Load extensions */
160 bool supports_fp = false;
161 if (strstr(extensions, "GL_ARB_fragment_program")) {
162 vgl->GenProgramsARB = (void (*)(GLsizei, GLuint *))vlc_gl_GetProcAddress(vgl->gl, "glGenProgramsARB");
163 vgl->BindProgramARB = (void (*)(GLenum, GLuint))vlc_gl_GetProcAddress(vgl->gl, "glBindProgramARB");
164 vgl->ProgramStringARB = (void (*)(GLenum, GLenum, GLsizei, const GLvoid *))vlc_gl_GetProcAddress(vgl->gl, "glProgramStringARB");
165 vgl->DeleteProgramsARB = (void (*)(GLsizei, const GLuint *))vlc_gl_GetProcAddress(vgl->gl, "glDeleteProgramsARB");
166 vgl->ProgramLocalParameter4fvARB = (void (*)(GLenum, GLuint, const GLfloat *))vlc_gl_GetProcAddress(vgl->gl, "glProgramLocalParameter4fvARB");
168 supports_fp = vgl->GenProgramsARB &&
169 vgl->BindProgramARB &&
170 vgl->ProgramStringARB &&
171 vgl->DeleteProgramsARB &&
172 vgl->ProgramLocalParameter4fvARB;
174 bool supports_multitexture = false;
175 if (strstr(extensions, "GL_ARB_multitexture")) {
176 vgl->ActiveTextureARB = (void (*)(GLenum))vlc_gl_GetProcAddress(vgl->gl, "glActiveTextureARB");
177 vgl->MultiTexCoord2fARB = (void (*)(GLenum, GLfloat, GLfloat))vlc_gl_GetProcAddress(vgl->gl, "glMultiTexCoord2fARB");
179 supports_multitexture = vgl->ActiveTextureARB &&
180 vgl->MultiTexCoord2fARB;
183 /* Initialize with default chroma */
186 vgl->fmt.i_chroma = VLC_CODEC_RGB16;
187 # if defined(WORDS_BIGENDIAN)
188 vgl->fmt.i_rmask = 0x001f;
189 vgl->fmt.i_gmask = 0x07e0;
190 vgl->fmt.i_bmask = 0xf800;
192 vgl->fmt.i_rmask = 0xf800;
193 vgl->fmt.i_gmask = 0x07e0;
194 vgl->fmt.i_bmask = 0x001f;
196 vgl->tex_target = GL_TEXTURE_2D;
197 vgl->tex_format = GL_RGB;
198 vgl->tex_type = GL_UNSIGNED_SHORT_5_6_5;
199 #elif defined(MACOS_OPENGL)
200 # if defined(WORDS_BIGENDIAN)
201 vgl->fmt.i_chroma = VLC_CODEC_YUYV;
203 vgl->fmt.i_chroma = VLC_CODEC_UYVY;
205 vgl->tex_target = GL_TEXTURE_RECTANGLE_EXT;
206 vgl->tex_format = GL_YCBCR_422_APPLE;
207 vgl->tex_type = GL_UNSIGNED_SHORT_8_8_APPLE;
209 vgl->fmt.i_chroma = VLC_CODEC_RGB32;
210 # if defined(WORDS_BIGENDIAN)
211 vgl->fmt.i_rmask = 0xff000000;
212 vgl->fmt.i_gmask = 0x00ff0000;
213 vgl->fmt.i_bmask = 0x0000ff00;
215 vgl->fmt.i_rmask = 0x000000ff;
216 vgl->fmt.i_gmask = 0x0000ff00;
217 vgl->fmt.i_bmask = 0x00ff0000;
219 vgl->tex_target = GL_TEXTURE_2D;
220 vgl->tex_format = GL_RGBA;
221 vgl->tex_type = GL_UNSIGNED_BYTE;
223 /* Use YUV if possible and needed */
224 bool need_fs_yuv = false;
225 if (supports_fp && supports_multitexture &&
226 vlc_fourcc_IsYUV(fmt->i_chroma) && !vlc_fourcc_IsYUV(vgl->fmt.i_chroma)) {
227 const vlc_fourcc_t *list = vlc_fourcc_GetYUVFallback(fmt->i_chroma);
229 const vlc_chroma_description_t *dsc = vlc_fourcc_GetChromaDescription(*list);
230 if (dsc && dsc->plane_count == 3 && dsc->pixel_size == 1) {
233 vgl->fmt.i_chroma = *list;
234 vgl->tex_format = GL_LUMINANCE;
235 vgl->tex_type = GL_UNSIGNED_BYTE;
242 vgl->chroma = vlc_fourcc_GetChromaDescription(vgl->fmt.i_chroma);
244 bool supports_npot = false;
245 #if USE_OPENGL_ES == 2
246 supports_npot = true;
247 #elif defined(MACOS_OPENGL)
248 supports_npot = true;
250 supports_npot |= strstr(extensions, "GL_APPLE_texture_2D_limited_npot") != NULL ||
251 strstr(extensions, "GL_ARB_texture_non_power_of_two");
255 for (unsigned j = 0; j < vgl->chroma->plane_count; j++) {
256 int w = vgl->fmt.i_width * vgl->chroma->p[j].w.num / vgl->chroma->p[j].w.den;
257 int h = vgl->fmt.i_height * vgl->chroma->p[j].h.num / vgl->chroma->p[j].h.den;
259 vgl->tex_width[j] = w;
260 vgl->tex_height[j] = h;
263 /* A texture must have a size aligned on a power of 2 */
264 vgl->tex_width[j] = GetAlignedSize(w);
265 vgl->tex_height[j] = GetAlignedSize(h);
269 /* Build fragment program if needed */
271 vgl->local_count = 0;
276 /* [R/G/B][Y U V O] from TV range to full range
277 * XXX we could also do hue/brightness/constrast/gamma
278 * by simply changing the coefficients
280 const float matrix_bt601_tv2full[3][4] = {
281 { 1.1640, 0.0000, 1.4030, -0.7773 },
282 { 1.1640, -0.3440, -0.7140, 0.4580 },
283 { 1.1640, 1.7730, 0.0000, -0.9630 },
285 const float matrix_bt709_tv2full[3][4] = {
286 { 1.1640, 0.0000, 1.5701, -0.8612 },
287 { 1.1640, -0.1870, -0.4664, 0.2549 },
288 { 1.1640, 1.8556, 0.0000, -1.0045 },
290 const float (*matrix)[4] = fmt->i_height > 576 ? matrix_bt709_tv2full
291 : matrix_bt601_tv2full;
293 /* Basic linear YUV -> RGB conversion using bilinear interpolation */
294 const char *template_yuv =
296 "OPTION ARB_precision_hint_fastest;"
299 "TEX src.x, fragment.texcoord[0], texture[0], 2D;"
300 "TEX src.%c, fragment.texcoord[1], texture[1], 2D;"
301 "TEX src.%c, fragment.texcoord[2], texture[2], 2D;"
303 "PARAM coefficient[4] = { program.local[0..3] };"
306 "MAD tmp.rgb, src.xxxx, coefficient[0], coefficient[3];"
307 "MAD tmp.rgb, src.yyyy, coefficient[1], tmp;"
308 "MAD result.color.rgb, src.zzzz, coefficient[2], tmp;"
310 bool swap_uv = vgl->fmt.i_chroma == VLC_CODEC_YV12 ||
311 vgl->fmt.i_chroma == VLC_CODEC_YV9;
312 if (asprintf(&code, template_yuv,
314 swap_uv ? 'y' : 'z') < 0)
317 for (int i = 0; i < 4; i++)
318 for (int j = 0; j < 4; j++)
319 vgl->local_value[vgl->local_count + i][j] = j < 3 ? matrix[j][i] : 0.0;
320 vgl->local_count += 4;
323 vgl->GenProgramsARB(1, &vgl->program);
324 vgl->BindProgramARB(GL_FRAGMENT_PROGRAM_ARB, vgl->program);
325 vgl->ProgramStringARB(GL_FRAGMENT_PROGRAM_ARB,
326 GL_PROGRAM_FORMAT_ASCII_ARB,
327 strlen(code), (const GLbyte*)code);
328 if (glGetError() == GL_INVALID_OPERATION) {
329 /* FIXME if the program was needed for YUV, the video will be broken */
332 glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &position);
334 const char *msg = (const char *)glGetString(GL_PROGRAM_ERROR_STRING_ARB);
335 fprintf(stderr, "GL_INVALID_OPERATION: error at %d: %s\n", position, msg);
337 vgl->DeleteProgramsARB(1, &vgl->program);
346 glDisable(GL_DEPTH_TEST);
347 glDepthMask(GL_FALSE);
348 glDisable(GL_CULL_FACE);
349 glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
350 glClear(GL_COLOR_BUFFER_BIT);
352 vlc_gl_Unlock(vgl->gl);
355 for (int i = 0; i < VLCGL_TEXTURE_COUNT; i++) {
356 for (int j = 0; j < PICTURE_PLANE_MAX; j++)
357 vgl->texture[i][j] = 0;
359 vgl->region_count = 0;
364 if (subpicture_chromas) {
365 *subpicture_chromas = NULL;
366 #if !defined(MACOS_OPENGL) && !USE_OPENGL_ES
368 *subpicture_chromas = gl_subpicture_chromas;
374 void vout_display_opengl_Delete(vout_display_opengl_t *vgl)
377 if (!vlc_gl_Lock(vgl->gl)) {
381 for (int i = 0; i < VLCGL_TEXTURE_COUNT; i++)
382 glDeleteTextures(vgl->chroma->plane_count, vgl->texture[i]);
385 vgl->DeleteProgramsARB(1, &vgl->program);
387 vlc_gl_Unlock(vgl->gl);
390 picture_pool_Delete(vgl->pool);
395 struct picture_sys_t {
396 vout_display_opengl_t *vgl;
401 static inline GLuint PictureGetTexture(picture_t *picture)
403 return *picture->p_sys->texture;
406 static int PictureLock(picture_t *picture)
411 vout_display_opengl_t *vgl = picture->p_sys->vgl;
412 if (!vlc_gl_Lock(vgl->gl)) {
413 glBindTexture(vgl->tex_target, PictureGetTexture(picture));
414 glTexSubImage2D(vgl->tex_target, 0,
415 0, 0, vgl->fmt.i_width, vgl->fmt.i_height,
416 vgl->tex_format, vgl->tex_type, picture->p[0].p_pixels);
418 vlc_gl_Unlock(vgl->gl);
423 static void PictureUnlock(picture_t *picture)
429 picture_pool_t *vout_display_opengl_GetPool(vout_display_opengl_t *vgl, unsigned requested_count)
434 /* Allocate our pictures */
435 picture_t *picture[VLCGL_PICTURE_MAX] = {NULL, };
438 for (count = 0; count < __MIN(VLCGL_PICTURE_MAX, requested_count); count++) {
439 picture[count] = picture_NewFromFormat(&vgl->fmt);
444 picture_sys_t *sys = picture[count]->p_sys = malloc(sizeof(*sys));
447 sys->texture = vgl->texture[count];
454 /* Wrap the pictures into a pool */
455 picture_pool_configuration_t cfg;
456 memset(&cfg, 0, sizeof(cfg));
457 cfg.picture_count = count;
458 cfg.picture = picture;
460 cfg.lock = PictureLock;
461 cfg.unlock = PictureUnlock;
463 vgl->pool = picture_pool_NewExtended(&cfg);
467 /* Allocates our textures */
468 if (vlc_gl_Lock(vgl->gl))
471 for (int i = 0; i < VLCGL_TEXTURE_COUNT; i++) {
472 glGenTextures(vgl->chroma->plane_count, vgl->texture[i]);
473 for (unsigned j = 0; j < vgl->chroma->plane_count; j++) {
474 if (vgl->chroma->plane_count > 1)
475 vgl->ActiveTextureARB(GL_TEXTURE0_ARB + j);
476 glBindTexture(vgl->tex_target, vgl->texture[i][j]);
479 /* Set the texture parameters */
480 glTexParameterf(vgl->tex_target, GL_TEXTURE_PRIORITY, 1.0);
481 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
484 glTexParameteri(vgl->tex_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
485 glTexParameteri(vgl->tex_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
486 glTexParameteri(vgl->tex_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
487 glTexParameteri(vgl->tex_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
490 /* Tell the driver not to make a copy of the texture but to use
492 glEnable(GL_UNPACK_CLIENT_STORAGE_APPLE);
493 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
495 /* Use AGP texturing */
496 glTexParameteri(vgl->tex_target, GL_TEXTURE_STORAGE_HINT_APPLE,
497 GL_STORAGE_SHARED_APPLE);
500 /* Call glTexImage2D only once, and use glTexSubImage2D later */
501 glTexImage2D(vgl->tex_target, 0,
502 vgl->tex_format, vgl->tex_width[j], vgl->tex_height[j],
503 0, vgl->tex_format, vgl->tex_type, NULL);
507 vlc_gl_Unlock(vgl->gl);
512 for (unsigned i = 0; i < count; i++)
513 picture_Delete(picture[i]);
517 int vout_display_opengl_Prepare(vout_display_opengl_t *vgl,
518 picture_t *picture, subpicture_t *subpicture)
520 /* On Win32/GLX, we do this the usual way:
521 + Fill the buffer with new content,
522 + Reload the texture,
525 On OS X with VRAM or AGP texturing, the order has to be:
526 + Reload the texture,
527 + Fill the buffer with new content,
530 (Thanks to gcc from the Arstechnica forums for the tip)
532 Therefore on OSX, we have to use two buffers and textures and use a
533 lock(/unlock) managed picture pool.
536 if (vlc_gl_Lock(vgl->gl))
540 /* Bind to the texture for drawing */
541 glBindTexture(vgl->tex_target, PictureGetTexture(picture));
543 /* Update the texture */
544 for (unsigned j = 0; j < vgl->chroma->plane_count; j++) {
545 if (vgl->chroma->plane_count > 1)
546 vgl->ActiveTextureARB(GL_TEXTURE0_ARB + j);
547 glBindTexture(vgl->tex_target, vgl->texture[0][j]);
548 glPixelStorei(GL_UNPACK_ROW_LENGTH, picture->p[j].i_pitch / picture->p[j].i_pixel_pitch);
549 glTexSubImage2D(vgl->tex_target, 0,
551 vgl->fmt.i_width * vgl->chroma->p[j].w.num / vgl->chroma->p[j].w.den,
552 vgl->fmt.i_height * vgl->chroma->p[j].h.num / vgl->chroma->p[j].h.den,
553 vgl->tex_format, vgl->tex_type, picture->p[j].p_pixels);
557 int last_count = vgl->region_count;
558 gl_region_t *last = vgl->region;
560 vgl->region_count = 0;
566 for (subpicture_region_t *r = subpicture->p_region; r; r = r->p_next)
569 vgl->region_count = count;
570 vgl->region = calloc(count, sizeof(*vgl->region));
572 if (vgl->chroma->plane_count > 1)
573 vgl->ActiveTextureARB(GL_TEXTURE0_ARB + 0);
575 for (subpicture_region_t *r = subpicture->p_region; r; r = r->p_next, i++) {
576 gl_region_t *glr = &vgl->region[i];
578 glr->format = GL_RGBA;
579 glr->type = GL_UNSIGNED_BYTE;
580 glr->width = r->fmt.i_visible_width;
581 glr->height = r->fmt.i_visible_height;
582 glr->alpha = (float)subpicture->i_alpha * r->i_alpha / 255 / 255;
583 glr->left = 2.0 * (r->i_x ) / subpicture->i_original_picture_width - 1.0;
584 glr->top = -2.0 * (r->i_y ) / subpicture->i_original_picture_height + 1.0;
585 glr->right = 2.0 * (r->i_x + r->fmt.i_visible_width ) / subpicture->i_original_picture_width - 1.0;
586 glr->bottom = -2.0 * (r->i_y + r->fmt.i_visible_height) / subpicture->i_original_picture_height + 1.0;
589 for (int j = 0; j < last_count; j++) {
590 if (last[i].texture &&
591 last[i].width == glr->width &&
592 last[i].height == glr->height &&
593 last[i].format == glr->format &&
594 last[i].type == glr->type) {
595 glr->texture = last[i].texture;
596 memset(&last[i], 0, sizeof(last[i]));
602 glBindTexture(GL_TEXTURE_2D, glr->texture);
603 /* TODO set GL_UNPACK_ALIGNMENT */
604 glPixelStorei(GL_UNPACK_ROW_LENGTH, r->p_picture->p->i_pitch / r->p_picture->p->i_pixel_pitch);
605 glTexSubImage2D(GL_TEXTURE_2D, 0,
606 0, 0, glr->width, glr->height,
607 glr->format, glr->type, r->p_picture->p->p_pixels);
609 glGenTextures(1, &glr->texture);
610 glBindTexture(GL_TEXTURE_2D, glr->texture);
611 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_PRIORITY, 1.0);
612 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
613 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
614 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
615 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
616 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
617 /* TODO set GL_UNPACK_ALIGNMENT */
618 glPixelStorei(GL_UNPACK_ROW_LENGTH, r->p_picture->p->i_pitch / r->p_picture->p->i_pixel_pitch);
619 glTexImage2D(GL_TEXTURE_2D, 0, glr->format,
620 glr->width, glr->height, 0, glr->format, glr->type,
621 r->p_picture->p->p_pixels);
625 for (int i = 0; i < last_count; i++) {
627 glDeleteTextures(1, &last[i].texture);
631 vlc_gl_Unlock(vgl->gl);
632 VLC_UNUSED(subpicture);
636 int vout_display_opengl_Display(vout_display_opengl_t *vgl,
637 const video_format_t *source)
639 if (vlc_gl_Lock(vgl->gl))
642 /* glTexCoord works differently with GL_TEXTURE_2D and
643 GL_TEXTURE_RECTANGLE_EXT */
644 float left[PICTURE_PLANE_MAX];
645 float top[PICTURE_PLANE_MAX];
646 float right[PICTURE_PLANE_MAX];
647 float bottom[PICTURE_PLANE_MAX];
648 for (unsigned j = 0; j < vgl->chroma->plane_count; j++) {
649 float scale_w, scale_h;
650 if (vgl->tex_target == GL_TEXTURE_2D) {
651 scale_w = (float)vgl->chroma->p[j].w.num / vgl->chroma->p[j].w.den / vgl->tex_width[j];
652 scale_h = (float)vgl->chroma->p[j].h.num / vgl->chroma->p[j].h.den / vgl->tex_height[j];
658 left[j] = (source->i_x_offset + 0 ) * scale_w;
659 top[j] = (source->i_y_offset + 0 ) * scale_h;
660 right[j] = (source->i_x_offset + source->i_visible_width ) * scale_w;
661 bottom[j] = (source->i_y_offset + source->i_visible_height) * scale_h;
665 /* Why drawing here and not in Render()? Because this way, the
666 OpenGL providers can call vout_display_opengl_Display to force redraw.i
667 Currently, the OS X provider uses it to get a smooth window resizing */
669 glClear(GL_COLOR_BUFFER_BIT);
672 glEnable(GL_FRAGMENT_PROGRAM_ARB);
673 for (int i = 0; i < vgl->local_count; i++)
674 vgl->ProgramLocalParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, i, vgl->local_value[i]);
676 glEnable(vgl->tex_target);
680 static const GLfloat vertexCoord[] = {
687 const GLfloat textureCoord[8] = {
694 glEnableClientState(GL_VERTEX_ARRAY);
695 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
696 glVertexPointer(2, GL_FLOAT, 0, vertexCoord);
697 glTexCoordPointer(2, GL_FLOAT, 0, textureCoord);
699 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
701 #if !defined(MACOS_OPENGL)
702 for (unsigned j = 0; j < vgl->chroma->plane_count; j++) {
703 if (vgl->chroma->plane_count > 1)
704 vgl->ActiveTextureARB(GL_TEXTURE0_ARB + j);
705 glBindTexture(vgl->tex_target, vgl->texture[0][j]);
710 glTexCoord2f(left[0], top[0]);
711 for (unsigned j = 1; j < vgl->chroma->plane_count; j++)
712 vgl->MultiTexCoord2fARB(GL_TEXTURE0_ARB + j, left[j], top[j]);
713 glVertex2f(-1.0, 1.0);
715 glTexCoord2f(right[0], top[0]);
716 for (unsigned j = 1; j < vgl->chroma->plane_count; j++)
717 vgl->MultiTexCoord2fARB(GL_TEXTURE0_ARB + j, right[j], top[j]);
718 glVertex2f( 1.0, 1.0);
720 glTexCoord2f(right[0], bottom[0]);
721 for (unsigned j = 1; j < vgl->chroma->plane_count; j++)
722 vgl->MultiTexCoord2fARB(GL_TEXTURE0_ARB + j, right[j], bottom[j]);
723 glVertex2f( 1.0, -1.0);
725 glTexCoord2f(left[0], bottom[0]);
726 for (unsigned j = 1; j < vgl->chroma->plane_count; j++)
727 vgl->MultiTexCoord2fARB(GL_TEXTURE0_ARB + j, left[j], bottom[j]);
728 glVertex2f(-1.0, -1.0);
734 glDisable(GL_FRAGMENT_PROGRAM_ARB);
736 glDisable(vgl->tex_target);
739 if (vgl->chroma->plane_count > 1)
740 vgl->ActiveTextureARB(GL_TEXTURE0_ARB + 0);
741 glEnable(GL_TEXTURE_2D);
743 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
744 for (int i = 0; i < vgl->region_count; i++) {
745 gl_region_t *glr = &vgl->region[i];
747 glBindTexture(GL_TEXTURE_2D, glr->texture);
751 glColor4f(1.0, 1.0, 1.0, glr->alpha);
753 glTexCoord2f(0.0, 0.0);
754 glVertex2f(glr->left, glr->top);
756 glTexCoord2f(1.0, 0.0);
757 glVertex2f(glr->right, glr->top);
759 glTexCoord2f(1.0, 1.0);
760 glVertex2f(glr->right, glr->bottom);
762 glTexCoord2f(0.0, 1.0);
763 glVertex2f(glr->left, glr->bottom);
768 glDisable(GL_TEXTURE_2D);
771 vlc_gl_Swap(vgl->gl);
773 vlc_gl_Unlock(vgl->gl);