diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2009-05-19 15:53:55 +0100 |
---|---|---|
committer | Chris Wilson <chris@chris-wilson.co.uk> | 2009-05-20 08:13:45 +0100 |
commit | 87b764908a38cbb4159ac76d8b7d1d08a24b838e (patch) | |
tree | 90150c81390f7e8386474b43f28fbb8a939f3725 | |
parent | 17b41fe7e3b8b493341be6384d816105aadf0cb6 (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.features | 20 | ||||
-rw-r--r-- | boilerplate/cairo-boilerplate-gl.c | 2 | ||||
-rw-r--r-- | build/Makefile.win32.features | 2 | ||||
-rw-r--r-- | build/Makefile.win32.features-h | 6 | ||||
-rw-r--r-- | build/configure.ac.features | 3 | ||||
-rw-r--r-- | configure.ac | 30 | ||||
-rw-r--r-- | src/Makefile.sources | 4 | ||||
-rw-r--r-- | src/Makefile.win32.features | 28 | ||||
-rw-r--r-- | src/cairo-egl-context.c | 181 | ||||
-rw-r--r-- | src/cairo-gl-private.h | 88 | ||||
-rw-r--r-- | src/cairo-gl-surface.c | 191 | ||||
-rw-r--r-- | src/cairo-gl.h | 41 | ||||
-rw-r--r-- | src/cairo-glx-context.c | 136 | ||||
-rw-r--r-- | test/.gitignore | 2 | ||||
-rw-r--r-- | test/Makefile.am | 10 | ||||
-rw-r--r-- | test/egl-flowers.c | 358 | ||||
-rw-r--r-- | test/glx-flowers.c | 256 | ||||
-rw-r--r-- | util/cairo-script/.gitignore | 2 | ||||
-rw-r--r-- | util/cairo-script/Makefile.am | 15 | ||||
-rw-r--r-- | util/cairo-script/csi-egl.c | 263 | ||||
-rw-r--r-- | util/cairo-script/csi-glx.c | 150 | ||||
-rw-r--r-- | util/cairo-script/csi-replay.c | 61 |
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 |