]> git.sesse.net Git - pistorm/blob - raylib/external/glfw/src/nsgl_context.m
Update raylib files and Makefile for Pi 4 testing
[pistorm] / raylib / external / glfw / src / nsgl_context.m
1 //========================================================================
2 // GLFW 3.4 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
34 static 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
48 static 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.occluded)
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
79 static 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
93 static int extensionSupportedNSGL(const char* extension)
94 {
95     // There are no NSGL extensions
96     return GLFW_FALSE;
97 }
98
99 static 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
113 static 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 //
133 GLFWbool _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 //
152 void _glfwTerminateNSGL(void)
153 {
154 }
155
156 // Create the OpenGL context
157 //
158 GLFWbool _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
179     // Context robustness modes (GL_KHR_robustness) are not yet supported by
180     // macOS but are not a hard constraint, so ignore and continue
181
182     // Context release behaviors (GL_KHR_context_flush_control) are not yet
183     // supported by macOS but are not a hard constraint, so ignore and continue
184
185     // Debug contexts (GL_KHR_debug) are not yet supported by macOS but are not
186     // a hard constraint, so ignore and continue
187
188     // No-error contexts (GL_KHR_no_error) are not yet supported by macOS but
189     // are not a hard constraint, so ignore and continue
190
191 #define addAttrib(a) \
192 { \
193     assert((size_t) index < sizeof(attribs) / sizeof(attribs[0])); \
194     attribs[index++] = a; \
195 }
196 #define setAttrib(a, v) { addAttrib(a); addAttrib(v); }
197
198     NSOpenGLPixelFormatAttribute attribs[40];
199     int index = 0;
200
201     addAttrib(NSOpenGLPFAAccelerated);
202     addAttrib(NSOpenGLPFAClosestPolicy);
203
204     if (ctxconfig->nsgl.offline)
205     {
206         addAttrib(NSOpenGLPFAAllowOfflineRenderers);
207         // NOTE: This replaces the NSSupportsAutomaticGraphicsSwitching key in
208         //       Info.plist for unbundled applications
209         // HACK: This assumes that NSOpenGLPixelFormat will remain
210         //       a straightforward wrapper of its CGL counterpart
211         addAttrib(kCGLPFASupportsAutomaticGraphicsSwitching);
212     }
213
214 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 101000
215     if (ctxconfig->major >= 4)
216     {
217         setAttrib(NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion4_1Core);
218     }
219     else
220 #endif /*MAC_OS_X_VERSION_MAX_ALLOWED*/
221     if (ctxconfig->major >= 3)
222     {
223         setAttrib(NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core);
224     }
225
226     if (ctxconfig->major <= 2)
227     {
228         if (fbconfig->auxBuffers != GLFW_DONT_CARE)
229             setAttrib(NSOpenGLPFAAuxBuffers, fbconfig->auxBuffers);
230
231         if (fbconfig->accumRedBits != GLFW_DONT_CARE &&
232             fbconfig->accumGreenBits != GLFW_DONT_CARE &&
233             fbconfig->accumBlueBits != GLFW_DONT_CARE &&
234             fbconfig->accumAlphaBits != GLFW_DONT_CARE)
235         {
236             const int accumBits = fbconfig->accumRedBits +
237                                   fbconfig->accumGreenBits +
238                                   fbconfig->accumBlueBits +
239                                   fbconfig->accumAlphaBits;
240
241             setAttrib(NSOpenGLPFAAccumSize, accumBits);
242         }
243     }
244
245     if (fbconfig->redBits != GLFW_DONT_CARE &&
246         fbconfig->greenBits != GLFW_DONT_CARE &&
247         fbconfig->blueBits != GLFW_DONT_CARE)
248     {
249         int colorBits = fbconfig->redBits +
250                         fbconfig->greenBits +
251                         fbconfig->blueBits;
252
253         // macOS needs non-zero color size, so set reasonable values
254         if (colorBits == 0)
255             colorBits = 24;
256         else if (colorBits < 15)
257             colorBits = 15;
258
259         setAttrib(NSOpenGLPFAColorSize, colorBits);
260     }
261
262     if (fbconfig->alphaBits != GLFW_DONT_CARE)
263         setAttrib(NSOpenGLPFAAlphaSize, fbconfig->alphaBits);
264
265     if (fbconfig->depthBits != GLFW_DONT_CARE)
266         setAttrib(NSOpenGLPFADepthSize, fbconfig->depthBits);
267
268     if (fbconfig->stencilBits != GLFW_DONT_CARE)
269         setAttrib(NSOpenGLPFAStencilSize, fbconfig->stencilBits);
270
271     if (fbconfig->stereo)
272     {
273 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 101200
274         _glfwInputError(GLFW_FORMAT_UNAVAILABLE,
275                         "NSGL: Stereo rendering is deprecated");
276         return GLFW_FALSE;
277 #else
278         addAttrib(NSOpenGLPFAStereo);
279 #endif
280     }
281
282     if (fbconfig->doublebuffer)
283         addAttrib(NSOpenGLPFADoubleBuffer);
284
285     if (fbconfig->samples != GLFW_DONT_CARE)
286     {
287         if (fbconfig->samples == 0)
288         {
289             setAttrib(NSOpenGLPFASampleBuffers, 0);
290         }
291         else
292         {
293             setAttrib(NSOpenGLPFASampleBuffers, 1);
294             setAttrib(NSOpenGLPFASamples, fbconfig->samples);
295         }
296     }
297
298     // NOTE: All NSOpenGLPixelFormats on the relevant cards support sRGB
299     //       framebuffer, so there's no need (and no way) to request it
300
301     addAttrib(0);
302
303 #undef addAttrib
304 #undef setAttrib
305
306     window->context.nsgl.pixelFormat =
307         [[NSOpenGLPixelFormat alloc] initWithAttributes:attribs];
308     if (window->context.nsgl.pixelFormat == nil)
309     {
310         _glfwInputError(GLFW_FORMAT_UNAVAILABLE,
311                         "NSGL: Failed to find a suitable pixel format");
312         return GLFW_FALSE;
313     }
314
315     NSOpenGLContext* share = nil;
316
317     if (ctxconfig->share)
318         share = ctxconfig->share->context.nsgl.object;
319
320     window->context.nsgl.object =
321         [[NSOpenGLContext alloc] initWithFormat:window->context.nsgl.pixelFormat
322                                    shareContext:share];
323     if (window->context.nsgl.object == nil)
324     {
325         _glfwInputError(GLFW_VERSION_UNAVAILABLE,
326                         "NSGL: Failed to create OpenGL context");
327         return GLFW_FALSE;
328     }
329
330     if (fbconfig->transparent)
331     {
332         GLint opaque = 0;
333         [window->context.nsgl.object setValues:&opaque
334                                   forParameter:NSOpenGLContextParameterSurfaceOpacity];
335     }
336
337     [window->ns.view setWantsBestResolutionOpenGLSurface:window->ns.retina];
338
339     [window->context.nsgl.object setView:window->ns.view];
340
341     window->context.makeCurrent = makeContextCurrentNSGL;
342     window->context.swapBuffers = swapBuffersNSGL;
343     window->context.swapInterval = swapIntervalNSGL;
344     window->context.extensionSupported = extensionSupportedNSGL;
345     window->context.getProcAddress = getProcAddressNSGL;
346     window->context.destroy = destroyContextNSGL;
347
348     return GLFW_TRUE;
349 }
350
351
352 //////////////////////////////////////////////////////////////////////////
353 //////                        GLFW native API                       //////
354 //////////////////////////////////////////////////////////////////////////
355
356 GLFWAPI id glfwGetNSGLContext(GLFWwindow* handle)
357 {
358     _GLFWwindow* window = (_GLFWwindow*) handle;
359     _GLFW_REQUIRE_INIT_OR_RETURN(nil);
360
361     if (window->context.client == GLFW_NO_API)
362     {
363         _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
364         return nil;
365     }
366
367     return window->context.nsgl.object;
368 }
369