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>
56 # define PFNGLGENPROGRAMSARBPROC typeof(glGenProgramsARB)*
57 # define PFNGLBINDPROGRAMARBPROC typeof(glBindProgramARB)*
58 # define PFNGLPROGRAMSTRINGARBPROC typeof(glProgramStringARB)*
59 # define PFNGLDELETEPROGRAMSARBPROC typeof(glDeleteProgramsARB)*
60 # define PFNGLPROGRAMLOCALPARAMETER4FVARBPROC typeof(glProgramLocalParameter4fvARB)*
61 # define PFNGLACTIVETEXTUREARBPROC typeof(glActiveTextureARB)*
62 # define PFNGLMULTITEXCOORD2FARBPROC typeof(glMultiTexCoord2fARB)*
66 #ifndef GL_UNSIGNED_SHORT_5_6_5
67 # define GL_UNSIGNED_SHORT_5_6_5 0x8363
69 #ifndef GL_CLAMP_TO_EDGE
70 # define GL_CLAMP_TO_EDGE 0x812F
74 # define VLCGL_TEXTURE_COUNT 1
75 # define VLCGL_PICTURE_MAX 1
76 #elif defined(MACOS_OPENGL)
77 # define VLCGL_TEXTURE_COUNT 2
78 # define VLCGL_PICTURE_MAX 2
80 # define VLCGL_TEXTURE_COUNT 1
81 # define VLCGL_PICTURE_MAX 128
84 static const vlc_fourcc_t gl_subpicture_chromas[] = {
104 struct vout_display_opengl_t {
108 const vlc_chroma_description_t *chroma;
115 int tex_width[PICTURE_PLANE_MAX];
116 int tex_height[PICTURE_PLANE_MAX];
118 GLuint texture[VLCGL_TEXTURE_COUNT][PICTURE_PLANE_MAX];
124 picture_pool_t *pool;
128 GLfloat local_value[16][4];
130 /* fragment_program */
131 PFNGLGENPROGRAMSARBPROC GenProgramsARB;
132 PFNGLBINDPROGRAMARBPROC BindProgramARB;
133 PFNGLPROGRAMSTRINGARBPROC ProgramStringARB;
134 PFNGLDELETEPROGRAMSARBPROC DeleteProgramsARB;
135 PFNGLPROGRAMLOCALPARAMETER4FVARBPROC ProgramLocalParameter4fvARB;
138 bool use_multitexture;
139 PFNGLACTIVETEXTUREARBPROC ActiveTextureARB;
140 PFNGLMULTITEXCOORD2FARBPROC MultiTexCoord2fARB;
143 static inline int GetAlignedSize(unsigned size)
145 /* Return the smallest larger or equal power of 2 */
146 unsigned align = 1 << (8 * sizeof (unsigned) - clz(size));
147 return ((align >> 1) == size) ? size : align;
150 static bool IsLuminance16Supported(int target)
154 glGenTextures(1, &texture);
155 glBindTexture(target, texture);
156 glTexImage2D(target, 0, GL_LUMINANCE16,
157 64, 64, 0, GL_LUMINANCE, GL_UNSIGNED_SHORT, NULL);
159 glGetTexLevelParameteriv(target, 0, GL_TEXTURE_LUMINANCE_SIZE, &size);
161 glDeleteTextures(1, &texture);
166 vout_display_opengl_t *vout_display_opengl_New(video_format_t *fmt,
167 const vlc_fourcc_t **subpicture_chromas,
170 vout_display_opengl_t *vgl = calloc(1, sizeof(*vgl));
175 if (vlc_gl_Lock(vgl->gl)) {
180 const char *extensions = (const char *)glGetString(GL_EXTENSIONS);
182 /* Load extensions */
183 bool supports_fp = false;
184 if (HasExtension(extensions, "GL_ARB_fragment_program")) {
185 vgl->GenProgramsARB = (PFNGLGENPROGRAMSARBPROC)vlc_gl_GetProcAddress(vgl->gl, "glGenProgramsARB");
186 vgl->BindProgramARB = (PFNGLBINDPROGRAMARBPROC)vlc_gl_GetProcAddress(vgl->gl, "glBindProgramARB");
187 vgl->ProgramStringARB = (PFNGLPROGRAMSTRINGARBPROC)vlc_gl_GetProcAddress(vgl->gl, "glProgramStringARB");
188 vgl->DeleteProgramsARB = (PFNGLDELETEPROGRAMSARBPROC)vlc_gl_GetProcAddress(vgl->gl, "glDeleteProgramsARB");
189 vgl->ProgramLocalParameter4fvARB = (PFNGLPROGRAMLOCALPARAMETER4FVARBPROC)vlc_gl_GetProcAddress(vgl->gl, "glProgramLocalParameter4fvARB");
191 supports_fp = vgl->GenProgramsARB &&
192 vgl->BindProgramARB &&
193 vgl->ProgramStringARB &&
194 vgl->DeleteProgramsARB &&
195 vgl->ProgramLocalParameter4fvARB;
198 bool supports_multitexture = false;
199 GLint max_texture_units = 0;
200 if (HasExtension(extensions, "GL_ARB_multitexture")) {
201 vgl->ActiveTextureARB = (PFNGLACTIVETEXTUREARBPROC)vlc_gl_GetProcAddress(vgl->gl, "glActiveTextureARB");
202 vgl->MultiTexCoord2fARB = (PFNGLMULTITEXCOORD2FARBPROC)vlc_gl_GetProcAddress(vgl->gl, "glMultiTexCoord2fARB");
204 supports_multitexture = vgl->ActiveTextureARB &&
205 vgl->MultiTexCoord2fARB;
206 if (supports_multitexture)
207 glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &max_texture_units);
210 /* Initialize with default chroma */
213 vgl->fmt.i_chroma = VLC_CODEC_RGB16;
214 # if defined(WORDS_BIGENDIAN)
215 vgl->fmt.i_rmask = 0x001f;
216 vgl->fmt.i_gmask = 0x07e0;
217 vgl->fmt.i_bmask = 0xf800;
219 vgl->fmt.i_rmask = 0xf800;
220 vgl->fmt.i_gmask = 0x07e0;
221 vgl->fmt.i_bmask = 0x001f;
223 vgl->tex_target = GL_TEXTURE_2D;
224 vgl->tex_format = GL_RGB;
225 vgl->tex_internal = GL_RGB;
226 vgl->tex_type = GL_UNSIGNED_SHORT_5_6_5;
227 #elif defined(MACOS_OPENGL)
228 # if defined(WORDS_BIGENDIAN)
229 vgl->fmt.i_chroma = VLC_CODEC_YUYV;
231 vgl->fmt.i_chroma = VLC_CODEC_UYVY;
233 vgl->tex_target = GL_TEXTURE_RECTANGLE_EXT;
234 vgl->tex_format = GL_YCBCR_422_APPLE;
235 vgl->tex_internal = GL_YCBCR_422_APPLE;
236 vgl->tex_type = GL_UNSIGNED_SHORT_8_8_APPLE;
238 vgl->fmt.i_chroma = VLC_CODEC_RGB32;
239 # if defined(WORDS_BIGENDIAN)
240 vgl->fmt.i_rmask = 0xff000000;
241 vgl->fmt.i_gmask = 0x00ff0000;
242 vgl->fmt.i_bmask = 0x0000ff00;
244 vgl->fmt.i_rmask = 0x000000ff;
245 vgl->fmt.i_gmask = 0x0000ff00;
246 vgl->fmt.i_bmask = 0x00ff0000;
248 vgl->tex_target = GL_TEXTURE_2D;
249 vgl->tex_format = GL_RGBA;
250 vgl->tex_internal = GL_RGBA;
251 vgl->tex_type = GL_UNSIGNED_BYTE;
253 /* Use YUV if possible and needed */
254 bool need_fs_yuv = false;
255 float yuv_range_correction = 1.0;
256 if (supports_fp && supports_multitexture && max_texture_units >= 3 &&
257 vlc_fourcc_IsYUV(fmt->i_chroma) && !vlc_fourcc_IsYUV(vgl->fmt.i_chroma)) {
258 const vlc_fourcc_t *list = vlc_fourcc_GetYUVFallback(fmt->i_chroma);
260 const vlc_chroma_description_t *dsc = vlc_fourcc_GetChromaDescription(*list);
261 if (dsc && dsc->plane_count == 3 && dsc->pixel_size == 1) {
264 vgl->fmt.i_chroma = *list;
265 vgl->tex_format = GL_LUMINANCE;
266 vgl->tex_internal = GL_LUMINANCE;
267 vgl->tex_type = GL_UNSIGNED_BYTE;
268 yuv_range_correction = 1.0;
270 } else if (dsc && dsc->plane_count == 3 && dsc->pixel_size == 2 &&
271 IsLuminance16Supported(vgl->tex_target)) {
274 vgl->fmt.i_chroma = *list;
275 vgl->tex_format = GL_LUMINANCE;
276 vgl->tex_internal = GL_LUMINANCE16;
277 vgl->tex_type = GL_UNSIGNED_SHORT;
278 yuv_range_correction = (float)((1 << 16) - 1) / ((1 << dsc->pixel_bits) - 1);
285 vgl->chroma = vlc_fourcc_GetChromaDescription(vgl->fmt.i_chroma);
286 vgl->use_multitexture = vgl->chroma->plane_count > 1;
288 bool supports_npot = false;
289 #if USE_OPENGL_ES == 2
290 supports_npot = true;
291 #elif defined(MACOS_OPENGL)
292 supports_npot = true;
294 supports_npot |= HasExtension(extensions, "GL_APPLE_texture_2D_limited_npot") ||
295 HasExtension(extensions, "GL_ARB_texture_non_power_of_two");
299 for (unsigned j = 0; j < vgl->chroma->plane_count; j++) {
300 int w = vgl->fmt.i_width * vgl->chroma->p[j].w.num / vgl->chroma->p[j].w.den;
301 int h = vgl->fmt.i_height * vgl->chroma->p[j].h.num / vgl->chroma->p[j].h.den;
303 vgl->tex_width[j] = w;
304 vgl->tex_height[j] = h;
307 /* A texture must have a size aligned on a power of 2 */
308 vgl->tex_width[j] = GetAlignedSize(w);
309 vgl->tex_height[j] = GetAlignedSize(h);
313 /* Build fragment program if needed */
315 vgl->local_count = 0;
320 /* [R/G/B][Y U V O] from TV range to full range
321 * XXX we could also do hue/brightness/constrast/gamma
322 * by simply changing the coefficients
324 const float matrix_bt601_tv2full[3][4] = {
325 { 1.1640, 0.0000, 1.4030, -0.7773 },
326 { 1.1640, -0.3440, -0.7140, 0.4580 },
327 { 1.1640, 1.7730, 0.0000, -0.9630 },
329 const float matrix_bt709_tv2full[3][4] = {
330 { 1.1640, 0.0000, 1.5701, -0.8612 },
331 { 1.1640, -0.1870, -0.4664, 0.2549 },
332 { 1.1640, 1.8556, 0.0000, -1.0045 },
334 const float (*matrix)[4] = fmt->i_height > 576 ? matrix_bt709_tv2full
335 : matrix_bt601_tv2full;
337 /* Basic linear YUV -> RGB conversion using bilinear interpolation */
338 const char *template_yuv =
340 "OPTION ARB_precision_hint_fastest;"
343 "TEX src.x, fragment.texcoord[0], texture[0], 2D;"
344 "TEX src.%c, fragment.texcoord[1], texture[1], 2D;"
345 "TEX src.%c, fragment.texcoord[2], texture[2], 2D;"
347 "PARAM coefficient[4] = { program.local[0..3] };"
350 "MAD tmp.rgb, src.xxxx, coefficient[0], coefficient[3];"
351 "MAD tmp.rgb, src.yyyy, coefficient[1], tmp;"
352 "MAD result.color.rgb, src.zzzz, coefficient[2], tmp;"
354 bool swap_uv = vgl->fmt.i_chroma == VLC_CODEC_YV12 ||
355 vgl->fmt.i_chroma == VLC_CODEC_YV9;
356 if (asprintf(&code, template_yuv,
358 swap_uv ? 'y' : 'z') < 0)
361 for (int i = 0; i < 4; i++) {
362 float correction = i < 3 ? yuv_range_correction : 1.0;
363 for (int j = 0; j < 4; j++) {
364 vgl->local_value[vgl->local_count + i][j] = j < 3 ? correction * matrix[j][i] : 0.0;
367 vgl->local_count += 4;
370 vgl->GenProgramsARB(1, &vgl->program);
371 vgl->BindProgramARB(GL_FRAGMENT_PROGRAM_ARB, vgl->program);
372 vgl->ProgramStringARB(GL_FRAGMENT_PROGRAM_ARB,
373 GL_PROGRAM_FORMAT_ASCII_ARB,
374 strlen(code), (const GLbyte*)code);
375 if (glGetError() == GL_INVALID_OPERATION) {
376 /* FIXME if the program was needed for YUV, the video will be broken */
379 glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &position);
381 const char *msg = (const char *)glGetString(GL_PROGRAM_ERROR_STRING_ARB);
382 fprintf(stderr, "GL_INVALID_OPERATION: error at %d: %s\n", position, msg);
384 vgl->DeleteProgramsARB(1, &vgl->program);
393 glDisable(GL_DEPTH_TEST);
394 glDepthMask(GL_FALSE);
395 glDisable(GL_CULL_FACE);
396 glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
397 glClear(GL_COLOR_BUFFER_BIT);
399 vlc_gl_Unlock(vgl->gl);
402 for (int i = 0; i < VLCGL_TEXTURE_COUNT; i++) {
403 for (int j = 0; j < PICTURE_PLANE_MAX; j++)
404 vgl->texture[i][j] = 0;
406 vgl->region_count = 0;
411 if (subpicture_chromas) {
412 *subpicture_chromas = NULL;
413 #if !defined(MACOS_OPENGL) && !USE_OPENGL_ES
415 *subpicture_chromas = gl_subpicture_chromas;
421 void vout_display_opengl_Delete(vout_display_opengl_t *vgl)
424 if (!vlc_gl_Lock(vgl->gl)) {
428 for (int i = 0; i < VLCGL_TEXTURE_COUNT; i++)
429 glDeleteTextures(vgl->chroma->plane_count, vgl->texture[i]);
430 for (int i = 0; i < vgl->region_count; i++) {
431 if (vgl->region[i].texture)
432 glDeleteTextures(1, &vgl->region[i].texture);
437 vgl->DeleteProgramsARB(1, &vgl->program);
439 vlc_gl_Unlock(vgl->gl);
442 picture_pool_Delete(vgl->pool);
447 struct picture_sys_t {
448 vout_display_opengl_t *vgl;
453 static inline GLuint PictureGetTexture(picture_t *picture)
455 return *picture->p_sys->texture;
458 static int PictureLock(picture_t *picture)
463 vout_display_opengl_t *vgl = picture->p_sys->vgl;
464 if (!vlc_gl_Lock(vgl->gl)) {
465 glBindTexture(vgl->tex_target, PictureGetTexture(picture));
466 glTexSubImage2D(vgl->tex_target, 0,
467 0, 0, vgl->fmt.i_width, vgl->fmt.i_height,
468 vgl->tex_format, vgl->tex_type, picture->p[0].p_pixels);
470 vlc_gl_Unlock(vgl->gl);
475 static void PictureUnlock(picture_t *picture)
481 picture_pool_t *vout_display_opengl_GetPool(vout_display_opengl_t *vgl, unsigned requested_count)
486 /* Allocate our pictures */
487 picture_t *picture[VLCGL_PICTURE_MAX] = {NULL, };
490 for (count = 0; count < __MIN(VLCGL_PICTURE_MAX, requested_count); count++) {
491 picture[count] = picture_NewFromFormat(&vgl->fmt);
496 picture_sys_t *sys = picture[count]->p_sys = malloc(sizeof(*sys));
499 sys->texture = vgl->texture[count];
506 /* Wrap the pictures into a pool */
507 picture_pool_configuration_t cfg;
508 memset(&cfg, 0, sizeof(cfg));
509 cfg.picture_count = count;
510 cfg.picture = picture;
512 cfg.lock = PictureLock;
513 cfg.unlock = PictureUnlock;
515 vgl->pool = picture_pool_NewExtended(&cfg);
519 /* Allocates our textures */
520 if (vlc_gl_Lock(vgl->gl))
523 for (int i = 0; i < VLCGL_TEXTURE_COUNT; i++) {
524 glGenTextures(vgl->chroma->plane_count, vgl->texture[i]);
525 for (unsigned j = 0; j < vgl->chroma->plane_count; j++) {
526 if (vgl->use_multitexture)
527 vgl->ActiveTextureARB(GL_TEXTURE0_ARB + j);
528 glBindTexture(vgl->tex_target, vgl->texture[i][j]);
531 /* Set the texture parameters */
532 glTexParameterf(vgl->tex_target, GL_TEXTURE_PRIORITY, 1.0);
533 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
536 glTexParameteri(vgl->tex_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
537 glTexParameteri(vgl->tex_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
538 glTexParameteri(vgl->tex_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
539 glTexParameteri(vgl->tex_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
542 /* Tell the driver not to make a copy of the texture but to use
544 glEnable(GL_UNPACK_CLIENT_STORAGE_APPLE);
545 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
547 /* Use AGP texturing */
548 glTexParameteri(vgl->tex_target, GL_TEXTURE_STORAGE_HINT_APPLE,
549 GL_STORAGE_SHARED_APPLE);
552 /* Call glTexImage2D only once, and use glTexSubImage2D later */
553 glTexImage2D(vgl->tex_target, 0,
554 vgl->tex_internal, vgl->tex_width[j], vgl->tex_height[j],
555 0, vgl->tex_format, vgl->tex_type, NULL);
559 vlc_gl_Unlock(vgl->gl);
564 for (unsigned i = 0; i < count; i++)
565 picture_Delete(picture[i]);
569 int vout_display_opengl_Prepare(vout_display_opengl_t *vgl,
570 picture_t *picture, subpicture_t *subpicture)
572 /* On Win32/GLX, we do this the usual way:
573 + Fill the buffer with new content,
574 + Reload the texture,
577 On OS X with VRAM or AGP texturing, the order has to be:
578 + Reload the texture,
579 + Fill the buffer with new content,
582 (Thanks to gcc from the Arstechnica forums for the tip)
584 Therefore on OSX, we have to use two buffers and textures and use a
585 lock(/unlock) managed picture pool.
588 if (vlc_gl_Lock(vgl->gl))
592 /* Bind to the texture for drawing */
593 glBindTexture(vgl->tex_target, PictureGetTexture(picture));
595 /* Update the texture */
596 for (unsigned j = 0; j < vgl->chroma->plane_count; j++) {
597 if (vgl->use_multitexture)
598 vgl->ActiveTextureARB(GL_TEXTURE0_ARB + j);
599 glBindTexture(vgl->tex_target, vgl->texture[0][j]);
600 glPixelStorei(GL_UNPACK_ROW_LENGTH, picture->p[j].i_pitch / picture->p[j].i_pixel_pitch);
601 glTexSubImage2D(vgl->tex_target, 0,
603 vgl->fmt.i_width * vgl->chroma->p[j].w.num / vgl->chroma->p[j].w.den,
604 vgl->fmt.i_height * vgl->chroma->p[j].h.num / vgl->chroma->p[j].h.den,
605 vgl->tex_format, vgl->tex_type, picture->p[j].p_pixels);
609 int last_count = vgl->region_count;
610 gl_region_t *last = vgl->region;
612 vgl->region_count = 0;
618 for (subpicture_region_t *r = subpicture->p_region; r; r = r->p_next)
621 vgl->region_count = count;
622 vgl->region = calloc(count, sizeof(*vgl->region));
624 if (vgl->use_multitexture)
625 vgl->ActiveTextureARB(GL_TEXTURE0_ARB + 0);
627 for (subpicture_region_t *r = subpicture->p_region; r; r = r->p_next, i++) {
628 gl_region_t *glr = &vgl->region[i];
630 glr->format = GL_RGBA;
631 glr->type = GL_UNSIGNED_BYTE;
632 glr->width = r->fmt.i_visible_width;
633 glr->height = r->fmt.i_visible_height;
634 glr->alpha = (float)subpicture->i_alpha * r->i_alpha / 255 / 255;
635 glr->left = 2.0 * (r->i_x ) / subpicture->i_original_picture_width - 1.0;
636 glr->top = -2.0 * (r->i_y ) / subpicture->i_original_picture_height + 1.0;
637 glr->right = 2.0 * (r->i_x + r->fmt.i_visible_width ) / subpicture->i_original_picture_width - 1.0;
638 glr->bottom = -2.0 * (r->i_y + r->fmt.i_visible_height) / subpicture->i_original_picture_height + 1.0;
641 for (int j = 0; j < last_count; j++) {
642 if (last[i].texture &&
643 last[i].width == glr->width &&
644 last[i].height == glr->height &&
645 last[i].format == glr->format &&
646 last[i].type == glr->type) {
647 glr->texture = last[i].texture;
648 memset(&last[i], 0, sizeof(last[i]));
654 glBindTexture(GL_TEXTURE_2D, glr->texture);
655 /* TODO set GL_UNPACK_ALIGNMENT */
656 glPixelStorei(GL_UNPACK_ROW_LENGTH, r->p_picture->p->i_pitch / r->p_picture->p->i_pixel_pitch);
657 glTexSubImage2D(GL_TEXTURE_2D, 0,
658 0, 0, glr->width, glr->height,
659 glr->format, glr->type, r->p_picture->p->p_pixels);
661 glGenTextures(1, &glr->texture);
662 glBindTexture(GL_TEXTURE_2D, glr->texture);
663 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_PRIORITY, 1.0);
664 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
665 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
666 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
667 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
668 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
669 /* TODO set GL_UNPACK_ALIGNMENT */
670 glPixelStorei(GL_UNPACK_ROW_LENGTH, r->p_picture->p->i_pitch / r->p_picture->p->i_pixel_pitch);
671 glTexImage2D(GL_TEXTURE_2D, 0, glr->format,
672 glr->width, glr->height, 0, glr->format, glr->type,
673 r->p_picture->p->p_pixels);
677 for (int i = 0; i < last_count; i++) {
679 glDeleteTextures(1, &last[i].texture);
683 vlc_gl_Unlock(vgl->gl);
684 VLC_UNUSED(subpicture);
688 int vout_display_opengl_Display(vout_display_opengl_t *vgl,
689 const video_format_t *source)
691 if (vlc_gl_Lock(vgl->gl))
694 /* glTexCoord works differently with GL_TEXTURE_2D and
695 GL_TEXTURE_RECTANGLE_EXT */
696 float left[PICTURE_PLANE_MAX];
697 float top[PICTURE_PLANE_MAX];
698 float right[PICTURE_PLANE_MAX];
699 float bottom[PICTURE_PLANE_MAX];
700 for (unsigned j = 0; j < vgl->chroma->plane_count; j++) {
701 float scale_w, scale_h;
702 if (vgl->tex_target == GL_TEXTURE_2D) {
703 scale_w = (float)vgl->chroma->p[j].w.num / vgl->chroma->p[j].w.den / vgl->tex_width[j];
704 scale_h = (float)vgl->chroma->p[j].h.num / vgl->chroma->p[j].h.den / vgl->tex_height[j];
710 left[j] = (source->i_x_offset + 0 ) * scale_w;
711 top[j] = (source->i_y_offset + 0 ) * scale_h;
712 right[j] = (source->i_x_offset + source->i_visible_width ) * scale_w;
713 bottom[j] = (source->i_y_offset + source->i_visible_height) * scale_h;
717 /* Why drawing here and not in Render()? Because this way, the
718 OpenGL providers can call vout_display_opengl_Display to force redraw.i
719 Currently, the OS X provider uses it to get a smooth window resizing */
721 glClear(GL_COLOR_BUFFER_BIT);
724 glEnable(GL_FRAGMENT_PROGRAM_ARB);
725 for (int i = 0; i < vgl->local_count; i++)
726 vgl->ProgramLocalParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, i, vgl->local_value[i]);
728 glEnable(vgl->tex_target);
732 static const GLfloat vertexCoord[] = {
739 const GLfloat textureCoord[8] = {
746 glEnableClientState(GL_VERTEX_ARRAY);
747 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
748 glVertexPointer(2, GL_FLOAT, 0, vertexCoord);
749 glTexCoordPointer(2, GL_FLOAT, 0, textureCoord);
751 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
753 #if !defined(MACOS_OPENGL)
754 for (unsigned j = 0; j < vgl->chroma->plane_count; j++) {
755 if (vgl->use_multitexture)
756 vgl->ActiveTextureARB(GL_TEXTURE0_ARB + j);
757 glBindTexture(vgl->tex_target, vgl->texture[0][j]);
762 glTexCoord2f(left[0], top[0]);
763 for (unsigned j = 1; j < vgl->chroma->plane_count; j++)
764 vgl->MultiTexCoord2fARB(GL_TEXTURE0_ARB + j, left[j], top[j]);
765 glVertex2f(-1.0, 1.0);
767 glTexCoord2f(right[0], top[0]);
768 for (unsigned j = 1; j < vgl->chroma->plane_count; j++)
769 vgl->MultiTexCoord2fARB(GL_TEXTURE0_ARB + j, right[j], top[j]);
770 glVertex2f( 1.0, 1.0);
772 glTexCoord2f(right[0], bottom[0]);
773 for (unsigned j = 1; j < vgl->chroma->plane_count; j++)
774 vgl->MultiTexCoord2fARB(GL_TEXTURE0_ARB + j, right[j], bottom[j]);
775 glVertex2f( 1.0, -1.0);
777 glTexCoord2f(left[0], bottom[0]);
778 for (unsigned j = 1; j < vgl->chroma->plane_count; j++)
779 vgl->MultiTexCoord2fARB(GL_TEXTURE0_ARB + j, left[j], bottom[j]);
780 glVertex2f(-1.0, -1.0);
786 glDisable(GL_FRAGMENT_PROGRAM_ARB);
788 glDisable(vgl->tex_target);
791 if (vgl->use_multitexture)
792 vgl->ActiveTextureARB(GL_TEXTURE0_ARB + 0);
793 glEnable(GL_TEXTURE_2D);
795 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
796 for (int i = 0; i < vgl->region_count; i++) {
797 gl_region_t *glr = &vgl->region[i];
799 glBindTexture(GL_TEXTURE_2D, glr->texture);
803 glColor4f(1.0, 1.0, 1.0, glr->alpha);
805 glTexCoord2f(0.0, 0.0);
806 glVertex2f(glr->left, glr->top);
808 glTexCoord2f(1.0, 0.0);
809 glVertex2f(glr->right, glr->top);
811 glTexCoord2f(1.0, 1.0);
812 glVertex2f(glr->right, glr->bottom);
814 glTexCoord2f(0.0, 1.0);
815 glVertex2f(glr->left, glr->bottom);
820 glDisable(GL_TEXTURE_2D);
823 vlc_gl_Swap(vgl->gl);
825 vlc_gl_Unlock(vgl->gl);