Atlas - SDL_cocoaopengl.m

Home / ext / SDL2 / src / video / cocoa Lines: 1 | Size: 13141 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)]
[FILE BEGIN]
1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2018 Sam Lantinga <[email protected]> 4 5 This software is provided 'as-is', without any express or implied 6 warranty. In no event will the authors be held liable for any damages 7 arising from the use of this software. 8 9 Permission is granted to anyone to use this software for any purpose, 10 including commercial applications, and to alter it and redistribute it 11 freely, subject to the following restrictions: 12 13 1. The origin of this software must not be misrepresented; you must not 14 claim that you wrote the original software. If you use this software 15 in a product, an acknowledgment in the product documentation would be 16 appreciated but is not required. 17 2. Altered source versions must be plainly marked as such, and must not be 18 misrepresented as being the original software. 19 3. This notice may not be removed or altered from any source distribution. 20*/ 21#include "../../SDL_internal.h" 22 23/* NSOpenGL implementation of SDL OpenGL support */ 24 25#if SDL_VIDEO_OPENGL_CGL 26#include "SDL_cocoavideo.h" 27#include "SDL_cocoaopengl.h" 28#include "SDL_cocoaopengles.h" 29 30#include <OpenGL/CGLTypes.h> 31#include <OpenGL/OpenGL.h> 32#include <OpenGL/CGLRenderers.h> 33 34#include "SDL_loadso.h" 35#include "SDL_opengl.h" 36 37#define DEFAULT_OPENGL "/System/Library/Frameworks/OpenGL.framework/Libraries/libGL.dylib" 38 39@implementation SDLOpenGLContext : NSOpenGLContext 40 41- (id)initWithFormat:(NSOpenGLPixelFormat *)format 42 shareContext:(NSOpenGLContext *)share 43{ 44 self = [super initWithFormat:format shareContext:share]; 45 if (self) { 46 SDL_AtomicSet(&self->dirty, 0); 47 self->window = NULL; 48 } 49 return self; 50} 51 52- (void)scheduleUpdate 53{ 54 SDL_AtomicAdd(&self->dirty, 1); 55} 56 57/* This should only be called on the thread on which a user is using the context. */ 58- (void)updateIfNeeded 59{ 60 int value = SDL_AtomicSet(&self->dirty, 0); 61 if (value > 0) { 62 /* We call the real underlying update here, since -[SDLOpenGLContext update] just calls us. */ 63 [super update]; 64 } 65} 66 67/* This should only be called on the thread on which a user is using the context. */ 68- (void)update 69{ 70 /* This ensures that regular 'update' calls clear the atomic dirty flag. */ 71 [self scheduleUpdate]; 72 [self updateIfNeeded]; 73} 74 75/* Updates the drawable for the contexts and manages related state. */ 76- (void)setWindow:(SDL_Window *)newWindow 77{ 78 if (self->window) { 79 SDL_WindowData *oldwindowdata = (SDL_WindowData *)self->window->driverdata; 80 81 /* Make sure to remove us from the old window's context list, or we'll get scheduled updates from it too. */ 82 NSMutableArray *contexts = oldwindowdata->nscontexts; 83 @synchronized (contexts) { 84 [contexts removeObject:self]; 85 } 86 } 87 88 self->window = newWindow; 89 90 if (newWindow) { 91 SDL_WindowData *windowdata = (SDL_WindowData *)newWindow->driverdata; 92 93 /* Now sign up for scheduled updates for the new window. */ 94 NSMutableArray *contexts = windowdata->nscontexts; 95 @synchronized (contexts) { 96 [contexts addObject:self]; 97 } 98 99 if ([self view] != [windowdata->nswindow contentView]) { 100 [self setView:[windowdata->nswindow contentView]]; 101 if (self == [NSOpenGLContext currentContext]) { 102 [self update]; 103 } else { 104 [self scheduleUpdate]; 105 } 106 } 107 } else { 108 [self clearDrawable]; 109 if (self == [NSOpenGLContext currentContext]) { 110 [self update]; 111 } else { 112 [self scheduleUpdate]; 113 } 114 } 115} 116 117@end 118 119 120int 121Cocoa_GL_LoadLibrary(_THIS, const char *path) 122{ 123 /* Load the OpenGL library */ 124 if (path == NULL) { 125 path = SDL_getenv("SDL_OPENGL_LIBRARY"); 126 } 127 if (path == NULL) { 128 path = DEFAULT_OPENGL; 129 } 130 _this->gl_config.dll_handle = SDL_LoadObject(path); 131 if (!_this->gl_config.dll_handle) { 132 return -1; 133 } 134 SDL_strlcpy(_this->gl_config.driver_path, path, 135 SDL_arraysize(_this->gl_config.driver_path)); 136 return 0; 137} 138 139void * 140Cocoa_GL_GetProcAddress(_THIS, const char *proc) 141{ 142 return SDL_LoadFunction(_this->gl_config.dll_handle, proc); 143} 144 145void 146Cocoa_GL_UnloadLibrary(_THIS) 147{ 148 SDL_UnloadObject(_this->gl_config.dll_handle); 149 _this->gl_config.dll_handle = NULL; 150} 151 152SDL_GLContext 153Cocoa_GL_CreateContext(_THIS, SDL_Window * window) 154{ @autoreleasepool 155{ 156 SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window); 157 SDL_DisplayData *displaydata = (SDL_DisplayData *)display->driverdata; 158 SDL_bool lion_or_later = floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_6; 159 NSOpenGLPixelFormatAttribute attr[32]; 160 NSOpenGLPixelFormat *fmt; 161 SDLOpenGLContext *context; 162 NSOpenGLContext *share_context = nil; 163 int i = 0; 164 const char *glversion; 165 int glversion_major; 166 int glversion_minor; 167 168 if (_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES) { 169#if SDL_VIDEO_OPENGL_EGL 170 /* Switch to EGL based functions */ 171 Cocoa_GL_UnloadLibrary(_this); 172 _this->GL_LoadLibrary = Cocoa_GLES_LoadLibrary; 173 _this->GL_GetProcAddress = Cocoa_GLES_GetProcAddress; 174 _this->GL_UnloadLibrary = Cocoa_GLES_UnloadLibrary; 175 _this->GL_CreateContext = Cocoa_GLES_CreateContext; 176 _this->GL_MakeCurrent = Cocoa_GLES_MakeCurrent; 177 _this->GL_SetSwapInterval = Cocoa_GLES_SetSwapInterval; 178 _this->GL_GetSwapInterval = Cocoa_GLES_GetSwapInterval; 179 _this->GL_SwapWindow = Cocoa_GLES_SwapWindow; 180 _this->GL_DeleteContext = Cocoa_GLES_DeleteContext; 181 182 if (Cocoa_GLES_LoadLibrary(_this, NULL) != 0) { 183 return NULL; 184 } 185 return Cocoa_GLES_CreateContext(_this, window); 186#else 187 SDL_SetError("SDL not configured with EGL support"); 188 return NULL; 189#endif 190 } 191 if ((_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_CORE) && !lion_or_later) { 192 SDL_SetError ("OpenGL Core Profile is not supported on this platform version"); 193 return NULL; 194 } 195 196 attr[i++] = NSOpenGLPFAAllowOfflineRenderers; 197 198 /* specify a profile if we're on Lion (10.7) or later. */ 199 if (lion_or_later) { 200 NSOpenGLPixelFormatAttribute profile = NSOpenGLProfileVersionLegacy; 201 if (_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_CORE) { 202 profile = NSOpenGLProfileVersion3_2Core; 203 } 204 attr[i++] = NSOpenGLPFAOpenGLProfile; 205 attr[i++] = profile; 206 } 207 208 attr[i++] = NSOpenGLPFAColorSize; 209 attr[i++] = SDL_BYTESPERPIXEL(display->current_mode.format)*8; 210 211 attr[i++] = NSOpenGLPFADepthSize; 212 attr[i++] = _this->gl_config.depth_size; 213 214 if (_this->gl_config.double_buffer) { 215 attr[i++] = NSOpenGLPFADoubleBuffer; 216 } 217 218 if (_this->gl_config.stereo) { 219 attr[i++] = NSOpenGLPFAStereo; 220 } 221 222 if (_this->gl_config.stencil_size) { 223 attr[i++] = NSOpenGLPFAStencilSize; 224 attr[i++] = _this->gl_config.stencil_size; 225 } 226 227 if ((_this->gl_config.accum_red_size + 228 _this->gl_config.accum_green_size + 229 _this->gl_config.accum_blue_size + 230 _this->gl_config.accum_alpha_size) > 0) { 231 attr[i++] = NSOpenGLPFAAccumSize; 232 attr[i++] = _this->gl_config.accum_red_size + _this->gl_config.accum_green_size + _this->gl_config.accum_blue_size + _this->gl_config.accum_alpha_size; 233 } 234 235 if (_this->gl_config.multisamplebuffers) { 236 attr[i++] = NSOpenGLPFASampleBuffers; 237 attr[i++] = _this->gl_config.multisamplebuffers; 238 } 239 240 if (_this->gl_config.multisamplesamples) { 241 attr[i++] = NSOpenGLPFASamples; 242 attr[i++] = _this->gl_config.multisamplesamples; 243 attr[i++] = NSOpenGLPFANoRecovery; 244 } 245 246 if (_this->gl_config.accelerated >= 0) { 247 if (_this->gl_config.accelerated) { 248 attr[i++] = NSOpenGLPFAAccelerated; 249 } else { 250 attr[i++] = NSOpenGLPFARendererID; 251 attr[i++] = kCGLRendererGenericFloatID; 252 } 253 } 254 255 attr[i++] = NSOpenGLPFAScreenMask; 256 attr[i++] = CGDisplayIDToOpenGLDisplayMask(displaydata->display); 257 attr[i] = 0; 258 259 fmt = [[NSOpenGLPixelFormat alloc] initWithAttributes:attr]; 260 if (fmt == nil) { 261 SDL_SetError("Failed creating OpenGL pixel format"); 262 return NULL; 263 } 264 265 if (_this->gl_config.share_with_current_context) { 266 share_context = (NSOpenGLContext*)SDL_GL_GetCurrentContext(); 267 } 268 269 context = [[SDLOpenGLContext alloc] initWithFormat:fmt shareContext:share_context]; 270 271 [fmt release]; 272 273 if (context == nil) { 274 SDL_SetError("Failed creating OpenGL context"); 275 return NULL; 276 } 277 278 if ( Cocoa_GL_MakeCurrent(_this, window, context) < 0 ) { 279 Cocoa_GL_DeleteContext(_this, context); 280 SDL_SetError("Failed making OpenGL context current"); 281 return NULL; 282 } 283 284 if (_this->gl_config.major_version < 3 && 285 _this->gl_config.profile_mask == 0 && 286 _this->gl_config.flags == 0) { 287 /* This is a legacy profile, so to match other backends, we're done. */ 288 } else { 289 const GLubyte *(APIENTRY * glGetStringFunc)(GLenum); 290 291 glGetStringFunc = (const GLubyte *(APIENTRY *)(GLenum)) SDL_GL_GetProcAddress("glGetString"); 292 if (!glGetStringFunc) { 293 Cocoa_GL_DeleteContext(_this, context); 294 SDL_SetError ("Failed getting OpenGL glGetString entry point"); 295 return NULL; 296 } 297 298 glversion = (const char *)glGetStringFunc(GL_VERSION); 299 if (glversion == NULL) { 300 Cocoa_GL_DeleteContext(_this, context); 301 SDL_SetError ("Failed getting OpenGL context version"); 302 return NULL; 303 } 304 305 if (SDL_sscanf(glversion, "%d.%d", &glversion_major, &glversion_minor) != 2) { 306 Cocoa_GL_DeleteContext(_this, context); 307 SDL_SetError ("Failed parsing OpenGL context version"); 308 return NULL; 309 } 310 311 if ((glversion_major < _this->gl_config.major_version) || 312 ((glversion_major == _this->gl_config.major_version) && (glversion_minor < _this->gl_config.minor_version))) { 313 Cocoa_GL_DeleteContext(_this, context); 314 SDL_SetError ("Failed creating OpenGL context at version requested"); 315 return NULL; 316 } 317 318 /* In the future we'll want to do this, but to match other platforms 319 we'll leave the OpenGL version the way it is for now 320 */ 321 /*_this->gl_config.major_version = glversion_major;*/ 322 /*_this->gl_config.minor_version = glversion_minor;*/ 323 } 324 return context; 325}} 326 327int 328Cocoa_GL_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context) 329{ @autoreleasepool 330{ 331 if (context) { 332 SDLOpenGLContext *nscontext = (SDLOpenGLContext *)context; 333 [nscontext setWindow:window]; 334 [nscontext updateIfNeeded]; 335 [nscontext makeCurrentContext]; 336 } else { 337 [NSOpenGLContext clearCurrentContext]; 338 } 339 340 return 0; 341}} 342 343void 344Cocoa_GL_GetDrawableSize(_THIS, SDL_Window * window, int * w, int * h) 345{ 346 SDL_WindowData *windata = (SDL_WindowData *) window->driverdata; 347 NSView *contentView = [windata->nswindow contentView]; 348 NSRect viewport = [contentView bounds]; 349 350 /* This gives us the correct viewport for a Retina-enabled view, only 351 * supported on 10.7+. */ 352 if ([contentView respondsToSelector:@selector(convertRectToBacking:)]) { 353 viewport = [contentView convertRectToBacking:viewport]; 354 } 355 356 if (w) { 357 *w = viewport.size.width; 358 } 359 360 if (h) { 361 *h = viewport.size.height; 362 } 363} 364 365int 366Cocoa_GL_SetSwapInterval(_THIS, int interval) 367{ @autoreleasepool 368{ 369 NSOpenGLContext *nscontext; 370 GLint value; 371 int status; 372 373 if (interval < 0) { /* no extension for this on Mac OS X at the moment. */ 374 return SDL_SetError("Late swap tearing currently unsupported"); 375 } 376 377 nscontext = (NSOpenGLContext*)SDL_GL_GetCurrentContext(); 378 if (nscontext != nil) { 379 value = interval; 380 [nscontext setValues:&value forParameter:NSOpenGLCPSwapInterval]; 381 status = 0; 382 } else { 383 status = SDL_SetError("No current OpenGL context"); 384 } 385 386 return status; 387}} 388 389int 390Cocoa_GL_GetSwapInterval(_THIS) 391{ @autoreleasepool 392{ 393 NSOpenGLContext *nscontext; 394 GLint value; 395 int status = 0; 396 397 nscontext = (NSOpenGLContext*)SDL_GL_GetCurrentContext(); 398 if (nscontext != nil) { 399 [nscontext getValues:&value forParameter:NSOpenGLCPSwapInterval]; 400 status = (int)value; 401 } 402 403 return status; 404}} 405 406int 407Cocoa_GL_SwapWindow(_THIS, SDL_Window * window) 408{ @autoreleasepool 409{ 410 SDLOpenGLContext* nscontext = (SDLOpenGLContext*)SDL_GL_GetCurrentContext(); 411 [nscontext flushBuffer]; 412 [nscontext updateIfNeeded]; 413 return 0; 414}} 415 416void 417Cocoa_GL_DeleteContext(_THIS, SDL_GLContext context) 418{ @autoreleasepool 419{ 420 SDLOpenGLContext *nscontext = (SDLOpenGLContext *)context; 421 422 [nscontext setWindow:NULL]; 423 [nscontext release]; 424}} 425 426#endif /* SDL_VIDEO_OPENGL_CGL */ 427 428/* vi: set ts=4 sw=4 expandtab: */ 429
[FILE END]
(C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.