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