src/video/cocoa/SDL_cocoaopengl.m
author Alex Szpakowski <slime73@gmail.com>
Wed, 17 Apr 2019 20:14:40 -0300
changeset 12706 d7782848eb50
parent 12702 0ff5bbe35bf5
child 12840 1b6f67e84802
permissions -rw-r--r--
macOS: Fix compilation when using the 10.9 SDK or older.
slouken@1936
     1
/*
slouken@5535
     2
  Simple DirectMedia Layer
slouken@12503
     3
  Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
slouken@1936
     4
slouken@5535
     5
  This software is provided 'as-is', without any express or implied
slouken@5535
     6
  warranty.  In no event will the authors be held liable for any damages
slouken@5535
     7
  arising from the use of this software.
slouken@1936
     8
slouken@5535
     9
  Permission is granted to anyone to use this software for any purpose,
slouken@5535
    10
  including commercial applications, and to alter it and redistribute it
slouken@5535
    11
  freely, subject to the following restrictions:
slouken@1936
    12
slouken@5535
    13
  1. The origin of this software must not be misrepresented; you must not
slouken@5535
    14
     claim that you wrote the original software. If you use this software
slouken@5535
    15
     in a product, an acknowledgment in the product documentation would be
slouken@5535
    16
     appreciated but is not required.
slouken@5535
    17
  2. Altered source versions must be plainly marked as such, and must not be
slouken@5535
    18
     misrepresented as being the original software.
slouken@5535
    19
  3. This notice may not be removed or altered from any source distribution.
slouken@1936
    20
*/
icculus@8093
    21
#include "../../SDL_internal.h"
slouken@1936
    22
slouken@1936
    23
/* NSOpenGL implementation of SDL OpenGL support */
slouken@1936
    24
slouken@1952
    25
#if SDL_VIDEO_OPENGL_CGL
slouken@6044
    26
#include "SDL_cocoavideo.h"
jorgen@7594
    27
#include "SDL_cocoaopengl.h"
slouken@11723
    28
#include "SDL_cocoaopengles.h"
slouken@6044
    29
slouken@1936
    30
#include <OpenGL/CGLTypes.h>
slouken@2738
    31
#include <OpenGL/OpenGL.h>
slouken@3570
    32
#include <OpenGL/CGLRenderers.h>
slouken@1936
    33
slouken@1936
    34
#include "SDL_loadso.h"
slouken@1936
    35
#include "SDL_opengl.h"
slouken@1936
    36
icculus@6567
    37
#define DEFAULT_OPENGL  "/System/Library/Frameworks/OpenGL.framework/Libraries/libGL.dylib"
slouken@1936
    38
icculus@12477
    39
static CVReturn
icculus@12477
    40
DisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeStamp* now, const CVTimeStamp* outputTime, CVOptionFlags flagsIn, CVOptionFlags* flagsOut, void* displayLinkContext)
icculus@12477
    41
{
icculus@12477
    42
    SDLOpenGLContext *nscontext = (SDLOpenGLContext *) displayLinkContext;
slime73@12702
    43
icculus@12477
    44
    /*printf("DISPLAY LINK! %u\n", (unsigned int) SDL_GetTicks()); */
icculus@12477
    45
    const int setting = SDL_AtomicGet(&nscontext->swapIntervalSetting);
icculus@12477
    46
    if (setting != 0) { /* nothing to do if vsync is disabled, don't even lock */
icculus@12477
    47
        SDL_LockMutex(nscontext->swapIntervalMutex);
icculus@12477
    48
        SDL_AtomicAdd(&nscontext->swapIntervalsPassed, 1);
icculus@12477
    49
        SDL_CondSignal(nscontext->swapIntervalCond);
icculus@12477
    50
        SDL_UnlockMutex(nscontext->swapIntervalMutex);
icculus@12477
    51
    }
icculus@12477
    52
icculus@12477
    53
    return kCVReturnSuccess;
icculus@12477
    54
}
icculus@12477
    55
jorgen@7594
    56
@implementation SDLOpenGLContext : NSOpenGLContext
jorgen@7594
    57
jorgen@7594
    58
- (id)initWithFormat:(NSOpenGLPixelFormat *)format
jorgen@7594
    59
        shareContext:(NSOpenGLContext *)share
jorgen@7594
    60
{
jorgen@7595
    61
    self = [super initWithFormat:format shareContext:share];
jorgen@7595
    62
    if (self) {
jorgen@7595
    63
        SDL_AtomicSet(&self->dirty, 0);
jorgen@7595
    64
        self->window = NULL;
icculus@12477
    65
        SDL_AtomicSet(&self->swapIntervalSetting, 0);
icculus@12477
    66
        SDL_AtomicSet(&self->swapIntervalsPassed, 0);
icculus@12477
    67
        self->swapIntervalCond = SDL_CreateCond();
icculus@12477
    68
        self->swapIntervalMutex = SDL_CreateMutex();
icculus@12477
    69
        if (!self->swapIntervalCond || !self->swapIntervalMutex) {
icculus@12477
    70
            [self release];
icculus@12477
    71
            return nil;
icculus@12477
    72
        }
icculus@12477
    73
icculus@12477
    74
        /* !!! FIXME: check return values. */
icculus@12477
    75
        CVDisplayLinkCreateWithActiveCGDisplays(&self->displayLink);
icculus@12477
    76
        CVDisplayLinkSetOutputCallback(self->displayLink, &DisplayLinkCallback, self);
icculus@12477
    77
        CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext(self->displayLink, [self CGLContextObj], [format CGLPixelFormatObj]);
icculus@12477
    78
        CVDisplayLinkStart(displayLink);
jorgen@7595
    79
    }
jorgen@7595
    80
    return self;
jorgen@7594
    81
}
jorgen@7594
    82
jorgen@7594
    83
- (void)scheduleUpdate
jorgen@7594
    84
{
jorgen@7594
    85
    SDL_AtomicAdd(&self->dirty, 1);
jorgen@7594
    86
}
jorgen@7594
    87
jorgen@7594
    88
/* This should only be called on the thread on which a user is using the context. */
jorgen@7594
    89
- (void)updateIfNeeded
jorgen@7594
    90
{
jorgen@7594
    91
    int value = SDL_AtomicSet(&self->dirty, 0);
jorgen@7594
    92
    if (value > 0) {
jorgen@7594
    93
        /* We call the real underlying update here, since -[SDLOpenGLContext update] just calls us. */
jorgen@7594
    94
        [super update];
jorgen@7594
    95
    }
jorgen@7594
    96
}
jorgen@7594
    97
jorgen@7594
    98
/* This should only be called on the thread on which a user is using the context. */
jorgen@7594
    99
- (void)update
jorgen@7594
   100
{
jorgen@7594
   101
    /* This ensures that regular 'update' calls clear the atomic dirty flag. */
jorgen@7594
   102
    [self scheduleUpdate];
jorgen@7594
   103
    [self updateIfNeeded];
jorgen@7594
   104
}
jorgen@7594
   105
jorgen@7595
   106
/* Updates the drawable for the contexts and manages related state. */
jorgen@7595
   107
- (void)setWindow:(SDL_Window *)newWindow
jorgen@7595
   108
{
jorgen@7595
   109
    if (self->window) {
jorgen@7595
   110
        SDL_WindowData *oldwindowdata = (SDL_WindowData *)self->window->driverdata;
jorgen@7595
   111
jorgen@7595
   112
        /* Make sure to remove us from the old window's context list, or we'll get scheduled updates from it too. */
jorgen@7595
   113
        NSMutableArray *contexts = oldwindowdata->nscontexts;
jorgen@7595
   114
        @synchronized (contexts) {
jorgen@7595
   115
            [contexts removeObject:self];
jorgen@7595
   116
        }
jorgen@7595
   117
    }
jorgen@7595
   118
jorgen@7595
   119
    self->window = newWindow;
jorgen@7595
   120
jorgen@7595
   121
    if (newWindow) {
jorgen@7595
   122
        SDL_WindowData *windowdata = (SDL_WindowData *)newWindow->driverdata;
jorgen@7595
   123
jorgen@7595
   124
        /* Now sign up for scheduled updates for the new window. */
jorgen@7595
   125
        NSMutableArray *contexts = windowdata->nscontexts;
jorgen@7595
   126
        @synchronized (contexts) {
jorgen@7595
   127
            [contexts addObject:self];
jorgen@7595
   128
        }
jorgen@7595
   129
jorgen@7595
   130
        if ([self view] != [windowdata->nswindow contentView]) {
jorgen@7595
   131
            [self setView:[windowdata->nswindow contentView]];
jorgen@8258
   132
            if (self == [NSOpenGLContext currentContext]) {
jorgen@8258
   133
                [self update];
jorgen@8258
   134
            } else {
jorgen@8258
   135
                [self scheduleUpdate];
jorgen@8258
   136
            }
jorgen@7595
   137
        }
jorgen@7595
   138
    } else {
jorgen@7595
   139
        [self clearDrawable];
jorgen@8258
   140
        if (self == [NSOpenGLContext currentContext]) {
jorgen@8258
   141
            [self update];
jorgen@8258
   142
        } else {
jorgen@8258
   143
            [self scheduleUpdate];
jorgen@8258
   144
        }
jorgen@7595
   145
    }
jorgen@7595
   146
}
jorgen@7595
   147
icculus@12477
   148
- (void)dealloc
icculus@12477
   149
{
icculus@12477
   150
    if (self->displayLink) {
icculus@12477
   151
        CVDisplayLinkRelease(self->displayLink);
icculus@12477
   152
    }
icculus@12477
   153
    if (self->swapIntervalCond) {
icculus@12477
   154
        SDL_DestroyCond(self->swapIntervalCond);
icculus@12477
   155
    }
icculus@12477
   156
    if (self->swapIntervalMutex) {
icculus@12477
   157
        SDL_DestroyMutex(self->swapIntervalMutex);
icculus@12477
   158
    }
icculus@12477
   159
    [super dealloc];
icculus@12477
   160
}
jorgen@7594
   161
@end
jorgen@7594
   162
slouken@1936
   163
slouken@1936
   164
int
slouken@1936
   165
Cocoa_GL_LoadLibrary(_THIS, const char *path)
slouken@1936
   166
{
slouken@3057
   167
    /* Load the OpenGL library */
slouken@1936
   168
    if (path == NULL) {
slouken@1952
   169
        path = SDL_getenv("SDL_OPENGL_LIBRARY");
slouken@1952
   170
    }
slouken@1952
   171
    if (path == NULL) {
slouken@1952
   172
        path = DEFAULT_OPENGL;
slouken@1936
   173
    }
slouken@1936
   174
    _this->gl_config.dll_handle = SDL_LoadObject(path);
slouken@1936
   175
    if (!_this->gl_config.dll_handle) {
slouken@1936
   176
        return -1;
slouken@1936
   177
    }
slouken@1936
   178
    SDL_strlcpy(_this->gl_config.driver_path, path,
slouken@1936
   179
                SDL_arraysize(_this->gl_config.driver_path));
slouken@1936
   180
    return 0;
slouken@1936
   181
}
slouken@1936
   182
slouken@1936
   183
void *
slouken@1936
   184
Cocoa_GL_GetProcAddress(_THIS, const char *proc)
slouken@1936
   185
{
slouken@1936
   186
    return SDL_LoadFunction(_this->gl_config.dll_handle, proc);
slouken@1936
   187
}
slouken@1936
   188
slouken@3057
   189
void
slouken@1936
   190
Cocoa_GL_UnloadLibrary(_THIS)
slouken@1936
   191
{
slouken@3057
   192
    SDL_UnloadObject(_this->gl_config.dll_handle);
slouken@3057
   193
    _this->gl_config.dll_handle = NULL;
slouken@1936
   194
}
slouken@1936
   195
slouken@1936
   196
SDL_GLContext
slouken@1936
   197
Cocoa_GL_CreateContext(_THIS, SDL_Window * window)
slime73@9587
   198
{ @autoreleasepool
slouken@1936
   199
{
slouken@5246
   200
    SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
slouken@1936
   201
    SDL_DisplayData *displaydata = (SDL_DisplayData *)display->driverdata;
slouken@8986
   202
    SDL_bool lion_or_later = floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_6;
slouken@1936
   203
    NSOpenGLPixelFormatAttribute attr[32];
slouken@1936
   204
    NSOpenGLPixelFormat *fmt;
jorgen@7594
   205
    SDLOpenGLContext *context;
flibitijibibo@7152
   206
    NSOpenGLContext *share_context = nil;
slouken@1936
   207
    int i = 0;
icculus@8276
   208
    const char *glversion;
icculus@8276
   209
    int glversion_major;
icculus@8276
   210
    int glversion_minor;
slime73@12702
   211
    int interval;
slouken@1936
   212
icculus@6567
   213
    if (_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES) {
slouken@11723
   214
#if SDL_VIDEO_OPENGL_EGL
slouken@11723
   215
        /* Switch to EGL based functions */
slouken@11723
   216
        Cocoa_GL_UnloadLibrary(_this);
slouken@11723
   217
        _this->GL_LoadLibrary = Cocoa_GLES_LoadLibrary;
slouken@11723
   218
        _this->GL_GetProcAddress = Cocoa_GLES_GetProcAddress;
slouken@11723
   219
        _this->GL_UnloadLibrary = Cocoa_GLES_UnloadLibrary;
slouken@11723
   220
        _this->GL_CreateContext = Cocoa_GLES_CreateContext;
slouken@11723
   221
        _this->GL_MakeCurrent = Cocoa_GLES_MakeCurrent;
slouken@11723
   222
        _this->GL_SetSwapInterval = Cocoa_GLES_SetSwapInterval;
slouken@11723
   223
        _this->GL_GetSwapInterval = Cocoa_GLES_GetSwapInterval;
slouken@11723
   224
        _this->GL_SwapWindow = Cocoa_GLES_SwapWindow;
slouken@11723
   225
        _this->GL_DeleteContext = Cocoa_GLES_DeleteContext;
slouken@11723
   226
        
slouken@11723
   227
        if (Cocoa_GLES_LoadLibrary(_this, NULL) != 0) {
slouken@11723
   228
            return NULL;
slouken@11723
   229
        }
slouken@11723
   230
        return Cocoa_GLES_CreateContext(_this, window);
slouken@11723
   231
#else
slouken@11723
   232
        SDL_SetError("SDL not configured with EGL support");
icculus@6567
   233
        return NULL;
slouken@11723
   234
#endif
icculus@6567
   235
    }
slouken@8986
   236
    if ((_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_CORE) && !lion_or_later) {
icculus@8276
   237
        SDL_SetError ("OpenGL Core Profile is not supported on this platform version");
icculus@6567
   238
        return NULL;
icculus@6567
   239
    }
icculus@6567
   240
icculus@10008
   241
    attr[i++] = NSOpenGLPFAAllowOfflineRenderers;
icculus@10008
   242
slouken@6848
   243
    /* specify a profile if we're on Lion (10.7) or later. */
slouken@8986
   244
    if (lion_or_later) {
icculus@8276
   245
        NSOpenGLPixelFormatAttribute profile = NSOpenGLProfileVersionLegacy;
slouken@6848
   246
        if (_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_CORE) {
icculus@8276
   247
            profile = NSOpenGLProfileVersion3_2Core;
alexey@6832
   248
        }
icculus@8276
   249
        attr[i++] = NSOpenGLPFAOpenGLProfile;
slouken@6848
   250
        attr[i++] = profile;
slouken@6848
   251
    }
slouken@1936
   252
slouken@6848
   253
    attr[i++] = NSOpenGLPFAColorSize;
slouken@6848
   254
    attr[i++] = SDL_BYTESPERPIXEL(display->current_mode.format)*8;
slouken@6848
   255
slouken@6848
   256
    attr[i++] = NSOpenGLPFADepthSize;
slouken@6848
   257
    attr[i++] = _this->gl_config.depth_size;
slouken@6848
   258
slouken@6848
   259
    if (_this->gl_config.double_buffer) {
slouken@6848
   260
        attr[i++] = NSOpenGLPFADoubleBuffer;
slouken@6848
   261
    }
slouken@6848
   262
slouken@6848
   263
    if (_this->gl_config.stereo) {
slouken@6848
   264
        attr[i++] = NSOpenGLPFAStereo;
slouken@6848
   265
    }
slouken@6848
   266
slouken@6848
   267
    if (_this->gl_config.stencil_size) {
slouken@6848
   268
        attr[i++] = NSOpenGLPFAStencilSize;
slouken@6848
   269
        attr[i++] = _this->gl_config.stencil_size;
slouken@6848
   270
    }
slouken@6848
   271
slouken@6848
   272
    if ((_this->gl_config.accum_red_size +
slouken@6848
   273
         _this->gl_config.accum_green_size +
slouken@6848
   274
         _this->gl_config.accum_blue_size +
slouken@6848
   275
         _this->gl_config.accum_alpha_size) > 0) {
slouken@6848
   276
        attr[i++] = NSOpenGLPFAAccumSize;
slouken@6848
   277
        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;
slouken@6848
   278
    }
slouken@6848
   279
slouken@6848
   280
    if (_this->gl_config.multisamplebuffers) {
slouken@6848
   281
        attr[i++] = NSOpenGLPFASampleBuffers;
slouken@6848
   282
        attr[i++] = _this->gl_config.multisamplebuffers;
slouken@6848
   283
    }
slouken@6848
   284
slouken@6848
   285
    if (_this->gl_config.multisamplesamples) {
slouken@6848
   286
        attr[i++] = NSOpenGLPFASamples;
slouken@6848
   287
        attr[i++] = _this->gl_config.multisamplesamples;
slouken@6848
   288
        attr[i++] = NSOpenGLPFANoRecovery;
slouken@6848
   289
    }
slouken@6848
   290
slouken@6848
   291
    if (_this->gl_config.accelerated >= 0) {
slouken@6848
   292
        if (_this->gl_config.accelerated) {
slouken@6848
   293
            attr[i++] = NSOpenGLPFAAccelerated;
slouken@6848
   294
        } else {
slouken@6848
   295
            attr[i++] = NSOpenGLPFARendererID;
slouken@6848
   296
            attr[i++] = kCGLRendererGenericFloatID;
alexey@6832
   297
        }
slouken@6848
   298
    }
slouken@6848
   299
slouken@6848
   300
    attr[i++] = NSOpenGLPFAScreenMask;
slouken@6848
   301
    attr[i++] = CGDisplayIDToOpenGLDisplayMask(displaydata->display);
slouken@6848
   302
    attr[i] = 0;
slouken@6848
   303
slouken@6848
   304
    fmt = [[NSOpenGLPixelFormat alloc] initWithAttributes:attr];
slouken@6848
   305
    if (fmt == nil) {
slouken@8601
   306
        SDL_SetError("Failed creating OpenGL pixel format");
slouken@6848
   307
        return NULL;
slouken@6848
   308
    }
slouken@6848
   309
flibitijibibo@7152
   310
    if (_this->gl_config.share_with_current_context) {
slouken@7412
   311
        share_context = (NSOpenGLContext*)SDL_GL_GetCurrentContext();
flibitijibibo@7152
   312
    }
flibitijibibo@7152
   313
jorgen@7594
   314
    context = [[SDLOpenGLContext alloc] initWithFormat:fmt shareContext:share_context];
slouken@6848
   315
slouken@6848
   316
    [fmt release];
slouken@6848
   317
slouken@6848
   318
    if (context == nil) {
slouken@8601
   319
        SDL_SetError("Failed creating OpenGL context");
slouken@6848
   320
        return NULL;
slouken@6848
   321
    }
slouken@6848
   322
slime73@12702
   323
    /* vsync is handled separately by synchronizing with a display link. */
slime73@12702
   324
    interval = 0;
slime73@12706
   325
    [context setValues:&interval forParameter:NSOpenGLCPSwapInterval];
slime73@12702
   326
slouken@2178
   327
    if ( Cocoa_GL_MakeCurrent(_this, window, context) < 0 ) {
slouken@2178
   328
        Cocoa_GL_DeleteContext(_this, context);
slouken@8601
   329
        SDL_SetError("Failed making OpenGL context current");
slouken@2178
   330
        return NULL;
slouken@2178
   331
    }
slouken@2178
   332
slouken@8604
   333
    if (_this->gl_config.major_version < 3 &&
slouken@8604
   334
        _this->gl_config.profile_mask == 0 &&
slouken@8604
   335
        _this->gl_config.flags == 0) {
slouken@8604
   336
        /* This is a legacy profile, so to match other backends, we're done. */
slouken@8604
   337
    } else {
slouken@8604
   338
        const GLubyte *(APIENTRY * glGetStringFunc)(GLenum);
slouken@8601
   339
slouken@8604
   340
        glGetStringFunc = (const GLubyte *(APIENTRY *)(GLenum)) SDL_GL_GetProcAddress("glGetString");
slouken@8604
   341
        if (!glGetStringFunc) {
slouken@8604
   342
            Cocoa_GL_DeleteContext(_this, context);
slouken@8604
   343
            SDL_SetError ("Failed getting OpenGL glGetString entry point");
slouken@8604
   344
            return NULL;
slouken@8604
   345
        }
slouken@8601
   346
slouken@8604
   347
        glversion = (const char *)glGetStringFunc(GL_VERSION);
slouken@8604
   348
        if (glversion == NULL) {
slouken@8604
   349
            Cocoa_GL_DeleteContext(_this, context);
slouken@8604
   350
            SDL_SetError ("Failed getting OpenGL context version");
slouken@8604
   351
            return NULL;
slouken@8604
   352
        }
slouken@8604
   353
slouken@8604
   354
        if (SDL_sscanf(glversion, "%d.%d", &glversion_major, &glversion_minor) != 2) {
slouken@8604
   355
            Cocoa_GL_DeleteContext(_this, context);
slouken@8604
   356
            SDL_SetError ("Failed parsing OpenGL context version");
slouken@8604
   357
            return NULL;
slouken@8604
   358
        }
slouken@8604
   359
slouken@8604
   360
        if ((glversion_major < _this->gl_config.major_version) ||
slouken@8604
   361
           ((glversion_major == _this->gl_config.major_version) && (glversion_minor < _this->gl_config.minor_version))) {
slouken@8604
   362
            Cocoa_GL_DeleteContext(_this, context);
slouken@8604
   363
            SDL_SetError ("Failed creating OpenGL context at version requested");
slouken@8604
   364
            return NULL;
slouken@8604
   365
        }
slouken@8604
   366
slouken@8604
   367
        /* In the future we'll want to do this, but to match other platforms
slouken@8604
   368
           we'll leave the OpenGL version the way it is for now
slouken@8604
   369
         */
slouken@8604
   370
        /*_this->gl_config.major_version = glversion_major;*/
slouken@8604
   371
        /*_this->gl_config.minor_version = glversion_minor;*/
icculus@8278
   372
    }
slouken@2178
   373
    return context;
slime73@9587
   374
}}
slouken@1936
   375
slouken@1936
   376
int
slouken@1936
   377
Cocoa_GL_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context)
slime73@9587
   378
{ @autoreleasepool
slouken@1936
   379
{
slouken@6848
   380
    if (context) {
jorgen@7594
   381
        SDLOpenGLContext *nscontext = (SDLOpenGLContext *)context;
jorgen@7595
   382
        [nscontext setWindow:window];
jorgen@7594
   383
        [nscontext updateIfNeeded];
slouken@6848
   384
        [nscontext makeCurrentContext];
slouken@6848
   385
    } else {
slouken@6848
   386
        [NSOpenGLContext clearCurrentContext];
slouken@1936
   387
    }
slouken@1936
   388
slouken@1936
   389
    return 0;
slime73@9587
   390
}}
slouken@1936
   391
urkle@7746
   392
void
urkle@7746
   393
Cocoa_GL_GetDrawableSize(_THIS, SDL_Window * window, int * w, int * h)
urkle@7746
   394
{
urkle@7746
   395
    SDL_WindowData *windata = (SDL_WindowData *) window->driverdata;
urkle@7746
   396
    NSView *contentView = [windata->nswindow contentView];
urkle@7746
   397
    NSRect viewport = [contentView bounds];
urkle@7746
   398
icculus@12338
   399
    if (window->flags & SDL_WINDOW_ALLOW_HIGHDPI) {
icculus@12338
   400
        /* This gives us the correct viewport for a Retina-enabled view, only
icculus@12338
   401
         * supported on 10.7+. */
icculus@12338
   402
        if ([contentView respondsToSelector:@selector(convertRectToBacking:)]) {
icculus@12338
   403
            viewport = [contentView convertRectToBacking:viewport];
icculus@12338
   404
        }
urkle@7746
   405
    }
urkle@7746
   406
urkle@7746
   407
    if (w) {
urkle@7746
   408
        *w = viewport.size.width;
urkle@7746
   409
    }
urkle@7746
   410
urkle@7746
   411
    if (h) {
urkle@7746
   412
        *h = viewport.size.height;
urkle@7746
   413
    }
urkle@7746
   414
}
urkle@7746
   415
slouken@1936
   416
int
slouken@1936
   417
Cocoa_GL_SetSwapInterval(_THIS, int interval)
slime73@9587
   418
{ @autoreleasepool
slouken@1936
   419
{
icculus@12477
   420
    SDLOpenGLContext *nscontext = (SDLOpenGLContext *) SDL_GL_GetCurrentContext();
slouken@1936
   421
    int status;
slouken@1936
   422
icculus@12477
   423
    if (nscontext == nil) {
icculus@12477
   424
        status = SDL_SetError("No current OpenGL context");
icculus@12477
   425
    } else {
icculus@12477
   426
        SDL_LockMutex(nscontext->swapIntervalMutex);
icculus@12477
   427
        SDL_AtomicSet(&nscontext->swapIntervalsPassed, 0);
icculus@12477
   428
        SDL_AtomicSet(&nscontext->swapIntervalSetting, interval);
icculus@12477
   429
        SDL_UnlockMutex(nscontext->swapIntervalMutex);
slouken@6848
   430
        status = 0;
slouken@1936
   431
    }
slouken@1936
   432
slouken@1936
   433
    return status;
slime73@9587
   434
}}
slouken@1936
   435
slouken@1936
   436
int
slouken@1936
   437
Cocoa_GL_GetSwapInterval(_THIS)
slime73@9587
   438
{ @autoreleasepool
slouken@1936
   439
{
icculus@12477
   440
    SDLOpenGLContext *nscontext = (SDLOpenGLContext *) SDL_GL_GetCurrentContext();
icculus@12477
   441
    return nscontext ? SDL_AtomicGet(&nscontext->swapIntervalSetting) : 0;
slime73@9587
   442
}}
slouken@1936
   443
slouken@10690
   444
int
slouken@1936
   445
Cocoa_GL_SwapWindow(_THIS, SDL_Window * window)
slime73@9587
   446
{ @autoreleasepool
slouken@1936
   447
{
slouken@7738
   448
    SDLOpenGLContext* nscontext = (SDLOpenGLContext*)SDL_GL_GetCurrentContext();
icculus@12343
   449
    SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
icculus@12477
   450
    const int setting = SDL_AtomicGet(&nscontext->swapIntervalSetting);
icculus@12477
   451
icculus@12477
   452
    if (setting == 0) {
icculus@12477
   453
        /* nothing to do if vsync is disabled, don't even lock */
icculus@12477
   454
    } else if (setting < 0) {  /* late swap tearing */
icculus@12477
   455
        SDL_LockMutex(nscontext->swapIntervalMutex);
icculus@12477
   456
        while (SDL_AtomicGet(&nscontext->swapIntervalsPassed) == 0) {
icculus@12477
   457
            SDL_CondWait(nscontext->swapIntervalCond, nscontext->swapIntervalMutex);
icculus@12477
   458
        }
icculus@12477
   459
        SDL_AtomicSet(&nscontext->swapIntervalsPassed, 0);
icculus@12477
   460
        SDL_UnlockMutex(nscontext->swapIntervalMutex);
icculus@12477
   461
    } else {
icculus@12477
   462
        SDL_LockMutex(nscontext->swapIntervalMutex);
icculus@12477
   463
        do {  /* always wait here so we know we just hit a swap interval. */
icculus@12477
   464
            SDL_CondWait(nscontext->swapIntervalCond, nscontext->swapIntervalMutex);
icculus@12477
   465
        } while ((SDL_AtomicGet(&nscontext->swapIntervalsPassed) % setting) != 0);
icculus@12477
   466
        SDL_AtomicSet(&nscontext->swapIntervalsPassed, 0);
icculus@12477
   467
        SDL_UnlockMutex(nscontext->swapIntervalMutex);
icculus@12477
   468
    }
icculus@12343
   469
icculus@12343
   470
    /* on 10.14 ("Mojave") and later, this deadlocks if two contexts in two
icculus@12343
   471
       threads try to swap at the same time, so put a mutex around it. */
icculus@12343
   472
    SDL_LockMutex(videodata->swaplock);
slouken@7408
   473
    [nscontext flushBuffer];
jorgen@7594
   474
    [nscontext updateIfNeeded];
icculus@12343
   475
    SDL_UnlockMutex(videodata->swaplock);
slouken@10690
   476
    return 0;
slime73@9587
   477
}}
slouken@1936
   478
slouken@1936
   479
void
slouken@1936
   480
Cocoa_GL_DeleteContext(_THIS, SDL_GLContext context)
slime73@9587
   481
{ @autoreleasepool
slouken@1936
   482
{
jorgen@7595
   483
    SDLOpenGLContext *nscontext = (SDLOpenGLContext *)context;
slouken@1936
   484
jorgen@7595
   485
    [nscontext setWindow:NULL];
slouken@6848
   486
    [nscontext release];
slime73@9587
   487
}}
slouken@1936
   488
slouken@1952
   489
#endif /* SDL_VIDEO_OPENGL_CGL */
slouken@1936
   490
slouken@1936
   491
/* vi: set ts=4 sw=4 expandtab: */