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 PFNGLVERTEXATTRIBLOCATIONPROC typeof(glVertexAttribPointer)*
56 # define PFNGLENABLEVERTEXATTRIBARRAYPROC typeof(glEnableVertexAttribArray)*
57 # define PFNGLUNIFORM4FVPROC typeof(glUniform4fv)*
58 # define PFNGLUNIFORM4FPROC typeof(glUniform4f)*
59 # define PFNGLUNIFORM3IPROC typeof(glUniform3i)*
60 # define PFNGLUNIFORM1IPROC typeof(glUniform1i)*
61 # define PFNGLCREATESHADERPROC typeof(glCreateShader)*
62 # define PFNGLSHADERSOURCEPROC typeof(glShaderSource)*
63 # define PFNGLCOMPILESHADERPROC typeof(glCompileShader)*
64 # define PFNGLDETACHSHADERPROC typeof(glDetachShader)*
65 # define PFNGLDELETESHADERPROC typeof(glDeleteShader)*
66 # define PFNGLCREATEPROGRAMPROC typeof(glCreateProgram)*
67 # define PFNGLLINKPROGRAMPROC typeof(glLinkProgram)*
68 # define PFNGLUSEPROGRAMPROC typeof(glUseProgram)*
69 # define PFNGLDELETEPROGRAMPROC typeof(glDeleteProgram)*
70 # define PFNGLATTACHSHADERPROC typeof(glAttachShader)*
71 # define PFNGLACTIVETEXTUREPROC typeof(glActiveTexture)*
72 # define PFNGLCLIENTACTIVETEXTUREPROC typeof(glClientActiveTexture)*
74 # define GL_UNPACK_ROW_LENGTH 0
75 # import <CoreFoundation/CoreFoundation.h>
80 # define VLCGL_TEXTURE_COUNT 1
81 # define VLCGL_PICTURE_MAX 1
83 # define VLCGL_TEXTURE_COUNT 1
84 # define VLCGL_PICTURE_MAX 128
87 static const vlc_fourcc_t gl_subpicture_chromas[] = {
107 struct vout_display_opengl_t {
112 const vlc_chroma_description_t *chroma;
119 int tex_width[PICTURE_PLANE_MAX];
120 int tex_height[PICTURE_PLANE_MAX];
122 GLuint texture[VLCGL_TEXTURE_COUNT][PICTURE_PLANE_MAX];
128 picture_pool_t *pool;
130 /* index 0 for normal and 1 for subtitle overlay */
132 GLint shader[3]; //3. is for the common vertex shader
134 GLfloat local_value[16];
136 /* Buffer commands */
137 PFNGLGENBUFFERSPROC GenBuffers;
138 PFNGLBINDBUFFERPROC BindBuffer;
139 PFNGLDELETEBUFFERSPROC DeleteBuffers;
140 PFNGLBUFFERSUBDATAPROC BufferSubData;
142 PFNGLBUFFERDATAPROC BufferData;
144 /* Shader variables commands*/
146 PFNGLGETUNIFORMLOCATIONPROC GetUniformLocation;
147 PFNGLGETATTRIBLOCATIONPROC GetAttribLocation;
148 PFNGLVERTEXATTRIBPOINTERPROC VertexAttribPointer;
149 PFNGLENABLEVERTEXATTRIBARRAYPROC EnableVertexAttribArray;
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;
182 /* Non-power-of-2 texture size support */
186 static inline int GetAlignedSize(unsigned size)
188 /* Return the smallest larger or equal power of 2 */
189 unsigned align = 1 << (8 * sizeof (unsigned) - clz(size));
190 return ((align >> 1) == size) ? size : align;
194 static bool IsLuminance16Supported(int target)
196 #if defined(MACOS_OPENGL)
197 /* OpenGL 1.x on OS X does _not_ support 16bit shaders, but pretends to.
198 * That's why we enforce return false here, even though the actual code below
200 * This fixes playback of 10bit content on the Intel GMA 950 chipset, which is
201 * the only "GPU" supported by 10.6 and 10.7 with just an OpenGL 1.4 driver.
203 * Presumely, this also improves playback on the GMA 3100, GeForce FX 5200,
204 * GeForce4 Ti, GeForce3, GeForce2 MX/4 MX and the Radeon 8500 when
205 * running OS X 10.5. */
206 const GLubyte * p_glversion;
208 p_glversion = glGetString (GL_VERSION);
209 sscanf((char *)p_glversion, "%f", &f_glversion);
216 glGenTextures(1, &texture);
217 glBindTexture(target, texture);
218 glTexImage2D(target, 0, GL_LUMINANCE16,
219 64, 64, 0, GL_LUMINANCE, GL_UNSIGNED_SHORT, NULL);
221 glGetTexLevelParameteriv(target, 0, GL_TEXTURE_LUMINANCE_SIZE, &size);
223 glDeleteTextures(1, &texture);
229 vout_display_opengl_t *vout_display_opengl_New(video_format_t *fmt,
230 const vlc_fourcc_t **subpicture_chromas,
233 vout_display_opengl_t *vgl = calloc(1, sizeof(*vgl));
238 if (vlc_gl_Lock(vgl->gl)) {
243 if( vgl->gl->getProcAddress == NULL )
245 fprintf(stderr, "getProcAddress not implemented, bailing out\n");
250 const char *extensions = (const char *)glGetString(GL_EXTENSIONS);
252 const unsigned char *ogl_version = glGetString(GL_VERSION);
253 bool supports_shaders = strverscmp((const char *)ogl_version, "2.0") >= 0;
255 bool supports_shaders = false;
257 if( kCFCoreFoundationVersionNumber >= 786. )
258 supports_shaders = true;
262 GLint max_texture_units = 0;
263 glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &max_texture_units);
265 /* Initialize with default chroma */
267 vgl->fmt.i_chroma = VLC_CODEC_RGB32;
268 # if defined(WORDS_BIGENDIAN)
269 vgl->fmt.i_rmask = 0xff000000;
270 vgl->fmt.i_gmask = 0x00ff0000;
271 vgl->fmt.i_bmask = 0x0000ff00;
273 vgl->fmt.i_rmask = 0x000000ff;
274 vgl->fmt.i_gmask = 0x0000ff00;
275 vgl->fmt.i_bmask = 0x00ff0000;
277 vgl->tex_target = GL_TEXTURE_2D;
278 vgl->tex_format = GL_RGBA;
279 vgl->tex_internal = GL_RGBA;
280 vgl->tex_type = GL_UNSIGNED_BYTE;
281 /* Use YUV if possible and needed */
282 bool need_fs_yuv = false;
283 float yuv_range_correction = 1.0;
284 if ( max_texture_units >= 3 && supports_shaders &&
285 vlc_fourcc_IsYUV(fmt->i_chroma) && !vlc_fourcc_IsYUV(vgl->fmt.i_chroma)) {
286 const vlc_fourcc_t *list = vlc_fourcc_GetYUVFallback(fmt->i_chroma);
288 const vlc_chroma_description_t *dsc = vlc_fourcc_GetChromaDescription(*list);
289 if (dsc && dsc->plane_count == 3 && dsc->pixel_size == 1) {
292 vgl->fmt.i_chroma = *list;
293 vgl->tex_format = GL_LUMINANCE;
294 vgl->tex_internal = GL_LUMINANCE;
295 vgl->tex_type = GL_UNSIGNED_BYTE;
296 yuv_range_correction = 1.0;
299 } else if (dsc && dsc->plane_count == 3 && dsc->pixel_size == 2 &&
300 IsLuminance16Supported(vgl->tex_target)) {
303 vgl->fmt.i_chroma = *list;
304 vgl->tex_format = GL_LUMINANCE;
305 vgl->tex_internal = GL_LUMINANCE16;
306 vgl->tex_type = GL_UNSIGNED_SHORT;
307 yuv_range_correction = (float)((1 << 16) - 1) / ((1 << dsc->pixel_bits) - 1);
314 #if (defined (__ppc__) || defined (__ppc64__) || defined (__powerpc__)) && defined (__APPLE__)
315 /* This is a work-around for dated PowerPC-based Macs, which run OpenGL 1.3 only and don't
316 * support the GL_ARB_fragment_program extension.
317 * Affected devices are all Macs built between 2002 and 2005 with an ATI Radeon 7500,
318 * an ATI Radeon 9200 or a NVIDIA GeForceFX 5200 Ultra. */
321 vgl->tex_format = GL_YCBCR_422_APPLE;
322 vgl->tex_type = GL_UNSIGNED_SHORT_8_8_APPLE;
323 vgl->fmt.i_chroma = VLC_CODEC_YUYV;
327 vgl->GenBuffers = (PFNGLGENBUFFERSPROC)vlc_gl_GetProcAddress(vgl->gl, "glGenBuffers");
328 vgl->BindBuffer = (PFNGLBINDBUFFERPROC)vlc_gl_GetProcAddress(vgl->gl, "glBindBuffer");
329 vgl->BufferData = (PFNGLBUFFERDATAPROC)vlc_gl_GetProcAddress(vgl->gl, "glBufferData");
330 vgl->BufferSubData = (PFNGLBUFFERSUBDATAPROC)vlc_gl_GetProcAddress(vgl->gl, "glBufferSubData");
331 vgl->DeleteBuffers = (PFNGLDELETEBUFFERSPROC)vlc_gl_GetProcAddress(vgl->gl, "glDeleteBuffers");
333 vgl->CreateShader = (PFNGLCREATESHADERPROC)vlc_gl_GetProcAddress(vgl->gl, "glCreateShader");
334 vgl->ShaderSource = (PFNGLSHADERSOURCEPROC)vlc_gl_GetProcAddress(vgl->gl, "glShaderSource");
335 vgl->CompileShader = (PFNGLCOMPILESHADERPROC)vlc_gl_GetProcAddress(vgl->gl, "glCompileShader");
336 vgl->AttachShader = (PFNGLATTACHSHADERPROC)vlc_gl_GetProcAddress(vgl->gl, "glAttachShader");
338 vgl->GetProgramiv = (PFNGLGETPROGRAMIVPROC)vlc_gl_GetProcAddress(vgl->gl, "glGetProgramiv");
339 vgl->GetShaderiv = (PFNGLGETSHADERIVPROC)vlc_gl_GetProcAddress(vgl->gl, "glGetShaderiv");
340 vgl->GetProgramInfoLog = (PFNGLGETPROGRAMINFOLOGPROC)vlc_gl_GetProcAddress(vgl->gl, "glGetProgramInfoLog");
341 vgl->GetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC)vlc_gl_GetProcAddress(vgl->gl, "glGetShaderInfoLog");
343 vgl->DetachShader = (PFNGLDETACHSHADERPROC)vlc_gl_GetProcAddress(vgl->gl, "glDetachShader");
344 vgl->DeleteShader = (PFNGLDELETESHADERPROC)vlc_gl_GetProcAddress(vgl->gl, "glDeleteShader");
346 vgl->GetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC)vlc_gl_GetProcAddress(vgl->gl, "glGetUniformLocation");
347 vgl->GetAttribLocation = (PFNGLGETATTRIBLOCATIONPROC)vlc_gl_GetProcAddress(vgl->gl, "glGetAttribLocation");
348 vgl->VertexAttribPointer= (PFNGLVERTEXATTRIBPOINTERPROC)vlc_gl_GetProcAddress(vgl->gl, "glVertexAttribPointer");
349 vgl->EnableVertexAttribArray = (PFNGLENABLEVERTEXATTRIBARRAYPROC)vlc_gl_GetProcAddress(vgl->gl, "glEnableVertexAttribArray");
350 vgl->Uniform4fv = (PFNGLUNIFORM4FVPROC)vlc_gl_GetProcAddress(vgl->gl,"glUniform4fv");
351 vgl->Uniform4f = (PFNGLUNIFORM4FPROC)vlc_gl_GetProcAddress(vgl->gl,"glUniform4f");
352 vgl->Uniform3i = (PFNGLUNIFORM3IPROC)vlc_gl_GetProcAddress(vgl->gl,"glUniform3i");
353 vgl->Uniform1i = (PFNGLUNIFORM1IPROC)vlc_gl_GetProcAddress(vgl->gl,"glUniform1i");
355 vgl->CreateProgram = (PFNGLCREATEPROGRAMPROC)vlc_gl_GetProcAddress(vgl->gl, "glCreateProgram");
356 vgl->LinkProgram = (PFNGLLINKPROGRAMPROC)vlc_gl_GetProcAddress(vgl->gl, "glLinkProgram");
357 vgl->UseProgram = (PFNGLUSEPROGRAMPROC)vlc_gl_GetProcAddress(vgl->gl, "glUseProgram");
358 vgl->DeleteProgram = (PFNGLDELETEPROGRAMPROC)vlc_gl_GetProcAddress(vgl->gl, "glDeleteProgram");
359 vgl->ActiveTexture = (PFNGLACTIVETEXTUREPROC)vlc_gl_GetProcAddress(vgl->gl, "glActiveTexture");
360 vgl->ClientActiveTexture = (PFNGLCLIENTACTIVETEXTUREPROC)vlc_gl_GetProcAddress(vgl->gl, "glClientActiveTexture");
362 vgl->chroma = vlc_fourcc_GetChromaDescription(vgl->fmt.i_chroma);
363 vgl->use_multitexture = vgl->chroma->plane_count > 1;
364 vgl->supports_npot = HasExtension( extensions, "GL_ARB_texture_non_power_of_two" ) ||
365 HasExtension( extensions, "GL_APPLE_texture_2D_limited_npot" );
367 if( !vgl->CreateShader || !vgl->ShaderSource || !vgl->CreateProgram )
369 fprintf(stderr, "Looks like you don't have all the opengl we need. Driver is %s, giving up\n", glGetString(GL_VERSION));
376 for (unsigned j = 0; j < vgl->chroma->plane_count; j++) {
377 int w = vgl->fmt.i_width * vgl->chroma->p[j].w.num / vgl->chroma->p[j].w.den;
378 int h = vgl->fmt.i_height * vgl->chroma->p[j].h.num / vgl->chroma->p[j].h.den;
379 if( vgl->supports_npot )
381 vgl->tex_width[j] = w;
382 vgl->tex_height[j] = h;
384 vgl->tex_width[j] = GetAlignedSize(w);
385 vgl->tex_height[j] = GetAlignedSize(h);
389 /* Build fragment program if needed */
392 vgl->local_count = 0;
393 vgl->shader[0] = vgl->shader[1] = vgl->shader[2] = -1;
394 if (supports_shaders) {
397 /* [R/G/B][Y U V O] from TV range to full range
398 * XXX we could also do hue/brightness/constrast/gamma
399 * by simply changing the coefficients
401 const float matrix_bt601_tv2full[12] = {
402 1.164383561643836, 0.0000, 1.596026785714286, -0.874202217873451 ,
403 1.164383561643836, -0.391762290094914, -0.812967647237771, 0.531667823499146 ,
404 1.164383561643836, 2.017232142857142, 0.0000, -1.085630789302022 ,
406 const float matrix_bt709_tv2full[12] = {
407 1.164383561643836, 0.0000, 1.792741071428571, -0.972945075016308 ,
408 1.164383561643836, -0.21324861427373, -0.532909328559444, 0.301482665475862 ,
409 1.164383561643836, 2.112401785714286, 0.0000, -1.133402217873451 ,
411 const float (*matrix) = fmt->i_height > 576 ? matrix_bt709_tv2full
412 : matrix_bt601_tv2full;
414 /* Basic linear YUV -> RGB conversion using bilinear interpolation */
415 const char *template_glsl_yuv =
417 "uniform sampler2D Texture[3];"
418 "uniform vec4 coefficient[4];"
419 "varying vec4 TexCoord0,TexCoord1,TexCoord2;"
422 " vec4 x,y,z,result;"
423 " x = texture2D(Texture[0], TexCoord0.st);"
424 " %c = texture2D(Texture[1], TexCoord1.st);"
425 " %c = texture2D(Texture[2], TexCoord2.st);"
427 " result = x * coefficient[0] + coefficient[3];"
428 " result = (y * coefficient[1]) + result;"
429 " result = (z * coefficient[2]) + result;"
430 " gl_FragColor = result;"
432 bool swap_uv = vgl->fmt.i_chroma == VLC_CODEC_YV12 ||
433 vgl->fmt.i_chroma == VLC_CODEC_YV9;
434 if (asprintf(&code, template_glsl_yuv,
436 swap_uv ? 'y' : 'z') < 0)
439 for (int i = 0; i < 4; i++) {
440 float correction = i < 3 ? yuv_range_correction : 1.0;
441 /* We place coefficient values for coefficient[4] in one array from matrix values.
442 Notice that we fill values from top down instead of left to right.*/
443 for( int j = 0; j < 4; j++ )
444 vgl->local_value[vgl->local_count + i*4+j] = j < 3 ? correction * matrix[j*4+i] : 0.0 ;
446 vgl->local_count += 4;
448 // Basic vertex shader that we use in both cases
449 const char *vertexShader =
451 "varying vec4 TexCoord0,TexCoord1, TexCoord2;"
452 "attribute vec4 MultiTexCoord0,MultiTexCoord1,MultiTexCoord2;"
453 "attribute vec4 vertex_position;"
455 " TexCoord0 = MultiTexCoord0;"
456 " TexCoord1 = MultiTexCoord1;"
457 " TexCoord2 = MultiTexCoord2;"
458 " gl_Position = vertex_position; }";
460 // Dummy shader for text overlay
461 const char *helloShader =
463 "uniform sampler2D Texture[3];"
464 "uniform vec4 fillColor;"
465 "varying vec4 TexCoord0,TexCoord1,TexCoord2;"
468 " gl_FragColor = texture2D(Texture[0], TexCoord0.st)*fillColor;}";
470 vgl->shader[2] = vgl->CreateShader( GL_VERTEX_SHADER );
471 vgl->ShaderSource( vgl->shader[2], 1, (const GLchar **)&vertexShader, NULL);
472 vgl->CompileShader( vgl->shader[2] );
474 /* Create 'dummy' shader that handles subpicture overlay for now*/
475 vgl->shader[1] = vgl->CreateShader( GL_FRAGMENT_SHADER );
476 vgl->ShaderSource( vgl->shader[1], 1, &helloShader, NULL);
477 vgl->CompileShader( vgl->shader[1] );
478 vgl->program[1] = vgl->CreateProgram();
479 vgl->AttachShader( vgl->program[1], vgl->shader[1]);
480 vgl->AttachShader( vgl->program[1], vgl->shader[2]);
481 vgl->LinkProgram( vgl->program[1] );
483 // Create shader from code
484 vgl->shader[0] = vgl->CreateShader( GL_FRAGMENT_SHADER );
485 vgl->program[0] = vgl->CreateProgram();
488 vgl->ShaderSource( vgl->shader[0], 1, (const GLchar **)&code, NULL );
489 vgl->CompileShader( vgl->shader[0]);
490 vgl->AttachShader( vgl->program[0], vgl->shader[0] );
492 /* Use simpler shader if we don't need to to yuv -> rgb,
493 for example when input is allready rgb (.bmp image).*/
494 vgl->AttachShader( vgl->program[0], vgl->shader[1] );
496 vgl->AttachShader( vgl->program[0], vgl->shader[2]);
498 vgl->LinkProgram( vgl->program[0] );
501 for( GLuint i = 0; i < 2; i++ )
504 int charsWritten = 0;
506 vgl->GetProgramiv( vgl->program[i], GL_INFO_LOG_LENGTH, &infoLength );
509 /* If there is some message, better to check linking is ok */
510 GLint link_status = GL_TRUE;
511 vgl->GetProgramiv( vgl->program[i], GL_LINK_STATUS, &link_status );
513 infolog = (char *)malloc(infoLength);
514 vgl->GetProgramInfoLog( vgl->program[i], infoLength, &charsWritten, infolog );
515 fprintf(stderr, "shader program %d:%s %d\n",i,infolog,infoLength);
518 /* Check shaders messages too */
519 for( GLuint j = 0; j < 2; j++ )
521 vgl->GetShaderiv( vgl->shader[j], GL_INFO_LOG_LENGTH, &infoLength );
524 infolog = (char *)malloc(infoLength);
525 vgl->GetShaderInfoLog( vgl->shader[j], infoLength, &charsWritten, infolog );
526 fprintf(stderr, "shader %d: %s\n",j,infolog );
531 if( link_status == GL_FALSE )
533 fprintf( stderr, "Unable to use program %d\n", i );
543 glDisable(GL_DEPTH_TEST);
544 glDepthMask(GL_FALSE);
545 glDisable(GL_CULL_FACE);
546 glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
547 glClear(GL_COLOR_BUFFER_BIT);
549 vlc_gl_Unlock(vgl->gl);
552 for (int i = 0; i < VLCGL_TEXTURE_COUNT; i++) {
553 for (int j = 0; j < PICTURE_PLANE_MAX; j++)
554 vgl->texture[i][j] = 0;
556 vgl->region_count = 0;
561 if (subpicture_chromas) {
562 *subpicture_chromas = gl_subpicture_chromas;
567 void vout_display_opengl_Delete(vout_display_opengl_t *vgl)
570 if (!vlc_gl_Lock(vgl->gl)) {
574 for (int i = 0; i < VLCGL_TEXTURE_COUNT; i++)
575 glDeleteTextures(vgl->chroma->plane_count, vgl->texture[i]);
576 for (int i = 0; i < vgl->region_count; i++) {
577 if (vgl->region[i].texture)
578 glDeleteTextures(1, &vgl->region[i].texture);
584 for( int i = 0; i < 2; i++ )
585 vgl->DeleteProgram( vgl->program[i] );
586 for( int i = 0; i < 3; i++ )
587 vgl->DeleteShader( vgl->shader[i] );
590 vlc_gl_Unlock(vgl->gl);
593 picture_pool_Delete(vgl->pool);
597 picture_pool_t *vout_display_opengl_GetPool(vout_display_opengl_t *vgl, unsigned requested_count)
602 /* Allocate our pictures */
603 picture_t *picture[VLCGL_PICTURE_MAX] = {NULL, };
606 for (count = 0; count < __MIN(VLCGL_PICTURE_MAX, requested_count); count++) {
607 picture[count] = picture_NewFromFormat(&vgl->fmt);
614 /* Wrap the pictures into a pool */
615 picture_pool_configuration_t cfg;
616 memset(&cfg, 0, sizeof(cfg));
617 cfg.picture_count = count;
618 cfg.picture = picture;
619 vgl->pool = picture_pool_NewExtended(&cfg);
623 /* Allocates our textures */
624 if (vlc_gl_Lock(vgl->gl))
627 for (int i = 0; i < VLCGL_TEXTURE_COUNT; i++) {
628 glGenTextures(vgl->chroma->plane_count, vgl->texture[i]);
629 for (unsigned j = 0; j < vgl->chroma->plane_count; j++) {
630 if (vgl->use_multitexture)
632 vgl->ActiveTexture(GL_TEXTURE0 + j);
633 vgl->ClientActiveTexture(GL_TEXTURE0 + j);
635 glBindTexture(vgl->tex_target, vgl->texture[i][j]);
638 /* Set the texture parameters */
639 glTexParameterf(vgl->tex_target, GL_TEXTURE_PRIORITY, 1.0);
640 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
643 glTexParameteri(vgl->tex_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
644 glTexParameteri(vgl->tex_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
645 glTexParameteri(vgl->tex_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
646 glTexParameteri(vgl->tex_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
648 /* Call glTexImage2D only once, and use glTexSubImage2D later */
649 glTexImage2D(vgl->tex_target, 0,
650 vgl->tex_internal, vgl->tex_width[j], vgl->tex_height[j],
651 0, vgl->tex_format, vgl->tex_type, NULL);
655 vlc_gl_Unlock(vgl->gl);
660 for (unsigned i = 0; i < count; i++)
661 picture_Release(picture[i]);
665 int vout_display_opengl_Prepare(vout_display_opengl_t *vgl,
666 picture_t *picture, subpicture_t *subpicture)
668 /* On Win32/GLX, we do this the usual way:
669 + Fill the buffer with new content,
670 + Reload the texture,
673 On OS X with VRAM or AGP texturing, the order has to be:
674 + Reload the texture,
675 + Fill the buffer with new content,
678 (Thanks to gcc from the Arstechnica forums for the tip)
680 Therefore on OSX, we have to use two buffers and textures and use a
681 lock(/unlock) managed picture pool.
684 if (vlc_gl_Lock(vgl->gl))
687 /* Update the texture */
688 for (unsigned j = 0; j < vgl->chroma->plane_count; j++) {
689 if (vgl->use_multitexture)
691 vgl->ActiveTexture(GL_TEXTURE0 + j);
692 vgl->ClientActiveTexture(GL_TEXTURE0 + j);
694 glBindTexture(vgl->tex_target, vgl->texture[0][j]);
695 glPixelStorei(GL_UNPACK_ROW_LENGTH, picture->p[j].i_pitch / picture->p[j].i_pixel_pitch);
696 glTexSubImage2D(vgl->tex_target, 0,
698 vgl->fmt.i_width * vgl->chroma->p[j].w.num / vgl->chroma->p[j].w.den,
699 vgl->fmt.i_height * vgl->chroma->p[j].h.num / vgl->chroma->p[j].h.den,
700 vgl->tex_format, vgl->tex_type, picture->p[j].p_pixels);
703 int last_count = vgl->region_count;
704 gl_region_t *last = vgl->region;
706 vgl->region_count = 0;
712 for (subpicture_region_t *r = subpicture->p_region; r; r = r->p_next)
715 vgl->region_count = count;
716 vgl->region = calloc(count, sizeof(*vgl->region));
718 if (vgl->use_multitexture)
720 vgl->ActiveTexture(GL_TEXTURE0 + 0);
721 vgl->ClientActiveTexture(GL_TEXTURE0 + 0);
724 for (subpicture_region_t *r = subpicture->p_region; r; r = r->p_next, i++) {
725 gl_region_t *glr = &vgl->region[i];
727 glr->format = GL_RGBA;
728 glr->type = GL_UNSIGNED_BYTE;
729 glr->width = r->fmt.i_visible_width;
730 glr->height = r->fmt.i_visible_height;
731 if(!vgl->supports_npot )
733 glr->width = GetAlignedSize( glr->width );
734 glr->height = GetAlignedSize( glr->height );
736 glr->alpha = (float)subpicture->i_alpha * r->i_alpha / 255 / 255;
737 glr->left = 2.0 * (r->i_x ) / subpicture->i_original_picture_width - 1.0;
738 glr->top = -2.0 * (r->i_y ) / subpicture->i_original_picture_height + 1.0;
739 glr->right = 2.0 * (r->i_x + r->fmt.i_visible_width ) / subpicture->i_original_picture_width - 1.0;
740 glr->bottom = -2.0 * (r->i_y + r->fmt.i_visible_height) / subpicture->i_original_picture_height + 1.0;
743 for (int j = 0; j < last_count; j++) {
744 if (last[j].texture &&
745 last[j].width == glr->width &&
746 last[j].height == glr->height &&
747 last[j].format == glr->format &&
748 last[j].type == glr->type) {
749 glr->texture = last[j].texture;
750 memset(&last[j], 0, sizeof(last[j]));
755 const int pixels_offset = r->fmt.i_y_offset * r->p_picture->p->i_pitch +
756 r->fmt.i_x_offset * r->p_picture->p->i_pixel_pitch;
758 glBindTexture(GL_TEXTURE_2D, glr->texture);
759 /* TODO set GL_UNPACK_ALIGNMENT */
760 glPixelStorei(GL_UNPACK_ROW_LENGTH, r->p_picture->p->i_pitch / r->p_picture->p->i_pixel_pitch);
761 glTexSubImage2D(GL_TEXTURE_2D, 0,
762 0, 0, glr->width, glr->height,
763 glr->format, glr->type, &r->p_picture->p->p_pixels[pixels_offset]);
765 glGenTextures(1, &glr->texture);
766 glBindTexture(GL_TEXTURE_2D, glr->texture);
768 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_PRIORITY, 1.0);
769 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
771 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
772 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
773 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
774 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
775 /* TODO set GL_UNPACK_ALIGNMENT */
776 glPixelStorei(GL_UNPACK_ROW_LENGTH, r->p_picture->p->i_pitch / r->p_picture->p->i_pixel_pitch);
777 glTexImage2D(GL_TEXTURE_2D, 0, glr->format,
778 glr->width, glr->height, 0, glr->format, glr->type,
779 &r->p_picture->p->p_pixels[pixels_offset]);
783 for (int i = 0; i < last_count; i++) {
785 glDeleteTextures(1, &last[i].texture);
789 vlc_gl_Unlock(vgl->gl);
790 VLC_UNUSED(subpicture);
794 static void draw_without_shaders( vout_display_opengl_t *vgl, float *left, float *top, float *right, float *bottom )
796 static const GLfloat vertexCoord[] = {
803 const GLfloat textureCoord[8] = {
810 for (unsigned j = 0; j < vgl->chroma->plane_count; j++) {
811 vgl->ActiveTexture( GL_TEXTURE0 + j );
812 vgl->ClientActiveTexture( GL_TEXTURE0 + j );
814 glEnableClientState(GL_VERTEX_ARRAY);
815 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
817 glEnable(vgl->tex_target);
819 glBindTexture(vgl->tex_target, vgl->texture[0][j]);
820 glTexCoordPointer(2, GL_FLOAT, 0, textureCoord);
822 vgl->ActiveTexture( GL_TEXTURE0 );
823 vgl->ClientActiveTexture( GL_TEXTURE0 );
825 glVertexPointer(2, GL_FLOAT, 0, vertexCoord);
827 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
829 for (unsigned j = 0; j < vgl->chroma->plane_count; j++) {
830 vgl->ActiveTexture( GL_TEXTURE0 + j );
831 vgl->ClientActiveTexture( GL_TEXTURE0 + j );
832 glDisable(vgl->tex_target);
833 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
834 glDisableClientState(GL_VERTEX_ARRAY);
836 vgl->ActiveTexture( GL_TEXTURE0 );
837 vgl->ClientActiveTexture( GL_TEXTURE0 );
840 static void draw_with_shaders( vout_display_opengl_t *vgl, float *left, float *top, float *right, float *bottom )
843 const GLfloat vertexCoord[] = {
850 for( unsigned j = 0; j < vgl->chroma->plane_count; j++)
852 char *attribute = NULL;
853 const GLfloat texCoord[] = {
859 vgl->ActiveTexture( GL_TEXTURE0+j);
860 vgl->ClientActiveTexture( GL_TEXTURE0+j);
861 glEnable(vgl->tex_target);
862 glBindTexture(vgl->tex_target, vgl->texture[0][j]);
863 if(asprintf( &attribute, "MultiTexCoord%1d", j ) == -1 )
866 vgl->EnableVertexAttribArray( vgl->GetAttribLocation(vgl->program[0], attribute ) );
867 vgl->VertexAttribPointer( vgl->GetAttribLocation( vgl->program[0], attribute ), 2, GL_FLOAT, 0, 0, texCoord);
871 vgl->ActiveTexture(GL_TEXTURE0 + 0);
872 vgl->ClientActiveTexture(GL_TEXTURE0 + 0);
873 vgl->EnableVertexAttribArray( vgl->GetAttribLocation( vgl->program[0], "vertex_position"));
874 vgl->VertexAttribPointer( vgl->GetAttribLocation( vgl->program[0], "vertex_position"), 2, GL_FLOAT, 0, 0, vertexCoord);
876 glDrawArrays( GL_TRIANGLE_STRIP, 0, 4);
879 int vout_display_opengl_Display(vout_display_opengl_t *vgl,
880 const video_format_t *source)
882 if (vlc_gl_Lock(vgl->gl))
885 /* glTexCoord works differently with GL_TEXTURE_2D and
886 GL_TEXTURE_RECTANGLE_EXT */
887 float left[PICTURE_PLANE_MAX];
888 float top[PICTURE_PLANE_MAX];
889 float right[PICTURE_PLANE_MAX];
890 float bottom[PICTURE_PLANE_MAX];
891 for (unsigned j = 0; j < vgl->chroma->plane_count; j++) {
892 float scale_w, scale_h;
893 if (vgl->tex_target == GL_TEXTURE_2D) {
894 scale_w = (float)vgl->chroma->p[j].w.num / vgl->chroma->p[j].w.den / vgl->tex_width[j];
895 scale_h = (float)vgl->chroma->p[j].h.num / vgl->chroma->p[j].h.den / vgl->tex_height[j];
901 left[j] = (source->i_x_offset + 0 ) * scale_w;
902 top[j] = (source->i_y_offset + 0 ) * scale_h;
903 right[j] = (source->i_x_offset + source->i_visible_width ) * scale_w;
904 bottom[j] = (source->i_y_offset + source->i_visible_height) * scale_h;
908 /* Why drawing here and not in Render()? Because this way, the
909 OpenGL providers can call vout_display_opengl_Display to force redraw.i
910 Currently, the OS X provider uses it to get a smooth window resizing */
912 glClear(GL_COLOR_BUFFER_BIT);
915 if( vgl->program[0] )
917 vgl->UseProgram(vgl->program[0]);
918 vgl->Uniform4fv( vgl->GetUniformLocation( vgl->program[0], "coefficient" ), 4, vgl->local_value);
919 vgl->Uniform1i( vgl->GetUniformLocation( vgl->program[0], "Texture[0]" ), 0);
920 vgl->Uniform1i( vgl->GetUniformLocation( vgl->program[0], "Texture[1]" ), 1);
921 vgl->Uniform1i( vgl->GetUniformLocation( vgl->program[0], "Texture[2]" ), 2);
922 draw_with_shaders( vgl, left, top ,right, bottom );
923 // Change the program for overlays
924 vgl->UseProgram(vgl->program[1]);
925 vgl->Uniform1i( vgl->GetUniformLocation( vgl->program[1], "Texture[0]" ), 0);
927 draw_without_shaders( vgl, left, top, right, bottom );
930 vgl->ActiveTexture(GL_TEXTURE0 + 0);
931 vgl->ClientActiveTexture(GL_TEXTURE0 + 0);
932 glEnable(GL_TEXTURE_2D);
934 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
936 for (int i = 0; i < vgl->region_count; i++) {
937 gl_region_t *glr = &vgl->region[i];
938 const GLfloat vertexCoord[] = {
940 glr->left, glr->bottom,
941 glr->right, glr->top,
942 glr->right,glr->bottom,
944 static const GLfloat textureCoord[] = {
951 glBindTexture(GL_TEXTURE_2D, glr->texture);
952 if( vgl->program[0] )
954 vgl->Uniform4f( vgl->GetUniformLocation( vgl->program[1], "fillColor"), 1.0f, 1.0f, 1.0f, glr->alpha);
955 vgl->EnableVertexAttribArray( vgl->GetAttribLocation( vgl->program[1], "MultiTexCoord0") );
956 vgl->VertexAttribPointer( vgl->GetAttribLocation( vgl->program[1], "MultiTexCoord0"), 2, GL_FLOAT, 0, 0, textureCoord);
957 vgl->EnableVertexAttribArray( vgl->GetAttribLocation( vgl->program[1], "vertex_position"));
958 vgl->VertexAttribPointer( vgl->GetAttribLocation( vgl->program[1], "vertex_position"), 2, GL_FLOAT, 0, 0, vertexCoord);
962 glEnableClientState(GL_VERTEX_ARRAY);
963 glColor4f( 1.0f, 1.0f, 1.0f, glr->alpha );
964 glEnable(GL_TEXTURE_COORD_ARRAY);
965 glEnable(GL_VERTEX_ARRAY);
966 glTexCoordPointer(2, GL_FLOAT, 0, textureCoord);
967 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
968 glVertexPointer(2, GL_FLOAT, 0, vertexCoord);
971 glDrawArrays( GL_TRIANGLE_STRIP, 0, 4 );
973 if( !vgl->program[0] )
975 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
976 glDisableClientState(GL_VERTEX_ARRAY);
980 glDisable(GL_TEXTURE_2D);
982 vlc_gl_Swap(vgl->gl);
984 vlc_gl_Unlock(vgl->gl);