2 * MACDRV Cocoa OpenGL code
4 * Copyright 2012, 2013 Ken Thomases for CodeWeavers Inc.
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include <OpenGL/gl.h>
22 #import "cocoa_opengl.h"
24 #include "macdrv_cocoa.h"
25 #include "cocoa_event.h"
28 @interface WineOpenGLContext ()
29 @property (retain, nonatomic) NSView* latentView;
33 @implementation WineOpenGLContext
34 @synthesize latentView, needsUpdate, shouldClearToBlack;
38 [[self view] release];
43 - (void) setView:(NSView*)newView
45 NSView* oldView = [self view];
46 [super setView:newView];
51 - (void) clearDrawable
53 NSView* oldView = [self view];
54 [super clearDrawable];
58 /* On at least some versions of Mac OS X, -[NSOpenGLContext clearDrawable] has the
59 undesirable side effect of ordering the view's GL surface off-screen. This isn't
60 done when just changing the context's view to a different view (which I would
61 think would be analogous, since the old view and surface end up without a
62 context attached). So, we finesse things by first setting the context's view to
63 a different view (the content view of an off-screen window) and then letting the
64 original implementation proceed. */
65 - (void) clearDrawableLeavingSurfaceOnScreen
67 static NSWindow* dummyWindow;
68 static dispatch_once_t once;
70 dispatch_once(&once, ^{
72 dummyWindow = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 100, 100)
73 styleMask:NSBorderlessWindowMask
74 backing:NSBackingStoreBuffered
79 [self setView:[dummyWindow contentView]];
83 - (void) clearToBlackIfNeeded
85 if (shouldClearToBlack)
87 NSOpenGLContext* origContext = [NSOpenGLContext currentContext];
88 const char *gl_version;
90 GLint draw_framebuffer_binding, draw_buffer;
91 GLboolean scissor_test, color_mask[4];
92 GLfloat clear_color[4];
94 [self makeCurrentContext];
96 gl_version = (const char *)glGetString(GL_VERSION);
97 major = gl_version[0] - '0';
98 /* FIXME: Should check for GL_ARB_framebuffer_object and GL_EXT_framebuffer_object
99 * for older GL versions. */
102 glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &draw_framebuffer_binding);
103 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
105 glGetIntegerv(GL_DRAW_BUFFER, &draw_buffer);
106 scissor_test = glIsEnabled(GL_SCISSOR_TEST);
107 glGetBooleanv(GL_COLOR_WRITEMASK, color_mask);
108 glGetFloatv(GL_COLOR_CLEAR_VALUE, clear_color);
109 glDrawBuffer(GL_FRONT_AND_BACK);
110 glDisable(GL_SCISSOR_TEST);
111 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
112 glClearColor(0, 0, 0, gl_surface_mode == GL_SURFACE_IN_FRONT_TRANSPARENT ? 0 : 1);
114 glClear(GL_COLOR_BUFFER_BIT);
116 glClearColor(clear_color[0], clear_color[1], clear_color[2], clear_color[3]);
117 glColorMask(color_mask[0], color_mask[1], color_mask[2], color_mask[3]);
119 glEnable(GL_SCISSOR_TEST);
120 glDrawBuffer(draw_buffer);
122 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, draw_framebuffer_binding);
126 [origContext makeCurrentContext];
128 [NSOpenGLContext clearCurrentContext];
130 shouldClearToBlack = FALSE;
134 - (void) removeFromViews:(BOOL)removeViews
138 macdrv_remove_view_opengl_context((macdrv_view)[self view], (macdrv_opengl_context)self);
140 [self clearDrawableLeavingSurfaceOnScreen];
142 if ([self latentView])
144 macdrv_remove_view_opengl_context((macdrv_view)[self latentView], (macdrv_opengl_context)self);
146 [self setLatentView:nil];
154 /***********************************************************************
155 * macdrv_create_opengl_context
157 * Returns a Cocoa OpenGL context created from a CoreGL context. The
158 * caller is responsible for calling macdrv_dispose_opengl_context()
159 * when done with the context object.
161 macdrv_opengl_context macdrv_create_opengl_context(void* cglctx)
163 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
164 WineOpenGLContext *context;
166 context = [[WineOpenGLContext alloc] initWithCGLContextObj:cglctx];
169 return (macdrv_opengl_context)context;
172 /***********************************************************************
173 * macdrv_dispose_opengl_context
175 * Destroys a Cocoa OpenGL context previously created by
176 * macdrv_create_opengl_context();
178 void macdrv_dispose_opengl_context(macdrv_opengl_context c)
180 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
181 WineOpenGLContext *context = (WineOpenGLContext*)c;
183 [context removeFromViews:YES];
189 /***********************************************************************
190 * macdrv_make_context_current
192 void macdrv_make_context_current(macdrv_opengl_context c, macdrv_view v)
194 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
195 WineOpenGLContext *context = (WineOpenGLContext*)c;
196 NSView* view = (NSView*)v;
200 if (view == [context view] || view == [context latentView])
201 macdrv_update_opengl_context(c);
204 [context removeFromViews:NO];
205 macdrv_add_view_opengl_context(v, c);
207 if (context.needsUpdate)
209 context.needsUpdate = FALSE;
210 [context setView:view];
211 [context setLatentView:nil];
216 [context clearDrawableLeavingSurfaceOnScreen];
217 [context setLatentView:view];
221 [context makeCurrentContext];
224 [context clearToBlackIfNeeded];
228 WineOpenGLContext* currentContext = (WineOpenGLContext*)[WineOpenGLContext currentContext];
230 if ([currentContext isKindOfClass:[WineOpenGLContext class]])
232 [WineOpenGLContext clearCurrentContext];
233 if (currentContext != context)
234 [currentContext removeFromViews:YES];
238 [context removeFromViews:YES];
244 /***********************************************************************
245 * macdrv_update_opengl_context
247 void macdrv_update_opengl_context(macdrv_opengl_context c)
249 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
250 WineOpenGLContext *context = (WineOpenGLContext*)c;
252 if (context.needsUpdate)
254 context.needsUpdate = FALSE;
255 if (context.latentView)
257 [context setView:context.latentView];
258 context.latentView = nil;
260 [context clearToBlackIfNeeded];
269 /***********************************************************************
270 * macdrv_flush_opengl_context
272 * Performs an implicit glFlush() and then swaps the back buffer to the
273 * front (if the context is double-buffered).
275 void macdrv_flush_opengl_context(macdrv_opengl_context c)
277 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
278 WineOpenGLContext *context = (WineOpenGLContext*)c;
280 macdrv_update_opengl_context(c);
281 [context flushBuffer];