summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaolo Bonzini <bonzini@gnu.org>2008-11-19 14:43:01 +0100
committerNicolas Bruguier <nicolas.bruguier@supersonicimagine.fr>2008-11-29 14:09:31 +0100
commit49e45fb1b8dc0f2b45254a370c62a0e36ca7be91 (patch)
treecf1fc537356a2677ab55b9ccb2cdf11e489e883b
parent87ea1a8b8a37a75e9859428e943fd8e0e41cdebb (diff)
[cgl] Add glitz-cgl backend
The backend is mostly derived from the AGL backend, but allows creating drawable on Cocoa NSView objects (*not* NSOpenGLView: the latter is mostly a NSView + OpenGL contexts and pixel formats, which glitz manages on its own). All the added files are Objective-C (.m). The only changes with respect to the AGL backend were in the pixel format queries that: 1) need to use CGL directly in order to avoid logging messages for unavailable formats; 2) needed some tweaking in order to find no-depth, no-stencil pbuffer formats (the new pbuffer format discovery code actually does not need it, but it's better to be safe; 3) have a slightly different sort order that is nicer (as seen in the output of glitzinfo). The renderer test's Objective-C bits in glitz_cgl.m has two parts in it. One is the boilerplate that sets up Cocoa without using .nib files; it can be useful only if you want to write a similar example program for Glitz. I split the test-specific code in two (before parsing command line/after parsing command line) to avoid showing the icon in the dock if the program is going to exit very soon. The second part is GlitzOpenGLView, which provides the bits of NSOpenGLView that go beyond storing OpenGL contexts and pixel formats; see the "Custom Cocoa OpenGL View" example from Apple. Programs using Glitz in their UI should be able to recycle it pretty easily as it's just four methods (one caveat: I didn't investigate how to deal with window resizes).
-rw-r--r--configure.in60
-rw-r--r--examples/glitzinfo/Makefile.am10
-rw-r--r--examples/glitzinfo/glitzinfo.c36
-rw-r--r--examples/renderer-test/Makefile.am17
-rw-r--r--examples/renderer-test/glitz_cgl.m315
-rw-r--r--src/Makefile.am2
-rw-r--r--src/cgl/.gitignore7
-rw-r--r--src/cgl/Makefile.am38
-rw-r--r--src/cgl/glitz-cgl.h86
-rw-r--r--src/cgl/glitz-cgl.man26
-rw-r--r--src/cgl/glitz-cgl.pc.in11
-rw-r--r--src/cgl/glitz_cgl_context.m520
-rw-r--r--src/cgl/glitz_cgl_drawable.m256
-rw-r--r--src/cgl/glitz_cgl_extension.m145
-rw-r--r--src/cgl/glitz_cgl_format.m338
-rw-r--r--src/cgl/glitz_cgl_info.m289
-rw-r--r--src/cgl/glitz_cgl_pbuffer.m65
-rw-r--r--src/cgl/glitz_cglint.h157
18 files changed, 2375 insertions, 3 deletions
diff --git a/configure.in b/configure.in
index d5765d1..8459802 100644
--- a/configure.in
+++ b/configure.in
@@ -46,6 +46,13 @@ AC_PROG_AWK
AM_PROG_LIBTOOL
AC_STDC_HEADERS
+# We don't require Automake 1.10, so invoke _AM_DEPENDENCIES manually. And
+# since we actually use Objective-C only on Mac OS, we get by with using
+# gcc as an Objective-C compiler.
+AC_SUBST(OBJC, ['$(CC)'])
+AC_SUBST(OBJCFLAGS, ['$(CFLAGS)'])
+_AM_DEPENDENCIES(OBJC)
+
if test "x$GCC" = "xyes"; then
case " $CFLAGS " in
*[[\ \ ]]-Wall[[\ \ ]]*) ;;
@@ -213,6 +220,56 @@ AC_SUBST(GLITZ_GLX_LIBS)
dnl ===========================================================================
+AC_ARG_ENABLE(cgl,
+ AC_HELP_STRING([--disable-cgl], [Disable glitz's NSOpenGL/CGL backend]),
+ [use_cgl=$enableval], [use_cgl=yes])
+
+AH_TEMPLATE([PTHREADS], [Define if PTHREADS are supported])
+
+if test "x$use_cgl" = "xyes"; then
+ CGL_LIBS="-framework OpenGL -framework Cocoa"
+ AC_MSG_CHECKING([for OpenGL.framework])
+ save_libs="$LIBS"
+ LIBS="-framework OpenGL"
+ AC_TRY_LINK_FUNC(CGLCreateContext, [use_cgl=yes], [use_cgl=no])
+ LIBS="$save_libs"
+ AC_MSG_RESULT([$use_cgl])
+
+ if test "x$use_cgl" = "xyes"; then
+ save_libs="$LIBS"
+ LIBS="-lpthread"
+
+ AC_MSG_CHECKING([for PTHREADS])
+ AC_TRY_LINK_FUNC(pthread_key_create, [use_pthreads=yes], [use_pthreads=no])
+
+ LIBS="$save_LIBS"
+
+ CGL_LIBS="-framework Cocoa -framework OpenGL"
+ if test "x$use_pthreads" = "xyes"
+ then
+ CGL_LIBS="$CGL_LIBS -lpthread"
+ AC_DEFINE(PTHREADS, 1)
+ fi
+ AC_MSG_RESULT($use_pthreads)
+ GLITZ_CGL_CFLAGS='$(CGL_CFLAGS) -I$(top_builddir)/src/cgl'
+ GLITZ_CGL_LIBS='$(CGL_LIBS) -L$(top_builddir)/src/cgl -lglitz-cgl'
+ fi
+fi
+
+if test "x$use_cgl" = "xyes"; then
+ AM_CONDITIONAL(GLITZ_BUILD_CGL_BACKEND, true)
+else
+ AM_CONDITIONAL(GLITZ_BUILD_CGL_BACKEND, false)
+fi
+
+AC_SUBST(CGL_CFLAGS)
+AC_SUBST(CGL_LIBS)
+AC_SUBST(GLITZ_CGL_CFLAGS)
+AC_SUBST(GLITZ_CGL_LIBS)
+
+
+dnl ===========================================================================
+
AC_ARG_ENABLE(agl,
AC_HELP_STRING([--disable-agl], [Disable glitz's AGL backend]),
[use_agl=$enableval], [use_agl=yes])
@@ -340,11 +397,13 @@ Makefile
src/Makefile
src/glx/Makefile
src/agl/Makefile
+src/cgl/Makefile
src/egl/Makefile
src/wgl/Makefile
src/glitz.pc
src/glx/glitz-glx.pc
src/agl/glitz-agl.pc
+src/cgl/glitz-cgl.pc
src/egl/glitz-egl.pc
src/wgl/glitz-wgl.pc
doc/Makefile
@@ -362,6 +421,7 @@ echo ""
echo "glitz will be compiled with the following backends:"
echo " GLX: $use_glx"
echo " AGL: $use_agl"
+echo " NSOpenGL/CGL: $use_cgl"
echo " EGL: $use_egl"
echo " WGL: $use_wgl"
echo ""
diff --git a/examples/glitzinfo/Makefile.am b/examples/glitzinfo/Makefile.am
index 22b74f7..a7b99d1 100644
--- a/examples/glitzinfo/Makefile.am
+++ b/examples/glitzinfo/Makefile.am
@@ -2,6 +2,16 @@ INCLUDES = $(GLITZ_INC)
noinst_PROGRAMS =
+if GLITZ_BUILD_CGL_BACKEND
+noinst_PROGRAMS += glitzinfo-cgl
+
+glitzinfo_cgl_CFLAGS = $(GLITZ_CGL_CFLAGS) -DGLITZ_CGL_BACKEND
+
+glitzinfo_cgl_SOURCES = glitzinfo.c
+
+glitzinfo_cgl_LDADD = $(GLITZ_LIB) $(GLITZ_CGL_LIBS)
+endif
+
if GLITZ_BUILD_AGL_BACKEND
noinst_PROGRAMS += glitzinfo-agl
diff --git a/examples/glitzinfo/glitzinfo.c b/examples/glitzinfo/glitzinfo.c
index e5eb7e6..0b7719f 100644
--- a/examples/glitzinfo/glitzinfo.c
+++ b/examples/glitzinfo/glitzinfo.c
@@ -40,6 +40,10 @@
#include <glitz-agl.h>
#endif
+#ifdef GLITZ_CGL_BACKEND
+#include <glitz-cgl.h>
+#endif
+
static void
print_features (unsigned long features)
{
@@ -245,6 +249,29 @@ main (int argc, char **argv)
}
#endif
+#ifdef GLITZ_CGL_BACKEND
+ /* Cannot make a window, it's too expensive. Find a reasonably lame
+ window format and use it to create a pbuffer. */
+ i = 0;
+ while ((dformat = glitz_cgl_find_window_format (0, 0, i)) != NULL
+ && (dformat->doublebuffer
+ || dformat->stencil_size
+ || dformat->depth_size))
+ i++;
+ if (!dformat)
+ {
+ fprintf (stderr, "Error: couldn't find drawable format\n");
+ return 1;
+ }
+
+ drawable = glitz_cgl_create_pbuffer_drawable (dformat, 1, 1);
+ if (!drawable)
+ {
+ fprintf (stderr, "Error: couldn't create glitz pbuffer drawable\n");
+ return 1;
+ }
+#endif
+
print_features (glitz_drawable_get_features (drawable));
printf ("\nWindow formats:\n");
@@ -271,6 +298,11 @@ main (int argc, char **argv)
i++;
#endif
+#ifdef GLITZ_CGL_BACKEND
+ while (print_format (glitz_cgl_find_window_format (0, 0, i)))
+ i++;
+#endif
+
printf ("\nPbuffer formats:\n");
printf ("id\tr/g/b/a \tdepth\tstencil\tdb\tsamples\n");
printf ("-------------------------------------"
@@ -343,5 +375,9 @@ main (int argc, char **argv)
glitz_agl_fini ();
#endif
+#ifdef GLITZ_CGL_BACKEND
+ glitz_cgl_fini ();
+#endif
+
return 0;
}
diff --git a/examples/renderer-test/Makefile.am b/examples/renderer-test/Makefile.am
index ae0b624..71670a8 100644
--- a/examples/renderer-test/Makefile.am
+++ b/examples/renderer-test/Makefile.am
@@ -16,8 +16,7 @@ glitz_common_sources = \
glitz.c \
glitz_common.h
-INCLUDES = $(GLITZ_INC) $(GLITZ_GLX_CFLAGS) $(GLITZ_EGL_CFLAGS) $(GLITZ_AGL_CFLAGS) \
- $(LIBPNG_CFLAGS)
+INCLUDES = $(GLITZ_INC) $(LIBPNG_CFLAGS)
if GLITZ_BUILD_GLX_BACKEND
noinst_PROGRAMS += rendertest_glitz_glx
@@ -26,6 +25,7 @@ rendertest_glitz_glx_SOURCES = \
$(glitz_common_sources) \
glitz_glx.c
+INCLUDES += $(GLITZ_GLX_CFLAGS)
rendertest_glitz_glx_LDADD = $(GLITZ_GLX_LIBS) $(LIBPNG_LIBS) -lm
endif
@@ -36,6 +36,7 @@ rendertest_glitz_egl_SOURCES = \
$(glitz_common_sources) \
glitz_egl.c
+INCLUDES += $(GLITZ_EGL_CFLAGS)
rendertest_glitz_egl_LDADD = $(GLITZ_EGL_LIBS) $(LIBPNG_LIBS) -lm
endif
@@ -46,7 +47,19 @@ rendertest_glitz_agl_SOURCES = \
$(glitz_common_sources) \
glitz_agl.c
+INCLUDES += $(GLITZ_AGL_CFLAGS)
rendertest_glitz_agl_LDADD = $(GLITZ_AGL_LIBS) $(CARBON_LIBS) $(LIBPNG_LIBS) -lm
endif
+if GLITZ_BUILD_CGL_BACKEND
+noinst_PROGRAMS += rendertest_glitz_cgl
+
+rendertest_glitz_cgl_SOURCES = \
+ $(glitz_common_sources) \
+ glitz_cgl.m
+
+INCLUDES += $(GLITZ_CGL_CFLAGS)
+rendertest_glitz_cgl_LDADD = $(GLITZ_CGL_LIBS) $(LIBPNG_LIBS) -lm
+endif
+
endif
diff --git a/examples/renderer-test/glitz_cgl.m b/examples/renderer-test/glitz_cgl.m
new file mode 100644
index 0000000..1b4bbf3
--- /dev/null
+++ b/examples/renderer-test/glitz_cgl.m
@@ -0,0 +1,315 @@
+/*
+ * Copyright © 2004 David Reveman
+ * Copyright © 2008 Paolo Bonzini
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of the
+ * copyright holders not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior permission.
+ * The copyright holders make no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express or
+ * implied warranty.
+ *
+ * COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+ * NO EVENT SHALL DAVID REVEMAN BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: David Reveman <davidr@novell.com>
+ * Author: Paolo Bonzini <bonzini@gnu.org>
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#import <OpenGL/gl.h>
+#import <OpenGL/glext.h>
+#import <OpenGL/glu.h>
+
+#include "rendertest.h"
+#include "glitz_common.h"
+#include <glitz-cgl.h>
+#import <Cocoa/Cocoa.h>
+
+
+static NSAutoreleasePool *pool;
+static NSObject *glitzMain;
+static int rendertest_main (void);
+
+@interface GlitzOpenGLView : NSView
+- (id)initWithFrame:(NSRect)frameRect;
+- (BOOL)isOpaque;
+- (void)update;
+- (void) _surfaceNeedsUpdate:(NSNotification*)notification;
+@end
+
+@interface GlitzMain : NSObject
+@end
+
+/* The view class. A (very...) simplified version of CustomOpenGLView
+ from the Custom Cocoa OpenGL example. */
+
+@implementation GlitzOpenGLView
+
+- (id)initWithFrame:(NSRect)frameRect
+{
+ self = [super initWithFrame:frameRect];
+ [[NSNotificationCenter defaultCenter]
+ addObserver:self selector:@selector(_surfaceNeedsUpdate:)
+ name:NSViewGlobalFrameDidChangeNotification object:self];
+ return self;
+}
+
+- (BOOL)isOpaque
+{
+ return YES;
+}
+
+- (void)update
+{
+ if ([[NSOpenGLContext currentContext] view] == self) {
+ [[NSOpenGLContext currentContext] update];
+ }
+}
+
+- (void) _surfaceNeedsUpdate:(NSNotification*)notification
+{
+ [self update];
+}
+
+@end
+
+
+
+/* The application delegate, which has the only purpose of firing
+ rendertest's main. */
+
+@implementation GlitzMain
+
+/* Called when the internal event loop has just started running */
+- (void) applicationDidFinishLaunching: (NSNotification *) note
+{
+ int status = rendertest_main ();
+
+ [glitzMain release];
+ [pool release];
+ exit (status);
+}
+
+@end
+
+static NSView *
+create_window (int width, int height)
+{
+ NSRect contentRect;
+ NSWindow *window;
+ NSView *view;
+
+ contentRect = NSMakeRect (50, 50, width, height);
+
+ /* Manually create a window, avoids having a nib file resource. We
+ do not care about NSMiniaturizableWindowMask and NSClosableWindowMask
+ because we do not handle events. NSResizableWindowMask wouldn't have
+ any effect for the same reason, but we explicitly do not want that. */
+ window = [ [ NSWindow alloc ]
+ initWithContentRect: contentRect
+ styleMask: NSTitledWindowMask
+ backing: NSBackingStoreBuffered
+ defer: NO ];
+
+ if (window == nil) {
+ printf ("Could not create the Cocoa window\n");
+ exit (1);
+ }
+
+ [ window setTitle: @PACKAGE ];
+ [ window setViewsNeedDisplay:NO ];
+
+ view = [ [ [ GlitzOpenGLView alloc ] init ] autorelease ];
+ [ window setContentView: view ];
+ [ window makeKeyAndOrderFront:nil ];
+ return view;
+}
+
+
+static const render_backend_t _glitz_cgl_render_backend = {
+ _glitz_render_create_similar,
+ _glitz_render_destroy,
+ _glitz_render_composite,
+ _glitz_render_set_pixels,
+ _glitz_render_show,
+ _glitz_render_set_fill,
+ _glitz_render_set_component_alpha,
+ _glitz_render_set_transform,
+ _glitz_render_set_filter,
+ _glitz_render_set_clip_rectangles,
+ _glitz_render_set_clip_trapezoids
+};
+
+typedef struct cgl_options {
+ int samples;
+ int db;
+ int offscreen;
+} cgl_options_t;
+
+static const render_option_t _cgl_options[] = {
+ { "single-buffer", 'l', NULL, 0, " use single buffered format" },
+ { "samples", 'p', "SAMPLES", 0, " use this hardware multi-sample format" },
+ { "offscreen", 'f', NULL, 0, " use offscreen rendering" },
+ { 0 }
+};
+
+static int
+_parse_option (int key, char *arg, render_arg_state_t *state)
+{
+ cgl_options_t *options = state->pointer;
+
+ switch (key) {
+ case 'l':
+ options->db = 0;
+ break;
+ case 'p':
+ options->samples = atoi (arg);
+ break;
+ case 'f':
+ options->offscreen = 1;
+ break;
+ default:
+ return 1;
+ }
+
+ return 0;
+}
+
+static render_arg_state_t state;
+static cgl_options_t options = { 1, 1, 0 };
+
+static int
+rendertest_main (void)
+{
+ int status;
+ render_surface_t surface;
+ glitz_drawable_format_t templ;
+ unsigned long mask;
+ glitz_drawable_format_t *dformat;
+ glitz_drawable_t *drawable, *offscreen = 0;
+ NSView *view;
+
+ surface.backend = &_glitz_cgl_render_backend;
+ surface.flags = 0;
+ surface.width = RENDER_DEFAULT_DST_WIDTH;
+ surface.height = RENDER_DEFAULT_DST_HEIGHT;
+
+ view = create_window (RENDER_DEFAULT_DST_WIDTH, RENDER_DEFAULT_DST_HEIGHT);
+
+ templ.samples = options.samples;
+ mask = GLITZ_FORMAT_SAMPLES_MASK;
+
+ if (options.db)
+ templ.doublebuffer = 1;
+ else
+ templ.doublebuffer = 0;
+
+ mask |= GLITZ_FORMAT_DOUBLEBUFFER_MASK;
+
+ dformat = glitz_cgl_find_window_format (mask, &templ, 0);
+ if (!dformat) {
+ fprintf (stderr, "Error: couldn't find window format\n");
+ return 1;
+ }
+
+ drawable =
+ glitz_cgl_create_drawable_for_view (dformat, view,
+ surface.width, surface.height);
+ if (!drawable) {
+ fprintf (stderr, "Error: couldn't create glitz drawable for view\n");
+ return 1;
+ }
+
+ if (options.offscreen)
+ {
+ dformat = glitz_find_drawable_format (drawable, 0, 0, 0);
+ if (!dformat)
+ {
+ fprintf (stderr, "Error: couldn't find offscreen format\n");
+ return 1;
+ }
+
+ offscreen = glitz_create_drawable (drawable, dformat,
+ surface.width, surface.height);
+ if (!offscreen)
+ {
+ fprintf (stderr, "Error: couldn't create offscreen drawable\n");
+ return 1;
+ }
+
+ surface.surface =
+ _glitz_create_and_attach_surface_to_drawable (drawable,
+ offscreen,
+ surface.width,
+ surface.height);
+ }
+ else
+ {
+ surface.surface =
+ _glitz_create_and_attach_surface_to_drawable (drawable,
+ drawable,
+ surface.width,
+ surface.height);
+ }
+
+ if (!surface.surface)
+ return 1;
+
+ status = render_run (&surface, &state.settings);
+
+ glitz_surface_destroy ((glitz_surface_t *) surface.surface);
+
+ if (offscreen)
+ glitz_drawable_destroy (offscreen);
+
+ glitz_drawable_destroy (drawable);
+
+ glitz_cgl_fini ();
+
+ return status;
+}
+
+
+int main(int argc, char *argv[])
+{
+ ProcessSerialNumber psn;
+
+ state.pointer = &options;
+ if (render_parse_arguments (_parse_option,
+ _cgl_options,
+ &state,
+ argc, argv))
+ return 1;
+
+ /* Add the icon to the dock. */
+ if (!GetCurrentProcess(&psn)) {
+ TransformProcessType(&psn, kProcessTransformToForegroundApplication);
+ SetFrontProcess(&psn);
+ }
+
+ pool = [[NSAutoreleasePool alloc] init];
+ [NSApplication sharedApplication];
+ [NSApp finishLaunching];
+
+ /* Create GlitzMain and make it the app delegate */
+ glitzMain = [[GlitzMain alloc] init];
+ [NSApp setDelegate: glitzMain];
+ [NSApp run];
+ return 0;
+}
diff --git a/src/Makefile.am b/src/Makefile.am
index 569c017..5251ea1 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,4 +1,4 @@
-SUBDIRS = . glx agl egl wgl
+SUBDIRS = . glx cgl agl egl wgl
if OS_WIN32
glitz_def = $(srcdir)/glitz.def
diff --git a/src/cgl/.gitignore b/src/cgl/.gitignore
new file mode 100644
index 0000000..6829f0d
--- /dev/null
+++ b/src/cgl/.gitignore
@@ -0,0 +1,7 @@
+Makefile
+Makefile.in
+*.la
+*.lo
+*.loT
+.libs
+.deps
diff --git a/src/cgl/Makefile.am b/src/cgl/Makefile.am
new file mode 100644
index 0000000..1906385
--- /dev/null
+++ b/src/cgl/Makefile.am
@@ -0,0 +1,38 @@
+if GLITZ_BUILD_CGL_BACKEND
+
+INCLUDES = \
+ $(GLITZ_INC) \
+ $(CGL_CFLAGS)
+
+lib_LTLIBRARIES = libglitz-cgl.la
+include_HEADERS = glitz-cgl.h
+
+libglitz_cgl_la_SOURCES = \
+ glitz-cgl.h \
+ glitz_cgl_drawable.m \
+ glitz_cgl_format.m \
+ glitz_cgl_info.m \
+ glitz_cgl_extension.m \
+ glitz_cgl_context.m \
+ glitz_cgl_pbuffer.m \
+ glitz_cglint.h
+
+libglitz_cgl_la_LDFLAGS = -version-info @VERSION_INFO@
+libglitz_cgl_la_LIBADD = $(GLITZ_LIB) $(CGL_LIBS)
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = glitz-cgl.pc
+
+endif
+
+EXTRA_DIST = \
+ glitz-cgl.h \
+ glitz_cgl_drawable.c \
+ glitz_cgl_format.c \
+ glitz_cgl_info.c \
+ glitz_cgl_extension.c \
+ glitz_cgl_context.c \
+ glitz_cgl_pbuffer.c \
+ glitz_cglint.h \
+ glitz-cgl.pc.in \
+ glitz-cgl.man
diff --git a/src/cgl/glitz-cgl.h b/src/cgl/glitz-cgl.h
new file mode 100644
index 0000000..74388fa
--- /dev/null
+++ b/src/cgl/glitz-cgl.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright © 2004 David Reveman
+ * Copyright © 2008 Paolo Bonzini
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of the
+ * copyright holders not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior permission.
+ * The copyright holders make no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express or
+ * implied warranty.
+ *
+ * COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+ * NO EVENT SHALL DAVID REVEMAN BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: David Reveman <davidr@novell.com>
+ * Author: Paolo Bonzini <bonzini@gnu.org>
+ */
+
+#ifndef GLITZ_CGL_H_INCLUDED
+#define GLITZ_CGL_H_INCLUDED
+
+#include <glitz.h>
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#include <OpenGL/OpenGL.h>
+
+#ifdef __OBJC__
+#include <AppKit/NSView.h>
+#include <AppKit/NSOpenGL.h>
+#endif
+
+
+/* glitz_cgl_info.c */
+
+void
+glitz_cgl_init (void);
+
+void
+glitz_cgl_fini (void);
+
+
+/* glitz_cgl_format.c */
+
+glitz_drawable_format_t *
+glitz_cgl_find_window_format (unsigned long mask,
+ const glitz_drawable_format_t *templ,
+ int count);
+
+glitz_drawable_format_t *
+glitz_cgl_find_pbuffer_format (unsigned long mask,
+ const glitz_drawable_format_t *templ,
+ int count);
+
+/* glitz_cgl_drawable.c */
+
+#ifdef __OBJC__
+glitz_drawable_t *
+glitz_cgl_create_drawable_for_view (glitz_drawable_format_t *format,
+ NSView *view,
+ unsigned int width,
+ unsigned int height);
+#endif
+
+glitz_drawable_t *
+glitz_cgl_create_pbuffer_drawable (glitz_drawable_format_t *format,
+ unsigned int width,
+ unsigned int height);
+
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif /* GLITZ_CGL_H_INCLUDED */
diff --git a/src/cgl/glitz-cgl.man b/src/cgl/glitz-cgl.man
new file mode 100644
index 0000000..4096628
--- /dev/null
+++ b/src/cgl/glitz-cgl.man
@@ -0,0 +1,26 @@
+.\"
+.\"
+.de TQ
+.br
+.ns
+.TP
+\\$1
+..
+.TH GLITZ-CGL 3 "Version 1.0"
+
+.SH NAME
+GLITZ-CGL \- Core OpenGL interface to glitz
+
+.SH SYNOPSIS
+.nf
+.B #include <glitz-cgl.h>
+.fi
+.SH DESCRIPTION
+
+CGL interface to glitz.
+
+.SH AUTHOR
+Paolo Bonzini
+
+.SH "SEE ALSO"
+.BR GLITZ (3)
diff --git a/src/cgl/glitz-cgl.pc.in b/src/cgl/glitz-cgl.pc.in
new file mode 100644
index 0000000..1d5b816
--- /dev/null
+++ b/src/cgl/glitz-cgl.pc.in
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: libglitz-cgl
+Description: OpenGL compositing library (NSOpenGL/CGL backend)
+Version: @VERSION@
+Requires: glitz
+Libs: -L${libdir} -lglitz-cgl @CGL_LIBS@
+Cflags: -I${includedir} @CGL_CFLAGS@
diff --git a/src/cgl/glitz_cgl_context.m b/src/cgl/glitz_cgl_context.m
new file mode 100644
index 0000000..d1413b2
--- /dev/null
+++ b/src/cgl/glitz_cgl_context.m
@@ -0,0 +1,520 @@
+/*
+ * Copyright © 2004 David Reveman
+ * Copyright © 2008 Paolo Bonzini
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of the
+ * copyright holders not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior permission.
+ * The copyright holders make no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express or
+ * implied warranty.
+ *
+ * COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+ * NO EVENT SHALL DAVID REVEMAN BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: David Reveman <davidr@novell.com>
+ * Author: Paolo Bonzini <bonzini@gnu.org>
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "../config.h"
+#endif
+
+#include "glitz_cglint.h"
+
+extern glitz_gl_proc_address_list_t _glitz_cgl_gl_proc_address;
+
+static CFBundleRef
+_glitz_cgl_get_bundle (const char *name)
+{
+ CFBundleRef bundle = 0;
+ FSRefParam ref_param;
+ char framework_name[256];
+
+ framework_name[0] = strlen (name);
+ strcpy (&framework_name[1], name);
+
+ memset (&ref_param, 0, sizeof (ref_param));
+
+ if (FindFolder (kSystemDomain,
+ kFrameworksFolderType,
+ kDontCreateFolder,
+ &ref_param.ioVRefNum,
+ &ref_param.ioDirID) == noErr) {
+ FSRef ref;
+
+ memset (&ref, 0, sizeof (ref));
+
+ ref_param.ioNamePtr = (unsigned char *) framework_name;
+ ref_param.newRef = &ref;
+
+ if (PBMakeFSRefSync (&ref_param) == noErr) {
+ CFURLRef url;
+
+ url = CFURLCreateFromFSRef (kCFAllocatorDefault, &ref);
+ if (url) {
+ bundle = CFBundleCreate (kCFAllocatorDefault, url);
+ CFRelease (url);
+
+ if (!CFBundleLoadExecutable (bundle)) {
+ CFRelease (bundle);
+ return (CFBundleRef) 0;
+ }
+ }
+ }
+ }
+
+ return bundle;
+}
+
+static void
+_glitz_cgl_release_bundle (CFBundleRef bundle)
+{
+ if (bundle) {
+ CFBundleUnloadExecutable (bundle);
+ CFRelease (bundle);
+ }
+}
+
+static void
+_glitz_cgl_notify_dummy (void *abstract_drawable,
+ glitz_surface_t *surface) {}
+
+static glitz_function_pointer_t
+_glitz_cgl_get_proc_address (const char *name, void *closure)
+{
+ glitz_function_pointer_t address = NULL;
+ CFBundleRef bundle = (CFBundleRef) closure;
+ CFStringRef str;
+
+ if (bundle) {
+ str = CFStringCreateWithCString (kCFAllocatorDefault, name,
+ kCFStringEncodingMacRoman);
+
+ address = CFBundleGetFunctionPointerForName (bundle, str);
+
+ CFRelease (str);
+ }
+
+ return address;
+}
+
+static glitz_context_t *
+_glitz_cgl_create_context (void *abstract_drawable,
+ glitz_drawable_format_t *format)
+{
+ NSAutoreleasePool *pool;
+ glitz_cgl_drawable_t *drawable = (glitz_cgl_drawable_t *)
+ abstract_drawable;
+ glitz_cgl_thread_info_t *thread_info = drawable->thread_info;
+ glitz_cgl_context_t *context;
+
+ context = malloc (sizeof (glitz_cgl_context_t));
+ if (!context)
+ return NULL;
+
+ pool = [[NSAutoreleasePool alloc] init];
+ context->context =
+ [[NSOpenGLContext alloc]
+ initWithFormat: (thread_info->pixel_formats[format->id])
+ shareContext: thread_info->root_context];
+
+ _glitz_context_init (&context->base, &drawable->base);
+
+ context->pbuffer = 0;
+
+ [pool release];
+ return (glitz_context_t *) context;
+}
+
+static void
+_glitz_cgl_context_destroy (void *abstract_context)
+{
+ glitz_cgl_context_t *context = (glitz_cgl_context_t *) abstract_context;
+ glitz_cgl_drawable_t *drawable = (glitz_cgl_drawable_t *)
+ context->base.drawable;
+
+ if (drawable->thread_info->cctx == &context->base)
+ {
+ [NSOpenGLContext clearCurrentContext];
+ drawable->thread_info->cctx = NULL;
+ }
+
+ [context->context release];
+
+ _glitz_context_fini (&context->base);
+
+ free (context);
+}
+
+static void
+_glitz_cgl_copy_context (void *abstract_src,
+ void *abstract_dst,
+ unsigned long mask)
+{
+ glitz_cgl_context_t *src = (glitz_cgl_context_t *) abstract_src;
+ glitz_cgl_context_t *dst = (glitz_cgl_context_t *) abstract_dst;
+
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+ [dst->context copyAttributesFromContext: src->context withMask: mask];
+ [pool release];
+}
+
+static void
+_glitz_cgl_make_current (void *abstract_drawable,
+ void *abstract_context)
+{
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+ glitz_cgl_context_t *context = (glitz_cgl_context_t *) abstract_context;
+ glitz_cgl_drawable_t *drawable = (glitz_cgl_drawable_t *)
+ abstract_drawable;
+ int update = 0;
+
+ if (drawable->base.width != drawable->width ||
+ drawable->base.height != drawable->height)
+ glitz_cgl_drawable_update_size (drawable,
+ drawable->base.width,
+ drawable->base.height);
+
+ if ([NSOpenGLContext currentContext] != context->context)
+ update = 1;
+ else if (context->pbuffer != !!drawable->pbuffer)
+ update = 1;
+ else {
+ if (drawable->pbuffer)
+ update |= ([context->context pixelBuffer] != drawable->pbuffer);
+ else if (drawable->view)
+ update |= ([context->context view] != drawable->view);
+ }
+
+ if (update)
+ {
+ if (drawable->thread_info->cctx)
+ {
+ glitz_context_t *ctx = drawable->thread_info->cctx;
+
+ if (ctx->lose_current)
+ ctx->lose_current (ctx->closure);
+ }
+
+ if (drawable->pbuffer) {
+ [context->context setPixelBuffer: drawable->pbuffer
+ cubeMapFace: 0 mipMapLevel: 0
+ currentVirtualScreen: [context->context currentVirtualScreen]];
+ context->pbuffer = 1;
+ }
+ else
+ {
+ if (context->pbuffer) {
+ [context->context clearDrawable];
+ context->pbuffer = 0;
+ }
+ [context->context setView: drawable->view];
+ }
+
+ [context->context makeCurrentContext];
+ }
+
+ drawable->thread_info->cctx = &context->base;
+ [pool release];
+}
+
+static glitz_function_pointer_t
+_glitz_cgl_context_get_proc_address (void *abstract_context,
+ const char *name)
+{
+ glitz_cgl_context_t *context = (glitz_cgl_context_t *) abstract_context;
+ glitz_cgl_drawable_t *drawable = (glitz_cgl_drawable_t *)
+ context->base.drawable;
+ glitz_function_pointer_t func;
+ CFBundleRef bundle;
+
+ _glitz_cgl_make_current (drawable, context);
+
+ bundle = _glitz_cgl_get_bundle ("OpenGL.framework");
+
+ func = _glitz_cgl_get_proc_address (name, (void *) bundle);
+
+ _glitz_cgl_release_bundle (bundle);
+
+ return func;
+}
+
+glitz_cgl_context_t *
+glitz_cgl_context_get (glitz_cgl_thread_info_t *thread_info,
+ glitz_drawable_format_t *format)
+{
+ glitz_cgl_context_t *context;
+ glitz_cgl_context_t **contexts = thread_info->contexts;
+ int index, n_contexts = thread_info->n_contexts;
+
+ for (; n_contexts; n_contexts--, contexts++)
+ if ((*contexts)->id == format->id)
+ return *contexts;
+
+ index = thread_info->n_contexts++;
+
+ thread_info->contexts =
+ realloc (thread_info->contexts,
+ sizeof (glitz_cgl_context_t *) * thread_info->n_contexts);
+ if (!thread_info->contexts)
+ return NULL;
+
+ context = malloc (sizeof (glitz_cgl_context_t));
+ if (!context)
+ return NULL;
+
+ thread_info->contexts[index] = context;
+
+ context->context =
+ [[NSOpenGLContext alloc]
+ initWithFormat: thread_info->pixel_formats[format->id]
+ shareContext: thread_info->root_context];
+ if (!context->context) {
+ free (context);
+ return NULL;
+ }
+
+ context->id = format->id;
+ context->pbuffer = 0;
+
+ if (!thread_info->root_context)
+ thread_info->root_context = context->context;
+
+ context->backend.gl = &_glitz_cgl_gl_proc_address;
+
+ context->backend.create_pbuffer = glitz_cgl_create_pbuffer;
+ context->backend.destroy = glitz_cgl_destroy;
+ context->backend.push_current = glitz_cgl_push_current;
+ context->backend.pop_current = glitz_cgl_pop_current;
+ context->backend.attach_notify = _glitz_cgl_notify_dummy;
+ context->backend.detach_notify = _glitz_cgl_notify_dummy;
+ context->backend.swap_buffers = glitz_cgl_swap_buffers;
+ context->backend.copy_sub_buffer = glitz_cgl_copy_sub_buffer;
+
+ context->backend.create_context = _glitz_cgl_create_context;
+ context->backend.destroy_context = _glitz_cgl_context_destroy;
+ context->backend.copy_context = _glitz_cgl_copy_context;
+ context->backend.make_current = _glitz_cgl_make_current;
+ context->backend.get_proc_address = _glitz_cgl_context_get_proc_address;
+
+ context->backend.draw_buffer = _glitz_drawable_draw_buffer;
+ context->backend.read_buffer = _glitz_drawable_read_buffer;
+
+ context->backend.drawable_formats = NULL;
+ context->backend.n_drawable_formats = 0;
+
+ if (thread_info->n_formats)
+ {
+ int size;
+
+ size = sizeof (glitz_int_drawable_format_t) * thread_info->n_formats;
+ context->backend.drawable_formats = malloc (size);
+ if (context->backend.drawable_formats)
+ {
+ memcpy (context->backend.drawable_formats, thread_info->formats,
+ size);
+ context->backend.n_drawable_formats = thread_info->n_formats;
+ }
+ }
+
+ context->backend.texture_formats = NULL;
+ context->backend.formats = NULL;
+ context->backend.n_formats = 0;
+
+ context->backend.program_map = &thread_info->program_map;
+ context->backend.feature_mask = 0;
+
+ context->initialized = 0;
+
+ return context;
+}
+
+void
+glitz_cgl_context_destroy (glitz_cgl_thread_info_t *thread_info,
+ glitz_cgl_context_t *context)
+{
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+ if (context->backend.drawable_formats)
+ free (context->backend.drawable_formats);
+
+ if (context->backend.formats)
+ free (context->backend.formats);
+
+ if (context->backend.texture_formats)
+ free (context->backend.texture_formats);
+
+ [context->context release];
+ [pool release];
+ free (context);
+}
+
+static void
+_glitz_cgl_context_initialize (glitz_cgl_thread_info_t *thread_info,
+ glitz_cgl_context_t *context)
+{
+ CFBundleRef bundle;
+
+ bundle = _glitz_cgl_get_bundle ("OpenGL.framework");
+
+ glitz_backend_init (&context->backend,
+ _glitz_cgl_get_proc_address,
+ (void *) bundle);
+
+ _glitz_cgl_release_bundle (bundle);
+
+ glitz_initiate_state (&_glitz_cgl_gl_proc_address);
+
+ context->initialized = 1;
+}
+
+static void
+_glitz_cgl_context_make_current (glitz_cgl_drawable_t *drawable,
+ glitz_bool_t finish)
+{
+ NSAutoreleasePool *pool;
+ if (finish)
+ glFinish ();
+
+ if (drawable->thread_info->cctx)
+ {
+ glitz_context_t *ctx = drawable->thread_info->cctx;
+
+ if (ctx->lose_current)
+ ctx->lose_current (ctx->closure);
+
+ drawable->thread_info->cctx = NULL;
+ }
+
+ pool = [[NSAutoreleasePool alloc] init];
+ if (drawable->pbuffer) {
+ [drawable->context->context setPixelBuffer: drawable->pbuffer
+ cubeMapFace: 0 mipMapLevel: 0
+ currentVirtualScreen: [drawable->context->context currentVirtualScreen]];
+ drawable->context->pbuffer = 1;
+ } else {
+ if (drawable->context->pbuffer) {
+ [drawable->context->context clearDrawable];
+ drawable->context->pbuffer = 0;
+ }
+
+ [drawable->context->context setView: drawable->view];
+ }
+
+ [drawable->context->context makeCurrentContext];
+
+ drawable->base.update_all = 1;
+
+ if (!drawable->context->initialized)
+ _glitz_cgl_context_initialize (drawable->thread_info,
+ drawable->context);
+ [pool release];
+}
+
+static void
+_glitz_cgl_context_update (glitz_cgl_drawable_t *drawable,
+ glitz_constraint_t constraint)
+{
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+ NSOpenGLContext *context;
+
+ drawable->base.flushed = drawable->base.finished = 0;
+
+ switch (constraint) {
+ case GLITZ_NONE:
+ break;
+ case GLITZ_ANY_CONTEXT_CURRENT:
+ context = [NSOpenGLContext currentContext];
+ if (context == NULL)
+ _glitz_cgl_context_make_current (drawable, 0);
+ break;
+ case GLITZ_CONTEXT_CURRENT:
+ context = [NSOpenGLContext currentContext];
+ if (context != drawable->context->context)
+ _glitz_cgl_context_make_current (drawable, (context)? 1: 0);
+ break;
+ case GLITZ_DRAWABLE_CURRENT:
+ if (drawable->base.width != drawable->width ||
+ drawable->base.height != drawable->height)
+ glitz_cgl_drawable_update_size (drawable,
+ drawable->base.width,
+ drawable->base.height);
+
+ context = [NSOpenGLContext currentContext];
+ if (context != drawable->context->context) {
+ _glitz_cgl_context_make_current (drawable, (context)? 1: 0);
+ } else {
+ if (drawable->pbuffer) {
+ if ([drawable->context->context pixelBuffer]
+ != drawable->pbuffer)
+ _glitz_cgl_context_make_current (drawable,
+ (context)? 1: 0);
+
+ } else if (drawable->view) {
+ if ([drawable->context->context view] != drawable->view)
+ _glitz_cgl_context_make_current (drawable,
+ (context)? 1: 0);
+ }
+ }
+ break;
+ }
+ [pool release];
+}
+
+glitz_bool_t
+glitz_cgl_push_current (void *abstract_drawable,
+ glitz_surface_t *surface,
+ glitz_constraint_t constraint,
+ glitz_bool_t *restore_state)
+{
+ glitz_cgl_drawable_t *drawable = (glitz_cgl_drawable_t *)
+ abstract_drawable;
+ glitz_cgl_context_info_t *context_info;
+ int index;
+
+ if (restore_state)
+ *restore_state = 0;
+
+ index = drawable->thread_info->context_stack_size++;
+
+ context_info = &drawable->thread_info->context_stack[index];
+ context_info->drawable = drawable;
+ context_info->surface = surface;
+ context_info->constraint = constraint;
+
+ _glitz_cgl_context_update (context_info->drawable, constraint);
+
+ return 1;
+}
+
+glitz_surface_t *
+glitz_cgl_pop_current (void *abstract_drawable)
+{
+ glitz_cgl_drawable_t *drawable = (glitz_cgl_drawable_t *)
+ abstract_drawable;
+ glitz_cgl_context_info_t *context_info = NULL;
+ int index;
+
+ drawable->thread_info->context_stack_size--;
+ index = drawable->thread_info->context_stack_size - 1;
+
+ context_info = &drawable->thread_info->context_stack[index];
+
+ if (context_info->drawable)
+ _glitz_cgl_context_update (context_info->drawable,
+ context_info->constraint);
+
+ if (context_info->constraint == GLITZ_DRAWABLE_CURRENT)
+ return context_info->surface;
+
+ return NULL;
+}
diff --git a/src/cgl/glitz_cgl_drawable.m b/src/cgl/glitz_cgl_drawable.m
new file mode 100644
index 0000000..d9072dc
--- /dev/null
+++ b/src/cgl/glitz_cgl_drawable.m
@@ -0,0 +1,256 @@
+/*
+ * Copyright © 2004 David Reveman
+ * Copyright © 2008 Paolo Bonzini
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of the
+ * copyright holders not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior permission.
+ * The copyright holders make no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express or
+ * implied warranty.
+ *
+ * COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+ * NO EVENT SHALL DAVID REVEMAN BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: David Reveman <davidr@novell.com>
+ * Author: Paolo Bonzini <bonzini@gnu.org>
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "../config.h"
+#endif
+
+#include "glitz_cglint.h"
+
+static glitz_cgl_drawable_t *
+_glitz_cgl_create_drawable (glitz_cgl_thread_info_t *thread_info,
+ glitz_cgl_context_t *context,
+ glitz_drawable_format_t *format,
+ NSView *view,
+ NSOpenGLPixelBuffer *pbuffer,
+ unsigned int width,
+ unsigned int height)
+{
+ glitz_cgl_drawable_t *drawable;
+
+ drawable = (glitz_cgl_drawable_t *) malloc (sizeof (glitz_cgl_drawable_t));
+ if (drawable == NULL)
+ return NULL;
+
+ drawable->thread_info = thread_info;
+ drawable->context = context;
+ drawable->view = view;
+ drawable->pbuffer = pbuffer;
+ drawable->width = width;
+ drawable->height = height;
+
+ _glitz_drawable_init (&drawable->base,
+ &thread_info->formats[format->id],
+ &context->backend,
+ width, height);
+
+ if (!context->initialized) {
+ glitz_cgl_push_current (drawable, NULL, GLITZ_CONTEXT_CURRENT, NULL);
+ glitz_cgl_pop_current (drawable);
+ }
+
+ if (width > context->backend.max_viewport_dims[0] ||
+ height > context->backend.max_viewport_dims[1]) {
+ free (drawable);
+ return NULL;
+ }
+
+ thread_info->drawables++;
+
+ return drawable;
+}
+
+glitz_bool_t
+glitz_cgl_drawable_update_size (glitz_cgl_drawable_t *drawable,
+ int width,
+ int height)
+{
+ if (drawable->pbuffer)
+ {
+ glitz_cgl_pbuffer_destroy (drawable->pbuffer);
+ drawable->pbuffer =
+ glitz_cgl_pbuffer_create (drawable->thread_info,
+ (int) width, (int) height);
+ if (!drawable->pbuffer)
+ return 0;
+ }
+
+ drawable->width = width;
+ drawable->height = height;
+
+ return 1;
+}
+
+static glitz_drawable_t *
+_glitz_cgl_create_pbuffer_drawable (glitz_cgl_thread_info_t *thread_info,
+ glitz_drawable_format_t *format,
+ unsigned int width,
+ unsigned int height)
+{
+ glitz_cgl_drawable_t *drawable;
+ glitz_cgl_context_t *context;
+ NSOpenGLPixelBuffer *pbuffer;
+
+ context = glitz_cgl_context_get (thread_info, format);
+ if (!context)
+ return NULL;
+
+ pbuffer = glitz_cgl_pbuffer_create (thread_info,
+ (int) width, (int) height);
+ if (!pbuffer)
+ return NULL;
+
+ drawable = _glitz_cgl_create_drawable (thread_info, context, format,
+ NULL, pbuffer,
+ width, height);
+ if (!drawable) {
+ glitz_cgl_pbuffer_destroy (pbuffer);
+ return NULL;
+ }
+
+ return &drawable->base;
+}
+
+glitz_drawable_t *
+glitz_cgl_create_pbuffer (void *abstract_templ,
+ glitz_drawable_format_t *format,
+ unsigned int width,
+ unsigned int height)
+{
+ glitz_cgl_drawable_t *templ = (glitz_cgl_drawable_t *) abstract_templ;
+
+ return _glitz_cgl_create_pbuffer_drawable (templ->thread_info, format,
+ width, height);
+}
+
+glitz_drawable_t *
+glitz_cgl_create_drawable_for_view (glitz_drawable_format_t *format,
+ NSView *view,
+ unsigned int width,
+ unsigned int height)
+{
+ glitz_cgl_drawable_t *drawable;
+ glitz_cgl_thread_info_t *thread_info;
+ glitz_cgl_context_t *context;
+
+ thread_info = glitz_cgl_thread_info_get ();
+ if (!thread_info)
+ return NULL;
+
+ if (format->id >= thread_info->n_formats)
+ return NULL;
+
+ context = glitz_cgl_context_get (thread_info, format);
+ if (!context)
+ return NULL;
+
+ drawable = _glitz_cgl_create_drawable (thread_info, context, format,
+ view, NULL,
+ width, height);
+ if (!drawable)
+ return NULL;
+
+ return &drawable->base;
+}
+slim_hidden_def(glitz_cgl_create_drawable_for_window);
+
+glitz_drawable_t *
+glitz_cgl_create_pbuffer_drawable (glitz_drawable_format_t *format,
+ unsigned int width,
+ unsigned int height)
+{
+ glitz_cgl_thread_info_t *thread_info;
+
+ thread_info = glitz_cgl_thread_info_get ();
+ if (!thread_info)
+ return NULL;
+
+ if (format->id >= thread_info->n_formats)
+ return NULL;
+
+ return _glitz_cgl_create_pbuffer_drawable (thread_info, format,
+ width, height);
+}
+slim_hidden_def(glitz_cgl_create_pbuffer_drawable);
+
+void
+glitz_cgl_destroy (void *abstract_drawable)
+{
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+ glitz_cgl_drawable_t *drawable = (glitz_cgl_drawable_t *)
+ abstract_drawable;
+
+ drawable->thread_info->drawables--;
+ if (drawable->thread_info->drawables == 0) {
+ /*
+ * Last drawable? We have to destroy all fragment programs as this may
+ * be our last chance to have a context current.
+ */
+ glitz_cgl_push_current (abstract_drawable, NULL,
+ GLITZ_CONTEXT_CURRENT, NULL);
+ glitz_program_map_fini (drawable->base.backend->gl,
+ &drawable->thread_info->program_map);
+ glitz_program_map_init (&drawable->thread_info->program_map);
+ glitz_cgl_pop_current (abstract_drawable);
+ }
+
+ if (drawable->view || drawable->pbuffer) {
+ NSOpenGLContext *context = [NSOpenGLContext currentContext];
+
+ if (context == drawable->context->context) {
+ if (drawable->pbuffer) {
+ if ([context pixelBuffer] == drawable->pbuffer)
+ [NSOpenGLContext clearCurrentContext];
+ } else {
+ if ([context view] == drawable->view)
+ [NSOpenGLContext clearCurrentContext];
+ }
+ }
+
+ if (drawable->pbuffer)
+ glitz_cgl_pbuffer_destroy (drawable->pbuffer);
+ }
+
+ [pool release];
+ free (drawable);
+}
+
+glitz_bool_t
+glitz_cgl_swap_buffers (void *abstract_drawable)
+{
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+ glitz_cgl_drawable_t *drawable = (glitz_cgl_drawable_t *)
+ abstract_drawable;
+
+ glitz_cgl_push_current (abstract_drawable, NULL, GLITZ_DRAWABLE_CURRENT,
+ NULL);
+ [drawable->context->context flushBuffer];
+ glitz_cgl_pop_current (abstract_drawable);
+
+ [pool release];
+ return 1;
+}
+
+glitz_bool_t
+glitz_cgl_copy_sub_buffer (void *abstract_drawable,
+ int x,
+ int y,
+ int width,
+ int height)
+{
+ return 0;
+}
diff --git a/src/cgl/glitz_cgl_extension.m b/src/cgl/glitz_cgl_extension.m
new file mode 100644
index 0000000..148a49b
--- /dev/null
+++ b/src/cgl/glitz_cgl_extension.m
@@ -0,0 +1,145 @@
+/*
+ * Copyright © 2004 David Reveman
+ * Copyright © 2008 Paolo Bonzini
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of the
+ * copyright holders not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior permission.
+ * The copyright holders make no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express or
+ * implied warranty.
+ *
+ * COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+ * NO EVENT SHALL DAVID REVEMAN BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: David Reveman <davidr@novell.com>
+ * Author: Paolo Bonzini <bonzini@gnu.org>
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "../config.h"
+#endif
+
+#include "glitz_cglint.h"
+
+static glitz_extension_map cgl_extensions[] = {
+ { 0.0, "GL_APPLE_pixel_buffer", GLITZ_CGL_FEATURE_PBUFFER_MASK },
+ { 0.0, "GL_ARB_multisample", GLITZ_CGL_FEATURE_MULTISAMPLE_MASK },
+ { 0.0, "GL_ARB_texture_rectangle",
+ GLITZ_CGL_FEATURE_TEXTURE_RECTANGLE_MASK },
+ { 0.0, "GL_EXT_texture_rectangle",
+ GLITZ_CGL_FEATURE_TEXTURE_RECTANGLE_MASK },
+ { 0.0, "GL_NV_texture_rectangle",
+ GLITZ_CGL_FEATURE_TEXTURE_RECTANGLE_MASK },
+ { 0.0, NULL, 0 }
+};
+
+static int
+glitz_test_pbuffer_format (CGLPixelFormatAttribute *attrib)
+{
+ CGLContextObj ctx = NULL;
+ CGLPixelFormatObj pix = NULL;
+ CGLPBufferObj pb = NULL;
+ GLint npix;
+ long screen;
+ int result;
+
+ result =
+ (CGLChoosePixelFormat (attrib, &pix, &npix) == kCGLNoError
+ && npix > 0
+ && CGLCreatePBuffer (2, 2, GLITZ_GL_TEXTURE_2D, GL_RGBA, 0, &pb) == kCGLNoError
+ && CGLCreateContext (pix, NULL, &ctx) == kCGLNoError
+ && CGLGetVirtualScreen (ctx, &screen) == kCGLNoError
+ && CGLSetPBuffer (ctx, pb, 0, 0, screen) == kCGLNoError);
+
+ if (ctx != NULL)
+ CGLDestroyContext (ctx);
+ if (pb != NULL)
+ CGLDestroyPBuffer (pb);
+ if (pix != NULL)
+ CGLDestroyPixelFormat (pix);
+ return result;
+}
+
+static CGLPixelFormatAttribute _default_attrib[] = {
+ kCGLPFANoRecovery,
+ 0
+};
+
+static CGLPixelFormatAttribute _db_attrib[] = {
+ kCGLPFADoubleBuffer,
+ kCGLPFANoRecovery,
+ 0
+};
+
+static CGLPixelFormatAttribute _depth_attrib[] = {
+ kCGLPFADepthSize, 8,
+ kCGLPFAStencilSize, 8,
+ kCGLPFANoRecovery,
+ 0
+};
+
+static CGLPixelFormatAttribute _ms_attrib[] = {
+ kCGLPFASampleBuffers, 1,
+ kCGLPFASamples, 2,
+ kCGLPFANoRecovery,
+ 0
+};
+
+glitz_status_t
+glitz_cgl_query_extensions (glitz_cgl_thread_info_t *thread_info)
+{
+ const char *gl_extensions_string;
+ CGLContextObj context;
+ CGLPixelFormatObj pix;
+ GLint npix;
+
+ thread_info->cgl_feature_mask = 0;
+
+ if (CGLChoosePixelFormat (_default_attrib, &pix, &npix) != kCGLNoError)
+ return GLITZ_STATUS_SUCCESS;
+
+ if (CGLCreateContext (pix, NULL, &context) != kCGLNoError)
+ return GLITZ_STATUS_SUCCESS;
+
+ CGLSetCurrentContext (context);
+ gl_extensions_string = (const char *) glGetString (GL_EXTENSIONS);
+
+ thread_info->cgl_feature_mask =
+ glitz_extensions_query (0.0,
+ gl_extensions_string,
+ cgl_extensions);
+
+ CGLSetCurrentContext (NULL);
+ CGLDestroyContext (context);
+ CGLDestroyPixelFormat (pix);
+
+ if (glitz_test_pbuffer_format (_db_attrib))
+ {
+ thread_info->cgl_feature_mask |=
+ GLITZ_CGL_FEATURE_PBUFFER_DOUBLEBUFFER_MASK;
+ }
+
+ if (glitz_test_pbuffer_format (_depth_attrib))
+ {
+ thread_info->cgl_feature_mask |=
+ GLITZ_CGL_FEATURE_PBUFFER_DEPTH_STENCIL_MASK;
+ }
+
+ if ((thread_info->cgl_feature_mask & GLITZ_CGL_FEATURE_MULTISAMPLE_MASK)
+ && glitz_test_pbuffer_format (_ms_attrib))
+ {
+ thread_info->cgl_feature_mask |=
+ GLITZ_CGL_FEATURE_PBUFFER_MULTISAMPLE_MASK;
+ }
+ return GLITZ_STATUS_SUCCESS;
+}
diff --git a/src/cgl/glitz_cgl_format.m b/src/cgl/glitz_cgl_format.m
new file mode 100644
index 0000000..0eb5622
--- /dev/null
+++ b/src/cgl/glitz_cgl_format.m
@@ -0,0 +1,338 @@
+/*
+ * Copyright © 2004 David Reveman
+ * Copyright © 2008 Paolo Bonzini
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of the
+ * copyright holders not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior permission.
+ * The copyright holders make no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express or
+ * implied warranty.
+ *
+ * COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+ * NO EVENT SHALL DAVID REVEMAN BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: David Reveman <davidr@novell.com>
+ * Author: Paolo Bonzini <bonzini@gnu.org>
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "../config.h"
+#endif
+
+#include "glitz_cglint.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+struct pixel_format_info {
+ int doublebuffer, depth_size, stencil_size, samples;
+};
+
+static struct pixel_format_info _attribs_list[] = {
+ /* Explicitly request no depth/no stencil to discover pbuffer formats.
+ Apparently things are a little different for AGL and CGL here. */
+ { 0, 0, 0, 1 },
+ { 1, 0, 0, 1 },
+
+ /* With stencil (why also NSOpenGLPFADepthSize for no double buffering?
+ I took this from glitz_agl_format.c). */
+ { 0, 8, 8, 1 },
+ { 1, -1, 8, 1 },
+
+ /* Multi-sampled formats. */
+ { 0, -1, 8, 2 },
+ { 1, -1, 8, 2 },
+
+ { 0, -1, 8, 4 },
+ { 1, -1, 8, 4 },
+
+ { 0, -1, 8, 6 },
+ { 1, -1, 8, 6 }
+};
+
+static int
+_glitz_cgl_format_compare (const void *elem1,
+ const void *elem2)
+{
+ glitz_int_drawable_format_t *format[2];
+ int i, score[2];
+
+ format[0] = (glitz_int_drawable_format_t *) elem1;
+ format[1] = (glitz_int_drawable_format_t *) elem2;
+ i = score[0] = score[1] = 0;
+
+ for (; i < 2; i++)
+ {
+ if (format[i]->d.color.red_size)
+ {
+ if (format[i]->d.color.red_size >= 8)
+ score[i] += 5;
+
+ score[i] += 10;
+ }
+
+ if (format[i]->d.color.alpha_size)
+ {
+ if (format[i]->d.color.alpha_size >= 8)
+ score[i] += 5;
+
+ score[i] += 10;
+ }
+
+ if (format[i]->d.stencil_size)
+ score[i] += 3;
+
+ if (format[i]->d.depth_size)
+ score[i] += 3;
+
+ if (format[i]->d.doublebuffer)
+ score[i] += 10;
+
+ if (format[i]->d.samples > 1)
+ score[i] -= (20 - format[i]->d.samples / 2);
+
+ if (format[i]->types & GLITZ_DRAWABLE_TYPE_WINDOW_MASK)
+ score[i] += 10;
+
+ if (format[i]->types & GLITZ_DRAWABLE_TYPE_PBUFFER_MASK)
+ score[i] += 10;
+
+ if (format[i]->caveat)
+ score[i] -= 1000;
+ }
+
+ return score[1] - score[0];
+}
+
+static void
+_glitz_cgl_add_format (glitz_cgl_thread_info_t *thread_info,
+ glitz_int_drawable_format_t *format,
+ NSOpenGLPixelFormat *pixel_format)
+{
+ if (!glitz_drawable_format_find (thread_info->formats,
+ thread_info->n_formats,
+ GLITZ_DRAWABLE_FORMAT_ALL_EXCEPT_ID_MASK,
+ format, 0)) {
+ int n = thread_info->n_formats;
+
+ thread_info->formats =
+ realloc (thread_info->formats,
+ sizeof (glitz_int_drawable_format_t) * (n + 1));
+ thread_info->pixel_formats =
+ realloc (thread_info->pixel_formats,
+ sizeof (NSOpenGLPixelFormat *) * (n + 1));
+
+ if (thread_info->formats && thread_info->pixel_formats) {
+ thread_info->formats[n] = *(glitz_int_drawable_format_t*)format;
+ thread_info->formats[n].d.id = n;
+ thread_info->pixel_formats[n] = pixel_format;
+ thread_info->n_formats++;
+ }
+ }
+}
+
+static GLint
+glitz_cgl_describe_format (NSOpenGLPixelFormat *pixel_format, int attrib)
+{
+ GLint value;
+ [pixel_format getValues: &value forAttribute: attrib forVirtualScreen: 0];
+ return value;
+}
+
+void
+glitz_cgl_query_formats (glitz_cgl_thread_info_t *thread_info)
+{
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+ glitz_int_drawable_format_t format;
+ NSOpenGLPixelFormat *pixel_format, **new_pfs;
+ int n_attribs_list, i;
+
+ NSScreen * screenWithMenubar = [[NSScreen screens] objectAtIndex: 0];
+ int color_size = NSBitsPerPixelFromDepth([screenWithMenubar depth]);
+ NSOpenGLPixelFormatAttribute attribs[16] = {
+ NSOpenGLPFAAlphaSize, (color_size <= 16) ? 1 : 8,
+ NSOpenGLPFAColorSize, (color_size <= 16) ? 16 : 32 };
+
+ format.types = GLITZ_DRAWABLE_TYPE_WINDOW_MASK;
+ format.d.id = 0;
+ format.d.color.fourcc = GLITZ_FOURCC_RGB;
+
+ n_attribs_list = sizeof (_attribs_list) / sizeof (GLint *);
+
+ for (i = 0; i < n_attribs_list; i++) {
+ GLint value;
+ CGLPixelFormatObj pix;
+ int j = 4;
+
+ if (_attribs_list[i].doublebuffer)
+ attribs[j++] = NSOpenGLPFADoubleBuffer;
+ if (_attribs_list[i].depth_size > -1)
+ {
+ attribs[j++] = NSOpenGLPFADepthSize;
+ attribs[j++] = _attribs_list[i].depth_size;
+ }
+ if (_attribs_list[i].stencil_size > -1)
+ {
+ attribs[j++] = NSOpenGLPFAStencilSize;
+ attribs[j++] = _attribs_list[i].stencil_size;
+ }
+ if (_attribs_list[i].samples > 1)
+ {
+ attribs[j++] = NSOpenGLPFASampleBuffers;
+ attribs[j++] = 1;
+ attribs[j++] = NSOpenGLPFASamples;
+ attribs[j++] = _attribs_list[i].samples;
+ }
+ attribs[j++] = 0;
+
+ /* NSOpenGLFormat logs an error message if given an invalid format, so try
+ the CGL function first. */
+ if (CGLChoosePixelFormat ((CGLPixelFormatAttribute *) attribs,
+ &pix, &value) != kCGLNoError)
+ continue;
+
+ CGLDestroyPixelFormat (pix);
+ pixel_format = [[NSOpenGLPixelFormat alloc] initWithAttributes: attribs];
+
+ /* Stereo is not supported yet */
+ if (glitz_cgl_describe_format (pixel_format, NSOpenGLPFAStereo)) {
+ [pixel_format release];
+ continue;
+ }
+
+ value = glitz_cgl_describe_format (pixel_format, NSOpenGLPFAAccelerated);
+ format.caveat = (value)? 0: 1;
+ value = glitz_cgl_describe_format (pixel_format, NSOpenGLPFADoubleBuffer);
+ format.d.doublebuffer = (value)? 1: 0;
+
+ value = glitz_cgl_describe_format (pixel_format, NSOpenGLPFAAlphaSize);
+ format.d.color.alpha_size = (unsigned short) value;
+ value = glitz_cgl_describe_format (pixel_format, NSOpenGLPFAColorSize) - value;
+ format.d.color.red_size = (unsigned short) (value + 1) / 3;
+ format.d.color.green_size = (unsigned short) (value + 2) / 3;
+ format.d.color.blue_size = (unsigned short) value / 3;
+ value = glitz_cgl_describe_format (pixel_format, NSOpenGLPFADepthSize);
+ format.d.depth_size = (unsigned short) value;
+ value = glitz_cgl_describe_format (pixel_format, NSOpenGLPFAStencilSize);
+ format.d.stencil_size = (unsigned short) value;
+
+ if (thread_info->cgl_feature_mask & GLITZ_CGL_FEATURE_MULTISAMPLE_MASK)
+ {
+ value = glitz_cgl_describe_format (pixel_format, NSOpenGLPFASampleBuffers);
+ if (value) {
+ value = glitz_cgl_describe_format (pixel_format, NSOpenGLPFASamples);
+ format.d.samples = (unsigned short) (value > 1)? value: 1;
+ } else
+ format.d.samples = 1;
+ } else
+ format.d.samples = 1;
+
+ format.types |= GLITZ_DRAWABLE_TYPE_PBUFFER_MASK;
+ if ((thread_info->cgl_feature_mask &
+ GLITZ_CGL_FEATURE_PBUFFER_MASK) == 0)
+ format.types &= ~GLITZ_DRAWABLE_TYPE_PBUFFER_MASK;
+
+ else if (format.d.color.red_size == 0 ||
+ format.d.color.green_size == 0 ||
+ format.d.color.blue_size == 0 ||
+ format.d.color.alpha_size == 0)
+ format.types &= ~GLITZ_DRAWABLE_TYPE_PBUFFER_MASK;
+
+ else if ((thread_info->cgl_feature_mask &
+ GLITZ_CGL_FEATURE_PBUFFER_DOUBLEBUFFER_MASK) == 0
+ && format.d.doublebuffer)
+ format.types &= ~GLITZ_DRAWABLE_TYPE_PBUFFER_MASK;
+
+ else if ((thread_info->cgl_feature_mask &
+ GLITZ_CGL_FEATURE_PBUFFER_MULTISAMPLE_MASK) == 0
+ && format.d.samples > 1)
+ format.types &= ~GLITZ_DRAWABLE_TYPE_PBUFFER_MASK;
+
+ else if ((thread_info->cgl_feature_mask &
+ GLITZ_CGL_FEATURE_PBUFFER_DEPTH_STENCIL_MASK) == 0
+ && (format.d.depth_size > 0 || format.d.stencil_size > 0))
+ format.types &= ~GLITZ_DRAWABLE_TYPE_PBUFFER_MASK;
+
+ if (format.d.color.red_size ||
+ format.d.color.green_size ||
+ format.d.color.blue_size ||
+ format.d.color.alpha_size)
+ _glitz_cgl_add_format (thread_info, &format, pixel_format);
+ }
+
+ if (!thread_info->n_formats)
+ return;
+
+ qsort (thread_info->formats, thread_info->n_formats,
+ sizeof (glitz_int_drawable_format_t), _glitz_cgl_format_compare);
+
+ /*
+ * Update NSOpenGLPixelFormat list so that it matches the sorted format list.
+ */
+ new_pfs = malloc (sizeof (NSOpenGLPixelFormat *) * thread_info->n_formats);
+ if (!new_pfs) {
+ thread_info->n_formats = 0;
+ return;
+ }
+
+ for (i = 0; i < thread_info->n_formats; i++) {
+ new_pfs[i] = thread_info->pixel_formats[thread_info->formats[i].d.id];
+ thread_info->formats[i].d.id = i;
+ }
+
+ free (thread_info->pixel_formats);
+ thread_info->pixel_formats = new_pfs;
+ [pool release];
+}
+
+glitz_drawable_format_t *
+glitz_cgl_find_window_format (unsigned long mask,
+ const glitz_drawable_format_t *templ,
+ int count)
+{
+ glitz_int_drawable_format_t itempl;
+ glitz_cgl_thread_info_t *thread_info =
+ glitz_cgl_thread_info_get ();
+
+ glitz_drawable_format_copy (templ, &itempl.d, mask);
+
+ itempl.types = GLITZ_DRAWABLE_TYPE_WINDOW_MASK;
+ mask |= GLITZ_INT_FORMAT_WINDOW_MASK;
+
+ return glitz_drawable_format_find (thread_info->formats,
+ thread_info->n_formats,
+ mask, &itempl, count);
+}
+slim_hidden_def(glitz_cgl_find_window_format);
+
+
+glitz_drawable_format_t *
+glitz_cgl_find_pbuffer_format (unsigned long mask,
+ const glitz_drawable_format_t *templ,
+ int count)
+{
+ glitz_int_drawable_format_t itempl;
+ glitz_cgl_thread_info_t *thread_info =
+ glitz_cgl_thread_info_get ();
+
+ glitz_drawable_format_copy (templ, &itempl.d, mask);
+
+ itempl.types = GLITZ_DRAWABLE_TYPE_PBUFFER_MASK;
+ mask |= GLITZ_INT_FORMAT_PBUFFER_MASK;
+
+ return glitz_drawable_format_find (thread_info->formats,
+ thread_info->n_formats,
+ mask, &itempl, count);
+}
+slim_hidden_def(glitz_cgl_find_pbuffer_format);
+
diff --git a/src/cgl/glitz_cgl_info.m b/src/cgl/glitz_cgl_info.m
new file mode 100644
index 0000000..322bba3
--- /dev/null
+++ b/src/cgl/glitz_cgl_info.m
@@ -0,0 +1,289 @@
+/*
+ * Copyright © 2004 David Reveman
+ * Copyright © 2008 Paolo Bonzini
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of the
+ * copyright holders not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior permission.
+ * The copyright holders make no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express or
+ * implied warranty.
+ *
+ * COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+ * NO EVENT SHALL DAVID REVEMAN BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: David Reveman <davidr@novell.com>
+ * Author: Paolo Bonzini <bonzini@gnu.org>
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "../config.h"
+#endif
+
+#include "glitz_cglint.h"
+
+#include <OpenGL/glext.h>
+
+glitz_gl_proc_address_list_t _glitz_cgl_gl_proc_address = {
+
+ /* core */
+ (glitz_gl_enable_t) glEnable,
+ (glitz_gl_disable_t) glDisable,
+ (glitz_gl_get_error_t) glGetError,
+ (glitz_gl_get_string_t) glGetString,
+ (glitz_gl_enable_client_state_t) glEnableClientState,
+ (glitz_gl_disable_client_state_t) glDisableClientState,
+ (glitz_gl_vertex_pointer_t) glVertexPointer,
+ (glitz_gl_tex_coord_pointer_t) glTexCoordPointer,
+ (glitz_gl_draw_arrays_t) glDrawArrays,
+ (glitz_gl_tex_env_f_t) glTexEnvf,
+ (glitz_gl_tex_env_fv_t) glTexEnvfv,
+ (glitz_gl_tex_gen_i_t) glTexGeni,
+ (glitz_gl_tex_gen_fv_t) glTexGenfv,
+ (glitz_gl_color_4us_t) glColor4us,
+ (glitz_gl_color_4f_t) glColor4f,
+ (glitz_gl_scissor_t) glScissor,
+ (glitz_gl_blend_func_t) glBlendFunc,
+ (glitz_gl_clear_t) glClear,
+ (glitz_gl_clear_color_t) glClearColor,
+ (glitz_gl_clear_stencil_t) glClearStencil,
+ (glitz_gl_stencil_func_t) glStencilFunc,
+ (glitz_gl_stencil_op_t) glStencilOp,
+ (glitz_gl_push_attrib_t) glPushAttrib,
+ (glitz_gl_pop_attrib_t) glPopAttrib,
+ (glitz_gl_matrix_mode_t) glMatrixMode,
+ (glitz_gl_push_matrix_t) glPushMatrix,
+ (glitz_gl_pop_matrix_t) glPopMatrix,
+ (glitz_gl_load_identity_t) glLoadIdentity,
+ (glitz_gl_load_matrix_f_t) glLoadMatrixf,
+ (glitz_gl_depth_range_t) glDepthRange,
+ (glitz_gl_viewport_t) glViewport,
+ (glitz_gl_raster_pos_2f_t) glRasterPos2f,
+ (glitz_gl_bitmap_t) glBitmap,
+ (glitz_gl_read_buffer_t) glReadBuffer,
+ (glitz_gl_draw_buffer_t) glDrawBuffer,
+ (glitz_gl_copy_pixels_t) glCopyPixels,
+ (glitz_gl_flush_t) glFlush,
+ (glitz_gl_finish_t) glFinish,
+ (glitz_gl_pixel_store_i_t) glPixelStorei,
+ (glitz_gl_ortho_t) glOrtho,
+ (glitz_gl_scale_f_t) glScalef,
+ (glitz_gl_translate_f_t) glTranslatef,
+ (glitz_gl_hint_t) glHint,
+ (glitz_gl_depth_mask_t) glDepthMask,
+ (glitz_gl_polygon_mode_t) glPolygonMode,
+ (glitz_gl_shade_model_t) glShadeModel,
+ (glitz_gl_color_mask_t) glColorMask,
+ (glitz_gl_read_pixels_t) glReadPixels,
+ (glitz_gl_get_tex_image_t) glGetTexImage,
+ (glitz_gl_tex_sub_image_2d_t) glTexSubImage2D,
+ (glitz_gl_gen_textures_t) glGenTextures,
+ (glitz_gl_delete_textures_t) glDeleteTextures,
+ (glitz_gl_bind_texture_t) glBindTexture,
+ (glitz_gl_tex_image_2d_t) glTexImage2D,
+ (glitz_gl_tex_parameter_i_t) glTexParameteri,
+ (glitz_gl_tex_parameter_fv_t) glTexParameterfv,
+ (glitz_gl_get_tex_level_parameter_iv_t) glGetTexLevelParameteriv,
+ (glitz_gl_copy_tex_sub_image_2d_t) glCopyTexSubImage2D,
+ (glitz_gl_get_integer_v_t) glGetIntegerv,
+
+ /* extensions */
+ (glitz_gl_blend_color_t) 0,
+ (glitz_gl_active_texture_t) 0,
+ (glitz_gl_client_active_texture_t) 0,
+ (glitz_gl_multi_draw_arrays_t) 0,
+ (glitz_gl_gen_programs_t) 0,
+ (glitz_gl_delete_programs_t) 0,
+ (glitz_gl_program_string_t) 0,
+ (glitz_gl_bind_program_t) 0,
+ (glitz_gl_program_local_param_4fv_t) 0,
+ (glitz_gl_get_program_iv_t) 0,
+ (glitz_gl_gen_buffers_t) 0,
+ (glitz_gl_delete_buffers_t) 0,
+ (glitz_gl_bind_buffer_t) 0,
+ (glitz_gl_buffer_data_t) 0,
+ (glitz_gl_buffer_sub_data_t) 0,
+ (glitz_gl_get_buffer_sub_data_t) 0,
+ (glitz_gl_map_buffer_t) 0,
+ (glitz_gl_unmap_buffer_t) 0,
+ (glitz_gl_gen_framebuffers_t) 0,
+ (glitz_gl_delete_framebuffers_t) 0,
+ (glitz_gl_bind_framebuffer_t) 0,
+ (glitz_gl_framebuffer_renderbuffer_t) 0,
+ (glitz_gl_framebuffer_texture_2d_t) 0,
+ (glitz_gl_check_framebuffer_status_t) 0,
+ (glitz_gl_gen_renderbuffers_t) 0,
+ (glitz_gl_delete_renderbuffers_t) 0,
+ (glitz_gl_bind_renderbuffer_t) 0,
+ (glitz_gl_renderbuffer_storage_t) 0,
+ (glitz_gl_get_renderbuffer_parameter_iv_t) 0
+};
+
+static void
+glitz_cgl_thread_info_init (glitz_cgl_thread_info_t *thread_info);
+
+static void
+glitz_cgl_thread_info_fini (glitz_cgl_thread_info_t *thread_info);
+
+#ifdef PTHREADS
+
+#include <pthread.h>
+#include <stdlib.h>
+
+/* thread safe */
+static int tsd_initialized = 0;
+static pthread_key_t info_tsd;
+
+static void
+glitz_cgl_thread_info_destroy (glitz_cgl_thread_info_t *thread_info)
+{
+ pthread_setspecific (info_tsd, NULL);
+
+ if (thread_info) {
+ glitz_cgl_thread_info_fini (thread_info);
+ free (thread_info);
+ }
+}
+
+static void
+_tsd_destroy (void *p)
+{
+ if (p) {
+ glitz_cgl_thread_info_fini ((glitz_cgl_thread_info_t *) p);
+ free (p);
+ }
+}
+
+glitz_cgl_thread_info_t *
+glitz_cgl_thread_info_get (void)
+{
+ glitz_cgl_thread_info_t *thread_info;
+ void *p;
+
+ if (!tsd_initialized) {
+ pthread_key_create (&info_tsd, _tsd_destroy);
+ tsd_initialized = 1;
+ }
+
+ p = pthread_getspecific (info_tsd);
+
+ if (p == NULL) {
+ thread_info = malloc (sizeof (glitz_cgl_thread_info_t));
+ glitz_cgl_thread_info_init (thread_info);
+
+ pthread_setspecific (info_tsd, thread_info);
+ } else
+ thread_info = (glitz_cgl_thread_info_t *) p;
+
+ return thread_info;
+}
+
+#else
+
+/* not thread safe */
+static glitz_cgl_thread_info_t _thread_info = {
+ 0,
+ NULL,
+ NULL,
+ 0,
+ NULL,
+ 0,
+ { 0 },
+ 0,
+ NULL,
+ 0,
+ NULL,
+ { 0 }
+};
+
+static void
+glitz_cgl_thread_info_destroy (glitz_cgl_thread_info_t *thread_info)
+{
+ if (thread_info)
+ glitz_cgl_thread_info_fini (thread_info);
+}
+
+glitz_cgl_thread_info_t *
+glitz_cgl_thread_info_get (void)
+{
+ if (_thread_info.context_stack_size == 0)
+ glitz_cgl_thread_info_init (&_thread_info);
+
+ return &_thread_info;
+}
+
+#endif
+
+static void
+glitz_cgl_thread_info_init (glitz_cgl_thread_info_t *thread_info)
+{
+ thread_info->formats = NULL;
+ thread_info->pixel_formats = (NSOpenGLPixelFormat **) 0;
+ thread_info->n_formats = 0;
+ thread_info->contexts = NULL;
+ thread_info->n_contexts = 0;
+
+ thread_info->context_stack_size = 1;
+ thread_info->context_stack->surface = NULL;
+ thread_info->context_stack->constraint = GLITZ_NONE;
+
+ thread_info->root_context = NULL;
+
+ thread_info->cgl_feature_mask = 0;
+
+ thread_info->cctx = NULL;
+
+ glitz_program_map_init (&thread_info->program_map);
+
+ if (!glitz_cgl_query_extensions (thread_info))
+ glitz_cgl_query_formats (thread_info);
+}
+
+static void
+glitz_cgl_thread_info_fini (glitz_cgl_thread_info_t *thread_info)
+{
+ int i;
+
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+ for (i = 0; i < thread_info->n_contexts; i++)
+ glitz_cgl_context_destroy (thread_info, thread_info->contexts[i]);
+
+ for (i = 0; i < thread_info->n_formats; i++)
+ {
+ NSOpenGLPixelFormat *pix = thread_info->pixel_formats[i];
+ [pix release];
+ }
+
+ if (thread_info->formats)
+ free (thread_info->formats);
+
+ if (thread_info->pixel_formats)
+ free (thread_info->pixel_formats);
+
+ [pool release];
+}
+
+void
+glitz_cgl_init (void)
+{
+ glitz_cgl_thread_info_get ();
+}
+slim_hidden_def(glitz_cgl_init);
+
+void
+glitz_cgl_fini (void)
+{
+ glitz_cgl_thread_info_t *info = glitz_cgl_thread_info_get ();
+
+ glitz_cgl_thread_info_destroy (info);
+}
+slim_hidden_def(glitz_cgl_fini);
diff --git a/src/cgl/glitz_cgl_pbuffer.m b/src/cgl/glitz_cgl_pbuffer.m
new file mode 100644
index 0000000..6aa8dee
--- /dev/null
+++ b/src/cgl/glitz_cgl_pbuffer.m
@@ -0,0 +1,65 @@
+/*
+ * Copyright © 2004 David Reveman
+ * Copyright © 2008 Paolo Bonzini
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of the
+ * copyright holders not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior permission.
+ * The copyright holders make no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express or
+ * implied warranty.
+ *
+ * COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+ * NO EVENT SHALL DAVID REVEMAN BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: David Reveman <davidr@novell.com>
+ * Author: Paolo Bonzini <bonzini@gnu.org>
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "../../config.h"
+#endif
+
+#include "glitz_cglint.h"
+
+NSOpenGLPixelBuffer *
+glitz_cgl_pbuffer_create (glitz_cgl_thread_info_t *thread_info,
+ int width,
+ int height)
+{
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+ NSOpenGLPixelBuffer *pbuffer;
+ glitz_gl_enum_t target;
+
+ if (!POWER_OF_TWO (width) || !POWER_OF_TWO (height)) {
+ if (thread_info->cgl_feature_mask &
+ GLITZ_CGL_FEATURE_TEXTURE_RECTANGLE_MASK)
+ target = GLITZ_GL_TEXTURE_RECTANGLE;
+ else
+ return NULL;
+ } else
+ target = GLITZ_GL_TEXTURE_2D;
+
+ pbuffer = [[NSOpenGLPixelBuffer alloc] initWithTextureTarget: target
+ textureInternalFormat: GLITZ_GL_RGBA
+ textureMaxMipMapLevel: 0 pixelsWide: width pixelsHigh: height];
+ [pool release];
+ return pbuffer;
+}
+
+void
+glitz_cgl_pbuffer_destroy (NSOpenGLPixelBuffer *pbuffer)
+{
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+ [pbuffer release];
+ [pool release];
+}
diff --git a/src/cgl/glitz_cglint.h b/src/cgl/glitz_cglint.h
new file mode 100644
index 0000000..bcfa9d0
--- /dev/null
+++ b/src/cgl/glitz_cglint.h
@@ -0,0 +1,157 @@
+/*
+ * Copyright © 2004 David Reveman
+ * Copyright © 2008 Paolo Bonzini
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of the
+ * copyright holders not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior permission.
+ * The copyright holders make no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express or
+ * implied warranty.
+ *
+ * COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+ * NO EVENT SHALL DAVID REVEMAN BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: David Reveman <davidr@novell.com>
+ * Author: Paolo Bonzini <bonzini@gnu.org>
+ */
+
+#ifndef GLITZ_GLXINT_H_INCLUDED
+#define GLITZ_GLXINT_H_INCLUDED
+
+#include "glitz.h"
+#include "glitzint.h"
+
+#include "glitz-cgl.h"
+
+#include <OpenGL/gl.h>
+#include <AppKit/AppKit.h>
+
+#define GLITZ_CGL_FEATURE_PBUFFER_MASK (1L << 0)
+#define GLITZ_CGL_FEATURE_MULTISAMPLE_MASK (1L << 1)
+#define GLITZ_CGL_FEATURE_PBUFFER_DOUBLEBUFFER_MASK (1L << 2)
+#define GLITZ_CGL_FEATURE_PBUFFER_MULTISAMPLE_MASK (1L << 3)
+#define GLITZ_CGL_FEATURE_PBUFFER_DEPTH_STENCIL_MASK (1L << 4)
+#define GLITZ_CGL_FEATURE_TEXTURE_RECTANGLE_MASK (1L << 5)
+
+typedef struct _glitz_cgl_drawable glitz_cgl_drawable_t;
+
+typedef struct _glitz_cgl_context_info_t {
+ glitz_cgl_drawable_t *drawable;
+ glitz_surface_t *surface;
+ glitz_constraint_t constraint;
+} glitz_cgl_context_info_t;
+
+typedef struct _glitz_cgl_context_t {
+ glitz_context_t base;
+ NSOpenGLContext *context;
+ glitz_format_id_t id;
+ NSOpenGLPixelFormat *pixel_format;
+ glitz_bool_t pbuffer;
+ glitz_backend_t backend;
+ glitz_bool_t initialized;
+} glitz_cgl_context_t;
+
+typedef struct _glitz_cgl_thread_info_t {
+ int drawables;
+ glitz_int_drawable_format_t *formats;
+ NSOpenGLPixelFormat **pixel_formats;
+ int n_formats;
+ glitz_cgl_context_t **contexts;
+ int n_contexts;
+ glitz_cgl_context_info_t context_stack[GLITZ_CONTEXT_STACK_SIZE];
+ int context_stack_size;
+ NSOpenGLContext *root_context;
+ unsigned long cgl_feature_mask;
+ glitz_context_t *cctx;
+ glitz_program_map_t program_map;
+} glitz_cgl_thread_info_t;
+
+struct _glitz_cgl_drawable {
+ glitz_drawable_t base;
+
+ glitz_cgl_thread_info_t *thread_info;
+ glitz_cgl_context_t *context;
+ NSOpenGLPixelBuffer *pbuffer;
+ NSView *view;
+ int width;
+ int height;
+};
+
+extern glitz_status_t __internal_linkage
+glitz_cgl_query_extensions (glitz_cgl_thread_info_t *thread_info);
+
+extern glitz_cgl_thread_info_t __internal_linkage *
+glitz_cgl_thread_info_get (void);
+
+extern glitz_cgl_context_t __internal_linkage *
+glitz_cgl_context_get (glitz_cgl_thread_info_t *thread_info,
+ glitz_drawable_format_t *format);
+
+extern void __internal_linkage
+glitz_cgl_context_destroy (glitz_cgl_thread_info_t *thread_info,
+ glitz_cgl_context_t *context);
+
+extern void __internal_linkage
+glitz_cgl_query_formats (glitz_cgl_thread_info_t *thread_info);
+
+extern NSOpenGLPixelBuffer *__internal_linkage
+glitz_cgl_pbuffer_create (glitz_cgl_thread_info_t *thread_info,
+ int width,
+ int height);
+
+extern void __internal_linkage
+glitz_cgl_pbuffer_destroy (NSOpenGLPixelBuffer *pbuffer);
+
+extern glitz_drawable_t __internal_linkage *
+glitz_cgl_create_pbuffer (void *abstract_templ,
+ glitz_drawable_format_t *format,
+ unsigned int width,
+ unsigned int height);
+
+extern glitz_bool_t __internal_linkage
+glitz_cgl_push_current (void *abstract_drawable,
+ glitz_surface_t *surface,
+ glitz_constraint_t constraint,
+ glitz_bool_t *restore_state);
+
+extern glitz_surface_t __internal_linkage *
+glitz_cgl_pop_current (void *abstract_drawable);
+
+extern void __internal_linkage
+glitz_cgl_destroy (void *abstract_drawable);
+
+extern glitz_bool_t __internal_linkage
+glitz_cgl_swap_buffers (void *abstract_drawable);
+
+extern glitz_bool_t __internal_linkage
+glitz_cgl_copy_sub_buffer (void *abstract_drawable,
+ int x,
+ int y,
+ int width,
+ int height);
+
+extern glitz_bool_t __internal_linkage
+glitz_cgl_drawable_update_size (glitz_cgl_drawable_t *drawable,
+ int width,
+ int height);
+
+/* Avoid unnecessary PLT entries. */
+
+slim_hidden_proto(glitz_cgl_init)
+slim_hidden_proto(glitz_cgl_fini)
+slim_hidden_proto(glitz_cgl_find_drawable_format)
+slim_hidden_proto(glitz_cgl_create_drawable_for_window)
+slim_hidden_proto(glitz_cgl_create_pbuffer_drawable)
+slim_hidden_proto(glitz_cgl_drawable_update_size)
+
+#endif /* GLITZ_GLXINT_H_INCLUDED */