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 vgl->GenProgramsARB = (PFNGLGENPROGRAMSARBPROC)vlc_gl_GetProcAddress(vgl->gl, "glGenProgramsARB");
170 vgl->BindProgramARB = (PFNGLBINDPROGRAMARBPROC)vlc_gl_GetProcAddress(vgl->gl, "glBindProgramARB");
171 vgl->ProgramStringARB = (PFNGLPROGRAMSTRINGARBPROC)vlc_gl_GetProcAddress(vgl->gl, "glProgramStringARB");
172 vgl->DeleteProgramsARB = (PFNGLDELETEPROGRAMSARBPROC)vlc_gl_GetProcAddress(vgl->gl, "glDeleteProgramsARB");
173 vgl->ProgramLocalParameter4fvARB = (PFNGLPROGRAMLOCALPARAMETER4FVARBPROC)vlc_gl_GetProcAddress(vgl->gl, "glProgramLocalParameter4fvARB");
175 supports_fp = vgl->GenProgramsARB &&
176 vgl->BindProgramARB &&
177 vgl->ProgramStringARB &&
178 vgl->DeleteProgramsARB &&
179 vgl->ProgramLocalParameter4fvARB;
182 bool supports_multitexture = false;
183 GLint max_texture_units = 0;
184 if (HasExtension(extensions, "GL_ARB_multitexture")) {
185 vgl->ActiveTextureARB = (PFNGLACTIVETEXTUREARBPROC)vlc_gl_GetProcAddress(vgl->gl, "glActiveTextureARB");
186 vgl->MultiTexCoord2fARB = (PFNGLMULTITEXCOORD2FARBPROC)vlc_gl_GetProcAddress(vgl->gl, "glMultiTexCoord2fARB");
188 supports_multitexture = vgl->ActiveTextureARB &&
189 vgl->MultiTexCoord2fARB;
190 if (supports_multitexture)
191 glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &max_texture_units);
194 /* Initialize with default chroma */
197 vgl->fmt.i_chroma = VLC_CODEC_RGB16;
198 # if defined(WORDS_BIGENDIAN)
199 vgl->fmt.i_rmask = 0x001f;
200 vgl->fmt.i_gmask = 0x07e0;
201 vgl->fmt.i_bmask = 0xf800;
203 vgl->fmt.i_rmask = 0xf800;
204 vgl->fmt.i_gmask = 0x07e0;
205 vgl->fmt.i_bmask = 0x001f;
207 vgl->tex_target = GL_TEXTURE_2D;
208 vgl->tex_format = GL_RGB;
209 vgl->tex_internal = GL_RGB;
210 vgl->tex_type = GL_UNSIGNED_SHORT_5_6_5;
211 #elif defined(MACOS_OPENGL)
212 # if defined(WORDS_BIGENDIAN)
213 vgl->fmt.i_chroma = VLC_CODEC_YUYV;
215 vgl->fmt.i_chroma = VLC_CODEC_UYVY;
217 vgl->tex_target = GL_TEXTURE_RECTANGLE_EXT;
218 vgl->tex_format = GL_YCBCR_422_APPLE;
219 vgl->tex_internal = GL_RGBA;
220 vgl->tex_type = GL_UNSIGNED_SHORT_8_8_APPLE;
222 vgl->fmt.i_chroma = VLC_CODEC_RGB32;
223 # if defined(WORDS_BIGENDIAN)
224 vgl->fmt.i_rmask = 0xff000000;
225 vgl->fmt.i_gmask = 0x00ff0000;
226 vgl->fmt.i_bmask = 0x0000ff00;
228 vgl->fmt.i_rmask = 0x000000ff;
229 vgl->fmt.i_gmask = 0x0000ff00;
230 vgl->fmt.i_bmask = 0x00ff0000;
232 vgl->tex_target = GL_TEXTURE_2D;
233 vgl->tex_format = GL_RGBA;
234 vgl->tex_internal = GL_RGBA;
235 vgl->tex_type = GL_UNSIGNED_BYTE;
237 /* Use YUV if possible and needed */
238 bool need_fs_yuv = false;
239 float yuv_range_correction = 1.0;
240 if (supports_fp && supports_multitexture && max_texture_units >= 3 &&
241 vlc_fourcc_IsYUV(fmt->i_chroma) && !vlc_fourcc_IsYUV(vgl->fmt.i_chroma)) {
242 const vlc_fourcc_t *list = vlc_fourcc_GetYUVFallback(fmt->i_chroma);
244 const vlc_chroma_description_t *dsc = vlc_fourcc_GetChromaDescription(*list);
245 if (dsc && dsc->plane_count == 3 && dsc->pixel_size == 1) {
248 vgl->fmt.i_chroma = *list;
249 vgl->tex_format = GL_LUMINANCE;
250 vgl->tex_internal = GL_LUMINANCE;
251 vgl->tex_type = GL_UNSIGNED_BYTE;
252 yuv_range_correction = 1.0;
254 } else if (dsc && dsc->plane_count == 3 && dsc->pixel_size == 2 &&
255 IsLuminance16Supported(vgl->tex_target)) {
258 vgl->fmt.i_chroma = *list;
259 vgl->tex_format = GL_LUMINANCE;
260 vgl->tex_internal = GL_LUMINANCE16;
261 vgl->tex_type = GL_UNSIGNED_SHORT;
262 yuv_range_correction = (float)((1 << 16) - 1) / ((1 << dsc->pixel_bits) - 1);
269 vgl->chroma = vlc_fourcc_GetChromaDescription(vgl->fmt.i_chroma);
270 vgl->use_multitexture = vgl->chroma->plane_count > 1;
272 bool supports_npot = false;
273 #if USE_OPENGL_ES == 2
274 supports_npot = true;
275 #elif defined(MACOS_OPENGL)
276 supports_npot = true;
278 supports_npot |= HasExtension(extensions, "GL_APPLE_texture_2D_limited_npot") ||
279 HasExtension(extensions, "GL_ARB_texture_non_power_of_two");
283 for (unsigned j = 0; j < vgl->chroma->plane_count; j++) {
284 int w = vgl->fmt.i_width * vgl->chroma->p[j].w.num / vgl->chroma->p[j].w.den;
285 int h = vgl->fmt.i_height * vgl->chroma->p[j].h.num / vgl->chroma->p[j].h.den;
287 vgl->tex_width[j] = w;
288 vgl->tex_height[j] = h;
291 /* A texture must have a size aligned on a power of 2 */
292 vgl->tex_width[j] = GetAlignedSize(w);
293 vgl->tex_height[j] = GetAlignedSize(h);
297 /* Build fragment program if needed */
299 vgl->local_count = 0;
304 /* [R/G/B][Y U V O] from TV range to full range
305 * XXX we could also do hue/brightness/constrast/gamma
306 * by simply changing the coefficients
308 const float matrix_bt601_tv2full[3][4] = {
309 { 1.1640, 0.0000, 1.4030, -0.7773 },
310 { 1.1640, -0.3440, -0.7140, 0.4580 },
311 { 1.1640, 1.7730, 0.0000, -0.9630 },
313 const float matrix_bt709_tv2full[3][4] = {
314 { 1.1640, 0.0000, 1.5701, -0.8612 },
315 { 1.1640, -0.1870, -0.4664, 0.2549 },
316 { 1.1640, 1.8556, 0.0000, -1.0045 },
318 const float (*matrix)[4] = fmt->i_height > 576 ? matrix_bt709_tv2full
319 : matrix_bt601_tv2full;
321 /* Basic linear YUV -> RGB conversion using bilinear interpolation */
322 const char *template_yuv =
324 "OPTION ARB_precision_hint_fastest;"
327 "TEX src.x, fragment.texcoord[0], texture[0], 2D;"
328 "TEX src.%c, fragment.texcoord[1], texture[1], 2D;"
329 "TEX src.%c, fragment.texcoord[2], texture[2], 2D;"
331 "PARAM coefficient[4] = { program.local[0..3] };"
334 "MAD tmp.rgb, src.xxxx, coefficient[0], coefficient[3];"
335 "MAD tmp.rgb, src.yyyy, coefficient[1], tmp;"
336 "MAD result.color.rgb, src.zzzz, coefficient[2], tmp;"
338 bool swap_uv = vgl->fmt.i_chroma == VLC_CODEC_YV12 ||
339 vgl->fmt.i_chroma == VLC_CODEC_YV9;
340 if (asprintf(&code, template_yuv,
342 swap_uv ? 'y' : 'z') < 0)
345 for (int i = 0; i < 4; i++) {
346 float correction = i < 3 ? yuv_range_correction : 1.0;
347 for (int j = 0; j < 4; j++) {
348 vgl->local_value[vgl->local_count + i][j] = j < 3 ? correction * matrix[j][i] : 0.0;
351 vgl->local_count += 4;
354 // Here you have shaders
355 vgl->GenProgramsARB(1, &vgl->program);
356 vgl->BindProgramARB(GL_FRAGMENT_PROGRAM_ARB, vgl->program);
357 vgl->ProgramStringARB(GL_FRAGMENT_PROGRAM_ARB,
358 GL_PROGRAM_FORMAT_ASCII_ARB,
359 strlen(code), (const GLbyte*)code);
360 if (glGetError() == GL_INVALID_OPERATION) {
361 /* FIXME if the program was needed for YUV, the video will be broken */
364 glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &position);
366 const char *msg = (const char *)glGetString(GL_PROGRAM_ERROR_STRING_ARB);
367 fprintf(stderr, "GL_INVALID_OPERATION: error at %d: %s\n", position, msg);
369 vgl->DeleteProgramsARB(1, &vgl->program);
378 glDisable(GL_DEPTH_TEST);
379 glDepthMask(GL_FALSE);
380 glDisable(GL_CULL_FACE);
381 glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
382 glClear(GL_COLOR_BUFFER_BIT);
384 vlc_gl_Unlock(vgl->gl);
387 for (int i = 0; i < VLCGL_TEXTURE_COUNT; i++) {
388 for (int j = 0; j < PICTURE_PLANE_MAX; j++)
389 vgl->texture[i][j] = 0;
391 vgl->region_count = 0;
396 if (subpicture_chromas) {
397 *subpicture_chromas = NULL;
398 #if !defined(MACOS_OPENGL) && !USE_OPENGL_ES
400 *subpicture_chromas = gl_subpicture_chromas;
406 void vout_display_opengl_Delete(vout_display_opengl_t *vgl)
409 if (!vlc_gl_Lock(vgl->gl)) {
413 for (int i = 0; i < VLCGL_TEXTURE_COUNT; i++)
414 glDeleteTextures(vgl->chroma->plane_count, vgl->texture[i]);
415 for (int i = 0; i < vgl->region_count; i++) {
416 if (vgl->region[i].texture)
417 glDeleteTextures(1, &vgl->region[i].texture);
422 vgl->DeleteProgramsARB(1, &vgl->program);
424 vlc_gl_Unlock(vgl->gl);
427 picture_pool_Delete(vgl->pool);
432 struct picture_sys_t {
433 vout_display_opengl_t *vgl;
438 static inline GLuint PictureGetTexture(picture_t *picture)
440 return *picture->p_sys->texture;
443 static int PictureLock(picture_t *picture)
448 vout_display_opengl_t *vgl = picture->p_sys->vgl;
449 if (!vlc_gl_Lock(vgl->gl)) {
450 glBindTexture(vgl->tex_target, PictureGetTexture(picture));
451 glPixelStorei(GL_UNPACK_ROW_LENGTH, picture->p->i_pitch / picture->p->i_pixel_pitch);
452 glTexSubImage2D(vgl->tex_target, 0,
453 0, 0, vgl->fmt.i_width, vgl->fmt.i_height,
454 vgl->tex_format, vgl->tex_type, picture->p[0].p_pixels);
456 vlc_gl_Unlock(vgl->gl);
461 static void PictureUnlock(picture_t *picture)
467 picture_pool_t *vout_display_opengl_GetPool(vout_display_opengl_t *vgl, unsigned requested_count)
472 /* Allocate our pictures */
473 picture_t *picture[VLCGL_PICTURE_MAX] = {NULL, };
476 for (count = 0; count < __MIN(VLCGL_PICTURE_MAX, requested_count); count++) {
477 picture[count] = picture_NewFromFormat(&vgl->fmt);
482 picture_sys_t *sys = picture[count]->p_sys = malloc(sizeof(*sys));
485 sys->texture = vgl->texture[count];
492 /* Wrap the pictures into a pool */
493 picture_pool_configuration_t cfg;
494 memset(&cfg, 0, sizeof(cfg));
495 cfg.picture_count = count;
496 cfg.picture = picture;
498 cfg.lock = PictureLock;
499 cfg.unlock = PictureUnlock;
501 vgl->pool = picture_pool_NewExtended(&cfg);
505 /* Allocates our textures */
506 if (vlc_gl_Lock(vgl->gl))
509 for (int i = 0; i < VLCGL_TEXTURE_COUNT; i++) {
510 glGenTextures(vgl->chroma->plane_count, vgl->texture[i]);
511 for (unsigned j = 0; j < vgl->chroma->plane_count; j++) {
512 uint8_t *buffer = NULL;
513 if (vgl->use_multitexture)
514 vgl->ActiveTextureARB(GL_TEXTURE0_ARB + j);
515 glBindTexture(vgl->tex_target, vgl->texture[i][j]);
518 /* Set the texture parameters */
519 glTexParameterf(vgl->tex_target, GL_TEXTURE_PRIORITY, 1.0);
520 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
523 glTexParameteri(vgl->tex_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
524 glTexParameteri(vgl->tex_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
525 glTexParameteri(vgl->tex_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
526 glTexParameteri(vgl->tex_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
529 /* Tell the driver not to make a copy of the texture but to use
531 glEnable(GL_UNPACK_CLIENT_STORAGE_APPLE);
532 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
534 buffer = picture[i]->p[j].p_pixels;
536 /* Use AGP texturing */
537 glTexParameteri(vgl->tex_target, GL_TEXTURE_STORAGE_HINT_APPLE,
538 GL_STORAGE_SHARED_APPLE);
541 /* Call glTexImage2D only once, and use glTexSubImage2D later */
542 glTexImage2D(vgl->tex_target, 0,
543 vgl->tex_internal, vgl->tex_width[j], vgl->tex_height[j],
544 0, vgl->tex_format, vgl->tex_type, buffer);
548 vlc_gl_Unlock(vgl->gl);
553 for (unsigned i = 0; i < count; i++)
554 picture_Delete(picture[i]);
558 int vout_display_opengl_Prepare(vout_display_opengl_t *vgl,
559 picture_t *picture, subpicture_t *subpicture)
561 /* On Win32/GLX, we do this the usual way:
562 + Fill the buffer with new content,
563 + Reload the texture,
566 On OS X with VRAM or AGP texturing, the order has to be:
567 + Reload the texture,
568 + Fill the buffer with new content,
571 (Thanks to gcc from the Arstechnica forums for the tip)
573 Therefore on OSX, we have to use two buffers and textures and use a
574 lock(/unlock) managed picture pool.
577 if (vlc_gl_Lock(vgl->gl))
581 /* Bind to the texture for drawing */
582 glBindTexture(vgl->tex_target, PictureGetTexture(picture));
584 /* Update the texture */
585 for (unsigned j = 0; j < vgl->chroma->plane_count; j++) {
586 if (vgl->use_multitexture)
587 vgl->ActiveTextureARB(GL_TEXTURE0_ARB + j);
588 glBindTexture(vgl->tex_target, vgl->texture[0][j]);
589 glPixelStorei(GL_UNPACK_ROW_LENGTH, picture->p[j].i_pitch / picture->p[j].i_pixel_pitch);
590 glTexSubImage2D(vgl->tex_target, 0,
592 vgl->fmt.i_width * vgl->chroma->p[j].w.num / vgl->chroma->p[j].w.den,
593 vgl->fmt.i_height * vgl->chroma->p[j].h.num / vgl->chroma->p[j].h.den,
594 vgl->tex_format, vgl->tex_type, picture->p[j].p_pixels);
598 int last_count = vgl->region_count;
599 gl_region_t *last = vgl->region;
601 vgl->region_count = 0;
607 for (subpicture_region_t *r = subpicture->p_region; r; r = r->p_next)
610 vgl->region_count = count;
611 vgl->region = calloc(count, sizeof(*vgl->region));
613 if (vgl->use_multitexture)
614 vgl->ActiveTextureARB(GL_TEXTURE0_ARB + 0);
616 for (subpicture_region_t *r = subpicture->p_region; r; r = r->p_next, i++) {
617 gl_region_t *glr = &vgl->region[i];
619 glr->format = GL_RGBA;
620 glr->type = GL_UNSIGNED_BYTE;
621 glr->width = r->fmt.i_visible_width;
622 glr->height = r->fmt.i_visible_height;
623 glr->alpha = (float)subpicture->i_alpha * r->i_alpha / 255 / 255;
624 glr->left = 2.0 * (r->i_x ) / subpicture->i_original_picture_width - 1.0;
625 glr->top = -2.0 * (r->i_y ) / subpicture->i_original_picture_height + 1.0;
626 glr->right = 2.0 * (r->i_x + r->fmt.i_visible_width ) / subpicture->i_original_picture_width - 1.0;
627 glr->bottom = -2.0 * (r->i_y + r->fmt.i_visible_height) / subpicture->i_original_picture_height + 1.0;
630 for (int j = 0; j < last_count; j++) {
631 if (last[j].texture &&
632 last[j].width == glr->width &&
633 last[j].height == glr->height &&
634 last[j].format == glr->format &&
635 last[j].type == glr->type) {
636 glr->texture = last[j].texture;
637 memset(&last[j], 0, sizeof(last[j]));
643 glBindTexture(GL_TEXTURE_2D, glr->texture);
644 /* TODO set GL_UNPACK_ALIGNMENT */
645 glPixelStorei(GL_UNPACK_ROW_LENGTH, r->p_picture->p->i_pitch / r->p_picture->p->i_pixel_pitch);
646 glTexSubImage2D(GL_TEXTURE_2D, 0,
647 0, 0, glr->width, glr->height,
648 glr->format, glr->type, r->p_picture->p->p_pixels);
650 glGenTextures(1, &glr->texture);
651 glBindTexture(GL_TEXTURE_2D, glr->texture);
652 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_PRIORITY, 1.0);
653 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
654 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
655 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
656 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
657 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
658 /* TODO set GL_UNPACK_ALIGNMENT */
659 glPixelStorei(GL_UNPACK_ROW_LENGTH, r->p_picture->p->i_pitch / r->p_picture->p->i_pixel_pitch);
660 glTexImage2D(GL_TEXTURE_2D, 0, glr->format,
661 glr->width, glr->height, 0, glr->format, glr->type,
662 r->p_picture->p->p_pixels);
666 for (int i = 0; i < last_count; i++) {
668 glDeleteTextures(1, &last[i].texture);
672 vlc_gl_Unlock(vgl->gl);
673 VLC_UNUSED(subpicture);
677 int vout_display_opengl_Display(vout_display_opengl_t *vgl,
678 const video_format_t *source)
680 if (vlc_gl_Lock(vgl->gl))
683 /* glTexCoord works differently with GL_TEXTURE_2D and
684 GL_TEXTURE_RECTANGLE_EXT */
685 float left[PICTURE_PLANE_MAX];
686 float top[PICTURE_PLANE_MAX];
687 float right[PICTURE_PLANE_MAX];
688 float bottom[PICTURE_PLANE_MAX];
689 for (unsigned j = 0; j < vgl->chroma->plane_count; j++) {
690 float scale_w, scale_h;
691 if (vgl->tex_target == GL_TEXTURE_2D) {
692 scale_w = (float)vgl->chroma->p[j].w.num / vgl->chroma->p[j].w.den / vgl->tex_width[j];
693 scale_h = (float)vgl->chroma->p[j].h.num / vgl->chroma->p[j].h.den / vgl->tex_height[j];
699 left[j] = (source->i_x_offset + 0 ) * scale_w;
700 top[j] = (source->i_y_offset + 0 ) * scale_h;
701 right[j] = (source->i_x_offset + source->i_visible_width ) * scale_w;
702 bottom[j] = (source->i_y_offset + source->i_visible_height) * scale_h;
706 /* Why drawing here and not in Render()? Because this way, the
707 OpenGL providers can call vout_display_opengl_Display to force redraw.i
708 Currently, the OS X provider uses it to get a smooth window resizing */
710 glClear(GL_COLOR_BUFFER_BIT);
713 glEnable(GL_FRAGMENT_PROGRAM_ARB);
714 for (int i = 0; i < vgl->local_count; i++)
715 vgl->ProgramLocalParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, i, vgl->local_value[i]);
717 glEnable(vgl->tex_target);
721 static const GLfloat vertexCoord[] = {
728 const GLfloat textureCoord[8] = {
735 glEnableClientState(GL_VERTEX_ARRAY);
736 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
737 glVertexPointer(2, GL_FLOAT, 0, vertexCoord);
738 glTexCoordPointer(2, GL_FLOAT, 0, textureCoord);
740 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
742 #if !defined(MACOS_OPENGL)
743 for (unsigned j = 0; j < vgl->chroma->plane_count; j++) {
744 if (vgl->use_multitexture)
745 vgl->ActiveTextureARB(GL_TEXTURE0_ARB + j);
746 glBindTexture(vgl->tex_target, vgl->texture[0][j]);
751 glTexCoord2f(left[0], top[0]);
752 for (unsigned j = 1; j < vgl->chroma->plane_count; j++)
753 vgl->MultiTexCoord2fARB(GL_TEXTURE0_ARB + j, left[j], top[j]);
754 glVertex2f(-1.0, 1.0);
756 glTexCoord2f(right[0], top[0]);
757 for (unsigned j = 1; j < vgl->chroma->plane_count; j++)
758 vgl->MultiTexCoord2fARB(GL_TEXTURE0_ARB + j, right[j], top[j]);
759 glVertex2f( 1.0, 1.0);
761 glTexCoord2f(right[0], bottom[0]);
762 for (unsigned j = 1; j < vgl->chroma->plane_count; j++)
763 vgl->MultiTexCoord2fARB(GL_TEXTURE0_ARB + j, right[j], bottom[j]);
764 glVertex2f( 1.0, -1.0);
766 glTexCoord2f(left[0], bottom[0]);
767 for (unsigned j = 1; j < vgl->chroma->plane_count; j++)
768 vgl->MultiTexCoord2fARB(GL_TEXTURE0_ARB + j, left[j], bottom[j]);
769 glVertex2f(-1.0, -1.0);
775 glDisable(GL_FRAGMENT_PROGRAM_ARB);
777 glDisable(vgl->tex_target);
780 if (vgl->use_multitexture)
781 vgl->ActiveTextureARB(GL_TEXTURE0_ARB + 0);
782 glEnable(GL_TEXTURE_2D);
784 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
785 for (int i = 0; i < vgl->region_count; i++) {
786 gl_region_t *glr = &vgl->region[i];
788 glBindTexture(GL_TEXTURE_2D, glr->texture);
792 glColor4f(1.0, 1.0, 1.0, glr->alpha);
794 glTexCoord2f(0.0, 0.0);
795 glVertex2f(glr->left, glr->top);
797 glTexCoord2f(1.0, 0.0);
798 glVertex2f(glr->right, glr->top);
800 glTexCoord2f(1.0, 1.0);
801 glVertex2f(glr->right, glr->bottom);
803 glTexCoord2f(0.0, 1.0);
804 glVertex2f(glr->left, glr->bottom);
809 glDisable(GL_TEXTURE_2D);
812 vlc_gl_Swap(vgl->gl);
814 vlc_gl_Unlock(vgl->gl);