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 PFNGLVERTEXATTRIBPOINTERPROC 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)
198 glGenTextures(1, &texture);
199 glBindTexture(target, texture);
200 glTexImage2D(target, 0, GL_LUMINANCE16,
201 64, 64, 0, GL_LUMINANCE, GL_UNSIGNED_SHORT, NULL);
203 glGetTexLevelParameteriv(target, 0, GL_TEXTURE_LUMINANCE_SIZE, &size);
205 glDeleteTextures(1, &texture);
211 vout_display_opengl_t *vout_display_opengl_New(video_format_t *fmt,
212 const vlc_fourcc_t **subpicture_chromas,
215 vout_display_opengl_t *vgl = calloc(1, sizeof(*vgl));
220 if (vlc_gl_Lock(vgl->gl)) {
225 if( vgl->gl->getProcAddress == NULL )
227 fprintf(stderr, "getProcAddress not implemented, bailing out\n");
232 const char *extensions = (const char *)glGetString(GL_EXTENSIONS);
234 const unsigned char *ogl_version = glGetString(GL_VERSION);
235 bool supports_shaders = strverscmp((const char *)ogl_version, "2.0") >= 0;
237 bool supports_shaders = false;
239 if( kCFCoreFoundationVersionNumber >= 786. )
240 supports_shaders = true;
244 GLint max_texture_units = 0;
245 glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &max_texture_units);
247 /* Initialize with default chroma */
249 vgl->fmt.i_chroma = VLC_CODEC_RGB32;
250 # if defined(WORDS_BIGENDIAN)
251 vgl->fmt.i_rmask = 0xff000000;
252 vgl->fmt.i_gmask = 0x00ff0000;
253 vgl->fmt.i_bmask = 0x0000ff00;
255 vgl->fmt.i_rmask = 0x000000ff;
256 vgl->fmt.i_gmask = 0x0000ff00;
257 vgl->fmt.i_bmask = 0x00ff0000;
259 vgl->tex_target = GL_TEXTURE_2D;
260 vgl->tex_format = GL_RGBA;
261 vgl->tex_internal = GL_RGBA;
262 vgl->tex_type = GL_UNSIGNED_BYTE;
263 /* Use YUV if possible and needed */
264 bool need_fs_yuv = false;
265 float yuv_range_correction = 1.0;
266 if ( max_texture_units >= 3 && supports_shaders &&
267 vlc_fourcc_IsYUV(fmt->i_chroma) && !vlc_fourcc_IsYUV(vgl->fmt.i_chroma)) {
268 const vlc_fourcc_t *list = vlc_fourcc_GetYUVFallback(fmt->i_chroma);
270 const vlc_chroma_description_t *dsc = vlc_fourcc_GetChromaDescription(*list);
271 if (dsc && dsc->plane_count == 3 && dsc->pixel_size == 1) {
274 vgl->fmt.i_chroma = *list;
275 vgl->tex_format = GL_LUMINANCE;
276 vgl->tex_internal = GL_LUMINANCE;
277 vgl->tex_type = GL_UNSIGNED_BYTE;
278 yuv_range_correction = 1.0;
281 } else if (dsc && dsc->plane_count == 3 && dsc->pixel_size == 2 &&
282 IsLuminance16Supported(vgl->tex_target)) {
285 vgl->fmt.i_chroma = *list;
286 vgl->tex_format = GL_LUMINANCE;
287 vgl->tex_internal = GL_LUMINANCE16;
288 vgl->tex_type = GL_UNSIGNED_SHORT;
289 yuv_range_correction = (float)((1 << 16) - 1) / ((1 << dsc->pixel_bits) - 1);
297 vgl->GenBuffers = (PFNGLGENBUFFERSPROC)vlc_gl_GetProcAddress(vgl->gl, "glGenBuffers");
298 vgl->BindBuffer = (PFNGLBINDBUFFERPROC)vlc_gl_GetProcAddress(vgl->gl, "glBindBuffer");
299 vgl->BufferData = (PFNGLBUFFERDATAPROC)vlc_gl_GetProcAddress(vgl->gl, "glBufferData");
300 vgl->BufferSubData = (PFNGLBUFFERSUBDATAPROC)vlc_gl_GetProcAddress(vgl->gl, "glBufferSubData");
301 vgl->DeleteBuffers = (PFNGLDELETEBUFFERSPROC)vlc_gl_GetProcAddress(vgl->gl, "glDeleteBuffers");
303 vgl->CreateShader = (PFNGLCREATESHADERPROC)vlc_gl_GetProcAddress(vgl->gl, "glCreateShader");
304 vgl->ShaderSource = (PFNGLSHADERSOURCEPROC)vlc_gl_GetProcAddress(vgl->gl, "glShaderSource");
305 vgl->CompileShader = (PFNGLCOMPILESHADERPROC)vlc_gl_GetProcAddress(vgl->gl, "glCompileShader");
306 vgl->AttachShader = (PFNGLATTACHSHADERPROC)vlc_gl_GetProcAddress(vgl->gl, "glAttachShader");
308 vgl->GetProgramiv = (PFNGLGETPROGRAMIVPROC)vlc_gl_GetProcAddress(vgl->gl, "glGetProgramiv");
309 vgl->GetShaderiv = (PFNGLGETSHADERIVPROC)vlc_gl_GetProcAddress(vgl->gl, "glGetShaderiv");
310 vgl->GetProgramInfoLog = (PFNGLGETPROGRAMINFOLOGPROC)vlc_gl_GetProcAddress(vgl->gl, "glGetProgramInfoLog");
311 vgl->GetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC)vlc_gl_GetProcAddress(vgl->gl, "glGetShaderInfoLog");
313 vgl->DetachShader = (PFNGLDETACHSHADERPROC)vlc_gl_GetProcAddress(vgl->gl, "glDetachShader");
314 vgl->DeleteShader = (PFNGLDELETESHADERPROC)vlc_gl_GetProcAddress(vgl->gl, "glDeleteShader");
316 vgl->GetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC)vlc_gl_GetProcAddress(vgl->gl, "glGetUniformLocation");
317 vgl->GetAttribLocation = (PFNGLGETATTRIBLOCATIONPROC)vlc_gl_GetProcAddress(vgl->gl, "glGetAttribLocation");
318 vgl->VertexAttribPointer= (PFNGLVERTEXATTRIBPOINTERPROC)vlc_gl_GetProcAddress(vgl->gl, "glVertexAttribPointer");
319 vgl->EnableVertexAttribArray = (PFNGLENABLEVERTEXATTRIBARRAYPROC)vlc_gl_GetProcAddress(vgl->gl, "glEnableVertexAttribArray");
320 vgl->Uniform4fv = (PFNGLUNIFORM4FVPROC)vlc_gl_GetProcAddress(vgl->gl,"glUniform4fv");
321 vgl->Uniform4f = (PFNGLUNIFORM4FPROC)vlc_gl_GetProcAddress(vgl->gl,"glUniform4f");
322 vgl->Uniform3i = (PFNGLUNIFORM3IPROC)vlc_gl_GetProcAddress(vgl->gl,"glUniform3i");
323 vgl->Uniform1i = (PFNGLUNIFORM1IPROC)vlc_gl_GetProcAddress(vgl->gl,"glUniform1i");
325 vgl->CreateProgram = (PFNGLCREATEPROGRAMPROC)vlc_gl_GetProcAddress(vgl->gl, "glCreateProgram");
326 vgl->LinkProgram = (PFNGLLINKPROGRAMPROC)vlc_gl_GetProcAddress(vgl->gl, "glLinkProgram");
327 vgl->UseProgram = (PFNGLUSEPROGRAMPROC)vlc_gl_GetProcAddress(vgl->gl, "glUseProgram");
328 vgl->DeleteProgram = (PFNGLDELETEPROGRAMPROC)vlc_gl_GetProcAddress(vgl->gl, "glDeleteProgram");
329 vgl->ActiveTexture = (PFNGLACTIVETEXTUREPROC)vlc_gl_GetProcAddress(vgl->gl, "glActiveTexture");
330 vgl->ClientActiveTexture = (PFNGLCLIENTACTIVETEXTUREPROC)vlc_gl_GetProcAddress(vgl->gl, "glClientActiveTexture");
332 vgl->chroma = vlc_fourcc_GetChromaDescription(vgl->fmt.i_chroma);
333 vgl->use_multitexture = vgl->chroma->plane_count > 1;
334 vgl->supports_npot = HasExtension( extensions, "GL_ARB_texture_non_power_of_two" ) ||
335 HasExtension( extensions, "GL_APPLE_texture_2D_limited_npot" );
337 if( !vgl->CreateShader || !vgl->ShaderSource || !vgl->CreateProgram )
339 fprintf(stderr, "Looks like you don't have all the opengl we need. Driver is %s, giving up\n", glGetString(GL_VERSION));
346 for (unsigned j = 0; j < vgl->chroma->plane_count; j++) {
347 int w = vgl->fmt.i_width * vgl->chroma->p[j].w.num / vgl->chroma->p[j].w.den;
348 int h = vgl->fmt.i_height * vgl->chroma->p[j].h.num / vgl->chroma->p[j].h.den;
349 if( vgl->supports_npot )
351 vgl->tex_width[j] = w;
352 vgl->tex_height[j] = h;
354 vgl->tex_width[j] = GetAlignedSize(w);
355 vgl->tex_height[j] = GetAlignedSize(h);
359 /* Build fragment program if needed */
362 vgl->local_count = 0;
363 vgl->shader[0] = vgl->shader[1] = vgl->shader[2] = -1;
364 if (supports_shaders) {
367 /* [R/G/B][Y U V O] from TV range to full range
368 * XXX we could also do hue/brightness/constrast/gamma
369 * by simply changing the coefficients
371 const float matrix_bt601_tv2full[12] = {
372 1.164383561643836, 0.0000, 1.596026785714286, -0.874202217873451 ,
373 1.164383561643836, -0.391762290094914, -0.812967647237771, 0.531667823499146 ,
374 1.164383561643836, 2.017232142857142, 0.0000, -1.085630789302022 ,
376 const float matrix_bt709_tv2full[12] = {
377 1.164383561643836, 0.0000, 1.792741071428571, -0.972945075016308 ,
378 1.164383561643836, -0.21324861427373, -0.532909328559444, 0.301482665475862 ,
379 1.164383561643836, 2.112401785714286, 0.0000, -1.133402217873451 ,
381 const float (*matrix) = fmt->i_height > 576 ? matrix_bt709_tv2full
382 : matrix_bt601_tv2full;
384 /* Basic linear YUV -> RGB conversion using bilinear interpolation */
385 const char *template_glsl_yuv =
387 "uniform sampler2D Texture[3];"
388 "uniform vec4 coefficient[4];"
389 "varying vec4 TexCoord0,TexCoord1,TexCoord2;"
392 " vec4 x,y,z,result;"
393 " x = texture2D(Texture[0], TexCoord0.st);"
394 " %c = texture2D(Texture[1], TexCoord1.st);"
395 " %c = texture2D(Texture[2], TexCoord2.st);"
397 " result = x * coefficient[0] + coefficient[3];"
398 " result = (y * coefficient[1]) + result;"
399 " result = (z * coefficient[2]) + result;"
400 " gl_FragColor = result;"
402 bool swap_uv = vgl->fmt.i_chroma == VLC_CODEC_YV12 ||
403 vgl->fmt.i_chroma == VLC_CODEC_YV9;
404 if (asprintf(&code, template_glsl_yuv,
406 swap_uv ? 'y' : 'z') < 0)
409 for (int i = 0; i < 4; i++) {
410 float correction = i < 3 ? yuv_range_correction : 1.0;
411 /* We place coefficient values for coefficient[4] in one array from matrix values.
412 Notice that we fill values from top down instead of left to right.*/
413 for( int j = 0; j < 4; j++ )
414 vgl->local_value[vgl->local_count + i*4+j] = j < 3 ? correction * matrix[j*4+i] : 0.0 ;
416 vgl->local_count += 4;
418 // Basic vertex shader that we use in both cases
419 const char *vertexShader =
421 "varying vec4 TexCoord0,TexCoord1, TexCoord2;"
422 "attribute vec4 MultiTexCoord0,MultiTexCoord1,MultiTexCoord2;"
423 "attribute vec4 vertex_position;"
425 " TexCoord0 = MultiTexCoord0;"
426 " TexCoord1 = MultiTexCoord1;"
427 " TexCoord2 = MultiTexCoord2;"
428 " gl_Position = vertex_position; }";
430 // Dummy shader for text overlay
431 const char *helloShader =
433 "uniform sampler2D Texture[3];"
434 "uniform vec4 fillColor;"
435 "varying vec4 TexCoord0,TexCoord1,TexCoord2;"
438 " gl_FragColor = texture2D(Texture[0], TexCoord0.st)*fillColor;}";
440 vgl->shader[2] = vgl->CreateShader( GL_VERTEX_SHADER );
441 vgl->ShaderSource( vgl->shader[2], 1, (const GLchar **)&vertexShader, NULL);
442 vgl->CompileShader( vgl->shader[2] );
444 /* Create 'dummy' shader that handles subpicture overlay for now*/
445 vgl->shader[1] = vgl->CreateShader( GL_FRAGMENT_SHADER );
446 vgl->ShaderSource( vgl->shader[1], 1, &helloShader, NULL);
447 vgl->CompileShader( vgl->shader[1] );
448 vgl->program[1] = vgl->CreateProgram();
449 vgl->AttachShader( vgl->program[1], vgl->shader[1]);
450 vgl->AttachShader( vgl->program[1], vgl->shader[2]);
451 vgl->LinkProgram( vgl->program[1] );
453 // Create shader from code
454 vgl->shader[0] = vgl->CreateShader( GL_FRAGMENT_SHADER );
455 vgl->program[0] = vgl->CreateProgram();
458 vgl->ShaderSource( vgl->shader[0], 1, (const GLchar **)&code, NULL );
459 vgl->CompileShader( vgl->shader[0]);
460 vgl->AttachShader( vgl->program[0], vgl->shader[0] );
462 /* Use simpler shader if we don't need to to yuv -> rgb,
463 for example when input is allready rgb (.bmp image).*/
464 vgl->AttachShader( vgl->program[0], vgl->shader[1] );
466 vgl->AttachShader( vgl->program[0], vgl->shader[2]);
468 vgl->LinkProgram( vgl->program[0] );
471 for( GLuint i = 0; i < 2; i++ )
474 int charsWritten = 0;
476 vgl->GetProgramiv( vgl->program[i], GL_INFO_LOG_LENGTH, &infoLength );
479 /* If there is some message, better to check linking is ok */
480 GLint link_status = GL_TRUE;
481 vgl->GetProgramiv( vgl->program[i], GL_LINK_STATUS, &link_status );
483 infolog = (char *)malloc(infoLength);
484 vgl->GetProgramInfoLog( vgl->program[i], infoLength, &charsWritten, infolog );
485 fprintf(stderr, "shader program %d:%s %d\n",i,infolog,infoLength);
488 /* Check shaders messages too */
489 for( GLuint j = 0; j < 2; j++ )
491 vgl->GetShaderiv( vgl->shader[j], GL_INFO_LOG_LENGTH, &infoLength );
494 infolog = (char *)malloc(infoLength);
495 vgl->GetShaderInfoLog( vgl->shader[j], infoLength, &charsWritten, infolog );
496 fprintf(stderr, "shader %d: %s\n",j,infolog );
501 if( link_status == GL_FALSE )
503 fprintf( stderr, "Unable to use program %d\n", i );
513 glDisable(GL_DEPTH_TEST);
514 glDepthMask(GL_FALSE);
515 glDisable(GL_CULL_FACE);
516 glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
517 glClear(GL_COLOR_BUFFER_BIT);
519 vlc_gl_Unlock(vgl->gl);
522 for (int i = 0; i < VLCGL_TEXTURE_COUNT; i++) {
523 for (int j = 0; j < PICTURE_PLANE_MAX; j++)
524 vgl->texture[i][j] = 0;
526 vgl->region_count = 0;
531 if (subpicture_chromas) {
532 *subpicture_chromas = gl_subpicture_chromas;
537 void vout_display_opengl_Delete(vout_display_opengl_t *vgl)
540 if (!vlc_gl_Lock(vgl->gl)) {
544 for (int i = 0; i < VLCGL_TEXTURE_COUNT; i++)
545 glDeleteTextures(vgl->chroma->plane_count, vgl->texture[i]);
546 for (int i = 0; i < vgl->region_count; i++) {
547 if (vgl->region[i].texture)
548 glDeleteTextures(1, &vgl->region[i].texture);
554 for( int i = 0; i < 2; i++ )
555 vgl->DeleteProgram( vgl->program[i] );
556 for( int i = 0; i < 3; i++ )
557 vgl->DeleteShader( vgl->shader[i] );
560 vlc_gl_Unlock(vgl->gl);
563 picture_pool_Delete(vgl->pool);
567 picture_pool_t *vout_display_opengl_GetPool(vout_display_opengl_t *vgl, unsigned requested_count)
572 /* Allocate our pictures */
573 picture_t *picture[VLCGL_PICTURE_MAX] = {NULL, };
576 for (count = 0; count < __MIN(VLCGL_PICTURE_MAX, requested_count); count++) {
577 picture[count] = picture_NewFromFormat(&vgl->fmt);
584 /* Wrap the pictures into a pool */
585 picture_pool_configuration_t cfg;
586 memset(&cfg, 0, sizeof(cfg));
587 cfg.picture_count = count;
588 cfg.picture = picture;
589 vgl->pool = picture_pool_NewExtended(&cfg);
593 /* Allocates our textures */
594 if (vlc_gl_Lock(vgl->gl))
597 for (int i = 0; i < VLCGL_TEXTURE_COUNT; i++) {
598 glGenTextures(vgl->chroma->plane_count, vgl->texture[i]);
599 for (unsigned j = 0; j < vgl->chroma->plane_count; j++) {
600 if (vgl->use_multitexture)
602 vgl->ActiveTexture(GL_TEXTURE0 + j);
603 vgl->ClientActiveTexture(GL_TEXTURE0 + j);
605 glBindTexture(vgl->tex_target, vgl->texture[i][j]);
608 /* Set the texture parameters */
609 glTexParameterf(vgl->tex_target, GL_TEXTURE_PRIORITY, 1.0);
610 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
613 glTexParameteri(vgl->tex_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
614 glTexParameteri(vgl->tex_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
615 glTexParameteri(vgl->tex_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
616 glTexParameteri(vgl->tex_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
618 /* Call glTexImage2D only once, and use glTexSubImage2D later */
619 glTexImage2D(vgl->tex_target, 0,
620 vgl->tex_internal, vgl->tex_width[j], vgl->tex_height[j],
621 0, vgl->tex_format, vgl->tex_type, NULL);
625 vlc_gl_Unlock(vgl->gl);
630 for (unsigned i = 0; i < count; i++)
631 picture_Release(picture[i]);
635 int vout_display_opengl_Prepare(vout_display_opengl_t *vgl,
636 picture_t *picture, subpicture_t *subpicture)
638 /* On Win32/GLX, we do this the usual way:
639 + Fill the buffer with new content,
640 + Reload the texture,
643 On OS X with VRAM or AGP texturing, the order has to be:
644 + Reload the texture,
645 + Fill the buffer with new content,
648 (Thanks to gcc from the Arstechnica forums for the tip)
650 Therefore on OSX, we have to use two buffers and textures and use a
651 lock(/unlock) managed picture pool.
654 if (vlc_gl_Lock(vgl->gl))
657 /* Update the texture */
658 for (unsigned j = 0; j < vgl->chroma->plane_count; j++) {
659 if (vgl->use_multitexture)
661 vgl->ActiveTexture(GL_TEXTURE0 + j);
662 vgl->ClientActiveTexture(GL_TEXTURE0 + j);
664 glBindTexture(vgl->tex_target, vgl->texture[0][j]);
665 glPixelStorei(GL_UNPACK_ROW_LENGTH, picture->p[j].i_pitch / picture->p[j].i_pixel_pitch);
666 glTexSubImage2D(vgl->tex_target, 0,
668 vgl->fmt.i_width * vgl->chroma->p[j].w.num / vgl->chroma->p[j].w.den,
669 vgl->fmt.i_height * vgl->chroma->p[j].h.num / vgl->chroma->p[j].h.den,
670 vgl->tex_format, vgl->tex_type, picture->p[j].p_pixels);
673 int last_count = vgl->region_count;
674 gl_region_t *last = vgl->region;
676 vgl->region_count = 0;
682 for (subpicture_region_t *r = subpicture->p_region; r; r = r->p_next)
685 vgl->region_count = count;
686 vgl->region = calloc(count, sizeof(*vgl->region));
688 if (vgl->use_multitexture)
690 vgl->ActiveTexture(GL_TEXTURE0 + 0);
691 vgl->ClientActiveTexture(GL_TEXTURE0 + 0);
694 for (subpicture_region_t *r = subpicture->p_region; r; r = r->p_next, i++) {
695 gl_region_t *glr = &vgl->region[i];
697 glr->format = GL_RGBA;
698 glr->type = GL_UNSIGNED_BYTE;
699 glr->width = r->fmt.i_visible_width;
700 glr->height = r->fmt.i_visible_height;
701 if(!vgl->supports_npot )
703 glr->width = GetAlignedSize( glr->width );
704 glr->height = GetAlignedSize( glr->height );
706 glr->alpha = (float)subpicture->i_alpha * r->i_alpha / 255 / 255;
707 glr->left = 2.0 * (r->i_x ) / subpicture->i_original_picture_width - 1.0;
708 glr->top = -2.0 * (r->i_y ) / subpicture->i_original_picture_height + 1.0;
709 glr->right = 2.0 * (r->i_x + r->fmt.i_visible_width ) / subpicture->i_original_picture_width - 1.0;
710 glr->bottom = -2.0 * (r->i_y + r->fmt.i_visible_height) / subpicture->i_original_picture_height + 1.0;
713 for (int j = 0; j < last_count; j++) {
714 if (last[j].texture &&
715 last[j].width == glr->width &&
716 last[j].height == glr->height &&
717 last[j].format == glr->format &&
718 last[j].type == glr->type) {
719 glr->texture = last[j].texture;
720 memset(&last[j], 0, sizeof(last[j]));
725 const int pixels_offset = r->fmt.i_y_offset * r->p_picture->p->i_pitch +
726 r->fmt.i_x_offset * r->p_picture->p->i_pixel_pitch;
728 glBindTexture(GL_TEXTURE_2D, glr->texture);
729 /* TODO set GL_UNPACK_ALIGNMENT */
730 glPixelStorei(GL_UNPACK_ROW_LENGTH, r->p_picture->p->i_pitch / r->p_picture->p->i_pixel_pitch);
731 glTexSubImage2D(GL_TEXTURE_2D, 0,
732 0, 0, glr->width, glr->height,
733 glr->format, glr->type, &r->p_picture->p->p_pixels[pixels_offset]);
735 glGenTextures(1, &glr->texture);
736 glBindTexture(GL_TEXTURE_2D, glr->texture);
738 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_PRIORITY, 1.0);
739 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
741 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
742 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
743 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
744 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
745 /* TODO set GL_UNPACK_ALIGNMENT */
746 glPixelStorei(GL_UNPACK_ROW_LENGTH, r->p_picture->p->i_pitch / r->p_picture->p->i_pixel_pitch);
747 glTexImage2D(GL_TEXTURE_2D, 0, glr->format,
748 glr->width, glr->height, 0, glr->format, glr->type,
749 &r->p_picture->p->p_pixels[pixels_offset]);
753 for (int i = 0; i < last_count; i++) {
755 glDeleteTextures(1, &last[i].texture);
759 vlc_gl_Unlock(vgl->gl);
760 VLC_UNUSED(subpicture);
764 static void draw_without_shaders( vout_display_opengl_t *vgl, float *left, float *top, float *right, float *bottom )
766 static const GLfloat vertexCoord[] = {
773 const GLfloat textureCoord[8] = {
780 for (unsigned j = 0; j < vgl->chroma->plane_count; j++) {
781 vgl->ActiveTexture( GL_TEXTURE0 + j );
782 vgl->ClientActiveTexture( GL_TEXTURE0 + j );
784 glEnableClientState(GL_VERTEX_ARRAY);
785 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
787 glEnable(vgl->tex_target);
789 glBindTexture(vgl->tex_target, vgl->texture[0][j]);
790 glTexCoordPointer(2, GL_FLOAT, 0, textureCoord);
792 vgl->ActiveTexture( GL_TEXTURE0 );
793 vgl->ClientActiveTexture( GL_TEXTURE0 );
795 glVertexPointer(2, GL_FLOAT, 0, vertexCoord);
797 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
799 for (unsigned j = 0; j < vgl->chroma->plane_count; j++) {
800 vgl->ActiveTexture( GL_TEXTURE0 + j );
801 vgl->ClientActiveTexture( GL_TEXTURE0 + j );
802 glDisable(vgl->tex_target);
803 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
804 glDisableClientState(GL_VERTEX_ARRAY);
806 vgl->ActiveTexture( GL_TEXTURE0 );
807 vgl->ClientActiveTexture( GL_TEXTURE0 );
810 static void draw_with_shaders( vout_display_opengl_t *vgl, float *left, float *top, float *right, float *bottom )
813 const GLfloat vertexCoord[] = {
820 for( unsigned j = 0; j < vgl->chroma->plane_count; j++)
822 char *attribute = NULL;
823 const GLfloat texCoord[] = {
829 vgl->ActiveTexture( GL_TEXTURE0+j);
830 vgl->ClientActiveTexture( GL_TEXTURE0+j);
831 glEnable(vgl->tex_target);
832 glBindTexture(vgl->tex_target, vgl->texture[0][j]);
833 if(asprintf( &attribute, "MultiTexCoord%1d", j ) == -1 )
836 vgl->EnableVertexAttribArray( vgl->GetAttribLocation(vgl->program[0], attribute ) );
837 vgl->VertexAttribPointer( vgl->GetAttribLocation( vgl->program[0], attribute ), 2, GL_FLOAT, 0, 0, texCoord);
841 vgl->ActiveTexture(GL_TEXTURE0 + 0);
842 vgl->ClientActiveTexture(GL_TEXTURE0 + 0);
843 vgl->EnableVertexAttribArray( vgl->GetAttribLocation( vgl->program[0], "vertex_position"));
844 vgl->VertexAttribPointer( vgl->GetAttribLocation( vgl->program[0], "vertex_position"), 2, GL_FLOAT, 0, 0, vertexCoord);
846 glDrawArrays( GL_TRIANGLE_STRIP, 0, 4);
849 int vout_display_opengl_Display(vout_display_opengl_t *vgl,
850 const video_format_t *source)
852 if (vlc_gl_Lock(vgl->gl))
855 /* glTexCoord works differently with GL_TEXTURE_2D and
856 GL_TEXTURE_RECTANGLE_EXT */
857 float left[PICTURE_PLANE_MAX];
858 float top[PICTURE_PLANE_MAX];
859 float right[PICTURE_PLANE_MAX];
860 float bottom[PICTURE_PLANE_MAX];
861 for (unsigned j = 0; j < vgl->chroma->plane_count; j++) {
862 float scale_w, scale_h;
863 if (vgl->tex_target == GL_TEXTURE_2D) {
864 scale_w = (float)vgl->chroma->p[j].w.num / vgl->chroma->p[j].w.den / vgl->tex_width[j];
865 scale_h = (float)vgl->chroma->p[j].h.num / vgl->chroma->p[j].h.den / vgl->tex_height[j];
871 left[j] = (source->i_x_offset + 0 ) * scale_w;
872 top[j] = (source->i_y_offset + 0 ) * scale_h;
873 right[j] = (source->i_x_offset + source->i_visible_width ) * scale_w;
874 bottom[j] = (source->i_y_offset + source->i_visible_height) * scale_h;
878 /* Why drawing here and not in Render()? Because this way, the
879 OpenGL providers can call vout_display_opengl_Display to force redraw.i
880 Currently, the OS X provider uses it to get a smooth window resizing */
882 glClear(GL_COLOR_BUFFER_BIT);
885 if( vgl->program[0] )
887 vgl->UseProgram(vgl->program[0]);
888 vgl->Uniform4fv( vgl->GetUniformLocation( vgl->program[0], "coefficient" ), 4, vgl->local_value);
889 vgl->Uniform1i( vgl->GetUniformLocation( vgl->program[0], "Texture[0]" ), 0);
890 vgl->Uniform1i( vgl->GetUniformLocation( vgl->program[0], "Texture[1]" ), 1);
891 vgl->Uniform1i( vgl->GetUniformLocation( vgl->program[0], "Texture[2]" ), 2);
892 draw_with_shaders( vgl, left, top ,right, bottom );
893 // Change the program for overlays
894 vgl->UseProgram(vgl->program[1]);
895 vgl->Uniform1i( vgl->GetUniformLocation( vgl->program[1], "Texture[0]" ), 0);
897 draw_without_shaders( vgl, left, top, right, bottom );
900 vgl->ActiveTexture(GL_TEXTURE0 + 0);
901 vgl->ClientActiveTexture(GL_TEXTURE0 + 0);
902 glEnable(GL_TEXTURE_2D);
904 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
906 for (int i = 0; i < vgl->region_count; i++) {
907 gl_region_t *glr = &vgl->region[i];
908 const GLfloat vertexCoord[] = {
910 glr->left, glr->bottom,
911 glr->right, glr->top,
912 glr->right,glr->bottom,
914 static const GLfloat textureCoord[] = {
921 glBindTexture(GL_TEXTURE_2D, glr->texture);
922 if( vgl->program[0] )
924 vgl->Uniform4f( vgl->GetUniformLocation( vgl->program[1], "fillColor"), 1.0f, 1.0f, 1.0f, glr->alpha);
925 vgl->EnableVertexAttribArray( vgl->GetAttribLocation( vgl->program[1], "MultiTexCoord0") );
926 vgl->VertexAttribPointer( vgl->GetAttribLocation( vgl->program[1], "MultiTexCoord0"), 2, GL_FLOAT, 0, 0, textureCoord);
927 vgl->EnableVertexAttribArray( vgl->GetAttribLocation( vgl->program[1], "vertex_position"));
928 vgl->VertexAttribPointer( vgl->GetAttribLocation( vgl->program[1], "vertex_position"), 2, GL_FLOAT, 0, 0, vertexCoord);
932 glEnableClientState(GL_VERTEX_ARRAY);
933 glColor4f( 1.0f, 1.0f, 1.0f, glr->alpha );
934 glEnable(GL_TEXTURE_COORD_ARRAY);
935 glEnable(GL_VERTEX_ARRAY);
936 glTexCoordPointer(2, GL_FLOAT, 0, textureCoord);
937 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
938 glVertexPointer(2, GL_FLOAT, 0, vertexCoord);
941 glDrawArrays( GL_TRIANGLE_STRIP, 0, 4 );
943 if( !vgl->program[0] )
945 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
946 glDisableClientState(GL_VERTEX_ARRAY);
950 glDisable(GL_TEXTURE_2D);
952 vlc_gl_Swap(vgl->gl);
954 vlc_gl_Unlock(vgl->gl);