1 /*****************************************************************************
2 * voutgl.m: MacOS X OpenGL provider
3 *****************************************************************************
4 * Copyright (C) 2001-2004, 2007-2009, 2011 the VideoLAN team
7 * Authors: Colin Delacroix <colin@zoy.org>
8 * Florian G. Pflug <fgp@phlo.org>
9 * Jon Lech Johansen <jon-vl@nanocrew.net>
10 * Derk-Jan Hartman <hartman at videolan dot org>
11 * Eric Petit <titer@m0k.org>
12 * Benjamin Pracht <bigben at videolan dot org>
13 * Damien Fouilleul <damienf at videolan dot org>
14 * Felix Paul Kuehne <fkuehne at videolan dot org>
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 2 of the License, or
19 * (at your option) any later version.
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, write to the Free Software
28 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
29 *****************************************************************************/
31 /*****************************************************************************
33 *****************************************************************************/
34 #include <stdlib.h> /* free() */
37 #include <vlc_common.h>
43 #include <OpenGL/OpenGL.h>
44 #include <OpenGL/gl.h>
48 /*****************************************************************************
50 *****************************************************************************/
51 @interface VLCGLView : NSOpenGLView <VLCVoutViewResetting>
53 vout_thread_t * p_vout;
56 + (void)resetVout: (NSValue *) voutValue;
57 - (id) initWithVout: (vout_thread_t *) p_vout;
63 VLCVoutView * o_vout_view;
71 /*****************************************************************************
73 *****************************************************************************/
75 static int Init ( vout_thread_t * p_vout );
76 static void End ( vout_thread_t * p_vout );
77 static int Manage ( vout_thread_t * p_vout );
78 static int Control( vout_thread_t *, int, va_list );
79 static void Swap ( vout_thread_t * p_vout );
80 static int Lock ( vout_thread_t * p_vout );
81 static void Unlock ( vout_thread_t * p_vout );
83 int OpenVideoGL ( vlc_object_t * p_this )
85 vout_thread_t * p_vout = (vout_thread_t *) p_this;
87 if( !CGDisplayUsesOpenGLAcceleration( kCGDirectMainDisplay ) )
89 msg_Warn( p_vout, "no OpenGL hardware acceleration found. "
90 "Video display might be slow" );
92 msg_Dbg( p_vout, "display is Quartz Extreme accelerated" );
94 p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
95 if( p_vout->p_sys == NULL )
98 memset( p_vout->p_sys, 0, sizeof( vout_sys_t ) );
100 NSAutoreleasePool *o_pool = [[NSAutoreleasePool alloc] init];
102 p_vout->p_sys->b_embedded = false;
104 [VLCGLView performSelectorOnMainThread:@selector(initVout:) withObject:[NSValue valueWithPointer:p_vout] waitUntilDone:YES];
108 /* Check to see if initVout: was successfull */
109 if( !p_vout->p_sys->o_vout_view )
111 free( p_vout->p_sys );
115 p_vout->pf_init = Init;
116 p_vout->pf_end = End;
117 p_vout->pf_manage = Manage;
118 p_vout->pf_control= Control;
119 p_vout->pf_swap = Swap;
120 p_vout->pf_lock = Lock;
121 p_vout->pf_unlock = Unlock;
122 p_vout->p_sys->b_got_frame = false;
127 void CloseVideoGL ( vlc_object_t * p_this )
129 vout_thread_t * p_vout = (vout_thread_t *) p_this;
131 if(VLCIntf && vlc_object_alive (VLCIntf))
133 NSAutoreleasePool *o_pool = [[NSAutoreleasePool alloc] init];
135 /* Close the window */
136 [p_vout->p_sys->o_vout_view performSelectorOnMainThread:@selector(closeVout) withObject:NULL waitUntilDone:YES];
141 free( p_vout->p_sys );
144 static int Init( vout_thread_t * p_vout )
146 [[p_vout->p_sys->o_glview openGLContext] makeCurrentContext];
150 static void End( vout_thread_t * p_vout )
152 [[p_vout->p_sys->o_glview openGLContext] makeCurrentContext];
155 static int Manage( vout_thread_t * p_vout )
157 if( p_vout->i_changes & VOUT_ASPECT_CHANGE )
159 [p_vout->p_sys->o_glview reshape];
160 p_vout->i_changes &= ~VOUT_ASPECT_CHANGE;
162 if( p_vout->i_changes & VOUT_CROP_CHANGE )
164 [p_vout->p_sys->o_glview reshape];
165 p_vout->i_changes &= ~VOUT_CROP_CHANGE;
168 if( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE )
170 NSAutoreleasePool *o_pool = [[NSAutoreleasePool alloc] init];
172 p_vout->b_fullscreen = !p_vout->b_fullscreen;
174 if( p_vout->b_fullscreen )
175 [p_vout->p_sys->o_vout_view enterFullscreen];
177 [p_vout->p_sys->o_vout_view leaveFullscreen];
181 p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
184 if( p_vout->p_sys->o_vout_view )
185 [p_vout->p_sys->o_vout_view manage];
189 /*****************************************************************************
190 * Control: control facility for the vout
191 *****************************************************************************/
192 static int Control( vout_thread_t *p_vout, int i_query, va_list args )
198 case VOUT_SET_STAY_ON_TOP:
199 b_arg = (bool) va_arg( args, int );
200 [p_vout->p_sys->o_vout_view setOnTop: b_arg];
208 static void Swap( vout_thread_t * p_vout )
210 p_vout->p_sys->b_got_frame = true;
211 [[p_vout->p_sys->o_glview openGLContext] flushBuffer];
214 static int Lock( vout_thread_t * p_vout )
216 if( kCGLNoError == CGLLockContext([[p_vout->p_sys->o_glview openGLContext] CGLContextObj]) )
218 [[p_vout->p_sys->o_glview openGLContext] makeCurrentContext];
224 static void Unlock( vout_thread_t * p_vout )
226 CGLUnlockContext([[p_vout->p_sys->o_glview openGLContext] CGLContextObj]);
229 /*****************************************************************************
230 * VLCGLView implementation
231 *****************************************************************************/
232 @implementation VLCGLView
233 + (void)initVout:(NSValue *)arg
235 vout_thread_t * p_vout = [arg pointerValue];
237 /* Create the GL view */
238 p_vout->p_sys->o_glview = [[VLCGLView alloc] initWithVout: p_vout];
239 [p_vout->p_sys->o_glview autorelease];
241 /* Spawn the window */
242 id old_vout = p_vout->p_sys->o_vout_view;
243 p_vout->p_sys->o_vout_view = [[VLCVoutView voutView: p_vout
244 subView: p_vout->p_sys->o_glview frame: nil] retain];
248 /* This function will reset the o_vout_view. It's useful to go fullscreen. */
249 + (void)resetVout:(NSValue *) voutValue
251 vout_thread_t * p_vout = [voutValue pointerValue];
252 if( p_vout->b_fullscreen )
254 /* Save window size and position */
255 p_vout->p_sys->s_frame.size =
256 [p_vout->p_sys->o_vout_view frame].size;
257 p_vout->p_sys->s_frame.origin =
258 [[p_vout->p_sys->o_vout_view voutWindow]frame].origin;
259 p_vout->p_sys->b_saved_frame = true;
262 [p_vout->p_sys->o_vout_view closeVout];
264 #define o_glview p_vout->p_sys->o_glview
265 o_glview = [[VLCGLView alloc] initWithVout: p_vout];
266 [o_glview autorelease];
268 if( p_vout->p_sys->b_saved_frame )
270 id old_vout = p_vout->p_sys->o_vout_view;
271 p_vout->p_sys->o_vout_view = [[VLCVoutView voutView: p_vout
273 frame: &p_vout->p_sys->s_frame] retain];
278 id old_vout = p_vout->p_sys->o_vout_view;
279 p_vout->p_sys->o_vout_view = [[VLCVoutView voutView: p_vout
280 subView: o_glview frame: nil] retain];
286 - (id) initWithVout: (vout_thread_t *) vout
288 /* Must be called from main thread:
289 * "The NSView class is generally thread-safe, with a few exceptions. You
290 * should create, destroy, resize, move, and perform other operations on NSView
291 * objects only from the main thread of an application. Drawing from secondary
292 * threads is thread-safe as long as you bracket drawing calls with calls to
293 * lockFocusIfCanDraw and unlockFocus." Cocoa Thread Safety */
297 NSOpenGLPixelFormatAttribute attribs[] =
299 NSOpenGLPFADoubleBuffer,
300 NSOpenGLPFAAccelerated,
301 NSOpenGLPFANoRecovery,
302 NSOpenGLPFAColorSize, 24,
303 NSOpenGLPFAAlphaSize, 8,
304 NSOpenGLPFADepthSize, 24,
309 NSOpenGLPixelFormat * fmt = [[NSOpenGLPixelFormat alloc]
310 initWithAttributes: attribs];
314 msg_Warn( p_vout, "could not create OpenGL video output" );
318 self = [super initWithFrame: NSMakeRect(0,0,10,10) pixelFormat: fmt];
321 [[self openGLContext] makeCurrentContext];
322 [[self openGLContext] update];
324 /* Swap buffers only during the vertical retrace of the monitor.
325 http://developer.apple.com/documentation/GraphicsImaging/
326 Conceptual/OpenGL/chap5/chapter_5_section_44.html */
327 GLint params[] = { 1 };
328 CGLSetParameter( CGLGetCurrentContext(), kCGLCPSwapInterval, params );
332 - (BOOL)mouseDownCanMoveWindow
342 NSRect bounds = [self bounds];
344 if( var_GetBool( p_vout, "macosx-stretch" ) )
346 x = bounds.size.width;
347 y = bounds.size.height;
349 else if( bounds.size.height * p_vout->fmt_in.i_visible_width *
350 p_vout->fmt_in.i_sar_num <
351 bounds.size.width * p_vout->fmt_in.i_visible_height *
352 p_vout->fmt_in.i_sar_den )
354 x = ( bounds.size.height * p_vout->fmt_in.i_visible_width *
355 p_vout->fmt_in.i_sar_num ) /
356 ( p_vout->fmt_in.i_visible_height * p_vout->fmt_in.i_sar_den);
358 y = bounds.size.height;
362 x = bounds.size.width;
363 y = ( bounds.size.width * p_vout->fmt_in.i_visible_height *
364 p_vout->fmt_in.i_sar_den) /
365 ( p_vout->fmt_in.i_visible_width * p_vout->fmt_in.i_sar_num );
368 glViewport( ( bounds.size.width - x ) / 2,
369 ( bounds.size.height - y ) / 2, x, y );
373 if( p_vout->p_sys->b_got_frame )
375 /* Ask the opengl module to redraw */
376 vout_thread_t * p_parent;
377 p_parent = (vout_thread_t *) p_vout->p_parent;
379 if( p_parent && p_parent->pf_display )
381 p_parent->pf_display( p_parent, NULL );
386 glClear( GL_COLOR_BUFFER_BIT );
398 - (void) drawRect: (NSRect) rect
401 [[p_vout->p_sys->o_glview openGLContext] flushBuffer];
402 [super drawRect:rect];
408 NSWindow *window = [self window];
410 if ([window respondsToSelector:@selector(disableScreenUpdatesUntilFlush)])
412 [window disableScreenUpdatesUntilFlush];