master
ブランチ master
cpputils / deps / glfw / src / nsgl_context.m
12 KB、376行 生 Blame 履歴
1//========================================================================
2// GLFW 3.3 macOS - www.glfw.org
3//------------------------------------------------------------------------
4// Copyright (c) 2009-2019 Camilla Löwy <elmindreda@glfw.org>
5//
6// This software is provided 'as-is', without any express or implied
7// warranty. In no event will the authors be held liable for any damages
8// arising from the use of this software.
9//
10// Permission is granted to anyone to use this software for any purpose,
11// including commercial applications, and to alter it and redistribute it
12// freely, subject to the following restrictions:
13//
14// 1. The origin of this software must not be misrepresented; you must not
15// claim that you wrote the original software. If you use this software
16// in a product, an acknowledgment in the product documentation would
17// be appreciated but is not required.
18//
19// 2. Altered source versions must be plainly marked as such, and must not
20// be misrepresented as being the original software.
21//
22// 3. This notice may not be removed or altered from any source
23// distribution.
24//
25//========================================================================
26// It is fine to use C99 in this file because it will not be built with VS
27//========================================================================
28
29#include "internal.h"
30
31#include <unistd.h>
32#include <math.h>
33
34static void makeContextCurrentNSGL(_GLFWwindow* window)
35{
36 @autoreleasepool {
37
38 if (window)
39 [window->context.nsgl.object makeCurrentContext];
40 else
41 [NSOpenGLContext clearCurrentContext];
42
43 _glfwPlatformSetTls(&_glfw.contextSlot, window);
44
45 } // autoreleasepool
46}
47
48static void swapBuffersNSGL(_GLFWwindow* window)
49{
50 @autoreleasepool {
51
52 // HACK: Simulate vsync with usleep as NSGL swap interval does not apply to
53 // windows with a non-visible occlusion state
54 if (!([window->ns.object occlusionState] & NSWindowOcclusionStateVisible))
55 {
56 int interval = 0;
57 [window->context.nsgl.object getValues:&interval
58 forParameter:NSOpenGLContextParameterSwapInterval];
59
60 if (interval > 0)
61 {
62 const double framerate = 60.0;
63 const uint64_t frequency = _glfwPlatformGetTimerFrequency();
64 const uint64_t value = _glfwPlatformGetTimerValue();
65
66 const double elapsed = value / (double) frequency;
67 const double period = 1.0 / framerate;
68 const double delay = period - fmod(elapsed, period);
69
70 usleep(floorl(delay * 1e6));
71 }
72 }
73
74 [window->context.nsgl.object flushBuffer];
75
76 } // autoreleasepool
77}
78
79static void swapIntervalNSGL(int interval)
80{
81 @autoreleasepool {
82
83 _GLFWwindow* window = _glfwPlatformGetTls(&_glfw.contextSlot);
84 if (window)
85 {
86 [window->context.nsgl.object setValues:&interval
87 forParameter:NSOpenGLContextParameterSwapInterval];
88 }
89
90 } // autoreleasepool
91}
92
93static int extensionSupportedNSGL(const char* extension)
94{
95 // There are no NSGL extensions
96 return GLFW_FALSE;
97}
98
99static GLFWglproc getProcAddressNSGL(const char* procname)
100{
101 CFStringRef symbolName = CFStringCreateWithCString(kCFAllocatorDefault,
102 procname,
103 kCFStringEncodingASCII);
104
105 GLFWglproc symbol = CFBundleGetFunctionPointerForName(_glfw.nsgl.framework,
106 symbolName);
107
108 CFRelease(symbolName);
109
110 return symbol;
111}
112
113static void destroyContextNSGL(_GLFWwindow* window)
114{
115 @autoreleasepool {
116
117 [window->context.nsgl.pixelFormat release];
118 window->context.nsgl.pixelFormat = nil;
119
120 [window->context.nsgl.object release];
121 window->context.nsgl.object = nil;
122
123 } // autoreleasepool
124}
125
126
127//////////////////////////////////////////////////////////////////////////
128////// GLFW internal API //////
129//////////////////////////////////////////////////////////////////////////
130
131// Initialize OpenGL support
132//
133GLFWbool _glfwInitNSGL(void)
134{
135 if (_glfw.nsgl.framework)
136 return GLFW_TRUE;
137
138 _glfw.nsgl.framework =
139 CFBundleGetBundleWithIdentifier(CFSTR("com.apple.opengl"));
140 if (_glfw.nsgl.framework == NULL)
141 {
142 _glfwInputError(GLFW_API_UNAVAILABLE,
143 "NSGL: Failed to locate OpenGL framework");
144 return GLFW_FALSE;
145 }
146
147 return GLFW_TRUE;
148}
149
150// Terminate OpenGL support
151//
152void _glfwTerminateNSGL(void)
153{
154}
155
156// Create the OpenGL context
157//
158GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window,
159 const _GLFWctxconfig* ctxconfig,
160 const _GLFWfbconfig* fbconfig)
161{
162 if (ctxconfig->client == GLFW_OPENGL_ES_API)
163 {
164 _glfwInputError(GLFW_API_UNAVAILABLE,
165 "NSGL: OpenGL ES is not available on macOS");
166 return GLFW_FALSE;
167 }
168
169 if (ctxconfig->major > 2)
170 {
171 if (ctxconfig->major == 3 && ctxconfig->minor < 2)
172 {
173 _glfwInputError(GLFW_VERSION_UNAVAILABLE,
174 "NSGL: The targeted version of macOS does not support OpenGL 3.0 or 3.1 but may support 3.2 and above");
175 return GLFW_FALSE;
176 }
177
178 if (!ctxconfig->forward || ctxconfig->profile != GLFW_OPENGL_CORE_PROFILE)
179 {
180 _glfwInputError(GLFW_VERSION_UNAVAILABLE,
181 "NSGL: The targeted version of macOS only supports forward-compatible core profile contexts for OpenGL 3.2 and above");
182 return GLFW_FALSE;
183 }
184 }
185
186 // Context robustness modes (GL_KHR_robustness) are not yet supported by
187 // macOS but are not a hard constraint, so ignore and continue
188
189 // Context release behaviors (GL_KHR_context_flush_control) are not yet
190 // supported by macOS but are not a hard constraint, so ignore and continue
191
192 // Debug contexts (GL_KHR_debug) are not yet supported by macOS but are not
193 // a hard constraint, so ignore and continue
194
195 // No-error contexts (GL_KHR_no_error) are not yet supported by macOS but
196 // are not a hard constraint, so ignore and continue
197
198#define addAttrib(a) \
199{ \
200 assert((size_t) index < sizeof(attribs) / sizeof(attribs[0])); \
201 attribs[index++] = a; \
202}
203#define setAttrib(a, v) { addAttrib(a); addAttrib(v); }
204
205 NSOpenGLPixelFormatAttribute attribs[40];
206 int index = 0;
207
208 addAttrib(NSOpenGLPFAAccelerated);
209 addAttrib(NSOpenGLPFAClosestPolicy);
210
211 if (ctxconfig->nsgl.offline)
212 {
213 addAttrib(NSOpenGLPFAAllowOfflineRenderers);
214 // NOTE: This replaces the NSSupportsAutomaticGraphicsSwitching key in
215 // Info.plist for unbundled applications
216 // HACK: This assumes that NSOpenGLPixelFormat will remain
217 // a straightforward wrapper of its CGL counterpart
218 addAttrib(kCGLPFASupportsAutomaticGraphicsSwitching);
219 }
220
221#if MAC_OS_X_VERSION_MAX_ALLOWED >= 101000
222 if (ctxconfig->major >= 4)
223 {
224 setAttrib(NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion4_1Core);
225 }
226 else
227#endif /*MAC_OS_X_VERSION_MAX_ALLOWED*/
228 if (ctxconfig->major >= 3)
229 {
230 setAttrib(NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core);
231 }
232
233 if (ctxconfig->major <= 2)
234 {
235 if (fbconfig->auxBuffers != GLFW_DONT_CARE)
236 setAttrib(NSOpenGLPFAAuxBuffers, fbconfig->auxBuffers);
237
238 if (fbconfig->accumRedBits != GLFW_DONT_CARE &&
239 fbconfig->accumGreenBits != GLFW_DONT_CARE &&
240 fbconfig->accumBlueBits != GLFW_DONT_CARE &&
241 fbconfig->accumAlphaBits != GLFW_DONT_CARE)
242 {
243 const int accumBits = fbconfig->accumRedBits +
244 fbconfig->accumGreenBits +
245 fbconfig->accumBlueBits +
246 fbconfig->accumAlphaBits;
247
248 setAttrib(NSOpenGLPFAAccumSize, accumBits);
249 }
250 }
251
252 if (fbconfig->redBits != GLFW_DONT_CARE &&
253 fbconfig->greenBits != GLFW_DONT_CARE &&
254 fbconfig->blueBits != GLFW_DONT_CARE)
255 {
256 int colorBits = fbconfig->redBits +
257 fbconfig->greenBits +
258 fbconfig->blueBits;
259
260 // macOS needs non-zero color size, so set reasonable values
261 if (colorBits == 0)
262 colorBits = 24;
263 else if (colorBits < 15)
264 colorBits = 15;
265
266 setAttrib(NSOpenGLPFAColorSize, colorBits);
267 }
268
269 if (fbconfig->alphaBits != GLFW_DONT_CARE)
270 setAttrib(NSOpenGLPFAAlphaSize, fbconfig->alphaBits);
271
272 if (fbconfig->depthBits != GLFW_DONT_CARE)
273 setAttrib(NSOpenGLPFADepthSize, fbconfig->depthBits);
274
275 if (fbconfig->stencilBits != GLFW_DONT_CARE)
276 setAttrib(NSOpenGLPFAStencilSize, fbconfig->stencilBits);
277
278 if (fbconfig->stereo)
279 {
280#if MAC_OS_X_VERSION_MAX_ALLOWED >= 101200
281 _glfwInputError(GLFW_FORMAT_UNAVAILABLE,
282 "NSGL: Stereo rendering is deprecated");
283 return GLFW_FALSE;
284#else
285 addAttrib(NSOpenGLPFAStereo);
286#endif
287 }
288
289 if (fbconfig->doublebuffer)
290 addAttrib(NSOpenGLPFADoubleBuffer);
291
292 if (fbconfig->samples != GLFW_DONT_CARE)
293 {
294 if (fbconfig->samples == 0)
295 {
296 setAttrib(NSOpenGLPFASampleBuffers, 0);
297 }
298 else
299 {
300 setAttrib(NSOpenGLPFASampleBuffers, 1);
301 setAttrib(NSOpenGLPFASamples, fbconfig->samples);
302 }
303 }
304
305 // NOTE: All NSOpenGLPixelFormats on the relevant cards support sRGB
306 // framebuffer, so there's no need (and no way) to request it
307
308 addAttrib(0);
309
310#undef addAttrib
311#undef setAttrib
312
313 window->context.nsgl.pixelFormat =
314 [[NSOpenGLPixelFormat alloc] initWithAttributes:attribs];
315 if (window->context.nsgl.pixelFormat == nil)
316 {
317 _glfwInputError(GLFW_FORMAT_UNAVAILABLE,
318 "NSGL: Failed to find a suitable pixel format");
319 return GLFW_FALSE;
320 }
321
322 NSOpenGLContext* share = nil;
323
324 if (ctxconfig->share)
325 share = ctxconfig->share->context.nsgl.object;
326
327 window->context.nsgl.object =
328 [[NSOpenGLContext alloc] initWithFormat:window->context.nsgl.pixelFormat
329 shareContext:share];
330 if (window->context.nsgl.object == nil)
331 {
332 _glfwInputError(GLFW_VERSION_UNAVAILABLE,
333 "NSGL: Failed to create OpenGL context");
334 return GLFW_FALSE;
335 }
336
337 if (fbconfig->transparent)
338 {
339 GLint opaque = 0;
340 [window->context.nsgl.object setValues:&opaque
341 forParameter:NSOpenGLContextParameterSurfaceOpacity];
342 }
343
344 [window->ns.view setWantsBestResolutionOpenGLSurface:window->ns.retina];
345
346 [window->context.nsgl.object setView:window->ns.view];
347
348 window->context.makeCurrent = makeContextCurrentNSGL;
349 window->context.swapBuffers = swapBuffersNSGL;
350 window->context.swapInterval = swapIntervalNSGL;
351 window->context.extensionSupported = extensionSupportedNSGL;
352 window->context.getProcAddress = getProcAddressNSGL;
353 window->context.destroy = destroyContextNSGL;
354
355 return GLFW_TRUE;
356}
357
358
359//////////////////////////////////////////////////////////////////////////
360////// GLFW native API //////
361//////////////////////////////////////////////////////////////////////////
362
363GLFWAPI id glfwGetNSGLContext(GLFWwindow* handle)
364{
365 _GLFWwindow* window = (_GLFWwindow*) handle;
366 _GLFW_REQUIRE_INIT_OR_RETURN(nil);
367
368 if (window->context.client == GLFW_NO_API)
369 {
370 _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
371 return nil;
372 }
373
374 return window->context.nsgl.object;
375}
376