]> git.cworth.org Git - apitrace/blob - retrace/glws_cocoa.mm
Use skiplist-based FastCallSet within trace::CallSet
[apitrace] / retrace / glws_cocoa.mm
1 /**************************************************************************
2  *
3  * Copyright 2011 VMware, Inc.
4  * All Rights Reserved.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22  * THE SOFTWARE.
23  *
24  **************************************************************************/
25
26
27 /**
28  * Minimal Cocoa integration.
29  *
30  * See also:
31  * - http://developer.apple.com/library/mac/#samplecode/CocoaGL/Introduction/Intro.html
32  * - http://developer.apple.com/library/mac/#samplecode/Cocoa_With_Carbon_or_CPP/Introduction/Intro.html
33  * - http://developer.apple.com/library/mac/#samplecode/glut/Introduction/Intro.html
34  * - http://developer.apple.com/library/mac/#samplecode/GLEssentials/Introduction/Intro.html
35  * - http://www.glfw.org/
36  * - http://cocoasamurai.blogspot.co.uk/2008/04/guide-to-threading-on-leopard.html
37  * - http://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/Multithreading/Introduction/Introduction.html
38  */
39
40
41 #include "glproc.hpp"
42
43 #include <stdlib.h>
44 #include <iostream>
45
46 #include <dlfcn.h>
47
48 #include <Cocoa/Cocoa.h>
49
50 #include "glws.hpp"
51
52
53 /**
54  * Dummy thread to force Cocoa to enter multithreading mode.
55  */
56 @interface DummyThread : NSObject
57     + (void)enterMultiThreaded;
58     + (void)dummyThreadMethod:(id)unused;
59 @end
60
61 @implementation DummyThread
62     + (void)dummyThreadMethod:(id)unused {
63         (void)unused;
64     }
65
66     + (void)enterMultiThreaded {
67         [NSThread detachNewThreadSelector:@selector(dummyThreadMethod:)
68                   toTarget:self
69                   withObject:nil];
70     }
71 @end
72
73
74 namespace glws {
75
76
77 static __thread NSAutoreleasePool *
78 autoreleasePool = nil;
79
80
81 class CocoaVisual : public Visual
82 {
83 public:
84     NSOpenGLPixelFormat *pixelFormat;
85
86     CocoaVisual(NSOpenGLPixelFormat *pf) :
87         pixelFormat(pf)
88     {}
89
90     ~CocoaVisual() {
91         [pixelFormat release];
92     }
93 };
94  
95
96 class CocoaDrawable : public Drawable
97 {
98 public:
99     NSWindow *window;
100     NSOpenGLView *view;
101     NSOpenGLContext *currentContext;
102
103     CocoaDrawable(const Visual *vis, int w, int h, bool pbuffer) :
104         Drawable(vis, w, h, pbuffer),
105         currentContext(nil)
106     {
107         NSOpenGLPixelFormat *pixelFormat = static_cast<const CocoaVisual *>(visual)->pixelFormat;
108
109         NSRect winRect = NSMakeRect(0, 0, w, h);
110
111         window = [[NSWindow alloc]
112                          initWithContentRect:winRect
113                                    styleMask:NSTitledWindowMask |
114                                              NSClosableWindowMask |
115                                              NSMiniaturizableWindowMask
116                                      backing:NSBackingStoreRetained
117                                        defer:NO];
118         assert(window != nil);
119
120         view = [[NSOpenGLView alloc]
121                 initWithFrame:winRect
122                   pixelFormat:pixelFormat];
123         assert(view != nil);
124
125         [window setContentView:view];
126         [window setTitle:@"glretrace"];
127
128     }
129
130     ~CocoaDrawable() {
131         [window release];
132     }
133
134     void
135     resize(int w, int h) {
136         if (w == width && h == height) {
137             return;
138         }
139
140         [window setContentSize:NSMakeSize(w, h)];
141
142         if (currentContext != nil) {
143             [currentContext update];
144             [window makeKeyAndOrderFront:nil];
145             [currentContext setView:view];
146             [currentContext makeCurrentContext];
147         }
148
149         Drawable::resize(w, h);
150     }
151
152     void show(void) {
153         if (visible) {
154             return;
155         }
156
157         // TODO
158
159         Drawable::show();
160     }
161
162     void swapBuffers(void) {
163         if (currentContext != nil) {
164             [currentContext flushBuffer];
165         }
166     }
167 };
168
169
170 class CocoaContext : public Context
171 {
172 public:
173     NSOpenGLContext *context;
174
175     CocoaContext(const Visual *vis, Profile prof, NSOpenGLContext *ctx) :
176         Context(vis, prof),
177         context(ctx)
178     {}
179
180     ~CocoaContext() {
181         [context release];
182     }
183 };
184
185
186 static inline void
187 initThread(void) {
188     if (autoreleasePool == nil) {
189         autoreleasePool = [[NSAutoreleasePool alloc] init];
190     }
191 }
192
193 void
194 init(void) {
195     // Prevent glproc to load system's OpenGL, so that we can trace glretrace.
196     _libGlHandle = dlopen("OpenGL", RTLD_LOCAL | RTLD_NOW | RTLD_FIRST);
197
198     initThread();
199
200     [DummyThread enterMultiThreaded];
201
202     bool isMultiThreaded = [NSThread isMultiThreaded];
203     if (!isMultiThreaded) {
204         std::cerr << "error: failed to enable Cocoa multi-threading\n";
205         exit(1);
206     }
207
208     [NSApplication sharedApplication];
209
210     [NSApp finishLaunching];
211 }
212
213
214 void
215 cleanup(void) {
216     [autoreleasePool release];
217 }
218
219
220 Visual *
221 createVisual(bool doubleBuffer, Profile profile) {
222
223     initThread();
224
225     if (profile != PROFILE_COMPAT &&
226         profile != PROFILE_CORE) {
227         return nil;
228     }
229
230     Attributes<NSOpenGLPixelFormatAttribute> attribs;
231
232     attribs.add(NSOpenGLPFAAlphaSize, (NSOpenGLPixelFormatAttribute)1);
233     attribs.add(NSOpenGLPFAColorSize, (NSOpenGLPixelFormatAttribute)24);
234     if (doubleBuffer) {
235         attribs.add(NSOpenGLPFADoubleBuffer);
236     }
237     attribs.add(NSOpenGLPFADepthSize, (NSOpenGLPixelFormatAttribute)1);
238     attribs.add(NSOpenGLPFAStencilSize, (NSOpenGLPixelFormatAttribute)1);
239     if (profile == PROFILE_CORE) {
240 #if CGL_VERSION_1_3
241         attribs.add(NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core);
242 #else
243         return NULL;
244 #endif
245     }
246     
247     // Use Apple software rendering for debugging purposes.
248     if (0) {
249         attribs.add(NSOpenGLPFARendererID, 0x00020200); // kCGLRendererGenericID
250     }
251
252     attribs.end();
253
254     NSOpenGLPixelFormat *pixelFormat = [[NSOpenGLPixelFormat alloc]
255                                      initWithAttributes:attribs];
256
257     return new CocoaVisual(pixelFormat);
258 }
259
260 Drawable *
261 createDrawable(const Visual *visual, int width, int height, bool pbuffer)
262 {
263     initThread();
264
265     return new CocoaDrawable(visual, width, height, pbuffer);
266 }
267
268 Context *
269 createContext(const Visual *visual, Context *shareContext, Profile profile, bool debug)
270 {
271     initThread();
272
273     NSOpenGLPixelFormat *pixelFormat = static_cast<const CocoaVisual *>(visual)->pixelFormat;
274     NSOpenGLContext *share_context = nil;
275     NSOpenGLContext *context;
276
277     if (profile != PROFILE_COMPAT &&
278         profile != PROFILE_CORE) {
279         return nil;
280     }
281
282     if (shareContext) {
283         share_context = static_cast<CocoaContext*>(shareContext)->context;
284     }
285
286     context = [[NSOpenGLContext alloc]
287                initWithFormat:pixelFormat
288                shareContext:share_context];
289     assert(context != nil);
290
291     return new CocoaContext(visual, profile, context);
292 }
293
294 bool
295 makeCurrent(Drawable *drawable, Context *context)
296 {
297     initThread();
298
299     if (!drawable || !context) {
300         [NSOpenGLContext clearCurrentContext];
301     } else {
302         CocoaDrawable *cocoaDrawable = static_cast<CocoaDrawable *>(drawable);
303         CocoaContext *cocoaContext = static_cast<CocoaContext *>(context);
304
305         [cocoaDrawable->window makeKeyAndOrderFront:nil];
306         [cocoaContext->context setView:[cocoaDrawable->window contentView]];
307         [cocoaContext->context makeCurrentContext];
308
309         cocoaDrawable->currentContext = cocoaContext->context;
310     }
311
312     return TRUE;
313 }
314
315 bool
316 processEvents(void) {
317     initThread();
318
319     NSEvent* event;
320     do {
321         event = [NSApp nextEventMatchingMask:NSAnyEventMask
322                                    untilDate:[NSDate distantPast]
323                                       inMode:NSDefaultRunLoopMode
324                                      dequeue:YES];
325         if (event)
326             [NSApp sendEvent:event];
327     } while (event);
328
329     return true;
330 }
331
332
333 } /* namespace glws */