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>
38 // Define USE_OPENGL_ES to the GL ES Version you want to select
41 #ifndef GL_UNSIGNED_SHORT_5_6_5
42 # define GL_UNSIGNED_SHORT_5_6_5 0x8363
44 #ifndef GL_CLAMP_TO_EDGE
45 # define GL_CLAMP_TO_EDGE 0x812F
49 # define PFNGLGENBUFFERSPROC typeof(glGenBuffers)*
50 # define PFNGLBINDBUFFERPROC typeof(glBindBuffer)*
51 # define PFNGLDELETEBUFFERSPROC typeof(glDeleteBuffers)*
52 # define PFNGLBUFFERSUBDATAPROC typeof(glBufferSubData)*
53 # define PFNGLBUFFERDATAPROC typeof(glBufferData)*
54 # define PFNGLGETPROGRAMIVPROC typeof(glGetProgramiv)*
55 # define PFNGLGETPROGRAMINFOLOGPROC typeof(glGetProgramInfoLog)*
56 # define PFNGLGETSHADERIVPROC typeof(glGetShaderiv)*
57 # define PFNGLGETSHADERINFOLOGPROC typeof(glGetShaderInfoLog)*
58 # define PFNGLGETUNIFORMLOCATIONPROC typeof(glGetUniformLocation)*
59 # define PFNGLGETATTRIBLOCATIONPROC typeof(glGetAttribLocation)*
60 # define PFNGLUNIFORM4FVPROC typeof(glUniform4fv)*
61 # define PFNGLUNIFORM4FPROC typeof(glUniform4f)*
62 # define PFNGLUNIFORM3IPROC typeof(glUniform3i)*
63 # define PFNGLUNIFORM1IPROC typeof(glUniform1i)*
64 # define PFNGLCREATESHADERPROC typeof(glCreateShader)*
65 # define PFNGLSHADERSOURCEPROC typeof(glShaderSource)*
66 # define PFNGLCOMPILESHADERPROC typeof(glCompileShader)*
67 # define PFNGLDETACHSHADERPROC typeof(glDetachShader)*
68 # define PFNGLDELETESHADERPROC typeof(glDeleteShader)*
69 # define PFNGLCREATEPROGRAMPROC typeof(glCreateProgram)*
70 # define PFNGLLINKPROGRAMPROC typeof(glLinkProgram)*
71 # define PFNGLUSEPROGRAMPROC typeof(glUseProgram)*
72 # define PFNGLDELETEPROGRAMPROC typeof(glDeleteProgram)*
73 # define PFNGLATTACHSHADERPROC typeof(glAttachShader)*
74 # define PFNGLACTIVETEXTUREPROC typeof(glActiveTexture)*
75 # define PFNGLCLIENTACTIVETEXTUREPROC typeof(glClientActiveTexture)*
77 # define GL_UNPACK_ROW_LENGTH 0
82 # define VLCGL_TEXTURE_COUNT 1
83 # define VLCGL_PICTURE_MAX 1
85 # define VLCGL_TEXTURE_COUNT 1
86 # define VLCGL_PICTURE_MAX 128
89 static const vlc_fourcc_t gl_subpicture_chromas[] = {
109 struct vout_display_opengl_t {
114 const vlc_chroma_description_t *chroma;
121 int tex_width[PICTURE_PLANE_MAX];
122 int tex_height[PICTURE_PLANE_MAX];
124 GLuint texture[VLCGL_TEXTURE_COUNT][PICTURE_PLANE_MAX];
130 picture_pool_t *pool;
132 /* index 0 for normal and 1 for subtitle overlay */
134 GLint shader[3]; //3. is for the common vertex shader
136 GLfloat local_value[16];
138 /* Buffer commands */
139 PFNGLGENBUFFERSPROC GenBuffers;
140 PFNGLBINDBUFFERPROC BindBuffer;
141 PFNGLDELETEBUFFERSPROC DeleteBuffers;
142 PFNGLBUFFERSUBDATAPROC BufferSubData;
144 PFNGLBUFFERDATAPROC BufferData;
146 /* Shader variables commands*/
148 PFNGLGETUNIFORMLOCATIONPROC GetUniformLocation;
149 PFNGLGETATTRIBLOCATIONPROC GetAttribLocation;
151 PFNGLUNIFORM4FVPROC Uniform4fv;
152 PFNGLUNIFORM4FPROC Uniform4f;
153 PFNGLUNIFORM3IPROC Uniform3i;
154 PFNGLUNIFORM1IPROC Uniform1i;
157 PFNGLCREATESHADERPROC CreateShader;
158 PFNGLSHADERSOURCEPROC ShaderSource;
159 PFNGLCOMPILESHADERPROC CompileShader;
160 PFNGLDETACHSHADERPROC DetachShader;
161 PFNGLDELETESHADERPROC DeleteShader;
163 PFNGLCREATEPROGRAMPROC CreateProgram;
164 PFNGLLINKPROGRAMPROC LinkProgram;
165 PFNGLUSEPROGRAMPROC UseProgram;
166 PFNGLDELETEPROGRAMPROC DeleteProgram;
168 PFNGLATTACHSHADERPROC AttachShader;
170 /* Shader log commands */
171 PFNGLGETPROGRAMIVPROC GetProgramiv;
172 PFNGLGETPROGRAMINFOLOGPROC GetProgramInfoLog;
173 PFNGLGETSHADERIVPROC GetShaderiv;
174 PFNGLGETSHADERINFOLOGPROC GetShaderInfoLog;
178 PFNGLACTIVETEXTUREPROC ActiveTexture;
179 PFNGLCLIENTACTIVETEXTUREPROC ClientActiveTexture;
180 bool use_multitexture;
183 static inline int GetAlignedSize(unsigned size)
185 /* Return the smallest larger or equal power of 2 */
186 unsigned align = 1 << (8 * sizeof (unsigned) - clz(size));
187 return ((align >> 1) == size) ? size : align;
191 static bool IsLuminance16Supported(int target)
193 #if defined(MACOS_OPENGL)
194 /* OpenGL 1.x on OS X does _not_ support 16bit shaders, but pretends to.
195 * That's why we enforce return false here, even though the actual code below
197 * This fixes playback of 10bit content on the Intel GMA 950 chipset, which is
198 * the only "GPU" supported by 10.6 and 10.7 with just an OpenGL 1.4 driver.
200 * Presumely, this also improves playback on the GMA 3100, GeForce FX 5200,
201 * GeForce4 Ti, GeForce3, GeForce2 MX/4 MX and the Radeon 8500 when
202 * running OS X 10.5. */
203 const GLubyte * p_glversion;
205 p_glversion = glGetString (GL_VERSION);
206 sscanf((char *)p_glversion, "%f", &f_glversion);
213 glGenTextures(1, &texture);
214 glBindTexture(target, texture);
215 glTexImage2D(target, 0, GL_LUMINANCE16,
216 64, 64, 0, GL_LUMINANCE, GL_UNSIGNED_SHORT, NULL);
218 glGetTexLevelParameteriv(target, 0, GL_TEXTURE_LUMINANCE_SIZE, &size);
220 glDeleteTextures(1, &texture);
226 vout_display_opengl_t *vout_display_opengl_New(video_format_t *fmt,
227 const vlc_fourcc_t **subpicture_chromas,
230 vout_display_opengl_t *vgl = calloc(1, sizeof(*vgl));
235 if (vlc_gl_Lock(vgl->gl)) {
240 if( vgl->gl->getProcAddress == NULL )
242 fprintf(stderr, "getProcAddress not implemented, bailing out\n");
248 const unsigned char *ogl_version = glGetString(GL_VERSION);
249 bool supports_shaders = strverscmp((const char *)ogl_version, "2.0") >= 0;
250 GLint max_texture_units = 0;
251 glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &max_texture_units);
253 /* Initialize with default chroma */
256 vgl->fmt.i_chroma = VLC_CODEC_RGB16;
257 # if defined(WORDS_BIGENDIAN)
258 vgl->fmt.i_rmask = 0x001f;
259 vgl->fmt.i_gmask = 0x07e0;
260 vgl->fmt.i_bmask = 0xf800;
262 vgl->fmt.i_rmask = 0xf800;
263 vgl->fmt.i_gmask = 0x07e0;
264 vgl->fmt.i_bmask = 0x001f;
266 vgl->tex_target = GL_TEXTURE_2D;
267 vgl->tex_format = GL_RGB;
268 vgl->tex_internal = GL_RGB;
269 vgl->tex_type = GL_UNSIGNED_SHORT_5_6_5;
271 vgl->fmt.i_chroma = VLC_CODEC_RGB32;
272 # if defined(WORDS_BIGENDIAN)
273 vgl->fmt.i_rmask = 0xff000000;
274 vgl->fmt.i_gmask = 0x00ff0000;
275 vgl->fmt.i_bmask = 0x0000ff00;
277 vgl->fmt.i_rmask = 0x000000ff;
278 vgl->fmt.i_gmask = 0x0000ff00;
279 vgl->fmt.i_bmask = 0x00ff0000;
281 vgl->tex_target = GL_TEXTURE_2D;
282 vgl->tex_format = GL_RGBA;
283 vgl->tex_internal = GL_RGBA;
284 vgl->tex_type = GL_UNSIGNED_BYTE;
286 /* Use YUV if possible and needed */
287 bool need_fs_yuv = false;
288 float yuv_range_correction = 1.0;
289 if ( max_texture_units >= 3 && supports_shaders &&
290 vlc_fourcc_IsYUV(fmt->i_chroma) && !vlc_fourcc_IsYUV(vgl->fmt.i_chroma)) {
291 const vlc_fourcc_t *list = vlc_fourcc_GetYUVFallback(fmt->i_chroma);
293 const vlc_chroma_description_t *dsc = vlc_fourcc_GetChromaDescription(*list);
294 if (dsc && dsc->plane_count == 3 && dsc->pixel_size == 1) {
297 vgl->fmt.i_chroma = *list;
298 vgl->tex_format = GL_LUMINANCE;
299 vgl->tex_internal = GL_LUMINANCE;
300 vgl->tex_type = GL_UNSIGNED_BYTE;
301 yuv_range_correction = 1.0;
304 } else if (dsc && dsc->plane_count == 3 && dsc->pixel_size == 2 &&
305 IsLuminance16Supported(vgl->tex_target)) {
308 vgl->fmt.i_chroma = *list;
309 vgl->tex_format = GL_LUMINANCE;
310 vgl->tex_internal = GL_LUMINANCE16;
311 vgl->tex_type = GL_UNSIGNED_SHORT;
312 yuv_range_correction = (float)((1 << 16) - 1) / ((1 << dsc->pixel_bits) - 1);
319 #if (defined (__ppc__) || defined (__ppc64__) || defined (__powerpc__)) && defined (__APPLE__)
320 /* This is a work-around for dated PowerPC-based Macs, which run OpenGL 1.3 only and don't
321 * support the GL_ARB_fragment_program extension.
322 * Affected devices are all Macs built between 2002 and 2005 with an ATI Radeon 7500,
323 * an ATI Radeon 9200 or a NVIDIA GeForceFX 5200 Ultra. */
326 vgl->tex_format = GL_YCBCR_422_APPLE;
327 vgl->tex_type = GL_UNSIGNED_SHORT_8_8_APPLE;
328 vgl->fmt.i_chroma = VLC_CODEC_YUYV;
332 vgl->GenBuffers = (PFNGLGENBUFFERSPROC)vlc_gl_GetProcAddress(vgl->gl, "glGenBuffers");
333 vgl->BindBuffer = (PFNGLBINDBUFFERPROC)vlc_gl_GetProcAddress(vgl->gl, "glBindBuffer");
334 vgl->BufferData = (PFNGLBUFFERDATAPROC)vlc_gl_GetProcAddress(vgl->gl, "glBufferData");
335 vgl->BufferSubData = (PFNGLBUFFERSUBDATAPROC)vlc_gl_GetProcAddress(vgl->gl, "glBufferSubData");
336 vgl->DeleteBuffers = (PFNGLDELETEBUFFERSPROC)vlc_gl_GetProcAddress(vgl->gl, "glDeleteBuffers");
338 vgl->CreateShader = (PFNGLCREATESHADERPROC)vlc_gl_GetProcAddress(vgl->gl, "glCreateShader");
339 vgl->ShaderSource = (PFNGLSHADERSOURCEPROC)vlc_gl_GetProcAddress(vgl->gl, "glShaderSource");
340 vgl->CompileShader = (PFNGLCOMPILESHADERPROC)vlc_gl_GetProcAddress(vgl->gl, "glCompileShader");
341 vgl->AttachShader = (PFNGLATTACHSHADERPROC)vlc_gl_GetProcAddress(vgl->gl, "glAttachShader");
342 vgl->GetProgramiv = (PFNGLGETPROGRAMIVPROC)vlc_gl_GetProcAddress(vgl->gl, "glGetProgramiv");
343 vgl->GetProgramInfoLog = (PFNGLGETPROGRAMINFOLOGPROC)vlc_gl_GetProcAddress(vgl->gl, "glGetProgramInfoLog");
344 vgl->GetShaderiv = (PFNGLGETSHADERIVPROC)vlc_gl_GetProcAddress(vgl->gl, "glGetShaderiv");
345 vgl->GetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC)vlc_gl_GetProcAddress(vgl->gl, "glGetShaderInfoLog");
346 vgl->DetachShader = (PFNGLDETACHSHADERPROC)vlc_gl_GetProcAddress(vgl->gl, "glDetachShader");
347 vgl->DeleteShader = (PFNGLDELETESHADERPROC)vlc_gl_GetProcAddress(vgl->gl, "glDeleteShader");
349 vgl->GetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC)vlc_gl_GetProcAddress(vgl->gl, "glGetUniformLocation");
350 vgl->GetAttribLocation = (PFNGLGETATTRIBLOCATIONPROC)vlc_gl_GetProcAddress(vgl->gl, "glGetAttribLocation");
351 vgl->Uniform4fv = (PFNGLUNIFORM4FVPROC)vlc_gl_GetProcAddress(vgl->gl,"glUniform4fv");
352 vgl->Uniform4f = (PFNGLUNIFORM4FPROC)vlc_gl_GetProcAddress(vgl->gl,"glUniform4f");
353 vgl->Uniform3i = (PFNGLUNIFORM3IPROC)vlc_gl_GetProcAddress(vgl->gl,"glUniform3i");
354 vgl->Uniform1i = (PFNGLUNIFORM1IPROC)vlc_gl_GetProcAddress(vgl->gl,"glUniform1i");
356 vgl->CreateProgram = (PFNGLCREATEPROGRAMPROC)vlc_gl_GetProcAddress(vgl->gl, "glCreateProgram");
357 vgl->LinkProgram = (PFNGLLINKPROGRAMPROC)vlc_gl_GetProcAddress(vgl->gl, "glLinkProgram");
358 vgl->UseProgram = (PFNGLUSEPROGRAMPROC)vlc_gl_GetProcAddress(vgl->gl, "glUseProgram");
359 vgl->DeleteProgram = (PFNGLDELETEPROGRAMPROC)vlc_gl_GetProcAddress(vgl->gl, "glDeleteProgram");
360 vgl->ActiveTexture = (PFNGLACTIVETEXTUREPROC)vlc_gl_GetProcAddress(vgl->gl, "glActiveTexture");
361 vgl->ClientActiveTexture = (PFNGLCLIENTACTIVETEXTUREPROC)vlc_gl_GetProcAddress(vgl->gl, "glClientActiveTexture");
363 vgl->chroma = vlc_fourcc_GetChromaDescription(vgl->fmt.i_chroma);
364 vgl->use_multitexture = vgl->chroma->plane_count > 1;
366 if( !vgl->CreateShader || !vgl->ShaderSource || !vgl->CreateProgram )
368 fprintf(stderr, "Looks like you don't have all the opengl we need. Driver is %s, giving up\n", glGetString(GL_VERSION));
375 for (unsigned j = 0; j < vgl->chroma->plane_count; j++) {
376 int w = vgl->fmt.i_width * vgl->chroma->p[j].w.num / vgl->chroma->p[j].w.den;
377 int h = vgl->fmt.i_height * vgl->chroma->p[j].h.num / vgl->chroma->p[j].h.den;
378 vgl->tex_width[j] = w;
379 vgl->tex_height[j] = h;
382 /* Build fragment program if needed */
385 vgl->local_count = 0;
386 vgl->shader[0] = vgl->shader[1] = vgl->shader[2] = -1;
387 if (supports_shaders) {
390 /* [R/G/B][Y U V O] from TV range to full range
391 * XXX we could also do hue/brightness/constrast/gamma
392 * by simply changing the coefficients
394 const float matrix_bt601_tv2full[12] = {
395 1.164383561643836, 0.0000, 1.596026785714286, -0.874202217873451 ,
396 1.164383561643836, -0.391762290094914, -0.812967647237771, 0.531667823499146 ,
397 1.164383561643836, 2.017232142857142, 0.0000, -1.085630789302022 ,
399 const float matrix_bt709_tv2full[12] = {
400 1.164383561643836, 0.0000, 1.792741071428571, -0.972945075016308 ,
401 1.164383561643836, -0.21324861427373, -0.532909328559444, 0.301482665475862 ,
402 1.164383561643836, 2.112401785714286, 0.0000, -1.133402217873451 ,
404 const float (*matrix) = fmt->i_height > 576 ? matrix_bt709_tv2full
405 : matrix_bt601_tv2full;
407 /* Basic linear YUV -> RGB conversion using bilinear interpolation */
408 const char *template_glsl_yuv =
410 "uniform sampler2D Texture0;"
411 "uniform sampler2D Texture1;"
412 "uniform sampler2D Texture2;"
413 "uniform vec4 coefficient[4];"
416 " vec4 x,y,z,result;"
417 " x = texture2D(Texture0, gl_TexCoord[0].st);"
418 " %c = texture2D(Texture1, gl_TexCoord[1].st);"
419 " %c = texture2D(Texture2, gl_TexCoord[2].st);"
421 " result = x * coefficient[0] + coefficient[3];"
422 " result = (y * coefficient[1]) + result;"
423 " result = (z * coefficient[2]) + result;"
424 " gl_FragColor = result;"
426 bool swap_uv = vgl->fmt.i_chroma == VLC_CODEC_YV12 ||
427 vgl->fmt.i_chroma == VLC_CODEC_YV9;
428 if (asprintf(&code, template_glsl_yuv,
430 swap_uv ? 'y' : 'z') < 0)
433 for (int i = 0; i < 4; i++) {
434 float correction = i < 3 ? yuv_range_correction : 1.0;
435 /* We place coefficient values for coefficient[4] in one array from matrix values.
436 Notice that we fill values from top down instead of left to right.*/
437 for( int j = 0; j < 4; j++ )
438 vgl->local_value[vgl->local_count + i*4+j] = j < 3 ? correction * matrix[j*4+i] : 0.0 ;
440 vgl->local_count += 4;
442 // Basic vertex shader that we use in both cases
443 const char *vertexShader =
446 " gl_TexCoord[0] = gl_MultiTexCoord0;"
447 " gl_TexCoord[1] = gl_MultiTexCoord1;"
448 " gl_TexCoord[2] = gl_MultiTexCoord2;"
449 " gl_Position = ftransform(); }";
451 // Dummy shader for text overlay
452 const char *helloShader =
454 "uniform sampler2D Texture0;"
455 "uniform vec4 fillColor;"
458 " gl_FragColor = texture2D(Texture0, gl_TexCoord[0].st)*fillColor;}";
460 vgl->shader[2] = vgl->CreateShader( GL_VERTEX_SHADER );
461 vgl->ShaderSource( vgl->shader[2], 1, (const GLchar **)&vertexShader, NULL);
462 vgl->CompileShader( vgl->shader[2] );
464 /* Create 'dummy' shader that handles subpicture overlay for now*/
465 vgl->shader[1] = vgl->CreateShader( GL_FRAGMENT_SHADER );
466 vgl->ShaderSource( vgl->shader[1], 1, &helloShader, NULL);
467 vgl->CompileShader( vgl->shader[1] );
468 vgl->program[1] = vgl->CreateProgram();
469 vgl->AttachShader( vgl->program[1], vgl->shader[1]);
470 vgl->AttachShader( vgl->program[1], vgl->shader[2]);
471 vgl->LinkProgram( vgl->program[1] );
473 // Create shader from code
474 vgl->shader[0] = vgl->CreateShader( GL_FRAGMENT_SHADER );
475 vgl->program[0] = vgl->CreateProgram();
478 vgl->ShaderSource( vgl->shader[0], 1, (const GLchar **)&code, NULL );
479 vgl->CompileShader( vgl->shader[0]);
480 vgl->AttachShader( vgl->program[0], vgl->shader[0] );
482 /* Use simpler shader if we don't need to to yuv -> rgb,
483 for example when input is allready rgb (.bmp image).*/
484 vgl->AttachShader( vgl->program[0], vgl->shader[1] );
486 vgl->AttachShader( vgl->program[0], vgl->shader[2]);
488 vgl->LinkProgram( vgl->program[0] );
491 for( GLuint i = 0; i < 2; i++ )
494 int charsWritten = 0;
496 vgl->GetProgramiv( vgl->program[i], GL_INFO_LOG_LENGTH, &infoLength );
499 /* If there is some message, better to check linking is ok */
500 GLint link_status = GL_TRUE;
501 vgl->GetProgramiv( vgl->program[i], GL_LINK_STATUS, &link_status );
503 infolog = (char *)malloc(infoLength);
504 vgl->GetProgramInfoLog( vgl->program[i], infoLength, &charsWritten, infolog );
505 fprintf(stderr, "shader program %d:%s %d\n",i,infolog,infoLength);
508 /* Check shaders messages too */
509 for( GLuint j = 0; j < 2; j++ )
511 vgl->GetShaderiv( vgl->shader[j], GL_INFO_LOG_LENGTH, &infoLength );
514 infolog = (char *)malloc(infoLength);
515 vgl->GetShaderInfoLog( vgl->shader[j], infoLength, &charsWritten, infolog );
516 fprintf(stderr, "shader %d: %s\n",j,infolog );
521 if( link_status == GL_FALSE )
523 fprintf( stderr, "Unable to use program %d", i );
533 glDisable(GL_DEPTH_TEST);
534 glDepthMask(GL_FALSE);
535 glDisable(GL_CULL_FACE);
536 glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
537 glClear(GL_COLOR_BUFFER_BIT);
539 vlc_gl_Unlock(vgl->gl);
542 for (int i = 0; i < VLCGL_TEXTURE_COUNT; i++) {
543 for (int j = 0; j < PICTURE_PLANE_MAX; j++)
544 vgl->texture[i][j] = 0;
546 vgl->region_count = 0;
551 if (subpicture_chromas) {
552 *subpicture_chromas = gl_subpicture_chromas;
557 void vout_display_opengl_Delete(vout_display_opengl_t *vgl)
560 if (!vlc_gl_Lock(vgl->gl)) {
564 for (int i = 0; i < VLCGL_TEXTURE_COUNT; i++)
565 glDeleteTextures(vgl->chroma->plane_count, vgl->texture[i]);
566 for (int i = 0; i < vgl->region_count; i++) {
567 if (vgl->region[i].texture)
568 glDeleteTextures(1, &vgl->region[i].texture);
574 for( int i = 0; i < 2; i++ )
575 vgl->DeleteProgram( vgl->program[i] );
576 for( int i = 0; i < 3; i++ )
577 vgl->DeleteShader( vgl->shader[i] );
580 vlc_gl_Unlock(vgl->gl);
583 picture_pool_Delete(vgl->pool);
587 picture_pool_t *vout_display_opengl_GetPool(vout_display_opengl_t *vgl, unsigned requested_count)
592 /* Allocate our pictures */
593 picture_t *picture[VLCGL_PICTURE_MAX] = {NULL, };
596 for (count = 0; count < __MIN(VLCGL_PICTURE_MAX, requested_count); count++) {
597 picture[count] = picture_NewFromFormat(&vgl->fmt);
604 /* Wrap the pictures into a pool */
605 picture_pool_configuration_t cfg;
606 memset(&cfg, 0, sizeof(cfg));
607 cfg.picture_count = count;
608 cfg.picture = picture;
609 vgl->pool = picture_pool_NewExtended(&cfg);
613 /* Allocates our textures */
614 if (vlc_gl_Lock(vgl->gl))
617 for (int i = 0; i < VLCGL_TEXTURE_COUNT; i++) {
618 glGenTextures(vgl->chroma->plane_count, vgl->texture[i]);
619 for (unsigned j = 0; j < vgl->chroma->plane_count; j++) {
620 if (vgl->use_multitexture)
622 vgl->ActiveTexture(GL_TEXTURE0 + j);
623 vgl->ClientActiveTexture(GL_TEXTURE0 + j);
625 glBindTexture(vgl->tex_target, vgl->texture[i][j]);
628 /* Set the texture parameters */
629 glTexParameterf(vgl->tex_target, GL_TEXTURE_PRIORITY, 1.0);
630 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
633 glTexParameteri(vgl->tex_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
634 glTexParameteri(vgl->tex_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
635 glTexParameteri(vgl->tex_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
636 glTexParameteri(vgl->tex_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
638 /* Call glTexImage2D only once, and use glTexSubImage2D later */
639 glTexImage2D(vgl->tex_target, 0,
640 vgl->tex_internal, vgl->tex_width[j], vgl->tex_height[j],
641 0, vgl->tex_format, vgl->tex_type, NULL);
645 vlc_gl_Unlock(vgl->gl);
650 for (unsigned i = 0; i < count; i++)
651 picture_Release(picture[i]);
655 int vout_display_opengl_Prepare(vout_display_opengl_t *vgl,
656 picture_t *picture, subpicture_t *subpicture)
658 /* On Win32/GLX, we do this the usual way:
659 + Fill the buffer with new content,
660 + Reload the texture,
663 On OS X with VRAM or AGP texturing, the order has to be:
664 + Reload the texture,
665 + Fill the buffer with new content,
668 (Thanks to gcc from the Arstechnica forums for the tip)
670 Therefore on OSX, we have to use two buffers and textures and use a
671 lock(/unlock) managed picture pool.
674 if (vlc_gl_Lock(vgl->gl))
677 /* Update the texture */
678 for (unsigned j = 0; j < vgl->chroma->plane_count; j++) {
679 if (vgl->use_multitexture)
681 vgl->ActiveTexture(GL_TEXTURE0 + j);
682 vgl->ClientActiveTexture(GL_TEXTURE0 + j);
684 glBindTexture(vgl->tex_target, vgl->texture[0][j]);
685 glPixelStorei(GL_UNPACK_ROW_LENGTH, picture->p[j].i_pitch / picture->p[j].i_pixel_pitch);
686 glTexSubImage2D(vgl->tex_target, 0,
688 vgl->fmt.i_width * vgl->chroma->p[j].w.num / vgl->chroma->p[j].w.den,
689 vgl->fmt.i_height * vgl->chroma->p[j].h.num / vgl->chroma->p[j].h.den,
690 vgl->tex_format, vgl->tex_type, picture->p[j].p_pixels);
693 int last_count = vgl->region_count;
694 gl_region_t *last = vgl->region;
696 vgl->region_count = 0;
702 for (subpicture_region_t *r = subpicture->p_region; r; r = r->p_next)
705 vgl->region_count = count;
706 vgl->region = calloc(count, sizeof(*vgl->region));
708 if (vgl->use_multitexture)
710 vgl->ActiveTexture(GL_TEXTURE0 + 0);
711 vgl->ClientActiveTexture(GL_TEXTURE0 + 0);
714 for (subpicture_region_t *r = subpicture->p_region; r; r = r->p_next, i++) {
715 gl_region_t *glr = &vgl->region[i];
717 glr->format = GL_RGBA;
718 glr->type = GL_UNSIGNED_BYTE;
719 glr->width = r->fmt.i_visible_width;
720 glr->height = r->fmt.i_visible_height;
721 glr->alpha = (float)subpicture->i_alpha * r->i_alpha / 255 / 255;
722 glr->left = 2.0 * (r->i_x ) / subpicture->i_original_picture_width - 1.0;
723 glr->top = -2.0 * (r->i_y ) / subpicture->i_original_picture_height + 1.0;
724 glr->right = 2.0 * (r->i_x + r->fmt.i_visible_width ) / subpicture->i_original_picture_width - 1.0;
725 glr->bottom = -2.0 * (r->i_y + r->fmt.i_visible_height) / subpicture->i_original_picture_height + 1.0;
728 for (int j = 0; j < last_count; j++) {
729 if (last[j].texture &&
730 last[j].width == glr->width &&
731 last[j].height == glr->height &&
732 last[j].format == glr->format &&
733 last[j].type == glr->type) {
734 glr->texture = last[j].texture;
735 memset(&last[j], 0, sizeof(last[j]));
740 const int pixels_offset = r->fmt.i_y_offset * r->p_picture->p->i_pitch +
741 r->fmt.i_x_offset * r->p_picture->p->i_pixel_pitch;
743 glBindTexture(GL_TEXTURE_2D, glr->texture);
744 /* TODO set GL_UNPACK_ALIGNMENT */
745 glPixelStorei(GL_UNPACK_ROW_LENGTH, r->p_picture->p->i_pitch / r->p_picture->p->i_pixel_pitch);
746 glTexSubImage2D(GL_TEXTURE_2D, 0,
747 0, 0, glr->width, glr->height,
748 glr->format, glr->type, &r->p_picture->p->p_pixels[pixels_offset]);
750 glGenTextures(1, &glr->texture);
751 glBindTexture(GL_TEXTURE_2D, glr->texture);
753 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_PRIORITY, 1.0);
754 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
756 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
757 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
758 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
759 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
760 /* TODO set GL_UNPACK_ALIGNMENT */
761 glPixelStorei(GL_UNPACK_ROW_LENGTH, r->p_picture->p->i_pitch / r->p_picture->p->i_pixel_pitch);
762 glTexImage2D(GL_TEXTURE_2D, 0, glr->format,
763 glr->width, glr->height, 0, glr->format, glr->type,
764 &r->p_picture->p->p_pixels[pixels_offset]);
768 for (int i = 0; i < last_count; i++) {
770 glDeleteTextures(1, &last[i].texture);
774 vlc_gl_Unlock(vgl->gl);
775 VLC_UNUSED(subpicture);
779 static void draw_without_shaders( vout_display_opengl_t *vgl, float *left, float *top, float *right, float *bottom )
781 static const GLfloat vertexCoord[] = {
788 const GLfloat textureCoord[8] = {
795 glEnableClientState(GL_VERTEX_ARRAY);
796 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
797 vgl->ActiveTexture( GL_TEXTURE0);
798 vgl->ClientActiveTexture( GL_TEXTURE0);
799 glEnable(vgl->tex_target);
800 glBindTexture(vgl->tex_target, vgl->texture[0][0]);
801 glVertexPointer(2, GL_FLOAT, 0, vertexCoord);
802 glTexCoordPointer(2, GL_FLOAT, 0, textureCoord);
804 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
806 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
807 glDisableClientState(GL_VERTEX_ARRAY);
808 glDisable(vgl->tex_target);
811 static void draw_with_shaders( vout_display_opengl_t *vgl, float *left, float *top, float *right, float *bottom )
813 vgl->UseProgram(vgl->program[0]);
814 vgl->Uniform4fv( vgl->GetUniformLocation( vgl->program[0], "coefficient" ), 4, vgl->local_value);
815 vgl->Uniform1i( vgl->GetUniformLocation( vgl->program[0], "Texture0" ), 0);
816 vgl->Uniform1i( vgl->GetUniformLocation( vgl->program[0], "Texture1" ), 1);
817 vgl->Uniform1i( vgl->GetUniformLocation( vgl->program[0], "Texture2" ), 2);
819 const GLfloat vertexCoord[] = {
826 for( unsigned j = 0; j < vgl->chroma->plane_count; j++)
828 const GLfloat texCoord[] = {
834 vgl->ActiveTexture( GL_TEXTURE0+j);
835 vgl->ClientActiveTexture( GL_TEXTURE0+j);
836 glEnable(vgl->tex_target);
837 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
838 glBindTexture(vgl->tex_target, vgl->texture[0][j]);
839 glTexCoordPointer(2, GL_FLOAT, 0, texCoord);
841 vgl->ActiveTexture(GL_TEXTURE0 + 0);
842 vgl->ClientActiveTexture(GL_TEXTURE0 + 0);
843 glEnableClientState(GL_VERTEX_ARRAY);
844 glVertexPointer(2, GL_FLOAT, 0, vertexCoord);
845 glDrawArrays( GL_TRIANGLE_STRIP, 0, 4);
846 glDisableClientState(GL_VERTEX_ARRAY);
848 for( int j = vgl->chroma->plane_count; j >= 0;j--)
850 vgl->ActiveTexture( GL_TEXTURE0+j);
851 vgl->ClientActiveTexture( GL_TEXTURE0+j);
852 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
855 vgl->ActiveTexture(GL_TEXTURE0 + 0);
856 vgl->ClientActiveTexture(GL_TEXTURE0 + 0);
859 int vout_display_opengl_Display(vout_display_opengl_t *vgl,
860 const video_format_t *source)
862 if (vlc_gl_Lock(vgl->gl))
865 /* glTexCoord works differently with GL_TEXTURE_2D and
866 GL_TEXTURE_RECTANGLE_EXT */
867 float left[PICTURE_PLANE_MAX];
868 float top[PICTURE_PLANE_MAX];
869 float right[PICTURE_PLANE_MAX];
870 float bottom[PICTURE_PLANE_MAX];
871 for (unsigned j = 0; j < vgl->chroma->plane_count; j++) {
872 float scale_w, scale_h;
873 if (vgl->tex_target == GL_TEXTURE_2D) {
874 scale_w = (float)vgl->chroma->p[j].w.num / vgl->chroma->p[j].w.den / vgl->tex_width[j];
875 scale_h = (float)vgl->chroma->p[j].h.num / vgl->chroma->p[j].h.den / vgl->tex_height[j];
881 left[j] = (source->i_x_offset + 0 ) * scale_w;
882 top[j] = (source->i_y_offset + 0 ) * scale_h;
883 right[j] = (source->i_x_offset + source->i_visible_width ) * scale_w;
884 bottom[j] = (source->i_y_offset + source->i_visible_height) * scale_h;
888 /* Why drawing here and not in Render()? Because this way, the
889 OpenGL providers can call vout_display_opengl_Display to force redraw.i
890 Currently, the OS X provider uses it to get a smooth window resizing */
892 glClear(GL_COLOR_BUFFER_BIT);
895 if( vgl->program[0] )
897 draw_with_shaders( vgl, left, top ,right, bottom );
898 // Change the program for overlays
899 vgl->UseProgram(vgl->program[1]);
900 vgl->Uniform1i( vgl->GetUniformLocation( vgl->program[1], "Texture0" ), 0);
902 draw_without_shaders( vgl, left, top, right, bottom );
905 vgl->ActiveTexture(GL_TEXTURE0 + 0);
906 vgl->ClientActiveTexture(GL_TEXTURE0 + 0);
907 glEnable(GL_TEXTURE_2D);
909 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
910 glEnableClientState(GL_VERTEX_ARRAY);
912 for (int i = 0; i < vgl->region_count; i++) {
913 gl_region_t *glr = &vgl->region[i];
914 const GLfloat vertexCoord[] = {
916 glr->left, glr->bottom,
917 glr->right, glr->top,
918 glr->right,glr->bottom,
920 static const GLfloat textureCoord[] = {
927 if( vgl->program[0] )
929 vgl->Uniform4f( vgl->GetUniformLocation( vgl->program[1], "fillColor"), 1.0f, 1.0f, 1.0f, glr->alpha);
933 glColor4f( 1.0f, 1.0f, 1.0f, glr->alpha );
934 glEnable(GL_TEXTURE_COORD_ARRAY);
935 glEnable(GL_VERTEX_ARRAY);
938 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
940 glBindTexture(GL_TEXTURE_2D, glr->texture);
941 glVertexPointer(2, GL_FLOAT, 0, vertexCoord);
942 glTexCoordPointer(2, GL_FLOAT, 0, textureCoord);
943 glDrawArrays( GL_TRIANGLE_STRIP, 0, 4 );
944 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
946 glDisableClientState(GL_VERTEX_ARRAY);
948 glDisable(GL_TEXTURE_2D);
950 vlc_gl_Swap(vgl->gl);
952 vlc_gl_Unlock(vgl->gl);