Commit f617d5fc authored by Chris Wilson's avatar Chris Wilson 🤔
Browse files

Add cairo_device_t

The device is a generic method for accessing the underlying interface
with the native graphics subsystem, typically the X connection or
perhaps the GL context. By exposing a cairo_device_t on a surface and
its various methods we enable finer control over interoperability with
external interactions of the device by applications. The use case in
mind is, for example, a multi-threaded gstreamer which needs to serialise
its own direct access to the device along with Cairo's across many
threads.

Secondly, the cairo_device_t is a unifying API for the mismash of
backend specific methods for controlling creation of surfaces with
explicit devices and a convenient hook for debugging and introspection.

The principal components of the API are the memory management of:

  cairo_device_reference(),
  cairo_device_finish() and
  cairo_device_destroy();

along with a pair of routines for serialising interaction:

  cairo_device_acquire() and
  cairo_device_release()

and a method to flush any outstanding accesses:

  cairo_device_flush().

The device for a particular surface may be retrieved using:

  cairo_surface_get_device().

The device returned is owned by the surface.
parent 82f8aa54
......@@ -59,6 +59,7 @@ cairo_private = \
cairo-clip-private.h \
cairo-combsort-private.h \
cairo-compiler-private.h \
cairo-device-private.h \
cairo-error-private.h \
cairo-fixed-private.h \
cairo-fixed-type-private.h \
......@@ -114,6 +115,7 @@ cairo_sources = \
cairo-clip.c \
cairo-color.c \
cairo-debug.c \
cairo-device.c \
cairo-fixed.c \
cairo-font-face.c \
cairo-font-face-twin.c \
......
......@@ -717,7 +717,9 @@ _cairo_analysis_surface_create (cairo_surface_t *target)
/* I believe the content type here is truly arbitrary. I'm quite
* sure nothing will ever use this value. */
_cairo_surface_init (&surface->base, &cairo_analysis_surface_backend,
_cairo_surface_init (&surface->base,
&cairo_analysis_surface_backend,
NULL, /* device */
CAIRO_CONTENT_COLOR_ALPHA);
cairo_matrix_init_identity (&surface->ctm);
......@@ -907,7 +909,10 @@ _cairo_null_surface_create (cairo_content_t content)
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
}
_cairo_surface_init (surface, &cairo_null_surface_backend, content);
_cairo_surface_init (surface,
&cairo_null_surface_backend,
NULL, /* device */
content);
return surface;
}
......@@ -915,7 +915,10 @@ _cairo_beos_surface_create_internal (BView* view,
cairo_content_t content = CAIRO_CONTENT_COLOR;
if (bmp && (bmp->ColorSpace() == B_RGBA32 || bmp->ColorSpace() == B_RGBA15))
content = CAIRO_CONTENT_COLOR_ALPHA;
_cairo_surface_init(&surface->base, &cairo_beos_surface_backend, content);
_cairo_surface_init (&surface->base,
&cairo_beos_surface_backend,
NULL, /* device */
content);
surface->view = view;
surface->bitmap = bmp;
......
/* Cairo - a vector graphics library with display and print output
*
* Copyright © 2009 Intel Corporation
*
* 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 Intel Corporation.
*
* Contributors(s):
* Chris Wilson <chris@chris-wilson.co.uk>
*/
#ifndef _CAIRO_DEVICE_PRIVATE_H_
#define _CAIRO_DEVICE_PRIVATE_H_
#include "cairo-compiler-private.h"
#include "cairo-mutex-private.h"
#include "cairo-reference-count-private.h"
#include "cairo-types-private.h"
struct _cairo_device {
cairo_reference_count_t ref_count;
cairo_status_t status;
const cairo_device_backend_t *backend;
cairo_recursive_mutex_t mutex;
unsigned mutex_depth;
cairo_bool_t finished;
};
struct _cairo_device_backend {
cairo_device_type_t type;
void (*lock) (void *device);
void (*unlock) (void *device);
void (*flush) (void *device);
void (*finish) (void *device);
void (*destroy) (void *device);
};
cairo_private cairo_device_t *
_cairo_device_create_in_error (cairo_status_t status);
cairo_private void
_cairo_device_init (cairo_device_t *device,
const cairo_device_backend_t *backend);
cairo_private cairo_status_t
_cairo_device_set_error (cairo_device_t *device,
cairo_status_t error);
slim_hidden_proto_no_warn (cairo_device_reference);
slim_hidden_proto (cairo_device_acquire);
slim_hidden_proto (cairo_device_release);
slim_hidden_proto (cairo_device_flush);
slim_hidden_proto (cairo_device_finish);
slim_hidden_proto (cairo_device_destroy);
#endif /* _CAIRO_DEVICE_PRIVATE_H_ */
/* Cairo - a vector graphics library with display and print output
*
* Copyright © 2009 Intel Corporation
*
* 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 Intel Corporation.
*
* Contributors(s):
* Chris Wilson <chris@chris-wilson.co.uk>
*/
#include "cairoint.h"
#include "cairo-device-private.h"
#include "cairo-error-private.h"
static const cairo_device_t _nil_device = {
CAIRO_REFERENCE_COUNT_INVALID,
CAIRO_STATUS_NO_MEMORY,
};
static const cairo_device_t _mismatch_device = {
CAIRO_REFERENCE_COUNT_INVALID,
CAIRO_STATUS_DEVICE_TYPE_MISMATCH,
};
static const cairo_device_t _invalid_device = {
CAIRO_REFERENCE_COUNT_INVALID,
CAIRO_STATUS_DEVICE_ERROR,
};
cairo_device_t *
_cairo_device_create_in_error (cairo_status_t status)
{
switch (status) {
case CAIRO_STATUS_NO_MEMORY:
return (cairo_device_t *) &_nil_device;
case CAIRO_STATUS_DEVICE_ERROR:
return (cairo_device_t *) &_invalid_device;
case CAIRO_STATUS_DEVICE_TYPE_MISMATCH:
return (cairo_device_t *) &_mismatch_device;
case CAIRO_STATUS_SUCCESS:
case CAIRO_STATUS_LAST_STATUS:
ASSERT_NOT_REACHED;
/* fall-through */
case CAIRO_STATUS_SURFACE_TYPE_MISMATCH:
case CAIRO_STATUS_INVALID_STATUS:
case CAIRO_STATUS_INVALID_FORMAT:
case CAIRO_STATUS_INVALID_VISUAL:
case CAIRO_STATUS_READ_ERROR:
case CAIRO_STATUS_WRITE_ERROR:
case CAIRO_STATUS_FILE_NOT_FOUND:
case CAIRO_STATUS_TEMP_FILE_ERROR:
case CAIRO_STATUS_INVALID_STRIDE:
case CAIRO_STATUS_INVALID_SIZE:
case CAIRO_STATUS_INVALID_RESTORE:
case CAIRO_STATUS_INVALID_POP_GROUP:
case CAIRO_STATUS_NO_CURRENT_POINT:
case CAIRO_STATUS_INVALID_MATRIX:
case CAIRO_STATUS_NULL_POINTER:
case CAIRO_STATUS_INVALID_STRING:
case CAIRO_STATUS_INVALID_PATH_DATA:
case CAIRO_STATUS_SURFACE_FINISHED:
case CAIRO_STATUS_PATTERN_TYPE_MISMATCH:
case CAIRO_STATUS_INVALID_DASH:
case CAIRO_STATUS_INVALID_DSC_COMMENT:
case CAIRO_STATUS_INVALID_INDEX:
case CAIRO_STATUS_CLIP_NOT_REPRESENTABLE:
case CAIRO_STATUS_FONT_TYPE_MISMATCH:
case CAIRO_STATUS_USER_FONT_IMMUTABLE:
case CAIRO_STATUS_USER_FONT_ERROR:
case CAIRO_STATUS_NEGATIVE_COUNT:
case CAIRO_STATUS_INVALID_CLUSTERS:
case CAIRO_STATUS_INVALID_SLANT:
case CAIRO_STATUS_INVALID_WEIGHT:
case CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED:
case CAIRO_STATUS_INVALID_CONTENT:
default:
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_device_t *) &_nil_device;
}
}
void
_cairo_device_init (cairo_device_t *device,
const cairo_device_backend_t *backend)
{
CAIRO_REFERENCE_COUNT_INIT (&device->ref_count, 1);
device->status = CAIRO_STATUS_SUCCESS;
device->backend = backend;
CAIRO_RECURSIVE_MUTEX_INIT (device->mutex);
device->mutex_depth = 0;
device->finished = FALSE;
}
cairo_device_t *
cairo_device_reference (cairo_device_t *device)
{
if (device == NULL ||
CAIRO_REFERENCE_COUNT_IS_INVALID (&device->ref_count))
{
return device;
}
assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&device->ref_count));
_cairo_reference_count_inc (&device->ref_count);
return device;
}
slim_hidden_def (cairo_device_reference);
cairo_status_t
cairo_device_status (cairo_device_t *device)
{
if (device == NULL)
return CAIRO_STATUS_NULL_POINTER;
return device->status;
}
void
cairo_device_flush (cairo_device_t *device)
{
if (device == NULL || device->status)
return;
if (device->backend->flush != NULL)
device->backend->flush (device);
}
slim_hidden_def (cairo_device_flush);
void
cairo_device_finish (cairo_device_t *device)
{
if (device == NULL ||
CAIRO_REFERENCE_COUNT_IS_INVALID (&device->ref_count))
{
return;
}
if (device->finished)
return;
device->finished = TRUE;
cairo_device_flush (device);
if (device->backend->finish != NULL)
device->backend->finish (device);
}
slim_hidden_def (cairo_device_finish);
void
cairo_device_destroy (cairo_device_t *device)
{
if (device == NULL ||
CAIRO_REFERENCE_COUNT_IS_INVALID (&device->ref_count))
{
return;
}
assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&device->ref_count));
if (! _cairo_reference_count_dec_and_test (&device->ref_count))
return;
cairo_device_finish (device);
assert (device->mutex_depth == 0);
CAIRO_MUTEX_FINI (device->mutex);
device->backend->destroy (device);
}
slim_hidden_def (cairo_device_destroy);
cairo_device_type_t
cairo_device_get_type (cairo_device_t *device)
{
if (device == NULL ||
CAIRO_REFERENCE_COUNT_IS_INVALID (&device->ref_count))
{
return (cairo_device_type_t) -1;
}
return device->backend->type;
}
cairo_status_t
cairo_device_acquire (cairo_device_t *device)
{
if (device == NULL)
return CAIRO_STATUS_SUCCESS;
if (unlikely (device->status))
return device->status;
if (unlikely (device->finished))
return _cairo_device_set_error (device, CAIRO_STATUS_SURFACE_FINISHED); /* XXX */
CAIRO_MUTEX_LOCK (device->mutex);
if (device->mutex_depth++ == 0) {
if (device->backend->lock != NULL)
device->backend->lock (device);
}
return CAIRO_STATUS_SUCCESS;
}
slim_hidden_def (cairo_device_acquire);
void
cairo_device_release (cairo_device_t *device)
{
if (device == NULL)
return;
assert (device->mutex_depth > 0);
if (--device->mutex_depth == 0) {
if (device->backend->unlock != NULL)
device->backend->unlock (device);
}
CAIRO_MUTEX_UNLOCK (device->mutex);
}
slim_hidden_def (cairo_device_release);
cairo_status_t
_cairo_device_set_error (cairo_device_t *device,
cairo_status_t status)
{
if (status == CAIRO_STATUS_SUCCESS || status >= CAIRO_INT_STATUS_UNSUPPORTED)
return status;
/* Don't overwrite an existing error. This preserves the first
* error, which is the most significant. */
_cairo_status_set_error (&device->status, status);
return _cairo_error (status);
}
......@@ -565,6 +565,7 @@ _cairo_directfb_surface_create_internal (IDirectFB *dfb,
_cairo_surface_init (&surface->base,
&_cairo_directfb_surface_backend,
NULL, /* device */
content);
surface->pixman_format = _directfb_to_pixman_format (format);
surface->supported_destination = pixman_format_supported_destination (surface->pixman_format);
......@@ -1956,6 +1957,7 @@ cairo_directfb_surface_create (IDirectFB *dfb, IDirectFBSurface *dfbsurface)
_cairo_surface_init (&surface->base,
&_cairo_directfb_surface_backend,
NULL, /* device */
_directfb_format_to_content (format));
return &surface->base;
......
......@@ -462,6 +462,7 @@ _cairo_gl_surface_init (cairo_gl_context_t *ctx,
{
_cairo_surface_init (&surface->base,
&_cairo_gl_surface_backend,
NULL, /* device */
content);
surface->ctx = cairo_gl_context_reference (ctx);
......
......@@ -2430,7 +2430,9 @@ cairo_glitz_surface_create (glitz_surface_t *surface)
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
format = glitz_surface_get_format (surface);
_cairo_surface_init (&crsurface->base, &cairo_glitz_surface_backend,
_cairo_surface_init (&crsurface->base,
&cairo_glitz_surface_backend,
NULL, /* device */
_glitz_format_to_content (format));
glitz_surface_reference (surface);
......
......@@ -176,7 +176,9 @@ _cairo_image_surface_create_for_pixman_image (pixman_image_t *pixman_image,
if (unlikely (surface == NULL))
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
_cairo_surface_init (&surface->base, &_cairo_image_surface_backend,
_cairo_surface_init (&surface->base,
&_cairo_image_surface_backend,
NULL, /* device */
_cairo_content_from_pixman_format (pixman_format));
surface->pixman_image = pixman_image;
......
......@@ -126,6 +126,10 @@ cairo_status_to_string (cairo_status_t status)
return "invalid value (typically too big) for the size of the input (surface, pattern, etc.)";
case CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED:
return "user-font method not implemented";
case CAIRO_STATUS_DEVICE_TYPE_MISMATCH:
return "the device type is not appropriate for the operation";
case CAIRO_STATUS_DEVICE_ERROR:
return "an operation to the device caused an unspecified error";
default:
case CAIRO_STATUS_LAST_STATUS:
return "<unknown error status>";
......
......@@ -845,6 +845,7 @@ cairo_os2_surface_create (HPS hps_client_window,
/* Initialize base surface */
_cairo_surface_init (&local_os2_surface->base,
&cairo_os2_surface_backend,
NULL, /* device */
_cairo_content_from_format (CAIRO_FORMAT_ARGB32));
return (cairo_surface_t *)local_os2_surface;
......
......@@ -102,7 +102,9 @@ _cairo_paginated_surface_create (cairo_surface_t *target,
goto FAIL;
}
_cairo_surface_init (&surface->base, &cairo_paginated_surface_backend,
_cairo_surface_init (&surface->base,
&cairo_paginated_surface_backend,
NULL, /* device */
content);
/* Override surface->base.type with target's type so we don't leak
......
......@@ -304,7 +304,9 @@ _cairo_pdf_surface_create_for_stream_internal (cairo_output_stream_t *output,
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
}
_cairo_surface_init (&surface->base, &cairo_pdf_surface_backend,
_cairo_surface_init (&surface->base,
&cairo_pdf_surface_backend,
NULL, /* device */
CAIRO_CONTENT_COLOR_ALPHA);
surface->output = output;
......
......@@ -910,7 +910,9 @@ _cairo_ps_surface_create_for_stream_internal (cairo_output_stream_t *stream,
goto CLEANUP;
}
_cairo_surface_init (&surface->base, &cairo_ps_surface_backend,
_cairo_surface_init (&surface->base,
&cairo_ps_surface_backend,
NULL, /* device */
CAIRO_CONTENT_COLOR_ALPHA);
surface->final_stream = stream;
......
......@@ -1697,6 +1697,7 @@ cairo_qt_surface_create (QPainter *painter)
_cairo_surface_init (&qs->base,
&cairo_qt_surface_backend,
NULL, /* device */
CAIRO_CONTENT_COLOR_ALPHA);
_cairo_surface_clipper_init (&qs->clipper,
......@@ -1739,6 +1740,7 @@ cairo_qt_surface_create_with_qimage (cairo_format_t format,
_cairo_surface_init (&qs->base,
&cairo_qt_surface_backend,
NULL, /* device */
_cairo_content_from_format (format));
_cairo_surface_clipper_init (&qs->clipper,
......@@ -1797,7 +1799,10 @@ cairo_qt_surface_create_with_qpixmap (cairo_content_t content,
if (content == CAIRO_CONTENT_COLOR_ALPHA)
pixmap->fill(Qt::transparent);
_cairo_surface_init (&qs->base, &cairo_qt_surface_backend, content);
_cairo_surface_init (&qs->base,
&cairo_qt_surface_backend,
NULL, /* device */
content);
_cairo_surface_clipper_init (&qs->clipper,
_cairo_qt_surface_clipper_intersect_clip_path);
......
......@@ -260,6 +260,7 @@ cairo_quartz_image_surface_create (cairo_surface_t *surface)
_cairo_surface_init (&qisurf->base,
&cairo_quartz_image_surface_backend,
NULL, /* device */
_cairo_content_from_format (format));
qisurf->extents.x = qisurf->extents.y = 0;
......
......@@ -2611,8 +2611,10 @@ _cairo_quartz_surface_create_internal (CGContextRef cgContext,
memset(surface, 0, sizeof(cairo_quartz_surface_t));
_cairo_surface_init(&surface->base, &cairo_quartz_surface_backend,
content);
_cairo_surface_init (&surface->base,
&cairo_quartz_surface_backend,
NULL, /* device */
content);
_cairo_surface_clipper_init (&surface->clipper,
_cairo_quartz_surface_clipper_intersect_clip_path);
......
......@@ -123,7 +123,10 @@ cairo_recording_surface_create (cairo_content_t content,
if (unlikely (recording_surface == NULL))
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
_cairo_surface_init (&recording_surface->base, &cairo_recording_surface_backend, content);
_cairo_surface_init (&recording_surface->base,
&cairo_recording_surface_backend,
NULL, /* device */
content);
recording_surface->content = content;
......@@ -616,7 +619,9 @@ _cairo_recording_surface_snapshot (void *abstract_other)
if (unlikely (recording_surface == NULL))
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
_cairo_surface_init (&recording_surface->base, &cairo_recording_surface_backend,
_cairo_surface_init (&recording_surface->base,
&cairo_recording_surface_backend,
NULL, /* device */
other->base.content);
recording_surface->extents_pixels = other->extents_pixels;
......
......@@ -3257,6 +3257,7 @@ _cairo_script_surface_create_internal (cairo_script_context_t *ctx,
_cairo_surface_init (&surface->base,
&_cairo_script_surface_backend,
NULL, /* device */
content);
_cairo_surface_wrapper_init (&surface->wrapper, passthrough);
......
......@@ -1027,6 +1027,7 @@ _cairo_skia_surface_create_internal (SkBitmap::Config config,
_cairo_surface_init (&surface->base,
&cairo_skia_surface_backend,
NULL, /* device */
_cairo_content_from_format (format));
_cairo_surface_clipper_init (&surface->clipper,
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment