]> git.cworth.org Git - apitrace/blob - retrace/glws_cocoa.mm
image: Fix PNM dumping for 2/4 channels.
[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 "os_thread.hpp"
51 #include "glws.hpp"
52
53
54 /**
55  * Dummy thread to force Cocoa to enter multithreading mode.
56  */
57 @interface DummyThread : NSObject
58     + (void)enterMultiThreaded;
59     + (void)dummyThreadMethod:(id)unused;
60 @end
61
62 @implementation DummyThread
63     + (void)dummyThreadMethod:(id)unused {
64         (void)unused;
65     }
66
67     + (void)enterMultiThreaded {
68         [NSThread detachNewThreadSelector:@selector(dummyThreadMethod:)
69                   toTarget:self
70                   withObject:nil];
71     }
72 @end
73
74
75 namespace glws {
76
77
78 static OS_THREAD_SPECIFIC_PTR(NSAutoreleasePool)
79 autoreleasePool;
80
81
82 class CocoaVisual : public Visual
83 {
84 public:
85     NSOpenGLPixelFormat *pixelFormat;
86
87     CocoaVisual(NSOpenGLPixelFormat *pf) :
88         pixelFormat(pf)
89     {}
90
91     ~CocoaVisual() {
92         [pixelFormat release];
93     }
94 };
95  
96
97 class CocoaDrawable : public Drawable
98 {
99 public:
100     NSWindow *window;
101     NSOpenGLView *view;
102     NSOpenGLContext *currentContext;
103
104     CocoaDrawable(const Visual *vis, int w, int h, bool pbuffer) :
105         Drawable(vis, w, h, pbuffer),
106         currentContext(nil)
107     {
108         NSOpenGLPixelFormat *pixelFormat = static_cast<const CocoaVisual *>(visual)->pixelFormat;
109
110         NSRect winRect = NSMakeRect(0, 0, w, h);
111
112         window = [[NSWindow alloc]
113                          initWithContentRect:winRect
114                                    styleMask:NSTitledWindowMask |
115                                              NSClosableWindowMask |
116                                              NSMiniaturizableWindowMask
117                                      backing:NSBackingStoreRetained
118                                        defer:NO];
119         assert(window != nil);
120
121         view = [[NSOpenGLView alloc]
122                 initWithFrame:winRect
123                   pixelFormat:pixelFormat];
124         assert(view != nil);
125
126         [window setContentView:view];
127         [window setTitle:@"glretrace"];
128
129     }
130
131     ~CocoaDrawable() {
132         [window release];
133     }
134
135     void
136     resize(int w, int h) {
137         if (w == width && h == height) {
138             return;
139         }
140
141         [window setContentSize:NSMakeSize(w, h)];
142
143         if (currentContext != nil) {
144             [currentContext update];
145             [window makeKeyAndOrderFront:nil];
146             [currentContext setView:view];
147             [currentContext makeCurrentContext];
148         }
149
150         Drawable::resize(w, h);
151     }
152
153     void show(void) {
154         if (visible) {
155             return;
156         }
157
158         // TODO
159
160         Drawable::show();
161     }
162
163     void swapBuffers(void) {
164         if (currentContext != nil) {
165             [currentContext flushBuffer];
166         }
167     }
168 };
169
170
171 class CocoaContext : public Context
172 {
173 public:
174     NSOpenGLContext *context;
175
176     CocoaContext(const Visual *vis, Profile prof, NSOpenGLContext *ctx) :
177         Context(vis, prof),
178         context(ctx)
179     {}
180
181     ~CocoaContext() {
182         [context release];
183     }
184 };
185
186
187 static inline void
188 initThread(void) {
189     if (autoreleasePool == nil) {
190         autoreleasePool = [[NSAutoreleasePool alloc] init];
191     }
192 }
193
194 void
195 init(void) {
196     // Prevent glproc to load system's OpenGL, so that we can trace glretrace.
197     _libGlHandle = dlopen("OpenGL", RTLD_LOCAL | RTLD_NOW | RTLD_FIRST);
198
199     initThread();
200
201     [DummyThread enterMultiThreaded];
202
203     bool isMultiThreaded = [NSThread isMultiThreaded];
204     if (!isMultiThreaded) {
205         std::cerr << "error: failed to enable Cocoa multi-threading\n";
206         exit(1);
207     }
208
209     [NSApplication sharedApplication];
210
211     [NSApp finishLaunching];
212 }
213
214
215 void
216 cleanup(void) {
217     [autoreleasePool release];
218 }
219
220
221 Visual *
222 createVisual(bool doubleBuffer, Profile profile) {
223
224     initThread();
225
226     if (profile != PROFILE_COMPAT &&
227         profile != PROFILE_CORE) {
228         return nil;
229     }
230
231     Attributes<NSOpenGLPixelFormatAttribute> attribs;
232
233     attribs.add(NSOpenGLPFAAlphaSize, (NSOpenGLPixelFormatAttribute)1);
234     attribs.add(NSOpenGLPFAColorSize, (NSOpenGLPixelFormatAttribute)24);
235     if (doubleBuffer) {
236         attribs.add(NSOpenGLPFADoubleBuffer);
237     }
238     attribs.add(NSOpenGLPFADepthSize, (NSOpenGLPixelFormatAttribute)1);
239     attribs.add(NSOpenGLPFAStencilSize, (NSOpenGLPixelFormatAttribute)1);
240     if (profile == PROFILE_CORE) {
241 #if CGL_VERSION_1_3
242         attribs.add(NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core);
243 #else
244         return NULL;
245 #endif
246     }
247     
248     // Use Apple software rendering for debugging purposes.
249     if (0) {
250         attribs.add(NSOpenGLPFARendererID, 0x00020200); // kCGLRendererGenericID
251     }
252
253     attribs.end();
254
255     NSOpenGLPixelFormat *pixelFormat = [[NSOpenGLPixelFormat alloc]
256                                      initWithAttributes:attribs];
257
258     return new CocoaVisual(pixelFormat);
259 }
260
261 Drawable *
262 createDrawable(const Visual *visual, int width, int height, bool pbuffer)
263 {
264     initThread();
265
266     return new CocoaDrawable(visual, width, height, pbuffer);
267 }
268
269 Context *
270 createContext(const Visual *visual, Context *shareContext, Profile profile, bool debug)
271 {
272     initThread();
273
274     NSOpenGLPixelFormat *pixelFormat = static_cast<const CocoaVisual *>(visual)->pixelFormat;
275     NSOpenGLContext *share_context = nil;
276     NSOpenGLContext *context;
277
278     if (profile != PROFILE_COMPAT &&
279         profile != PROFILE_CORE) {
280         return nil;
281     }
282
283     if (shareContext) {
284         share_context = static_cast<CocoaContext*>(shareContext)->context;
285     }
286
287     context = [[NSOpenGLContext alloc]
288                initWithFormat:pixelFormat
289                shareContext:share_context];
290     assert(context != nil);
291
292     return new CocoaContext(visual, profile, context);
293 }
294
295 bool
296 makeCurrent(Drawable *drawable, Context *context)
297 {
298     initThread();
299
300     if (!drawable || !context) {
301         [NSOpenGLContext clearCurrentContext];
302     } else {
303         CocoaDrawable *cocoaDrawable = static_cast<CocoaDrawable *>(drawable);
304         CocoaContext *cocoaContext = static_cast<CocoaContext *>(context);
305
306         [cocoaDrawable->window makeKeyAndOrderFront:nil];
307         [cocoaContext->context setView:[cocoaDrawable->window contentView]];
308         [cocoaContext->context makeCurrentContext];
309
310         cocoaDrawable->currentContext = cocoaContext->context;
311     }
312
313     return TRUE;
314 }
315
316 bool
317 processEvents(void) {
318     initThread();
319
320     NSEvent* event;
321     do {
322         event = [NSApp nextEventMatchingMask:NSAnyEventMask
323                                    untilDate:[NSDate distantPast]
324                                       inMode:NSDefaultRunLoopMode
325                                      dequeue:YES];
326         if (event)
327             [NSApp sendEvent:event];
328     } while (event);
329
330     return true;
331 }
332
333
334 } /* namespace glws */