1 /* GDK - The GIMP Drawing Kit
2  *
3  * gdkglcontext-quartz.c: Quartz specific OpenGL wrappers
4  *
5  * Copyright © 2014  Emmanuele Bassi
6  * Copyright © 2014  Alexander Larsson
7  * Copyright © 2014  Brion Vibber
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Library General Public
11  * License as published by the Free Software Foundation; either
12  * version 2 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Library General Public License for more details.
18  *
19  * You should have received a copy of the GNU Library General Public
20  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
21  */
22 
23 #include "config.h"
24 
25 #include "gdkglcontext-quartz.h"
26 
27 #include "gdkquartzdisplay.h"
28 #include "gdkquartzglcontext.h"
29 #include "gdkquartzwindow.h"
30 #include "gdkprivate-quartz.h"
31 #include "gdkquartz-cocoa-access.h"
32 
33 #include "gdkinternals.h"
34 
35 #include "gdkintl.h"
36 
37 G_DEFINE_TYPE (GdkQuartzGLContext, gdk_quartz_gl_context, GDK_TYPE_GL_CONTEXT)
38 
39 static void gdk_quartz_gl_context_dispose (GObject *gobject);
40 
41 void
gdk_quartz_window_invalidate_for_new_frame(GdkWindow * window,cairo_region_t * update_area)42 gdk_quartz_window_invalidate_for_new_frame (GdkWindow      *window,
43                                             cairo_region_t *update_area)
44 {
45   cairo_rectangle_int_t window_rect;
46 
47   /* Minimal update is ok if we're not drawing with gl */
48   if (window->gl_paint_context == NULL)
49     return;
50 
51   window_rect.x = 0;
52   window_rect.y = 0;
53   window_rect.width = gdk_window_get_width (window);
54   window_rect.height = gdk_window_get_height (window);
55 
56   /* If nothing else is known, repaint everything so that the back
57   buffer is fully up-to-date for the swapbuffer */
58   cairo_region_union_rectangle (update_area, &window_rect);
59 }
60 
61 static gboolean
gdk_quartz_gl_context_realize(GdkGLContext * context,GError ** error)62 gdk_quartz_gl_context_realize (GdkGLContext *context,
63                                GError      **error)
64 {
65   return TRUE;
66 }
67 
68 static void
gdk_quartz_gl_context_end_frame(GdkGLContext * context,cairo_region_t * painted,cairo_region_t * damage)69 gdk_quartz_gl_context_end_frame (GdkGLContext *context,
70                                  cairo_region_t *painted,
71                                  cairo_region_t *damage)
72 {
73   GdkQuartzGLContext *context_quartz = GDK_QUARTZ_GL_CONTEXT (context);
74 
75   [context_quartz->gl_context flushBuffer];
76 }
77 
78 static void
gdk_quartz_gl_context_class_init(GdkQuartzGLContextClass * klass)79 gdk_quartz_gl_context_class_init (GdkQuartzGLContextClass *klass)
80 {
81   GdkGLContextClass *context_class = GDK_GL_CONTEXT_CLASS (klass);
82   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
83 
84   context_class->realize = gdk_quartz_gl_context_realize;
85   context_class->end_frame = gdk_quartz_gl_context_end_frame;
86   gobject_class->dispose = gdk_quartz_gl_context_dispose;
87 }
88 
89 static void
gdk_quartz_gl_context_init(GdkQuartzGLContext * self)90 gdk_quartz_gl_context_init (GdkQuartzGLContext *self)
91 {
92 }
93 
94 gboolean
gdk_quartz_display_init_gl(GdkDisplay * display)95 gdk_quartz_display_init_gl (GdkDisplay *display)
96 {
97   return TRUE;
98 }
99 
100 GdkGLContext *
gdk_quartz_window_create_gl_context(GdkWindow * window,gboolean attached,GdkGLContext * share,GError ** error)101 gdk_quartz_window_create_gl_context (GdkWindow     *window,
102                                      gboolean       attached,
103                                      GdkGLContext  *share,
104                                      GError       **error)
105 {
106   GdkDisplay *display = gdk_window_get_display (window);
107   GdkQuartzGLContext *context;
108   NSOpenGLContext *ctx;
109   NSOpenGLPixelFormatAttribute attrs[] =
110     {
111       NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core,
112       NSOpenGLPFADoubleBuffer,
113       NSOpenGLPFAColorSize, 24,
114       NSOpenGLPFAAlphaSize, 8,
115       0
116     };
117   NSOpenGLPixelFormat *format = [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs];
118 
119   if (format == NULL)
120     {
121       g_set_error_literal (error, GDK_GL_ERROR,
122                            GDK_GL_ERROR_NOT_AVAILABLE,
123                            _("Unable to create a GL pixel format"));
124       return NULL;
125     }
126 
127   ctx = [[NSOpenGLContext alloc] initWithFormat:format
128                                  shareContext:share ? GDK_QUARTZ_GL_CONTEXT (share)->gl_context : nil];
129   if (ctx == NULL)
130     {
131       g_set_error_literal (error, GDK_GL_ERROR,
132                            GDK_GL_ERROR_NOT_AVAILABLE,
133                            _("Unable to create a GL context"));
134       return NULL;
135     }
136 
137   [format release];
138 
139   if (attached)
140     {
141       NSView *view = gdk_quartz_window_get_nsview (window);
142 
143       if ([view respondsToSelector:@selector(setWantsBestResolutionOpenGLSurface:)])
144         [view setWantsBestResolutionOpenGLSurface:YES];
145 
146       GLint sync_to_framerate = 1;
147       [ctx setValues:&sync_to_framerate forParameter:NSOpenGLCPSwapInterval];
148 
149       [ctx setView:view];
150     }
151 
152   GDK_NOTE (OPENGL,
153             g_print ("Created NSOpenGLContext[%p]\n", ctx));
154 
155   context = g_object_new (GDK_TYPE_QUARTZ_GL_CONTEXT,
156                           "window", window,
157                           "display", display,
158                           "shared-context", share,
159                           NULL);
160 
161   context->gl_context = ctx;
162   context->is_attached = attached;
163 
164   return GDK_GL_CONTEXT (context);
165 }
166 
167 static void
gdk_quartz_gl_context_dispose(GObject * gobject)168 gdk_quartz_gl_context_dispose (GObject *gobject)
169 {
170   GdkQuartzGLContext *context_quartz = GDK_QUARTZ_GL_CONTEXT (gobject);
171 
172   if (context_quartz->gl_context != NULL)
173     {
174       [context_quartz->gl_context clearDrawable];
175       [context_quartz->gl_context release];
176       context_quartz->gl_context = NULL;
177     }
178 
179   G_OBJECT_CLASS (gdk_quartz_gl_context_parent_class)->dispose (gobject);
180 }
181 
182 gboolean
gdk_quartz_display_make_gl_context_current(GdkDisplay * display,GdkGLContext * context)183 gdk_quartz_display_make_gl_context_current (GdkDisplay   *display,
184                                             GdkGLContext *context)
185 {
186   GdkQuartzGLContext *context_quartz;
187 
188   if (context == NULL)
189     {
190       [NSOpenGLContext clearCurrentContext];
191       return TRUE;
192     }
193 
194   context_quartz = GDK_QUARTZ_GL_CONTEXT (context);
195 
196   [context_quartz->gl_context makeCurrentContext];
197 
198   return TRUE;
199 }
200