[818/906] window: add send_message_async vmethod
[platform/upstream/gstreamer.git] / gst-libs / gst / gl / cocoa / gstglcontext_cocoa.m
1 /*
2  * GStreamer
3  * Copyright (C) 2012 Matthew Waters <ystreet00@gmail.com>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  */
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include <Cocoa/Cocoa.h>
26
27 #include "gstglcontext_cocoa.h"
28 #include "gstgl_cocoa_private.h"
29
30 static gboolean gst_gl_context_cocoa_create_context (GstGLContext *context, GstGLAPI gl_api,
31     GstGLContext * other_context, GError **error);
32 static void gst_gl_context_cocoa_destroy_context (GstGLContext *context);
33 static guintptr gst_gl_context_cocoa_get_gl_context (GstGLContext * window);
34 static gboolean gst_gl_context_cocoa_activate (GstGLContext * context, gboolean activate);
35 static GstGLAPI gst_gl_context_cocoa_get_gl_api (GstGLContext * context);
36
37 #define GST_GL_CONTEXT_COCOA_GET_PRIVATE(o)  \
38   (G_TYPE_INSTANCE_GET_PRIVATE((o), GST_GL_TYPE_CONTEXT_COCOA, GstGLContextCocoaPrivate))
39
40 G_DEFINE_TYPE (GstGLContextCocoa, gst_gl_context_cocoa, GST_GL_TYPE_CONTEXT);
41
42 #ifndef GNUSTEP
43 static gboolean
44 gst_gl_window_cocoa_nsapp_iteration (gpointer data)
45 {
46   NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
47
48   NSEvent *event = nil;
49
50   if ([NSThread isMainThread]) {
51
52     while ((event = ([NSApp nextEventMatchingMask:NSAnyEventMask
53       untilDate:[NSDate dateWithTimeIntervalSinceNow:0.5]
54       inMode:NSDefaultRunLoopMode dequeue:YES])) != nil) {
55
56       [NSApp sendEvent:event];
57     }
58   }
59
60   [pool release];
61
62   return TRUE;
63 }
64 #endif
65
66 static void
67 gst_gl_context_cocoa_class_init (GstGLContextCocoaClass * klass)
68 {
69   GstGLContextClass *context_class;
70
71 #ifndef GNUSTEP
72   NSAutoreleasePool* pool = nil;
73 #endif
74
75   context_class = (GstGLContextClass *) klass;
76
77   g_type_class_add_private (klass, sizeof (GstGLContextCocoaPrivate));
78
79   context_class->destroy_context =
80       GST_DEBUG_FUNCPTR (gst_gl_context_cocoa_destroy_context);
81   context_class->create_context =
82       GST_DEBUG_FUNCPTR (gst_gl_context_cocoa_create_context);
83   context_class->get_gl_context =
84       GST_DEBUG_FUNCPTR (gst_gl_context_cocoa_get_gl_context);
85   context_class->activate = GST_DEBUG_FUNCPTR (gst_gl_context_cocoa_activate);
86   context_class->get_gl_api =
87       GST_DEBUG_FUNCPTR (gst_gl_context_cocoa_get_gl_api);
88
89 #ifndef GNUSTEP
90   pool = [[NSAutoreleasePool alloc] init];
91   [NSApplication sharedApplication];
92
93   [pool release];
94 #endif
95 }
96
97 static void
98 gst_gl_context_cocoa_init (GstGLContextCocoa * context)
99 {
100   context->priv = GST_GL_CONTEXT_COCOA_GET_PRIVATE (context);
101 }
102
103 /* Must be called in the gl thread */
104 GstGLContextCocoa *
105 gst_gl_context_cocoa_new (void)
106 {
107   GstGLContextCocoa *context = g_object_new (GST_GL_TYPE_CONTEXT_COCOA, NULL);
108
109   return context;
110 }
111
112 static gboolean
113 gst_gl_context_cocoa_create_context (GstGLContext *context, GstGLAPI gl_api,
114     GstGLContext *other_context, GError **error)
115 {
116   GstGLContextCocoa *context_cocoa = GST_GL_CONTEXT_COCOA (context);
117   GstGLContextCocoaPrivate *priv = context_cocoa->priv;
118   GstGLWindow *window = gst_gl_context_get_window (context);
119   GstGLWindowCocoa *window_cocoa = GST_GL_WINDOW_COCOA (window);
120   GstGLNSOpenGLView *glView = nil;
121   NSWindow *window_handle;
122   NSRect rect;
123   NSAutoreleasePool *pool;
124   NSOpenGLPixelFormat *fmt = nil;
125   NSOpenGLContext *glContext = nil;
126   NSOpenGLPixelFormatAttribute attribs[] = {
127     NSOpenGLPFADoubleBuffer,
128     NSOpenGLPFAAccumSize, 32,
129     0
130   };
131
132   priv->gl_context = nil;
133   if (other_context)
134     priv->external_gl_context = (NSOpenGLContext *) gst_gl_context_get_gl_context (other_context);
135   else
136     priv->external_gl_context = NULL;
137
138   GSRegisterCurrentThread();
139
140   pool = [[NSAutoreleasePool alloc] init];
141
142 #ifdef GNUSTEP
143   [NSApplication sharedApplication];
144 #endif
145
146   rect.origin.x = 0;
147   rect.origin.y = 0;
148   rect.size.width = 320;
149   rect.size.height = 240;
150
151   priv->rect = rect;
152
153   gst_gl_window_cocoa_create_window (window_cocoa);
154   window_handle = (NSWindow *) gst_gl_window_get_window_handle (window);
155
156   glView = [GstGLNSOpenGLView alloc];
157
158   fmt = [[NSOpenGLPixelFormat alloc] initWithAttributes:attribs];
159
160   if (!fmt) {
161     gst_object_unref (window);
162     GST_WARNING ("cannot create NSOpenGLPixelFormat");
163     return FALSE;
164   }
165
166   glView = [glView initWithFrame:window_cocoa rect:rect pixelFormat:fmt];
167
168   [window_handle setContentView:glView];
169
170 #ifndef GNUSTEP
171   glContext = [[NSOpenGLContext alloc] initWithFormat:fmt 
172     shareContext:context_cocoa->priv->external_gl_context];
173
174   GST_DEBUG ("NSOpenGL context created: %lud\n", (guintptr) glContext);
175
176   context_cocoa->priv->gl_context = glContext;
177
178   [glView setOpenGLContext:glContext];
179
180 #else
181   /* FIXME try to make context sharing work in GNUstep */
182   context_cocoa->priv->gl_context = [glView openGLContext];
183 #endif
184
185   /* OpenGL context is made current only one time threre.
186    * Indeed, all OpenGL calls are made in only one thread,
187    * the Application thread */
188   [glContext makeCurrentContext];
189
190   [glContext update];
191
192   /* Back and front buffers are swapped only during the vertical retrace of the monitor.
193    * Discarded if you configured your driver to Never-use-V-Sync.
194    */
195   NS_DURING {
196     if (glContext) {
197 #ifdef GNUSTEP
198       const long swapInterval = 1;
199 #else
200       const GLint swapInterval = 1;
201 #endif
202       [[glView openGLContext] setValues:&swapInterval forParameter:NSOpenGLCPSwapInterval];
203     }
204   } NS_HANDLER {
205      GST_DEBUG ("your back-end does not implement NSOpenglContext::setValues\n");
206   }
207   NS_ENDHANDLER
208
209   GST_DEBUG ("opengl GstGLNSWindow initialized: %d x %d\n",
210     (gint) rect.size.width, (gint) rect.size.height);
211
212   [pool release];
213
214 #ifndef GNUSTEP
215   priv->source_id = g_timeout_add_seconds (1, gst_gl_window_cocoa_nsapp_iteration, NULL);
216 #endif
217
218   gst_object_unref (window);
219
220   return TRUE;
221 }
222
223 static void
224 gst_gl_context_cocoa_destroy_context (GstGLContext *context)
225 {
226 }
227
228 static guintptr
229 gst_gl_context_cocoa_get_gl_context (GstGLContext * context)
230 {
231   return (guintptr) GST_GL_CONTEXT_COCOA (context)->priv->gl_context;
232 }
233
234 static gboolean
235 gst_gl_context_cocoa_activate (GstGLContext * context, gboolean activate)
236 {
237   GstGLContextCocoa *context_cocoa;
238
239   context_cocoa = GST_GL_CONTEXT_COCOA (context);
240
241   if (activate)
242     [context_cocoa->priv->gl_context makeCurrentContext];
243 #if 0
244   else
245     /* FIXME */
246     [context_cocoa->priv->gl_context clearCurrentContext];
247 #endif
248   return TRUE;
249 }
250
251 static GstGLAPI
252 gst_gl_context_cocoa_get_gl_api (GstGLContext * context)
253 {
254   return GST_GL_API_OPENGL;
255 }