Merge branch 'gl' into gl-span-renderer

Conflicts:
	src/cairo-gl-surface.c
This commit is contained in:
Eric Anholt 2009-06-01 10:45:36 -07:00
commit 7ee0fee900
22 changed files with 1732 additions and 134 deletions

View file

@ -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)

View file

@ -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);

View file

@ -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

View file

@ -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

View file

@ -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)"

View file

@ -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

View file

@ -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

View file

@ -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)

181
src/cairo-egl-context.c Normal file
View file

@ -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;
}

88
src/cairo-gl-private.h Normal file
View file

@ -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 */

View file

@ -35,17 +35,13 @@
* 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"
slim_hidden_proto (cairo_gl_context_reference);
slim_hidden_proto (cairo_gl_context_destroy);
slim_hidden_proto (cairo_gl_surface_create);
#define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))
@ -61,29 +57,6 @@ int_as_float(uint32_t val)
return fi.f;
}
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,
@ -116,7 +89,7 @@ typedef struct _cairo_gl_composite_setup {
static const cairo_surface_backend_t _cairo_gl_surface_backend;
const cairo_gl_context_t _nil_context = {
static const cairo_gl_context_t _nil_context = {
CAIRO_REFERENCE_COUNT_INVALID,
CAIRO_STATUS_NO_MEMORY
};
@ -126,7 +99,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)
@ -136,37 +109,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. */
@ -175,7 +142,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 *
@ -192,6 +159,7 @@ cairo_gl_context_reference (cairo_gl_context_t *context)
return context;
}
slim_hidden_def (cairo_gl_context_reference);
void
cairo_gl_context_destroy (cairo_gl_context_t *context)
@ -208,8 +176,11 @@ cairo_gl_context_destroy (cairo_gl_context_t *context)
glDeleteTextures (1, &context->dummy_tex);
context->destroy (context);
free (context);
}
slim_hidden_def (cairo_gl_context_destroy);
static cairo_gl_context_t *
_cairo_gl_context_acquire (cairo_gl_context_t *ctx)
@ -237,8 +208,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);
@ -292,7 +262,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)
@ -347,6 +317,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,
@ -371,12 +356,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:
@ -419,9 +399,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);
@ -431,33 +408,7 @@ 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;
}
slim_hidden_def (cairo_gl_surface_create);
void
cairo_gl_surface_set_size (cairo_surface_t *abstract_surface,
@ -477,19 +428,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 *
@ -540,8 +515,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;
@ -559,7 +534,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++) {
@ -609,23 +584,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;
}
@ -646,7 +621,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,
@ -765,7 +740,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;
@ -1024,7 +1000,7 @@ _cairo_gl_pattern_image_texture_setup (cairo_gl_composite_operand_t *operand,
}
/**
* Like cairo_pattern_acquire_surface, but returns a matrix that transforms
* Like cairo_pattern_acquire_surface(), but returns a matrix that transforms
* from dest to src coords.
*/
static cairo_status_t
@ -1472,7 +1448,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

View file

@ -34,8 +34,6 @@
#ifndef CAIRO_GL_H
#define CAIRO_GL_H
#include <GL/glx.h>
#include "cairo.h"
#if CAIRO_HAS_GL_SURFACE
@ -44,15 +42,9 @@ 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
cairo_gl_context_status (cairo_gl_context_t *context);
cairo_public void
cairo_gl_context_destroy (cairo_gl_context_t *context);
@ -61,23 +53,45 @@ 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 +99,3 @@ CAIRO_END_DECLS
#endif /* CAIRO_HAS_GL_SURFACE */
#endif /* CAIRO_GL_H */

136
src/cairo-glx-context.c Normal file
View file

@ -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;
}

2
test/.gitignore vendored
View file

@ -13,6 +13,8 @@ any2ppm
.any2ppm.errors
cairo-test-constructors.c
cairo-test-suite
egl-flowers
glx-flowers
pdf2png
ps2png
svg2png

View file

@ -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

358
test/egl-flowers.c Normal file
View file

@ -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;
}

256
test/glx-flowers.c Normal file
View file

@ -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;
}

View file

@ -1,2 +1,4 @@
csi-replay
csi-exec
csi-egl
csi-glx

View file

@ -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

263
util/cairo-script/csi-egl.c Normal file
View file

@ -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);
}

150
util/cairo-script/csi-glx.c Normal file
View file

@ -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);
}

View file

@ -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