diff src/video/cocoa/SDL_cocoaopengl.m @ 1936:83946ee0ff1f

Implemented OpenGL support on Mac OS X The OpenGL renderer works without changes, yay! :)
author Sam Lantinga <slouken@libsdl.org>
date Tue, 25 Jul 2006 06:22:42 +0000
parents
children 420716272158
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/video/cocoa/SDL_cocoaopengl.m	Tue Jul 25 06:22:42 2006 +0000
@@ -0,0 +1,357 @@
+/*
+    SDL - Simple DirectMedia Layer
+    Copyright (C) 1997-2006 Sam Lantinga
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+    Sam Lantinga
+    slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+#include "SDL_cocoavideo.h"
+
+/* NSOpenGL implementation of SDL OpenGL support */
+
+#if SDL_VIDEO_OPENGL
+#include <OpenGL/CGLTypes.h>
+
+#include "SDL_loadso.h"
+#include "SDL_opengl.h"
+
+
+#define DEFAULT_OPENGL_PATH  "/System/Library/Frameworks/OpenGL.framework/Libraries/libGL.dylib"
+
+/* This is implemented in Mac OS X 10.3 and above */
+#if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_3
+@implementation NSOpenGLContext(CGLContextAccess)
+- (CGLContextObj)CGLContextObj;
+{
+    return _contextAuxiliary;
+}
+@end
+#endif /* < 10.3 */
+
+int
+Cocoa_GL_LoadLibrary(_THIS, const char *path)
+{
+    if (_this->gl_config.driver_loaded) {
+        if (path) {
+            SDL_SetError("OpenGL library already loaded");
+            return -1;
+        } else {
+            ++_this->gl_config.driver_loaded;
+            return 0;
+        }
+    }
+    if (path == NULL) {
+        path = DEFAULT_OPENGL_PATH;
+    }
+    _this->gl_config.dll_handle = SDL_LoadObject(path);
+    if (!_this->gl_config.dll_handle) {
+        return -1;
+    }
+    SDL_strlcpy(_this->gl_config.driver_path, path,
+                SDL_arraysize(_this->gl_config.driver_path));
+    _this->gl_config.driver_loaded = 1;
+    return 0;
+}
+
+void *
+Cocoa_GL_GetProcAddress(_THIS, const char *proc)
+{
+    return SDL_LoadFunction(_this->gl_config.dll_handle, proc);
+}
+
+static void
+Cocoa_GL_UnloadLibrary(_THIS)
+{
+    if (_this->gl_config.driver_loaded > 0) {
+        if (--_this->gl_config.driver_loaded > 0) {
+            return;
+        }
+        SDL_UnloadObject(_this->gl_config.dll_handle);
+        _this->gl_config.dll_handle = NULL;
+    }
+}
+
+static void
+Cocoa_GL_Shutdown(_THIS)
+{
+    if (!_this->gl_data || (--_this->gl_data->initialized > 0)) {
+        return;
+    }
+
+    Cocoa_GL_UnloadLibrary(_this);
+
+    SDL_free(_this->gl_data);
+    _this->gl_data = NULL;
+}
+
+static int
+Cocoa_GL_Initialize(_THIS)
+{
+    if (_this->gl_data) {
+        ++_this->gl_data->initialized;
+        return 0;
+    }
+
+    _this->gl_data =
+        (struct SDL_GLDriverData *) SDL_calloc(1,
+                                               sizeof(struct
+                                                      SDL_GLDriverData));
+    if (!_this->gl_data) {
+        SDL_OutOfMemory();
+        return -1;
+    }
+    _this->gl_data->initialized = 1;
+
+    if (Cocoa_GL_LoadLibrary(_this, NULL) < 0) {
+        return -1;
+    }
+    return 0;
+}
+
+int
+Cocoa_GL_SetupWindow(_THIS, SDL_Window * window)
+{
+    if (Cocoa_GL_Initialize(_this) < 0) {
+        return -1;
+    }
+    return 0;
+}
+
+void
+Cocoa_GL_CleanupWindow(_THIS, SDL_Window * window)
+{
+    Cocoa_GL_Shutdown(_this);
+}
+
+SDL_GLContext
+Cocoa_GL_CreateContext(_THIS, SDL_Window * window)
+{
+    NSAutoreleasePool *pool;
+    SDL_VideoDisplay *display = SDL_GetDisplayFromWindow(window);
+    SDL_DisplayData *displaydata = (SDL_DisplayData *)display->driverdata;
+    NSOpenGLPixelFormatAttribute attr[32];
+    NSOpenGLPixelFormat *fmt;
+    NSOpenGLContext *nscontext;
+    int i = 0;
+
+    pool = [[NSAutoreleasePool alloc] init];
+
+    if (window->flags & SDL_WINDOW_FULLSCREEN) {
+        attr[i++] = NSOpenGLPFAFullScreen;
+    }
+
+    attr[i++] = NSOpenGLPFAColorSize;
+    attr[i++] = SDL_BYTESPERPIXEL(display->current_mode.format)*8;
+
+    attr[i++] = NSOpenGLPFADepthSize;
+    attr[i++] = _this->gl_config.depth_size;
+
+    if (_this->gl_config.double_buffer) {
+        attr[i++] = NSOpenGLPFADoubleBuffer;
+    }
+
+    if (_this->gl_config.stereo) {
+        attr[i++] = NSOpenGLPFAStereo;
+    }
+
+    if (_this->gl_config.stencil_size) {
+        attr[i++] = NSOpenGLPFAStencilSize;
+        attr[i++] = _this->gl_config.stencil_size;
+    }
+
+    if ((_this->gl_config.accum_red_size +
+         _this->gl_config.accum_green_size +
+         _this->gl_config.accum_blue_size +
+         _this->gl_config.accum_alpha_size) > 0) {
+        attr[i++] = NSOpenGLPFAAccumSize;
+        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;
+    }
+
+    if (_this->gl_config.multisamplebuffers) {
+        attr[i++] = NSOpenGLPFASampleBuffers;
+        attr[i++] = _this->gl_config.multisamplebuffers;
+    }
+
+    if (_this->gl_config.multisamplesamples) {
+        attr[i++] = NSOpenGLPFASamples;
+        attr[i++] = _this->gl_config.multisamplesamples;
+        attr[i++] = NSOpenGLPFANoRecovery;
+    }
+
+    if (_this->gl_config.accelerated > 0) {
+        attr[i++] = NSOpenGLPFAAccelerated;
+    }
+
+    attr[i++] = NSOpenGLPFAScreenMask;
+    attr[i++] = CGDisplayIDToOpenGLDisplayMask(displaydata->display);
+    attr[i] = 0;
+
+    fmt = [[NSOpenGLPixelFormat alloc] initWithAttributes:attr];
+    if (fmt == nil) {
+        SDL_SetError ("Failed creating OpenGL pixel format");
+        [pool release];
+        return NULL;
+    }
+
+    nscontext = [[NSOpenGLContext alloc] initWithFormat:fmt shareContext:nil];
+
+    [fmt release];
+
+    if (nscontext == nil) {
+        SDL_SetError ("Failed creating OpenGL context");
+        [pool release];
+        return NULL;
+    }
+
+    /*
+     * Wisdom from Apple engineer in reference to UT2003's OpenGL performance:
+     *  "You are blowing a couple of the internal OpenGL function caches. This
+     *  appears to be happening in the VAO case.  You can tell OpenGL to up
+     *  the cache size by issuing the following calls right after you create
+     *  the OpenGL context.  The default cache size is 16."    --ryan.
+     */
+
+    #ifndef GLI_ARRAY_FUNC_CACHE_MAX
+    #define GLI_ARRAY_FUNC_CACHE_MAX 284
+    #endif
+
+    #ifndef GLI_SUBMIT_FUNC_CACHE_MAX
+    #define GLI_SUBMIT_FUNC_CACHE_MAX 280
+    #endif
+
+    {
+        long cache_max = 64;
+        CGLContextObj ctx = [nscontext CGLContextObj];
+        CGLSetParameter (ctx, GLI_SUBMIT_FUNC_CACHE_MAX, &cache_max);
+        CGLSetParameter (ctx, GLI_ARRAY_FUNC_CACHE_MAX, &cache_max);
+    }
+
+    /* End Wisdom from Apple Engineer section. --ryan. */
+
+    /* FIXME: should this go somewhere else? */
+    if (window->flags & SDL_WINDOW_FULLSCREEN) {
+        [nscontext setFullScreen];
+    }
+
+    [pool release];
+    return nscontext;
+}
+
+int
+Cocoa_GL_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context)
+{
+    NSAutoreleasePool *pool;
+
+    pool = [[NSAutoreleasePool alloc] init];
+
+    if (context) {
+        SDL_WindowData *windowdata = (SDL_WindowData *)window->driverdata;
+        NSOpenGLContext *nscontext = (NSOpenGLContext *)context;
+
+        [nscontext setView:[windowdata->window contentView]];
+        [nscontext makeCurrentContext];
+    } else {
+        [NSOpenGLContext clearCurrentContext];
+    }
+
+    [pool release];
+    return 0;
+}
+
+int
+Cocoa_GL_SetSwapInterval(_THIS, int interval)
+{
+    NSAutoreleasePool *pool;
+    NSOpenGLContext *nscontext;
+    long value;
+    int status;
+
+    pool = [[NSAutoreleasePool alloc] init];
+
+    nscontext = [NSOpenGLContext currentContext];
+    if (nscontext != nil) {
+        value = interval;
+        [nscontext setValues:&value forParameter:NSOpenGLCPSwapInterval];
+        status = 0;
+    } else {
+        SDL_SetError("No current OpenGL context");
+        status = -1;
+    }
+
+    [pool release];
+    return status;
+}
+
+int
+Cocoa_GL_GetSwapInterval(_THIS)
+{
+    NSAutoreleasePool *pool;
+    NSOpenGLContext *nscontext;
+    long value;
+    int status;
+
+    pool = [[NSAutoreleasePool alloc] init];
+
+    nscontext = [NSOpenGLContext currentContext];
+    if (nscontext != nil) {
+        [nscontext getValues:&value forParameter:NSOpenGLCPSwapInterval];
+        status = (int)value;
+    } else {
+        SDL_SetError("No current OpenGL context");
+        status = -1;
+    }
+
+    [pool release];
+    return status;
+}
+
+void
+Cocoa_GL_SwapWindow(_THIS, SDL_Window * window)
+{
+    NSAutoreleasePool *pool;
+    NSOpenGLContext *nscontext;
+
+    pool = [[NSAutoreleasePool alloc] init];
+
+    /* FIXME: Do we need to get the context for the window? */
+    nscontext = [NSOpenGLContext currentContext];
+    if (nscontext != nil) {
+        [nscontext flushBuffer];
+    }
+
+    [pool release];
+}
+
+void
+Cocoa_GL_DeleteContext(_THIS, SDL_GLContext context)
+{
+    NSAutoreleasePool *pool;
+    NSOpenGLContext *nscontext = (NSOpenGLContext *)context;
+
+    pool = [[NSAutoreleasePool alloc] init];
+
+    [nscontext clearDrawable];
+    [nscontext release];
+
+    [pool release];
+}
+
+#endif /* SDL_VIDEO_OPENGL */
+
+/* vi: set ts=4 sw=4 expandtab: */