SDL  2.0
SDL_cocoaopengl.m
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
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 
120 int
121 Cocoa_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  }
131  if (!_this->gl_config.dll_handle) {
132  return -1;
133  }
136  return 0;
137 }
138 
139 void *
140 Cocoa_GL_GetProcAddress(_THIS, const char *proc)
141 {
143 }
144 
145 void
146 Cocoa_GL_UnloadLibrary(_THIS)
147 {
150 }
151 
153 Cocoa_GL_CreateContext(_THIS, SDL_Window * window)
154 { @autoreleasepool
155 {
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 
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;
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 
215  attr[i++] = NSOpenGLPFADoubleBuffer;
216  }
217 
218  if (_this->gl_config.stereo) {
219  attr[i++] = NSOpenGLPFAStereo;
220  }
221 
223  attr[i++] = NSOpenGLPFAStencilSize;
224  attr[i++] = _this->gl_config.stencil_size;
225  }
226 
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 
236  attr[i++] = NSOpenGLPFASampleBuffers;
237  attr[i++] = _this->gl_config.multisamplebuffers;
238  }
239 
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 
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 
327 int
328 Cocoa_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 
343 void
344 Cocoa_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  if (window->flags & SDL_WINDOW_ALLOW_HIGHDPI) {
351  /* This gives us the correct viewport for a Retina-enabled view, only
352  * supported on 10.7+. */
353  if ([contentView respondsToSelector:@selector(convertRectToBacking:)]) {
354  viewport = [contentView convertRectToBacking:viewport];
355  }
356  }
357 
358  if (w) {
359  *w = viewport.size.width;
360  }
361 
362  if (h) {
363  *h = viewport.size.height;
364  }
365 }
366 
367 int
368 Cocoa_GL_SetSwapInterval(_THIS, int interval)
369 { @autoreleasepool
370 {
371  NSOpenGLContext *nscontext;
372  GLint value;
373  int status;
374 
375  if (interval < 0) { /* no extension for this on Mac OS X at the moment. */
376  return SDL_SetError("Late swap tearing currently unsupported");
377  }
378 
379  nscontext = (NSOpenGLContext*)SDL_GL_GetCurrentContext();
380  if (nscontext != nil) {
381  value = interval;
382  [nscontext setValues:&value forParameter:NSOpenGLCPSwapInterval];
383  status = 0;
384  } else {
385  status = SDL_SetError("No current OpenGL context");
386  }
387 
388  return status;
389 }}
390 
391 int
392 Cocoa_GL_GetSwapInterval(_THIS)
393 { @autoreleasepool
394 {
395  NSOpenGLContext *nscontext;
396  GLint value;
397  int status = 0;
398 
399  nscontext = (NSOpenGLContext*)SDL_GL_GetCurrentContext();
400  if (nscontext != nil) {
401  [nscontext getValues:&value forParameter:NSOpenGLCPSwapInterval];
402  status = (int)value;
403  }
404 
405  return status;
406 }}
407 
408 int
409 Cocoa_GL_SwapWindow(_THIS, SDL_Window * window)
410 { @autoreleasepool
411 {
412  SDLOpenGLContext* nscontext = (SDLOpenGLContext*)SDL_GL_GetCurrentContext();
413  SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
414 
415  /* on 10.14 ("Mojave") and later, this deadlocks if two contexts in two
416  threads try to swap at the same time, so put a mutex around it. */
417  SDL_LockMutex(videodata->swaplock);
418  [nscontext flushBuffer];
419  [nscontext updateIfNeeded];
420  SDL_UnlockMutex(videodata->swaplock);
421  return 0;
422 }}
423 
424 void
425 Cocoa_GL_DeleteContext(_THIS, SDL_GLContext context)
426 { @autoreleasepool
427 {
428  SDLOpenGLContext *nscontext = (SDLOpenGLContext *)context;
429 
430  [nscontext setWindow:NULL];
431  [nscontext release];
432 }}
433 
434 #endif /* SDL_VIDEO_OPENGL_CGL */
435 
436 /* vi: set ts=4 sw=4 expandtab: */
SDL_DisplayMode::format
Uint32 format
Definition: SDL_video.h:55
SDL_WINDOW_ALLOW_HIGHDPI
@ SDL_WINDOW_ALLOW_HIGHDPI
Definition: SDL_video.h:113
SDL_strlcpy
#define SDL_strlcpy
Definition: SDL_dynapi_overrides.h:394
SDL_cocoaopengl.h
SDL_VideoDevice::driverdata
void * driverdata
Definition: SDL_sysvideo.h:381
SDL_WindowData::nscontexts
NSMutableArray * nscontexts
Definition: SDL_cocoawindow.h:116
SDL_LockMutex
#define SDL_LockMutex
Definition: SDL_dynapi_overrides.h:260
NULL
#define NULL
Definition: begin_code.h:164
SDL_opengl.h
SDL_VideoDevice::multisamplesamples
int multisamplesamples
Definition: SDL_sysvideo.h:341
SDL_VideoDevice::accum_alpha_size
int accum_alpha_size
Definition: SDL_sysvideo.h:338
SDL_VideoDevice::accum_green_size
int accum_green_size
Definition: SDL_sysvideo.h:336
SDL_WindowData
Definition: SDL_androidwindow.h:36
SDL_GetDisplayForWindow
SDL_VideoDisplay * SDL_GetDisplayForWindow(SDL_Window *window)
Definition: SDL_video.c:1092
SDL_VideoDevice::driver_path
char driver_path[256]
Definition: SDL_sysvideo.h:354
SDL_VideoDevice::major_version
int major_version
Definition: SDL_sysvideo.h:343
SDL_VideoDevice::accum_blue_size
int accum_blue_size
Definition: SDL_sysvideo.h:337
viewport
SDL_Rect viewport
Definition: testviewport.c:28
SDL_GL_CONTEXT_PROFILE_CORE
@ SDL_GL_CONTEXT_PROFILE_CORE
Definition: SDL_video.h:231
SDL_UnloadObject
#define SDL_UnloadObject
Definition: SDL_dynapi_overrides.h:234
SDL_VideoDevice::profile_mask
int profile_mask
Definition: SDL_sysvideo.h:346
path
GLsizei const GLchar *const * path
Definition: SDL_opengl_glext.h:3730
SDL_VideoDevice::depth_size
int depth_size
Definition: SDL_sysvideo.h:331
SDL_cocoavideo.h
GLubyte
unsigned char GLubyte
Definition: SDL_opengl.h:183
h
GLfloat GLfloat GLfloat GLfloat h
Definition: SDL_opengl_glext.h:1946
SDL_LoadObject
#define SDL_LoadObject
Definition: SDL_dynapi_overrides.h:232
SDL_Window
The type used to identify a window.
Definition: SDL_sysvideo.h:74
GL_VERSION
#define GL_VERSION
Definition: SDL_opengl.h:715
SDL_VideoDevice::accum_red_size
int accum_red_size
Definition: SDL_sysvideo.h:335
SDL_GLContext
void * SDL_GLContext
An opaque handle to an OpenGL context.
Definition: SDL_video.h:193
context
static screen_context_t context
Definition: video.c:25
_this
static SDL_VideoDevice * _this
Definition: SDL_video.c:121
window
EGLSurface EGLNativeWindowType * window
Definition: eglext.h:1025
SDL_GL_GetProcAddress
#define SDL_GL_GetProcAddress
Definition: SDL_dynapi_overrides.h:554
SDL_VideoDevice::multisamplebuffers
int multisamplebuffers
Definition: SDL_sysvideo.h:340
SDL_GL_CONTEXT_PROFILE_ES
@ SDL_GL_CONTEXT_PROFILE_ES
Definition: SDL_video.h:233
SDL_VideoDevice::share_with_current_context
int share_with_current_context
Definition: SDL_sysvideo.h:347
_THIS
#define _THIS
Definition: SDL_alsa_audio.h:31
SDL_WindowData::window
SDL_Window * window
Definition: SDL_cocoawindow.h:114
SDL_VideoDevice::dll_handle
void * dll_handle
Definition: SDL_sysvideo.h:355
SDL_GL_GetCurrentContext
#define SDL_GL_GetCurrentContext
Definition: SDL_dynapi_overrides.h:562
SDL_VideoDisplay::driverdata
void * driverdata
Definition: SDL_sysvideo.h:139
SDL_sscanf
#define SDL_sscanf
Definition: SDL_dynapi_overrides.h:39
SDL_VideoDevice::double_buffer
int double_buffer
Definition: SDL_sysvideo.h:334
SDL_DisplayData
Definition: SDL_cocoamodes.h:27
APIENTRY
#define APIENTRY
Definition: SDL_opengl.h:139
SDL_VideoDevice::flags
int flags
Definition: SDL_sysvideo.h:345
id
GLuint id
Definition: SDL_opengl_glext.h:528
SDL_arraysize
#define SDL_arraysize(array)
Definition: SDL_stdinc.h:115
SDL_VideoData::swaplock
SDL_mutex * swaplock
Definition: SDL_cocoavideo.h:110
SDL_VideoDevice::GL_SetSwapInterval
int(* GL_SetSwapInterval)(_THIS, int interval)
Definition: SDL_sysvideo.h:261
SDL_Window::driverdata
void * driverdata
Definition: SDL_sysvideo.h:111
SDL_VideoDevice::stereo
int stereo
Definition: SDL_sysvideo.h:339
SDL_getenv
#define SDL_getenv
Definition: SDL_dynapi_overrides.h:378
SDL_AtomicAdd
#define SDL_AtomicAdd
Definition: SDL_dynapi_overrides.h:69
value
GLsizei const GLfloat * value
Definition: SDL_opengl_glext.h:698
SDL_VideoDisplay
Definition: SDL_sysvideo.h:126
SDL_SetError
#define SDL_SetError
Definition: SDL_dynapi_overrides.h:30
SDL_BYTESPERPIXEL
#define SDL_BYTESPERPIXEL(X)
Definition: SDL_pixels.h:128
SDL_VideoDevice::GL_MakeCurrent
int(* GL_MakeCurrent)(_THIS, SDL_Window *window, SDL_GLContext context)
Definition: SDL_sysvideo.h:259
SDL_VideoDevice::GL_LoadLibrary
int(* GL_LoadLibrary)(_THIS, const char *path)
Definition: SDL_sysvideo.h:255
SDL_LoadFunction
void * SDL_LoadFunction(void *handle, const char *name)
SDL_VideoDevice::GL_UnloadLibrary
void(* GL_UnloadLibrary)(_THIS)
Definition: SDL_sysvideo.h:257
SDL_VideoDevice::GL_CreateContext
SDL_GLContext(* GL_CreateContext)(_THIS, SDL_Window *window)
Definition: SDL_sysvideo.h:258
GLenum
unsigned int GLenum
Definition: SDL_opengl.h:176
SDL_VideoDevice::GL_GetSwapInterval
int(* GL_GetSwapInterval)(_THIS)
Definition: SDL_sysvideo.h:262
SDL_bool
SDL_bool
Definition: SDL_stdinc.h:162
SDL_VideoDevice::GL_SwapWindow
int(* GL_SwapWindow)(_THIS, SDL_Window *window)
Definition: SDL_sysvideo.h:263
SDL_VideoDevice::accelerated
int accelerated
Definition: SDL_sysvideo.h:342
SDL_AtomicSet
#define SDL_AtomicSet
Definition: SDL_dynapi_overrides.h:67
SDL_VideoDisplay::current_mode
SDL_DisplayMode current_mode
Definition: SDL_sysvideo.h:132
SDL_VideoDevice::GL_GetProcAddress
void *(* GL_GetProcAddress)(_THIS, const char *proc)
Definition: SDL_sysvideo.h:256
SDL_VideoDevice::stencil_size
int stencil_size
Definition: SDL_sysvideo.h:333
SDL_cocoaopengles.h
void
SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char const char SDL_SCANF_FORMAT_STRING const char return SDL_ThreadFunction const char void return Uint32 return Uint32 void
Definition: SDL_dynapi_procs.h:89
SDL_UnlockMutex
#define SDL_UnlockMutex
Definition: SDL_dynapi_overrides.h:262
floor
double floor(double x)
Definition: s_floor.c:29
SDL_VideoDevice::GL_DeleteContext
void(* GL_DeleteContext)(_THIS, SDL_GLContext context)
Definition: SDL_sysvideo.h:264
SDL_loadso.h
i
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int in i)
Definition: SDL_x11sym.h:50
GLint
int GLint
Definition: SDL_opengl.h:182
SDL_VideoDevice::gl_config
struct SDL_VideoDevice::@33 gl_config
SDL_DisplayData::display
CGDirectDisplayID display
Definition: SDL_cocoamodes.h:28
SDL_VideoData
Definition: SDL_androidvideo.h:36
SDL_WindowData::nswindow
NSWindow * nswindow
Definition: SDL_cocoawindow.h:115
w
GLubyte GLubyte GLubyte GLubyte w
Definition: SDL_opengl_glext.h:731