diff options
-rw-r--r-- | cogl/Makefile.am | 7 | ||||
-rw-r--r-- | cogl/cogl-renderer.c | 6 | ||||
-rw-r--r-- | cogl/cogl-renderer.h | 1 | ||||
-rw-r--r-- | cogl/winsys/cogl-winsys-osx.m | 470 | ||||
-rw-r--r-- | configure.ac | 35 |
5 files changed, 516 insertions, 3 deletions
diff --git a/cogl/Makefile.am b/cogl/Makefile.am index 0c223b86..288ef521 100644 --- a/cogl/Makefile.am +++ b/cogl/Makefile.am @@ -34,6 +34,8 @@ AM_CPPFLAGS = \ AM_CFLAGS = $(COGL_DEP_CFLAGS) $(COGL_EXTRA_CFLAGS) $(MAINTAINER_CFLAGS) +AM_OBJCFLAGS= $(COGL_OBJCFLAGS) $(COGL_DEP_CFLAGS) $(COGL_EXTRA_CFLAGS) $(MAINTAINER_CFLAGS) + BUILT_SOURCES += cogl-defines.h DISTCLEANFILES += cogl-defines.h EXTRA_DIST += cogl-defines.h.in @@ -432,6 +434,11 @@ cogl_sources_c += \ $(srcdir)/winsys/cogl-winsys-sdl.c endif +if OS_OSX +cogl_sources_c += \ + $(srcdir)/winsys/cogl-winsys-osx.m +endif + EXTRA_DIST += stb_image.c # glib-mkenums rules diff --git a/cogl/cogl-renderer.c b/cogl/cogl-renderer.c index 1a01b594..55b5cb08 100644 --- a/cogl/cogl-renderer.c +++ b/cogl/cogl-renderer.c @@ -77,6 +77,9 @@ extern const CoglWinsysVtable *_cogl_winsys_wgl_get_vtable (void); #ifdef COGL_HAS_SDL_SUPPORT extern const CoglWinsysVtable *_cogl_winsys_sdl_get_vtable (void); #endif +#ifdef COGL_HAS_OSX_SUPPORT +extern const CoglWinsysVtable *_cogl_winsys_osx_get_vtable (void); +#endif typedef const CoglWinsysVtable *(*CoglWinsysVtableGetter) (void); @@ -109,6 +112,9 @@ static CoglWinsysVtableGetter _cogl_winsys_vtable_getters[] = #ifdef COGL_HAS_SDL_SUPPORT _cogl_winsys_sdl_get_vtable, #endif +#ifdef COGL_HAS_OSX_SUPPORT + _cogl_winsys_osx_get_vtable, +#endif _cogl_winsys_stub_get_vtable, }; diff --git a/cogl/cogl-renderer.h b/cogl/cogl-renderer.h index 94d4de9d..d7f0768a 100644 --- a/cogl/cogl-renderer.h +++ b/cogl/cogl-renderer.h @@ -72,6 +72,7 @@ cogl_renderer_new (void); * @COGL_WINSYS_ID_EGL_ANDROID: Use EGL with the Android platform * @COGL_WINSYS_ID_WGL: Use the Microsoft Windows WGL binding API * @COGL_WINSYS_ID_SDL: Use the SDL window system + * @COGL_WINSYS_ID_OSX: Use the OSX window system * * Identifies specific window system backends that Cogl supports. * diff --git a/cogl/winsys/cogl-winsys-osx.m b/cogl/winsys/cogl-winsys-osx.m new file mode 100644 index 00000000..6ebaf871 --- /dev/null +++ b/cogl/winsys/cogl-winsys-osx.m @@ -0,0 +1,470 @@ +/* + * Cogl + * + * An object oriented GL/GLES Abstraction/Utility Layer + * + * Copyright (C) 2011 Intel Corporation. + * + * 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 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, see <http://www.gnu.org/licenses/>. + * + * + * Authors: + * Neil Roberts <neil@linux.intel.com> + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "cogl-renderer-private.h" +#include "cogl-display-private.h" +#include "cogl-framebuffer-private.h" +#include "cogl-swap-chain-private.h" +#include "cogl-onscreen-template-private.h" +#include "cogl-context-private.h" +#include "cogl-onscreen-private.h" + +#import <AppKit/AppKit.h> + +/* might need this */ +#if 0 +@class NSOpenGLPixelFormat, NSOpenGLContext; +#endif + +typedef struct _CoglRendererOSX +{ + int stub; +} CoglRendererOSX; + +typedef struct _CoglDisplayOSX +{ + NSOpenGLPixelFormat *ns_pixel_format; + NSOpenGLView *ns_dummy_view; + NSWindow *ns_dummy_window; + NSOpenGLContext *ns_context; +} CoglDisplayOSX; + +typedef struct _CoglOnscreenOSX +{ + NSOpenGLPixelFormat *ns_pixel_format; + NSOpenGLView *ns_view; + NSWindow *ns_window; +} CoglOnscreenOSX; + +#if 0 +@interface CoglOSXOpenGLView : NSOpenGLView +{ + CoglOnscreen *onscreen; +} +- (id) initWithContext: (CoglContext *) context: (int) width: (int) height; +//- (void) drawRect: (NSRect) bounds; +@end +#endif + +static CoglFuncPtr +_cogl_winsys_renderer_get_proc_address (CoglRenderer *renderer, + const char *name) +{ + static GModule *module = NULL; + + /* this should find the right function if the program is linked against a + * library providing it */ + if (G_UNLIKELY (module == NULL)) + module = g_module_open (NULL, 0); + + if (module) + { + void *symbol; + + if (g_module_symbol (module, name, &symbol)) + return symbol; + } + + return NULL; +} + +static void +_cogl_winsys_renderer_disconnect (CoglRenderer *renderer) +{ + g_slice_free (CoglRendererOSX, renderer->winsys); +} + +static gboolean +_cogl_winsys_renderer_connect (CoglRenderer *renderer, + GError **error) +{ + NSAutoreleasePool *autorelease_pool = [[NSAutoreleasePool alloc] init]; + NSApplication *myApplication; + + /* XXX: Hack to trick gnustep into initializing its backend including the + * GSDisplayServer which we require to access GLX. */ + if (!NSApp) + myApplication = [NSApplication sharedApplication]; + + [autorelease_pool release]; + + if (renderer->driver != COGL_DRIVER_GL) + { + g_set_error (error, COGL_WINSYS_ERROR, + COGL_WINSYS_ERROR_INIT, + "The OSX winsys only supports the GL driver"); + return FALSE; + } + + renderer->winsys = g_slice_new0 (CoglRendererOSX); + return TRUE; +} + +static void +_cogl_winsys_display_destroy (CoglDisplay *display) +{ + CoglDisplayOSX *ns_display = display->winsys; + + _COGL_RETURN_IF_FAIL (ns_display != NULL); + + if (ns_display->ns_context) + [ns_display->ns_context release]; + + if (ns_display->ns_pixel_format) + [ns_display->ns_pixel_format release]; + + g_slice_free (CoglDisplayOSX, display->winsys); + display->winsys = NULL; +} + +#define MAX_PIXEL_FORMAT_ATTRIBS 30 + +static NSOpenGLPixelFormat * +ns_pixel_format_from_framebuffer_config (CoglFramebufferConfig *config) +{ + NSOpenGLPixelFormatAttribute attrs[MAX_PIXEL_FORMAT_ATTRIBS]; + int i = 0; + + attrs[i++] = NSOpenGLPFAMinimumPolicy; + + if (config->swap_chain->length >= 1) + attrs[i++] = NSOpenGLPFADoubleBuffer; + + if (config->need_stencil) + { + attrs[i++] = NSOpenGLPFAStencilSize; + attrs[i++] = 8; + } + + if (config->swap_chain->has_alpha) + { + attrs[i++] = NSOpenGLPFAAlphaSize; + attrs[i++] = 1; + } + + attrs[i++] = NSOpenGLPFADepthSize; + attrs[i++] = 24; + + if (config->samples_per_pixel) + { + attrs[i++] = NSOpenGLPFAMultisample; + attrs[i++] = NSOpenGLPFASampleBuffers; + attrs[i++] = 1; + attrs[i++] = NSOpenGLPFASamples; + attrs[i++] = config->samples_per_pixel; + } + + attrs[i++] = 0; + + g_assert (i < MAX_PIXEL_FORMAT_ATTRIBS); + + return [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs]; +} + +static gboolean +create_context (CoglDisplay *display, + GError **error) +{ + CoglDisplayOSX *ns_display = display->winsys; + CoglFramebufferConfig *config; +#ifndef USING_GNUSTEP + const long sw = 1; +#endif + gboolean status = TRUE; + NSRect rect; + + NSAutoreleasePool *autorelease_pool = [[NSAutoreleasePool alloc] init]; + + config = &display->onscreen_template->config; + ns_display->ns_pixel_format = + ns_pixel_format_from_framebuffer_config (config); + if (!ns_display->ns_pixel_format) + { + g_set_error (error, COGL_WINSYS_ERROR, + COGL_WINSYS_ERROR_CREATE_CONTEXT, + "Unable to find suitable GL pixel format"); + status = FALSE; + goto done; + } + + config = &display->onscreen_template->config; + ns_display->ns_context = + [[NSOpenGLContext alloc] initWithFormat: ns_display->ns_pixel_format + shareContext: nil]; + if (!ns_display->ns_context) + { + g_set_error (error, COGL_WINSYS_ERROR, + COGL_WINSYS_ERROR_CREATE_CONTEXT, + "Unable to create suitable GL context"); + status = FALSE; + goto done; + } + +#ifndef USING_GNUSTEP + /* Enable vblank sync - http://developer.apple.com/qa/qa2007/qa1521.html */ + [ns_display->ns_context setValues:&sw forParameter: NSOpenGLCPSwapInterval]; +#endif + + rect = NSMakeRect (0, 0, 1, 1); + + ns_display->ns_dummy_view = [[NSOpenGLView alloc] + initWithFrame: rect + pixelFormat: ns_display->ns_pixel_format]; + if (!ns_display->ns_dummy_view) + { + g_set_error (error, COGL_WINSYS_ERROR, + COGL_WINSYS_ERROR_CREATE_ONSCREEN, + "Unable to create suitable NSView"); + status = FALSE; + goto done; + } + + ns_display->ns_dummy_window = [[NSWindow alloc] + initWithContentRect: [ns_display->ns_dummy_view frame] + styleMask: NSTitledWindowMask | NSClosableWindowMask | NSResizableWindowMask + backing: NSBackingStoreBuffered + defer: NO]; + if (!ns_display->ns_dummy_window) + { + g_set_error (error, COGL_WINSYS_ERROR, + COGL_WINSYS_ERROR_CREATE_ONSCREEN, + "Unable to create suitable NSWindow"); + status = FALSE; + goto done; + } + [ns_display->ns_dummy_window setContentView:ns_display->ns_dummy_view]; + [ns_display->ns_dummy_window useOptimizedDrawing:YES]; + + [ns_display->ns_dummy_view setOpenGLContext:ns_display->ns_context]; + + [ns_display->ns_context setView: ns_display->ns_dummy_view]; + [ns_display->ns_context makeCurrentContext]; + +done: + [autorelease_pool release]; + return status; +} + +static gboolean +_cogl_winsys_display_setup (CoglDisplay *display, + GError **error) +{ + CoglDisplayOSX *ns_display; + + _COGL_RETURN_VAL_IF_FAIL (display->winsys == NULL, FALSE); + + ns_display = g_slice_new0 (CoglDisplayOSX); + display->winsys = ns_display; + + if (!create_context (display, error)) + goto error; + + return TRUE; +error: + _cogl_winsys_display_destroy (display); + return FALSE; +} + +static gboolean +_cogl_winsys_context_init (CoglContext *context, GError **error) +{ + return _cogl_context_update_features (context, error); +} + +static void +_cogl_winsys_context_deinit (CoglContext *context) +{ +} + +static void +_cogl_winsys_onscreen_bind (CoglOnscreen *onscreen) +{ + CoglContext *context = COGL_FRAMEBUFFER (onscreen)->context; + CoglDisplay *display = context->display; + CoglDisplayOSX *ns_display = display->winsys; + CoglOnscreenOSX *ns_onscreen = onscreen->winsys; + + NSAutoreleasePool *autorelease_pool = [[NSAutoreleasePool alloc] init]; + + [ns_display->ns_context setView: ns_onscreen->ns_view]; + + [autorelease_pool release]; +} + +static void +_cogl_winsys_onscreen_deinit (CoglOnscreen *onscreen) +{ +} + +static gboolean +_cogl_winsys_onscreen_init (CoglOnscreen *onscreen, + GError **error) +{ + CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen); + CoglContext *context = framebuffer->context; + CoglDisplay *display = context->display; + CoglDisplayOSX *ns_display = display->winsys; + CoglOnscreenOSX *ns_onscreen; + int width, height; + NSRect rect; + gboolean status = TRUE; + + NSAutoreleasePool *autorelease_pool = [[NSAutoreleasePool alloc] init]; + + ns_onscreen = g_slice_new0 (CoglOnscreenOSX); + onscreen->winsys = ns_onscreen; + + ns_onscreen->ns_pixel_format = + ns_pixel_format_from_framebuffer_config (&framebuffer->config); + if (!ns_onscreen->ns_pixel_format) + { + g_set_error (error, COGL_WINSYS_ERROR, + COGL_WINSYS_ERROR_CREATE_ONSCREEN, + "Unable to create suitable NSOpenGLPixelFormat"); + status = FALSE; + goto done; + } + + width = cogl_framebuffer_get_width (framebuffer); + height = cogl_framebuffer_get_height (framebuffer); + + rect = NSMakeRect (0, 0, width, height); + + ns_onscreen->ns_view = [[NSOpenGLView alloc] + initWithFrame: rect + pixelFormat: ns_onscreen->ns_pixel_format]; + if (!ns_onscreen->ns_view) + { + g_set_error (error, COGL_WINSYS_ERROR, + COGL_WINSYS_ERROR_CREATE_ONSCREEN, + "Unable to create suitable NSView"); + status = FALSE; + goto done; + } + [ns_onscreen->ns_view setOpenGLContext:ns_display->ns_context]; + + ns_onscreen->ns_window = [[NSWindow alloc] + initWithContentRect: [ns_onscreen->ns_view frame] + styleMask: NSTitledWindowMask | NSClosableWindowMask | NSResizableWindowMask + backing: NSBackingStoreBuffered + defer: NO]; + if (!ns_onscreen->ns_window) + { + g_set_error (error, COGL_WINSYS_ERROR, + COGL_WINSYS_ERROR_CREATE_ONSCREEN, + "Unable to create suitable NSWindow"); + status = FALSE; + goto done; + } + + [ns_onscreen->ns_window setContentView:ns_onscreen->ns_view]; + [ns_onscreen->ns_window useOptimizedDrawing:YES]; + + //[ns_onscreen->ns_view setOpenGLContext:ns_display->ns_context]; +#if 0 + + [ns_display->ns_context setView: ns_onscreen->ns_view]; + [ns_display->ns_context makeCurrentContext]; +#endif + +done: + [autorelease_pool release]; + return status; +} + +static void +_cogl_winsys_onscreen_swap_buffers (CoglOnscreen *onscreen) +{ + CoglContext *context = COGL_FRAMEBUFFER (onscreen)->context; + CoglDisplay *display = context->display; + CoglDisplayOSX *ns_display = display->winsys; + + [ns_display->ns_context flushBuffer]; +} + +static void +_cogl_winsys_onscreen_update_swap_throttled (CoglOnscreen *onscreen) +{ + /* OSX doesn't appear to provide a way to set this per window */ +} + +static void +_cogl_winsys_onscreen_set_visibility (CoglOnscreen *onscreen, + gboolean visibility) +{ + CoglContext *context = COGL_FRAMEBUFFER (onscreen)->context; + CoglDisplay *display = context->display; + CoglDisplayOSX *ns_display = display->winsys; + CoglOnscreenOSX *ns_onscreen = onscreen->winsys; + + NSAutoreleasePool *autorelease_pool = [[NSAutoreleasePool alloc] init]; + if (visibility) + [ns_onscreen->ns_window makeKeyAndOrderFront: nil]; + else + [ns_onscreen->ns_window orderOut: nil]; + + /* XXX: HACK */ + [ns_display->ns_context setView: ns_onscreen->ns_view]; + [ns_display->ns_context makeCurrentContext]; + + [autorelease_pool release]; +} + +const CoglWinsysVtable * +_cogl_winsys_osx_get_vtable (void) +{ + static gboolean vtable_inited = FALSE; + static CoglWinsysVtable vtable; + + if (!vtable_inited) + { + memset (&vtable, 0, sizeof (vtable)); + + vtable.id = COGL_WINSYS_ID_SDL; + vtable.name = "OSX"; + vtable.renderer_get_proc_address = _cogl_winsys_renderer_get_proc_address; + vtable.renderer_connect = _cogl_winsys_renderer_connect; + vtable.renderer_disconnect = _cogl_winsys_renderer_disconnect; + vtable.display_setup = _cogl_winsys_display_setup; + vtable.display_destroy = _cogl_winsys_display_destroy; + vtable.context_init = _cogl_winsys_context_init; + vtable.context_deinit = _cogl_winsys_context_deinit; + vtable.onscreen_init = _cogl_winsys_onscreen_init; + vtable.onscreen_deinit = _cogl_winsys_onscreen_deinit; + vtable.onscreen_bind = _cogl_winsys_onscreen_bind; + vtable.onscreen_swap_buffers = _cogl_winsys_onscreen_swap_buffers; + vtable.onscreen_update_swap_throttled = + _cogl_winsys_onscreen_update_swap_throttled; + vtable.onscreen_set_visibility = _cogl_winsys_onscreen_set_visibility; + + vtable_inited = TRUE; + } + + return &vtable; +} diff --git a/configure.ac b/configure.ac index 755cb5f2..877850cb 100644 --- a/configure.ac +++ b/configure.ac @@ -159,8 +159,7 @@ AS_CASE([$host], AC_MSG_RESULT([$platform_win32]) AM_CONDITIONAL(OS_WIN32, [test "$platform_win32" = "yes"]) -AC_CHECK_HEADER([OpenGL/gl.h], [platform_quartz=yes], [platform_quartz=no]) -AM_CONDITIONAL(OS_QUARTZ, [test "$platform_quartz" = "yes"]) +AC_CHECK_HEADER([OpenGL/gl.h], [platform_osx=yes], [platform_osx=no]) dnl ================================================================ dnl Handle extra configure options @@ -318,6 +317,26 @@ AS_CASE([$enable_deprecated], # strip leading spaces COGL_EXTRA_CFLAGS="$COGL_EXTRA_CFLAGS ${DEPRECATED_CFLAGS#* }" +COGL_OBJCFLAGS="" +AC_ARG_ENABLE( + [osx], + [AC_HELP_STRING([--enable-osx=@<:@no/yes@:>@], [Enable the osx winsys (also works with gnustep) @<:@default=auto@:>@])], + [platform_osx=$enable_osx], +) +if test "x$platform_osx" = "xyes"; then + AC_CHECK_PROG(platform_gnustep, gnustep-config, yes, no) + AC_PROG_OBJC + COGL_DEFINES_SYMBOLS="$COGL_DEFINES_SYMBOLS COGL_HAS_OSX_SUPPORT" + GL_WINSYS_APIS="$GL_WINSYS_APIS osx" +fi +if test "x$platform_gnustep" = "xyes"; then + COGL_OBJCFLAGS=`gnustep-config --objc-flags` + COGL_EXTRA_LDFLAGS="$COGL_EXTRA_LDFLAGS `gnustep-config --gui-libs`" + AC_DEFINE([USING_GNUSTEP], 1, [Using the gnustep build environment]) +fi +AM_CONDITIONAL(OS_OSX, [test "$platform_osx" = "yes"]) +AC_SUBST(COGL_OBJCFLAGS) + dnl ============================================================ dnl Choose image loading backend dnl ============================================================ @@ -565,7 +584,7 @@ AS_IF([test "x$enable_gl" = "xyes"], cogl_gl_headers="GL/gl.h" - AS_IF([test "x$platform_quartz" = "xyes"], + AS_IF([test "x$platform_osx" = "xyes" -a "x$platform_gnustep" != "xyes"], [ cogl_gl_headers="OpenGL/gl.h" COGL_EXTRA_LDFLAGS="$COGL_EXTRA_LDFLAGS -framework OpenGL" @@ -573,6 +592,16 @@ AS_IF([test "x$enable_gl" = "xyes"], dnl no need to dlopen it separately GL_LIBRARY_DIRECTLY_LINKED=yes COGL_GL_LIBNAME="" + ALLOW_GLX=no + ], + + [test "x$platform_gnustep" = "xyes"], + [ + COGL_EXTRA_LDFLAGS="$COGL_EXTRA_LDFLAGS -framework OpenGL" + dnl The GL API is being directly linked in so there is + dnl no need to dlopen it separately + GL_LIBRARY_DIRECTLY_LINKED=yes + COGL_GL_LIBNAME="" ], [test "x$platform_win32" = "xyes"], |