winemac: Clear OpenGL views to black the first time a context is attached.
[wine.git] / dlls / winemac.drv / cocoa_opengl.m
blob13b9ea3e88b518c8c8d13650385a51968e659703
1 /*
2  * MACDRV Cocoa OpenGL code
3  *
4  * Copyright 2012, 2013 Ken Thomases for CodeWeavers Inc.
5  *
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.
10  *
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.
15  *
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
19  */
21 #import "cocoa_opengl.h"
23 #include "macdrv_cocoa.h"
24 #include "cocoa_event.h"
27 @interface WineOpenGLContext ()
28 @property (retain, nonatomic) NSView* latentView;
29 @end
32 @implementation WineOpenGLContext
33 @synthesize latentView, needsUpdate, shouldClearToBlack;
35     - (void) dealloc
36     {
37         [latentView release];
38         [super dealloc];
39     }
41     /* On at least some versions of Mac OS X, -[NSOpenGLContext clearDrawable] has the
42        undesirable side effect of ordering the view's GL surface off-screen.  This isn't
43        done when just changing the context's view to a different view (which I would
44        think would be analogous, since the old view and surface end up without a
45        context attached).  So, we finesse things by first setting the context's view to
46        a different view (the content view of an off-screen window) and then letting the
47        original implementation proceed. */
48     - (void) clearDrawableLeavingSurfaceOnScreen
49     {
50         static NSWindow* dummyWindow;
51         static dispatch_once_t once;
53         dispatch_once(&once, ^{
54             OnMainThread(^{
55                 dummyWindow = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 100, 100)
56                                                           styleMask:NSBorderlessWindowMask
57                                                             backing:NSBackingStoreBuffered
58                                                               defer:NO];
59             });
60         });
62         [self setView:[dummyWindow contentView]];
63         [self clearDrawable];
64     }
66     - (void) clearToBlackIfNeeded
67     {
68         if (shouldClearToBlack)
69         {
70             NSOpenGLContext* origContext = [NSOpenGLContext currentContext];
72             [self makeCurrentContext];
74             glPushAttrib(GL_COLOR_BUFFER_BIT | GL_SCISSOR_BIT);
75             glDrawBuffer(GL_FRONT_AND_BACK);
76             glDisable(GL_SCISSOR_TEST);
77             glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
78             glClearColor(0, 0, 0, 1);
79             glClear(GL_COLOR_BUFFER_BIT);
80             glPopAttrib();
81             glFlush();
83             if (origContext)
84                 [origContext makeCurrentContext];
85             else
86                 [NSOpenGLContext clearCurrentContext];
88             shouldClearToBlack = FALSE;
89         }
90     }
92 @end
95 /***********************************************************************
96  *              macdrv_create_opengl_context
97  *
98  * Returns a Cocoa OpenGL context created from a CoreGL context.  The
99  * caller is responsible for calling macdrv_dispose_opengl_context()
100  * when done with the context object.
101  */
102 macdrv_opengl_context macdrv_create_opengl_context(void* cglctx)
104     NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
105     WineOpenGLContext *context;
107     context = [[WineOpenGLContext alloc] initWithCGLContextObj:cglctx];
109     [pool release];
110     return (macdrv_opengl_context)context;
113 /***********************************************************************
114  *              macdrv_dispose_opengl_context
116  * Destroys a Cocoa OpenGL context previously created by
117  * macdrv_create_opengl_context();
118  */
119 void macdrv_dispose_opengl_context(macdrv_opengl_context c)
121     NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
122     WineOpenGLContext *context = (WineOpenGLContext*)c;
124     if ([context view])
125         macdrv_remove_view_opengl_context((macdrv_view)[context view], c);
126     if ([context latentView])
127         macdrv_remove_view_opengl_context((macdrv_view)[context latentView], c);
128     [context clearDrawableLeavingSurfaceOnScreen];
129     [context release];
131     [pool release];
134 /***********************************************************************
135  *              macdrv_make_context_current
136  */
137 void macdrv_make_context_current(macdrv_opengl_context c, macdrv_view v)
139     NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
140     WineOpenGLContext *context = (WineOpenGLContext*)c;
141     NSView* view = (NSView*)v;
143     if (context)
144     {
145         if ([context view])
146             macdrv_remove_view_opengl_context((macdrv_view)[context view], c);
147         if ([context latentView])
148             macdrv_remove_view_opengl_context((macdrv_view)[context latentView], c);
149         context.needsUpdate = FALSE;
150         if (view)
151         {
152             macdrv_add_view_opengl_context(v, c);
154             if (context.needsUpdate)
155             {
156                 context.needsUpdate = FALSE;
157                 [context setView:view];
158                 [context setLatentView:nil];
159             }
160             else
161                 [context setLatentView:view];
163             [context makeCurrentContext];
165             if ([context view])
166                 [context clearToBlackIfNeeded];
167         }
168         else
169         {
170             [WineOpenGLContext clearCurrentContext];
171             [context clearDrawableLeavingSurfaceOnScreen];
172         }
173     }
174     else
175         [WineOpenGLContext clearCurrentContext];
177     [pool release];
180 /***********************************************************************
181  *              macdrv_update_opengl_context
182  */
183 void macdrv_update_opengl_context(macdrv_opengl_context c)
185     NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
186     WineOpenGLContext *context = (WineOpenGLContext*)c;
188     if (context.needsUpdate)
189     {
190         context.needsUpdate = FALSE;
191         if (context.latentView)
192         {
193             [context setView:context.latentView];
194             context.latentView = nil;
196             [context clearToBlackIfNeeded];
197         }
198         else
199             [context update];
200     }
202     [pool release];
205 /***********************************************************************
206  *              macdrv_flush_opengl_context
208  * Performs an implicit glFlush() and then swaps the back buffer to the
209  * front (if the context is double-buffered).
210  */
211 void macdrv_flush_opengl_context(macdrv_opengl_context c)
213     NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
214     WineOpenGLContext *context = (WineOpenGLContext*)c;
216     macdrv_update_opengl_context(c);
217     [context flushBuffer];
219     [pool release];