X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fvideo_output%2Fopengllayer.m;h=fe5717c03b1ca7f28eb467bb5e1d3a90433697b6;hb=c5c06b64c806052086e5772d64e540a8db7e4a9b;hp=11ed466f829d84bc2a567243d5a59ac34e12634a;hpb=5452eae72be0adceac74746e4d646450b4410632;p=vlc diff --git a/modules/video_output/opengllayer.m b/modules/video_output/opengllayer.m index 11ed466f82..fe5717c03b 100644 --- a/modules/video_output/opengllayer.m +++ b/modules/video_output/opengllayer.m @@ -3,7 +3,7 @@ * a layer. The layer will register itself to the drawable object stored in * the "drawable" variable. ***************************************************************************** - * Copyright (C) 2004 the VideoLAN team + * Copyright (C) 2004-2009 the VideoLAN team * $Id$ * * Authors: Cyril Deguet @@ -32,7 +32,12 @@ *****************************************************************************/ #include /* ENOMEM */ -#include +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include #include #import @@ -84,15 +89,15 @@ static int Control ( vout_thread_t *, int, va_list ); static int InitTextures ( vout_thread_t * ); -vlc_module_begin(); - set_shortname( "OpenGLLayer" ); - set_category( CAT_VIDEO ); - set_subcategory( SUBCAT_VIDEO_VOUT ); - set_description( _("Core Animation OpenGL Layer (Mac OS X)") ); - set_capability( "video output", 20 ); - add_shortcut( "opengllayer" ); - set_callbacks( CreateVout, DestroyVout ); -vlc_module_end(); +vlc_module_begin () + set_shortname( "OpenGLLayer" ) + set_category( CAT_VIDEO ) + set_subcategory( SUBCAT_VIDEO_VOUT ) + set_description( N_("Core Animation OpenGL Layer (Mac OS X)") ) + set_capability( "video output", 20 ) + add_shortcut( "opengllayer" ) + set_callbacks( CreateVout, DestroyVout ) +vlc_module_end () @interface VLCVoutLayer : CAOpenGLLayer { vout_thread_t * p_vout; @@ -112,7 +117,9 @@ struct vout_sys_t uint8_t *pp_buffer[2]; /* one last rendered, one to be rendered */ int i_index; - vlc_bool_t b_frame_available; + bool b_frame_available; + + CGLContextObj glContext; int i_tex_width; int i_tex_height; @@ -133,12 +140,9 @@ static int CreateVout( vlc_object_t *p_this ) char * psz; /* Allocate structure */ - p_vout->p_sys = p_sys = calloc( sizeof( vout_sys_t ), 1 ); + p_vout->p_sys = p_sys = calloc( 1, sizeof( vout_sys_t ) ); if( p_sys == NULL ) - { - msg_Err( p_vout, "out of memory" ); return VLC_EGENERIC; - } p_sys->i_tex_width = p_vout->fmt_in.i_width; p_sys->i_tex_height = p_vout->fmt_in.i_height; @@ -146,7 +150,6 @@ static int CreateVout( vlc_object_t *p_this ) msg_Dbg( p_vout, "Texture size: %dx%d", p_sys->i_tex_width, p_sys->i_tex_height ); - p_vout->pf_init = Init; p_vout->pf_end = End; p_vout->pf_manage = Manage; @@ -167,10 +170,10 @@ static int Init( vout_thread_t *p_vout ) vlc_value_t val; #if ( defined( WORDS_BIGENDIAN ) && VLCGL_FORMAT == GL_YCBCR_422_APPLE ) || (VLCGL_FORMAT == YCBCR_MESA) - p_vout->output.i_chroma = VLC_FOURCC('Y','U','Y','2'); + p_vout->output.i_chroma = VLC_CODEC_YUYV; i_pixel_pitch = 2; #elif (VLCGL_FORMAT == GL_YCBCR_422_APPLE) - p_vout->output.i_chroma = VLC_FOURCC('U','Y','V','Y'); + p_vout->output.i_chroma = VLC_CODEC_UYVY; i_pixel_pitch = 2; #endif @@ -182,8 +185,8 @@ static int Init( vout_thread_t *p_vout ) /* We do need a drawable to work properly */ vlc_value_t value_drawable; - var_Create( p_vout, "drawable", VLC_VAR_DOINHERIT ); - var_Get( p_vout, "drawable", &value_drawable ); + var_Create( p_vout, "drawable-gl", VLC_VAR_DOINHERIT ); + var_Get( p_vout, "drawable-gl", &value_drawable ); p_vout->p_sys->o_cocoa_container = (id) value_drawable.i_int; @@ -198,16 +201,13 @@ static int Init( vout_thread_t *p_vout ) p_sys->pp_buffer[i] = malloc( p_sys->i_tex_width * p_sys->i_tex_height * i_pixel_pitch ); if( !p_sys->pp_buffer[i] ) - { - msg_Err( p_vout, "out of memory" ); return VLC_EGENERIC; - } } - p_sys->b_frame_available = VLC_FALSE; + p_sys->b_frame_available = false; p_sys->i_index = 0; - + p_vout->p_picture[0].i_planes = 1; - p_vout->p_picture[0].p->p_pixels = p_sys->pp_buffer[0]; + p_vout->p_picture[0].p->p_pixels = p_sys->pp_buffer[p_sys->i_index]; p_vout->p_picture[0].p->i_lines = p_vout->output.i_height; p_vout->p_picture[0].p->i_visible_lines = p_vout->output.i_height; p_vout->p_picture[0].p->i_pixel_pitch = i_pixel_pitch; @@ -238,23 +238,17 @@ static void End( vout_thread_t *p_vout ) { vout_sys_t *p_sys = p_vout->p_sys; - p_vout->p_sys->b_frame_available = 0; - - [CATransaction performSelectorOnMainThread:@selector(begin) - withObject:nil waitUntilDone:YES]; + p_vout->p_sys->b_frame_available = false; - [p_sys->o_layer performSelectorOnMainThread:@selector(removeFromSuperlayer) - withObject:nil waitUntilDone:YES]; - [CATransaction performSelectorOnMainThread:@selector(commit) - withObject:nil waitUntilDone:YES]; + [p_vout->p_sys->o_cocoa_container performSelectorOnMainThread:@selector(removeVoutLayer:) withObject:p_vout->p_sys->o_layer waitUntilDone:YES]; // Should be done automatically [p_sys->o_layer release]; [p_sys->autorealease_pool release]; /* Free the texture buffer*/ - if( p_sys->pp_buffer[0] ) free( p_sys->pp_buffer[0] ); - if( p_sys->pp_buffer[1] ) free( p_sys->pp_buffer[1] ); + free( p_sys->pp_buffer[0] ); + free( p_sys->pp_buffer[1] ); } /***************************************************************************** @@ -276,7 +270,9 @@ static void DestroyVout( vlc_object_t *p_this ) * a non null value if an error occurred. *****************************************************************************/ static int Manage( vout_thread_t *p_vout ) -{ +{ + vout_sys_t *p_sys = p_vout->p_sys; + return VLC_SUCCESS; } @@ -287,16 +283,37 @@ static void Render( vout_thread_t *p_vout, picture_t *p_pic ) { vout_sys_t *p_sys = p_vout->p_sys; - /* Switch buffers */ - int p_new_index; - @synchronized(p_sys->o_layer) + @synchronized( p_sys->o_layer ) /* Make sure the p_sys->glContext isn't edited */ { - p_new_index = (p_sys->i_index + 1) & 1; + if( p_sys->glContext ) + { + CGLLockContext(p_sys->glContext); + CGLSetCurrentContext(p_sys->glContext); + int i_new_index; + i_new_index = ( p_sys->i_index + 1 ) & 1; + + + /* Update the texture */ + glBindTexture( VLCGL_TARGET, p_sys->p_textures[i_new_index] ); + glTexSubImage2D( VLCGL_TARGET, 0, 0, 0, + p_vout->fmt_out.i_width, + p_vout->fmt_out.i_height, + VLCGL_FORMAT, VLCGL_TYPE, p_sys->pp_buffer[i_new_index] ); + + /* Bind to the previous texture for drawing */ + glBindTexture( VLCGL_TARGET, p_sys->p_textures[p_sys->i_index] ); + + /* Switch buffers */ + p_sys->i_index = i_new_index; + p_pic->p->p_pixels = p_sys->pp_buffer[p_sys->i_index]; + CGLUnlockContext(p_sys->glContext); + + p_sys->b_frame_available = true; + } } /* Give a buffer where the image will be rendered */ - p_pic->p->p_pixels = p_sys->pp_buffer[p_new_index]; - + p_pic->p->p_pixels = p_sys->pp_buffer[p_sys->i_index]; } /***************************************************************************** @@ -305,14 +322,9 @@ static void Render( vout_thread_t *p_vout, picture_t *p_pic ) static void DisplayVideo( vout_thread_t *p_vout, picture_t *p_pic ) { vout_sys_t *p_sys = p_vout->p_sys; - - /* The frame is ready, give its number so the o_layer can display it */ - @synchronized(p_sys->o_layer) - { - p_sys->i_index = (p_sys->i_index + 1) & 1; /* Indicate the layer should use that index */ - } - - p_sys->b_frame_available = 1; + + [p_sys->o_layer performSelectorOnMainThread:@selector(display) + withObject:nil waitUntilDone:YES]; } /***************************************************************************** @@ -322,17 +334,9 @@ static int Control( vout_thread_t *p_vout, int i_query, va_list args ) { vout_sys_t *p_sys = p_vout->p_sys; - switch( i_query ) - { - case VOUT_SNAPSHOT: - return vout_vaControlDefault( p_vout, i_query, args ); - - default: - if( p_sys->p_vout->pf_control ) - return p_sys->p_vout->pf_control( p_sys->p_vout, i_query, args ); - else - return vout_vaControlDefault( p_vout, i_query, args ); - } + if( p_sys->p_vout->pf_control ) + return p_sys->p_vout->pf_control( p_sys->p_vout, i_query, args ); + return VLC_EGENERIC; } /***************************************************************************** @@ -361,18 +365,19 @@ static int InitTextures( vout_thread_t *p_vout ) glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ); -#ifdef __DISABLED_FOR_NOW__ + /* Note: It seems that we can't bypass those, and even + * disabled they are used. They are the cause of the flickering */ + /* Tell the driver not to make a copy of the texture but to use our buffer */ glEnable( GL_UNPACK_CLIENT_STORAGE_APPLE ); glPixelStorei( GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE ); -#endif /* Use AGP texturing */ - glTexParameteri( VLCGL_TARGET, GL_TEXTURE_STORAGE_HINT_APPLE, - GL_STORAGE_SHARED_APPLE ); + glTexParameteri( VLCGL_TARGET, GL_TEXTURE_STORAGE_HINT_APPLE, GL_STORAGE_SHARED_APPLE ); + /* Call glTexImage2D only once, and use glTexSubImage2D later */ - glTexImage2D( VLCGL_TARGET, 0, 3, p_sys->i_tex_width, + glTexImage2D( VLCGL_TARGET, 0, 4, p_sys->i_tex_width, p_sys->i_tex_height, 0, VLCGL_FORMAT, VLCGL_TYPE, p_sys->pp_buffer[i_index] ); } @@ -393,22 +398,17 @@ static int InitTextures( vout_thread_t *p_vout ) + (void)autoinitInVout:(NSValue*)arg { vout_thread_t * p_vout = [arg pointerValue]; - p_vout->p_sys->o_layer = [[VLCVoutLayer layerWithVout: p_vout] retain]; + p_vout->p_sys->o_layer = [[VLCVoutLayer layerWithVout:p_vout] retain]; [p_vout->p_sys->o_cocoa_container addVoutLayer:p_vout->p_sys->o_layer]; } -- (void)setVout:(vout_thread_t*)_p_vout -{ - p_vout = _p_vout; -} - + (id)layerWithVout:(vout_thread_t*)_p_vout { - VLCVoutLayer* me = [super layer]; + VLCVoutLayer* me = [[[self alloc] init] autorelease]; if( me ) { - me.asynchronous = YES; - [me setVout: _p_vout]; + me->p_vout = _p_vout; + me.asynchronous = NO; me.bounds = CGRectMake( 0.0, 0.0, (float)_p_vout->fmt_in.i_visible_width * _p_vout->fmt_in.i_sar_num, (float)_p_vout->fmt_in.i_visible_height * _p_vout->fmt_in.i_sar_den ); @@ -418,16 +418,15 @@ static int InitTextures( vout_thread_t *p_vout ) - (BOOL)canDrawInCGLContext:(CGLContextObj)glContext pixelFormat:(CGLPixelFormatObj)pixelFormat forLayerTime:(CFTimeInterval)timeInterval displayTime:(const CVTimeStamp *)timeStamp { - /* Only draw the frame when if have a frame that was previously rendered */ - return p_vout->p_sys->b_frame_available; + /* Only draw the frame if we have a frame that was previously rendered */ + return p_vout->p_sys->b_frame_available; // Flag is cleared by drawInCGLContext:pixelFormat:forLayerTime:displayTime: } - (void)drawInCGLContext:(CGLContextObj)glContext pixelFormat:(CGLPixelFormatObj)pixelFormat forLayerTime:(CFTimeInterval)timeInterval displayTime:(const CVTimeStamp *)timeStamp { - /* Init */ CGLLockContext( glContext ); CGLSetCurrentContext( glContext ); - + float f_width, f_height, f_x, f_y; f_x = (float)p_vout->fmt_out.i_x_offset; @@ -437,17 +436,6 @@ static int InitTextures( vout_thread_t *p_vout ) f_height = (float)p_vout->fmt_out.i_y_offset + (float)p_vout->fmt_out.i_visible_height; - @synchronized(self) - { - glBindTexture( VLCGL_TARGET, p_vout->p_sys->p_textures[p_vout->p_sys->i_index] ); - - glTexSubImage2D( VLCGL_TARGET, 0, 0, 0, - p_vout->fmt_out.i_width, - p_vout->fmt_out.i_height, - VLCGL_FORMAT, VLCGL_TYPE, p_vout->p_sys->pp_buffer[p_vout->p_sys->i_index] ); - - } - glClear( GL_COLOR_BUFFER_BIT ); glEnable( VLCGL_TARGET ); @@ -457,33 +445,12 @@ static int InitTextures( vout_thread_t *p_vout ) glTexCoord2f( f_width, f_height ); glVertex2f( 1.0, -1.0 ); glTexCoord2f( f_x, f_height ); glVertex2f( -1.0, -1.0 ); glEnd(); - + glDisable( VLCGL_TARGET ); glFlush(); - CGLUnlockContext( glContext ); -} - -- (CGLPixelFormatObj)copyCGLPixelFormatForDisplayMask:(uint32_t)mask -{ - GLuint attribs[] = - { - NSOpenGLPFANoRecovery, - NSOpenGLPFAWindow, - NSOpenGLPFAAccelerated, - NSOpenGLPFADoubleBuffer, - NSOpenGLPFAColorSize, 24, - NSOpenGLPFAAlphaSize, 8, - NSOpenGLPFADepthSize, 24, - NSOpenGLPFAStencilSize, 8, - NSOpenGLPFAAccumSize, 0, - 0 - }; - - NSOpenGLPixelFormat* fmt = [[NSOpenGLPixelFormat alloc] initWithAttributes: (NSOpenGLPixelFormatAttribute*) attribs]; - - return [fmt CGLPixelFormatObj]; + CGLUnlockContext( glContext ); } - (CGLContextObj)copyCGLContextForPixelFormat:(CGLPixelFormatObj)pixelFormat @@ -491,16 +458,8 @@ static int InitTextures( vout_thread_t *p_vout ) CGLContextObj context = [super copyCGLContextForPixelFormat:pixelFormat]; CGLLockContext( context ); - CGLSetCurrentContext( context ); - InitTextures( p_vout ); - - glDisable(GL_BLEND); - glDisable(GL_DEPTH_TEST); - glDepthMask(GL_FALSE); - glDisable(GL_CULL_FACE); - glClearColor( 0.0f, 0.0f, 0.0f, 1.0f ); - glClear( GL_COLOR_BUFFER_BIT ); + CGLSetCurrentContext( context ); /* Swap buffers only during the vertical retrace of the monitor. http://developer.apple.com/documentation/GraphicsImaging/ @@ -508,14 +467,33 @@ static int InitTextures( vout_thread_t *p_vout ) GLint params = 1; CGLSetParameter( CGLGetCurrentContext(), kCGLCPSwapInterval, - ¶ms ); + ¶ms ); + + InitTextures( p_vout ); + + glDisable( GL_BLEND ); + glDisable( GL_DEPTH_TEST ); + glDepthMask( GL_FALSE ); + glDisable( GL_CULL_FACE) ; + glClearColor( 0.0f, 0.0f, 0.0f, 1.0f ); + glClear( GL_COLOR_BUFFER_BIT ); CGLUnlockContext( context ); + @synchronized( self ) + { + p_vout->p_sys->glContext = context; + } + return context; } - (void)releaseCGLContext:(CGLContextObj)glContext { + @synchronized( self ) + { + p_vout->p_sys->glContext = nil; + } + CGLLockContext( glContext ); CGLSetCurrentContext( glContext ); @@ -523,5 +501,4 @@ static int InitTextures( vout_thread_t *p_vout ) CGLUnlockContext( glContext ); } - @end