1 /*****************************************************************************
2 * voutgl.m: MacOS X OpenGL provider
3 *****************************************************************************
4 * Copyright (C) 2001-2004 VideoLAN
5 * $Id: vout.m 8351 2004-08-02 13:06:38Z hartman $
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>
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
26 *****************************************************************************/
28 /*****************************************************************************
30 *****************************************************************************/
31 #include <errno.h> /* ENOMEM */
32 #include <stdlib.h> /* free() */
33 #include <string.h> /* strerror() */
40 #include <OpenGL/OpenGL.h>
41 #include <OpenGL/gl.h>
43 /*****************************************************************************
45 *****************************************************************************/
46 @interface VLCGLView : NSOpenGLView
48 vout_thread_t * p_vout;
51 - (id)initWithFrame: (NSRect) frame vout: (vout_thread_t*) p_vout;
58 NSAutoreleasePool * o_pool;
61 vlc_bool_t b_saved_frame;
63 vlc_bool_t b_got_frame;
67 /*****************************************************************************
69 *****************************************************************************/
71 static int Init ( vout_thread_t * p_vout );
72 static void End ( vout_thread_t * p_vout );
73 static int Manage ( vout_thread_t * p_vout );
74 static int Control( vout_thread_t *, int, va_list );
75 static void Swap ( vout_thread_t * p_vout );
76 static int Lock ( vout_thread_t * p_vout );
77 static void Unlock ( vout_thread_t * p_vout );
79 int E_(OpenVideoGL) ( vlc_object_t * p_this )
81 vout_thread_t * p_vout = (vout_thread_t *) p_this;
83 if( !CGDisplayUsesOpenGLAcceleration( kCGDirectMainDisplay ) )
85 msg_Warn( p_vout, "no hardware acceleration" );
88 msg_Dbg( p_vout, "display is Quartz Extreme accelerated" );
90 p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
91 if( p_vout->p_sys == NULL )
93 msg_Err( p_vout, "out of memory" );
97 memset( p_vout->p_sys, 0, sizeof( vout_sys_t ) );
99 p_vout->p_sys->o_pool = [[NSAutoreleasePool alloc] init];
100 vlc_mutex_init( p_vout, &p_vout->p_sys->lock );
103 p_vout->p_sys->b_got_frame = VLC_FALSE;
104 p_vout->p_sys->o_window = [[VLCWindow alloc] initWithVout: p_vout
106 if( !p_vout->p_sys->o_window )
111 /* Add OpenGL view */
112 #define o_glview p_vout->p_sys->o_glview
113 o_glview = [[VLCGLView alloc] initWithFrame:
114 [p_vout->p_sys->o_window frame] vout: p_vout];
115 [p_vout->p_sys->o_window setContentView: o_glview];
116 [o_glview autorelease];
119 p_vout->pf_init = Init;
120 p_vout->pf_end = End;
121 p_vout->pf_manage = Manage;
122 p_vout->pf_control= Control;
123 p_vout->pf_swap = Swap;
124 p_vout->pf_lock = Lock;
125 p_vout->pf_unlock = Unlock;
130 void E_(CloseVideoGL) ( vlc_object_t * p_this )
132 vout_thread_t * p_vout = (vout_thread_t *) p_this;
133 NSAutoreleasePool *o_pool = [[NSAutoreleasePool alloc] init];
135 /* Remove the GLView from the window, because we are not sure OS X
136 will actually close the window right away. When it doesn't,
137 VLCGLView's reshape is called while p_vout and p_vout->p_sys
138 aren't valid anymore and crashes. */
139 [p_vout->p_sys->o_window setContentView: NULL];
141 /* Close the window */
142 [p_vout->p_sys->o_window close];
145 vlc_mutex_destroy( &p_vout->p_sys->lock );
147 free( p_vout->p_sys );
150 static int Init( vout_thread_t * p_vout )
152 [[p_vout->p_sys->o_glview openGLContext] makeCurrentContext];
156 static void End( vout_thread_t * p_vout )
158 [[p_vout->p_sys->o_glview openGLContext] makeCurrentContext];
161 static int Manage( vout_thread_t * p_vout )
163 if( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE )
165 NSAutoreleasePool *o_pool = [[NSAutoreleasePool alloc] init];
167 if( !p_vout->b_fullscreen )
169 /* Save window size and position */
170 p_vout->p_sys->s_frame.size =
171 [[p_vout->p_sys->o_window contentView] frame].size;
172 p_vout->p_sys->s_frame.origin =
173 [p_vout->p_sys->o_window frame].origin;
174 p_vout->p_sys->b_saved_frame = VLC_TRUE;
176 [p_vout->p_sys->o_window close];
178 p_vout->b_fullscreen = !p_vout->b_fullscreen;
180 if( p_vout->p_sys->b_saved_frame )
182 p_vout->p_sys->o_window = [[VLCWindow alloc]
183 initWithVout: p_vout frame: &p_vout->p_sys->s_frame];
187 p_vout->p_sys->o_window = [[VLCWindow alloc]
188 initWithVout: p_vout frame: nil];
191 #define o_glview p_vout->p_sys->o_glview
192 o_glview = [[VLCGLView alloc] initWithFrame: [p_vout->p_sys->o_window frame] vout: p_vout];
193 [p_vout->p_sys->o_window setContentView: o_glview];
194 [o_glview autorelease];
195 [[o_glview openGLContext] makeCurrentContext];
199 p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
201 [p_vout->p_sys->o_window manage];
205 /*****************************************************************************
206 * Control: control facility for the vout
207 *****************************************************************************/
208 static int Control( vout_thread_t *p_vout, int i_query, va_list args )
214 case VOUT_SET_STAY_ON_TOP:
215 b_arg = va_arg( args, vlc_bool_t );
216 [p_vout->p_sys->o_window setOnTop: b_arg];
222 return vout_vaControlDefault( p_vout, i_query, args );
226 static void Swap( vout_thread_t * p_vout )
228 p_vout->p_sys->b_got_frame = VLC_TRUE;
229 [[p_vout->p_sys->o_glview openGLContext] makeCurrentContext];
233 static int Lock( vout_thread_t * p_vout )
235 vlc_mutex_lock( &p_vout->p_sys->lock );
239 static void Unlock( vout_thread_t * p_vout )
241 vlc_mutex_unlock( &p_vout->p_sys->lock );
244 /*****************************************************************************
245 * VLCGLView implementation
246 *****************************************************************************/
247 @implementation VLCGLView
249 - (id) initWithFrame: (NSRect) frame vout: (vout_thread_t*) _p_vout
253 NSOpenGLPixelFormatAttribute attribs[] =
255 NSOpenGLPFAAccelerated,
256 NSOpenGLPFANoRecovery,
257 NSOpenGLPFAColorSize, 24,
258 NSOpenGLPFAAlphaSize, 8,
259 NSOpenGLPFADepthSize, 24,
264 NSOpenGLPixelFormat * fmt = [[NSOpenGLPixelFormat alloc]
265 initWithAttributes: attribs];
269 msg_Warn( p_vout, "Cannot create NSOpenGLPixelFormat" );
273 self = [super initWithFrame:frame pixelFormat: fmt];
276 [[self openGLContext] makeCurrentContext];
277 [[self openGLContext] update];
279 /* Swap buffers only during the vertical retrace of the monitor.
280 http://developer.apple.com/documentation/GraphicsImaging/
281 Conceptual/OpenGL/chap5/chapter_5_section_44.html */
282 long params[] = { 1 };
283 CGLSetParameter( CGLGetCurrentContext(), kCGLCPSwapInterval,
292 NSRect bounds = [self bounds];
294 [[self openGLContext] makeCurrentContext];
296 var_Get( p_vout, "macosx-stretch", &val );
299 x = bounds.size.width;
300 y = bounds.size.height;
302 else if( bounds.size.height * p_vout->render.i_aspect <
303 bounds.size.width * VOUT_ASPECT_FACTOR )
305 x = bounds.size.height * p_vout->render.i_aspect / VOUT_ASPECT_FACTOR;
306 y = bounds.size.height;
310 x = bounds.size.width;
311 y = bounds.size.width * VOUT_ASPECT_FACTOR / p_vout->render.i_aspect;
315 glViewport( ( bounds.size.width - x ) / 2,
316 ( bounds.size.height - y ) / 2, x, y );
319 if( p_vout->p_sys->b_got_frame )
321 /* Ask the opengl module to redraw */
322 vout_thread_t * p_parent;
323 p_parent = (vout_thread_t *) p_vout->p_parent;
324 if( p_parent && p_parent->pf_display )
326 p_parent->pf_display( p_parent, NULL );
332 glClear( GL_COLOR_BUFFER_BIT );
337 - (void) drawRect: (NSRect) rect
339 [[self openGLContext] makeCurrentContext];