summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2009-05-19 15:53:55 +0100
committerChris Wilson <chris@chris-wilson.co.uk>2009-05-20 08:13:45 +0100
commit87b764908a38cbb4159ac76d8b7d1d08a24b838e (patch)
tree90150c81390f7e8386474b43f28fbb8a939f3725
parent17b41fe7e3b8b493341be6384d816105aadf0cb6 (diff)
[gl] Add EGL target
Split the GLX context from the GL surface to enable use of an alternative EGL interface.
-rw-r--r--boilerplate/Makefile.win32.features20
-rw-r--r--boilerplate/cairo-boilerplate-gl.c2
-rw-r--r--build/Makefile.win32.features2
-rw-r--r--build/Makefile.win32.features-h6
-rw-r--r--build/configure.ac.features3
-rw-r--r--configure.ac30
-rw-r--r--src/Makefile.sources4
-rw-r--r--src/Makefile.win32.features28
-rw-r--r--src/cairo-egl-context.c181
-rw-r--r--src/cairo-gl-private.h88
-rw-r--r--src/cairo-gl-surface.c191
-rw-r--r--src/cairo-gl.h41
-rw-r--r--src/cairo-glx-context.c136
-rw-r--r--test/.gitignore2
-rw-r--r--test/Makefile.am10
-rw-r--r--test/egl-flowers.c358
-rw-r--r--test/glx-flowers.c256
-rw-r--r--util/cairo-script/.gitignore2
-rw-r--r--util/cairo-script/Makefile.am15
-rw-r--r--util/cairo-script/csi-egl.c263
-rw-r--r--util/cairo-script/csi-glx.c150
-rw-r--r--util/cairo-script/csi-replay.c61
22 files changed, 1723 insertions, 126 deletions
diff --git a/boilerplate/Makefile.win32.features b/boilerplate/Makefile.win32.features
index 3d55ced7..fd08ed60 100644
--- a/boilerplate/Makefile.win32.features
+++ b/boilerplate/Makefile.win32.features
@@ -149,6 +149,26 @@ enabled_cairo_boilerplate_private += $(cairo_boilerplate_gl_private)
enabled_cairo_boilerplate_sources += $(cairo_boilerplate_gl_sources)
endif
+supported_cairo_boilerplate_headers += $(cairo_boilerplate_gl_glx_headers)
+all_cairo_boilerplate_headers += $(cairo_boilerplate_gl_glx_headers)
+all_cairo_boilerplate_private += $(cairo_boilerplate_gl_glx_private)
+all_cairo_boilerplate_sources += $(cairo_boilerplate_gl_glx_sources)
+ifeq ($(CAIRO_HAS_GL_GLX_SURFACE),1)
+enabled_cairo_boilerplate_headers += $(cairo_boilerplate_gl_glx_headers)
+enabled_cairo_boilerplate_private += $(cairo_boilerplate_gl_glx_private)
+enabled_cairo_boilerplate_sources += $(cairo_boilerplate_gl_glx_sources)
+endif
+
+supported_cairo_boilerplate_headers += $(cairo_boilerplate_gl_egl_headers)
+all_cairo_boilerplate_headers += $(cairo_boilerplate_gl_egl_headers)
+all_cairo_boilerplate_private += $(cairo_boilerplate_gl_egl_private)
+all_cairo_boilerplate_sources += $(cairo_boilerplate_gl_egl_sources)
+ifeq ($(CAIRO_HAS_GL_EGL_SURFACE),1)
+enabled_cairo_boilerplate_headers += $(cairo_boilerplate_gl_egl_headers)
+enabled_cairo_boilerplate_private += $(cairo_boilerplate_gl_egl_private)
+enabled_cairo_boilerplate_sources += $(cairo_boilerplate_gl_egl_sources)
+endif
+
unsupported_cairo_boilerplate_headers += $(cairo_boilerplate_glitz_headers)
all_cairo_boilerplate_headers += $(cairo_boilerplate_glitz_headers)
all_cairo_boilerplate_private += $(cairo_boilerplate_glitz_private)
diff --git a/boilerplate/cairo-boilerplate-gl.c b/boilerplate/cairo-boilerplate-gl.c
index e818341c..37dfc42f 100644
--- a/boilerplate/cairo-boilerplate-gl.c
+++ b/boilerplate/cairo-boilerplate-gl.c
@@ -119,7 +119,7 @@ _cairo_boilerplate_gl_create_surface (const char *name,
XFree (visinfo);
gltc->gl_ctx = gl_ctx;
- gltc->ctx = cairo_gl_glx_context_create (dpy, gl_ctx);
+ gltc->ctx = cairo_glx_context_create (dpy, gl_ctx);
gltc->surface = cairo_gl_surface_create (gltc->ctx, content,
width, height);
diff --git a/build/Makefile.win32.features b/build/Makefile.win32.features
index 69b3b39e..f9e064de 100644
--- a/build/Makefile.win32.features
+++ b/build/Makefile.win32.features
@@ -13,6 +13,8 @@ CAIRO_HAS_BEOS_SURFACE=0
CAIRO_HAS_SDL_SURFACE=0
CAIRO_HAS_PNG_FUNCTIONS=1
CAIRO_HAS_GL_SURFACE=0
+CAIRO_HAS_GL_GLX_SURFACE=0
+CAIRO_HAS_GL_EGL_SURFACE=0
CAIRO_HAS_GLITZ_SURFACE=0
CAIRO_HAS_DIRECTFB_SURFACE=0
CAIRO_HAS_SCRIPT_SURFACE=0
diff --git a/build/Makefile.win32.features-h b/build/Makefile.win32.features-h
index cae81357..da80593d 100644
--- a/build/Makefile.win32.features-h
+++ b/build/Makefile.win32.features-h
@@ -44,6 +44,12 @@ endif
ifeq ($(CAIRO_HAS_GL_SURFACE),1)
@echo "#define CAIRO_HAS_GL_SURFACE 1" >> src/cairo-features.h
endif
+ifeq ($(CAIRO_HAS_GL_GLX_SURFACE),1)
+ @echo "#define CAIRO_HAS_GL_GLX_SURFACE 1" >> src/cairo-features.h
+endif
+ifeq ($(CAIRO_HAS_GL_EGL_SURFACE),1)
+ @echo "#define CAIRO_HAS_GL_EGL_SURFACE 1" >> src/cairo-features.h
+endif
ifeq ($(CAIRO_HAS_GLITZ_SURFACE),1)
@echo "#define CAIRO_HAS_GLITZ_SURFACE 1" >> src/cairo-features.h
endif
diff --git a/build/configure.ac.features b/build/configure.ac.features
index 06ed7f3e..f4774143 100644
--- a/build/configure.ac.features
+++ b/build/configure.ac.features
@@ -377,6 +377,9 @@ AC_DEFUN([CAIRO_REPORT],
echo " BeOS: $use_beos"
echo " DirectFB: $use_directfb"
echo " SDL: $use_sdl"
+ echo " GL: $use_gl"
+ echo " GL/GLX: $use_gl_glx"
+ echo " GL/EGL: $use_gl_egl"
echo ""
echo "The following font backends:"
echo " User: yes (always builtin)"
diff --git a/configure.ac b/configure.ac
index 4d1e8116..821545ff 100644
--- a/configure.ac
+++ b/configure.ac
@@ -199,14 +199,40 @@ CAIRO_ENABLE_SURFACE_BACKEND(gl, gl, no, [
AC_CHECK_LIB(GLEW, glewInit, [
AC_CHECK_HEADER(GL/glew.h, [], [
- have_gl="no (requires glew http://glew.sourceforge.net/)"
+ use_gl="no (requires glew http://glew.sourceforge.net/)"
])
], [
- have_gl="no (requires glew http://glew.sourceforge.net/)"
+ use_gl="no (requires glew http://glew.sourceforge.net/)"
])
gl_NONPKGCONFIG_LIBS="-lGLEW"
])
+CAIRO_ENABLE_SURFACE_BACKEND(gl_glx, GLX, auto, [
+ if test "x$use_gl" != "xyes"; then
+ use_gl_glx="no (requires --enable-gl)"
+ else
+ gl_glx_BASE=cairo-gl
+ old_CPPFLAGS=$CPPFLAGS
+ CPPFLAGS="$CPPFLAGS $gl_CFLAGS $gl_NONPKGCONFIG_CFLAGS"
+ AC_CHECK_HEADER(GL/glx.h,
+ [],
+ [use_gl_glx="no (requires GLX)"])
+ CPPFLAGS=$old_CPPFLAGS
+ fi
+])
+
+CAIRO_ENABLE_SURFACE_BACKEND(gl_egl, eagle, auto, [
+ if test "x$use_gl" != "xyes"; then
+ use_gl_egl="no (requires --enable-gl)"
+ else
+ gl_egl_BASE=cairo-gl
+ gl_egl_REQUIRES="eagle"
+ PKG_CHECK_MODULES(gl_egl, $gl_egl_REQUIRES, ,
+ [AC_MSG_RESULT(no)
+ use_gl_egl="no (requires eagle)"])
+ fi
+])
+
dnl ===========================================================================
GLITZ_MIN_VERSION=0.5.1
diff --git a/src/Makefile.sources b/src/Makefile.sources
index 6407271e..a9260640 100644
--- a/src/Makefile.sources
+++ b/src/Makefile.sources
@@ -245,8 +245,10 @@ cairo_beos_headers = cairo-beos.h
#cairo_beos_sources = cairo-beos-surface.cpp
cairo_gl_headers = cairo-gl.h
-cairo_gl_private =
+cairo_gl_private = cairo-gl-private.h
cairo_gl_sources = cairo-gl-surface.c
+cairo_gl_glx_sources = cairo-glx-context.c
+cairo_gl_egl_sources = cairo-egl-context.c
cairo_glitz_headers = cairo-glitz.h
cairo_glitz_private = cairo-glitz-private.h
diff --git a/src/Makefile.win32.features b/src/Makefile.win32.features
index 9e7bffe5..f90c36b8 100644
--- a/src/Makefile.win32.features
+++ b/src/Makefile.win32.features
@@ -203,6 +203,34 @@ ifeq ($(CAIRO_HAS_GL_SURFACE),1)
enabled_cairo_pkgconf += cairo-gl.pc
endif
+supported_cairo_headers += $(cairo_gl_glx_headers)
+all_cairo_headers += $(cairo_gl_glx_headers)
+all_cairo_private += $(cairo_gl_glx_private)
+all_cairo_sources += $(cairo_gl_glx_sources)
+ifeq ($(CAIRO_HAS_GL_GLX_SURFACE),1)
+enabled_cairo_headers += $(cairo_gl_glx_headers)
+enabled_cairo_private += $(cairo_gl_glx_private)
+enabled_cairo_sources += $(cairo_gl_glx_sources)
+endif
+all_cairo_pkgconf += cairo-gl-glx.pc
+ifeq ($(CAIRO_HAS_GL_GLX_SURFACE),1)
+enabled_cairo_pkgconf += cairo-gl-glx.pc
+endif
+
+supported_cairo_headers += $(cairo_gl_egl_headers)
+all_cairo_headers += $(cairo_gl_egl_headers)
+all_cairo_private += $(cairo_gl_egl_private)
+all_cairo_sources += $(cairo_gl_egl_sources)
+ifeq ($(CAIRO_HAS_GL_EGL_SURFACE),1)
+enabled_cairo_headers += $(cairo_gl_egl_headers)
+enabled_cairo_private += $(cairo_gl_egl_private)
+enabled_cairo_sources += $(cairo_gl_egl_sources)
+endif
+all_cairo_pkgconf += cairo-gl-egl.pc
+ifeq ($(CAIRO_HAS_GL_EGL_SURFACE),1)
+enabled_cairo_pkgconf += cairo-gl-egl.pc
+endif
+
unsupported_cairo_headers += $(cairo_glitz_headers)
all_cairo_headers += $(cairo_glitz_headers)
all_cairo_private += $(cairo_glitz_private)
diff --git a/src/cairo-egl-context.c b/src/cairo-egl-context.c
new file mode 100644
index 00000000..ba314d52
--- /dev/null
+++ b/src/cairo-egl-context.c
@@ -0,0 +1,181 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2009 Eric Anholt
+ * Copyright © 2009 Chris Wilson
+ * Copyright © 2005 Red Hat, Inc
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is Red Hat, Inc.
+ *
+ * Contributor(s):
+ * Carl Worth <cworth@cworth.org>
+ * Chris Wilson <chris@chris-wilson.co.uk>
+ */
+
+#include "cairoint.h"
+
+#include "cairo-gl-private.h"
+
+#include <i915_drm.h> /* XXX dummy surface for glewInit() */
+#include <sys/ioctl.h>
+
+typedef struct _cairo_egl_context {
+ cairo_gl_context_t base;
+
+ EGLDisplay display;
+ EGLContext context;
+} cairo_egl_context_t;
+
+typedef struct _cairo_egl_surface {
+ cairo_gl_surface_t base;
+
+ EGLSurface egl;
+} cairo_egl_surface_t;
+
+static void
+_egl_make_current (void *abstract_ctx,
+ cairo_gl_surface_t *abstract_surface)
+{
+ cairo_egl_context_t *ctx = abstract_ctx;
+ cairo_egl_surface_t *surface = (cairo_egl_surface_t *) abstract_surface;
+
+ eglMakeCurrent (ctx->display, surface->egl, surface->egl, ctx->context);
+}
+
+static void
+_egl_swap_buffers (void *abstract_ctx,
+ cairo_gl_surface_t *abstract_surface)
+{
+ cairo_egl_context_t *ctx = abstract_ctx;
+ cairo_egl_surface_t *surface = (cairo_egl_surface_t *) abstract_surface;
+
+ eglSwapBuffers (ctx->display, surface->egl);
+}
+
+static void
+_egl_destroy (void *abstract_ctx)
+{
+}
+
+static cairo_bool_t
+_egl_init (EGLDisplay display, EGLContext context)
+{
+ const EGLint config_attribs[] = {
+ EGL_CONFIG_CAVEAT, EGL_NONE,
+ EGL_NONE
+ };
+ const EGLint surface_attribs[] = {
+ EGL_RENDER_BUFFER, EGL_BACK_BUFFER,
+ EGL_NONE
+ };
+ EGLConfig config;
+ EGLSurface dummy;
+ struct drm_i915_gem_create create;
+ struct drm_gem_flink flink;
+ int fd;
+ GLenum err;
+
+ if (! eglChooseConfig (display, config_attribs, &config, 1, NULL)) {
+ fprintf (stderr, "Unable to choose config\n");
+ return FALSE;
+ }
+
+ /* XXX */
+ fd = eglGetDisplayFD (display);
+
+ create.size = 4096;
+ if (ioctl (fd, DRM_IOCTL_I915_GEM_CREATE, &create) != 0) {
+ fprintf (stderr, "gem create failed: %m\n");
+ return FALSE;
+ }
+ flink.handle = create.handle;
+ if (ioctl (fd, DRM_IOCTL_GEM_FLINK, &flink) != 0) {
+ fprintf (stderr, "gem flink failed: %m\n");
+ return FALSE;
+ }
+
+ dummy = eglCreateSurfaceForName (display, config, flink.name,
+ 1, 1, 4, surface_attribs);
+ if (dummy == NULL) {
+ fprintf (stderr, "Failed to create dummy surface\n");
+ return FALSE;
+ }
+
+ eglMakeCurrent (display, dummy, dummy, context);
+}
+
+cairo_gl_context_t *
+cairo_egl_context_create (EGLDisplay display, EGLContext context)
+{
+ cairo_egl_context_t *ctx;
+ cairo_status_t status;
+
+ if (! _egl_init (display, context)) {
+ return _cairo_gl_context_create_in_error (CAIRO_STATUS_NO_MEMORY);
+ }
+
+ ctx = calloc (1, sizeof (cairo_egl_context_t));
+ if (ctx == NULL)
+ return _cairo_gl_context_create_in_error (CAIRO_STATUS_NO_MEMORY);
+
+ ctx->display = display;
+ ctx->context = context;
+
+ ctx->base.make_current = _egl_make_current;
+ ctx->base.swap_buffers = _egl_swap_buffers;
+ ctx->base.destroy = _egl_destroy;
+
+ status = _cairo_gl_context_init (&ctx->base);
+ if (status) {
+ free (ctx);
+ return _cairo_gl_context_create_in_error (status);
+ }
+
+ return &ctx->base;
+}
+
+cairo_surface_t *
+cairo_gl_surface_create_for_eagle (cairo_gl_context_t *ctx,
+ EGLSurface egl,
+ int width,
+ int height)
+{
+ cairo_egl_surface_t *surface;
+
+ if (ctx->status)
+ return _cairo_surface_create_in_error (ctx->status);
+
+ surface = calloc (1, sizeof (cairo_egl_surface_t));
+ if (unlikely (surface == NULL))
+ return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
+
+ _cairo_gl_surface_init (ctx, &surface->base,
+ CAIRO_CONTENT_COLOR_ALPHA, width, height);
+ surface->egl = egl;
+
+ return &surface->base.base;
+}
diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h
new file mode 100644
index 00000000..47ebd01d
--- /dev/null
+++ b/src/cairo-gl-private.h
@@ -0,0 +1,88 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2009 Eric Anholt
+ * Copyright © 2009 Chris Wilson
+ * Copyright © 2005 Red Hat, Inc
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is Red Hat, Inc.
+ *
+ * Contributor(s):
+ * Carl Worth <cworth@cworth.org>
+ * Chris Wilson <chris@chris-wilson.co.uk>
+ */
+
+#ifndef CAIRO_GL_PRIVATE_H
+#define CAIRO_GL_PRIVATE_H
+
+#include "cairoint.h"
+
+#include <GL/glew.h>
+
+#include "cairo-gl.h"
+
+#include <GL/gl.h>
+#define GL_GLEXT_PROTOTYPES
+#include <GL/glext.h>
+
+typedef struct _cairo_gl_surface {
+ cairo_surface_t base;
+
+ cairo_gl_context_t *ctx;
+ int width, height;
+
+ GLuint tex; /* GL texture object containing our data. */
+ GLuint fb; /* GL framebuffer object wrapping our data. */
+} cairo_gl_surface_t;
+
+struct _cairo_gl_context {
+ cairo_reference_count_t ref_count;
+ cairo_status_t status;
+
+ cairo_mutex_t mutex; /* needed? */
+ GLuint dummy_tex;
+
+ cairo_gl_surface_t *current_target;
+
+ void (*make_current)(void *ctx, cairo_gl_surface_t *surface);
+ void (*swap_buffers)(void *ctx, cairo_gl_surface_t *surface);
+ void (*destroy) (void *ctx);
+};
+
+cairo_private cairo_gl_context_t *
+_cairo_gl_context_create_in_error (cairo_status_t status);
+
+cairo_private cairo_status_t
+_cairo_gl_context_init (cairo_gl_context_t *ctx);
+
+cairo_private void
+_cairo_gl_surface_init (cairo_gl_context_t *ctx,
+ cairo_gl_surface_t *surface,
+ cairo_content_t content,
+ int width, int height);
+
+#endif /* CAIRO_GL_PRIVATE_H */
diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index 8bf6e298..299500f5 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -35,43 +35,12 @@
* Carl Worth <cworth@cworth.org>
*/
-
-#include <X11/Xlib.h>
-
-#include <GL/glew.h>
-#define GL_GLEXT_PROTOTYPES
-#include <GL/glx.h>
-#include <GL/glext.h>
-
#include "cairoint.h"
-#include "cairo-gl.h"
+#include "cairo-gl-private.h"
#define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))
-typedef struct _cairo_gl_surface {
- cairo_surface_t base;
-
- cairo_gl_context_t *ctx;
- cairo_content_t content;
- int width, height;
-
- Window win; /* window if not rendering to FBO */
- GLuint tex; /* GL texture object containing our data. */
- GLuint fb; /* GL framebuffer object wrapping our data. */
-} cairo_gl_surface_t;
-
-struct _cairo_gl_context {
- cairo_reference_count_t ref_count;
- cairo_status_t status;
-
- Display *dpy;
- GLXContext gl_ctx;
- cairo_mutex_t mutex; /* needed? */
- cairo_gl_surface_t *current_target;
- GLuint dummy_tex;
-};
-
enum cairo_gl_composite_operand_type {
OPERAND_CONSTANT,
OPERAND_TEXTURE,
@@ -114,7 +83,7 @@ static cairo_bool_t _cairo_surface_is_gl (cairo_surface_t *surface)
return surface->backend == &_cairo_gl_surface_backend;
}
-static cairo_gl_context_t *
+cairo_gl_context_t *
_cairo_gl_context_create_in_error (cairo_status_t status)
{
if (status == CAIRO_STATUS_NO_MEMORY)
@@ -124,37 +93,31 @@ _cairo_gl_context_create_in_error (cairo_status_t status)
return NULL;
}
-cairo_gl_context_t *
-cairo_gl_glx_context_create (Display *dpy, GLXContext gl_ctx)
+cairo_status_t
+_cairo_gl_context_init (cairo_gl_context_t *ctx)
{
- cairo_gl_context_t *ctx;
- GLenum err;
-
- ctx = calloc (1, sizeof(cairo_gl_context_t));
- if (ctx == NULL)
- return _cairo_gl_context_create_in_error (CAIRO_STATUS_NO_MEMORY);
-
+ ctx->status = CAIRO_STATUS_SUCCESS;
CAIRO_REFERENCE_COUNT_INIT (&ctx->ref_count, 1);
- ctx->dpy = dpy;
- ctx->gl_ctx = gl_ctx;
+ CAIRO_MUTEX_INIT (ctx->mutex);
- /* Make our GL context active. While we'll be setting the destination
- * drawable with each rendering operation, in order to set the context
- * we have to choose a drawable. The root window happens to be convenient
- * for this.
- */
- glXMakeCurrent(dpy, RootWindow (dpy, DefaultScreen (dpy)), gl_ctx);
-
- err = glewInit();
- if (err != GLEW_OK) {
- free(ctx);
- return NULL;
+ if (glewInit () != GLEW_OK) {
+ return _cairo_error (CAIRO_STATUS_INVALID_FORMAT); /* XXX */
}
- if (!GLEW_EXT_framebuffer_object || !GLEW_ARB_texture_env_combine ||
- !GLEW_ARB_texture_non_power_of_two) {
- free(ctx);
- return NULL;
+ if (! GLEW_EXT_framebuffer_object ||
+ ! GLEW_ARB_texture_env_combine ||
+ ! GLEW_ARB_texture_non_power_of_two)
+ {
+ fprintf (stderr,
+ "Required GL extensions not available:\n");
+ if (! GLEW_EXT_framebuffer_object)
+ fprintf (stderr, " GL_EXT_framebuffer_object\n");
+ if (! GLEW_ARB_texture_env_combine)
+ fprintf (stderr, " GL_ARB_texture_env_combine\n");
+ if (! GLEW_ARB_texture_non_power_of_two)
+ fprintf (stderr, " GL_ARB_texture_non_power_of_two\n");
+
+ return _cairo_error (CAIRO_STATUS_INVALID_FORMAT); /* XXX */
}
/* Set up the dummy texture for tex_env_combine with constant color. */
@@ -163,7 +126,7 @@ cairo_gl_glx_context_create (Display *dpy, GLXContext gl_ctx)
glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0,
GL_RGBA, GL_UNSIGNED_BYTE, NULL);
- return ctx;
+ return CAIRO_STATUS_SUCCESS;
}
cairo_gl_context_t *
@@ -196,6 +159,8 @@ cairo_gl_context_destroy (cairo_gl_context_t *context)
glDeleteTextures (1, &context->dummy_tex);
+ context->destroy (context);
+
free (context);
}
@@ -225,8 +190,7 @@ _cairo_gl_set_destination (cairo_gl_surface_t *surface)
glDrawBuffer (GL_COLOR_ATTACHMENT0_EXT);
glReadBuffer (GL_COLOR_ATTACHMENT0_EXT);
} else {
- /* Set the window as the target of our context. */
- glXMakeCurrent (ctx->dpy, surface->win, ctx->gl_ctx);
+ ctx->make_current (ctx, surface);
glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0);
glDrawBuffer (GL_BACK_LEFT);
glReadBuffer (GL_BACK_LEFT);
@@ -280,7 +244,7 @@ _cairo_gl_set_operator (cairo_gl_surface_t *dst, cairo_operator_t op)
/* We may have a visual with alpha bits despite the user requesting
* CAIRO_CONTENT_COLOR. So clear out those bits in that case.
*/
- if (dst->content == CAIRO_CONTENT_COLOR) {
+ if (dst->base.content == CAIRO_CONTENT_COLOR) {
if (src_factor == GL_ONE_MINUS_DST_ALPHA)
src_factor = GL_ZERO;
if (src_factor == GL_DST_ALPHA)
@@ -335,6 +299,21 @@ _cairo_gl_set_texture_surface (int tex_unit, GLuint tex,
glEnable (GL_TEXTURE_2D);
}
+void
+_cairo_gl_surface_init (cairo_gl_context_t *ctx,
+ cairo_gl_surface_t *surface,
+ cairo_content_t content,
+ int width, int height)
+{
+ _cairo_surface_init (&surface->base,
+ &_cairo_gl_surface_backend,
+ content);
+
+ surface->ctx = cairo_gl_context_reference (ctx);
+ surface->width = width;
+ surface->height = height;
+}
+
cairo_surface_t *
cairo_gl_surface_create (cairo_gl_context_t *ctx,
cairo_content_t content,
@@ -359,12 +338,7 @@ cairo_gl_surface_create (cairo_gl_context_t *ctx,
if (unlikely (surface == NULL))
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
- _cairo_surface_init (&surface->base,
- &_cairo_gl_surface_backend,
- content);
-
- surface->ctx = cairo_gl_context_reference (ctx);
- surface->content = content;
+ _cairo_gl_surface_init (ctx, surface, content, width, height);
switch (content) {
default:
@@ -407,9 +381,6 @@ cairo_gl_surface_create (cairo_gl_context_t *ctx,
if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
fprintf(stderr, "destination is framebuffer incomplete\n");
- surface->width = width;
- surface->height = height;
-
/* Cairo surfaces start out initialized to transparent (black) */
ctx = _cairo_gl_context_acquire (surface->ctx);
_cairo_gl_set_destination (surface);
@@ -420,33 +391,6 @@ cairo_gl_surface_create (cairo_gl_context_t *ctx,
return &surface->base;
}
-
-cairo_surface_t *
-cairo_gl_surface_create_for_window (cairo_gl_context_t *ctx,
- Window win,
- int width,
- int height)
-{
- cairo_gl_surface_t *surface;
- cairo_content_t content = CAIRO_CONTENT_COLOR_ALPHA;
-
- surface = calloc (1, sizeof (cairo_gl_surface_t));
- if (unlikely (surface == NULL))
- return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
-
- _cairo_surface_init (&surface->base,
- &_cairo_gl_surface_backend,
- content);
-
- surface->ctx = cairo_gl_context_reference (ctx);
- surface->content = content;
- surface->width = width;
- surface->height = height;
- surface->win = win;
-
- return &surface->base;
-}
-
void
cairo_gl_surface_set_size (cairo_surface_t *abstract_surface,
int width,
@@ -465,19 +409,43 @@ cairo_gl_surface_set_size (cairo_surface_t *abstract_surface,
surface->height = height;
}
+int
+cairo_gl_surface_get_width (cairo_surface_t *abstract_surface)
+{
+ cairo_gl_surface_t *surface = (cairo_gl_surface_t *) abstract_surface;
+
+ if (! _cairo_surface_is_gl (abstract_surface))
+ return 0;
+
+ return surface->width;
+}
+
+int
+cairo_gl_surface_get_height (cairo_surface_t *abstract_surface)
+{
+ cairo_gl_surface_t *surface = (cairo_gl_surface_t *) abstract_surface;
+
+ if (! _cairo_surface_is_gl (abstract_surface))
+ return 0;
+
+ return surface->height;
+}
+
+
void
cairo_gl_surface_swapbuffers (cairo_surface_t *abstract_surface)
{
cairo_gl_surface_t *surface = (cairo_gl_surface_t *) abstract_surface;
cairo_status_t status;
- if (! _cairo_surface_is_gl (abstract_surface) || surface->fb) {
+ if (! _cairo_surface_is_gl (abstract_surface)) {
status = _cairo_surface_set_error (abstract_surface,
CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
return;
}
- glXSwapBuffers(surface->ctx->dpy, surface->win);
+ if (! surface->fb)
+ surface->ctx->swap_buffers (surface->ctx, surface);
}
static cairo_surface_t *
@@ -528,8 +496,8 @@ _cairo_gl_surface_draw_image (cairo_gl_surface_t *dst,
type = GL_UNSIGNED_INT_8_8_8_8_REV;
cpp = 4;
} else if (src->pixman_format == PIXMAN_x8r8g8b8) {
- assert(dst->content != CAIRO_CONTENT_COLOR_ALPHA);
- assert(dst->content != CAIRO_CONTENT_ALPHA);
+ assert(dst->base.content != CAIRO_CONTENT_COLOR_ALPHA);
+ assert(dst->base.content != CAIRO_CONTENT_ALPHA);
format = GL_BGRA;
type = GL_UNSIGNED_INT_8_8_8_8_REV;
cpp = 4;
@@ -547,7 +515,7 @@ _cairo_gl_surface_draw_image (cairo_gl_surface_t *dst,
*/
temp_data = malloc (width * height * cpp);
if (temp_data == NULL)
- return CAIRO_STATUS_NO_MEMORY;
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
src_data_start = (char *)src->data + (src_y * src->stride) + (src_x * cpp);
for (y = 0; y < height; y++) {
@@ -597,23 +565,23 @@ _cairo_gl_surface_get_image (cairo_gl_surface_t *surface,
*rect_out = extents;
/* Want to use a switch statement here but the compiler gets whiny. */
- if (surface->content == CAIRO_CONTENT_COLOR_ALPHA) {
+ if (surface->base.content == CAIRO_CONTENT_COLOR_ALPHA) {
format = GL_BGRA;
cairo_format = CAIRO_FORMAT_ARGB32;
type = GL_UNSIGNED_INT_8_8_8_8_REV;
cpp = 4;
- } else if (surface->content == CAIRO_CONTENT_COLOR) {
+ } else if (surface->base.content == CAIRO_CONTENT_COLOR) {
format = GL_BGRA;
cairo_format = CAIRO_FORMAT_RGB24;
type = GL_UNSIGNED_INT_8_8_8_8_REV;
cpp = 4;
- } else if (surface->content == CAIRO_CONTENT_ALPHA) {
+ } else if (surface->base.content == CAIRO_CONTENT_ALPHA) {
format = GL_ALPHA;
cairo_format = CAIRO_FORMAT_A8;
type = GL_UNSIGNED_BYTE;
cpp = 1;
} else {
- fprintf(stderr, "get_image fallback: %d\n", surface->content);
+ fprintf(stderr, "get_image fallback: %d\n", surface->base.content);
return CAIRO_INT_STATUS_UNSUPPORTED;
}
@@ -634,7 +602,7 @@ _cairo_gl_surface_get_image (cairo_gl_surface_t *surface,
*/
temp_data = malloc (extents.width * extents.height * cpp);
if (temp_data == NULL)
- return CAIRO_STATUS_NO_MEMORY;
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
glPixelStorei(GL_PACK_ALIGNMENT, 1);
glReadPixels(extents.x, extents.y,
@@ -753,7 +721,8 @@ _cairo_gl_surface_clone_similar (void *abstract_surface,
return CAIRO_INT_STATUS_UNSUPPORTED;
clone = (cairo_gl_surface_t *)
- _cairo_gl_surface_create_similar (&surface->base, src->content,
+ _cairo_gl_surface_create_similar (&surface->base,
+ src->content,
width, height);
if (clone == NULL)
return CAIRO_INT_STATUS_UNSUPPORTED;
@@ -1449,7 +1418,7 @@ _cairo_gl_surface_fill_rectangles (void *abstract_surface,
_cairo_gl_context_release(ctx);
free(vertices);
free(colors);
- return CAIRO_STATUS_NO_MEMORY;
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
/* This should be loaded in as either a blend constant and an operator
diff --git a/src/cairo-gl.h b/src/cairo-gl.h
index eb989773..6b7fee25 100644
--- a/src/cairo-gl.h
+++ b/src/cairo-gl.h
@@ -34,8 +34,6 @@
#ifndef CAIRO_GL_H
#define CAIRO_GL_H
-#include <GL/glx.h>
-
#include "cairo.h"
#if CAIRO_HAS_GL_SURFACE
@@ -45,9 +43,6 @@ CAIRO_BEGIN_DECLS
typedef struct _cairo_gl_context cairo_gl_context_t;
cairo_public cairo_gl_context_t *
-cairo_gl_glx_context_create (Display *dpy, GLXContext gl_ctx);
-
-cairo_public cairo_gl_context_t *
cairo_gl_context_reference (cairo_gl_context_t *context);
cairo_public cairo_status_t
@@ -61,23 +56,48 @@ cairo_gl_surface_create (cairo_gl_context_t *ctx,
cairo_content_t content,
int width, int height);
-cairo_public cairo_surface_t *
-cairo_gl_surface_create_for_window (cairo_gl_context_t *ctx,
- Window win,
- int width, int height);
-
cairo_public cairo_gl_context_t *
cairo_gl_surface_get_context (cairo_surface_t *abstract_surface);
cairo_public void
cairo_gl_surface_set_size (cairo_surface_t *surface, int width, int height);
+cairo_public int
+cairo_gl_surface_get_width (cairo_surface_t *abstract_surface);
+
+cairo_public int
+cairo_gl_surface_get_height (cairo_surface_t *abstract_surface);
+
cairo_public void
cairo_gl_surface_swapbuffers (cairo_surface_t *surface);
cairo_public cairo_status_t
cairo_gl_surface_glfinish (cairo_surface_t *surface);
+#if CAIRO_HAS_GL_GLX_SURFACE
+#include <GL/glx.h>
+
+cairo_public cairo_gl_context_t *
+cairo_glx_context_create (Display *dpy, GLXContext gl_ctx);
+
+cairo_public cairo_surface_t *
+cairo_gl_surface_create_for_window (cairo_gl_context_t *ctx,
+ Window win,
+ int width, int height);
+#endif
+
+#if CAIRO_HAS_GL_EGL_SURFACE
+#include <eagle.h>
+
+cairo_public cairo_gl_context_t *
+cairo_egl_context_create (EGLDisplay display, EGLContext context);
+
+cairo_public cairo_surface_t *
+cairo_gl_surface_create_for_eagle (cairo_gl_context_t *ctx,
+ EGLSurface surface,
+ int width, int height);
+#endif
+
CAIRO_END_DECLS
#else /* CAIRO_HAS_GL_SURFACE */
@@ -85,4 +105,3 @@ CAIRO_END_DECLS
#endif /* CAIRO_HAS_GL_SURFACE */
#endif /* CAIRO_GL_H */
-
diff --git a/src/cairo-glx-context.c b/src/cairo-glx-context.c
new file mode 100644
index 00000000..2fa5faf5
--- /dev/null
+++ b/src/cairo-glx-context.c
@@ -0,0 +1,136 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2009 Eric Anholt
+ * Copyright © 2009 Chris Wilson
+ * Copyright © 2005 Red Hat, Inc
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is Red Hat, Inc.
+ *
+ * Contributor(s):
+ * Carl Worth <cworth@cworth.org>
+ * Chris Wilson <chris@chris-wilson.co.uk>
+ */
+
+#include "cairoint.h"
+
+#include "cairo-gl-private.h"
+
+typedef struct _cairo_glx_context {
+ cairo_gl_context_t base;
+
+ Display *display;
+ GLXContext context;
+} cairo_glx_context_t;
+
+typedef struct _cairo_glx_surface {
+ cairo_gl_surface_t base;
+
+ Window win;
+} cairo_glx_surface_t;
+
+static void
+_glx_make_current (void *abstract_ctx,
+ cairo_gl_surface_t *abstract_surface)
+{
+ cairo_glx_context_t *ctx = abstract_ctx;
+ cairo_glx_surface_t *surface = (cairo_glx_surface_t *) abstract_surface;
+
+ /* Set the window as the target of our context. */
+ glXMakeCurrent (ctx->display, surface->win, ctx->context);
+}
+
+static void
+_glx_swap_buffers (void *abstract_ctx,
+ cairo_gl_surface_t *abstract_surface)
+{
+ cairo_glx_context_t *ctx = abstract_ctx;
+ cairo_glx_surface_t *surface = (cairo_glx_surface_t *) abstract_surface;
+
+ glXSwapBuffers (ctx->display, surface->win);
+}
+
+static void
+_glx_destroy (void *abstract_ctx)
+{
+}
+
+cairo_gl_context_t *
+cairo_glx_context_create (Display *dpy, GLXContext gl_ctx)
+{
+ cairo_glx_context_t *ctx;
+ cairo_status_t status;
+
+ /* Make our GL context active. While we'll be setting the destination
+ * drawable with each rendering operation, in order to set the context
+ * we have to choose a drawable. The root window happens to be convenient
+ * for this.
+ */
+ if (! glXMakeCurrent (dpy, RootWindow (dpy, DefaultScreen (dpy)), gl_ctx))
+ return _cairo_gl_context_create_in_error (CAIRO_STATUS_NO_MEMORY);
+
+ ctx = calloc (1, sizeof (cairo_glx_context_t));
+ if (ctx == NULL)
+ return _cairo_gl_context_create_in_error (CAIRO_STATUS_NO_MEMORY);
+
+ ctx->display = dpy;
+ ctx->context = gl_ctx;
+
+ ctx->base.make_current = _glx_make_current;
+ ctx->base.swap_buffers = _glx_swap_buffers;
+ ctx->base.destroy = _glx_destroy;
+
+ status = _cairo_gl_context_init (&ctx->base);
+ if (status) {
+ free (ctx);
+ return _cairo_gl_context_create_in_error (status);
+ }
+
+ return &ctx->base;
+}
+
+cairo_surface_t *
+cairo_gl_surface_create_for_window (cairo_gl_context_t *ctx,
+ Window win,
+ int width,
+ int height)
+{
+ cairo_glx_surface_t *surface;
+
+ if (ctx->status)
+ return _cairo_surface_create_in_error (ctx->status);
+
+ surface = calloc (1, sizeof (cairo_glx_surface_t));
+ if (unlikely (surface == NULL))
+ return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
+
+ _cairo_gl_surface_init (ctx, &surface->base,
+ CAIRO_CONTENT_COLOR_ALPHA, width, height);
+ surface->win = win;
+
+ return &surface->base.base;
+}
diff --git a/test/.gitignore b/test/.gitignore
index 24ec7a61..fd3f4fb2 100644
--- a/test/.gitignore
+++ b/test/.gitignore
@@ -13,6 +13,8 @@ any2ppm
.any2ppm.errors
cairo-test-constructors.c
cairo-test-suite
+egl-flowers
+glx-flowers
pdf2png
ps2png
svg2png
diff --git a/test/Makefile.am b/test/Makefile.am
index 0b531167..567e6848 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -227,6 +227,16 @@ if CAIRO_HAS_QUARTZ_SURFACE
test_sources += quartz-surface-source.c
endif
+if CAIRO_HAS_GL_EGL_SURFACE
+EXTRA_PROGRAMS += egl-flowers$(EXEEXT)
+egl_flowers_LDADD = $(top_builddir)/src/libcairo.la $(CAIRO_LDADD)
+endif
+
+if CAIRO_HAS_GL_GLX_SURFACE
+EXTRA_PROGRAMS += glx-flowers$(EXEEXT)
+glx_flowers_LDADD = $(top_builddir)/src/libcairo.la $(CAIRO_LDADD)
+endif
+
if CAIRO_HAS_GLITZ_SURFACE
test_sources += glitz-surface-source.c
endif
diff --git a/test/egl-flowers.c b/test/egl-flowers.c
new file mode 100644
index 00000000..4facec7f
--- /dev/null
+++ b/test/egl-flowers.c
@@ -0,0 +1,358 @@
+/*
+ * Copyright © 2007 Michael Dominic K.
+ * Copyright © 2008, 2009 Kristian Høgsberg
+ * Copyright © 2009 Chris Wilson
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any later
+ * version.
+ *
+ * This program 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 General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+#include <cairo-gl.h>
+
+#include <math.h>
+#include <stdio.h>
+
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <xf86drmMode.h>
+#include <i915_drm.h>
+
+#define LIBUDEV_I_KNOW_THE_API_IS_SUBJECT_TO_CHANGE
+#include <libudev.h>
+
+typedef struct {
+ float x;
+ float y;
+ float scale;
+ float rotation;
+ float r1, g1, b1, a1;
+ float r2, b2, g2, a2;
+} Flower;
+
+#define N_FLOWERS 200
+#define FLOWER_SIZE 128
+static Flower flowers[N_FLOWERS];
+
+static EGLDisplay
+_get_display (void)
+{
+ EGLint major, minor;
+ EGLDisplay display;
+ struct udev *udev;
+ struct udev_device *device;
+ struct stat st;
+
+ if (stat ("/dev/dri/card0", &st) < 0) {
+ fprintf(stderr, "no such device\n");
+ return NULL;
+ }
+
+ udev = udev_new ();
+ device = udev_device_new_from_devnum (udev, 'c', st.st_rdev);
+ if (device == NULL) {
+ fprintf (stderr, "failed to find device\n");
+ return NULL;
+ }
+ display = eglCreateDisplayNative (device);
+ udev_device_unref (device);
+ udev_unref (udev);
+
+ if (display == NULL) {
+ fprintf (stderr, "failed to open display\n");
+ return NULL;
+ }
+
+ if (! eglInitialize (display, &major, &minor)) {
+ fprintf (stderr, "failed to initialize display\n");
+ return NULL;
+ }
+
+ return display;
+}
+
+static cairo_surface_t *
+_get_fb (void)
+{
+ const EGLint config_attribs[] = {
+ EGL_DEPTH_SIZE, 24,
+ EGL_STENCIL_SIZE, 8,
+ EGL_CONFIG_CAVEAT, EGL_NONE,
+ EGL_NONE
+ };
+ const EGLint surface_attribs[] = {
+ EGL_RENDER_BUFFER, EGL_BACK_BUFFER,
+ EGL_NONE
+ };
+
+ EGLDisplay display;
+ EGLContext context;
+ EGLConfig config;
+ EGLSurface s;
+
+ cairo_gl_context_t *ctx;
+ cairo_surface_t *surface;
+
+ drmModeConnector *connector;
+ drmModeRes *resources;
+ drmModeEncoder *encoder;
+ drmModeModeInfo *mode;
+ struct drm_i915_gem_create create;
+ struct drm_gem_flink flink;
+ int i, ret, fd;
+ uint32_t fb_id;
+
+ display = _get_display ();
+ if (display == NULL) {
+ fprintf (stderr, "Unable to open display\n");
+ return NULL;
+ }
+
+ if (! eglChooseConfig (display, config_attribs, &config, 1, NULL)) {
+ fprintf (stderr, "Unable to choose config\n");
+ return NULL;
+ }
+
+ context = eglCreateContext (display, config, NULL, NULL);
+ if (context == NULL) {
+ fprintf (stderr, "failed to create context\n");
+ return NULL;
+ }
+
+ fd = eglGetDisplayFD (display);
+ resources = drmModeGetResources (fd);
+ if (resources == NULL) {
+ fprintf (stderr, "drmModeGetResources failed\n");
+ return NULL;
+ }
+
+ for (i = 0; i < resources->count_connectors; i++) {
+ connector = drmModeGetConnector (fd, resources->connectors[i]);
+ if (connector == NULL)
+ continue;
+
+ if (connector->connection == DRM_MODE_CONNECTED &&
+ connector->count_modes > 0)
+ break;
+
+ drmModeFreeConnector (connector);
+ }
+
+ if (i == resources->count_connectors) {
+ fprintf (stderr, "No currently active connector found.\n");
+ return NULL;
+ }
+
+ mode = &connector->modes[0];
+
+ for (i = 0; i < resources->count_encoders; i++) {
+ encoder = drmModeGetEncoder(fd, resources->encoders[i]);
+
+ if (encoder == NULL)
+ continue;
+
+ if (encoder->encoder_id == connector->encoder_id)
+ break;
+
+ drmModeFreeEncoder(encoder);
+ }
+
+ /* Mode size at 32 bpp */
+ create.size = mode->hdisplay * mode->vdisplay * 4;
+ if (ioctl (fd, DRM_IOCTL_I915_GEM_CREATE, &create) != 0) {
+ fprintf (stderr, "gem create failed: %m\n");
+ return NULL;
+ }
+
+ ret = drmModeAddFB (fd, mode->hdisplay, mode->vdisplay,
+ 32, 32, mode->hdisplay * 4, create.handle, &fb_id);
+ if (ret) {
+ fprintf (stderr, "failed to add fb: %m\n");
+ return NULL;
+ }
+
+ ret = drmModeSetCrtc (fd, encoder->crtc_id, fb_id, 0, 0,
+ &connector->connector_id, 1, mode);
+ if (ret) {
+ fprintf (stderr, "failed to set mode: %m\n");
+ return NULL;
+ }
+
+ flink.handle = create.handle;
+ if (ioctl (fd, DRM_IOCTL_GEM_FLINK, &flink) != 0) {
+ fprintf (stderr, "gem flink failed: %m\n");
+ return NULL;
+ }
+
+ s = eglCreateSurfaceForName (display, config,
+ flink.name,
+ mode->hdisplay, mode->vdisplay,
+ mode->hdisplay * 4,
+ surface_attribs);
+ if (s == NULL) {
+ fprintf (stderr, "failed to create surface\n");
+ return NULL;
+ }
+
+ ctx = cairo_egl_context_create (display, context);
+ surface = cairo_gl_surface_create_for_eagle (ctx, s,
+ mode->hdisplay,
+ mode->vdisplay);
+ cairo_gl_context_destroy (ctx);
+
+ if (cairo_surface_status (surface)) {
+ fprintf (stderr, "failed to create cairo surface\n");
+ return NULL;
+ }
+
+ return surface;
+}
+
+
+static unsigned int
+hars_petruska_f54_1_random (void)
+{
+#define rol(x,k) ((x << k) | (x >> (32-k)))
+ static unsigned int x;
+ return x = (x ^ rol (x, 5) ^ rol (x, 24)) + 0x37798849;
+#undef rol
+}
+
+static void
+random_colour (float *r, float *g, float *b, float *a)
+{
+ unsigned int x = hars_petruska_f54_1_random ();
+ *r = (x & 255) / 255.; x >>= 8;
+ *g = (x & 255) / 255.; x >>= 8;
+ *b = (x & 255) / 255.; x >>= 8;
+ *a = x / 255.;
+}
+
+static void
+randomize_flower (Flower *flower, int width, int height)
+{
+ flower->x = (hars_petruska_f54_1_random() & 8191) * width / 8191.;
+ flower->y = (hars_petruska_f54_1_random() & 8191) * height / 8191.;
+ flower->scale = 10 + (hars_petruska_f54_1_random() & 511) * 140 / 512.;
+ flower->rotation = (hars_petruska_f54_1_random() & 511) * M_PI / 256;
+
+ random_colour (&flower->r1,
+ &flower->g1,
+ &flower->b1,
+ &flower->a1);
+ random_colour (&flower->r2,
+ &flower->g2,
+ &flower->b2,
+ &flower->a2);
+}
+
+static void
+randomize_flowers (int width, int height)
+{
+ int i;
+
+ for (i = 0; i < N_FLOWERS; i++)
+ randomize_flower (&flowers [i], width, height);
+}
+
+static cairo_pattern_t *
+create_flower (cairo_surface_t *target, int size)
+{
+ cairo_surface_t *surface;
+ cairo_pattern_t *mask;
+ cairo_t *cr;
+
+ surface = cairo_surface_create_similar (target,
+ CAIRO_CONTENT_ALPHA, size, size);
+ cr = cairo_create (surface);
+ cairo_surface_destroy (surface);
+
+ cairo_scale (cr, size/2, size/2);
+ cairo_translate (cr, 1., 1.);
+ cairo_move_to (cr, 0, 0);
+ cairo_curve_to (cr, -0.9, 0, -0.9, -0.9, -0.9, -0.9);
+ cairo_curve_to (cr, 0.0, -0.9, 0, 0, 0, 0);
+ cairo_curve_to (cr, 0.9, 0.0, 0.9, -0.9, 0.9, -0.9);
+ cairo_curve_to (cr, 0.0, -0.9, 0.0, 0.0, 0.0, 0.0);
+ cairo_curve_to (cr, 0.9, 0.0, 0.9, 0.9, 0.9, 0.9);
+ cairo_curve_to (cr, 0.0, 0.9, 0.0, 0.0, 0.0, 0.0);
+ cairo_curve_to (cr, -0.9, 0.0, -0.9, 0.9, -0.9, 0.9);
+ cairo_curve_to (cr, 0.0, 0.9, 0.0, 0.0, 0.0, 0.0);
+ cairo_set_source_rgb (cr, 1, 1, 1);
+ cairo_fill (cr);
+
+ mask = cairo_pattern_create_for_surface (cairo_get_target (cr));
+ cairo_destroy (cr);
+
+ return mask;
+}
+
+static void
+paint (cairo_surface_t *surface,
+ cairo_pattern_t *mask,
+ int mask_size)
+{
+ cairo_t *cr;
+ int i;
+
+ cr = cairo_create (surface);
+ for (i = 0; i < N_FLOWERS; i++) {
+ cairo_pattern_t *pattern;
+ cairo_matrix_t matrix;
+
+ cairo_matrix_init_identity (&matrix);
+ cairo_matrix_translate (&matrix, flowers[i].x, flowers[i].y);
+ cairo_matrix_scale (&matrix,
+ flowers[i].scale/mask_size,
+ flowers[i].scale/mask_size);
+ cairo_matrix_rotate (&matrix, flowers[i].rotation);
+ cairo_set_matrix (cr, &matrix);
+
+ pattern = cairo_pattern_create_linear (0, -mask_size, 0, mask_size);
+ cairo_pattern_add_color_stop_rgba (pattern, 0,
+ flowers[i].r1, flowers[i].g1, flowers[i].b1, flowers[i].a1);
+ cairo_pattern_add_color_stop_rgba (pattern, 1,
+ flowers[i].r2, flowers[i].g2, flowers[i].b2, flowers[i].a2);
+ cairo_set_source (cr, pattern);
+ cairo_pattern_destroy (pattern);
+
+ cairo_mask (cr, mask);
+ }
+ cairo_destroy (cr);
+}
+
+int
+main (int argc, char *argv[])
+{
+ cairo_surface_t *surface;
+ cairo_pattern_t *flower;
+
+ surface = _get_fb ();
+ if (surface == NULL) {
+ fprintf (stderr, "Failed to create framebuffer\n");
+ return 1;
+ }
+
+ flower = create_flower (surface, FLOWER_SIZE);
+ while (1) {
+ randomize_flowers (cairo_gl_surface_get_width (surface),
+ cairo_gl_surface_get_height (surface));
+ paint (surface, flower, FLOWER_SIZE);
+ cairo_gl_surface_swapbuffers (surface);
+ }
+
+ cairo_pattern_destroy (flower);
+ cairo_surface_destroy (surface);
+
+ return 0;
+}
diff --git a/test/glx-flowers.c b/test/glx-flowers.c
new file mode 100644
index 00000000..855c204a
--- /dev/null
+++ b/test/glx-flowers.c
@@ -0,0 +1,256 @@
+/*
+ * Copyright © 2007 Michael Dominic K.
+ * Copyright © 2009 Chris Wilson
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any later
+ * version.
+ *
+ * This program 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 General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+#include <cairo-gl.h>
+
+#include <math.h>
+#include <stdio.h>
+#include <sys/time.h>
+
+typedef struct {
+ float x;
+ float y;
+ float scale;
+ float rotation;
+ float r1, g1, b1, a1;
+ float r2, b2, g2, a2;
+} Flower;
+
+#define N_FLOWERS 200
+#define FLOWER_SIZE 128
+static Flower flowers[N_FLOWERS];
+
+#define WIDTH 640
+#define HEIGHT 480
+
+static cairo_surface_t *
+_surface_create (void)
+{
+ int rgb_attribs[] = { GLX_RGBA,
+ GLX_RED_SIZE, 1,
+ GLX_GREEN_SIZE, 1,
+ GLX_BLUE_SIZE, 1,
+ GLX_DOUBLEBUFFER,
+ None };
+ XVisualInfo *vi;
+ GLXContext ctx;
+ Display *dpy;
+ Colormap cmap;
+ XSetWindowAttributes swa;
+ Window win;
+
+ cairo_gl_context_t *context;
+ cairo_surface_t *surface;
+
+ dpy = XOpenDisplay (NULL);
+ if (dpy == NULL) {
+ fprintf (stderr, "Failed to open display\n");
+ return NULL;
+ }
+
+ vi = glXChooseVisual (dpy, DefaultScreen (dpy), rgb_attribs);
+ if (vi == NULL) {
+ fprintf (stderr, "Failed to create RGB, double-buffered visual\n");
+ XCloseDisplay (dpy);
+ return NULL;
+ }
+
+ ctx = glXCreateContext (dpy, vi, NULL, True);
+
+ cmap = XCreateColormap (dpy,
+ RootWindow (dpy, vi->screen),
+ vi->visual,
+ AllocNone);
+ swa.colormap = cmap;
+ swa.border_pixel = 0;
+ win = XCreateWindow (dpy, RootWindow (dpy, vi->screen),
+ 0, 0,
+ 640, 480,
+ 0,
+ vi->depth,
+ InputOutput,
+ vi->visual,
+ CWBorderPixel | CWColormap, &swa);
+ XMapWindow (dpy, win);
+ XFlush (dpy);
+ XFree (vi);
+
+ context = cairo_glx_context_create (dpy, ctx);
+ surface = cairo_gl_surface_create_for_window (context, win, WIDTH, HEIGHT);
+ cairo_gl_context_destroy (context);
+
+ if (cairo_surface_status (surface)) {
+ fprintf (stderr, "failed to create cairo surface\n");
+ return NULL;
+ }
+
+ return surface;
+}
+
+static unsigned int
+hars_petruska_f54_1_random (void)
+{
+#define rol(x,k) ((x << k) | (x >> (32-k)))
+ static unsigned int x;
+ return x = (x ^ rol (x, 5) ^ rol (x, 24)) + 0x37798849;
+#undef rol
+}
+
+static void
+random_colour (float *r, float *g, float *b, float *a)
+{
+ unsigned int x = hars_petruska_f54_1_random ();
+ *r = (x & 255) / 255.; x >>= 8;
+ *g = (x & 255) / 255.; x >>= 8;
+ *b = (x & 255) / 255.; x >>= 8;
+ *a = x / 255.;
+}
+
+static void
+randomize_flower (Flower *flower, int width, int height)
+{
+ flower->x = (hars_petruska_f54_1_random() & 8191) * width / 8191.;
+ flower->y = (hars_petruska_f54_1_random() & 8191) * height / 8191.;
+ flower->scale = 10 + (hars_petruska_f54_1_random() & 511) * 140 / 512.;
+ flower->rotation = (hars_petruska_f54_1_random() & 511) * M_PI / 256;
+
+ random_colour (&flower->r1, &flower->g1, &flower->b1, &flower->a1);
+ random_colour (&flower->r2, &flower->g2, &flower->b2, &flower->a2);
+}
+
+static void
+randomize_flowers (int width, int height)
+{
+ int i;
+
+ for (i = 0; i < N_FLOWERS; i++)
+ randomize_flower (&flowers [i], width, height);
+}
+
+static cairo_pattern_t *
+create_flower (cairo_surface_t *target, int size)
+{
+ cairo_surface_t *surface;
+ cairo_pattern_t *mask;
+ cairo_t *cr;
+
+ surface = cairo_surface_create_similar (target,
+ CAIRO_CONTENT_ALPHA, size, size);
+ cr = cairo_create (surface);
+ cairo_surface_destroy (surface);
+
+ cairo_scale (cr, size/2, size/2);
+ cairo_translate (cr, 1., 1.);
+ cairo_move_to (cr, 0, 0);
+ cairo_curve_to (cr, -0.9, 0, -0.9, -0.9, -0.9, -0.9);
+ cairo_curve_to (cr, 0.0, -0.9, 0, 0, 0, 0);
+ cairo_curve_to (cr, 0.9, 0.0, 0.9, -0.9, 0.9, -0.9);
+ cairo_curve_to (cr, 0.0, -0.9, 0.0, 0.0, 0.0, 0.0);
+ cairo_curve_to (cr, 0.9, 0.0, 0.9, 0.9, 0.9, 0.9);
+ cairo_curve_to (cr, 0.0, 0.9, 0.0, 0.0, 0.0, 0.0);
+ cairo_curve_to (cr, -0.9, 0.0, -0.9, 0.9, -0.9, 0.9);
+ cairo_curve_to (cr, 0.0, 0.9, 0.0, 0.0, 0.0, 0.0);
+ cairo_set_source_rgb (cr, 1, 1, 1);
+ cairo_fill (cr);
+
+ mask = cairo_pattern_create_for_surface (cairo_get_target (cr));
+ cairo_destroy (cr);
+
+ return mask;
+}
+
+static void
+paint (cairo_surface_t *surface,
+ cairo_pattern_t *mask,
+ int mask_size)
+{
+ cairo_t *cr;
+ int i;
+
+ cr = cairo_create (surface);
+ for (i = 0; i < N_FLOWERS; i++) {
+ cairo_pattern_t *pattern;
+ cairo_matrix_t matrix;
+
+ cairo_matrix_init_identity (&matrix);
+ cairo_matrix_translate (&matrix, flowers[i].x, flowers[i].y);
+ cairo_matrix_scale (&matrix,
+ flowers[i].scale/mask_size,
+ flowers[i].scale/mask_size);
+ cairo_matrix_rotate (&matrix, flowers[i].rotation);
+ cairo_set_matrix (cr, &matrix);
+
+ pattern = cairo_pattern_create_linear (0, -mask_size, 0, mask_size);
+ cairo_pattern_add_color_stop_rgba (pattern, 0,
+ flowers[i].r1, flowers[i].g1, flowers[i].b1, flowers[i].a1);
+ cairo_pattern_add_color_stop_rgba (pattern, 1,
+ flowers[i].r2, flowers[i].g2, flowers[i].b2, flowers[i].a2);
+ cairo_set_source (cr, pattern);
+ cairo_pattern_destroy (pattern);
+
+ cairo_mask (cr, mask);
+ }
+ cairo_destroy (cr);
+}
+
+int
+main (int argc, char *argv[])
+{
+ cairo_surface_t *surface;
+ cairo_pattern_t *flower;
+ int frame, frame_target = 5;
+ struct timeval start, stop;
+
+ surface = _surface_create ();
+ if (surface == NULL) {
+ fprintf (stderr, "Failed to create framebuffer\n");
+ return 1;
+ }
+
+ flower = create_flower (surface, FLOWER_SIZE);
+ frame = 0;
+ gettimeofday (&start, NULL);
+ while (1) {
+ randomize_flowers (cairo_gl_surface_get_width (surface),
+ cairo_gl_surface_get_height (surface));
+ paint (surface, flower, FLOWER_SIZE);
+ cairo_gl_surface_swapbuffers (surface);
+
+ if (++frame == frame_target) {
+ int ticks;
+
+ gettimeofday (&stop, NULL);
+
+ ticks = (stop.tv_sec - start.tv_sec) * 1000000;
+ ticks += (stop.tv_usec - start.tv_usec);
+ printf ("%.2f fps\n", frame * 1000000. / ticks);
+
+ /* rate-limit output to once every 5 seconds */
+ frame_target = (frame_target + 5000000 * frame / ticks + 1) / 2;
+
+ frame = 0;
+ start = stop;
+ }
+ }
+
+ cairo_pattern_destroy (flower);
+ cairo_surface_destroy (surface);
+
+ return 0;
+}
diff --git a/util/cairo-script/.gitignore b/util/cairo-script/.gitignore
index 855d6402..0c31a3ae 100644
--- a/util/cairo-script/.gitignore
+++ b/util/cairo-script/.gitignore
@@ -1,2 +1,4 @@
csi-replay
csi-exec
+csi-egl
+csi-glx
diff --git a/util/cairo-script/Makefile.am b/util/cairo-script/Makefile.am
index db5e9531..4966e20e 100644
--- a/util/cairo-script/Makefile.am
+++ b/util/cairo-script/Makefile.am
@@ -22,10 +22,25 @@ libcairo_script_interpreter_la_LDFLAGS = -version-info $(CAIRO_LIBTOOL_VERSION_I
libcairo_script_interpreter_la_LIBADD = $(top_builddir)/src/libcairo.la $(CAIRO_LIBS)
csi_replay_SOURCES = csi-replay.c
+csi_replay_CFLAGS = $(CAIRO_CFLAGS)
csi_replay_LDADD = libcairo-script-interpreter.la $(top_builddir)/src/libcairo.la $(CAIRO_LIBS)
csi_exec_SOURCES = csi-exec.c
csi_exec_LDADD = libcairo-script-interpreter.la $(top_builddir)/src/libcairo.la $(CAIRO_LIBS)
+if CAIRO_HAS_GL_EGL_SURFACE
+noinst_PROGRAMS += csi-egl
+csi_egl_SOURCES = csi-egl.c
+csi_egl_CFLAGS = $(CAIRO_CFLAGS)
+csi_egl_LDADD = libcairo-script-interpreter.la $(top_builddir)/src/libcairo.la $(CAIRO_LIBS)
+endif
+
+if CAIRO_HAS_GL_GLX_SURFACE
+noinst_PROGRAMS += csi-glx
+csi_glx_SOURCES = csi-glx.c
+csi_glx_CFLAGS = $(CAIRO_CFLAGS)
+csi_glx_LDADD = libcairo-script-interpreter.la $(top_builddir)/src/libcairo.la $(CAIRO_LIBS)
+endif
+
EXTRA_DIST = \
COPYING
diff --git a/util/cairo-script/csi-egl.c b/util/cairo-script/csi-egl.c
new file mode 100644
index 00000000..41b45fbb
--- /dev/null
+++ b/util/cairo-script/csi-egl.c
@@ -0,0 +1,263 @@
+#include <cairo-gl.h>
+#include "cairo-script-interpreter.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <xf86drmMode.h>
+#include <i915_drm.h>
+
+#define LIBUDEV_I_KNOW_THE_API_IS_SUBJECT_TO_CHANGE
+#include <libudev.h>
+
+static void
+die (const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start (ap, fmt);
+ vfprintf (stderr, fmt, ap);
+ va_end (ap);
+
+ exit (EXIT_FAILURE);
+}
+
+static EGLDisplay
+_get_display (const char *card)
+{
+ EGLint major, minor;
+ EGLDisplay display;
+ struct udev *udev;
+ struct udev_device *device;
+ struct stat st;
+
+ if (stat (card, &st) < 0) {
+ die ("no such device\n");
+ return NULL;
+ }
+
+ udev = udev_new ();
+ device = udev_device_new_from_devnum (udev, 'c', st.st_rdev);
+ if (device == NULL) {
+ die ("failed to find device\n");
+ return NULL;
+ }
+ display = eglCreateDisplayNative (device);
+ udev_device_unref (device);
+ udev_unref (udev);
+
+ if (display == NULL) {
+ die ("failed to open display\n");
+ return NULL;
+ }
+
+ if (! eglInitialize (display, &major, &minor)) {
+ die ("failed to initialize display\n");
+ return NULL;
+ }
+
+ return display;
+}
+
+static cairo_surface_t *
+_get_fb (const char *card)
+{
+ const EGLint config_attribs[] = {
+ EGL_DEPTH_SIZE, 24,
+ EGL_STENCIL_SIZE, 8,
+ EGL_CONFIG_CAVEAT, EGL_NONE,
+ EGL_NONE
+ };
+ const EGLint surface_attribs[] = {
+ EGL_RENDER_BUFFER, EGL_BACK_BUFFER,
+ EGL_NONE
+ };
+
+ EGLDisplay display;
+ EGLContext context;
+ EGLConfig config;
+ EGLSurface s;
+
+ cairo_gl_context_t *ctx;
+ cairo_surface_t *surface;
+
+ drmModeConnector *connector;
+ drmModeRes *resources;
+ drmModeEncoder *encoder;
+ drmModeModeInfo *mode;
+ struct drm_i915_gem_create create;
+ struct drm_gem_flink flink;
+ int i, ret, fd;
+ uint32_t fb_id;
+
+ display = _get_display (card);
+ if (display == NULL) {
+ die ("Unable to open display\n");
+ return NULL;
+ }
+
+ if (! eglChooseConfig (display, config_attribs, &config, 1, NULL)) {
+ die ("Unable to choose config\n");
+ return NULL;
+ }
+
+ context = eglCreateContext (display, config, NULL, NULL);
+ if (context == NULL) {
+ die ("failed to create context\n");
+ return NULL;
+ }
+
+ fd = eglGetDisplayFD (display);
+ resources = drmModeGetResources (fd);
+ if (resources == NULL) {
+ die ("drmModeGetResources failed\n");
+ return NULL;
+ }
+
+ for (i = 0; i < resources->count_connectors; i++) {
+ connector = drmModeGetConnector (fd, resources->connectors[i]);
+ if (connector == NULL)
+ continue;
+
+ if (connector->connection == DRM_MODE_CONNECTED &&
+ connector->count_modes > 0)
+ break;
+
+ drmModeFreeConnector (connector);
+ }
+
+ if (i == resources->count_connectors) {
+ die ("No currently active connector found.\n");
+ return NULL;
+ }
+
+ mode = &connector->modes[0];
+
+ for (i = 0; i < resources->count_encoders; i++) {
+ encoder = drmModeGetEncoder(fd, resources->encoders[i]);
+
+ if (encoder == NULL)
+ continue;
+
+ if (encoder->encoder_id == connector->encoder_id)
+ break;
+
+ drmModeFreeEncoder(encoder);
+ }
+
+ /* Mode size at 32 bpp */
+ create.size = mode->hdisplay * mode->vdisplay * 4;
+ if (ioctl (fd, DRM_IOCTL_I915_GEM_CREATE, &create) != 0) {
+ die ("gem create failed: %m\n");
+ return NULL;
+ }
+
+ ret = drmModeAddFB (fd, mode->hdisplay, mode->vdisplay,
+ 32, 32, mode->hdisplay * 4, create.handle, &fb_id);
+ if (ret) {
+ die ("failed to add fb: %m\n");
+ return NULL;
+ }
+
+ ret = drmModeSetCrtc (fd, encoder->crtc_id, fb_id, 0, 0,
+ &connector->connector_id, 1, mode);
+ if (ret) {
+ die ("failed to set mode: %m\n");
+ return NULL;
+ }
+
+ flink.handle = create.handle;
+ if (ioctl (fd, DRM_IOCTL_GEM_FLINK, &flink) != 0) {
+ die ("gem flink failed: %m\n");
+ return NULL;
+ }
+
+ s = eglCreateSurfaceForName (display, config,
+ flink.name,
+ mode->hdisplay, mode->vdisplay,
+ mode->hdisplay * 4,
+ surface_attribs);
+ if (s == NULL) {
+ die ("failed to create surface\n");
+ return NULL;
+ }
+
+ ctx = cairo_egl_context_create (display, context);
+ surface = cairo_gl_surface_create_for_eagle (ctx, s,
+ mode->hdisplay,
+ mode->vdisplay);
+ cairo_gl_context_destroy (ctx);
+
+ return surface;
+}
+
+static cairo_surface_t *
+_egl_surface_create (void *closure,
+ cairo_content_t content,
+ double width, double height)
+{
+ return cairo_surface_create_similar (closure, content, width, height);
+}
+
+static struct list {
+ struct list *next;
+ cairo_t *context;
+ cairo_surface_t *surface;
+} *list;
+
+static cairo_t *
+_egl_context_create (void *closure, cairo_surface_t *surface)
+{
+ cairo_t *cr = cairo_create (surface);
+ struct list *l = malloc (sizeof (*l));
+ l->next = list;
+ l->context = cr;
+ l->surface = cairo_surface_reference (surface);
+ list = l;
+ return cr;
+}
+
+static void
+_egl_context_destroy (void *closure, void *ptr)
+{
+ struct list *l, **prev = &list;
+ while ((l = *prev) != NULL) {
+ if (l->context == ptr) {
+ if (cairo_surface_status (l->surface) == CAIRO_STATUS_SUCCESS) {
+ cairo_t *cr = cairo_create (closure);
+ cairo_set_source_surface (cr, l->surface, 0, 0);
+ cairo_paint (cr);
+ cairo_destroy (cr);
+ cairo_gl_surface_swapbuffers (closure);
+ }
+
+ cairo_surface_destroy (l->surface);
+ *prev = l->next;
+ free (l);
+ return;
+ }
+ prev = &l->next;
+ }
+}
+
+int
+main (int argc, char **argv)
+{
+ const cairo_script_interpreter_hooks_t hooks = {
+ .closure = _get_fb ("/dev/dri/card0"),
+ .surface_create = _egl_surface_create,
+ .context_create = _egl_context_create,
+ .context_destroy = _egl_context_destroy
+ };
+ cairo_script_interpreter_t *csi;
+ int i;
+
+ csi = cairo_script_interpreter_create ();
+ cairo_script_interpreter_install_hooks (csi, &hooks);
+ for (i = 1; i < argc; i++)
+ cairo_script_interpreter_run (csi, argv[i]);
+ return cairo_script_interpreter_destroy (csi);
+}
diff --git a/util/cairo-script/csi-glx.c b/util/cairo-script/csi-glx.c
new file mode 100644
index 00000000..e55542a1
--- /dev/null
+++ b/util/cairo-script/csi-glx.c
@@ -0,0 +1,150 @@
+#include <cairo-gl.h>
+#include "cairo-script-interpreter.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+static void
+die (const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start (ap, fmt);
+ vfprintf (stderr, fmt, ap);
+ va_end (ap);
+
+ exit (EXIT_FAILURE);
+}
+
+static cairo_surface_t *
+_get_fb (void)
+{
+ int rgb_attribs[] = { GLX_RGBA,
+ GLX_RED_SIZE, 1,
+ GLX_GREEN_SIZE, 1,
+ GLX_BLUE_SIZE, 1,
+ GLX_DOUBLEBUFFER,
+ None };
+ XVisualInfo *vi;
+ GLXContext ctx;
+ Display *dpy;
+ Screen *screen;
+ Colormap cmap;
+ XSetWindowAttributes swa;
+ Window win;
+
+ cairo_gl_context_t *context;
+ cairo_surface_t *surface;
+
+ dpy = XOpenDisplay (NULL);
+ if (dpy == NULL)
+ die ("Failed to open display\n");
+
+ vi = glXChooseVisual (dpy, DefaultScreen (dpy), rgb_attribs);
+ if (vi == NULL)
+ die ("Failed to create RGB, double-buffered visual\n");
+
+ ctx = glXCreateContext (dpy, vi, NULL, True);
+
+ screen = ScreenOfDisplay (dpy, vi->screen);
+
+ cmap = XCreateColormap (dpy,
+ RootWindowOfScreen (screen),
+ vi->visual,
+ AllocNone);
+ swa.colormap = cmap;
+ swa.border_pixel = 0;
+ swa.override_redirect = True;
+ win = XCreateWindow (dpy, RootWindowOfScreen (screen),
+ 0, 0,
+ WidthOfScreen (screen), HeightOfScreen (screen),
+ 0,
+ vi->depth,
+ InputOutput,
+ vi->visual,
+ CWBorderPixel | CWColormap | CWOverrideRedirect,
+ &swa);
+ XMapWindow (dpy, win);
+ XFlush (dpy);
+ XFree (vi);
+
+ context = cairo_glx_context_create (dpy, ctx);
+ surface = cairo_gl_surface_create_for_window (context, win,
+ WidthOfScreen (screen),
+ HeightOfScreen (screen));
+ cairo_gl_context_destroy (context);
+
+ if (cairo_surface_status (surface))
+ die ("failed to create cairo surface\n");
+
+ return surface;
+}
+
+static cairo_surface_t *
+_glx_surface_create (void *closure,
+ cairo_content_t content,
+ double width, double height)
+{
+ return cairo_surface_create_similar (closure, content, width, height);
+}
+
+static struct list {
+ struct list *next;
+ cairo_t *context;
+ cairo_surface_t *surface;
+} *list;
+
+static cairo_t *
+_glx_context_create (void *closure, cairo_surface_t *surface)
+{
+ cairo_t *cr = cairo_create (surface);
+ struct list *l = malloc (sizeof (*l));
+ l->next = list;
+ l->context = cr;
+ l->surface = cairo_surface_reference (surface);
+ list = l;
+ return cr;
+}
+
+static void
+_glx_context_destroy (void *closure, void *ptr)
+{
+ struct list *l, **prev = &list;
+ while ((l = *prev) != NULL) {
+ if (l->context == ptr) {
+ if (cairo_surface_status (l->surface) == CAIRO_STATUS_SUCCESS) {
+ cairo_t *cr = cairo_create (closure);
+ cairo_set_source_surface (cr, l->surface, 0, 0);
+ cairo_paint (cr);
+ cairo_destroy (cr);
+ cairo_gl_surface_swapbuffers (closure);
+ }
+
+ cairo_surface_destroy (l->surface);
+ *prev = l->next;
+ free (l);
+ return;
+ }
+ prev = &l->next;
+ }
+}
+
+int
+main (int argc, char **argv)
+{
+ const cairo_script_interpreter_hooks_t hooks = {
+ .closure = _get_fb (),
+ .surface_create = _glx_surface_create,
+ .context_create = _glx_context_create,
+ .context_destroy = _glx_context_destroy
+ };
+ cairo_script_interpreter_t *csi;
+ int i;
+
+ csi = cairo_script_interpreter_create ();
+ cairo_script_interpreter_install_hooks (csi, &hooks);
+ for (i = 1; i < argc; i++)
+ cairo_script_interpreter_run (csi, argv[i]);
+ return cairo_script_interpreter_destroy (csi);
+}
diff --git a/util/cairo-script/csi-replay.c b/util/cairo-script/csi-replay.c
index cfae74c9..8a1f3cd9 100644
--- a/util/cairo-script/csi-replay.c
+++ b/util/cairo-script/csi-replay.c
@@ -3,6 +3,7 @@
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
static const cairo_user_data_key_t _key;
@@ -107,6 +108,63 @@ _xrender_surface_create (void *closure,
}
#endif
+#if CAIRO_HAS_GL_GLX_SURFACE
+#include <cairo-gl.h>
+static cairo_gl_context_t *
+_glx_get_context (cairo_content_t content)
+{
+ static cairo_gl_context_t *context;
+
+ if (context == NULL) {
+ int rgba_attribs[] = {
+ GLX_RGBA,
+ GLX_RED_SIZE, 1,
+ GLX_GREEN_SIZE, 1,
+ GLX_BLUE_SIZE, 1,
+ GLX_ALPHA_SIZE, 1,
+ GLX_DOUBLEBUFFER,
+ None
+ };
+ XVisualInfo *visinfo;
+ GLXContext gl_ctx;
+ Display *dpy;
+
+ dpy = XOpenDisplay (NULL);
+ if (dpy == NULL) {
+ fprintf (stderr, "Failed to open display.\n");
+ exit (1);
+ }
+
+ visinfo = glXChooseVisual (dpy, DefaultScreen (dpy), rgba_attribs);
+ if (visinfo == NULL) {
+ fprintf (stderr, "Failed to create RGBA, double-buffered visual\n");
+ exit (1);
+ }
+
+ gl_ctx = glXCreateContext (dpy, visinfo, NULL, True);
+ XFree (visinfo);
+
+ context = cairo_glx_context_create (dpy, gl_ctx);
+ }
+
+ return context;
+}
+
+static cairo_surface_t *
+_glx_surface_create (void *closure,
+ cairo_content_t content,
+ double width, double height)
+{
+ if (width == 0)
+ width = 1;
+ if (height == 0)
+ height = 1;
+
+ return cairo_gl_surface_create (_glx_get_context (content),
+ content, width, height);
+}
+#endif
+
#if CAIRO_HAS_PDF_SURFACE
#include <cairo-pdf.h>
static cairo_surface_t *
@@ -174,6 +232,9 @@ main (int argc, char **argv)
#if CAIRO_HAS_XLIB_XRENDER_SURFACE
{ "--xrender", _xrender_surface_create },
#endif
+#if CAIRO_HAS_GL_GLX_SURFACE
+ { "--glx", _glx_surface_create },
+#endif
#if CAIRO_HAS_PDF_SURFACE
{ "--pdf", _pdf_surface_create },
#endif