nsgl_context.m (10537B)
1 //======================================================================== 2 // GLFW 3.3 macOS - www.glfw.org 3 //------------------------------------------------------------------------ 4 // Copyright (c) 2009-2016 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 27 #include "internal.h" 28 29 30 static void makeContextCurrentNSGL(_GLFWwindow* window) 31 { 32 if (window) 33 [window->context.nsgl.object makeCurrentContext]; 34 else 35 [NSOpenGLContext clearCurrentContext]; 36 37 _glfwPlatformSetTls(&_glfw.contextSlot, window); 38 } 39 40 static void swapBuffersNSGL(_GLFWwindow* window) 41 { 42 // ARP appears to be unnecessary, but this is future-proof 43 [window->context.nsgl.object flushBuffer]; 44 } 45 46 static void swapIntervalNSGL(int interval) 47 { 48 _GLFWwindow* window = _glfwPlatformGetTls(&_glfw.contextSlot); 49 50 GLint sync = interval; 51 [window->context.nsgl.object setValues:&sync 52 forParameter:NSOpenGLCPSwapInterval]; 53 } 54 55 static int extensionSupportedNSGL(const char* extension) 56 { 57 // There are no NSGL extensions 58 return GLFW_FALSE; 59 } 60 61 static GLFWglproc getProcAddressNSGL(const char* procname) 62 { 63 CFStringRef symbolName = CFStringCreateWithCString(kCFAllocatorDefault, 64 procname, 65 kCFStringEncodingASCII); 66 67 GLFWglproc symbol = CFBundleGetFunctionPointerForName(_glfw.nsgl.framework, 68 symbolName); 69 70 CFRelease(symbolName); 71 72 return symbol; 73 } 74 75 // Destroy the OpenGL context 76 // 77 static void destroyContextNSGL(_GLFWwindow* window) 78 { 79 [window->context.nsgl.pixelFormat release]; 80 window->context.nsgl.pixelFormat = nil; 81 82 [window->context.nsgl.object release]; 83 window->context.nsgl.object = nil; 84 } 85 86 87 ////////////////////////////////////////////////////////////////////////// 88 ////// GLFW internal API ////// 89 ////////////////////////////////////////////////////////////////////////// 90 91 // Initialize OpenGL support 92 // 93 GLFWbool _glfwInitNSGL(void) 94 { 95 if (_glfw.nsgl.framework) 96 return GLFW_TRUE; 97 98 _glfw.nsgl.framework = 99 CFBundleGetBundleWithIdentifier(CFSTR("com.apple.opengl")); 100 if (_glfw.nsgl.framework == NULL) 101 { 102 _glfwInputError(GLFW_API_UNAVAILABLE, 103 "NSGL: Failed to locate OpenGL framework"); 104 return GLFW_FALSE; 105 } 106 107 return GLFW_TRUE; 108 } 109 110 // Terminate OpenGL support 111 // 112 void _glfwTerminateNSGL(void) 113 { 114 } 115 116 // Create the OpenGL context 117 // 118 GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window, 119 const _GLFWctxconfig* ctxconfig, 120 const _GLFWfbconfig* fbconfig) 121 { 122 if (ctxconfig->client == GLFW_OPENGL_ES_API) 123 { 124 _glfwInputError(GLFW_API_UNAVAILABLE, 125 "NSGL: OpenGL ES is not available on macOS"); 126 return GLFW_FALSE; 127 } 128 129 if (ctxconfig->major > 2) 130 { 131 if (ctxconfig->major == 3 && ctxconfig->minor < 2) 132 { 133 _glfwInputError(GLFW_VERSION_UNAVAILABLE, 134 "NSGL: The targeted version of macOS does not support OpenGL 3.0 or 3.1 but may support 3.2 and above"); 135 return GLFW_FALSE; 136 } 137 138 if (!ctxconfig->forward || ctxconfig->profile != GLFW_OPENGL_CORE_PROFILE) 139 { 140 _glfwInputError(GLFW_VERSION_UNAVAILABLE, 141 "NSGL: The targeted version of macOS only supports forward-compatible core profile contexts for OpenGL 3.2 and above"); 142 return GLFW_FALSE; 143 } 144 } 145 146 // Context robustness modes (GL_KHR_robustness) are not yet supported by 147 // macOS but are not a hard constraint, so ignore and continue 148 149 // Context release behaviors (GL_KHR_context_flush_control) are not yet 150 // supported by macOS but are not a hard constraint, so ignore and continue 151 152 // Debug contexts (GL_KHR_debug) are not yet supported by macOS but are not 153 // a hard constraint, so ignore and continue 154 155 // No-error contexts (GL_KHR_no_error) are not yet supported by macOS but 156 // are not a hard constraint, so ignore and continue 157 158 #define addAttrib(a) \ 159 { \ 160 assert((size_t) index < sizeof(attribs) / sizeof(attribs[0])); \ 161 attribs[index++] = a; \ 162 } 163 #define setAttrib(a, v) { addAttrib(a); addAttrib(v); } 164 165 NSOpenGLPixelFormatAttribute attribs[40]; 166 int index = 0; 167 168 addAttrib(NSOpenGLPFAAccelerated); 169 addAttrib(NSOpenGLPFAClosestPolicy); 170 171 if (ctxconfig->nsgl.offline) 172 { 173 addAttrib(NSOpenGLPFAAllowOfflineRenderers); 174 // NOTE: This replaces the NSSupportsAutomaticGraphicsSwitching key in 175 // Info.plist for unbundled applications 176 // HACK: This assumes that NSOpenGLPixelFormat will remain 177 // a straightforward wrapper of its CGL counterpart 178 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 100800 179 addAttrib(kCGLPFASupportsAutomaticGraphicsSwitching); 180 #endif /*MAC_OS_X_VERSION_MAX_ALLOWED*/ 181 } 182 183 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 101000 184 if (ctxconfig->major >= 4) 185 { 186 setAttrib(NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion4_1Core); 187 } 188 else 189 #endif /*MAC_OS_X_VERSION_MAX_ALLOWED*/ 190 if (ctxconfig->major >= 3) 191 { 192 setAttrib(NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core); 193 } 194 195 if (ctxconfig->major <= 2) 196 { 197 if (fbconfig->auxBuffers != GLFW_DONT_CARE) 198 setAttrib(NSOpenGLPFAAuxBuffers, fbconfig->auxBuffers); 199 200 if (fbconfig->accumRedBits != GLFW_DONT_CARE && 201 fbconfig->accumGreenBits != GLFW_DONT_CARE && 202 fbconfig->accumBlueBits != GLFW_DONT_CARE && 203 fbconfig->accumAlphaBits != GLFW_DONT_CARE) 204 { 205 const int accumBits = fbconfig->accumRedBits + 206 fbconfig->accumGreenBits + 207 fbconfig->accumBlueBits + 208 fbconfig->accumAlphaBits; 209 210 setAttrib(NSOpenGLPFAAccumSize, accumBits); 211 } 212 } 213 214 if (fbconfig->redBits != GLFW_DONT_CARE && 215 fbconfig->greenBits != GLFW_DONT_CARE && 216 fbconfig->blueBits != GLFW_DONT_CARE) 217 { 218 int colorBits = fbconfig->redBits + 219 fbconfig->greenBits + 220 fbconfig->blueBits; 221 222 // macOS needs non-zero color size, so set reasonable values 223 if (colorBits == 0) 224 colorBits = 24; 225 else if (colorBits < 15) 226 colorBits = 15; 227 228 setAttrib(NSOpenGLPFAColorSize, colorBits); 229 } 230 231 if (fbconfig->alphaBits != GLFW_DONT_CARE) 232 setAttrib(NSOpenGLPFAAlphaSize, fbconfig->alphaBits); 233 234 if (fbconfig->depthBits != GLFW_DONT_CARE) 235 setAttrib(NSOpenGLPFADepthSize, fbconfig->depthBits); 236 237 if (fbconfig->stencilBits != GLFW_DONT_CARE) 238 setAttrib(NSOpenGLPFAStencilSize, fbconfig->stencilBits); 239 240 if (fbconfig->stereo) 241 { 242 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 101200 243 _glfwInputError(GLFW_FORMAT_UNAVAILABLE, 244 "NSGL: Stereo rendering is deprecated"); 245 return GLFW_FALSE; 246 #else 247 addAttrib(NSOpenGLPFAStereo); 248 #endif 249 } 250 251 if (fbconfig->doublebuffer) 252 addAttrib(NSOpenGLPFADoubleBuffer); 253 254 if (fbconfig->samples != GLFW_DONT_CARE) 255 { 256 if (fbconfig->samples == 0) 257 { 258 setAttrib(NSOpenGLPFASampleBuffers, 0); 259 } 260 else 261 { 262 setAttrib(NSOpenGLPFASampleBuffers, 1); 263 setAttrib(NSOpenGLPFASamples, fbconfig->samples); 264 } 265 } 266 267 // NOTE: All NSOpenGLPixelFormats on the relevant cards support sRGB 268 // framebuffer, so there's no need (and no way) to request it 269 270 addAttrib(0); 271 272 #undef addAttrib 273 #undef setAttrib 274 275 window->context.nsgl.pixelFormat = 276 [[NSOpenGLPixelFormat alloc] initWithAttributes:attribs]; 277 if (window->context.nsgl.pixelFormat == nil) 278 { 279 _glfwInputError(GLFW_FORMAT_UNAVAILABLE, 280 "NSGL: Failed to find a suitable pixel format"); 281 return GLFW_FALSE; 282 } 283 284 NSOpenGLContext* share = NULL; 285 286 if (ctxconfig->share) 287 share = ctxconfig->share->context.nsgl.object; 288 289 window->context.nsgl.object = 290 [[NSOpenGLContext alloc] initWithFormat:window->context.nsgl.pixelFormat 291 shareContext:share]; 292 if (window->context.nsgl.object == nil) 293 { 294 _glfwInputError(GLFW_VERSION_UNAVAILABLE, 295 "NSGL: Failed to create OpenGL context"); 296 return GLFW_FALSE; 297 } 298 299 [window->context.nsgl.object setView:window->ns.view]; 300 301 window->context.makeCurrent = makeContextCurrentNSGL; 302 window->context.swapBuffers = swapBuffersNSGL; 303 window->context.swapInterval = swapIntervalNSGL; 304 window->context.extensionSupported = extensionSupportedNSGL; 305 window->context.getProcAddress = getProcAddressNSGL; 306 window->context.destroy = destroyContextNSGL; 307 308 return GLFW_TRUE; 309 } 310 311 312 ////////////////////////////////////////////////////////////////////////// 313 ////// GLFW native API ////// 314 ////////////////////////////////////////////////////////////////////////// 315 316 GLFWAPI id glfwGetNSGLContext(GLFWwindow* handle) 317 { 318 _GLFWwindow* window = (_GLFWwindow*) handle; 319 _GLFW_REQUIRE_INIT_OR_RETURN(nil); 320 321 if (window->context.client == GLFW_NO_API) 322 { 323 _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL); 324 return NULL; 325 } 326 327 return window->context.nsgl.object; 328 } 329