1 /*****************************************************************************
2 * opengl.c: OpenGL and OpenGL ES output common code
3 *****************************************************************************
4 * Copyright (C) 2004-2012 VLC authors and VideoLAN
5 * Copyright (C) 2009, 2011 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>
12 * Ilkka Ollakka <ileoo@videolan.org>
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
27 *****************************************************************************/
32 #include <vlc_common.h>
33 #include <vlc_picture_pool.h>
34 #include <vlc_subpicture.h>
35 #include <vlc_opengl.h>
39 #ifndef GL_CLAMP_TO_EDGE
40 # define GL_CLAMP_TO_EDGE 0x812F
44 # define PFNGLGENBUFFERSPROC typeof(glGenBuffers)*
45 # define PFNGLBINDBUFFERPROC typeof(glBindBuffer)*
46 # define PFNGLDELETEBUFFERSPROC typeof(glDeleteBuffers)*
47 # define PFNGLBUFFERSUBDATAPROC typeof(glBufferSubData)*
48 # define PFNGLBUFFERDATAPROC typeof(glBufferData)*
49 # define PFNGLGETPROGRAMIVPROC typeof(glGetProgramiv)*
50 # define PFNGLGETPROGRAMINFOLOGPROC typeof(glGetProgramInfoLog)*
51 # define PFNGLGETSHADERIVPROC typeof(glGetShaderiv)*
52 # define PFNGLGETSHADERINFOLOGPROC typeof(glGetShaderInfoLog)*
53 # define PFNGLGETUNIFORMLOCATIONPROC typeof(glGetUniformLocation)*
54 # define PFNGLGETATTRIBLOCATIONPROC typeof(glGetAttribLocation)*
55 # define PFNGLUNIFORM4FVPROC typeof(glUniform4fv)*
56 # define PFNGLUNIFORM4FPROC typeof(glUniform4f)*
57 # define PFNGLUNIFORM3IPROC typeof(glUniform3i)*
58 # define PFNGLUNIFORM1IPROC typeof(glUniform1i)*
59 # define PFNGLCREATESHADERPROC typeof(glCreateShader)*
60 # define PFNGLSHADERSOURCEPROC typeof(glShaderSource)*
61 # define PFNGLCOMPILESHADERPROC typeof(glCompileShader)*
62 # define PFNGLDETACHSHADERPROC typeof(glDetachShader)*
63 # define PFNGLDELETESHADERPROC typeof(glDeleteShader)*
64 # define PFNGLCREATEPROGRAMPROC typeof(glCreateProgram)*
65 # define PFNGLLINKPROGRAMPROC typeof(glLinkProgram)*
66 # define PFNGLUSEPROGRAMPROC typeof(glUseProgram)*
67 # define PFNGLDELETEPROGRAMPROC typeof(glDeleteProgram)*
68 # define PFNGLATTACHSHADERPROC typeof(glAttachShader)*
69 # define PFNGLACTIVETEXTUREPROC typeof(glActiveTexture)*
70 # define PFNGLCLIENTACTIVETEXTUREPROC typeof(glClientActiveTexture)*
72 # define GL_UNPACK_ROW_LENGTH 0
73 # import <CoreFoundation/CoreFoundation.h>
78 # define VLCGL_TEXTURE_COUNT 1
79 # define VLCGL_PICTURE_MAX 1
81 # define VLCGL_TEXTURE_COUNT 1
82 # define VLCGL_PICTURE_MAX 128
85 static const vlc_fourcc_t gl_subpicture_chromas[] = {
105 struct vout_display_opengl_t {
110 const vlc_chroma_description_t *chroma;
117 int tex_width[PICTURE_PLANE_MAX];
118 int tex_height[PICTURE_PLANE_MAX];
120 GLuint texture[VLCGL_TEXTURE_COUNT][PICTURE_PLANE_MAX];
126 picture_pool_t *pool;
128 /* index 0 for normal and 1 for subtitle overlay */
130 GLint shader[3]; //3. is for the common vertex shader
132 GLfloat local_value[16];
134 /* Buffer commands */
135 PFNGLGENBUFFERSPROC GenBuffers;
136 PFNGLBINDBUFFERPROC BindBuffer;
137 PFNGLDELETEBUFFERSPROC DeleteBuffers;
138 PFNGLBUFFERSUBDATAPROC BufferSubData;
140 PFNGLBUFFERDATAPROC BufferData;
142 /* Shader variables commands*/
144 PFNGLGETUNIFORMLOCATIONPROC GetUniformLocation;
145 PFNGLGETATTRIBLOCATIONPROC GetAttribLocation;
147 PFNGLUNIFORM4FVPROC Uniform4fv;
148 PFNGLUNIFORM4FPROC Uniform4f;
149 PFNGLUNIFORM3IPROC Uniform3i;
150 PFNGLUNIFORM1IPROC Uniform1i;
153 PFNGLCREATESHADERPROC CreateShader;
154 PFNGLSHADERSOURCEPROC ShaderSource;
155 PFNGLCOMPILESHADERPROC CompileShader;
156 PFNGLDETACHSHADERPROC DetachShader;
157 PFNGLDELETESHADERPROC DeleteShader;
159 PFNGLCREATEPROGRAMPROC CreateProgram;
160 PFNGLLINKPROGRAMPROC LinkProgram;
161 PFNGLUSEPROGRAMPROC UseProgram;
162 PFNGLDELETEPROGRAMPROC DeleteProgram;
164 PFNGLATTACHSHADERPROC AttachShader;
166 /* Shader log commands */
167 PFNGLGETPROGRAMIVPROC GetProgramiv;
168 PFNGLGETPROGRAMINFOLOGPROC GetProgramInfoLog;
169 PFNGLGETSHADERIVPROC GetShaderiv;
170 PFNGLGETSHADERINFOLOGPROC GetShaderInfoLog;
174 PFNGLACTIVETEXTUREPROC ActiveTexture;
175 PFNGLCLIENTACTIVETEXTUREPROC ClientActiveTexture;
176 bool use_multitexture;
179 static inline int GetAlignedSize(unsigned size)
181 /* Return the smallest larger or equal power of 2 */
182 unsigned align = 1 << (8 * sizeof (unsigned) - clz(size));
183 return ((align >> 1) == size) ? size : align;
187 static bool IsLuminance16Supported(int target)
189 #if defined(MACOS_OPENGL)
190 /* OpenGL 1.x on OS X does _not_ support 16bit shaders, but pretends to.
191 * That's why we enforce return false here, even though the actual code below
193 * This fixes playback of 10bit content on the Intel GMA 950 chipset, which is
194 * the only "GPU" supported by 10.6 and 10.7 with just an OpenGL 1.4 driver.
196 * Presumely, this also improves playback on the GMA 3100, GeForce FX 5200,
197 * GeForce4 Ti, GeForce3, GeForce2 MX/4 MX and the Radeon 8500 when
198 * running OS X 10.5. */
199 const GLubyte * p_glversion;
201 p_glversion = glGetString (GL_VERSION);
202 sscanf((char *)p_glversion, "%f", &f_glversion);
209 glGenTextures(1, &texture);
210 glBindTexture(target, texture);
211 glTexImage2D(target, 0, GL_LUMINANCE16,
212 64, 64, 0, GL_LUMINANCE, GL_UNSIGNED_SHORT, NULL);
214 glGetTexLevelParameteriv(target, 0, GL_TEXTURE_LUMINANCE_SIZE, &size);
216 glDeleteTextures(1, &texture);
222 vout_display_opengl_t *vout_display_opengl_New(video_format_t *fmt,
223 const vlc_fourcc_t **subpicture_chromas,
226 vout_display_opengl_t *vgl = calloc(1, sizeof(*vgl));
231 if (vlc_gl_Lock(vgl->gl)) {
236 if( vgl->gl->getProcAddress == NULL )
238 fprintf(stderr, "getProcAddress not implemented, bailing out\n");
244 const unsigned char *ogl_version = glGetString(GL_VERSION);
245 bool supports_shaders = strverscmp((const char *)ogl_version, "2.0") >= 0;
247 bool supports_shaders = false;
249 if( kCFCoreFoundationVersionNumber >= 786. )
250 supports_shaders = true;
254 GLint max_texture_units = 0;
255 glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &max_texture_units);
257 /* Initialize with default chroma */
259 vgl->fmt.i_chroma = VLC_CODEC_RGB32;
260 # if defined(WORDS_BIGENDIAN)
261 vgl->fmt.i_rmask = 0xff000000;
262 vgl->fmt.i_gmask = 0x00ff0000;
263 vgl->fmt.i_bmask = 0x0000ff00;
265 vgl->fmt.i_rmask = 0x000000ff;
266 vgl->fmt.i_gmask = 0x0000ff00;
267 vgl->fmt.i_bmask = 0x00ff0000;
269 vgl->tex_target = GL_TEXTURE_2D;
270 vgl->tex_format = GL_RGBA;
271 vgl->tex_internal = GL_RGBA;
272 vgl->tex_type = GL_UNSIGNED_BYTE;
273 /* Use YUV if possible and needed */
274 bool need_fs_yuv = false;
275 float yuv_range_correction = 1.0;
276 if ( max_texture_units >= 3 && supports_shaders &&
277 vlc_fourcc_IsYUV(fmt->i_chroma) && !vlc_fourcc_IsYUV(vgl->fmt.i_chroma)) {
278 const vlc_fourcc_t *list = vlc_fourcc_GetYUVFallback(fmt->i_chroma);
280 const vlc_chroma_description_t *dsc = vlc_fourcc_GetChromaDescription(*list);
281 if (dsc && dsc->plane_count == 3 && dsc->pixel_size == 1) {
284 vgl->fmt.i_chroma = *list;
285 vgl->tex_format = GL_LUMINANCE;
286 vgl->tex_internal = GL_LUMINANCE;
287 vgl->tex_type = GL_UNSIGNED_BYTE;
288 yuv_range_correction = 1.0;
291 } else if (dsc && dsc->plane_count == 3 && dsc->pixel_size == 2 &&
292 IsLuminance16Supported(vgl->tex_target)) {
295 vgl->fmt.i_chroma = *list;
296 vgl->tex_format = GL_LUMINANCE;
297 vgl->tex_internal = GL_LUMINANCE16;
298 vgl->tex_type = GL_UNSIGNED_SHORT;
299 yuv_range_correction = (float)((1 << 16) - 1) / ((1 << dsc->pixel_bits) - 1);
306 #if (defined (__ppc__) || defined (__ppc64__) || defined (__powerpc__)) && defined (__APPLE__)
307 /* This is a work-around for dated PowerPC-based Macs, which run OpenGL 1.3 only and don't
308 * support the GL_ARB_fragment_program extension.
309 * Affected devices are all Macs built between 2002 and 2005 with an ATI Radeon 7500,
310 * an ATI Radeon 9200 or a NVIDIA GeForceFX 5200 Ultra. */
313 vgl->tex_format = GL_YCBCR_422_APPLE;
314 vgl->tex_type = GL_UNSIGNED_SHORT_8_8_APPLE;
315 vgl->fmt.i_chroma = VLC_CODEC_YUYV;
319 vgl->GenBuffers = (PFNGLGENBUFFERSPROC)vlc_gl_GetProcAddress(vgl->gl, "glGenBuffers");
320 vgl->BindBuffer = (PFNGLBINDBUFFERPROC)vlc_gl_GetProcAddress(vgl->gl, "glBindBuffer");
321 vgl->BufferData = (PFNGLBUFFERDATAPROC)vlc_gl_GetProcAddress(vgl->gl, "glBufferData");
322 vgl->BufferSubData = (PFNGLBUFFERSUBDATAPROC)vlc_gl_GetProcAddress(vgl->gl, "glBufferSubData");
323 vgl->DeleteBuffers = (PFNGLDELETEBUFFERSPROC)vlc_gl_GetProcAddress(vgl->gl, "glDeleteBuffers");
325 vgl->CreateShader = (PFNGLCREATESHADERPROC)vlc_gl_GetProcAddress(vgl->gl, "glCreateShader");
326 vgl->ShaderSource = (PFNGLSHADERSOURCEPROC)vlc_gl_GetProcAddress(vgl->gl, "glShaderSource");
327 vgl->CompileShader = (PFNGLCOMPILESHADERPROC)vlc_gl_GetProcAddress(vgl->gl, "glCompileShader");
328 vgl->AttachShader = (PFNGLATTACHSHADERPROC)vlc_gl_GetProcAddress(vgl->gl, "glAttachShader");
329 vgl->GetProgramiv = (PFNGLGETPROGRAMIVPROC)vlc_gl_GetProcAddress(vgl->gl, "glGetProgramiv");
330 vgl->GetProgramInfoLog = (PFNGLGETPROGRAMINFOLOGPROC)vlc_gl_GetProcAddress(vgl->gl, "glGetProgramInfoLog");
331 vgl->GetShaderiv = (PFNGLGETSHADERIVPROC)vlc_gl_GetProcAddress(vgl->gl, "glGetShaderiv");
332 vgl->GetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC)vlc_gl_GetProcAddress(vgl->gl, "glGetShaderInfoLog");
333 vgl->DetachShader = (PFNGLDETACHSHADERPROC)vlc_gl_GetProcAddress(vgl->gl, "glDetachShader");
334 vgl->DeleteShader = (PFNGLDELETESHADERPROC)vlc_gl_GetProcAddress(vgl->gl, "glDeleteShader");
336 vgl->GetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC)vlc_gl_GetProcAddress(vgl->gl, "glGetUniformLocation");
337 vgl->GetAttribLocation = (PFNGLGETATTRIBLOCATIONPROC)vlc_gl_GetProcAddress(vgl->gl, "glGetAttribLocation");
338 vgl->Uniform4fv = (PFNGLUNIFORM4FVPROC)vlc_gl_GetProcAddress(vgl->gl,"glUniform4fv");
339 vgl->Uniform4f = (PFNGLUNIFORM4FPROC)vlc_gl_GetProcAddress(vgl->gl,"glUniform4f");
340 vgl->Uniform3i = (PFNGLUNIFORM3IPROC)vlc_gl_GetProcAddress(vgl->gl,"glUniform3i");
341 vgl->Uniform1i = (PFNGLUNIFORM1IPROC)vlc_gl_GetProcAddress(vgl->gl,"glUniform1i");
343 vgl->CreateProgram = (PFNGLCREATEPROGRAMPROC)vlc_gl_GetProcAddress(vgl->gl, "glCreateProgram");
344 vgl->LinkProgram = (PFNGLLINKPROGRAMPROC)vlc_gl_GetProcAddress(vgl->gl, "glLinkProgram");
345 vgl->UseProgram = (PFNGLUSEPROGRAMPROC)vlc_gl_GetProcAddress(vgl->gl, "glUseProgram");
346 vgl->DeleteProgram = (PFNGLDELETEPROGRAMPROC)vlc_gl_GetProcAddress(vgl->gl, "glDeleteProgram");
347 vgl->ActiveTexture = (PFNGLACTIVETEXTUREPROC)vlc_gl_GetProcAddress(vgl->gl, "glActiveTexture");
348 vgl->ClientActiveTexture = (PFNGLCLIENTACTIVETEXTUREPROC)vlc_gl_GetProcAddress(vgl->gl, "glClientActiveTexture");
350 vgl->chroma = vlc_fourcc_GetChromaDescription(vgl->fmt.i_chroma);
351 vgl->use_multitexture = vgl->chroma->plane_count > 1;
353 if( !vgl->CreateShader || !vgl->ShaderSource || !vgl->CreateProgram )
355 fprintf(stderr, "Looks like you don't have all the opengl we need. Driver is %s, giving up\n", glGetString(GL_VERSION));
362 for (unsigned j = 0; j < vgl->chroma->plane_count; j++) {
363 int w = vgl->fmt.i_width * vgl->chroma->p[j].w.num / vgl->chroma->p[j].w.den;
364 int h = vgl->fmt.i_height * vgl->chroma->p[j].h.num / vgl->chroma->p[j].h.den;
365 vgl->tex_width[j] = w;
366 vgl->tex_height[j] = h;
369 /* Build fragment program if needed */
372 vgl->local_count = 0;
373 vgl->shader[0] = vgl->shader[1] = vgl->shader[2] = -1;
374 if (supports_shaders) {
377 /* [R/G/B][Y U V O] from TV range to full range
378 * XXX we could also do hue/brightness/constrast/gamma
379 * by simply changing the coefficients
381 const float matrix_bt601_tv2full[12] = {
382 1.164383561643836, 0.0000, 1.596026785714286, -0.874202217873451 ,
383 1.164383561643836, -0.391762290094914, -0.812967647237771, 0.531667823499146 ,
384 1.164383561643836, 2.017232142857142, 0.0000, -1.085630789302022 ,
386 const float matrix_bt709_tv2full[12] = {
387 1.164383561643836, 0.0000, 1.792741071428571, -0.972945075016308 ,
388 1.164383561643836, -0.21324861427373, -0.532909328559444, 0.301482665475862 ,
389 1.164383561643836, 2.112401785714286, 0.0000, -1.133402217873451 ,
391 const float (*matrix) = fmt->i_height > 576 ? matrix_bt709_tv2full
392 : matrix_bt601_tv2full;
394 /* Basic linear YUV -> RGB conversion using bilinear interpolation */
395 const char *template_glsl_yuv =
397 "uniform sampler2D Texture0;"
398 "uniform sampler2D Texture1;"
399 "uniform sampler2D Texture2;"
400 "uniform vec4 coefficient[4];"
403 " vec4 x,y,z,result;"
404 " x = texture2D(Texture0, gl_TexCoord[0].st);"
405 " %c = texture2D(Texture1, gl_TexCoord[1].st);"
406 " %c = texture2D(Texture2, gl_TexCoord[2].st);"
408 " result = x * coefficient[0] + coefficient[3];"
409 " result = (y * coefficient[1]) + result;"
410 " result = (z * coefficient[2]) + result;"
411 " gl_FragColor = result;"
413 bool swap_uv = vgl->fmt.i_chroma == VLC_CODEC_YV12 ||
414 vgl->fmt.i_chroma == VLC_CODEC_YV9;
415 if (asprintf(&code, template_glsl_yuv,
417 swap_uv ? 'y' : 'z') < 0)
420 for (int i = 0; i < 4; i++) {
421 float correction = i < 3 ? yuv_range_correction : 1.0;
422 /* We place coefficient values for coefficient[4] in one array from matrix values.
423 Notice that we fill values from top down instead of left to right.*/
424 for( int j = 0; j < 4; j++ )
425 vgl->local_value[vgl->local_count + i*4+j] = j < 3 ? correction * matrix[j*4+i] : 0.0 ;
427 vgl->local_count += 4;
429 // Basic vertex shader that we use in both cases
430 const char *vertexShader =
433 " gl_TexCoord[0] = gl_MultiTexCoord0;"
434 " gl_TexCoord[1] = gl_MultiTexCoord1;"
435 " gl_TexCoord[2] = gl_MultiTexCoord2;"
436 " gl_Position = ftransform(); }";
438 // Dummy shader for text overlay
439 const char *helloShader =
441 "uniform sampler2D Texture0;"
442 "uniform vec4 fillColor;"
445 " gl_FragColor = texture2D(Texture0, gl_TexCoord[0].st)*fillColor;}";
447 vgl->shader[2] = vgl->CreateShader( GL_VERTEX_SHADER );
448 vgl->ShaderSource( vgl->shader[2], 1, (const GLchar **)&vertexShader, NULL);
449 vgl->CompileShader( vgl->shader[2] );
451 /* Create 'dummy' shader that handles subpicture overlay for now*/
452 vgl->shader[1] = vgl->CreateShader( GL_FRAGMENT_SHADER );
453 vgl->ShaderSource( vgl->shader[1], 1, &helloShader, NULL);
454 vgl->CompileShader( vgl->shader[1] );
455 vgl->program[1] = vgl->CreateProgram();
456 vgl->AttachShader( vgl->program[1], vgl->shader[1]);
457 vgl->AttachShader( vgl->program[1], vgl->shader[2]);
458 vgl->LinkProgram( vgl->program[1] );
460 // Create shader from code
461 vgl->shader[0] = vgl->CreateShader( GL_FRAGMENT_SHADER );
462 vgl->program[0] = vgl->CreateProgram();
465 vgl->ShaderSource( vgl->shader[0], 1, (const GLchar **)&code, NULL );
466 vgl->CompileShader( vgl->shader[0]);
467 vgl->AttachShader( vgl->program[0], vgl->shader[0] );
469 /* Use simpler shader if we don't need to to yuv -> rgb,
470 for example when input is allready rgb (.bmp image).*/
471 vgl->AttachShader( vgl->program[0], vgl->shader[1] );
473 vgl->AttachShader( vgl->program[0], vgl->shader[2]);
475 vgl->LinkProgram( vgl->program[0] );
478 for( GLuint i = 0; i < 2; i++ )
481 int charsWritten = 0;
483 vgl->GetProgramiv( vgl->program[i], GL_INFO_LOG_LENGTH, &infoLength );
486 /* If there is some message, better to check linking is ok */
487 GLint link_status = GL_TRUE;
488 vgl->GetProgramiv( vgl->program[i], GL_LINK_STATUS, &link_status );
490 infolog = (char *)malloc(infoLength);
491 vgl->GetProgramInfoLog( vgl->program[i], infoLength, &charsWritten, infolog );
492 fprintf(stderr, "shader program %d:%s %d\n",i,infolog,infoLength);
495 /* Check shaders messages too */
496 for( GLuint j = 0; j < 2; j++ )
498 vgl->GetShaderiv( vgl->shader[j], GL_INFO_LOG_LENGTH, &infoLength );
501 infolog = (char *)malloc(infoLength);
502 vgl->GetShaderInfoLog( vgl->shader[j], infoLength, &charsWritten, infolog );
503 fprintf(stderr, "shader %d: %s\n",j,infolog );
508 if( link_status == GL_FALSE )
510 fprintf( stderr, "Unable to use program %d\n", i );
520 glDisable(GL_DEPTH_TEST);
521 glDepthMask(GL_FALSE);
522 glDisable(GL_CULL_FACE);
523 glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
524 glClear(GL_COLOR_BUFFER_BIT);
526 vlc_gl_Unlock(vgl->gl);
529 for (int i = 0; i < VLCGL_TEXTURE_COUNT; i++) {
530 for (int j = 0; j < PICTURE_PLANE_MAX; j++)
531 vgl->texture[i][j] = 0;
533 vgl->region_count = 0;
538 if (subpicture_chromas) {
539 *subpicture_chromas = gl_subpicture_chromas;
544 void vout_display_opengl_Delete(vout_display_opengl_t *vgl)
547 if (!vlc_gl_Lock(vgl->gl)) {
551 for (int i = 0; i < VLCGL_TEXTURE_COUNT; i++)
552 glDeleteTextures(vgl->chroma->plane_count, vgl->texture[i]);
553 for (int i = 0; i < vgl->region_count; i++) {
554 if (vgl->region[i].texture)
555 glDeleteTextures(1, &vgl->region[i].texture);
561 for( int i = 0; i < 2; i++ )
562 vgl->DeleteProgram( vgl->program[i] );
563 for( int i = 0; i < 3; i++ )
564 vgl->DeleteShader( vgl->shader[i] );
567 vlc_gl_Unlock(vgl->gl);
570 picture_pool_Delete(vgl->pool);
574 picture_pool_t *vout_display_opengl_GetPool(vout_display_opengl_t *vgl, unsigned requested_count)
579 /* Allocate our pictures */
580 picture_t *picture[VLCGL_PICTURE_MAX] = {NULL, };
583 for (count = 0; count < __MIN(VLCGL_PICTURE_MAX, requested_count); count++) {
584 picture[count] = picture_NewFromFormat(&vgl->fmt);
591 /* Wrap the pictures into a pool */
592 picture_pool_configuration_t cfg;
593 memset(&cfg, 0, sizeof(cfg));
594 cfg.picture_count = count;
595 cfg.picture = picture;
596 vgl->pool = picture_pool_NewExtended(&cfg);
600 /* Allocates our textures */
601 if (vlc_gl_Lock(vgl->gl))
604 for (int i = 0; i < VLCGL_TEXTURE_COUNT; i++) {
605 glGenTextures(vgl->chroma->plane_count, vgl->texture[i]);
606 for (unsigned j = 0; j < vgl->chroma->plane_count; j++) {
607 if (vgl->use_multitexture)
609 vgl->ActiveTexture(GL_TEXTURE0 + j);
610 vgl->ClientActiveTexture(GL_TEXTURE0 + j);
612 glBindTexture(vgl->tex_target, vgl->texture[i][j]);
615 /* Set the texture parameters */
616 glTexParameterf(vgl->tex_target, GL_TEXTURE_PRIORITY, 1.0);
617 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
620 glTexParameteri(vgl->tex_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
621 glTexParameteri(vgl->tex_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
622 glTexParameteri(vgl->tex_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
623 glTexParameteri(vgl->tex_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
625 /* Call glTexImage2D only once, and use glTexSubImage2D later */
626 glTexImage2D(vgl->tex_target, 0,
627 vgl->tex_internal, vgl->tex_width[j], vgl->tex_height[j],
628 0, vgl->tex_format, vgl->tex_type, NULL);
632 vlc_gl_Unlock(vgl->gl);
637 for (unsigned i = 0; i < count; i++)
638 picture_Release(picture[i]);
642 int vout_display_opengl_Prepare(vout_display_opengl_t *vgl,
643 picture_t *picture, subpicture_t *subpicture)
645 /* On Win32/GLX, we do this the usual way:
646 + Fill the buffer with new content,
647 + Reload the texture,
650 On OS X with VRAM or AGP texturing, the order has to be:
651 + Reload the texture,
652 + Fill the buffer with new content,
655 (Thanks to gcc from the Arstechnica forums for the tip)
657 Therefore on OSX, we have to use two buffers and textures and use a
658 lock(/unlock) managed picture pool.
661 if (vlc_gl_Lock(vgl->gl))
664 /* Update the texture */
665 for (unsigned j = 0; j < vgl->chroma->plane_count; j++) {
666 if (vgl->use_multitexture)
668 vgl->ActiveTexture(GL_TEXTURE0 + j);
669 vgl->ClientActiveTexture(GL_TEXTURE0 + j);
671 glBindTexture(vgl->tex_target, vgl->texture[0][j]);
672 glPixelStorei(GL_UNPACK_ROW_LENGTH, picture->p[j].i_pitch / picture->p[j].i_pixel_pitch);
673 glTexSubImage2D(vgl->tex_target, 0,
675 vgl->fmt.i_width * vgl->chroma->p[j].w.num / vgl->chroma->p[j].w.den,
676 vgl->fmt.i_height * vgl->chroma->p[j].h.num / vgl->chroma->p[j].h.den,
677 vgl->tex_format, vgl->tex_type, picture->p[j].p_pixels);
680 int last_count = vgl->region_count;
681 gl_region_t *last = vgl->region;
683 vgl->region_count = 0;
689 for (subpicture_region_t *r = subpicture->p_region; r; r = r->p_next)
692 vgl->region_count = count;
693 vgl->region = calloc(count, sizeof(*vgl->region));
695 if (vgl->use_multitexture)
697 vgl->ActiveTexture(GL_TEXTURE0 + 0);
698 vgl->ClientActiveTexture(GL_TEXTURE0 + 0);
701 for (subpicture_region_t *r = subpicture->p_region; r; r = r->p_next, i++) {
702 gl_region_t *glr = &vgl->region[i];
704 glr->format = GL_RGBA;
705 glr->type = GL_UNSIGNED_BYTE;
706 glr->width = r->fmt.i_visible_width;
707 glr->height = r->fmt.i_visible_height;
708 glr->alpha = (float)subpicture->i_alpha * r->i_alpha / 255 / 255;
709 glr->left = 2.0 * (r->i_x ) / subpicture->i_original_picture_width - 1.0;
710 glr->top = -2.0 * (r->i_y ) / subpicture->i_original_picture_height + 1.0;
711 glr->right = 2.0 * (r->i_x + r->fmt.i_visible_width ) / subpicture->i_original_picture_width - 1.0;
712 glr->bottom = -2.0 * (r->i_y + r->fmt.i_visible_height) / subpicture->i_original_picture_height + 1.0;
715 for (int j = 0; j < last_count; j++) {
716 if (last[j].texture &&
717 last[j].width == glr->width &&
718 last[j].height == glr->height &&
719 last[j].format == glr->format &&
720 last[j].type == glr->type) {
721 glr->texture = last[j].texture;
722 memset(&last[j], 0, sizeof(last[j]));
727 const int pixels_offset = r->fmt.i_y_offset * r->p_picture->p->i_pitch +
728 r->fmt.i_x_offset * r->p_picture->p->i_pixel_pitch;
730 glBindTexture(GL_TEXTURE_2D, glr->texture);
731 /* TODO set GL_UNPACK_ALIGNMENT */
732 glPixelStorei(GL_UNPACK_ROW_LENGTH, r->p_picture->p->i_pitch / r->p_picture->p->i_pixel_pitch);
733 glTexSubImage2D(GL_TEXTURE_2D, 0,
734 0, 0, glr->width, glr->height,
735 glr->format, glr->type, &r->p_picture->p->p_pixels[pixels_offset]);
737 glGenTextures(1, &glr->texture);
738 glBindTexture(GL_TEXTURE_2D, glr->texture);
740 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_PRIORITY, 1.0);
741 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
743 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
744 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
745 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
746 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
747 /* TODO set GL_UNPACK_ALIGNMENT */
748 glPixelStorei(GL_UNPACK_ROW_LENGTH, r->p_picture->p->i_pitch / r->p_picture->p->i_pixel_pitch);
749 glTexImage2D(GL_TEXTURE_2D, 0, glr->format,
750 glr->width, glr->height, 0, glr->format, glr->type,
751 &r->p_picture->p->p_pixels[pixels_offset]);
755 for (int i = 0; i < last_count; i++) {
757 glDeleteTextures(1, &last[i].texture);
761 vlc_gl_Unlock(vgl->gl);
762 VLC_UNUSED(subpicture);
766 static void draw_without_shaders( vout_display_opengl_t *vgl, float *left, float *top, float *right, float *bottom )
768 static const GLfloat vertexCoord[] = {
775 const GLfloat textureCoord[8] = {
782 glEnableClientState(GL_VERTEX_ARRAY);
783 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
784 glEnable(GL_VERTEX_ARRAY);
785 glEnable(GL_TEXTURE_COORD_ARRAY);
787 vgl->ActiveTexture( GL_TEXTURE0);
788 vgl->ClientActiveTexture( GL_TEXTURE0);
790 glEnable(vgl->tex_target);
791 glBindTexture(vgl->tex_target, vgl->texture[0][0]);
792 glVertexPointer(2, GL_FLOAT, 0, vertexCoord);
793 glTexCoordPointer(2, GL_FLOAT, 0, textureCoord);
795 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
797 glDisable(vgl->tex_target);
798 glDisable(GL_TEXTURE_COORD_ARRAY);
799 glDisable(GL_VERTEX_ARRAY);
800 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
801 glDisableClientState(GL_VERTEX_ARRAY);
804 static void draw_with_shaders( vout_display_opengl_t *vgl, float *left, float *top, float *right, float *bottom )
806 vgl->UseProgram(vgl->program[0]);
807 vgl->Uniform4fv( vgl->GetUniformLocation( vgl->program[0], "coefficient" ), 4, vgl->local_value);
808 vgl->Uniform1i( vgl->GetUniformLocation( vgl->program[0], "Texture0" ), 0);
809 vgl->Uniform1i( vgl->GetUniformLocation( vgl->program[0], "Texture1" ), 1);
810 vgl->Uniform1i( vgl->GetUniformLocation( vgl->program[0], "Texture2" ), 2);
812 const GLfloat vertexCoord[] = {
819 for( unsigned j = 0; j < vgl->chroma->plane_count; j++)
821 const GLfloat texCoord[] = {
827 vgl->ActiveTexture( GL_TEXTURE0+j);
828 vgl->ClientActiveTexture( GL_TEXTURE0+j);
829 glEnable(vgl->tex_target);
830 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
831 glBindTexture(vgl->tex_target, vgl->texture[0][j]);
832 glTexCoordPointer(2, GL_FLOAT, 0, texCoord);
834 vgl->ActiveTexture(GL_TEXTURE0 + 0);
835 vgl->ClientActiveTexture(GL_TEXTURE0 + 0);
836 glEnableClientState(GL_VERTEX_ARRAY);
837 glVertexPointer(2, GL_FLOAT, 0, vertexCoord);
838 glDrawArrays( GL_TRIANGLE_STRIP, 0, 4);
839 glDisableClientState(GL_VERTEX_ARRAY);
841 for( int j = vgl->chroma->plane_count; j >= 0;j--)
843 vgl->ActiveTexture( GL_TEXTURE0+j);
844 vgl->ClientActiveTexture( GL_TEXTURE0+j);
845 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
848 vgl->ActiveTexture(GL_TEXTURE0 + 0);
849 vgl->ClientActiveTexture(GL_TEXTURE0 + 0);
852 int vout_display_opengl_Display(vout_display_opengl_t *vgl,
853 const video_format_t *source)
855 if (vlc_gl_Lock(vgl->gl))
858 /* glTexCoord works differently with GL_TEXTURE_2D and
859 GL_TEXTURE_RECTANGLE_EXT */
860 float left[PICTURE_PLANE_MAX];
861 float top[PICTURE_PLANE_MAX];
862 float right[PICTURE_PLANE_MAX];
863 float bottom[PICTURE_PLANE_MAX];
864 for (unsigned j = 0; j < vgl->chroma->plane_count; j++) {
865 float scale_w, scale_h;
866 if (vgl->tex_target == GL_TEXTURE_2D) {
867 scale_w = (float)vgl->chroma->p[j].w.num / vgl->chroma->p[j].w.den / vgl->tex_width[j];
868 scale_h = (float)vgl->chroma->p[j].h.num / vgl->chroma->p[j].h.den / vgl->tex_height[j];
874 left[j] = (source->i_x_offset + 0 ) * scale_w;
875 top[j] = (source->i_y_offset + 0 ) * scale_h;
876 right[j] = (source->i_x_offset + source->i_visible_width ) * scale_w;
877 bottom[j] = (source->i_y_offset + source->i_visible_height) * scale_h;
881 /* Why drawing here and not in Render()? Because this way, the
882 OpenGL providers can call vout_display_opengl_Display to force redraw.i
883 Currently, the OS X provider uses it to get a smooth window resizing */
885 glClear(GL_COLOR_BUFFER_BIT);
888 if( vgl->program[0] )
890 draw_with_shaders( vgl, left, top ,right, bottom );
891 // Change the program for overlays
892 vgl->UseProgram(vgl->program[1]);
893 vgl->Uniform1i( vgl->GetUniformLocation( vgl->program[1], "Texture0" ), 0);
895 draw_without_shaders( vgl, left, top, right, bottom );
898 vgl->ActiveTexture(GL_TEXTURE0 + 0);
899 vgl->ClientActiveTexture(GL_TEXTURE0 + 0);
900 glEnable(GL_TEXTURE_2D);
902 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
903 glEnableClientState(GL_VERTEX_ARRAY);
905 for (int i = 0; i < vgl->region_count; i++) {
906 gl_region_t *glr = &vgl->region[i];
907 const GLfloat vertexCoord[] = {
909 glr->left, glr->bottom,
910 glr->right, glr->top,
911 glr->right,glr->bottom,
913 static const GLfloat textureCoord[] = {
920 if( vgl->program[0] )
922 vgl->Uniform4f( vgl->GetUniformLocation( vgl->program[1], "fillColor"), 1.0f, 1.0f, 1.0f, glr->alpha);
926 glColor4f( 1.0f, 1.0f, 1.0f, glr->alpha );
927 glEnable(GL_TEXTURE_COORD_ARRAY);
928 glEnable(GL_VERTEX_ARRAY);
931 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
933 glBindTexture(GL_TEXTURE_2D, glr->texture);
934 glVertexPointer(2, GL_FLOAT, 0, vertexCoord);
935 glTexCoordPointer(2, GL_FLOAT, 0, textureCoord);
936 glDrawArrays( GL_TRIANGLE_STRIP, 0, 4 );
937 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
939 glDisableClientState(GL_VERTEX_ARRAY);
941 glDisable(GL_TEXTURE_2D);
943 vlc_gl_Swap(vgl->gl);
945 vlc_gl_Unlock(vgl->gl);