[cairo-commit] 64 commits - boilerplate/cairo-boilerplate.c boilerplate/cairo-boilerplate-drm.c boilerplate/cairo-boilerplate-gl.c boilerplate/cairo-boilerplate-pdf.c boilerplate/cairo-boilerplate-ps.c boilerplate/cairo-boilerplate-qt.cpp boilerplate/cairo-boilerplate-script.c boilerplate/cairo-boilerplate-xcb.c boilerplate/Makefile.win32.features build/configure.ac.features build/Makefile.win32.features build/Makefile.win32.features-h configure.ac .gitignore perf/cairo-perf-trace.c perf/.gitignore perf/Makefile.am src/cairo-analysis-surface.c src/cairo-array.c src/cairo-base64-stream.c src/cairo-base85-stream.c src/cairo-bentley-ottmann.c src/cairo-bentley-ottmann-rectangular.c src/cairo-bentley-ottmann-rectilinear.c src/cairo-beos-surface.cpp src/cairo-botor-scan-converter.c src/cairo-boxes.c src/cairo-boxes-private.h src/cairo.c src/cairo-cache.c src/cairo-cff-subset.c src/cairo-clip.c src/cairo-clip-private.h src/cairo-color.c src/cairo-compiler-private.h src/cairo-composite-rectangles.c src/cairo-composite-rectangles-private.h src/cairo-debug.c src/cairo-deflate-stream.c src/cairo-device.c src/cairo-device-private.h src/cairo-directfb-surface.c src/cairo-drm.h src/cairo-eagle-context.c src/cairo-error-private.h src/cairo-fixed-private.h src/cairo-font-face.c src/cairo-font-face-twin.c src/cairo-font-options.c src/cairo-freed-pool.c src/cairo-freed-pool-private.h src/cairo-freelist.c src/cairo-freelist-private.h src/cairo-ft-font.c src/cairo-gl-glyphs.c src/cairo-gl.h src/cairo-glitz-surface.c src/cairo-gl-private.h src/cairo-gl-shaders.c src/cairo-gl-surface.c src/cairo-glx-context.c src/cairo-gstate.c src/cairo.h src/cairo-hash.c src/cairo-hull.c src/cairo-image-surface.c src/cairoint.h src/cairo-list-private.h src/cairo-lzw.c src/cairo-matrix.c src/cairo-misc.c src/cairo-mutex-impl-private.h src/cairo-mutex-list-private.h src/cairo-mutex-type-private.h src/cairo-os2-surface.c src/cairo-output-stream.c src/cairo-paginated-surface.c src/cairo-path-bounds.c src/cairo-path.c src/cairo-path-fill.c src/cairo-path-fixed.c src/cairo-path-fixed-private.h src/cairo-path-stroke.c src/cairo-pattern.c src/cairo-pdf-operators.c src/cairo-pdf-operators-private.h src/cairo-pdf-surface.c src/cairo-pdf-surface-private.h src/cairo-pen.c src/cairo-png.c src/cairo-polygon.c src/cairo-ps-surface.c src/cairo-qt-surface.cpp src/cairo-quartz-font.c src/cairo-quartz-image-surface.c src/cairo-quartz-surface.c src/cairo-recording-surface.c src/cairo-rectangle.c src/cairo-rectangular-scan-converter.c src/cairo-region.c src/cairo-rtree.c src/cairo-scaled-font.c src/cairo-scaled-font-subsets.c src/cairo-script.h src/cairo-script-surface.c src/cairo-skia-surface.cpp src/cairo-spans.c src/cairo-spans-private.h src/cairo-stroke-style.c src/cairo-surface.c src/cairo-surface-fallback.c src/cairo-surface-fallback-private.h src/cairo-surface-offset.c src/cairo-surface-offset-private.h src/cairo-surface-private.h src/cairo-surface-snapshot.c src/cairo-surface-snapshot-private.h src/cairo-surface-subsurface.c src/cairo-surface-subsurface-private.h src/cairo-surface-wrapper.c src/cairo-surface-wrapper-private.h src/cairo-svg-surface.c src/cairo-tee-surface.c src/cairo-tor-scan-converter.c src/cairo-toy-font-face.c src/cairo-traps.c src/cairo-truetype-subset.c src/cairo-type1-fallback.c src/cairo-type1-subset.c src/cairo-type3-glyph-surface.c src/cairo-types-private.h src/cairo-unicode.c src/cairo-user-font.c src/cairo-vg-surface.c src/cairo-win32-font.c src/cairo-win32-printing-surface.c src/cairo-win32-surface.c src/cairo-xcb-connection.c src/cairo-xcb-connection-core.c src/cairo-xcb-connection-render.c src/cairo-xcb-connection-shm.c src/cairo-xcb.h src/cairo-xcb-private.h src/cairo-xcb-screen.c src/cairo-xcb-shm.c src/cairo-xcb-surface.c src/cairo-xcb-surface-cairo.c src/cairo-xcb-surface-core.c src/cairo-xcb-surface-private.h src/cairo-xcb-surface-render.c src/cairo-xcb-xrender.h src/cairo-xlib-display.c src/cairo-xlib-screen.c src/cairo-xlib-surface.c src/cairo-xlib-visual.c src/cairo-xlib-xcb-surface.c src/cairo-xml.h src/cairo-xml-surface.c src/drm src/glew src/Makefile.sources src/Makefile.win32.features src/test-fallback16-surface.c src/test-fallback-surface.c src/test-null-surface.c src/test-paginated-surface.c src/test-wrapping-surface.c test/any2ppm.c test/cairo-test-trace.c test/clear-source.c test/clear-source.ref.png test/clip-fill-unbounded.argb32.ref.png test/clip-fill-unbounded.rgb24.ref.png test/clipped-group.ref.png test/clip-stroke.ref.png test/clip-stroke-unbounded.argb32.ref.png test/clip-stroke-unbounded.rgb24.ref.png test/leaky-dashed-rectangle.ref.png test/Makefile.am test/Makefile.sources test/pthread-same-source.c test/pthread-same-source.ref.png test/pthread-similar.c test/pthread-similar.ref.png test/rounded-rectangle-fill.c test/rounded-rectangle-fill.xlib.ref.png test/rounded-rectangle-stroke.c test/rounded-rectangle-stroke.xlib.ref.png test/scale-offset-image.xfail.png test/scale-offset-similar.xfail.png test/self-intersecting.ref.png test/subsurface.c test/subsurface.ref.png test/subsurface-repeat.c test/subsurface-repeat.ref.png test/subsurface-similar-repeat.c test/subsurface-similar-repeat.ref.png test/text-rotate.c test/text-rotate.ref.png test/xcb-surface-source.argb32.ref.png test/xcb-surface-source.c test/xcb-surface-source.rgb24.ref.png test/xlib-surface-source.c util/cairo-fdr util/cairo-script util/cairo-sphinx util/cairo-trace util/.gitignore util/trace-to-xml.c
Chris Wilson
ickle at kemper.freedesktop.org
Fri Jan 22 15:06:05 PST 2010
.gitignore | 1
boilerplate/Makefile.win32.features | 20
boilerplate/cairo-boilerplate-drm.c | 2
boilerplate/cairo-boilerplate-gl.c | 127
boilerplate/cairo-boilerplate-pdf.c | 4
boilerplate/cairo-boilerplate-ps.c | 4
boilerplate/cairo-boilerplate-qt.cpp | 2
boilerplate/cairo-boilerplate-script.c | 6
boilerplate/cairo-boilerplate-xcb.c | 522 +++
boilerplate/cairo-boilerplate.c | 6
build/Makefile.win32.features | 2
build/Makefile.win32.features-h | 6
build/configure.ac.features | 2
configure.ac | 29
perf/.gitignore | 1
perf/Makefile.am | 3
perf/cairo-perf-trace.c | 141
src/Makefile.sources | 56
src/Makefile.win32.features | 28
src/cairo-analysis-surface.c | 22
src/cairo-array.c | 1
src/cairo-base64-stream.c | 1
src/cairo-base85-stream.c | 1
src/cairo-bentley-ottmann-rectangular.c | 779 ++--
src/cairo-bentley-ottmann-rectilinear.c | 123
src/cairo-bentley-ottmann.c | 1
src/cairo-beos-surface.cpp | 7
src/cairo-botor-scan-converter.c | 2199 +++++++++++++
src/cairo-boxes-private.h | 80
src/cairo-boxes.c | 269 +
src/cairo-cache.c | 1
src/cairo-cff-subset.c | 1
src/cairo-clip-private.h | 6
src/cairo-clip.c | 369 --
src/cairo-color.c | 13
src/cairo-compiler-private.h | 11
src/cairo-composite-rectangles-private.h | 105
src/cairo-composite-rectangles.c | 197 +
src/cairo-debug.c | 6
src/cairo-deflate-stream.c | 1
src/cairo-device-private.h | 85
src/cairo-device.c | 265 +
src/cairo-directfb-surface.c | 3
src/cairo-drm.h | 31
src/cairo-eagle-context.c | 26
src/cairo-error-private.h | 60
src/cairo-fixed-private.h | 22
src/cairo-font-face-twin.c | 1
src/cairo-font-face.c | 1
src/cairo-font-options.c | 1
src/cairo-freed-pool-private.h | 121
src/cairo-freed-pool.c | 91
src/cairo-freelist-private.h | 16
src/cairo-freelist.c | 39
src/cairo-ft-font.c | 32
src/cairo-gl-glyphs.c | 58
src/cairo-gl-private.h | 43
src/cairo-gl-shaders.c | 1
src/cairo-gl-surface.c | 391 +-
src/cairo-gl.h | 22
src/cairo-glitz-surface.c | 6
src/cairo-glx-context.c | 27
src/cairo-gstate.c | 135
src/cairo-hash.c | 1
src/cairo-hull.c | 1
src/cairo-image-surface.c | 3970 ++++++++++++++++++++---
src/cairo-list-private.h | 7
src/cairo-lzw.c | 1
src/cairo-matrix.c | 5
src/cairo-misc.c | 105
src/cairo-mutex-impl-private.h | 28
src/cairo-mutex-list-private.h | 6
src/cairo-mutex-type-private.h | 9
src/cairo-os2-surface.c | 2
src/cairo-output-stream.c | 1
src/cairo-paginated-surface.c | 18
src/cairo-path-bounds.c | 159
src/cairo-path-fill.c | 77
src/cairo-path-fixed-private.h | 4
src/cairo-path-fixed.c | 84
src/cairo-path-stroke.c | 231 +
src/cairo-path.c | 1
src/cairo-pattern.c | 237 -
src/cairo-pdf-operators-private.h | 24
src/cairo-pdf-operators.c | 39
src/cairo-pdf-surface-private.h | 11
src/cairo-pdf-surface.c | 265 -
src/cairo-pen.c | 1
src/cairo-png.c | 2
src/cairo-polygon.c | 1
src/cairo-ps-surface.c | 279 -
src/cairo-qt-surface.cpp | 27
src/cairo-quartz-font.c | 2
src/cairo-quartz-image-surface.c | 3
src/cairo-quartz-surface.c | 14
src/cairo-recording-surface.c | 21
src/cairo-rectangle.c | 21
src/cairo-rectangular-scan-converter.c | 723 ++++
src/cairo-region.c | 1
src/cairo-rtree.c | 1
src/cairo-scaled-font-subsets.c | 3
src/cairo-scaled-font.c | 67
src/cairo-script-surface.c | 510 +--
src/cairo-script.h | 35
src/cairo-skia-surface.cpp | 1
src/cairo-spans-private.h | 72
src/cairo-spans.c | 39
src/cairo-stroke-style.c | 3
src/cairo-surface-fallback-private.h | 6
src/cairo-surface-fallback.c | 432 --
src/cairo-surface-offset-private.h | 95
src/cairo-surface-offset.c | 354 ++
src/cairo-surface-private.h | 1
src/cairo-surface-snapshot-private.h | 48
src/cairo-surface-snapshot.c | 226 +
src/cairo-surface-subsurface-private.h | 48
src/cairo-surface-subsurface.c | 465 ++
src/cairo-surface-wrapper-private.h | 12
src/cairo-surface-wrapper.c | 147
src/cairo-surface.c | 165
src/cairo-svg-surface.c | 45
src/cairo-tee-surface.c | 8
src/cairo-tor-scan-converter.c | 344 +-
src/cairo-toy-font-face.c | 1
src/cairo-traps.c | 48
src/cairo-truetype-subset.c | 1
src/cairo-type1-fallback.c | 1
src/cairo-type1-subset.c | 1
src/cairo-type3-glyph-surface.c | 11
src/cairo-types-private.h | 60
src/cairo-unicode.c | 1
src/cairo-user-font.c | 1
src/cairo-vg-surface.c | 12
src/cairo-win32-font.c | 1
src/cairo-win32-printing-surface.c | 16
src/cairo-win32-surface.c | 41
src/cairo-xcb-connection-core.c | 482 ++
src/cairo-xcb-connection-render.c | 969 +++++
src/cairo-xcb-connection-shm.c | 194 +
src/cairo-xcb-connection.c | 867 +++++
src/cairo-xcb-private.h | 760 ++++
src/cairo-xcb-screen.c | 518 +++
src/cairo-xcb-shm.c | 576 +++
src/cairo-xcb-surface-cairo.c | 94
src/cairo-xcb-surface-core.c | 613 +++
src/cairo-xcb-surface-private.h | 37
src/cairo-xcb-surface-render.c | 4471 +++++++++++++++++++++++++++
src/cairo-xcb-surface.c | 3354 +++++---------------
src/cairo-xcb-xrender.h | 63
src/cairo-xcb.h | 41
src/cairo-xlib-display.c | 1
src/cairo-xlib-screen.c | 1
src/cairo-xlib-surface.c | 19
src/cairo-xlib-visual.c | 2
src/cairo-xlib-xcb-surface.c | 515 +++
src/cairo-xml-surface.c | 216 -
src/cairo-xml.h | 13
src/cairo.c | 3
src/cairo.h | 124
src/cairoint.h | 200 -
src/drm/cairo-drm-bo.c | 14
src/drm/cairo-drm-gallium-surface.c | 1
src/drm/cairo-drm-i915-glyphs.c | 534 +++
src/drm/cairo-drm-i915-private.h | 1169 +++++++
src/drm/cairo-drm-i915-shader.c | 2674 ++++++++++++++++
src/drm/cairo-drm-i915-spans.c | 708 ++++
src/drm/cairo-drm-i915-surface.c | 1996 ++++++++++++
src/drm/cairo-drm-i965-glyphs.c | 500 +++
src/drm/cairo-drm-i965-private.h | 742 ++++
src/drm/cairo-drm-i965-shader.c | 2852 +++++++++++++++++
src/drm/cairo-drm-i965-spans.c | 408 ++
src/drm/cairo-drm-i965-surface.c | 1949 +++++++++++
src/drm/cairo-drm-intel-brw-defines.h | 824 ++++
src/drm/cairo-drm-intel-brw-eu-emit.c | 1089 ++++++
src/drm/cairo-drm-intel-brw-eu-util.c | 121
src/drm/cairo-drm-intel-brw-eu.c | 250 +
src/drm/cairo-drm-intel-brw-eu.h | 1043 ++++++
src/drm/cairo-drm-intel-brw-structs.h | 1328 ++++++++
src/drm/cairo-drm-intel-command-private.h | 909 +++++
src/drm/cairo-drm-intel-debug.c | 1208 +++++++
src/drm/cairo-drm-intel-ioctl-private.h | 417 ++
src/drm/cairo-drm-intel-private.h | 427 ++
src/drm/cairo-drm-intel-surface.c | 424 +-
src/drm/cairo-drm-intel.c | 1241 +++++--
src/drm/cairo-drm-private.h | 101
src/drm/cairo-drm-radeon-private.h | 3
src/drm/cairo-drm-radeon-surface.c | 288 -
src/drm/cairo-drm-radeon.c | 6
src/drm/cairo-drm-surface.c | 236 -
src/drm/cairo-drm.c | 233 -
src/glew/GL/glew.h | 2
src/glew/glew.c | 9
src/test-fallback-surface.c | 5
src/test-fallback16-surface.c | 2
src/test-null-surface.c | 13
src/test-paginated-surface.c | 11
src/test-wrapping-surface.c | 8
test/Makefile.am | 17
test/Makefile.sources | 15
test/any2ppm.c | 4
test/cairo-test-trace.c | 7
test/clear-source.c | 163
test/clear-source.ref.png |binary
test/clip-fill-unbounded.argb32.ref.png |binary
test/clip-fill-unbounded.rgb24.ref.png |binary
test/clip-stroke-unbounded.argb32.ref.png |binary
test/clip-stroke-unbounded.rgb24.ref.png |binary
test/clip-stroke.ref.png |binary
test/clipped-group.ref.png |binary
test/leaky-dashed-rectangle.ref.png |binary
test/pthread-same-source.c | 160
test/pthread-same-source.ref.png |binary
test/pthread-similar.c | 106
test/pthread-similar.ref.png |binary
test/rounded-rectangle-fill.c | 65
test/rounded-rectangle-fill.xlib.ref.png |binary
test/rounded-rectangle-stroke.c | 64
test/rounded-rectangle-stroke.xlib.ref.png |binary
test/scale-offset-image.xfail.png |binary
test/scale-offset-similar.xfail.png |binary
test/self-intersecting.ref.png |binary
test/subsurface-repeat.c | 72
test/subsurface-repeat.ref.png |binary
test/subsurface-similar-repeat.c | 83
test/subsurface-similar-repeat.ref.png |binary
test/subsurface.c | 80
test/subsurface.ref.png |binary
test/text-rotate.c | 68
test/text-rotate.ref.png |binary
test/xcb-surface-source.argb32.ref.png |binary
test/xcb-surface-source.c | 144
test/xcb-surface-source.rgb24.ref.png |binary
test/xlib-surface-source.c | 5
util/.gitignore | 2
util/cairo-fdr/fdr.c | 10
util/cairo-script/.gitignore | 1
util/cairo-script/cairo-script-interpreter.h | 3
util/cairo-script/cairo-script-operators.c | 103
util/cairo-script/csi-trace.c | 11
util/cairo-sphinx/fdr.c | 4
util/cairo-sphinx/sphinx.c | 20
util/cairo-trace/trace.c | 10
util/trace-to-xml.c | 7
243 files changed, 48168 insertions(+), 7269 deletions(-)
New commits:
commit 2a466ba07072cb394cfc955cfb0633b0cc278044
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Fri Jan 22 22:26:52 2010 +0000
script: Encode octal values correctly.
Oops, we were emitting the octal numerals in reverse order.
diff --git a/src/cairo-script-surface.c b/src/cairo-script-surface.c
index 53cfb7a..af4abbc 100644
--- a/src/cairo-script-surface.c
+++ b/src/cairo-script-surface.c
@@ -2841,6 +2841,15 @@ _emit_scaled_glyphs (cairo_script_surface_t *surface,
}
static void
+to_octal (int value, char *buf, size_t size)
+{
+ do {
+ buf[--size] = '0' + (value & 7);
+ value >>= 3;
+ } while (size);
+}
+
+static void
_emit_string_literal (cairo_script_surface_t *surface,
const char *utf8, int len)
{
@@ -2885,14 +2894,10 @@ ESCAPED_CHAR:
if (isprint (c) || isspace (c)) {
_cairo_output_stream_printf (ctx->stream, "%c", c);
} else {
- int octal = 0;
- while (c) {
- octal *= 10;
- octal += c&7;
- c /= 8;
- }
- _cairo_output_stream_printf (ctx->stream,
- "\\%03d", octal);
+ char buf[4] = { '\\' };
+
+ to_octal (c, buf+1, 3);
+ _cairo_output_stream_write (ctx->stream, buf, 4);
}
break;
}
commit 87529198aa37f5eb5943eb80cc1aae858fdaadd0
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Fri Jan 22 22:21:44 2010 +0000
scaled-font: Mark an error site with _cairo_error()
diff --git a/src/cairo-scaled-font-subsets.c b/src/cairo-scaled-font-subsets.c
index e911f31..228b65a 100644
--- a/src/cairo-scaled-font-subsets.c
+++ b/src/cairo-scaled-font-subsets.c
@@ -401,7 +401,7 @@ _cairo_sub_font_glyph_map_to_unicode (cairo_sub_font_glyph_t *sub_font_glyph,
/* No existing mapping. Use the requested mapping */
sub_font_glyph->utf8 = malloc (utf8_len + 1);
if (unlikely (sub_font_glyph->utf8 == NULL))
- return CAIRO_STATUS_NO_MEMORY;
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
memcpy (sub_font_glyph->utf8, utf8, utf8_len);
sub_font_glyph->utf8[utf8_len] = 0;
commit 6544f3b25d2120b7bd04f6c956c2ea7b9c101c76
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Fri Jan 22 22:15:25 2010 +0000
ps: Wean off the low-level image composite interface
The low-level surface composite interface will disappear in the near
future and results in much more ugly code than calling the high level
interface - so use it when flattening images into the page background.
diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c
index cafa430..bbe44af 100644
--- a/src/cairo-ps-surface.c
+++ b/src/cairo-ps-surface.c
@@ -1662,7 +1662,7 @@ surface_pattern_supported (const cairo_surface_pattern_t *pattern)
* don't think it's worth the extra code to support it. */
/* XXX: Need to write this function here...
- content = cairo_surface_get_content (pattern->surface);
+ content = pattern->surface->content;
if (content == CAIRO_CONTENT_ALPHA)
return FALSE;
*/
@@ -1974,55 +1974,36 @@ _cairo_ps_surface_flatten_image_transparency (cairo_ps_surface_t *surface,
cairo_image_surface_t *image,
cairo_image_surface_t **opaque_image)
{
- const cairo_color_t *background_color;
cairo_surface_t *opaque;
cairo_surface_pattern_t pattern;
cairo_status_t status;
- if (surface->content == CAIRO_CONTENT_COLOR_ALPHA)
- background_color = CAIRO_COLOR_WHITE;
- else
- background_color = CAIRO_COLOR_BLACK;
-
opaque = cairo_image_surface_create (CAIRO_FORMAT_RGB24,
image->width,
image->height);
- if (opaque->status)
+ if (unlikely (opaque->status))
return opaque->status;
- _cairo_pattern_init_for_surface (&pattern, &image->base);
-
- status = _cairo_surface_fill_rectangle (opaque,
- CAIRO_OPERATOR_SOURCE,
- background_color,
- 0, 0,
- image->width, image->height);
- if (unlikely (status))
- goto fail;
-
- status = _cairo_surface_composite (CAIRO_OPERATOR_OVER,
- &pattern.base,
- NULL,
- opaque,
- 0, 0,
- 0, 0,
- 0, 0,
- image->width,
- image->height,
+ if (surface->content == CAIRO_CONTENT_COLOR_ALPHA) {
+ status = _cairo_surface_paint (opaque,
+ CAIRO_OPERATOR_SOURCE,
+ &_cairo_pattern_white.base,
NULL);
- if (unlikely (status))
- goto fail;
+ if (unlikely (status)) {
+ cairo_surface_destroy (opaque);
+ return status;
+ }
+ }
+ _cairo_pattern_init_for_surface (&pattern, &image->base);
+ pattern.base.filter = CAIRO_FILTER_NEAREST;
+ status = _cairo_surface_paint (opaque, CAIRO_OPERATOR_OVER, &pattern.base, NULL);
_cairo_pattern_fini (&pattern.base);
- *opaque_image = (cairo_image_surface_t *) opaque;
+ if (unlikely (status))
+ return status;
+ *opaque_image = (cairo_image_surface_t *) opaque;
return CAIRO_STATUS_SUCCESS;
-
-fail:
- _cairo_pattern_fini (&pattern.base);
- cairo_surface_destroy (opaque);
-
- return status;
}
static cairo_status_t
@@ -2448,7 +2429,7 @@ _cairo_ps_surface_emit_recording_surface (cairo_ps_surface_t *surface,
&surface->cairo_to_ps);
_cairo_output_stream_printf (surface->stream, " q\n");
- if (cairo_surface_get_content (recording_surface) == CAIRO_CONTENT_COLOR) {
+ if (recording_surface->content == CAIRO_CONTENT_COLOR) {
surface->content = CAIRO_CONTENT_COLOR;
_cairo_output_stream_printf (surface->stream,
" 0 g %d %d %d %d rectfill\n",
@@ -2575,9 +2556,11 @@ _cairo_ps_surface_acquire_surface (cairo_ps_surface_t *surface,
x = -rect.x;
y = -rect.y;
- pad_image = _cairo_image_surface_create_with_content (pattern->surface->content,
- rect.width,
- rect.height);
+ pad_image =
+ _cairo_image_surface_create_with_pixman_format (NULL,
+ surface->acquired_image->pixman_format,
+ rect.width, rect.height,
+ 0);
if (pad_image->status) {
status = pad_image->status;
goto BAIL;
@@ -2586,16 +2569,10 @@ _cairo_ps_surface_acquire_surface (cairo_ps_surface_t *surface,
_cairo_pattern_init_for_surface (&pad_pattern, &surface->acquired_image->base);
cairo_matrix_init_translate (&pad_pattern.base.matrix, -x, -y);
pad_pattern.base.extend = CAIRO_EXTEND_PAD;
- status = _cairo_surface_composite (CAIRO_OPERATOR_SOURCE,
- &pad_pattern.base,
- NULL,
- pad_image,
- 0, 0,
- 0, 0,
- 0, 0,
- rect.width,
- rect.height,
- NULL);
+ status = _cairo_surface_paint (pad_image,
+ CAIRO_OPERATOR_SOURCE,
+ &pad_pattern.base,
+ NULL);
_cairo_pattern_fini (&pad_pattern.base);
if (unlikely (status)) {
if (pad_image != &surface->acquired_image->base)
commit f57cb45fa9274351b36f96eb932a931493b5db94
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Fri Jan 22 22:18:35 2010 +0000
ps: Arguments to fill_extents() were reversed.
diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c
index b7f3aa2..cafa430 100644
--- a/src/cairo-ps-surface.c
+++ b/src/cairo-ps-surface.c
@@ -3605,7 +3605,8 @@ _cairo_ps_surface_fill (void *abstract_surface,
/* use the more accurate extents */
if (extents.is_bounded) {
_cairo_path_fixed_fill_extents (path,
- tolerance, fill_rule,
+ fill_rule,
+ tolerance,
&extents.mask);
if (! _cairo_rectangle_intersect (&extents.bounded, &extents.mask))
commit 58540405d9bc6581c1d07f17bd5aee330f06d4a2
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Fri Jan 22 22:05:37 2010 +0000
pdf: Arguments to fill_extents() were reversed.
diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c
index 2b6ebc3..f0bdebd 100644
--- a/src/cairo-pdf-surface.c
+++ b/src/cairo-pdf-surface.c
@@ -5666,7 +5666,8 @@ _cairo_pdf_surface_fill (void *abstract_surface,
/* use the more accurate extents */
if (extents.is_bounded) {
_cairo_path_fixed_fill_extents (path,
- tolerance, fill_rule,
+ fill_rule,
+ tolerance,
&extents.mask);
if (! _cairo_rectangle_intersect (&extents.bounded, &extents.mask))
commit 34dd80632e4671f0ca245be9db4280db62bdb1f9
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Thu Jan 21 18:39:26 2010 +0000
glew: Silence compiler.
diff --git a/src/glew/GL/glew.h b/src/glew/GL/glew.h
index 7932a1c..e398287 100644
--- a/src/glew/GL/glew.h
+++ b/src/glew/GL/glew.h
@@ -12222,7 +12222,7 @@ GLEWAPI GLboolean glewContextIsSupported (GLEWContext* ctx, const char* name);
#else /* GLEW_MX */
-GLEWAPI GLenum glewInit ();
+GLEWAPI GLenum glewInit (void);
GLEWAPI GLboolean glewIsSupported (const char* name);
#define glewIsExtensionSupported(x) glewIsSupported(x)
diff --git a/src/glew/glew.c b/src/glew/glew.c
index 0690583..6ef6d22 100644
--- a/src/glew/glew.c
+++ b/src/glew/glew.c
@@ -8857,7 +8857,7 @@ GLboolean glxewGetExtension (const char* name)
return GL_FALSE;
}
-GLenum glxewContextInit (GLXEW_CONTEXT_ARG_DEF_LIST)
+static GLenum glxewContextInit (GLXEW_CONTEXT_ARG_DEF_LIST)
{
int major, minor;
@@ -9102,7 +9102,7 @@ extern GLenum wglewContextInit (void);
extern GLenum glxewContextInit (void);
#endif /* _WIN32 */
-GLenum glewInit ()
+GLenum glewInit (void)
{
GLenum r;
if ( (r = glewContextInit()) ) return r;
commit cf9ea9f2f0ea1e1b42dc1507ed0dac4dfbf5d387
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Thu Jan 21 18:39:12 2010 +0000
gl: Acquire the context whilst creating surfaces.
diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h
index 91f1bd4..d08e545 100644
--- a/src/cairo-gl-private.h
+++ b/src/cairo-gl-private.h
@@ -158,7 +158,7 @@ _cairo_gl_operand_init (cairo_gl_composite_operand_t *operand,
int dst_x, int dst_y,
int width, int height);
-static inline cairo_status_t cairo_warn
+static always_inline cairo_status_t cairo_warn
_cairo_gl_context_acquire (cairo_device_t *device,
cairo_gl_context_t **ctx)
{
@@ -172,13 +172,12 @@ _cairo_gl_context_acquire (cairo_device_t *device,
return CAIRO_STATUS_SUCCESS;
}
-static inline void
+static always_inline void
_cairo_gl_context_release (cairo_gl_context_t *ctx)
{
cairo_device_release (&ctx->base);
}
-
cairo_private void
_cairo_gl_set_destination (cairo_gl_surface_t *surface);
diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index 35b946c..5c57bed 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -414,9 +414,6 @@ _cairo_gl_surface_create_scratch (cairo_gl_context_t *ctx,
GLenum err, format;
cairo_status_t status;
- if (ctx->base.status)
- return _cairo_surface_create_in_error (ctx->base.status);
-
assert (width <= ctx->max_framebuffer_size && height <= ctx->max_framebuffer_size);
surface = calloc (1, sizeof (cairo_gl_surface_t));
@@ -425,6 +422,12 @@ _cairo_gl_surface_create_scratch (cairo_gl_context_t *ctx,
_cairo_gl_surface_init (&ctx->base, surface, content, width, height);
+ /* adjust the texture size after setting our real extents */
+ if (width < 1)
+ width = 1;
+ if (height < 1)
+ height = 1;
+
switch (content) {
default:
ASSERT_NOT_REACHED;
@@ -523,15 +526,22 @@ cairo_gl_surface_create (cairo_device_t *abstract_device,
if (ctx->base.backend->type != CAIRO_DEVICE_TYPE_GL)
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH));
+ status = _cairo_gl_context_acquire (abstract_device, &ctx);
+ if (unlikely (status))
+ return _cairo_surface_create_in_error (status);
+
surface = (cairo_gl_surface_t *)
_cairo_gl_surface_create_scratch (ctx, content, width, height);
- if (unlikely (surface->base.status))
+ if (unlikely (surface->base.status)) {
+ _cairo_gl_context_release (ctx);
return &surface->base;
+ }
/* Cairo surfaces start out initialized to transparent (black) */
status = _cairo_gl_surface_clear (surface);
if (unlikely (status)) {
cairo_surface_destroy (&surface->base);
+ _cairo_gl_context_release (ctx);
return _cairo_surface_create_in_error (status);
}
@@ -603,10 +613,9 @@ _cairo_gl_surface_create_similar (void *abstract_surface,
int width,
int height)
{
- cairo_gl_surface_t *surface = abstract_surface;
- cairo_gl_context_t *ctx = (cairo_gl_context_t *) surface->base.device;
-
- assert (CAIRO_CONTENT_VALID (content));
+ cairo_surface_t *surface = abstract_surface;
+ cairo_gl_context_t *ctx = (cairo_gl_context_t *) surface->device;
+ cairo_status_t status;
if (width > ctx->max_framebuffer_size ||
height > ctx->max_framebuffer_size)
@@ -614,12 +623,14 @@ _cairo_gl_surface_create_similar (void *abstract_surface,
return NULL;
}
- if (width < 1)
- width = 1;
- if (height < 1)
- height = 1;
+ status = _cairo_gl_context_acquire (surface->device, &ctx);
+ if (unlikely (status))
+ return _cairo_surface_create_in_error (status);
+
+ surface = _cairo_gl_surface_create_scratch (ctx, content, width, height);
+ _cairo_gl_context_release (ctx);
- return _cairo_gl_surface_create_scratch (ctx, content, width, height);
+ return surface;
}
cairo_status_t
commit a7e05bd602e7f8bee63f5d32cb95d65628e6e715
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Thu Jan 21 18:22:04 2010 +0000
glew: Do not assume that UNIX == GLX
diff --git a/src/glew/glew.c b/src/glew/glew.c
index aa2278f..0690583 100644
--- a/src/glew/glew.c
+++ b/src/glew/glew.c
@@ -8860,8 +8860,13 @@ GLboolean glxewGetExtension (const char* name)
GLenum glxewContextInit (GLXEW_CONTEXT_ARG_DEF_LIST)
{
int major, minor;
+
/* initialize core GLX 1.2 */
if (_glewInit_GLX_VERSION_1_2(GLEW_CONTEXT_ARG_VAR_INIT)) return GLEW_ERROR_GLX_VERSION_11_ONLY;
+
+ if (glXGetCurrentDisplay() == NULL)
+ return GLEW_OK;
+
/* initialize flags */
CONST_CAST(GLXEW_VERSION_1_0) = GL_TRUE;
CONST_CAST(GLXEW_VERSION_1_1) = GL_TRUE;
commit c0008242b0f162d8c7717009ba792ed61b2924d1
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Fri Jan 22 21:35:23 2010 +0000
misc: Only use custom lround() under DISABLE_SOME_FLOATING_POINT
On my Core2, the library version of lround() is faster than our
hand-rolled non-floating point implementation. So only enable our code
if we are trying to minimise the number of floating point operations --
even then, it would worth investigating the library performance first.
[Just a reminder that optimisation choices will change over time as our
hardware and software evolves.]
diff --git a/src/cairo-misc.c b/src/cairo-misc.c
index 56409af..32c2428 100644
--- a/src/cairo-misc.c
+++ b/src/cairo-misc.c
@@ -463,6 +463,7 @@ _cairo_operator_bounded_by_either (cairo_operator_t op)
}
+#if DISABLE_SOME_FLOATING_POINT
/* This function is identical to the C99 function lround(), except that it
* performs arithmetic rounding (floor(d + .5) instead of away-from-zero rounding) and
* has a valid input range of (INT_MIN, INT_MAX] instead of
@@ -673,6 +674,7 @@ _cairo_lround (double d)
#undef MSW
#undef LSW
}
+#endif
/* Convert a 32-bit IEEE single precision floating point number to a
* 'half' representation (s10.5)
diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c
index 3e48ebb..b7f3aa2 100644
--- a/src/cairo-ps-surface.c
+++ b/src/cairo-ps-surface.c
@@ -880,8 +880,8 @@ _cairo_ps_surface_get_page_media (cairo_ps_surface_t *surface)
page->name = strdup (page_name);
} else {
snprintf (buf, sizeof (buf), "%dx%dmm",
- _cairo_lround (surface->width * 25.4/72),
- _cairo_lround (surface->height * 25.4/72));
+ (int) _cairo_lround (surface->width * 25.4/72),
+ (int) _cairo_lround (surface->height * 25.4/72));
page->name = strdup (buf);
}
diff --git a/src/cairoint.h b/src/cairoint.h
index acc5769..9cd5cfa 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -947,8 +947,13 @@ _cairo_round (double r)
return floor (r + .5);
}
+#if DISABLE_SOME_FLOATING_POINT
cairo_private int
_cairo_lround (double d) cairo_const;
+#else
+#define _cairo_lround lround
+#endif
+
cairo_private uint16_t
_cairo_half_from_float (float f) cairo_const;
commit 1236c41072a7966eda7db48a381fd0508e5289be
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Fri Jan 22 21:26:26 2010 +0000
xcb: Refresh.
Still an experimental backend, it's now a little too late to stabilise
for 1.10, but this should represent a major step forward in its feature
set and an attempt to catch up with all the bug fixes that have been
performed on xlib. Notably not tested yet (and expected to be broken)
are mixed-endian connections and low bitdepth servers (the dithering
support has not been copied over for instance). However, it seems robust
enough for daily use...
Of particular note in this update is that the xcb surface is now capable
of subverting the xlib surface through the ./configure --enable-xlib-xcb
option. This replaces the xlib surface with a proxy that forwards all
operations to an equivalent xcb surface whilst preserving the cairo-xlib
API that is required for compatibility with the existing applications,
for instance GTK+ and Mozilla. Also you can experiment with enabling a
DRM bypass, though you need to be extremely foolhardy to do so.
diff --git a/boilerplate/Makefile.win32.features b/boilerplate/Makefile.win32.features
index 5c1e011..8d56411 100644
--- a/boilerplate/Makefile.win32.features
+++ b/boilerplate/Makefile.win32.features
@@ -49,6 +49,16 @@ enabled_cairo_boilerplate_private += $(cairo_boilerplate_xcb_private)
enabled_cairo_boilerplate_sources += $(cairo_boilerplate_xcb_sources)
endif
+unsupported_cairo_boilerplate_headers += $(cairo_boilerplate_xlib_xcb_headers)
+all_cairo_boilerplate_headers += $(cairo_boilerplate_xlib_xcb_headers)
+all_cairo_boilerplate_private += $(cairo_boilerplate_xlib_xcb_private)
+all_cairo_boilerplate_sources += $(cairo_boilerplate_xlib_xcb_sources)
+ifeq ($(CAIRO_HAS_XLIB_XCB_FUNCTIONS),1)
+enabled_cairo_boilerplate_headers += $(cairo_boilerplate_xlib_xcb_headers)
+enabled_cairo_boilerplate_private += $(cairo_boilerplate_xlib_xcb_private)
+enabled_cairo_boilerplate_sources += $(cairo_boilerplate_xlib_xcb_sources)
+endif
+
unsupported_cairo_boilerplate_headers += $(cairo_boilerplate_qt_headers)
all_cairo_boilerplate_headers += $(cairo_boilerplate_qt_headers)
all_cairo_boilerplate_private += $(cairo_boilerplate_qt_private)
@@ -159,6 +169,16 @@ enabled_cairo_boilerplate_private += $(cairo_boilerplate_gallium_private)
enabled_cairo_boilerplate_sources += $(cairo_boilerplate_gallium_sources)
endif
+unsupported_cairo_boilerplate_headers += $(cairo_boilerplate_xcb_drm_headers)
+all_cairo_boilerplate_headers += $(cairo_boilerplate_xcb_drm_headers)
+all_cairo_boilerplate_private += $(cairo_boilerplate_xcb_drm_private)
+all_cairo_boilerplate_sources += $(cairo_boilerplate_xcb_drm_sources)
+ifeq ($(CAIRO_HAS_XCB_DRM_FUNCTIONS),1)
+enabled_cairo_boilerplate_headers += $(cairo_boilerplate_xcb_drm_headers)
+enabled_cairo_boilerplate_private += $(cairo_boilerplate_xcb_drm_private)
+enabled_cairo_boilerplate_sources += $(cairo_boilerplate_xcb_drm_sources)
+endif
+
supported_cairo_boilerplate_headers += $(cairo_boilerplate_png_headers)
all_cairo_boilerplate_headers += $(cairo_boilerplate_png_headers)
all_cairo_boilerplate_private += $(cairo_boilerplate_png_private)
diff --git a/boilerplate/cairo-boilerplate-xcb.c b/boilerplate/cairo-boilerplate-xcb.c
index 0ab2026..ed173e6 100644
--- a/boilerplate/cairo-boilerplate-xcb.c
+++ b/boilerplate/cairo-boilerplate-xcb.c
@@ -26,15 +26,16 @@
#include "cairo-boilerplate-private.h"
-#include <cairo-xcb-xrender.h>
-
-#include <xcb/xcb_renderutil.h>
+#include <cairo-xcb.h>
static const cairo_user_data_key_t xcb_closure_key;
typedef struct _xcb_target_closure {
xcb_connection_t *c;
- xcb_pixmap_t pixmap;
+ cairo_device_t *device;
+ uint32_t drawable;
+ cairo_bool_t is_pixmap;
+ cairo_surface_t *surface;
} xcb_target_closure_t;
static void
@@ -42,8 +43,17 @@ _cairo_boilerplate_xcb_cleanup (void *closure)
{
xcb_target_closure_t *xtc = closure;
- xcb_free_pixmap (xtc->c, xtc->pixmap);
+ if (xtc->is_pixmap)
+ xcb_free_pixmap (xtc->c, xtc->drawable);
+ else
+ xcb_destroy_window (xtc->c, xtc->drawable);
+ cairo_surface_destroy (xtc->surface);
+
+ cairo_device_finish (xtc->device);
+ cairo_device_destroy (xtc->device);
+
xcb_disconnect (xtc->c);
+
free (xtc);
}
@@ -53,10 +63,42 @@ _cairo_boilerplate_xcb_synchronize (void *closure)
xcb_target_closure_t *xtc = closure;
free (xcb_get_image_reply (xtc->c,
xcb_get_image (xtc->c, XCB_IMAGE_FORMAT_Z_PIXMAP,
- xtc->pixmap, 0, 0, 1, 1, /* AllPlanes */ ~0UL),
+ xtc->drawable, 0, 0, 1, 1, /* AllPlanes */ -1),
0));
}
+static xcb_render_pictforminfo_t *
+find_depth (xcb_connection_t *connection, int depth, void **formats_out)
+{
+ xcb_render_query_pict_formats_reply_t *formats;
+ xcb_render_query_pict_formats_cookie_t cookie;
+ xcb_render_pictforminfo_iterator_t i;
+
+ cookie = xcb_render_query_pict_formats (connection);
+ xcb_flush (connection);
+
+ formats = xcb_render_query_pict_formats_reply (connection, cookie, 0);
+ if (formats == NULL)
+ return NULL;
+
+ for (i = xcb_render_query_pict_formats_formats_iterator (formats);
+ i.rem;
+ xcb_render_pictforminfo_next (&i))
+ {
+ if (XCB_RENDER_PICT_TYPE_DIRECT != i.data->type)
+ continue;
+
+ if (depth != i.data->depth)
+ continue;
+
+ *formats_out = formats;
+ return i.data;
+ }
+
+ free (formats);
+ return NULL;
+}
+
static cairo_surface_t *
_cairo_boilerplate_xcb_create_surface (const char *name,
cairo_content_t content,
@@ -72,10 +114,11 @@ _cairo_boilerplate_xcb_create_surface (const char *name,
xcb_target_closure_t *xtc;
xcb_connection_t *c;
xcb_render_pictforminfo_t *render_format;
- xcb_pict_standard_t format;
+ int depth;
xcb_void_cookie_t cookie;
cairo_surface_t *surface;
cairo_status_t status;
+ void *formats;
*closure = xtc = xmalloc (sizeof (xcb_target_closure_t));
@@ -85,32 +128,279 @@ _cairo_boilerplate_xcb_create_surface (const char *name,
height = 1;
xtc->c = c = xcb_connect(NULL,NULL);
- if (xcb_connection_has_error(c)) {
- fprintf (stderr, "Failed to connect to X server through XCB\n");
+ if (xcb_connection_has_error(c))
+ return NULL;
+
+ root = xcb_setup_roots_iterator(xcb_get_setup(c)).data;
+
+ xtc->surface = NULL;
+ xtc->is_pixmap = TRUE;
+ xtc->drawable = xcb_generate_id (c);
+ switch (content) {
+ case CAIRO_CONTENT_COLOR:
+ depth = 24;
+ cookie = xcb_create_pixmap_checked (c, depth,
+ xtc->drawable, root->root,
+ width, height);
+ break;
+
+ case CAIRO_CONTENT_COLOR_ALPHA:
+ depth = 32;
+ cookie = xcb_create_pixmap_checked (c, depth,
+ xtc->drawable, root->root,
+ width, height);
+ break;
+
+ case CAIRO_CONTENT_ALPHA: /* would be XCB_PICT_STANDARD_A_8 */
+ default:
+ xcb_disconnect (c);
+ free (xtc);
+ return NULL;
+ }
+
+ /* slow, but sure */
+ if (xcb_request_check (c, cookie) != NULL) {
+ xcb_disconnect (c);
+ free (xtc);
+ return NULL;
+ }
+
+ render_format = find_depth (c, depth, &formats);
+ if (render_format == NULL) {
+ xcb_disconnect (c);
+ free (xtc);
+ return NULL;
+ }
+
+ surface = cairo_xcb_surface_create_with_xrender_format (c, root,
+ xtc->drawable,
+ render_format,
+ width, height);
+ free (formats);
+
+ xtc->device = cairo_device_reference (cairo_surface_get_device (surface));
+ status = cairo_surface_set_user_data (surface, &xcb_closure_key, xtc, NULL);
+ if (status == CAIRO_STATUS_SUCCESS)
+ return surface;
+
+ cairo_surface_destroy (surface);
+
+ _cairo_boilerplate_xcb_cleanup (xtc);
+ return cairo_boilerplate_surface_create_in_error (status);
+}
+
+static xcb_visualtype_t *
+lookup_visual (xcb_screen_t *s, xcb_visualid_t visual)
+{
+ xcb_depth_iterator_t d;
+
+ d = xcb_screen_allowed_depths_iterator (s);
+ for (; d.rem; xcb_depth_next (&d)) {
+ xcb_visualtype_iterator_t v = xcb_depth_visuals_iterator (d.data);
+ for (; v.rem; xcb_visualtype_next (&v)) {
+ if (v.data->visual_id == visual)
+ return v.data;
+ }
+ }
+
+ return 0;
+}
+
+static cairo_surface_t *
+_cairo_boilerplate_xcb_create_window (const char *name,
+ cairo_content_t content,
+ double width,
+ double height,
+ double max_width,
+ double max_height,
+ cairo_boilerplate_mode_t mode,
+ int id,
+ void **closure)
+{
+ xcb_target_closure_t *xtc;
+ xcb_connection_t *c;
+ xcb_screen_t *s;
+ xcb_void_cookie_t cookie;
+ cairo_surface_t *surface;
+ cairo_status_t status;
+ uint32_t values[] = { 1 };
+
+ *closure = xtc = xmalloc (sizeof (xcb_target_closure_t));
+
+ if (width == 0)
+ width = 1;
+ if (height == 0)
+ height = 1;
+
+ xtc->c = c = xcb_connect(NULL,NULL);
+ if (xcb_connection_has_error(c))
+ return NULL;
+
+ xtc->surface = NULL;
+
+ s = xcb_setup_roots_iterator (xcb_get_setup (c)).data;
+ xtc->is_pixmap = FALSE;
+ xtc->drawable = xcb_generate_id (c);
+ cookie = xcb_create_window_checked (c,
+ s->root_depth,
+ xtc->drawable,
+ s->root,
+ 0, 0, width, height, 0,
+ XCB_WINDOW_CLASS_INPUT_OUTPUT,
+ s->root_visual,
+ XCB_CW_OVERRIDE_REDIRECT,
+ values);
+ xcb_map_window (c, xtc->drawable);
+
+ /* slow, but sure */
+ if (xcb_request_check (c, cookie) != NULL) {
+ xcb_disconnect (c);
+ free (xtc);
+ return NULL;
+ }
+
+ surface = cairo_xcb_surface_create (c,
+ xtc->drawable,
+ lookup_visual (s, s->root_visual),
+ width, height);
+
+ xtc->device = cairo_device_reference (cairo_surface_get_device (surface));
+ status = cairo_surface_set_user_data (surface, &xcb_closure_key, xtc, NULL);
+ if (status == CAIRO_STATUS_SUCCESS)
+ return surface;
+
+ cairo_surface_destroy (surface);
+
+ _cairo_boilerplate_xcb_cleanup (xtc);
+ return cairo_boilerplate_surface_create_in_error (status);
+}
+
+static cairo_surface_t *
+_cairo_boilerplate_xcb_create_window_db (const char *name,
+ cairo_content_t content,
+ double width,
+ double height,
+ double max_width,
+ double max_height,
+ cairo_boilerplate_mode_t mode,
+ int id,
+ void **closure)
+{
+ xcb_target_closure_t *xtc;
+ xcb_connection_t *c;
+ xcb_screen_t *s;
+ xcb_void_cookie_t cookie;
+ cairo_surface_t *surface;
+ cairo_status_t status;
+ uint32_t values[] = { 1 };
+
+ *closure = xtc = xmalloc (sizeof (xcb_target_closure_t));
+
+ if (width == 0)
+ width = 1;
+ if (height == 0)
+ height = 1;
+
+ xtc->c = c = xcb_connect(NULL,NULL);
+ if (xcb_connection_has_error(c))
+ return NULL;
+
+ xtc->surface = NULL;
+
+ s = xcb_setup_roots_iterator (xcb_get_setup (c)).data;
+ xtc->is_pixmap = FALSE;
+ xtc->drawable = xcb_generate_id (c);
+ cookie = xcb_create_window_checked (c,
+ s->root_depth,
+ xtc->drawable,
+ s->root,
+ 0, 0, width, height, 0,
+ XCB_WINDOW_CLASS_INPUT_OUTPUT,
+ s->root_visual,
+ XCB_CW_OVERRIDE_REDIRECT,
+ values);
+ xcb_map_window (c, xtc->drawable);
+
+ /* slow, but sure */
+ if (xcb_request_check (c, cookie) != NULL) {
+ xcb_disconnect (c);
+ free (xtc);
return NULL;
}
+ xtc->surface = cairo_xcb_surface_create (c,
+ xtc->drawable,
+ lookup_visual (s, s->root_visual),
+ width, height);
+ surface = cairo_surface_create_similar (xtc->surface, content, width, height);
+
+ xtc->device = cairo_device_reference (cairo_surface_get_device (surface));
+ status = cairo_surface_set_user_data (surface, &xcb_closure_key, xtc, NULL);
+ if (status == CAIRO_STATUS_SUCCESS)
+ return surface;
+
+ cairo_surface_destroy (surface);
+
+ _cairo_boilerplate_xcb_cleanup (xtc);
+ return cairo_boilerplate_surface_create_in_error (status);
+}
+
+static cairo_surface_t *
+_cairo_boilerplate_xcb_create_render_0_0 (const char *name,
+ cairo_content_t content,
+ double width,
+ double height,
+ double max_width,
+ double max_height,
+ cairo_boilerplate_mode_t mode,
+ int id,
+ void **closure)
+{
+ xcb_screen_t *root;
+ xcb_target_closure_t *xtc;
+ xcb_connection_t *c;
+ xcb_render_pictforminfo_t *render_format;
+ int depth;
+ xcb_void_cookie_t cookie;
+ cairo_surface_t *surface, *tmp;
+ cairo_status_t status;
+ void *formats;
+
+ *closure = xtc = xmalloc (sizeof (xcb_target_closure_t));
+
+ if (width == 0)
+ width = 1;
+ if (height == 0)
+ height = 1;
+
+ xtc->c = c = xcb_connect(NULL,NULL);
+ if (xcb_connection_has_error(c))
+ return NULL;
+
root = xcb_setup_roots_iterator(xcb_get_setup(c)).data;
- xtc->pixmap = xcb_generate_id (c);
+ xtc->surface = NULL;
+ xtc->is_pixmap = TRUE;
+ xtc->drawable = xcb_generate_id (c);
switch (content) {
case CAIRO_CONTENT_COLOR:
- cookie = xcb_create_pixmap_checked (c, 24,
- xtc->pixmap, root->root,
+ depth = 24;
+ cookie = xcb_create_pixmap_checked (c, depth,
+ xtc->drawable, root->root,
width, height);
- format = XCB_PICT_STANDARD_RGB_24;
break;
case CAIRO_CONTENT_COLOR_ALPHA:
- cookie = xcb_create_pixmap_checked (c, 32,
- xtc->pixmap, root->root,
+ depth = 32;
+ cookie = xcb_create_pixmap_checked (c, depth,
+ xtc->drawable, root->root,
width, height);
- format = XCB_PICT_STANDARD_ARGB_32;
break;
case CAIRO_CONTENT_ALPHA: /* would be XCB_PICT_STANDARD_A_8 */
default:
- fprintf (stderr, "Invalid content for XCB test: %d\n", content);
+ xcb_disconnect (c);
+ free (xtc);
return NULL;
}
@@ -121,24 +411,127 @@ _cairo_boilerplate_xcb_create_surface (const char *name,
return NULL;
}
- render_format = xcb_render_util_find_standard_format (xcb_render_util_query_formats (c), format);
- if (render_format->id == 0)
+ render_format = find_depth (c, depth, &formats);
+ if (render_format == NULL) {
+ xcb_disconnect (c);
+ free (xtc);
return NULL;
+ }
- surface = cairo_xcb_surface_create_with_xrender_format (c, xtc->pixmap, root,
+ tmp = cairo_xcb_surface_create_with_xrender_format (c, root,
+ xtc->drawable,
+ render_format,
+ width, height);
+
+ cairo_xcb_device_debug_cap_xrender_version (cairo_surface_get_device (tmp),
+ 0, 0);
+ /* recreate with impaired connection */
+ surface = cairo_xcb_surface_create_with_xrender_format (c, root,
+ xtc->drawable,
render_format,
width, height);
+ free (formats);
+ cairo_surface_destroy (tmp);
+ xtc->device = cairo_device_reference (cairo_surface_get_device (surface));
status = cairo_surface_set_user_data (surface, &xcb_closure_key, xtc, NULL);
if (status == CAIRO_STATUS_SUCCESS)
return surface;
cairo_surface_destroy (surface);
- surface = cairo_boilerplate_surface_create_in_error (status);
_cairo_boilerplate_xcb_cleanup (xtc);
+ return cairo_boilerplate_surface_create_in_error (status);
+}
+
+static cairo_surface_t *
+_cairo_boilerplate_xcb_create_fallback (const char *name,
+ cairo_content_t content,
+ double width,
+ double height,
+ double max_width,
+ double max_height,
+ cairo_boilerplate_mode_t mode,
+ int id,
+ void **closure)
+{
+ xcb_target_closure_t *xtc;
+ xcb_connection_t *c;
+ xcb_screen_t *s;
+ xcb_void_cookie_t cookie;
+ cairo_surface_t *tmp, *surface;
+ cairo_status_t status;
+ uint32_t values[] = { 1 };
+
+ *closure = xtc = xmalloc (sizeof (xcb_target_closure_t));
+
+ if (width == 0)
+ width = 1;
+ if (height == 0)
+ height = 1;
+
+ xtc->c = c = xcb_connect (NULL,NULL);
+ if (xcb_connection_has_error(c)) {
+ free (xtc);
+ return NULL;
+ }
+
+ s = xcb_setup_roots_iterator (xcb_get_setup (c)).data;
+ if (width > s->width_in_pixels || height > s->height_in_pixels) {
+ xcb_disconnect (c);
+ free (xtc);
+ return NULL;
+ }
+
+ xtc->surface = NULL;
+ xtc->is_pixmap = FALSE;
+ xtc->drawable = xcb_generate_id (c);
+ cookie = xcb_create_window_checked (c,
+ s->root_depth,
+ xtc->drawable,
+ s->root,
+ 0, 0, width, height, 0,
+ XCB_WINDOW_CLASS_INPUT_OUTPUT,
+ s->root_visual,
+ XCB_CW_OVERRIDE_REDIRECT,
+ values);
+ xcb_map_window (c, xtc->drawable);
+
+ /* slow, but sure */
+ if (xcb_request_check (c, cookie) != NULL) {
+ xcb_disconnect (c);
+ free (xtc);
+ return NULL;
+ }
+
+ tmp = cairo_xcb_surface_create (c,
+ xtc->drawable,
+ lookup_visual (s, s->root_visual),
+ width, height);
+ if (cairo_surface_status (tmp)) {
+ xcb_disconnect (c);
+ free (xtc);
+ return tmp;
+ }
+
+ cairo_xcb_device_debug_cap_xrender_version (cairo_surface_get_device (tmp),
+ -1, -1);
+ /* recreate with impaired connection */
+ surface = cairo_xcb_surface_create (c,
+ xtc->drawable,
+ lookup_visual (s, s->root_visual),
+ width, height);
+ cairo_surface_destroy (tmp);
- return surface;
+ xtc->device = cairo_device_reference (cairo_surface_get_device (surface));
+ status = cairo_surface_set_user_data (surface, &xcb_closure_key, xtc, NULL);
+ if (status == CAIRO_STATUS_SUCCESS)
+ return surface;
+
+ cairo_surface_destroy (surface);
+
+ _cairo_boilerplate_xcb_cleanup (xtc);
+ return cairo_boilerplate_surface_create_in_error (status);
}
static cairo_status_t
@@ -148,20 +541,39 @@ _cairo_boilerplate_xcb_finish_surface (cairo_surface_t *surface)
&xcb_closure_key);
xcb_generic_event_t *ev;
- cairo_surface_flush (surface);
+ if (xtc->surface != NULL) {
+ cairo_t *cr;
+
+ cr = cairo_create (xtc->surface);
+ cairo_surface_set_device_offset (surface, 0, 0);
+ cairo_set_source_surface (cr, surface, 0, 0);
+ cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
+ cairo_paint (cr);
+ cairo_destroy (cr);
+
+ surface = xtc->surface;
+ }
+ cairo_surface_flush (surface);
if (cairo_surface_status (surface))
return cairo_surface_status (surface);
while ((ev = xcb_poll_for_event (xtc->c)) != NULL) {
+ cairo_status_t status = CAIRO_STATUS_SUCCESS;
+
if (ev->response_type == 0 /* trust me! */) {
xcb_generic_error_t *error = (xcb_generic_error_t *) ev;
- fprintf (stderr, "Detected error during xcb run: %d major=%d, minor=%d\n",
+ fprintf (stderr,
+ "Detected error during xcb run: %d major=%d, minor=%d\n",
error->error_code, error->major_code, error->minor_code);
+ free (error);
- return CAIRO_STATUS_WRITE_ERROR;
+ status = CAIRO_STATUS_WRITE_ERROR;
}
+
+ if (status)
+ return status;
}
if (xcb_connection_has_error (xtc->c))
@@ -197,5 +609,65 @@ static const cairo_boilerplate_target_t targets[] = {
_cairo_boilerplate_xcb_cleanup,
_cairo_boilerplate_xcb_synchronize
},
+ {
+ "xcb-window", "xlib", NULL, NULL,
+ CAIRO_SURFACE_TYPE_XCB, CAIRO_CONTENT_COLOR, 1,
+ "cairo_xcb_surface_create_with_xrender_format",
+ _cairo_boilerplate_xcb_create_window,
+ NULL,
+ _cairo_boilerplate_xcb_finish_surface,
+ _cairo_boilerplate_get_image_surface,
+ cairo_surface_write_to_png,
+ _cairo_boilerplate_xcb_cleanup,
+ _cairo_boilerplate_xcb_synchronize
+ },
+ {
+ "xcb-window&", "xlib", NULL, NULL,
+ CAIRO_SURFACE_TYPE_XCB, CAIRO_CONTENT_COLOR, 1,
+ "cairo_xcb_surface_create_with_xrender_format",
+ _cairo_boilerplate_xcb_create_window_db,
+ NULL,
+ _cairo_boilerplate_xcb_finish_surface,
+ _cairo_boilerplate_get_image_surface,
+ cairo_surface_write_to_png,
+ _cairo_boilerplate_xcb_cleanup,
+ _cairo_boilerplate_xcb_synchronize
+ },
+ {
+ "xcb-render-0.0", "xlib-fallback", NULL, NULL,
+ CAIRO_SURFACE_TYPE_XCB, CAIRO_CONTENT_COLOR_ALPHA, 1,
+ "cairo_xcb_surface_create_with_xrender_format",
+ _cairo_boilerplate_xcb_create_render_0_0,
+ NULL,
+ _cairo_boilerplate_xcb_finish_surface,
+ _cairo_boilerplate_get_image_surface,
+ cairo_surface_write_to_png,
+ _cairo_boilerplate_xcb_cleanup,
+ _cairo_boilerplate_xcb_synchronize
+ },
+ {
+ "xcb-render-0.0", "xlib-fallback", NULL, NULL,
+ CAIRO_SURFACE_TYPE_XCB, CAIRO_CONTENT_COLOR, 1,
+ "cairo_xcb_surface_create_with_xrender_format",
+ _cairo_boilerplate_xcb_create_render_0_0,
+ NULL,
+ _cairo_boilerplate_xcb_finish_surface,
+ _cairo_boilerplate_get_image_surface,
+ cairo_surface_write_to_png,
+ _cairo_boilerplate_xcb_cleanup,
+ _cairo_boilerplate_xcb_synchronize
+ },
+ {
+ "xcb-fallback", "xlib-fallback", NULL, NULL,
+ CAIRO_SURFACE_TYPE_XCB, CAIRO_CONTENT_COLOR, 1,
+ "cairo_xcb_surface_create_with_xrender_format",
+ _cairo_boilerplate_xcb_create_fallback,
+ NULL,
+ _cairo_boilerplate_xcb_finish_surface,
+ _cairo_boilerplate_get_image_surface,
+ cairo_surface_write_to_png,
+ _cairo_boilerplate_xcb_cleanup,
+ _cairo_boilerplate_xcb_synchronize
+ },
};
CAIRO_BOILERPLATE (xcb, targets)
diff --git a/build/Makefile.win32.features b/build/Makefile.win32.features
index bd314e9..b8c40a8 100644
--- a/build/Makefile.win32.features
+++ b/build/Makefile.win32.features
@@ -3,6 +3,7 @@
CAIRO_HAS_XLIB_SURFACE=0
CAIRO_HAS_XLIB_XRENDER_SURFACE=0
CAIRO_HAS_XCB_SURFACE=0
+CAIRO_HAS_XLIB_XCB_FUNCTIONS=0
CAIRO_HAS_QT_SURFACE=0
CAIRO_HAS_QUARTZ_SURFACE=0
CAIRO_HAS_QUARTZ_FONT=0
@@ -14,6 +15,7 @@ CAIRO_HAS_OS2_SURFACE=0
CAIRO_HAS_BEOS_SURFACE=0
CAIRO_HAS_DRM_SURFACE=0
CAIRO_HAS_GALLIUM_SURFACE=0
+CAIRO_HAS_XCB_DRM_FUNCTIONS=0
CAIRO_HAS_PNG_FUNCTIONS=1
CAIRO_HAS_GL_SURFACE=0
CAIRO_HAS_GLITZ_SURFACE=0
diff --git a/build/Makefile.win32.features-h b/build/Makefile.win32.features-h
index 7e49cd6..95e9386 100644
--- a/build/Makefile.win32.features-h
+++ b/build/Makefile.win32.features-h
@@ -14,6 +14,9 @@ endif
ifeq ($(CAIRO_HAS_XCB_SURFACE),1)
@echo "#define CAIRO_HAS_XCB_SURFACE 1" >> src/cairo-features.h
endif
+ifeq ($(CAIRO_HAS_XLIB_XCB_FUNCTIONS),1)
+ @echo "#define CAIRO_HAS_XLIB_XCB_FUNCTIONS 1" >> src/cairo-features.h
+endif
ifeq ($(CAIRO_HAS_QT_SURFACE),1)
@echo "#define CAIRO_HAS_QT_SURFACE 1" >> src/cairo-features.h
endif
@@ -47,6 +50,9 @@ endif
ifeq ($(CAIRO_HAS_GALLIUM_SURFACE),1)
@echo "#define CAIRO_HAS_GALLIUM_SURFACE 1" >> src/cairo-features.h
endif
+ifeq ($(CAIRO_HAS_XCB_DRM_FUNCTIONS),1)
+ @echo "#define CAIRO_HAS_XCB_DRM_FUNCTIONS 1" >> src/cairo-features.h
+endif
ifeq ($(CAIRO_HAS_PNG_FUNCTIONS),1)
@echo "#define CAIRO_HAS_PNG_FUNCTIONS 1" >> src/cairo-features.h
endif
diff --git a/build/configure.ac.features b/build/configure.ac.features
index e057e2c..c55b4ef 100644
--- a/build/configure.ac.features
+++ b/build/configure.ac.features
@@ -393,6 +393,8 @@ AC_DEFUN([CAIRO_REPORT],
echo " GLX functions: $use_glx"
echo " EGL functions: $use_egl"
echo " Eagle functions: $use_eagle"
+ echo " X11-xcb functions: $use_xlib_xcb"
+ echo " XCB-drm functions: $use_xcb_drm"
echo ""
echo "The following features and utilies:"
echo " cairo-trace: $use_trace"
diff --git a/configure.ac b/configure.ac
index d704353..f94d9c1 100644
--- a/configure.ac
+++ b/configure.ac
@@ -109,10 +109,22 @@ CAIRO_ENABLE_SURFACE_BACKEND(xlib_xrender, Xlib Xrender, auto, [
dnl ===========================================================================
CAIRO_ENABLE_SURFACE_BACKEND(xcb, XCB, no, [
- xcb_REQUIRES="xcb >= 0.9.92 xcb-render >= 0.9.92 xcb-renderutil"
- PKG_CHECK_MODULES(xcb, $xcb_REQUIRES, , [AC_MSG_RESULT(no)
- use_xcb="no (requires $xcb_REQUIRES http://xcb.freedesktop.org)"])
+ xcb_REQUIRES="xcb >= 0.9.92 xcb-render >= 0.9.92 xcb-shm xcb-dri2"
+ PKG_CHECK_MODULES(xcb, $xcb_REQUIRES, ,
+ [AC_MSG_RESULT(no)
+ use_xcb="no (requires $xcb_REQUIRES http://xcb.freedesktop.org)"])
+])
+
+CAIRO_ENABLE_FUNCTIONS(xlib_xcb, Xlib/XCB, no, [
+ if test "x$use_xcb" == "xyes" -a "x$use_xlib" == "xyes"; then
+ xlib_xcb_REQUIRES="x11-xcb"
+ PKG_CHECK_MODULES(xlib_xcb, $xlib_xcb_REQUIRES, ,
+ [use_xlib_xcb="no (requires $xlib_xcb_REQUIRES http://xcb.freedesktop.org)"])
+ else
+ use_xlib_xcb="no (requires both --enable-xlib and --enable-xcb)"
+ fi
])
+AM_CONDITIONAL(BUILD_XLIB_XCB, test "x$use_xlib_xcb" = "xyes")
dnl ===========================================================================
@@ -241,6 +253,14 @@ CAIRO_ENABLE_SURFACE_BACKEND(gallium, Gallium3D, no, [
fi
])
+CAIRO_ENABLE_FUNCTIONS(xcb_drm, XCB/DRM, no, [
+ if test "x$use_xcb" == "xyes" -a "x$use_drm" == "xyes"; then
+ use_xcb_drm="yes"
+ else
+ use_xcb_drm="no (requires both --enable-xcb and --enable-drm)"
+ fi
+])
+
dnl ===========================================================================
CAIRO_ENABLE_FUNCTIONS(png, PNG, yes, [
diff --git a/src/Makefile.sources b/src/Makefile.sources
index f6d4fe3..0f77f0e 100644
--- a/src/Makefile.sources
+++ b/src/Makefile.sources
@@ -250,19 +250,33 @@ cairo_xlib_private = \
cairo-xlib-surface-private.h \
cairo-xlib-xrender-private.h \
$(NULL)
+if BUILD_XLIB_XCB
+cairo_xlib_sources = cairo-xlib-xcb-surface.c
+else
cairo_xlib_sources = \
cairo-xlib-display.c \
cairo-xlib-screen.c \
cairo-xlib-surface.c \
cairo-xlib-visual.c \
$(NULL)
+endif
cairo_xlib_xrender_headers = cairo-xlib-xrender.h
-# XXX split xcb-xrender. or better yet, merge it into xcb. xcb is so recent
-# that it's hard to imagine having xcb but not render.
-cairo_xcb_headers = cairo-xcb.h cairo-xcb-xrender.h
-cairo_xcb_sources = cairo-xcb-surface.c
+cairo_xcb_headers = cairo-xcb.h
+cairo_xcb_private = cairo-xcb-private.h
+cairo_xcb_sources = \
+ cairo-xcb-connection.c \
+ cairo-xcb-connection-core.c \
+ cairo-xcb-connection-render.c \
+ cairo-xcb-connection-shm.c \
+ cairo-xcb-screen.c \
+ cairo-xcb-shm.c \
+ cairo-xcb-surface.c \
+ cairo-xcb-surface-cairo.c \
+ cairo-xcb-surface-core.c \
+ cairo-xcb-surface-render.c \
+ $(NULL)
cairo_qt_headers = cairo-qt.h
cairo_qt_sources = cairo-qt-surface.cpp
diff --git a/src/Makefile.win32.features b/src/Makefile.win32.features
index 048c921..3575057 100644
--- a/src/Makefile.win32.features
+++ b/src/Makefile.win32.features
@@ -63,6 +63,20 @@ ifeq ($(CAIRO_HAS_XCB_SURFACE),1)
enabled_cairo_pkgconf += cairo-xcb.pc
endif
+unsupported_cairo_headers += $(cairo_xlib_xcb_headers)
+all_cairo_headers += $(cairo_xlib_xcb_headers)
+all_cairo_private += $(cairo_xlib_xcb_private)
+all_cairo_sources += $(cairo_xlib_xcb_sources)
+ifeq ($(CAIRO_HAS_XLIB_XCB_FUNCTIONS),1)
+enabled_cairo_headers += $(cairo_xlib_xcb_headers)
+enabled_cairo_private += $(cairo_xlib_xcb_private)
+enabled_cairo_sources += $(cairo_xlib_xcb_sources)
+endif
+all_cairo_pkgconf += cairo-xlib-xcb.pc
+ifeq ($(CAIRO_HAS_XLIB_XCB_FUNCTIONS),1)
+enabled_cairo_pkgconf += cairo-xlib-xcb.pc
+endif
+
unsupported_cairo_headers += $(cairo_qt_headers)
all_cairo_headers += $(cairo_qt_headers)
all_cairo_private += $(cairo_qt_private)
@@ -217,6 +231,20 @@ ifeq ($(CAIRO_HAS_GALLIUM_SURFACE),1)
enabled_cairo_pkgconf += cairo-gallium.pc
endif
+unsupported_cairo_headers += $(cairo_xcb_drm_headers)
+all_cairo_headers += $(cairo_xcb_drm_headers)
+all_cairo_private += $(cairo_xcb_drm_private)
+all_cairo_sources += $(cairo_xcb_drm_sources)
+ifeq ($(CAIRO_HAS_XCB_DRM_FUNCTIONS),1)
+enabled_cairo_headers += $(cairo_xcb_drm_headers)
+enabled_cairo_private += $(cairo_xcb_drm_private)
+enabled_cairo_sources += $(cairo_xcb_drm_sources)
+endif
+all_cairo_pkgconf += cairo-xcb-drm.pc
+ifeq ($(CAIRO_HAS_XCB_DRM_FUNCTIONS),1)
+enabled_cairo_pkgconf += cairo-xcb-drm.pc
+endif
+
supported_cairo_headers += $(cairo_png_headers)
all_cairo_headers += $(cairo_png_headers)
all_cairo_private += $(cairo_png_private)
diff --git a/src/cairo-list-private.h b/src/cairo-list-private.h
index b8254bb..6d65bf1 100644
--- a/src/cairo-list-private.h
+++ b/src/cairo-list-private.h
@@ -186,4 +186,11 @@ cairo_list_is_empty (const cairo_list_t *head)
return head->next == head;
}
+static inline cairo_bool_t
+cairo_list_is_singular (const cairo_list_t *head)
+{
+ cairo_list_validate (head);
+ return head->next == head || head->next == head->prev;
+}
+
#endif /* CAIRO_LIST_PRIVATE_H */
diff --git a/src/cairo-mutex-list-private.h b/src/cairo-mutex-list-private.h
index c84cebf..aa2c8f8 100644
--- a/src/cairo-mutex-list-private.h
+++ b/src/cairo-mutex-list-private.h
@@ -54,6 +54,10 @@ CAIRO_MUTEX_DECLARE (_cairo_ft_unscaled_font_map_mutex)
CAIRO_MUTEX_DECLARE (_cairo_xlib_display_mutex)
#endif
+#if CAIRO_HAS_XCB_SURFACE
+CAIRO_MUTEX_DECLARE (_cairo_xcb_connections_mutex)
+#endif
+
#if CAIRO_HAS_GL_SURFACE
CAIRO_MUTEX_DECLARE (_cairo_gl_context_mutex)
#endif
diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c
index e77f153..aae1aa5 100644
--- a/src/cairo-pattern.c
+++ b/src/cairo-pattern.c
@@ -2628,23 +2628,20 @@ _cairo_gradient_color_stops_hash (unsigned long hash,
return hash;
}
-static unsigned long
+unsigned long
_cairo_linear_pattern_hash (unsigned long hash,
- const cairo_pattern_t *pattern)
+ const cairo_linear_pattern_t *linear)
{
- const cairo_linear_pattern_t *linear = (cairo_linear_pattern_t *) pattern;
-
hash = _cairo_hash_bytes (hash, &linear->p1, sizeof (linear->p1));
hash = _cairo_hash_bytes (hash, &linear->p2, sizeof (linear->p2));
return _cairo_gradient_color_stops_hash (hash, &linear->base);
}
-static unsigned long
-_cairo_radial_pattern_hash (unsigned long hash, const cairo_pattern_t *pattern)
+unsigned long
+_cairo_radial_pattern_hash (unsigned long hash,
+ const cairo_radial_pattern_t *radial)
{
- const cairo_radial_pattern_t *radial = (cairo_radial_pattern_t *) pattern;
-
hash = _cairo_hash_bytes (hash, &radial->c1, sizeof (radial->c1));
hash = _cairo_hash_bytes (hash, &radial->r1, sizeof (radial->r1));
hash = _cairo_hash_bytes (hash, &radial->c2, sizeof (radial->c2));
@@ -2689,9 +2686,9 @@ _cairo_pattern_hash (const cairo_pattern_t *pattern)
case CAIRO_PATTERN_TYPE_SOLID:
return _cairo_solid_pattern_hash (hash, pattern);
case CAIRO_PATTERN_TYPE_LINEAR:
- return _cairo_linear_pattern_hash (hash, pattern);
+ return _cairo_linear_pattern_hash (hash, (cairo_linear_pattern_t *) pattern);
case CAIRO_PATTERN_TYPE_RADIAL:
- return _cairo_radial_pattern_hash (hash, pattern);
+ return _cairo_radial_pattern_hash (hash, (cairo_radial_pattern_t *) pattern);
case CAIRO_PATTERN_TYPE_SURFACE:
return _cairo_surface_pattern_hash (hash, pattern);
default:
@@ -2768,13 +2765,10 @@ _cairo_gradient_color_stops_equal (const cairo_gradient_pattern_t *a,
return TRUE;
}
-static cairo_bool_t
-_cairo_linear_pattern_equal (const cairo_pattern_t *A,
- const cairo_pattern_t *B)
+cairo_bool_t
+_cairo_linear_pattern_equal (const cairo_linear_pattern_t *a,
+ const cairo_linear_pattern_t *b)
{
- const cairo_linear_pattern_t *a = (cairo_linear_pattern_t *) A;
- const cairo_linear_pattern_t *b = (cairo_linear_pattern_t *) B;
-
if (a->p1.x != b->p1.x)
return FALSE;
@@ -2790,13 +2784,10 @@ _cairo_linear_pattern_equal (const cairo_pattern_t *A,
return _cairo_gradient_color_stops_equal (&a->base, &b->base);
}
-static cairo_bool_t
-_cairo_radial_pattern_equal (const cairo_pattern_t *A,
- const cairo_pattern_t *B)
+cairo_bool_t
+_cairo_radial_pattern_equal (const cairo_radial_pattern_t *a,
+ const cairo_radial_pattern_t *b)
{
- const cairo_radial_pattern_t *a = (cairo_radial_pattern_t *) A;
- const cairo_radial_pattern_t *b = (cairo_radial_pattern_t *) B;
-
if (a->c1.x != b->c1.x)
return FALSE;
@@ -2858,9 +2849,11 @@ _cairo_pattern_equal (const cairo_pattern_t *a, const cairo_pattern_t *b)
case CAIRO_PATTERN_TYPE_SOLID:
return _cairo_solid_pattern_equal (a, b);
case CAIRO_PATTERN_TYPE_LINEAR:
- return _cairo_linear_pattern_equal (a, b);
+ return _cairo_linear_pattern_equal ((cairo_linear_pattern_t *) a,
+ (cairo_linear_pattern_t *) b);
case CAIRO_PATTERN_TYPE_RADIAL:
- return _cairo_radial_pattern_equal (a, b);
+ return _cairo_radial_pattern_equal ((cairo_radial_pattern_t *) a,
+ (cairo_radial_pattern_t *) b);
case CAIRO_PATTERN_TYPE_SURFACE:
return _cairo_surface_pattern_equal (a, b);
default:
diff --git a/src/cairo-xcb-connection-core.c b/src/cairo-xcb-connection-core.c
new file mode 100644
index 0000000..22a340d
--- /dev/null
+++ b/src/cairo-xcb-connection-core.c
@@ -0,0 +1,482 @@
+/* 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.
+ *
+ * Contributor(s):
+ * Chris Wilson <chris at chris-wilson.co.uk>
+ */
+
+#include "cairoint.h"
+
+#include "cairo-xcb-private.h"
+
+#include <xcb/xcbext.h>
+
+xcb_pixmap_t
+_cairo_xcb_connection_create_pixmap (cairo_xcb_connection_t *connection,
+ uint8_t depth,
+ xcb_drawable_t drawable,
+ uint16_t width,
+ uint16_t height)
+{
+ struct {
+ uint8_t req;
+ uint8_t depth;
+ uint16_t len;
+ uint32_t pixmap;
+ uint32_t drawable;
+ uint16_t width, height;
+ } req;
+ struct iovec vec[1];
+
+ req.req = 53;
+ req.depth = depth;
+ req.len = sizeof (req) >> 2;
+
+ req.pixmap = _cairo_xcb_connection_get_xid (connection);
+ req.drawable = drawable;
+ req.width = width;
+ req.height = height;
+
+ vec[0].iov_base = &req;
+ vec[0].iov_len = sizeof (req);
+
+ _cairo_xcb_connection_write (connection, vec, 1);
+
+ return req.pixmap;
+}
+
+void
+_cairo_xcb_connection_free_pixmap (cairo_xcb_connection_t *connection,
+ xcb_pixmap_t pixmap)
+{
+ struct {
+ uint8_t req;
+ uint8_t pad;
+ uint16_t len;
+ uint32_t pixmap;
+ } req;
+ struct iovec vec[1];
+
+ req.req = 54;
+ req.len = sizeof (req) >> 2;
+ req.pixmap = pixmap;
+
+ vec[0].iov_base = &req;
+ vec[0].iov_len = sizeof (req);
+
+ _cairo_xcb_connection_write (connection, vec, 1);
+ _cairo_xcb_connection_put_xid (connection, pixmap);
+}
+
+xcb_gcontext_t
+_cairo_xcb_connection_create_gc (cairo_xcb_connection_t *connection,
+ xcb_drawable_t drawable,
+ uint32_t value_mask,
+ uint32_t *values)
+{
+ struct {
+ uint8_t req;
+ uint8_t pad;
+ uint16_t len;
+ uint32_t gc;
+ uint32_t drawable;
+ uint32_t mask;
+ } req;
+ struct iovec vec[2];
+ int len = _cairo_popcount (value_mask) * 4;
+
+ req.req = 55;
+ req.len = (sizeof (req) + len) >> 2;
+ req.gc = _cairo_xcb_connection_get_xid (connection);
+ req.drawable = drawable;
+ req.mask = value_mask;
+
+ vec[0].iov_base = &req;
+ vec[0].iov_len = sizeof (req);
+ vec[1].iov_base = values;
+ vec[1].iov_len = len;
+
+ _cairo_xcb_connection_write (connection, vec, 2);
+
+ return req.gc;
+}
+
+void
+_cairo_xcb_connection_free_gc (cairo_xcb_connection_t *connection,
+ xcb_gcontext_t gc)
+{
+ struct {
+ uint8_t req;
+ uint8_t pad;
+ uint16_t len;
+ uint32_t gc;
+ } req;
+ struct iovec vec[1];
+
+ req.req = 60;
+ req.len = sizeof (req) >> 2;
+ req.gc = gc;
+
+ vec[0].iov_base = &req;
+ vec[0].iov_len = sizeof (req);
+
+ _cairo_xcb_connection_write (connection, vec, 1);
+ _cairo_xcb_connection_put_xid (connection, gc);
+}
+
+void
+_cairo_xcb_connection_change_gc (cairo_xcb_connection_t *connection,
+ xcb_gcontext_t gc,
+ uint32_t value_mask,
+ uint32_t *values)
+{
+ struct {
+ uint8_t req;
+ uint8_t pad;
+ uint16_t len;
+ uint32_t gc;
+ uint32_t mask;
+ } req;
+ struct iovec vec[2];
+ int len = _cairo_popcount (value_mask) * 4;
+
+ req.req = 56;
+ req.len = (sizeof (req) + len) >> 2;
+ req.gc = gc;
+ req.mask = value_mask;
+
+ vec[0].iov_base = &req;
+ vec[0].iov_len = sizeof (req);
+ vec[1].iov_base = values;
+ vec[1].iov_len = len;
+
+ _cairo_xcb_connection_write (connection, vec, 2);
+}
+
+void
+_cairo_xcb_connection_copy_area (cairo_xcb_connection_t *connection,
+ xcb_drawable_t src,
+ xcb_drawable_t dst,
+ xcb_gcontext_t gc,
+ int16_t src_x,
+ int16_t src_y,
+ int16_t dst_x,
+ int16_t dst_y,
+ uint16_t width,
+ uint16_t height)
+{
+ struct {
+ uint8_t req;
+ uint8_t pad;
+ uint16_t len;
+ uint32_t src;
+ uint32_t dst;
+ uint32_t gc;
+ int16_t src_x;
+ int16_t src_y;
+ int16_t dst_x;
+ int16_t dst_y;
+ uint16_t width;
+ uint16_t height;
+ } req;
+ struct iovec vec[1];
+
+ req.req = 62;
+ req.len = sizeof (req) >> 2;
+ req.src = src;
+ req.dst = dst;
+ req.gc = gc;
+ req.src_x = src_x;
+ req.src_y = src_y;
+ req.dst_x = dst_x;
+ req.dst_y = dst_y;
+ req.width = width;
+ req.height = height;
+
+ vec[0].iov_base = &req;
+ vec[0].iov_len = sizeof (req);
+
+ _cairo_xcb_connection_write (connection, vec, 1);
+}
+
+void
+_cairo_xcb_connection_poly_fill_rectangle (cairo_xcb_connection_t *connection,
+ xcb_drawable_t dst,
+ xcb_gcontext_t gc,
+ uint32_t num_rectangles,
+ xcb_rectangle_t *rectangles)
+{
+ struct {
+ uint8_t req;
+ uint8_t pad;
+ uint16_t len;
+ uint32_t dst;
+ uint32_t gc;
+ } req;
+ struct iovec vec[2];
+
+ req.req = 70;
+ req.len = (sizeof (req) + num_rectangles * sizeof (xcb_rectangle_t)) >> 2;
+ req.dst = dst;
+ req.gc = gc;
+
+ vec[0].iov_base = &req;
+ vec[0].iov_len = sizeof (req);
+ vec[1].iov_base = rectangles;
+ vec[1].iov_len = num_rectangles * sizeof (xcb_rectangle_t);
+
+ _cairo_xcb_connection_write (connection, vec, 2);
+}
+
+void
+_cairo_xcb_connection_put_image (cairo_xcb_connection_t *connection,
+ xcb_drawable_t dst,
+ xcb_gcontext_t gc,
+ uint16_t width,
+ uint16_t height,
+ int16_t dst_x,
+ int16_t dst_y,
+ uint8_t depth,
+ uint32_t stride,
+ void *data)
+{
+ struct {
+ uint8_t req;
+ uint8_t format;
+ uint16_t len;
+ uint32_t dst;
+ uint32_t gc;
+ uint16_t width;
+ uint16_t height;
+ int16_t dst_x;
+ int16_t dst_y;
+ uint8_t left;
+ uint8_t depth;
+ uint16_t pad;
+ } req;
+ struct iovec vec[3];
+ uint32_t prefix[2];
+ uint32_t length = height * stride;
+ uint32_t len = (sizeof (req) + length) >> 2;
+
+ req.req = 72;
+ req.format = XCB_IMAGE_FORMAT_Z_PIXMAP;
+ req.len = 0;
+ req.dst = dst;
+ req.gc = gc;
+ req.width = width;
+ req.height = height;
+ req.dst_x = dst_x;
+ req.dst_y = dst_y;
+ req.left = 0;
+ req.depth = depth;
+
+ if (len < connection->root->maximum_request_length) {
+ req.len = len;
+
+ vec[0].iov_base = &req;
+ vec[0].iov_len = sizeof (req);
+ vec[1].iov_base = data;
+ vec[1].iov_len = length;
+
+ _cairo_xcb_connection_write (connection, vec, 2);
+ } else if (len < connection->maximum_request_length) {
+ prefix[0] = *(uint32_t *) &req;
+ prefix[1] = len + 1;
+ vec[0].iov_base = prefix;
+ vec[0].iov_len = sizeof (prefix);
+ vec[1].iov_base = (uint32_t *) &req + 1;
+ vec[1].iov_len = sizeof (req) - 4;
+ vec[2].iov_base = data;
+ vec[2].iov_len = length;
+
+ _cairo_xcb_connection_write (connection, vec, 3);
+ } else {
+ int rows;
+
+ rows = (connection->maximum_request_length - sizeof (req) - 4) / stride;
+ if (rows > 0) {
+ do {
+ if (rows > height)
+ rows = height;
+
+ length = rows * stride;
+ len = (sizeof (req) + 4 + length) >> 2;
+
+ req.height = rows;
+
+ prefix[0] = *(uint32_t *) &req;
+ prefix[1] = len;
+
+ vec[0].iov_base = prefix;
+ vec[0].iov_len = sizeof (prefix);
+ vec[1].iov_base = (uint32_t *) &req + 1;
+ vec[1].iov_len = sizeof (req) - 4;
+ vec[2].iov_base = data;
+ vec[2].iov_len = length;
+
+ /* note may modify vec */
+ _cairo_xcb_connection_write (connection, vec, 3);
+
+ height -= rows;
+ req.dst_y += rows;
+ data = (char *) data + length;
+ } while (height);
+ } else {
+ ASSERT_NOT_REACHED;
+ }
+ }
+}
+
+void
+_cairo_xcb_connection_put_subimage (cairo_xcb_connection_t *connection,
+ xcb_drawable_t dst,
+ xcb_gcontext_t gc,
+ int16_t src_x,
+ int16_t src_y,
+ uint16_t width,
+ uint16_t height,
+ uint16_t cpp,
+ uint16_t stride,
+ int16_t dst_x,
+ int16_t dst_y,
+ uint8_t depth,
+ void *_data)
+{
+ struct {
+ uint8_t req;
+ uint8_t format;
+ uint16_t len;
+ uint32_t dst;
+ uint32_t gc;
+ uint16_t width;
+ uint16_t height;
+ int16_t dst_x;
+ int16_t dst_y;
+ uint8_t left;
+ uint8_t depth;
+ uint16_t pad;
+ } req;
+ struct iovec vec_stack[CAIRO_STACK_ARRAY_LENGTH (struct iovec)];
+ struct iovec *vec = vec_stack;
+ uint32_t prefix[2];
+ uint32_t len = (sizeof (req) + cpp*width*height) >> 2;
+ uint8_t *data = _data;
+ int n;
+
+ req.req = 72;
+ req.format = XCB_IMAGE_FORMAT_Z_PIXMAP;
+ req.len = 0;
+ req.dst = dst;
+ req.gc = gc;
+ req.width = width;
+ req.height = height;
+ req.dst_x = dst_x;
+ req.dst_y = dst_y;
+ req.left = 0;
+ req.depth = depth;
+
+ if (height + 2 > ARRAY_LENGTH (vec_stack)) {
+ vec = _cairo_malloc_ab (height+2, sizeof (struct iovec));
+ if (unlikely (vec == NULL)) {
+ /* XXX loop over ARRAY_LENGTH (vec_stack) */
+ return;
+ }
+ }
+
+ data += src_y * stride + src_x * cpp;
+ if (len < connection->root->maximum_request_length) {
+ req.len = len;
+
+ vec[0].iov_base = &req;
+ vec[0].iov_len = sizeof (req);
+
+ n = 1;
+ } else if (len < connection->maximum_request_length) {
+ prefix[0] = *(uint32_t *) &req;
+ prefix[1] = len + 1;
+ vec[0].iov_base = prefix;
+ vec[0].iov_len = sizeof (prefix);
+ vec[1].iov_base = (uint32_t *) &req + 1;
+ vec[1].iov_len = sizeof (req) - 4;
+
+ n = 2;
+ } else {
+ ASSERT_NOT_REACHED;
+ }
+
+ while (height--) {
+ vec[n].iov_base = data;
+ vec[n].iov_len = cpp * width;
+ data += stride;
+ n++;
+ }
+
+ _cairo_xcb_connection_write (connection, vec, n);
+
+ if (vec != vec_stack)
+ free (vec);
+}
+
+cairo_status_t
+_cairo_xcb_connection_get_image (cairo_xcb_connection_t *connection,
+ xcb_drawable_t src,
+ int16_t src_x,
+ int16_t src_y,
+ uint16_t width,
+ uint16_t height,
+ xcb_get_image_reply_t **reply)
+{
+ xcb_generic_error_t *error;
+ cairo_status_t status;
+
+ *reply = xcb_get_image_reply (connection->xcb_connection,
+ xcb_get_image (connection->xcb_connection,
+ XCB_IMAGE_FORMAT_Z_PIXMAP,
+ src,
+ src_x, src_y,
+ width, height,
+ (uint32_t) -1),
+
+ &error);
+ if (error) {
+ free (error);
+
+ if (*reply)
+ free (*reply);
+ *reply = NULL;
+ }
+
+ status = _cairo_xcb_connection_take_socket (connection);
+ if (unlikely (status)) {
+ if (*reply)
+ free (*reply);
+ *reply = NULL;
+ }
+
+ return status;
+}
diff --git a/src/cairo-xcb-connection-render.c b/src/cairo-xcb-connection-render.c
new file mode 100644
index 0000000..2ebd6b4
--- /dev/null
+++ b/src/cairo-xcb-connection-render.c
@@ -0,0 +1,969 @@
+/* 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.
+ *
+ * Contributor(s):
+ * Chris Wilson <chris at chris-wilson.co.uk>
+ */
+
+#include "cairoint.h"
+
+#include "cairo-xcb-private.h"
+
+#include <xcb/xcbext.h>
+
+#define X_RenderSpans 99
+#define XLIB_COORD_MAX 32767
+
+void
+_cairo_xcb_connection_render_create_picture (cairo_xcb_connection_t *connection,
+ xcb_render_picture_t picture,
+ xcb_drawable_t drawable,
+ xcb_render_pictformat_t format,
+ uint32_t value_mask,
+ uint32_t *value_list)
+{
+ struct {
+ uint8_t major;
+ uint8_t minor;
+ uint16_t length;
+ uint32_t picture;
+ uint32_t drawable;
+ uint32_t format;
+ uint32_t mask;
+ } req;
+ struct iovec vec[2];
+ int len = _cairo_popcount (value_mask) * 4;
+
+ COMPILE_TIME_ASSERT (sizeof (req) == 20);
+
+ req.major = connection->render->major_opcode;
+ req.minor = 4;
+ req.length = (sizeof (req) + len) >> 2;
+ req.picture = picture;
+ req.drawable = drawable;
+ req.format = format;
+ req.mask = value_mask;
+
+ vec[0].iov_base = &req;
+ vec[0].iov_len = sizeof (req);
+ vec[1].iov_base = value_list;
+ vec[1].iov_len = len;
+
+ _cairo_xcb_connection_write (connection, vec, 1 + (len != 0));
+}
+
+void
+_cairo_xcb_connection_render_change_picture (cairo_xcb_connection_t *connection,
+ xcb_render_picture_t picture,
+ uint32_t value_mask,
+ uint32_t *value_list)
+{
+ struct {
+ uint8_t major;
+ uint8_t minor;
+ uint16_t length;
+ uint32_t picture;
+ uint32_t mask;
+ } req;
+ struct iovec vec[2];
+ int len = _cairo_popcount (value_mask) * 4;
+
+ COMPILE_TIME_ASSERT (sizeof (req) == 12);
+
+ req.major = connection->render->major_opcode;
+ req.minor = 5;
+ req.length = (sizeof (req) + len) >> 2;
+ req.picture = picture;
+ req.mask = value_mask;
+
+ vec[0].iov_base = &req;
+ vec[0].iov_len = sizeof (req);
+ vec[1].iov_base = value_list;
+ vec[1].iov_len = len;
+
+ _cairo_xcb_connection_write (connection, vec, 2);
+}
+
+void
+_cairo_xcb_connection_render_set_picture_clip_rectangles (cairo_xcb_connection_t *connection,
+ xcb_render_picture_t picture,
+ int16_t clip_x_origin,
+ int16_t clip_y_origin,
+ uint32_t rectangles_len,
+ xcb_rectangle_t *rectangles)
+{
+ struct {
+ uint8_t major;
+ uint8_t minor;
+ uint16_t length;
+ uint32_t picture;
+ uint16_t x;
+ uint16_t y;
+ } req;
+ struct iovec vec[2];
+ int len = sizeof (xcb_rectangle_t) * rectangles_len;
+
+ COMPILE_TIME_ASSERT (sizeof (req) == 12);
+ assert ((len + sizeof (req)) >> 2 < connection->root->maximum_request_length);
+
+ req.major = connection->render->major_opcode;
+ req.minor = 6;
+ req.length = (sizeof (req) + len) >> 2;
+ req.picture = picture;
+ req.x = clip_x_origin;
+ req.y = clip_y_origin;
+
+ vec[0].iov_base = &req;
+ vec[0].iov_len = sizeof (req);
+ vec[1].iov_base = rectangles;
+ vec[1].iov_len = len;
+
+ _cairo_xcb_connection_write (connection, vec, 2);
+}
+
+void
+_cairo_xcb_connection_render_free_picture (cairo_xcb_connection_t *connection,
+ xcb_render_picture_t picture)
+{
+ struct {
+ uint8_t major;
+ uint8_t minor;
+ uint16_t length;
+ uint32_t picture;
+ } req;
+ struct iovec vec[1];
+
+ COMPILE_TIME_ASSERT (sizeof (req) == 8);
+
+ req.major = connection->render->major_opcode;
+ req.minor = 7;
+ req.length = sizeof (req) >> 2;
+ req.picture = picture;
+
+ vec[0].iov_base = &req;
+ vec[0].iov_len = sizeof (req);
+
+ _cairo_xcb_connection_write (connection, vec, 1);
+ _cairo_xcb_connection_put_xid (connection, picture);
+}
+
+void
+_cairo_xcb_connection_render_composite (cairo_xcb_connection_t *connection,
+ uint8_t op,
+ xcb_render_picture_t src,
+ xcb_render_picture_t mask,
+ xcb_render_picture_t dst,
+ int16_t src_x,
+ int16_t src_y,
+ int16_t mask_x,
+ int16_t mask_y,
+ int16_t dst_x,
+ int16_t dst_y,
+ uint16_t width,
+ uint16_t height)
+{
+ struct {
+ uint8_t major;
+ uint8_t minor;
+ uint16_t length;
+ uint8_t op;
+ uint8_t pad1;
+ uint16_t pad2;
+ uint32_t src;
+ uint32_t mask;
+ uint32_t dst;
+ int16_t src_x;
+ int16_t src_y;
+ int16_t mask_x;
+ int16_t mask_y;
+ int16_t dst_x;
+ int16_t dst_y;
+ uint16_t width;
+ uint16_t height;
+ } req;
+ struct iovec vec[1];
+
+ COMPILE_TIME_ASSERT (sizeof (req) == 36);
+
+ req.major = connection->render->major_opcode;
+ req.minor = 8;
+ req.length = sizeof (req) >> 2;
+ req.op = op;
+ req.src = src;
+ req.mask = mask;
+ req.dst = dst;
+ req.src_x = src_x;
+ req.src_y = src_y;
+ req.mask_x = mask_x;
+ req.mask_y = mask_y;
+ req.dst_x = dst_x;
+ req.dst_y = dst_y;
+ req.width = width;
+ req.height = height;
+
+ vec[0].iov_base = &req;
+ vec[0].iov_len = sizeof (req);
+
+ _cairo_xcb_connection_write (connection, vec, 1);
+}
+
+void
+_cairo_xcb_connection_render_trapezoids (cairo_xcb_connection_t *connection,
+ uint8_t op,
+ xcb_render_picture_t src,
+ xcb_render_picture_t dst,
+ xcb_render_pictformat_t mask_format,
+ int16_t src_x,
+ int16_t src_y,
+ uint32_t traps_len,
+ xcb_render_trapezoid_t *traps)
+{
+ struct {
+ uint8_t major;
+ uint8_t minor;
+ uint16_t length;
+ uint8_t op;
+ uint8_t pad1;
+ uint16_t pad2;
+ uint32_t src;
+ uint32_t dst;
+ uint32_t mask_format;
+ int16_t src_x;
+ int16_t src_y;
+ } req;
+ struct iovec vec[3];
+ uint32_t prefix[2];
+ uint32_t len = (sizeof (req) + traps_len * sizeof (xcb_render_trapezoid_t)) >> 2;
+
+ COMPILE_TIME_ASSERT (sizeof (req) == 24);
+
+ req.major = connection->render->major_opcode;
+ req.minor = 10;
+ req.length = 0;
+ req.op = op;
+ req.src = src;
+ req.dst = dst;
+ req.mask_format = mask_format;
+ req.src_x = src_x;
+ req.src_y = src_y;
+
+ if (len < connection->root->maximum_request_length) {
+ req.length = len;
+
+ vec[0].iov_base = &req;
+ vec[0].iov_len = sizeof (req);
+ vec[1].iov_base = traps;
+ vec[1].iov_len = traps_len * sizeof (xcb_render_trapezoid_t);
+
+ _cairo_xcb_connection_write (connection, vec, 2);
+ } else {
+ prefix[0] = *(uint32_t *) &req;
+ prefix[1] = len + 1;
+ vec[0].iov_base = prefix;
+ vec[0].iov_len = sizeof (prefix);
+ vec[1].iov_base = (uint32_t *) &req + 1;
+ vec[1].iov_len = sizeof (req) - 4;
+ vec[2].iov_base = traps;
+ vec[2].iov_len = traps_len * sizeof (xcb_render_trapezoid_t);
+
+ _cairo_xcb_connection_write (connection, vec, 3);
+ }
+}
+
+void
+_cairo_xcb_connection_render_spans (cairo_xcb_connection_t *connection,
+ xcb_render_picture_t dst,
+ int op,
+ xcb_render_picture_t src,
+ int16_t src_x, int16_t src_y,
+ int16_t dst_x, int16_t dst_y,
+ int16_t width, int16_t height,
+ uint32_t num_spans,
+ uint16_t *spans)
+{
+ struct {
+ uint8_t major;
+ uint8_t minor;
+ uint16_t length;
+ uint8_t op;
+ uint8_t pad1;
+ uint16_t pad2;
+ uint32_t src;
+ uint32_t dst;
+ int16_t src_x;
+ int16_t src_y;
+ int16_t dst_x;
+ int16_t dst_y;
+ uint16_t width;
+ uint16_t height;
+ } req;
+ struct iovec vec[3];
+ uint32_t prefix[2];
+ uint32_t len = (sizeof (req) + num_spans * sizeof (uint16_t)) >> 2;
+
+ req.major = connection->render->major_opcode;
+ req.minor = X_RenderSpans;
+ req.length = 0;
+
+ req.dst = dst;
+ req.op = op;
+ req.src = src;
+ req.src_x = src_x;
+ req.src_y = src_y;
+ req.dst_x = dst_x;
+ req.dst_y = dst_y;
+ req.width = width;
+ req.height = height;
+
+ if (len < connection->root->maximum_request_length) {
+ req.length = len;
+
+ vec[0].iov_base = &req;
+ vec[0].iov_len = sizeof (req);
+ vec[1].iov_base = spans;
+ vec[1].iov_len = num_spans * sizeof (uint16_t);
+
+ _cairo_xcb_connection_write (connection, vec, 2);
+ } else {
+ prefix[0] = *(uint32_t *) &req;
+ prefix[1] = len + 1;
+ vec[0].iov_base = prefix;
+ vec[0].iov_len = sizeof (prefix);
+ vec[1].iov_base = (uint32_t *) &req + 1;
+ vec[1].iov_len = sizeof (req) - 4;
+ vec[2].iov_base = spans;
+ vec[2].iov_len = num_spans * sizeof (uint16_t);
+
+ _cairo_xcb_connection_write (connection, vec, 3);
+ }
+}
+
+void
+_cairo_xcb_connection_render_create_glyph_set (cairo_xcb_connection_t *connection,
+ xcb_render_glyphset_t id,
+ xcb_render_pictformat_t format)
+{
+ struct {
+ uint8_t major;
+ uint8_t minor;
+ uint16_t length;
+ uint32_t gsid;
+ uint32_t format;
+ } req;
+ struct iovec vec[1];
+
+ COMPILE_TIME_ASSERT (sizeof (req) == 12);
+
+ req.major = connection->render->major_opcode;
+ req.minor = 17;
+ req.length = sizeof (req) >> 2;
+ req.gsid = id;
+ req.format = format;
+
+ vec[0].iov_base = &req;
+ vec[0].iov_len = sizeof (req);
+
+ _cairo_xcb_connection_write (connection, vec, 1);
+}
+
+void
+_cairo_xcb_connection_render_free_glyph_set (cairo_xcb_connection_t *connection,
+ xcb_render_glyphset_t glyphset)
+{
+ struct {
+ uint8_t major;
+ uint8_t minor;
+ uint16_t length;
+ uint32_t gsid;
+ } req;
+ struct iovec vec[1];
+
+ COMPILE_TIME_ASSERT (sizeof (req) == 8);
+
+ req.major = connection->render->major_opcode;
+ req.minor = 19;
+ req.length = sizeof (req) >> 2;
+ req.gsid = glyphset;
+
+ vec[0].iov_base = &req;
+ vec[0].iov_len = sizeof (req);
+
+ _cairo_xcb_connection_write (connection, vec, 1);
+ _cairo_xcb_connection_put_xid (connection, glyphset);
+}
+
+void
+_cairo_xcb_connection_render_add_glyphs (cairo_xcb_connection_t *connection,
+ xcb_render_glyphset_t glyphset,
+ uint32_t num_glyphs,
+ uint32_t *glyphs_id,
+ xcb_render_glyphinfo_t *glyphs,
+ uint32_t data_len,
+ uint8_t *data)
+{
+ struct {
+ uint8_t major;
+ uint8_t minor;
+ uint16_t length;
+ uint32_t gsid;
+ uint32_t num_glyphs;
+ } req;
+ struct iovec vec[5];
+ uint32_t prefix[2];
+ uint32_t len = (sizeof (req) + num_glyphs * (sizeof (uint32_t) + sizeof (xcb_render_glyphinfo_t)) + data_len) >> 2;
+ int cnt;
+
+ COMPILE_TIME_ASSERT (sizeof (req) == 12);
+
+ req.major = connection->render->major_opcode;
+ req.minor = 20;
+ req.length = 0;
+ req.gsid = glyphset;
+ req.num_glyphs = num_glyphs;
+
+ if (len < connection->root->maximum_request_length) {
+ req.length = len;
+
+ vec[0].iov_base = &req;
+ vec[0].iov_len = sizeof (req);
+
+ cnt = 1;
+ } else {
+ prefix[0] = *(uint32_t *) &req;
+ prefix[1] = len + 1;
+ vec[0].iov_base = prefix;
+ vec[0].iov_len = sizeof (prefix);
+ vec[1].iov_base = (uint32_t *) &req + 1;
+ vec[1].iov_len = sizeof (req) - 4;
+
+ cnt = 2;
+ }
+
+ vec[cnt].iov_base = glyphs_id;
+ vec[cnt].iov_len = num_glyphs * sizeof (uint32_t);
+ cnt++;
+
+ vec[cnt].iov_base = glyphs;
+ vec[cnt].iov_len = num_glyphs * sizeof (xcb_render_glyphinfo_t);
+ cnt++;
+
+ vec[cnt].iov_base = data;
+ vec[cnt].iov_len = data_len;
+ cnt++;
+
+ _cairo_xcb_connection_write (connection, vec, cnt);
+}
+
+void
+_cairo_xcb_connection_render_free_glyphs (cairo_xcb_connection_t *connection,
+ xcb_render_glyphset_t glyphset,
+ uint32_t num_glyphs,
+ xcb_render_glyph_t *glyphs)
+{
+ struct {
+ uint8_t major;
+ uint8_t minor;
+ uint16_t length;
+ uint32_t gsid;
+ } req;
+ struct iovec vec[2];
+
+ COMPILE_TIME_ASSERT (sizeof (req) == 8);
+ assert ( (sizeof (req) + num_glyphs * sizeof (uint32_t)) >> 2 < connection->root->maximum_request_length);
+
+ req.major = connection->render->major_opcode;
+ req.minor = 22;
+ req.length = (sizeof (req) + num_glyphs * sizeof (uint32_t)) >> 2;
+ req.gsid = glyphset;
+
+ vec[0].iov_base = &req;
+ vec[0].iov_len = sizeof (req);
+ vec[1].iov_base = glyphs;
+ vec[1].iov_len = num_glyphs * sizeof (uint32_t);
+
+ _cairo_xcb_connection_write (connection, vec, 2);
+}
+
+void
+_cairo_xcb_connection_render_composite_glyphs_8 (cairo_xcb_connection_t *connection,
+ uint8_t op,
+ xcb_render_picture_t src,
+ xcb_render_picture_t dst,
+ xcb_render_pictformat_t mask_format,
+ xcb_render_glyphset_t glyphset,
+ int16_t src_x,
+ int16_t src_y,
+ uint32_t glyphcmds_len,
+ uint8_t *glyphcmds)
+{
+ struct {
+ uint8_t major;
+ uint8_t minor;
+ uint16_t length;
+ uint8_t op;
+ uint8_t pad1;
+ uint16_t pad2;
+ uint32_t src;
+ uint32_t dst;
+ uint32_t mask_format;
+ uint32_t glyphset;
+ int16_t src_x;
+ int16_t src_y;
+ } req;
+ struct iovec vec[3];
+ uint32_t prefix[2];
+ int len;
+
+ COMPILE_TIME_ASSERT (sizeof (req) == 28);
+
+ req.major = connection->render->major_opcode;
+ req.minor = 23;
+ req.length = 0;
+ req.op = op;
+ req.src = src;
+ req.dst = dst;
+ req.mask_format = mask_format;
+ req.glyphset = glyphset;
+ req.src_x = src_x;
+ req.src_y = src_y;
+
+ len = (sizeof (req) + glyphcmds_len) >> 2;
+ if (len < connection->root->maximum_request_length) {
+ req.length = len;
+
+ vec[0].iov_base = &req;
+ vec[0].iov_len = sizeof (req);
+
+ len = 1;
+ } else {
+ prefix[0] = *(uint32_t *) &req;
+ prefix[1] = len + 1;
+ vec[0].iov_base = prefix;
+ vec[0].iov_len = sizeof (prefix);
+ vec[1].iov_base = (uint32_t *) &req + 1;
+ vec[1].iov_len = sizeof (req) - 4;
+
+ len = 2;
+ }
+
+ vec[len].iov_base = glyphcmds;
+ vec[len].iov_len = glyphcmds_len;
+ len++;
+
+ _cairo_xcb_connection_write (connection, vec, len);
+}
+
+void
+_cairo_xcb_connection_render_composite_glyphs_16 (cairo_xcb_connection_t *connection,
+ uint8_t op,
+ xcb_render_picture_t src,
+ xcb_render_picture_t dst,
+ xcb_render_pictformat_t mask_format,
+ xcb_render_glyphset_t glyphset,
+ int16_t src_x,
+ int16_t src_y,
+ uint32_t glyphcmds_len,
+ uint8_t *glyphcmds)
+{
+ struct {
+ uint8_t major;
+ uint8_t minor;
+ uint16_t length;
+ uint8_t op;
+ uint8_t pad1;
+ uint16_t pad2;
+ uint32_t src;
+ uint32_t dst;
+ uint32_t mask_format;
+ uint32_t glyphset;
+ int16_t src_x;
+ int16_t src_y;
+ } req;
+ struct iovec vec[3];
+ uint32_t prefix[2];
+ int len;
+
+ COMPILE_TIME_ASSERT (sizeof (req) == 28);
+
+ req.major = connection->render->major_opcode;
+ req.minor = 24;
+ req.length = 0;
+ req.op = op;
+ req.src = src;
+ req.dst = dst;
+ req.mask_format = mask_format;
+ req.glyphset = glyphset;
+ req.src_x = src_x;
+ req.src_y = src_y;
+
+ len = (sizeof (req) + glyphcmds_len) >> 2;
+ if (len < connection->root->maximum_request_length) {
+ req.length = len;
+
+ vec[0].iov_base = &req;
+ vec[0].iov_len = sizeof (req);
+
+ len = 1;
+ } else {
+ prefix[0] = *(uint32_t *) &req;
+ prefix[1] = len + 1;
+ vec[0].iov_base = prefix;
+ vec[0].iov_len = sizeof (prefix);
+ vec[1].iov_base = (uint32_t *) &req + 1;
+ vec[1].iov_len = sizeof (req) - 4;
+
+ len = 2;
+ }
+
+ vec[len].iov_base = glyphcmds;
+ vec[len].iov_len = glyphcmds_len;
+ len++;
+
+ _cairo_xcb_connection_write (connection, vec, len);
+}
+
+void
+_cairo_xcb_connection_render_composite_glyphs_32 (cairo_xcb_connection_t *connection,
+ uint8_t op,
+ xcb_render_picture_t src,
+ xcb_render_picture_t dst,
+ xcb_render_pictformat_t mask_format,
+ xcb_render_glyphset_t glyphset,
+ int16_t src_x,
+ int16_t src_y,
+ uint32_t glyphcmds_len,
+ uint8_t *glyphcmds)
+{
+ struct {
+ uint8_t major;
+ uint8_t minor;
+ uint16_t length;
+ uint8_t op;
+ uint8_t pad1;
+ uint16_t pad2;
+ uint32_t src;
+ uint32_t dst;
+ uint32_t mask_format;
+ uint32_t glyphset;
+ int16_t src_x;
+ int16_t src_y;
+ } req;
+ struct iovec vec[2];
+ uint32_t prefix[2];
+ int len;
+
+ COMPILE_TIME_ASSERT (sizeof (req) == 28);
+
+ req.major = connection->render->major_opcode;
+ req.minor = 25;
+ req.length = 0;
+ req.op = op;
+ req.src = src;
+ req.dst = dst;
+ req.mask_format = mask_format;
+ req.glyphset = glyphset;
+ req.src_x = src_x;
+ req.src_y = src_y;
+
+ len = (sizeof (req) + glyphcmds_len) >> 2;
+ if (len < connection->root->maximum_request_length) {
+ req.length = len;
+
+ vec[0].iov_base = &req;
+ vec[0].iov_len = sizeof (req);
+
+ len = 1;
+ } else {
+ prefix[0] = *(uint32_t *) &req;
+ prefix[1] = len + 1;
+ vec[0].iov_base = prefix;
+ vec[0].iov_len = sizeof (prefix);
+ vec[1].iov_base = (uint32_t *) &req + 1;
+ vec[1].iov_len = sizeof (req) - 4;
+
+ len = 2;
+ }
+
+ vec[len].iov_base = glyphcmds;
+ vec[len].iov_len = glyphcmds_len;
+ len++;
+
+ _cairo_xcb_connection_write (connection, vec, len);
+}
+
+void
+_cairo_xcb_connection_render_fill_rectangles (cairo_xcb_connection_t *connection,
+ uint8_t op,
+ xcb_render_picture_t dst,
+ xcb_render_color_t color,
+ uint32_t num_rects,
+ xcb_rectangle_t *rects)
+{
+ struct {
+ uint8_t major;
+ uint8_t minor;
+ uint16_t length;
+ uint8_t op;
+ uint8_t pad1;
+ uint16_t pad2;
+ uint32_t dst;
+ xcb_render_color_t color;
+ } req;
+ struct iovec vec[2];
+ uint32_t len = (sizeof (req) + num_rects * sizeof (xcb_rectangle_t)) >> 2;
+
+ COMPILE_TIME_ASSERT (sizeof (req) == 20);
+ assert(len < connection->root->maximum_request_length);
+
+ req.major = connection->render->major_opcode;
+ req.minor = 26;
+ req.length = (sizeof (req) + num_rects * sizeof (xcb_rectangle_t)) >> 2;
+ req.op = op;
+ req.dst = dst;
+ req.color = color;
+
+ vec[0].iov_base = &req;
+ vec[0].iov_len = sizeof (req);
+ vec[1].iov_base = rects;
+ vec[1].iov_len = num_rects * sizeof (xcb_rectangle_t);
+
+ _cairo_xcb_connection_write (connection, vec, 2);
+}
+
+void
+_cairo_xcb_connection_render_set_picture_transform (cairo_xcb_connection_t *connection,
+ xcb_render_picture_t picture,
+ xcb_render_transform_t *transform)
+{
+ struct {
+ uint8_t major;
+ uint8_t minor;
+ uint16_t length;
+ uint32_t picture;
+ } req;
+ struct iovec vec[2];
+
+ req.major = connection->render->major_opcode;
+ req.minor = 28;
+ req.length = (sizeof (req) + sizeof (xcb_render_transform_t)) >> 2;
+ req.picture = picture;
+
+ vec[0].iov_base = &req;
+ vec[0].iov_len = sizeof (req);
+ vec[1].iov_base = transform;
+ vec[1].iov_len = sizeof (xcb_render_transform_t);
+
+ _cairo_xcb_connection_write (connection, vec, 2);
+}
+
+void
+_cairo_xcb_connection_render_set_picture_filter (cairo_xcb_connection_t *connection,
+ xcb_render_picture_t picture,
+ uint16_t filter_len,
+ char *filter)
+{
+ struct {
+ uint8_t major;
+ uint8_t minor;
+ uint16_t length;
+ uint32_t picture;
+ uint16_t nbytes;
+ uint16_t pad;
+ } req;
+ struct iovec vec[2];
+
+ req.nbytes = filter_len;
+ filter_len = (filter_len + 3) & ~3;
+
+ req.major = connection->render->major_opcode;
+ req.minor = 30;
+ req.length = (sizeof (req) + filter_len) >> 2;
+ req.picture = picture;
+
+ vec[0].iov_base = &req;
+ vec[0].iov_len = sizeof (req);
+ vec[1].iov_base = filter;
+ vec[1].iov_len = filter_len;
+
+ _cairo_xcb_connection_write (connection, vec, 2);
+}
+
+void
+_cairo_xcb_connection_render_create_solid_fill (cairo_xcb_connection_t *connection,
+ xcb_render_picture_t picture,
+ xcb_render_color_t color)
+{
+ struct {
+ uint8_t major;
+ uint8_t minor;
+ uint16_t length;
+ uint32_t picture;
+ xcb_render_color_t color;
+ } req;
+ struct iovec vec[1];
+
+ COMPILE_TIME_ASSERT (sizeof (req) == 16);
+
+ req.major = connection->render->major_opcode;
+ req.minor = 33;
+ req.length = sizeof (req) >> 2;
+ req.picture = picture;
+ req.color = color;
+
+ vec[0].iov_base = &req;
+ vec[0].iov_len = sizeof (req);
+
+ _cairo_xcb_connection_write (connection, vec, 1);
+}
+
+void
+_cairo_xcb_connection_render_create_linear_gradient (cairo_xcb_connection_t *connection,
+ xcb_render_picture_t picture,
+ xcb_render_pointfix_t p1,
+ xcb_render_pointfix_t p2,
+ uint32_t num_stops,
+ xcb_render_fixed_t *stops,
+ xcb_render_color_t *colors)
+{
+ struct {
+ uint8_t major;
+ uint8_t minor;
+ uint16_t length;
+ uint32_t picture;
+ xcb_render_pointfix_t p1, p2;
+ uint32_t num_stops;
+ } req;
+ struct iovec vec[3];
+
+ COMPILE_TIME_ASSERT (sizeof (req) == 28);
+ assert((sizeof (req) + num_stops * (sizeof (xcb_render_fixed_t) + sizeof (xcb_render_color_t))) >> 2 < connection->root->maximum_request_length);
+
+ req.major = connection->render->major_opcode;
+ req.minor = 34;
+ req.length = (sizeof (req) + num_stops * (sizeof (xcb_render_fixed_t) + sizeof (xcb_render_color_t))) >> 2;
+ req.picture = picture;
+ req.p1 = p1;
+ req.p2 = p2;
+ req.num_stops = num_stops;
+
+ vec[0].iov_base = &req;
+ vec[0].iov_len = sizeof (req);
+ vec[1].iov_base = stops;
+ vec[1].iov_len = num_stops * sizeof (xcb_render_fixed_t);
+ vec[2].iov_base = colors;
+ vec[2].iov_len = num_stops * sizeof (xcb_render_color_t);
+
+ _cairo_xcb_connection_write (connection, vec, 3);
+}
+
+void
+_cairo_xcb_connection_render_create_radial_gradient (cairo_xcb_connection_t *connection,
+ xcb_render_picture_t picture,
+ xcb_render_pointfix_t inner,
+ xcb_render_pointfix_t outer,
+ xcb_render_fixed_t inner_radius,
+ xcb_render_fixed_t outer_radius,
+ uint32_t num_stops,
+ xcb_render_fixed_t *stops,
+ xcb_render_color_t *colors)
+{
+ struct {
+ uint8_t major;
+ uint8_t minor;
+ uint16_t length;
+ uint32_t picture;
+ xcb_render_pointfix_t inner;
+ xcb_render_pointfix_t outer;
+ xcb_render_fixed_t inner_radius;
+ xcb_render_fixed_t outer_radius;
+ uint32_t num_stops;
+ } req;
+ struct iovec vec[3];
+
+ COMPILE_TIME_ASSERT (sizeof (req) == 36);
+ assert((sizeof (req) + num_stops * (sizeof (xcb_render_fixed_t) + sizeof (xcb_render_color_t))) >> 2 < connection->root->maximum_request_length);
+
+ req.major = connection->render->major_opcode;
+ req.minor = 35;
+ req.length = (sizeof (req) + num_stops * (sizeof (xcb_render_fixed_t) + sizeof (xcb_render_color_t))) >> 2;
+ req.picture = picture;
+ req.inner = inner;
+ req.outer = outer;
+ req.inner_radius = inner_radius;
+ req.outer_radius = outer_radius;
+ req.num_stops = num_stops;
+
+ vec[0].iov_base = &req;
+ vec[0].iov_len = sizeof (req);
+ vec[1].iov_base = stops;
+ vec[1].iov_len = num_stops * sizeof (xcb_render_fixed_t);
+ vec[2].iov_base = colors;
+ vec[2].iov_len = num_stops * sizeof (xcb_render_color_t);
+
+ _cairo_xcb_connection_write (connection, vec, 3);
+}
+
+void
+_cairo_xcb_connection_render_create_conical_gradient (cairo_xcb_connection_t *connection,
+ xcb_render_picture_t picture,
+ xcb_render_pointfix_t center,
+ xcb_render_fixed_t angle,
+ uint32_t num_stops,
+ xcb_render_fixed_t *stops,
+ xcb_render_color_t *colors)
+{
+ struct {
+ uint8_t major;
+ uint8_t minor;
+ uint16_t length;
+ uint32_t picture;
+ xcb_render_pointfix_t center;
+ xcb_render_fixed_t angle;
+ uint32_t num_stops;
+ } req;
+ struct iovec vec[3];
+
+ COMPILE_TIME_ASSERT (sizeof (req) == 24);
+ assert((sizeof (req) + num_stops * (sizeof (xcb_render_fixed_t) + sizeof (xcb_render_color_t))) >> 2 < connection->root->maximum_request_length);
+
+ req.major = connection->render->major_opcode;
+ req.minor = 36;
+ req.length = (sizeof (req) + num_stops * (sizeof (xcb_render_fixed_t) + sizeof (xcb_render_color_t))) >> 2;
+ req.picture = picture;
+ req.center = center;
+ req.angle = angle;
+ req.num_stops = num_stops;
+
+ vec[0].iov_base = &req;
+ vec[0].iov_len = sizeof (req);
+ vec[1].iov_base = stops;
+ vec[1].iov_len = num_stops * sizeof (xcb_render_fixed_t);
+ vec[2].iov_base = colors;
+ vec[2].iov_len = num_stops * sizeof (xcb_render_color_t);
+
+ _cairo_xcb_connection_write (connection, vec, 3);
+}
diff --git a/src/cairo-xcb-connection-shm.c b/src/cairo-xcb-connection-shm.c
new file mode 100644
index 0000000..2c13b1b
--- /dev/null
+++ b/src/cairo-xcb-connection-shm.c
@@ -0,0 +1,194 @@
+/* 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.
+ *
+ * Contributor(s):
+ * Chris Wilson <chris at chris-wilson.co.uk>
+ */
+
+#include "cairoint.h"
+
+#include "cairo-xcb-private.h"
+
+#include <xcb/xcbext.h>
+#include <xcb/shm.h>
+
+uint32_t
+_cairo_xcb_connection_shm_attach (cairo_xcb_connection_t *connection,
+ uint32_t id,
+ cairo_bool_t readonly)
+{
+ struct {
+ uint8_t req;
+ uint8_t shm_req;
+ uint16_t length;
+ uint32_t segment;
+ uint32_t id;
+ uint8_t readonly;
+ uint8_t pad1;
+ uint16_t pad2;
+ } req;
+ struct iovec vec[1];
+
+ COMPILE_TIME_ASSERT (sizeof (req) == 16);
+
+ req.req = connection->shm->major_opcode;
+ req.shm_req = 1;
+ req.length = sizeof (req) >> 2;
+ req.segment = _cairo_xcb_connection_get_xid (connection);
+ req.id = id;
+ req.readonly = readonly;
+
+ vec[0].iov_base = &req;
+ vec[0].iov_len = sizeof (req);
+
+ _cairo_xcb_connection_write (connection, vec, 1);
+ return req.segment;
+}
+
+uint64_t
+_cairo_xcb_connection_shm_put_image (cairo_xcb_connection_t *connection,
+ xcb_drawable_t dst,
+ xcb_gcontext_t gc,
+ uint16_t total_width,
+ uint16_t total_height,
+ int16_t src_x,
+ int16_t src_y,
+ uint16_t width,
+ uint16_t height,
+ int16_t dst_x,
+ int16_t dst_y,
+ uint8_t depth,
+ uint32_t shm,
+ uint32_t offset)
+{
+ struct {
+ uint8_t req;
+ uint8_t shm_req;
+ uint16_t len;
+ uint32_t dst;
+ uint32_t gc;
+ uint16_t total_width;
+ uint16_t total_height;
+ int16_t src_x;
+ int16_t src_y;
+ uint16_t src_width;
+ uint16_t src_height;
+ int16_t dst_x;
+ int16_t dst_y;
+ uint8_t depth;
+ uint8_t format;
+ uint8_t send_event;
+ uint8_t pad;
+ uint32_t shm;
+ uint32_t offset;
+ } req;
+ struct iovec vec[2];
+
+ req.req = connection->shm->major_opcode;
+ req.shm_req = 3;
+ req.len = sizeof (req) >> 2;
+ req.dst = dst;
+ req.gc = gc;
+ req.total_width = total_width;
+ req.total_height = total_height;
+ req.src_x = src_x;
+ req.src_y = src_y;
+ req.src_width = width;
+ req.src_height = height;
+ req.dst_x = dst_x;
+ req.dst_y = dst_y;
+ req.depth = depth;
+ req.format = XCB_IMAGE_FORMAT_Z_PIXMAP;
+ req.send_event = 0;
+ req.shm = shm;
+ req.offset = offset;
+
+ vec[0].iov_base = &req;
+ vec[0].iov_len = sizeof (req);
+
+ _cairo_xcb_connection_write (connection, vec, 1);
+ return connection->seqno;
+}
+
+cairo_status_t
+_cairo_xcb_connection_shm_get_image (cairo_xcb_connection_t *connection,
+ xcb_drawable_t src,
+ int16_t src_x,
+ int16_t src_y,
+ uint16_t width,
+ uint16_t height,
+ uint32_t shmseg,
+ uint32_t offset)
+{
+ xcb_shm_get_image_reply_t *reply;
+ xcb_generic_error_t *error;
+
+ reply = xcb_shm_get_image_reply (connection->xcb_connection,
+ xcb_shm_get_image (connection->xcb_connection,
+ src,
+ src_x, src_y,
+ width, height,
+ (uint32_t) -1,
+ XCB_IMAGE_FORMAT_Z_PIXMAP,
+ shmseg, offset),
+ &error);
+ free (reply);
+
+ if (error) {
+ /* an error here should be impossible */
+ free (error);
+ return _cairo_error (CAIRO_STATUS_READ_ERROR);
+ }
+
+ return _cairo_xcb_connection_take_socket (connection);
+}
+
+void
+_cairo_xcb_connection_shm_detach (cairo_xcb_connection_t *connection,
+ uint32_t segment)
+{
+ struct {
+ uint8_t req;
+ uint8_t shm_req;
+ uint16_t length;
+ uint32_t segment;
+ } req;
+ struct iovec vec[1];
+
+ COMPILE_TIME_ASSERT (sizeof (req) == 8);
+
+ req.req = connection->shm->major_opcode;
+ req.shm_req = 2;
+ req.length = sizeof (req) >> 2;
+ req.segment = segment;
+
+ vec[0].iov_base = &req;
+ vec[0].iov_len = sizeof (req);
+
+ _cairo_xcb_connection_write (connection, vec, 1);
+ _cairo_xcb_connection_put_xid (connection, segment);
+}
diff --git a/src/cairo-xcb-connection.c b/src/cairo-xcb-connection.c
new file mode 100644
index 0000000..6721e92
--- /dev/null
+++ b/src/cairo-xcb-connection.c
@@ -0,0 +1,867 @@
+/* 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.
+ *
+ * Authors:
+ * Chris Wilson <chris at chris-wilson.co.uk>
+ */
+
+
+#include "cairoint.h"
+
+#include "cairo-xcb-private.h"
+#include "cairo-hash-private.h"
+#include "cairo-freelist-private.h"
+#include "cairo-list-private.h"
+
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <xcb/xcbext.h>
+#include <xcb/bigreq.h>
+#include <xcb/dri2.h>
+#include <xcb/shm.h>
+#include <errno.h>
+
+typedef struct _cairo_xcb_xrender_format {
+ cairo_hash_entry_t key;
+ xcb_render_pictformat_t xrender_format;
+} cairo_xcb_xrender_format_t;
+
+typedef struct _cairo_xcb_xid {
+ cairo_list_t link;
+ uint32_t xid;
+} cairo_xcb_xid_t;
+
+#define XCB_RENDER_AT_LEAST(V, major, minor) \
+ (((V)->major_version > major) || \
+ (((V)->major_version == major) && ((V)->minor_version >= minor)))
+
+#define XCB_RENDER_HAS_CREATE_PICTURE(surface) XCB_RENDER_AT_LEAST((surface), 0, 0)
+#define XCB_RENDER_HAS_COMPOSITE(surface) XCB_RENDER_AT_LEAST((surface), 0, 0)
+#define XCB_RENDER_HAS_COMPOSITE_TEXT(surface) XCB_RENDER_AT_LEAST((surface), 0, 0)
+
+#define XCB_RENDER_HAS_FILL_RECTANGLES(surface) XCB_RENDER_AT_LEAST((surface), 0, 1)
+
+#define XCB_RENDER_HAS_DISJOINT(surface) XCB_RENDER_AT_LEAST((surface), 0, 2)
+#define XCB_RENDER_HAS_CONJOINT(surface) XCB_RENDER_AT_LEAST((surface), 0, 2)
+
+#define XCB_RENDER_HAS_TRAPEZOIDS(surface) XCB_RENDER_AT_LEAST((surface), 0, 4)
+#define XCB_RENDER_HAS_TRIANGLES(surface) XCB_RENDER_AT_LEAST((surface), 0, 4)
+#define XCB_RENDER_HAS_TRISTRIP(surface) XCB_RENDER_AT_LEAST((surface), 0, 4)
+#define XCB_RENDER_HAS_TRIFAN(surface) XCB_RENDER_AT_LEAST((surface), 0, 4)
+#define XCB_RENDER_HAS_SPANS(surface) XCB_RENDER_AT_LEAST((surface), 0, 12)
+
+#define XCB_RENDER_HAS_PICTURE_TRANSFORM(surface) XCB_RENDER_AT_LEAST((surface), 0, 6)
+#define XCB_RENDER_HAS_FILTERS(surface) XCB_RENDER_AT_LEAST((surface), 0, 6)
+
+#define XCB_RENDER_HAS_EXTENDED_REPEAT(surface) XCB_RENDER_AT_LEAST((surface), 0, 10)
+#define XCB_RENDER_HAS_GRADIENTS(surface) XCB_RENDER_AT_LEAST((surface), 0, 10)
+
+#define XCB_RENDER_HAS_PDF_OPERATORS(surface) XCB_RENDER_AT_LEAST((surface), 0, 11)
+
+static cairo_list_t connections;
+
+static cairo_status_t
+_cairo_xcb_connection_find_visual_formats (cairo_xcb_connection_t *connection,
+ const xcb_render_query_pict_formats_reply_t *formats)
+{
+ xcb_render_pictscreen_iterator_t screens;
+ xcb_render_pictdepth_iterator_t depths;
+ xcb_render_pictvisual_iterator_t visuals;
+
+ for (screens = xcb_render_query_pict_formats_screens_iterator (formats);
+ screens.rem;
+ xcb_render_pictscreen_next (&screens))
+ {
+ for (depths = xcb_render_pictscreen_depths_iterator (screens.data);
+ depths.rem;
+ xcb_render_pictdepth_next (&depths))
+ {
+ for (visuals = xcb_render_pictdepth_visuals_iterator (depths.data);
+ visuals.rem;
+ xcb_render_pictvisual_next (&visuals))
+ {
+ cairo_xcb_xrender_format_t *f;
+ cairo_status_t status;
+
+ f = malloc (sizeof (cairo_xcb_xrender_format_t));
+ if (unlikely (f == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+ f->key.hash = visuals.data->visual;
+ f->xrender_format = visuals.data->format;
+ status = _cairo_hash_table_insert (connection->visual_to_xrender_format,
+ &f->key);
+ if (unlikely (status))
+ return status;
+ }
+ }
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+#if 0
+static xcb_format_t *
+find_format_for_depth (const xcb_setup_t *setup, uint8_t depth)
+{
+ xcb_format_t *fmt = xcb_setup_pixmap_formats (setup);
+ xcb_format_t *fmtend = fmt + xcb_setup_pixmap_formats_length (setup);
+
+ for (; fmt != fmtend; ++fmt)
+ if (fmt->depth == depth)
+ return fmt;
+
+ return 0;
+}
+#endif
+
+static cairo_status_t
+_cairo_xcb_connection_parse_xrender_formats (cairo_xcb_connection_t *connection,
+ const xcb_render_query_pict_formats_reply_t *formats)
+{
+ xcb_render_pictforminfo_iterator_t i;
+ cairo_status_t status;
+
+ for (i = xcb_render_query_pict_formats_formats_iterator (formats);
+ i.rem;
+ xcb_render_pictforminfo_next (&i))
+ {
+ cairo_format_masks_t masks;
+ pixman_format_code_t pixman_format;
+
+ if (i.data->type != XCB_RENDER_PICT_TYPE_DIRECT)
+ continue;
+
+ masks.alpha_mask =
+ (unsigned long) i.data->direct.alpha_mask << i.data->direct.alpha_shift;
+ masks.red_mask =
+ (unsigned long) i.data->direct.red_mask << i.data->direct.red_shift;
+ masks.green_mask =
+ (unsigned long) i.data->direct.green_mask << i.data->direct.green_shift;
+ masks.blue_mask =
+ (unsigned long) i.data->direct.blue_mask << i.data->direct.blue_shift;
+ masks.bpp = i.data->depth;
+
+ if (_pixman_format_from_masks (&masks, &pixman_format)) {
+ cairo_hash_entry_t key;
+
+ key.hash = pixman_format;
+ if (! _cairo_hash_table_lookup (connection->xrender_formats, &key)) {
+ cairo_xcb_xrender_format_t *f;
+
+ f = malloc (sizeof (cairo_xcb_xrender_format_t));
+ if (unlikely (f == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+ f->key.hash = pixman_format;
+ f->xrender_format = i.data->id;
+ status = _cairo_hash_table_insert (connection->xrender_formats,
+ &f->key);
+ if (unlikely (status))
+ return status;
+
+#if 0
+ printf ("xrender %x -> (%lx, %lx, %lx, %lx, %d) %x [%d, %d]\n",
+ i.data->id,
+ masks.alpha_mask,
+ masks.red_mask,
+ masks.green_mask,
+ masks.blue_mask,
+ masks.bpp,
+ pixman_format,
+ PIXMAN_FORMAT_DEPTH(pixman_format),
+ PIXMAN_FORMAT_BPP(pixman_format));
+#endif
+ }
+ }
+ }
+
+ status = _cairo_xcb_connection_find_visual_formats (connection, formats);
+ if (unlikely (status))
+ return status;
+
+ connection->standard_formats[CAIRO_FORMAT_A1] =
+ _cairo_xcb_connection_get_xrender_format (connection, PIXMAN_a1);
+
+ connection->standard_formats[CAIRO_FORMAT_A8] =
+ _cairo_xcb_connection_get_xrender_format (connection, PIXMAN_a8);
+
+ connection->standard_formats[CAIRO_FORMAT_RGB24] =
+ _cairo_xcb_connection_get_xrender_format (connection,
+ PIXMAN_FORMAT (24,
+ PIXMAN_TYPE_ARGB,
+ 0, 8, 8, 8));
+ if (connection->standard_formats[CAIRO_FORMAT_RGB24] == XCB_NONE) {
+ connection->standard_formats[CAIRO_FORMAT_RGB24] =
+ _cairo_xcb_connection_get_xrender_format (connection,
+ PIXMAN_FORMAT (24, PIXMAN_TYPE_ABGR,
+ 0, 8, 8, 8));
+ }
+
+ connection->standard_formats[CAIRO_FORMAT_ARGB32] =
+ _cairo_xcb_connection_get_xrender_format (connection, PIXMAN_a8r8g8b8);
+ if (connection->standard_formats[CAIRO_FORMAT_ARGB32] == XCB_NONE) {
+ connection->standard_formats[CAIRO_FORMAT_ARGB32] =
+ _cairo_xcb_connection_get_xrender_format (connection, PIXMAN_a8b8g8r8);
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+/*
+ * We require support for depth 1, 8, 24 and 32 pixmaps
+ */
+#define DEPTH_MASK(d) (1 << ((d) - 1))
+#define REQUIRED_DEPTHS (DEPTH_MASK(1) | \
+ DEPTH_MASK(8) | \
+ DEPTH_MASK(24) | \
+ DEPTH_MASK(32))
+static cairo_bool_t
+pixmap_depths_usable (cairo_xcb_connection_t *connection,
+ uint32_t missing,
+ xcb_drawable_t root)
+{
+ xcb_connection_t *c = connection->xcb_connection;
+ xcb_void_cookie_t create_cookie[32];
+ xcb_pixmap_t pixmap;
+ cairo_bool_t success = TRUE;
+ int depth, i, j;
+
+ pixmap = _cairo_xcb_connection_get_xid (connection);
+
+ for (depth = 1, i = 0; depth <= 32; depth++) {
+ if (missing & DEPTH_MASK(depth)) {
+ create_cookie[i] = xcb_create_pixmap_checked (c, depth, pixmap, root, 1, 1);
+ xcb_free_pixmap (c, pixmap);
+ if (!create_cookie[i].sequence) {
+ success = FALSE;
+ break;
+ }
+ i++;
+ }
+ }
+
+ for (j = 0; j < i; j++) {
+ xcb_generic_error_t *create_error = xcb_request_check (c, create_cookie[j]);
+ success &= create_error == NULL;
+ free (create_error);
+ }
+
+ _cairo_xcb_connection_put_xid (connection, pixmap);
+
+ return success;
+}
+
+static cairo_bool_t
+has_required_depths (cairo_xcb_connection_t *connection)
+{
+ xcb_screen_iterator_t screens;
+
+ for (screens = xcb_setup_roots_iterator (connection->root);
+ screens.rem;
+ xcb_screen_next (&screens))
+ {
+ xcb_depth_iterator_t depths;
+ uint32_t missing = REQUIRED_DEPTHS;
+
+ for (depths = xcb_screen_allowed_depths_iterator (screens.data);
+ depths.rem;
+ xcb_depth_next (&depths))
+ {
+ missing &= ~DEPTH_MASK (depths.data->depth);
+ }
+ if (missing == 0)
+ continue;
+
+ /*
+ * Ok, this is ugly. It should be sufficient at this
+ * point to just return false, but Xinerama is broken at
+ * this point and only advertises depths which have an
+ * associated visual. Of course, the other depths still
+ * work, but the only way to find out is to try them.
+ */
+ if (! pixmap_depths_usable (connection, missing, screens.data->root))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static cairo_status_t
+_cairo_xcb_connection_query_render (cairo_xcb_connection_t *connection)
+{
+ xcb_connection_t *c = connection->xcb_connection;
+ xcb_render_query_version_cookie_t version_cookie;
+ xcb_render_query_pict_formats_cookie_t formats_cookie;
+ xcb_render_query_version_reply_t *version;
+ xcb_render_query_pict_formats_reply_t *formats;
+ cairo_status_t status;
+ cairo_bool_t present;
+
+ version_cookie = xcb_render_query_version (c, 0, 10);
+ formats_cookie = xcb_render_query_pict_formats (c);
+
+ present = has_required_depths (connection);
+ version = xcb_render_query_version_reply (c, version_cookie, 0);
+ formats = xcb_render_query_pict_formats_reply (c, formats_cookie, 0);
+ if (! present || version == NULL || formats == NULL) {
+ free (version);
+ free (formats);
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+ /* always true if the extension is present (i.e. >= 0.0) */
+ connection->flags |= CAIRO_XCB_HAS_RENDER;
+ connection->flags |= CAIRO_XCB_RENDER_HAS_COMPOSITE;
+ connection->flags |= CAIRO_XCB_RENDER_HAS_COMPOSITE_GLYPHS;
+
+ if (XCB_RENDER_HAS_FILL_RECTANGLES (version))
+ connection->flags |= CAIRO_XCB_RENDER_HAS_FILL_RECTANGLES;
+
+ if (XCB_RENDER_HAS_TRAPEZOIDS (version))
+ connection->flags |= CAIRO_XCB_RENDER_HAS_COMPOSITE_TRAPEZOIDS;
+
+ if (XCB_RENDER_HAS_PICTURE_TRANSFORM (version))
+ connection->flags |= CAIRO_XCB_RENDER_HAS_PICTURE_TRANSFORM;
+
+ if (XCB_RENDER_HAS_FILTERS (version))
+ connection->flags |= CAIRO_XCB_RENDER_HAS_FILTERS;
+
+ if (XCB_RENDER_HAS_PDF_OPERATORS (version))
+ connection->flags |= CAIRO_XCB_RENDER_HAS_PDF_OPERATORS;
+
+ if (XCB_RENDER_HAS_EXTENDED_REPEAT (version))
+ connection->flags |= CAIRO_XCB_RENDER_HAS_EXTENDED_REPEAT;
+
+ if (XCB_RENDER_HAS_GRADIENTS (version))
+ connection->flags |= CAIRO_XCB_RENDER_HAS_GRADIENTS;
+
+ free (version);
+
+ status = _cairo_xcb_connection_parse_xrender_formats (connection, formats);
+ free (formats);
+
+ return status;
+}
+
+#if 0
+static void
+_cairo_xcb_connection_query_cairo (cairo_xcb_connection_t *connection)
+{
+ xcb_connection_t *c = connection->xcb_connection;
+ xcb_cairo_query_version_reply_t *version;
+
+ version = xcb_cairo_query_version_reply (c,
+ xcb_cairo_query_version (c, 0, 0),
+ 0);
+
+ free (version);
+}
+#endif
+
+static cairo_bool_t
+can_use_shm (cairo_xcb_connection_t *connection)
+{
+ cairo_bool_t success = TRUE;
+ xcb_connection_t *c = connection->xcb_connection;
+ xcb_void_cookie_t cookie[2];
+ xcb_generic_error_t *error;
+ int shmid;
+ uint32_t shmseg;
+ void *ptr;
+
+ shmid = shmget (IPC_PRIVATE, 0x1000, IPC_CREAT | 0600);
+ if (shmid == -1)
+ return FALSE;
+
+ ptr = shmat (shmid, NULL, 0);
+ if (ptr == (char *) -1) {
+ shmctl (shmid, IPC_RMID, NULL);
+ return FALSE;
+ }
+
+ shmseg = _cairo_xcb_connection_get_xid (connection);
+ cookie[0] = xcb_shm_attach_checked (c, shmseg, shmid, FALSE);
+ cookie[1] = xcb_shm_detach_checked (c, shmseg);
+ _cairo_xcb_connection_put_xid (connection, shmseg);
+
+ error = xcb_request_check (c, cookie[0]);
+ if (error != NULL)
+ success = FALSE;
+
+ error = xcb_request_check (c, cookie[1]);
+ if (error != NULL)
+ success = FALSE;
+
+ shmctl (shmid, IPC_RMID, NULL);
+ shmdt (ptr);
+
+ return success;
+}
+
+static void
+_cairo_xcb_connection_query_shm (cairo_xcb_connection_t *connection)
+{
+ xcb_connection_t *c = connection->xcb_connection;
+ xcb_shm_query_version_reply_t *version;
+
+ version = xcb_shm_query_version_reply (c, xcb_shm_query_version (c), 0);
+ if (version == NULL)
+ return;
+
+ free (version);
+
+ if (can_use_shm (connection))
+ connection->flags |= CAIRO_XCB_HAS_SHM;
+}
+
+#if CAIRO_HAS_XCB_DRM_FUNCTIONS
+static void
+_cairo_xcb_connection_query_dri2 (cairo_xcb_connection_t *connection)
+{
+ xcb_connection_t *c = connection->xcb_connection;
+ xcb_dri2_query_version_reply_t *version;
+
+ version = xcb_dri2_query_version_reply (c,
+ xcb_dri2_query_version (c,
+ XCB_DRI2_MAJOR_VERSION,
+ XCB_DRI2_MINOR_VERSION),
+ 0);
+ if (version == NULL)
+ return;
+
+ free (version);
+
+ connection->flags |= CAIRO_XCB_HAS_DRI2;
+}
+#endif
+
+static void
+_device_flush (void *device)
+{
+ cairo_xcb_connection_t *connection = device;
+ cairo_xcb_screen_t *screen;
+ cairo_status_t status;
+
+ status = cairo_device_acquire (&connection->device);
+ if (unlikely (status))
+ return;
+
+ CAIRO_MUTEX_LOCK (connection->screens_mutex);
+ cairo_list_foreach_entry (screen, cairo_xcb_screen_t,
+ &connection->screens, link)
+ {
+ if (screen->device != NULL)
+ cairo_device_flush (screen->device);
+ }
+ CAIRO_MUTEX_UNLOCK (connection->screens_mutex);
+
+ xcb_flush (connection->xcb_connection);
+
+ cairo_device_release (&connection->device);
+}
+
+static cairo_bool_t
+_xrender_formats_equal (const void *A, const void *B)
+{
+ const cairo_xcb_xrender_format_t *a = A, *b = B;
+ return a->key.hash == b->key.hash;
+}
+
+static void
+_pluck_xrender_format (void *entry,
+ void *closure)
+{
+ _cairo_hash_table_remove (closure, entry);
+ free (entry);
+}
+
+static void
+_device_finish (void *device)
+{
+ cairo_xcb_connection_t *connection = device;
+
+ if (! cairo_list_is_empty (&connection->link)) {
+ CAIRO_MUTEX_LOCK (_cairo_xcb_connections_mutex);
+ cairo_list_del (&connection->link);
+ CAIRO_MUTEX_UNLOCK (_cairo_xcb_connections_mutex);
+ }
+
+ while (! cairo_list_is_empty (&connection->fonts)) {
+ cairo_xcb_font_t *font;
+
+ font = cairo_list_first_entry (&connection->fonts,
+ cairo_xcb_font_t,
+ link);
+ _cairo_xcb_font_finish (font);
+ }
+
+ while (! cairo_list_is_empty (&connection->screens)) {
+ cairo_xcb_screen_t *screen;
+
+ screen = cairo_list_first_entry (&connection->screens,
+ cairo_xcb_screen_t,
+ link);
+ _cairo_xcb_screen_finish (screen);
+ }
+}
+
+static void
+_device_destroy (void *device)
+{
+ cairo_xcb_connection_t *connection = device;
+
+ _cairo_hash_table_foreach (connection->xrender_formats,
+ _pluck_xrender_format, connection->xrender_formats);
+ _cairo_hash_table_destroy (connection->xrender_formats);
+
+ _cairo_hash_table_foreach (connection->visual_to_xrender_format,
+ _pluck_xrender_format,
+ connection->visual_to_xrender_format);
+ _cairo_hash_table_destroy (connection->visual_to_xrender_format);
+
+ _cairo_xcb_connection_shm_mem_pools_fini (connection);
+ _cairo_freepool_fini (&connection->shm_info_freelist);
+
+ _cairo_freepool_fini (&connection->xid_pool);
+
+ CAIRO_MUTEX_FINI (connection->shm_mutex);
+ CAIRO_MUTEX_FINI (connection->screens_mutex);
+
+ free (connection);
+}
+
+static const cairo_device_backend_t _cairo_xcb_device_backend = {
+ CAIRO_DEVICE_TYPE_XCB,
+
+ NULL, NULL, /* lock, unlock */
+
+ _device_flush,
+ _device_finish,
+ _device_destroy,
+};
+
+cairo_xcb_connection_t *
+_cairo_xcb_connection_get (xcb_connection_t *xcb_connection)
+{
+ cairo_xcb_connection_t *connection;
+ const xcb_query_extension_reply_t *ext;
+ cairo_status_t status;
+
+ CAIRO_MUTEX_LOCK (_cairo_xcb_connections_mutex);
+ if (connections.next == NULL) {
+ /* XXX _cairo_init () */
+ cairo_list_init (&connections);
+ }
+
+ cairo_list_foreach_entry (connection,
+ cairo_xcb_connection_t,
+ &connections,
+ link)
+ {
+ if (connection->xcb_connection == xcb_connection) {
+ /* Maintain MRU order. */
+ if (connections.next != &connection->link)
+ cairo_list_move (&connection->link, &connections);
+
+ goto unlock;
+ }
+ }
+
+ connection = malloc (sizeof (cairo_xcb_connection_t));
+ if (unlikely (connection == NULL))
+ goto unlock;
+
+ _cairo_device_init (&connection->device, &_cairo_xcb_device_backend);
+ CAIRO_MUTEX_INIT (connection->shm_mutex);
+ CAIRO_MUTEX_INIT (connection->screens_mutex);
+
+ connection->xcb_connection = xcb_connection;
+ connection->has_socket = FALSE;
+
+ xcb_prefetch_extension_data (xcb_connection, &xcb_big_requests_id);
+ xcb_prefetch_extension_data (xcb_connection, &xcb_shm_id);
+ xcb_prefetch_extension_data (xcb_connection, &xcb_render_id);
+#if 0
+ xcb_prefetch_extension_data (xcb_connection, &xcb_cairo_id);
+#endif
+#if CAIRO_HAS_XCB_DRM_FUNCTIONS
+ xcb_prefetch_extension_data (xcb_connection, &xcb_dri2_id);
+#endif
+
+ xcb_prefetch_maximum_request_length (xcb_connection);
+
+ cairo_list_init (&connection->fonts);
+ cairo_list_init (&connection->screens);
+ cairo_list_add (&connection->link, &connections);
+ connection->xrender_formats = _cairo_hash_table_create (_xrender_formats_equal);
+ connection->visual_to_xrender_format = _cairo_hash_table_create (_xrender_formats_equal);
+
+ cairo_list_init (&connection->free_xids);
+ _cairo_freepool_init (&connection->xid_pool,
+ sizeof (cairo_xcb_xid_t));
+
+ cairo_list_init (&connection->shm_pools);
+ _cairo_freepool_init (&connection->shm_info_freelist,
+ sizeof (cairo_xcb_shm_info_t));
+
+ connection->maximum_request_length =
+ xcb_get_maximum_request_length (xcb_connection);
+
+ connection->flags = 0;
+
+ connection->root = xcb_get_setup (xcb_connection);
+ connection->render = NULL;
+ ext = xcb_get_extension_data (xcb_connection, &xcb_render_id);
+ if (ext != NULL && ext->present) {
+ status = _cairo_xcb_connection_query_render (connection);
+ if (unlikely (status)) {
+ _cairo_xcb_connection_destroy (connection);
+ connection = NULL;
+ goto unlock;
+ }
+
+ connection->render = ext;
+ }
+
+#if 0
+ ext = xcb_get_extension_data (connection, &xcb_cairo_id);
+ if (ext != NULL && ext->present)
+ _cairo_xcb_connection_query_cairo (connection);
+#endif
+
+ connection->shm = NULL;
+ ext = xcb_get_extension_data (xcb_connection, &xcb_shm_id);
+ if (ext != NULL && ext->present) {
+ _cairo_xcb_connection_query_shm (connection);
+ connection->shm = ext;
+ }
+
+ connection->dri2 = NULL;
+#if CAIRO_HAS_XCB_DRM_FUNCTIONS
+ ext = xcb_get_extension_data (xcb_connection, &xcb_dri2_id);
+ if (ext != NULL && ext->present) {
+ _cairo_xcb_connection_query_dri2 (connection);
+ connection->dri2 = ext;
+ }
+#endif
+
+unlock:
+ CAIRO_MUTEX_UNLOCK (_cairo_xcb_connections_mutex);
+
+ return connection;
+}
+
+xcb_render_pictformat_t
+_cairo_xcb_connection_get_xrender_format (cairo_xcb_connection_t *connection,
+ pixman_format_code_t pixman_format)
+{
+ cairo_hash_entry_t key;
+ cairo_xcb_xrender_format_t *format;
+
+ key.hash = pixman_format;
+ format = _cairo_hash_table_lookup (connection->xrender_formats, &key);
+ return format ? format->xrender_format : XCB_NONE;
+}
+
+xcb_render_pictformat_t
+_cairo_xcb_connection_get_xrender_format_for_visual (cairo_xcb_connection_t *connection,
+ const xcb_visualid_t visual)
+{
+ cairo_hash_entry_t key;
+ cairo_xcb_xrender_format_t *format;
+
+ key.hash = visual;
+ format = _cairo_hash_table_lookup (connection->visual_to_xrender_format, &key);
+ return format ? format->xrender_format : XCB_NONE;
+}
+
+void
+_cairo_xcb_connection_put_xid (cairo_xcb_connection_t *connection,
+ uint32_t xid)
+{
+ cairo_xcb_xid_t *cache;
+
+ assert (CAIRO_MUTEX_IS_LOCKED (connection->mutex));
+ cache = _cairo_freepool_alloc (&connection->xid_pool);
+ if (likely (cache != NULL)) {
+ cache->xid = xid;
+ cairo_list_add (&cache->link, &connection->free_xids);
+ }
+}
+
+uint32_t
+_cairo_xcb_connection_get_xid (cairo_xcb_connection_t *connection)
+{
+ uint32_t xid;
+
+ assert (CAIRO_MUTEX_IS_LOCKED (connection->mutex));
+ if (! cairo_list_is_empty (&connection->free_xids)) {
+ cairo_xcb_xid_t *cache;
+
+ cache = cairo_list_first_entry (&connection->free_xids,
+ cairo_xcb_xid_t,
+ link);
+ xid = cache->xid;
+
+ cairo_list_del (&cache->link);
+ _cairo_freepool_free (&connection->xid_pool, cache);
+ } else {
+ xid = xcb_generate_id (connection->xcb_connection);
+ }
+
+ return xid;
+}
+
+static void
+_cairo_xcb_return_socket (void *closure)
+{
+ cairo_xcb_connection_t *connection = closure;
+
+ CAIRO_MUTEX_LOCK (connection->device.mutex);
+ connection->has_socket = FALSE;
+ CAIRO_MUTEX_UNLOCK (connection->device.mutex);
+}
+
+cairo_status_t
+_cairo_xcb_connection_take_socket (cairo_xcb_connection_t *connection)
+{
+ assert (CAIRO_MUTEX_IS_LOCKED (connection->mutex));
+
+ if (unlikely (connection->device.status))
+ return connection->device.status;
+
+ if (! connection->has_socket) {
+ if (! xcb_take_socket (connection->xcb_connection,
+ _cairo_xcb_return_socket,
+ connection,
+ 0, &connection->seqno))
+ {
+ return connection->device.status = _cairo_error (CAIRO_STATUS_WRITE_ERROR);
+ }
+
+ connection->has_socket = TRUE;
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+/* public (debug) interface */
+
+void
+cairo_xcb_device_debug_cap_xshm_version (cairo_device_t *device,
+ int major_version,
+ int minor_version)
+{
+ cairo_xcb_connection_t *connection = (cairo_xcb_connection_t *) device;
+ cairo_status_t status;
+
+ if (device->backend->type != CAIRO_DEVICE_TYPE_XCB) {
+ status = _cairo_device_set_error (device, CAIRO_STATUS_DEVICE_TYPE_MISMATCH);
+ return;
+ }
+
+ /* clear any flags that are inappropriate for the desired version */
+ if (major_version < 0 && minor_version < 0) {
+ connection->flags &= ~(CAIRO_XCB_HAS_SHM);
+ }
+}
+
+void
+cairo_xcb_device_debug_cap_xrender_version (cairo_device_t *device,
+ int major_version,
+ int minor_version)
+{
+ cairo_xcb_connection_t *connection = (cairo_xcb_connection_t *) device;
+ cairo_status_t status;
+
+ if (device->backend->type != CAIRO_DEVICE_TYPE_XCB) {
+ status = _cairo_device_set_error (device, CAIRO_STATUS_DEVICE_TYPE_MISMATCH);
+ return;
+ }
+
+ /* clear any flags that are inappropriate for the desired version */
+ if (major_version < 0 && minor_version < 0) {
+ connection->flags &= ~(CAIRO_XCB_HAS_RENDER |
+ CAIRO_XCB_RENDER_HAS_COMPOSITE |
+ CAIRO_XCB_RENDER_HAS_COMPOSITE_GLYPHS |
+ CAIRO_XCB_RENDER_HAS_FILL_RECTANGLES |
+ CAIRO_XCB_RENDER_HAS_COMPOSITE_TRAPEZOIDS |
+ CAIRO_XCB_RENDER_HAS_PICTURE_TRANSFORM |
+ CAIRO_XCB_RENDER_HAS_FILTERS |
+ CAIRO_XCB_RENDER_HAS_PDF_OPERATORS |
+ CAIRO_XCB_RENDER_HAS_EXTENDED_REPEAT |
+ CAIRO_XCB_RENDER_HAS_GRADIENTS);
+ } else {
+ xcb_render_query_version_reply_t version;
+
+ version.major_version = major_version;
+ version.minor_version = minor_version;
+
+ if (! XCB_RENDER_HAS_FILL_RECTANGLES (&version))
+ connection->flags &= ~CAIRO_XCB_RENDER_HAS_FILL_RECTANGLES;
+
+ if (! XCB_RENDER_HAS_TRAPEZOIDS (&version))
+ connection->flags &= ~CAIRO_XCB_RENDER_HAS_COMPOSITE_TRAPEZOIDS;
+
+ if (! XCB_RENDER_HAS_PICTURE_TRANSFORM (&version))
+ connection->flags &= ~CAIRO_XCB_RENDER_HAS_PICTURE_TRANSFORM;
+
+ if (! XCB_RENDER_HAS_FILTERS (&version))
+ connection->flags &= ~CAIRO_XCB_RENDER_HAS_FILTERS;
+
+ if (! XCB_RENDER_HAS_PDF_OPERATORS (&version))
+ connection->flags &= ~CAIRO_XCB_RENDER_HAS_PDF_OPERATORS;
+
+ if (! XCB_RENDER_HAS_EXTENDED_REPEAT (&version))
+ connection->flags &= ~CAIRO_XCB_RENDER_HAS_EXTENDED_REPEAT;
+
+ if (! XCB_RENDER_HAS_GRADIENTS (&version))
+ connection->flags &= ~CAIRO_XCB_RENDER_HAS_GRADIENTS;
+ }
+}
+
+#if 0
+void
+cairo_xcb_device_debug_cap_xcairo_version (cairo_device_t *device,
+ int major_version,
+ int minor_version)
+{
+ cairo_xcb_connection_t *connection = (cairo_xcb_connection_t *) device;
+ cairo_status_t status;
+
+ if (device->backend->type != CAIRO_DEVICE_TYPE_XCB) {
+ status = _cairo_device_set_error (device, CAIRO_STATUS_DEVICE_TYPE_MISMATCH);
+ return;
+ }
+
+ /* clear any flags that are inappropriate for the desired version */
+ if (major_version < 0 && minor_version < 0) {
+ connection->flags &= ~(CAIRO_XCB_HAS_CAIRO);
+ }
+}
+#endif
diff --git a/src/cairo-xcb-private.h b/src/cairo-xcb-private.h
new file mode 100644
index 0000000..18a485c
--- /dev/null
+++ b/src/cairo-xcb-private.h
@@ -0,0 +1,760 @@
+/* Cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2005 Red Hat, Inc.
+ * 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 Red Hat, Inc.
+ *
+ * Contributors(s):
+ * Chris Wilson <chris at chris-wilson.co.uk>
+ */
+
+#ifndef CAIRO_XCB_PRIVATE_H
+#define CAIRO_XCB_PRIVATE_H
+
+#include "cairo-xcb.h"
+
+#include "cairo-cache-private.h"
+#include "cairo-compiler-private.h"
+#include "cairo-device-private.h"
+#include "cairo-error-private.h"
+#include "cairo-freelist-private.h"
+#include "cairo-list-private.h"
+#include "cairo-mutex-private.h"
+#include "cairo-reference-count-private.h"
+#include "cairo-spans-private.h"
+#include "cairo-surface-private.h"
+
+#include <xcb/xcb.h>
+#include <xcb/render.h>
+#include <xcb/xcbext.h>
+#include <pixman.h>
+
+typedef struct _cairo_xcb_connection cairo_xcb_connection_t;
+typedef struct _cairo_xcb_font cairo_xcb_font_t;
+typedef struct _cairo_xcb_screen cairo_xcb_screen_t;
+typedef struct _cairo_xcb_surface cairo_xcb_surface_t;
+typedef struct _cairo_xcb_shm_mem_pool cairo_xcb_shm_mem_pool_t;
+typedef struct _cairo_xcb_shm_info cairo_xcb_shm_info_t;
+
+struct _cairo_xcb_shm_info {
+ cairo_xcb_connection_t *connection;
+ uint32_t shm;
+ uint32_t offset;
+ uint64_t seqno;
+ void *mem;
+ cairo_xcb_shm_mem_pool_t *pool;
+};
+
+struct _cairo_xcb_surface {
+ cairo_surface_t base;
+ cairo_surface_t *fallback;
+
+ cairo_xcb_connection_t *connection;
+ cairo_xcb_screen_t *screen;
+
+ cairo_surface_t *drm;
+ cairo_bool_t marked_dirty;
+
+ xcb_drawable_t drawable;
+ cairo_bool_t owns_pixmap;
+ int use_pixmap;
+
+ int width;
+ int height;
+ int depth;
+
+ unsigned int flags;
+ xcb_render_picture_t picture;
+ xcb_render_pictformat_t xrender_format;
+ pixman_format_code_t pixman_format;
+
+ cairo_list_t link;
+};
+
+#if CAIRO_HAS_XLIB_XCB_FUNCTIONS
+typedef struct _cairo_xlib_xcb_surface {
+ cairo_surface_t base;
+
+ cairo_xcb_surface_t *xcb;
+
+ /* original settings for query */
+ void *display;
+ void *screen;
+ void *visual;
+ void *format;
+} cairo_xlib_xcb_surface_t;
+#endif
+
+
+enum {
+ GLYPHSET_INDEX_ARGB32,
+ GLYPHSET_INDEX_A8,
+ GLYPHSET_INDEX_A1,
+ NUM_GLYPHSETS
+};
+
+typedef struct _cairo_xcb_font_glyphset_free_glyphs {
+ xcb_render_glyphset_t glyphset;
+ int glyph_count;
+ xcb_render_glyph_t glyph_indices[128];
+} cairo_xcb_font_glyphset_free_glyphs_t;
+
+typedef struct _cairo_xcb_font_glyphset_info {
+ xcb_render_glyphset_t glyphset;
+ cairo_format_t format;
+ xcb_render_pictformat_t xrender_format;
+ cairo_xcb_font_glyphset_free_glyphs_t *pending_free_glyphs;
+} cairo_xcb_font_glyphset_info_t;
+
+struct _cairo_xcb_font {
+ cairo_scaled_font_t *scaled_font;
+ cairo_xcb_connection_t *connection;
+ cairo_xcb_font_glyphset_info_t glyphset_info[NUM_GLYPHSETS];
+ cairo_list_t link;
+};
+
+struct _cairo_xcb_screen {
+ cairo_xcb_connection_t *connection;
+
+ xcb_screen_t *xcb_screen;
+ cairo_device_t *device;
+
+ xcb_gcontext_t gc[4];
+ int gc_depths; /* 4 x uint8_t */
+
+ cairo_surface_t *stock_colors[CAIRO_STOCK_NUM_COLORS];
+ struct {
+ cairo_surface_t *picture;
+ cairo_color_t color;
+ } solid_cache[16];
+ int solid_cache_size;
+
+ cairo_cache_t surface_pattern_cache;
+ cairo_cache_t linear_pattern_cache;
+ cairo_cache_t radial_pattern_cache;
+ cairo_freelist_t pattern_cache_entry_freelist;
+
+ cairo_list_t link;
+ cairo_list_t surfaces;
+};
+
+struct _cairo_xcb_connection {
+ cairo_device_t device;
+
+ xcb_connection_t *xcb_connection;
+ cairo_bool_t has_socket;
+
+ xcb_render_pictformat_t standard_formats[5];
+ cairo_hash_table_t *xrender_formats;
+ cairo_hash_table_t *visual_to_xrender_format;
+
+ unsigned int maximum_request_length;
+ unsigned int flags;
+
+ const xcb_setup_t *root;
+ const xcb_query_extension_reply_t *render;
+ const xcb_query_extension_reply_t *shm;
+ const xcb_query_extension_reply_t *dri2;
+ uint64_t seqno;
+
+ cairo_list_t free_xids;
+ cairo_freepool_t xid_pool;
+
+ cairo_mutex_t shm_mutex;
+ cairo_list_t shm_pools;
+ cairo_freepool_t shm_info_freelist;
+
+ cairo_mutex_t screens_mutex;
+ cairo_list_t screens;
+
+ cairo_list_t fonts;
+
+ cairo_list_t link;
+};
+
+enum {
+ CAIRO_XCB_HAS_RENDER = 0x0001,
+ CAIRO_XCB_RENDER_HAS_FILL_RECTANGLES = 0x0002,
+ CAIRO_XCB_RENDER_HAS_COMPOSITE = 0x0004,
+ CAIRO_XCB_RENDER_HAS_COMPOSITE_TRAPEZOIDS = 0x0008,
+ CAIRO_XCB_RENDER_HAS_COMPOSITE_SPANS = 0x0010,
+ CAIRO_XCB_RENDER_HAS_COMPOSITE_GLYPHS = 0x0020,
+ CAIRO_XCB_RENDER_HAS_PICTURE_TRANSFORM = 0x0040,
+ CAIRO_XCB_RENDER_HAS_FILTERS = 0x0080,
+ CAIRO_XCB_RENDER_HAS_PDF_OPERATORS = 0x0100,
+ CAIRO_XCB_RENDER_HAS_EXTENDED_REPEAT = 0x0200,
+ CAIRO_XCB_RENDER_HAS_GRADIENTS = 0x0400,
+
+ CAIRO_XCB_HAS_CAIRO = 0x10000,
+
+ CAIRO_XCB_HAS_DRI2 = 0x40000000,
+ CAIRO_XCB_HAS_SHM = 0x80000000
+};
+
+#define CAIRO_XCB_SHM_SMALL_IMAGE 8192
+
+cairo_private extern const cairo_surface_backend_t _cairo_xcb_surface_backend;
+
+cairo_private cairo_xcb_connection_t *
+_cairo_xcb_connection_get (xcb_connection_t *connection);
+
+static inline cairo_xcb_connection_t *
+_cairo_xcb_connection_reference (cairo_xcb_connection_t *connection)
+{
+ return (cairo_xcb_connection_t *) cairo_device_reference (&connection->device);
+}
+
+cairo_private xcb_render_pictformat_t
+_cairo_xcb_connection_get_xrender_format (cairo_xcb_connection_t *connection,
+ pixman_format_code_t pixman_format);
+
+cairo_private xcb_render_pictformat_t
+_cairo_xcb_connection_get_xrender_format_for_visual (cairo_xcb_connection_t *connection,
+ const xcb_visualid_t visual);
+
+static inline cairo_status_t cairo_warn
+_cairo_xcb_connection_acquire (cairo_xcb_connection_t *connection)
+{
+ return cairo_device_acquire (&connection->device);
+}
+
+cairo_private cairo_status_t
+_cairo_xcb_connection_take_socket (cairo_xcb_connection_t *connection);
+
+cairo_private uint32_t
+_cairo_xcb_connection_get_xid (cairo_xcb_connection_t *connection);
+
+cairo_private void
+_cairo_xcb_connection_put_xid (cairo_xcb_connection_t *connection,
+ uint32_t xid);
+
+static inline void
+_cairo_xcb_connection_release (cairo_xcb_connection_t *connection)
+{
+ cairo_device_release (&connection->device);
+}
+
+static inline void
+_cairo_xcb_connection_destroy (cairo_xcb_connection_t *connection)
+{
+ cairo_device_destroy (&connection->device);
+}
+
+cairo_private cairo_int_status_t
+_cairo_xcb_connection_allocate_shm_info (cairo_xcb_connection_t *display,
+ size_t size,
+ cairo_xcb_shm_info_t **shm_info_out);
+
+cairo_private void
+_cairo_xcb_shm_info_destroy (cairo_xcb_shm_info_t *shm_info);
+
+cairo_private void
+_cairo_xcb_connection_shm_mem_pools_fini (cairo_xcb_connection_t *connection);
+
+cairo_private void
+_cairo_xcb_font_finish (cairo_xcb_font_t *font);
+
+cairo_private cairo_xcb_screen_t *
+_cairo_xcb_screen_get (xcb_connection_t *connection,
+ xcb_screen_t *screen);
+
+cairo_private void
+_cairo_xcb_screen_finish (cairo_xcb_screen_t *screen);
+
+cairo_private xcb_gcontext_t
+_cairo_xcb_screen_get_gc (cairo_xcb_screen_t *screen,
+ xcb_drawable_t drawable,
+ int depth);
+
+cairo_private void
+_cairo_xcb_screen_put_gc (cairo_xcb_screen_t *screen, int depth, xcb_gcontext_t gc);
+
+cairo_private cairo_status_t
+_cairo_xcb_screen_store_surface_picture (cairo_xcb_screen_t *screen,
+ cairo_surface_t *picture,
+ unsigned int size);
+cairo_private void
+_cairo_xcb_screen_remove_surface_picture (cairo_xcb_screen_t *screen,
+ cairo_surface_t *picture);
+
+cairo_private cairo_status_t
+_cairo_xcb_screen_store_linear_picture (cairo_xcb_screen_t *screen,
+ const cairo_linear_pattern_t *linear,
+ cairo_surface_t *picture);
+
+cairo_private cairo_surface_t *
+_cairo_xcb_screen_lookup_linear_picture (cairo_xcb_screen_t *screen,
+ const cairo_linear_pattern_t *linear);
+
+cairo_private cairo_status_t
+_cairo_xcb_screen_store_radial_picture (cairo_xcb_screen_t *screen,
+ const cairo_radial_pattern_t *radial,
+ cairo_surface_t *picture);
+
+cairo_private cairo_surface_t *
+_cairo_xcb_screen_lookup_radial_picture (cairo_xcb_screen_t *screen,
+ const cairo_radial_pattern_t *radial);
+
+cairo_private cairo_surface_t *
+_cairo_xcb_surface_create_similar_image (cairo_xcb_surface_t *other,
+ cairo_content_t content,
+ int width, int height);
+
+cairo_private cairo_surface_t *
+_cairo_xcb_surface_create_similar (void *abstract_other,
+ cairo_content_t content,
+ int width,
+ int height);
+
+cairo_private cairo_surface_t *
+_cairo_xcb_surface_create_internal (cairo_xcb_screen_t *screen,
+ xcb_drawable_t drawable,
+ cairo_bool_t owns_pixmap,
+ pixman_format_code_t pixman_format,
+ xcb_render_pictformat_t xrender_format,
+ int width,
+ int height);
+
+cairo_private cairo_int_status_t
+_cairo_xcb_surface_cairo_paint (cairo_xcb_surface_t *surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_clip_t *clip);
+
+cairo_private cairo_int_status_t
+_cairo_xcb_surface_cairo_mask (cairo_xcb_surface_t *surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ const cairo_pattern_t *mask,
+ cairo_clip_t *clip);
+
+cairo_private cairo_int_status_t
+_cairo_xcb_surface_cairo_stroke (cairo_xcb_surface_t *surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_path_fixed_t *path,
+ const cairo_stroke_style_t *style,
+ const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm_inverse,
+ double tolerance,
+ cairo_antialias_t antialias,
+ cairo_clip_t *clip);
+
+cairo_private cairo_int_status_t
+_cairo_xcb_surface_cairo_fill (cairo_xcb_surface_t *surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_path_fixed_t *path,
+ cairo_fill_rule_t fill_rule,
+ double tolerance,
+ cairo_antialias_t antialias,
+ cairo_clip_t *clip);
+
+cairo_private cairo_int_status_t
+_cairo_xcb_surface_cairo_glyphs (cairo_xcb_surface_t *surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_scaled_font_t *scaled_font,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_clip_t *clip);
+
+cairo_private cairo_int_status_t
+_cairo_xcb_surface_render_paint (cairo_xcb_surface_t *surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_clip_t *clip);
+
+cairo_private cairo_int_status_t
+_cairo_xcb_surface_render_mask (cairo_xcb_surface_t *surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ const cairo_pattern_t *mask,
+ cairo_clip_t *clip);
+
+cairo_private cairo_int_status_t
+_cairo_xcb_surface_render_stroke (cairo_xcb_surface_t *surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_path_fixed_t *path,
+ const cairo_stroke_style_t *style,
+ const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm_inverse,
+ double tolerance,
+ cairo_antialias_t antialias,
+ cairo_clip_t *clip);
+
+cairo_private cairo_int_status_t
+_cairo_xcb_surface_render_fill (cairo_xcb_surface_t *surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_path_fixed_t *path,
+ cairo_fill_rule_t fill_rule,
+ double tolerance,
+ cairo_antialias_t antialias,
+ cairo_clip_t *clip);
+
+cairo_private cairo_int_status_t
+_cairo_xcb_surface_render_glyphs (cairo_xcb_surface_t *surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_scaled_font_t *scaled_font,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_clip_t *clip);
+cairo_private void
+_cairo_xcb_surface_scaled_font_fini (cairo_scaled_font_t *scaled_font);
+
+cairo_private void
+_cairo_xcb_surface_scaled_glyph_fini (cairo_scaled_glyph_t *scaled_glyph,
+ cairo_scaled_font_t *scaled_font);
+
+cairo_private cairo_status_t
+_cairo_xcb_surface_core_copy_boxes (cairo_xcb_surface_t *dst,
+ const cairo_pattern_t *src_pattern,
+ const cairo_rectangle_int_t *extents,
+ const cairo_boxes_t *boxes);
+
+cairo_private cairo_status_t
+_cairo_xcb_surface_core_fill_boxes (cairo_xcb_surface_t *dst,
+ const cairo_color_t *color,
+ cairo_boxes_t *boxes);
+
+static inline void
+_cairo_xcb_connection_write (cairo_xcb_connection_t *connection,
+ struct iovec *vec,
+ int count)
+{
+ if (unlikely (connection->device.status))
+ return;
+
+ connection->seqno++;
+ if (unlikely (! xcb_writev (connection->xcb_connection, vec, count, 1)))
+ connection->device.status = _cairo_error (CAIRO_STATUS_WRITE_ERROR);
+}
+
+cairo_private xcb_pixmap_t
+_cairo_xcb_connection_create_pixmap (cairo_xcb_connection_t *connection,
+ uint8_t depth,
+ xcb_drawable_t drawable,
+ uint16_t width,
+ uint16_t height);
+
+cairo_private void
+_cairo_xcb_connection_free_pixmap (cairo_xcb_connection_t *connection,
+ xcb_pixmap_t pixmap);
+
+cairo_private xcb_gcontext_t
+_cairo_xcb_connection_create_gc (cairo_xcb_connection_t *connection,
+ xcb_drawable_t drawable,
+ uint32_t value_mask,
+ uint32_t *values);
+
+cairo_private void
+_cairo_xcb_connection_free_gc (cairo_xcb_connection_t *connection,
+ xcb_gcontext_t gc);
+
+cairo_private void
+_cairo_xcb_connection_change_gc (cairo_xcb_connection_t *connection,
+ xcb_gcontext_t gc,
+ uint32_t value_mask,
+ uint32_t *values);
+
+cairo_private void
+_cairo_xcb_connection_copy_area (cairo_xcb_connection_t *connection,
+ xcb_drawable_t src,
+ xcb_drawable_t dst,
+ xcb_gcontext_t gc,
+ int16_t src_x,
+ int16_t src_y,
+ int16_t dst_x,
+ int16_t dst_y,
+ uint16_t width,
+ uint16_t height);
+
+cairo_private void
+_cairo_xcb_connection_put_image (cairo_xcb_connection_t *connection,
+ xcb_drawable_t dst,
+ xcb_gcontext_t gc,
+ uint16_t width,
+ uint16_t height,
+ int16_t dst_x,
+ int16_t dst_y,
+ uint8_t depth,
+ uint32_t length,
+ void *data);
+
+cairo_private void
+_cairo_xcb_connection_put_subimage (cairo_xcb_connection_t *connection,
+ xcb_drawable_t dst,
+ xcb_gcontext_t gc,
+ int16_t src_x,
+ int16_t src_y,
+ uint16_t width,
+ uint16_t height,
+ uint16_t cpp,
+ uint16_t stride,
+ int16_t dst_x,
+ int16_t dst_y,
+ uint8_t depth,
+ void *data);
+
+cairo_private cairo_status_t
+_cairo_xcb_connection_get_image (cairo_xcb_connection_t *connection,
+ xcb_drawable_t src,
+ int16_t src_x,
+ int16_t src_y,
+ uint16_t width,
+ uint16_t height,
+ xcb_get_image_reply_t **reply);
+
+cairo_private void
+_cairo_xcb_connection_poly_fill_rectangle (cairo_xcb_connection_t *connection,
+ xcb_drawable_t dst,
+ xcb_gcontext_t gc,
+ uint32_t num_rectangles,
+ xcb_rectangle_t *rectangles);
+
+cairo_private uint32_t
+_cairo_xcb_connection_shm_attach (cairo_xcb_connection_t *connection,
+ uint32_t id,
+ cairo_bool_t readonly);
+
+cairo_private uint64_t
+_cairo_xcb_connection_shm_put_image (cairo_xcb_connection_t *connection,
+ xcb_drawable_t dst,
+ xcb_gcontext_t gc,
+ uint16_t total_width,
+ uint16_t total_height,
+ int16_t src_x,
+ int16_t src_y,
+ uint16_t width,
+ uint16_t height,
+ int16_t dst_x,
+ int16_t dst_y,
+ uint8_t depth,
+ uint32_t shm,
+ uint32_t offset);
+
+cairo_private cairo_status_t
+_cairo_xcb_connection_shm_get_image (cairo_xcb_connection_t *connection,
+ xcb_drawable_t src,
+ int16_t src_x,
+ int16_t src_y,
+ uint16_t width,
+ uint16_t height,
+ uint32_t shmseg,
+ uint32_t offset);
+
+cairo_private void
+_cairo_xcb_connection_shm_detach (cairo_xcb_connection_t *connection,
+ uint32_t segment);
+
+cairo_private void
+_cairo_xcb_connection_render_spans (cairo_xcb_connection_t *connection,
+ xcb_render_picture_t dst,
+ int op,
+ xcb_render_picture_t src,
+ int16_t src_x, int16_t src_y,
+ int16_t dst_x, int16_t dst_y,
+ int16_t width, int16_t height,
+ unsigned int length,
+ uint16_t *spans);
+cairo_private void
+_cairo_xcb_connection_render_create_picture (cairo_xcb_connection_t *connection,
+ xcb_render_picture_t picture,
+ xcb_drawable_t drawable,
+ xcb_render_pictformat_t format,
+ uint32_t value_mask,
+ uint32_t *value_list);
+
+cairo_private void
+_cairo_xcb_connection_render_change_picture (cairo_xcb_connection_t *connection,
+ xcb_render_picture_t picture,
+ uint32_t value_mask,
+ uint32_t *value_list);
+
+cairo_private void
+_cairo_xcb_connection_render_set_picture_clip_rectangles (cairo_xcb_connection_t *connection,
+ xcb_render_picture_t picture,
+ int16_t clip_x_origin,
+ int16_t clip_y_origin,
+ uint32_t rectangles_len,
+ xcb_rectangle_t *rectangles);
+
+cairo_private void
+_cairo_xcb_connection_render_free_picture (cairo_xcb_connection_t *connection,
+ xcb_render_picture_t picture);
+
+cairo_private void
+_cairo_xcb_connection_render_composite (cairo_xcb_connection_t *connection,
+ uint8_t op,
+ xcb_render_picture_t src,
+ xcb_render_picture_t mask,
+ xcb_render_picture_t dst,
+ int16_t src_x,
+ int16_t src_y,
+ int16_t mask_x,
+ int16_t mask_y,
+ int16_t dst_x,
+ int16_t dst_y,
+ uint16_t width,
+ uint16_t height);
+
+cairo_private void
+_cairo_xcb_connection_render_trapezoids (cairo_xcb_connection_t *connection,
+ uint8_t op,
+ xcb_render_picture_t src,
+ xcb_render_picture_t dst,
+ xcb_render_pictformat_t mask_format,
+ int16_t src_x,
+ int16_t src_y,
+ uint32_t traps_len,
+ xcb_render_trapezoid_t *traps);
+
+cairo_private void
+_cairo_xcb_connection_render_create_glyph_set (cairo_xcb_connection_t *connection,
+ xcb_render_glyphset_t id,
+ xcb_render_pictformat_t format);
+
+cairo_private void
+_cairo_xcb_connection_render_free_glyph_set (cairo_xcb_connection_t *connection,
+ xcb_render_glyphset_t glyphset);
+
+cairo_private void
+_cairo_xcb_connection_render_add_glyphs (cairo_xcb_connection_t *connection,
+ xcb_render_glyphset_t glyphset,
+ uint32_t num_glyphs,
+ uint32_t *glyphs_id,
+ xcb_render_glyphinfo_t *glyphs,
+ uint32_t data_len,
+ uint8_t *data);
+
+cairo_private void
+_cairo_xcb_connection_render_free_glyphs (cairo_xcb_connection_t *connection,
+ xcb_render_glyphset_t glyphset,
+ uint32_t num_glyphs,
+ xcb_render_glyph_t *glyphs);
+
+cairo_private void
+_cairo_xcb_connection_render_composite_glyphs_8 (cairo_xcb_connection_t *connection,
+ uint8_t op,
+ xcb_render_picture_t src,
+ xcb_render_picture_t dst,
+ xcb_render_pictformat_t mask_format,
+ xcb_render_glyphset_t glyphset,
+ int16_t src_x,
+ int16_t src_y,
+ uint32_t glyphcmds_len,
+ uint8_t *glyphcmds);
+
+cairo_private void
+_cairo_xcb_connection_render_composite_glyphs_16 (cairo_xcb_connection_t *connection,
+ uint8_t op,
+ xcb_render_picture_t src,
+ xcb_render_picture_t dst,
+ xcb_render_pictformat_t mask_format,
+ xcb_render_glyphset_t glyphset,
+ int16_t src_x,
+ int16_t src_y,
+ uint32_t glyphcmds_len,
+ uint8_t *glyphcmds);
+
+cairo_private void
+_cairo_xcb_connection_render_composite_glyphs_32 (cairo_xcb_connection_t *connection,
+ uint8_t op,
+ xcb_render_picture_t src,
+ xcb_render_picture_t dst,
+ xcb_render_pictformat_t mask_format,
+ xcb_render_glyphset_t glyphset,
+ int16_t src_x,
+ int16_t src_y,
+ uint32_t glyphcmds_len,
+ uint8_t *glyphcmds);
+
+cairo_private void
+_cairo_xcb_connection_render_fill_rectangles (cairo_xcb_connection_t *connection,
+ uint8_t op,
+ xcb_render_picture_t dst,
+ xcb_render_color_t color,
+ uint32_t num_rects,
+ xcb_rectangle_t *rects);
+
+cairo_private void
+_cairo_xcb_connection_render_set_picture_transform (cairo_xcb_connection_t *connection,
+ xcb_render_picture_t picture,
+ xcb_render_transform_t *transform);
+
+cairo_private void
+_cairo_xcb_connection_render_set_picture_filter (cairo_xcb_connection_t *connection,
+ xcb_render_picture_t picture,
+ uint16_t filter_len,
+ char *filter);
+
+cairo_private void
+_cairo_xcb_connection_render_create_solid_fill (cairo_xcb_connection_t *connection,
+ xcb_render_picture_t picture,
+ xcb_render_color_t color);
+
+cairo_private void
+_cairo_xcb_connection_render_create_linear_gradient (cairo_xcb_connection_t *connection,
+ xcb_render_picture_t picture,
+ xcb_render_pointfix_t p1,
+ xcb_render_pointfix_t p2,
+ uint32_t num_stops,
+ xcb_render_fixed_t *stops,
+ xcb_render_color_t *colors);
+
+cairo_private void
+_cairo_xcb_connection_render_create_radial_gradient (cairo_xcb_connection_t *connection,
+ xcb_render_picture_t picture,
+ xcb_render_pointfix_t inner,
+ xcb_render_pointfix_t outer,
+ xcb_render_fixed_t inner_radius,
+ xcb_render_fixed_t outer_radius,
+ uint32_t num_stops,
+ xcb_render_fixed_t *stops,
+ xcb_render_color_t *colors);
+
+cairo_private void
+_cairo_xcb_connection_render_create_conical_gradient (cairo_xcb_connection_t *c,
+ xcb_render_picture_t picture,
+ xcb_render_pointfix_t center,
+ xcb_render_fixed_t angle,
+ uint32_t num_stops,
+ xcb_render_fixed_t *stops,
+ xcb_render_color_t *colors);
+#if CAIRO_HAS_XLIB_XCB_FUNCTIONS
+slim_hidden_proto (cairo_xcb_surface_create);
+slim_hidden_proto (cairo_xcb_surface_create_for_bitmap);
+slim_hidden_proto (cairo_xcb_surface_create_with_xrender_format);
+slim_hidden_proto (cairo_xcb_surface_set_size);
+#endif
+
+#endif /* CAIRO_XCB_PRIVATE_H */
diff --git a/src/cairo-xcb-screen.c b/src/cairo-xcb-screen.c
new file mode 100644
index 0000000..06c07a5
--- /dev/null
+++ b/src/cairo-xcb-screen.c
@@ -0,0 +1,518 @@
+/* Cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2008 Chris Wilson
+ * 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.
+ *
+ * Authors:
+ * Chris Wilson <chris at chris-wilson.co.uk>
+ */
+
+#include "cairoint.h"
+
+#include "cairo-xcb-private.h"
+
+struct pattern_cache_entry {
+ cairo_cache_entry_t key;
+ cairo_xcb_screen_t *screen;
+ cairo_pattern_union_t pattern;
+ cairo_surface_t *picture;
+};
+
+void
+_cairo_xcb_screen_finish (cairo_xcb_screen_t *screen)
+{
+ int i;
+
+ CAIRO_MUTEX_LOCK (screen->connection->screens_mutex);
+ cairo_list_del (&screen->link);
+ CAIRO_MUTEX_UNLOCK (screen->connection->screens_mutex);
+
+ while (! cairo_list_is_empty (&screen->surfaces)) {
+ cairo_surface_t *surface;
+
+ surface = &cairo_list_first_entry (&screen->surfaces,
+ cairo_xcb_surface_t,
+ link)->base;
+
+ cairo_surface_reference (surface);
+ cairo_surface_finish (surface);
+ cairo_surface_destroy (surface);
+ }
+
+ for (i = 0; i < screen->solid_cache_size; i++)
+ cairo_surface_destroy (screen->solid_cache[i].picture);
+
+ for (i = 0; i < ARRAY_LENGTH (screen->stock_colors); i++)
+ cairo_surface_destroy (screen->stock_colors[i]);
+
+ _cairo_cache_fini (&screen->surface_pattern_cache);
+ _cairo_cache_fini (&screen->linear_pattern_cache);
+ _cairo_cache_fini (&screen->radial_pattern_cache);
+ _cairo_freelist_fini (&screen->pattern_cache_entry_freelist);
+
+ cairo_device_finish (screen->device);
+ cairo_device_destroy (screen->device);
+
+ free (screen);
+}
+
+static cairo_bool_t
+_surface_pattern_cache_entry_equal (const void *A, const void *B)
+{
+ const struct pattern_cache_entry *a = A, *b = B;
+
+ return a->key.hash == b->key.hash;
+}
+
+static cairo_bool_t
+_linear_pattern_cache_entry_equal (const void *A, const void *B)
+{
+ const struct pattern_cache_entry *a = A, *b = B;
+
+ if (a->key.hash != b->key.hash)
+ return FALSE;
+
+ return _cairo_linear_pattern_equal (&a->pattern.gradient.linear,
+ &b->pattern.gradient.linear);
+}
+
+static cairo_bool_t
+_radial_pattern_cache_entry_equal (const void *A, const void *B)
+{
+ const struct pattern_cache_entry *a = A, *b = B;
+
+ if (a->key.hash != b->key.hash)
+ return FALSE;
+
+ return _cairo_radial_pattern_equal (&a->pattern.gradient.radial,
+ &b->pattern.gradient.radial);
+}
+
+static void
+_surface_cache_entry_destroy (void *closure)
+{
+ struct pattern_cache_entry *entry = closure;
+
+ cairo_surface_finish (entry->picture);
+ cairo_surface_destroy (entry->picture);
+ _cairo_freelist_free (&entry->screen->pattern_cache_entry_freelist, entry);
+}
+
+static void
+_pattern_cache_entry_destroy (void *closure)
+{
+ struct pattern_cache_entry *entry = closure;
+
+ _cairo_pattern_fini (&entry->pattern.base);
+ cairo_surface_destroy (entry->picture);
+ _cairo_freelist_free (&entry->screen->pattern_cache_entry_freelist, entry);
+}
+
+#if CAIRO_HAS_DRM_SURFACE && CAIRO_HAS_XCB_DRM_FUNCTIONS
+#include "drm/cairo-drm-private.h"
+
+#include <drm/drm.h>
+#include <sys/ioctl.h>
+#include <xcb/dri2.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+
+static int drm_magic (int fd, uint32_t *magic)
+{
+ drm_auth_t auth;
+
+ if (ioctl (fd, DRM_IOCTL_GET_MAGIC, &auth))
+ return -errno;
+
+ *magic = auth.magic;
+ return 0;
+}
+
+static cairo_device_t *
+_xcb_drm_device (xcb_connection_t *xcb_connection,
+ xcb_screen_t *xcb_screen)
+{
+ cairo_device_t *device = NULL;
+ xcb_dri2_connect_reply_t *connect;
+ drm_magic_t magic;
+ int fd;
+
+ connect = xcb_dri2_connect_reply (xcb_connection,
+ xcb_dri2_connect (xcb_connection,
+ xcb_screen->root,
+ 0),
+ 0);
+ if (connect == NULL)
+ return NULL;
+
+ fd = open (xcb_dri2_connect_device_name (connect), O_RDWR);
+ free (connect);
+
+ if (fd < 0)
+ return NULL;
+
+ device = cairo_drm_device_get_for_fd (fd);
+ close (fd);
+
+ if (device != NULL) {
+ xcb_dri2_authenticate_reply_t *authenticate;
+
+ if (drm_magic (((cairo_drm_device_t *) device)->fd, &magic) < 0) {
+ cairo_device_destroy (device);
+ return NULL;
+ }
+
+ authenticate = xcb_dri2_authenticate_reply (xcb_connection,
+ xcb_dri2_authenticate (xcb_connection,
+ xcb_screen->root,
+ magic),
+ 0);
+ if (authenticate == NULL) {
+ cairo_device_destroy (device);
+ return NULL;
+ }
+
+ free (authenticate);
+ }
+
+ return device;
+}
+#else
+static cairo_device_t *
+_xcb_drm_device (xcb_connection_t *xcb_connection,
+ xcb_screen_t *xcb_screen)
+{
+ return NULL;
+}
+#endif
+
+cairo_xcb_screen_t *
+_cairo_xcb_screen_get (xcb_connection_t *xcb_connection,
+ xcb_screen_t *xcb_screen)
+{
+ cairo_xcb_connection_t *connection;
+ cairo_xcb_screen_t *screen;
+ cairo_status_t status;
+ int i;
+
+ connection = _cairo_xcb_connection_get (xcb_connection);
+ if (unlikely (connection == NULL))
+ return NULL;
+
+ CAIRO_MUTEX_LOCK (connection->screens_mutex);
+
+ cairo_list_foreach_entry (screen,
+ cairo_xcb_screen_t,
+ &connection->screens,
+ link)
+ {
+ if (screen->xcb_screen == xcb_screen) {
+ /* Maintain list in MRU order */
+ if (&screen->link != connection->screens.next)
+ cairo_list_move (&screen->link, &connection->screens);
+
+ goto unlock;
+ }
+ }
+
+ screen = malloc (sizeof (cairo_xcb_screen_t));
+ if (unlikely (screen == NULL))
+ goto unlock;
+
+ screen->connection = connection;
+ screen->xcb_screen = xcb_screen;
+
+ if (connection->flags & CAIRO_XCB_HAS_DRI2)
+ screen->device = _xcb_drm_device (xcb_connection, xcb_screen);
+ else
+ screen->device = NULL;
+
+ screen->gc_depths = 0;
+ memset (screen->gc, 0, sizeof (screen->gc));
+
+ screen->solid_cache_size = 0;
+ for (i = 0; i < ARRAY_LENGTH (screen->stock_colors); i++)
+ screen->stock_colors[i] = NULL;
+
+ status = _cairo_cache_init (&screen->surface_pattern_cache,
+ _surface_pattern_cache_entry_equal,
+ NULL,
+ _surface_cache_entry_destroy,
+ 16*1024*1024);
+ if (unlikely (status))
+ goto error_screen;
+
+ status = _cairo_cache_init (&screen->linear_pattern_cache,
+ _linear_pattern_cache_entry_equal,
+ NULL,
+ _pattern_cache_entry_destroy,
+ 16);
+ if (unlikely (status))
+ goto error_surface;
+
+ status = _cairo_cache_init (&screen->radial_pattern_cache,
+ _radial_pattern_cache_entry_equal,
+ NULL,
+ _pattern_cache_entry_destroy,
+ 4);
+ if (unlikely (status))
+ goto error_linear;
+
+ _cairo_freelist_init (&screen->pattern_cache_entry_freelist,
+ sizeof (struct pattern_cache_entry));
+
+ cairo_list_add (&screen->link, &connection->screens);
+ cairo_list_init (&screen->surfaces);
+
+unlock:
+ CAIRO_MUTEX_UNLOCK (connection->screens_mutex);
+
+ return screen;
+
+error_surface:
+ _cairo_cache_fini (&screen->surface_pattern_cache);
+error_linear:
+ _cairo_cache_fini (&screen->linear_pattern_cache);
+error_screen:
+ cairo_device_destroy (screen->device);
+ free (screen);
+ CAIRO_MUTEX_UNLOCK (connection->screens_mutex);
+
+ return NULL;
+}
+
+static xcb_gcontext_t
+_create_gc (cairo_xcb_screen_t *screen,
+ xcb_drawable_t drawable)
+{
+ uint32_t values[] = { 0 };
+
+ return _cairo_xcb_connection_create_gc (screen->connection, drawable,
+ XCB_GC_GRAPHICS_EXPOSURES,
+ values);
+}
+
+xcb_gcontext_t
+_cairo_xcb_screen_get_gc (cairo_xcb_screen_t *screen,
+ xcb_drawable_t drawable,
+ int depth)
+{
+ int i;
+
+ assert (CAIRO_MUTEX_IS_LOCKED (screen->connection->mutex));
+
+ for (i = 0; i < ARRAY_LENGTH (screen->gc); i++) {
+ if (((screen->gc_depths >> (8*i)) & 0xff) == depth) {
+ screen->gc_depths &= ~(0xff << (8*i));
+ return screen->gc[i];
+ }
+ }
+
+ return _create_gc (screen, drawable);
+}
+
+void
+_cairo_xcb_screen_put_gc (cairo_xcb_screen_t *screen, int depth, xcb_gcontext_t gc)
+{
+ int i;
+
+ assert (CAIRO_MUTEX_IS_LOCKED (screen->connection->mutex));
+
+ for (i = 0; i < ARRAY_LENGTH (screen->gc); i++) {
+ if (((screen->gc_depths >> (8*i)) & 0xff) == 0)
+ break;
+ }
+
+ if (i == ARRAY_LENGTH (screen->gc)) {
+ /* perform random substitution to ensure fair caching over depths */
+ i = rand () % ARRAY_LENGTH (screen->gc);
+ _cairo_xcb_connection_free_gc (screen->connection, screen->gc[i]);
+ }
+
+ screen->gc[i] = gc;
+ screen->gc_depths &= ~(0xff << (8*i));
+ screen->gc_depths |= depth << (8*i);
+}
+
+cairo_status_t
+_cairo_xcb_screen_store_surface_picture (cairo_xcb_screen_t *screen,
+ cairo_surface_t *picture,
+ unsigned int size)
+{
+ struct pattern_cache_entry *entry;
+ cairo_status_t status;
+
+ assert (CAIRO_MUTEX_IS_LOCKED (screen->connection->mutex));
+
+ entry = _cairo_freelist_alloc (&screen->pattern_cache_entry_freelist);
+ if (unlikely (entry == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+ entry->key.hash = picture->unique_id;
+ entry->key.size = size;
+
+ entry->picture = cairo_surface_reference (picture);
+ entry->screen = screen;
+
+ status = _cairo_cache_insert (&screen->surface_pattern_cache,
+ &entry->key);
+ if (unlikely (status)) {
+ _cairo_freelist_free (&screen->pattern_cache_entry_freelist, entry);
+ return status;
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+void
+_cairo_xcb_screen_remove_surface_picture (cairo_xcb_screen_t *screen,
+ cairo_surface_t *picture)
+{
+ struct pattern_cache_entry tmpl;
+ struct pattern_cache_entry *entry;
+
+ assert (CAIRO_MUTEX_IS_LOCKED (screen->connection->mutex));
+
+ tmpl.key.hash = picture->unique_id;
+
+ entry = _cairo_cache_lookup (&screen->surface_pattern_cache, &tmpl.key);
+ if (entry != NULL)
+ _cairo_cache_remove (&screen->surface_pattern_cache, &entry->key);
+}
+
+cairo_status_t
+_cairo_xcb_screen_store_linear_picture (cairo_xcb_screen_t *screen,
+ const cairo_linear_pattern_t *linear,
+ cairo_surface_t *picture)
+{
+ struct pattern_cache_entry *entry;
+ cairo_status_t status;
+
+ assert (CAIRO_MUTEX_IS_LOCKED (screen->connection->mutex));
+
+ entry = _cairo_freelist_alloc (&screen->pattern_cache_entry_freelist);
+ if (unlikely (entry == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+ entry->key.hash = _cairo_linear_pattern_hash (_CAIRO_HASH_INIT_VALUE, linear);
+ entry->key.size = 1;
+
+ status = _cairo_pattern_init_copy (&entry->pattern.base, &linear->base.base);
+ if (unlikely (status)) {
+ _cairo_freelist_free (&screen->pattern_cache_entry_freelist, entry);
+ return status;
+ }
+
+ entry->picture = cairo_surface_reference (picture);
+ entry->screen = screen;
+
+ status = _cairo_cache_insert (&screen->linear_pattern_cache,
+ &entry->key);
+ if (unlikely (status)) {
+ cairo_surface_destroy (picture);
+ _cairo_freelist_free (&screen->pattern_cache_entry_freelist, entry);
+ return status;
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+cairo_surface_t *
+_cairo_xcb_screen_lookup_linear_picture (cairo_xcb_screen_t *screen,
+ const cairo_linear_pattern_t *linear)
+{
+ cairo_surface_t *picture = NULL;
+ struct pattern_cache_entry tmpl;
+ struct pattern_cache_entry *entry;
+
+ assert (CAIRO_MUTEX_IS_LOCKED (screen->connection->mutex));
+
+ tmpl.key.hash = _cairo_linear_pattern_hash (_CAIRO_HASH_INIT_VALUE, linear);
+ _cairo_pattern_init_static_copy (&tmpl.pattern.base, &linear->base.base);
+
+ entry = _cairo_cache_lookup (&screen->linear_pattern_cache, &tmpl.key);
+ if (entry != NULL)
+ picture = cairo_surface_reference (entry->picture);
+
+ return picture;
+}
+
+cairo_status_t
+_cairo_xcb_screen_store_radial_picture (cairo_xcb_screen_t *screen,
+ const cairo_radial_pattern_t *radial,
+ cairo_surface_t *picture)
+{
+ struct pattern_cache_entry *entry;
+ cairo_status_t status;
+
+ assert (CAIRO_MUTEX_IS_LOCKED (screen->connection->mutex));
+
+ entry = _cairo_freelist_alloc (&screen->pattern_cache_entry_freelist);
+ if (unlikely (entry == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+ entry->key.hash = _cairo_radial_pattern_hash (_CAIRO_HASH_INIT_VALUE, radial);
+ entry->key.size = 1;
+
+ status = _cairo_pattern_init_copy (&entry->pattern.base, &radial->base.base);
+ if (unlikely (status)) {
+ _cairo_freelist_free (&screen->pattern_cache_entry_freelist, entry);
+ return status;
+ }
+
+ entry->picture = cairo_surface_reference (picture);
+ entry->screen = screen;
+
+ status = _cairo_cache_insert (&screen->radial_pattern_cache, &entry->key);
+ if (unlikely (status)) {
+ cairo_surface_destroy (picture);
+ _cairo_freelist_free (&screen->pattern_cache_entry_freelist, entry);
+ return status;
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+cairo_surface_t *
+_cairo_xcb_screen_lookup_radial_picture (cairo_xcb_screen_t *screen,
+ const cairo_radial_pattern_t *radial)
+{
+ cairo_surface_t *picture = NULL;
+ struct pattern_cache_entry tmpl;
+ struct pattern_cache_entry *entry;
+
+ assert (CAIRO_MUTEX_IS_LOCKED (screen->connection->mutex));
+
+ tmpl.key.hash = _cairo_radial_pattern_hash (_CAIRO_HASH_INIT_VALUE, radial);
+ _cairo_pattern_init_static_copy (&tmpl.pattern.base, &radial->base.base);
+
+ entry = _cairo_cache_lookup (&screen->radial_pattern_cache, &tmpl.key);
+ if (entry != NULL)
+ picture = cairo_surface_reference (entry->picture);
+
+ return picture;
+}
diff --git a/src/cairo-xcb-shm.c b/src/cairo-xcb-shm.c
new file mode 100644
index 0000000..7a47f33
--- /dev/null
+++ b/src/cairo-xcb-shm.c
@@ -0,0 +1,576 @@
+/* Cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2007 Chris Wilson
+ * 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 Red Hat, Inc.
+ *
+ * Contributors(s):
+ * Chris Wilson <chris at chris-wilson.co.uk>
+ */
+
+#include "cairoint.h"
+
+#include "cairo-xcb-private.h"
+
+#include <xcb/shm.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <errno.h>
+
+/* a simple buddy allocator for memory pools
+ * XXX fragmentation? use Doug Lea's malloc?
+ */
+
+typedef struct _cairo_xcb_shm_mem_block cairo_xcb_shm_mem_block_t;
+
+struct _cairo_xcb_shm_mem_block {
+ unsigned int bits;
+ cairo_list_t link;
+};
+
+struct _cairo_xcb_shm_mem_pool {
+ int shmid;
+ uint32_t shmseg;
+
+ char *base;
+ unsigned int nBlocks;
+ cairo_xcb_shm_mem_block_t *blocks;
+ cairo_list_t free[32];
+ unsigned char *map;
+
+ unsigned int min_bits; /* Minimum block size is 1 << min_bits */
+ unsigned int num_sizes;
+
+ size_t free_bytes;
+ size_t max_bytes;
+ unsigned int max_free_bits;
+
+ cairo_list_t link;
+};
+
+#define BITTEST(p, n) ((p)->map[(n) >> 3] & (128 >> ((n) & 7)))
+#define BITSET(p, n) ((p)->map[(n) >> 3] |= (128 >> ((n) & 7)))
+#define BITCLEAR(p, n) ((p)->map[(n) >> 3] &= ~(128 >> ((n) & 7)))
+
+static void
+clear_bits (cairo_xcb_shm_mem_pool_t *pi, size_t first, size_t last)
+{
+ size_t i, n = last;
+ size_t first_full = (first + 7) & ~7;
+ size_t past_full = last & ~7;
+ size_t bytes;
+
+ if (n > first_full)
+ n = first_full;
+ for (i = first; i < n; i++)
+ BITCLEAR (pi, i);
+
+ if (past_full > first_full) {
+ bytes = past_full - first_full;
+ bytes = bytes >> 3;
+ memset (pi->map + (first_full >> 3), 0, bytes);
+ }
+
+ if (past_full < n)
+ past_full = n;
+ for (i = past_full; i < last; i++)
+ BITCLEAR (pi, i);
+}
+
+static void
+free_bits (cairo_xcb_shm_mem_pool_t *pi,
+ size_t start,
+ unsigned int bits,
+ cairo_bool_t clear)
+{
+ cairo_xcb_shm_mem_block_t *block;
+
+ if (clear)
+ clear_bits (pi, start, start + (1 << bits));
+
+ block = pi->blocks + start;
+ block->bits = bits;
+
+ cairo_list_add (&block->link, &pi->free[bits]);
+
+ pi->free_bytes += 1 << (bits + pi->min_bits);
+ if (bits > pi->max_free_bits)
+ pi->max_free_bits = bits;
+}
+
+/* Add a chunk to the free list */
+static void
+free_blocks (cairo_xcb_shm_mem_pool_t *pi,
+ size_t first,
+ size_t last,
+ cairo_bool_t clear)
+{
+ size_t i;
+ size_t bits = 0;
+ size_t len = 1;
+
+ i = first;
+ while (i < last) {
+ /* To avoid cost quadratic in the number of different
+ * blocks produced from this chunk of store, we have to
+ * use the size of the previous block produced from this
+ * chunk as the starting point to work out the size of the
+ * next block we can produce. If you look at the binary
+ * representation of the starting points of the blocks
+ * produced, you can see that you first of all increase the
+ * size of the blocks produced up to some maximum as the
+ * address dealt with gets offsets added on which zap out
+ * low order bits, then decrease as the low order bits of the
+ * final block produced get added in. E.g. as you go from
+ * 001 to 0111 you generate blocks
+ * of size 001 at 001 taking you to 010
+ * of size 010 at 010 taking you to 100
+ * of size 010 at 100 taking you to 110
+ * of size 001 at 110 taking you to 111
+ * So the maximum total cost of the loops below this comment
+ * is one trip from the lowest blocksize to the highest and
+ * back again.
+ */
+ while (bits < pi->num_sizes - 1) {
+ size_t next_bits = bits + 1;
+ size_t next_len = len << 1;
+
+ if (i + next_bits > last) {
+ /* off end of chunk to be freed */
+ break;
+ }
+
+ if (i & (next_len - 1)) /* block would not be on boundary */
+ break;
+
+ bits = next_bits;
+ len = next_len;
+ }
+
+ do {
+ if (i + len > last) /* off end of chunk to be freed */
+ continue;
+
+ if (i & (len - 1)) /* block would not be on boundary */
+ continue;
+
+ /* OK */
+ break;
+
+ bits--;
+ len >>=1;
+ } while (len > 0);
+
+ if (len == 0)
+ break;
+
+ free_bits (pi, i, bits, clear);
+ i += len;
+ }
+}
+
+static cairo_status_t
+_cairo_xcb_shm_mem_pool_init (cairo_xcb_shm_mem_pool_t *pi,
+ size_t bytes,
+ unsigned int min_bits,
+ unsigned int num_sizes)
+{
+ size_t setBits;
+ int i;
+
+ assert ((((unsigned long) pi->base) & ((1 << min_bits) - 1)) == 0);
+ assert (num_sizes < ARRAY_LENGTH (pi->free));
+
+ pi->free_bytes = 0;
+ pi->max_bytes = bytes;
+ pi->max_free_bits = 0;
+
+ setBits = bytes >> min_bits;
+ pi->blocks = calloc (setBits, sizeof (cairo_xcb_shm_mem_block_t));
+ if (pi->blocks == NULL)
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+ pi->nBlocks = setBits;
+ pi->min_bits = min_bits;
+ pi->num_sizes = num_sizes;
+
+ for (i = 0; i < ARRAY_LENGTH (pi->free); i++)
+ cairo_list_init (&pi->free[i]);
+
+ pi->map = malloc ((setBits + 7) >> 3);
+ if (pi->map == NULL) {
+ free (pi->blocks);
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ }
+
+ memset (pi->map, -1, (setBits + 7) >> 3);
+ clear_bits (pi, 0, setBits);
+
+ /* Now add all blocks to the free list */
+ free_blocks (pi, 0, setBits, 1);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_xcb_shm_mem_block_t *
+get_buddy (cairo_xcb_shm_mem_pool_t *pi,
+ size_t offset,
+ unsigned int bits)
+{
+ cairo_xcb_shm_mem_block_t *block;
+
+ assert (offset + (1 << bits) <= pi->nBlocks);
+
+ if (BITTEST (pi, offset + (1 << bits) - 1))
+ return NULL; /* buddy is allocated */
+
+ block = pi->blocks + offset;
+ if (block->bits != bits)
+ return NULL; /* buddy is partially allocated */
+
+ return block;
+}
+
+static void
+merge_buddies (cairo_xcb_shm_mem_pool_t *pi,
+ cairo_xcb_shm_mem_block_t *block,
+ unsigned int max_bits)
+{
+ size_t block_offset = block_offset = block - pi->blocks;
+ unsigned int bits = block->bits;
+
+ while (bits < max_bits - 1) {
+ /* while you can, merge two blocks and get a legal block size */
+ size_t buddy_offset = block_offset ^ (1 << bits);
+
+ block = get_buddy (pi, buddy_offset, bits);
+ if (block == NULL)
+ break;
+
+ cairo_list_del (&block->link);
+
+ /* Merged block starts at buddy */
+ if (buddy_offset < block_offset)
+ block_offset = buddy_offset;
+
+ bits++;
+ }
+
+ block = pi->blocks + block_offset;
+ block->bits = bits;
+ cairo_list_add (&block->link, &pi->free[bits]);
+
+ if (bits > pi->max_free_bits)
+ pi->max_free_bits = bits;
+}
+
+/* attempt to merge all available buddies up to a particular size */
+static unsigned int
+merge_bits (cairo_xcb_shm_mem_pool_t *pi,
+ unsigned int max_bits)
+{
+ cairo_xcb_shm_mem_block_t *block, *buddy, *next;
+ unsigned int bits;
+
+ for (bits = 0; bits < max_bits - 1; bits++) {
+ cairo_list_foreach_entry_safe (block, next,
+ cairo_xcb_shm_mem_block_t,
+ &pi->free[bits],
+ link)
+ {
+ size_t buddy_offset = (block - pi->blocks) ^ (1 << bits);
+
+ buddy = get_buddy (pi, buddy_offset, bits);
+ if (buddy == NULL)
+ continue;
+
+ if (buddy == next) {
+ next = cairo_container_of (buddy->link.next,
+ cairo_xcb_shm_mem_block_t,
+ link);
+ }
+
+ cairo_list_del (&block->link);
+ merge_buddies (pi, block, max_bits);
+ }
+ }
+
+ return pi->max_free_bits;
+}
+
+/* find store for 1 << bits blocks */
+static void *
+buddy_malloc (cairo_xcb_shm_mem_pool_t *pi,
+ unsigned int bits)
+{
+ unsigned int b;
+ size_t offset;
+ size_t past;
+ cairo_xcb_shm_mem_block_t *block;
+
+ if (bits > pi->max_free_bits && bits > merge_bits (pi, bits))
+ return NULL;
+
+ /* Find a list with blocks big enough on it */
+ block = NULL;
+ for (b = bits; b <= pi->max_free_bits; b++) {
+ if (! cairo_list_is_empty (&pi->free[b])) {
+ block = cairo_list_first_entry (&pi->free[b],
+ cairo_xcb_shm_mem_block_t,
+ link);
+ break;
+ }
+ }
+ assert (block != NULL);
+
+ cairo_list_del (&block->link);
+
+ while (cairo_list_is_empty (&pi->free[pi->max_free_bits])) {
+ if (--pi->max_free_bits == 0)
+ break;
+ }
+
+ /* Mark end of allocated area */
+ offset = block - pi->blocks;
+ past = offset + (1 << bits);
+ BITSET (pi, past - 1);
+ block->bits = bits;
+
+ /* If we used a larger free block than we needed, free the rest */
+ pi->free_bytes -= 1 << (b + pi->min_bits);
+ free_blocks (pi, past, offset + (1 << b), 0);
+
+ return pi->base + ((block - pi->blocks) << pi->min_bits);
+}
+
+static void *
+_cairo_xcb_shm_mem_pool_malloc (cairo_xcb_shm_mem_pool_t *pi,
+ size_t bytes)
+{
+ unsigned int bits;
+ size_t size;
+
+ size = 1 << pi->min_bits;
+ for (bits = 0; size < bytes; bits++)
+ size <<= 1;
+ if (bits >= pi->num_sizes)
+ return NULL;
+
+ return buddy_malloc (pi, bits);
+}
+
+static void
+_cairo_xcb_shm_mem_pool_free (cairo_xcb_shm_mem_pool_t *pi,
+ char *storage)
+{
+ size_t block_offset;
+ cairo_xcb_shm_mem_block_t *block;
+
+ block_offset = (storage - pi->base) >> pi->min_bits;
+ block = pi->blocks + block_offset;
+
+ BITCLEAR (pi, block_offset + ((1 << block->bits) - 1));
+ pi->free_bytes += 1 << (block->bits + pi->min_bits);
+
+ merge_buddies (pi, block, pi->num_sizes);
+}
+
+static void
+_cairo_xcb_shm_mem_pool_destroy (cairo_xcb_shm_mem_pool_t *pool)
+{
+ shmdt (pool->base);
+ cairo_list_del (&pool->link);
+
+ free (pool->map);
+ free (pool->blocks);
+ free (pool);
+}
+
+cairo_int_status_t
+_cairo_xcb_connection_allocate_shm_info (cairo_xcb_connection_t *connection,
+ size_t size,
+ cairo_xcb_shm_info_t **shm_info_out)
+{
+ cairo_xcb_shm_info_t *shm_info;
+ cairo_xcb_shm_mem_pool_t *pool, *next;
+ size_t bytes, maxbits = 16, minbits = 8;
+ void *mem = NULL;
+ cairo_status_t status;
+
+ assert (connection->flags & CAIRO_XCB_HAS_SHM);
+
+ CAIRO_MUTEX_LOCK (connection->shm_mutex);
+ cairo_list_foreach_entry_safe (pool, next, cairo_xcb_shm_mem_pool_t,
+ &connection->shm_pools, link)
+ {
+ if (pool->free_bytes > size) {
+ mem = _cairo_xcb_shm_mem_pool_malloc (pool, size);
+ if (mem != NULL) {
+ /* keep the active pools towards the front */
+ cairo_list_move (&pool->link, &connection->shm_pools);
+ goto allocate_shm_info;
+ }
+ }
+ /* scan for old, unused pools */
+ if (pool->free_bytes == pool->max_bytes) {
+ _cairo_xcb_connection_shm_detach (connection,
+ pool->shmseg);
+ _cairo_xcb_shm_mem_pool_destroy (pool);
+ }
+ }
+
+ pool = malloc (sizeof (cairo_xcb_shm_mem_pool_t));
+ if (unlikely (pool == NULL)) {
+ CAIRO_MUTEX_UNLOCK (connection->shm_mutex);
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ }
+
+ bytes = 1 << maxbits;
+ while (bytes <= size)
+ bytes <<= 1, maxbits++;
+ bytes <<= 3;
+
+ do {
+ pool->shmid = shmget (IPC_PRIVATE, bytes, IPC_CREAT | 0600);
+ if (pool->shmid != -1)
+ break;
+
+ if (errno == EINVAL && bytes > size) {
+ bytes >>= 1;
+ continue;
+ }
+ } while (FALSE);
+ if (pool->shmid == -1) {
+ int err = errno;
+ if (! (err == EINVAL || err == ENOMEM))
+ connection->flags &= ~CAIRO_XCB_HAS_SHM;
+ free (pool);
+ CAIRO_MUTEX_UNLOCK (connection->shm_mutex);
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ }
+
+ pool->base = shmat (pool->shmid, NULL, 0);
+ if (unlikely (pool->base == (char *) -1)) {
+ shmctl (pool->shmid, IPC_RMID, NULL);
+ free (pool);
+ CAIRO_MUTEX_UNLOCK (connection->shm_mutex);
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ }
+
+ status = _cairo_xcb_shm_mem_pool_init (pool,
+ bytes,
+ minbits,
+ maxbits - minbits + 1);
+ if (unlikely (status)) {
+ shmdt (pool->base);
+ free (pool);
+ CAIRO_MUTEX_UNLOCK (connection->shm_mutex);
+ return status;
+ }
+
+ pool->shmseg = _cairo_xcb_connection_shm_attach (connection, pool->shmid, FALSE);
+ shmctl (pool->shmid, IPC_RMID, NULL);
+
+ cairo_list_add (&pool->link, &connection->shm_pools);
+ mem = _cairo_xcb_shm_mem_pool_malloc (pool, size);
+
+ allocate_shm_info:
+ shm_info = _cairo_freepool_alloc (&connection->shm_info_freelist);
+ if (unlikely (shm_info == NULL)) {
+ _cairo_xcb_shm_mem_pool_free (pool, mem);
+ CAIRO_MUTEX_UNLOCK (connection->shm_mutex);
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ }
+
+ shm_info->connection = connection;
+ shm_info->pool = pool;
+ shm_info->shm = pool->shmseg;
+ shm_info->offset = (char *) mem - (char *) pool->base;
+ shm_info->mem = mem;
+
+ /* scan for old, unused pools */
+ cairo_list_foreach_entry_safe (pool, next, cairo_xcb_shm_mem_pool_t,
+ &connection->shm_pools, link)
+ {
+ if (pool->free_bytes == pool->max_bytes) {
+ _cairo_xcb_connection_shm_detach (connection,
+ pool->shmseg);
+ _cairo_xcb_shm_mem_pool_destroy (pool);
+ }
+ }
+ CAIRO_MUTEX_UNLOCK (connection->shm_mutex);
+
+ *shm_info_out = shm_info;
+ return CAIRO_STATUS_SUCCESS;
+}
+
+void
+_cairo_xcb_shm_info_destroy (cairo_xcb_shm_info_t *shm_info)
+{
+ cairo_xcb_connection_t *connection = shm_info->connection;
+
+ CAIRO_MUTEX_LOCK (connection->shm_mutex);
+
+ _cairo_xcb_shm_mem_pool_free (shm_info->pool, shm_info->mem);
+ _cairo_freepool_free (&connection->shm_info_freelist, shm_info);
+
+ /* scan for old, unused pools - hold at least one in reserve */
+ if (! cairo_list_is_singular (&connection->shm_pools) &&
+ _cairo_xcb_connection_take_socket (connection) == CAIRO_STATUS_SUCCESS)
+ {
+ cairo_xcb_shm_mem_pool_t *pool, *next;
+ cairo_list_t head;
+
+ cairo_list_init (&head);
+ cairo_list_move (connection->shm_pools.next, &head);
+
+ cairo_list_foreach_entry_safe (pool, next, cairo_xcb_shm_mem_pool_t,
+ &connection->shm_pools, link)
+ {
+ if (pool->free_bytes == pool->max_bytes) {
+ _cairo_xcb_connection_shm_detach (connection, pool->shmseg);
+ _cairo_xcb_shm_mem_pool_destroy (pool);
+ }
+ }
+
+ cairo_list_move (head.next, &connection->shm_pools);
+ }
+
+ CAIRO_MUTEX_UNLOCK (connection->shm_mutex);
+}
+
+void
+_cairo_xcb_connection_shm_mem_pools_fini (cairo_xcb_connection_t *connection)
+{
+ while (! cairo_list_is_empty (&connection->shm_pools)) {
+ _cairo_xcb_shm_mem_pool_destroy (cairo_list_first_entry (&connection->shm_pools,
+ cairo_xcb_shm_mem_pool_t,
+ link));
+ }
+}
diff --git a/src/cairo-xcb-surface-cairo.c b/src/cairo-xcb-surface-cairo.c
new file mode 100644
index 0000000..c8305cf
--- /dev/null
+++ b/src/cairo-xcb-surface-cairo.c
@@ -0,0 +1,94 @@
+/* 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.
+ *
+ * Contributor(s):
+ * Chris Wilson <chris at chris-wilson.co.uk>
+ */
+
+#include "cairoint.h"
+
+#include "cairo-clip-private.h"
+#include "cairo-xcb-private.h"
+
+cairo_int_status_t
+_cairo_xcb_surface_cairo_paint (cairo_xcb_surface_t *surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_clip_t *clip)
+{
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+}
+
+cairo_int_status_t
+_cairo_xcb_surface_cairo_mask (cairo_xcb_surface_t *surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ const cairo_pattern_t *mask,
+ cairo_clip_t *clip)
+{
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+}
+
+cairo_int_status_t
+_cairo_xcb_surface_cairo_stroke (cairo_xcb_surface_t *surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_path_fixed_t *path,
+ const cairo_stroke_style_t *style,
+ const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm_inverse,
+ double tolerance,
+ cairo_antialias_t antialias,
+ cairo_clip_t *clip)
+{
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+}
+
+cairo_int_status_t
+_cairo_xcb_surface_cairo_fill (cairo_xcb_surface_t *surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_path_fixed_t *path,
+ cairo_fill_rule_t fill_rule,
+ double tolerance,
+ cairo_antialias_t antialias,
+ cairo_clip_t *clip)
+{
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+}
+
+cairo_int_status_t
+_cairo_xcb_surface_cairo_glyphs (cairo_xcb_surface_t *surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_scaled_font_t *scaled_font,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_clip_t *clip)
+{
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+}
diff --git a/src/cairo-xcb-surface-core.c b/src/cairo-xcb-surface-core.c
new file mode 100644
index 0000000..6f1002a
--- /dev/null
+++ b/src/cairo-xcb-surface-core.c
@@ -0,0 +1,613 @@
+/* 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.
+ *
+ * Contributor(s):
+ * Chris Wilson <chris at chris-wilson.co.uk>
+ */
+
+#include "cairoint.h"
+
+#include "cairo-boxes-private.h"
+#include "cairo-xcb-private.h"
+
+/* XXX dithering */
+
+typedef struct _cairo_xcb_pixmap {
+ cairo_surface_t base;
+
+ cairo_xcb_connection_t *connection;
+ cairo_xcb_screen_t *screen;
+
+ cairo_surface_t *owner;
+ xcb_pixmap_t pixmap;
+ int width;
+ int height;
+ int depth;
+ int x0, y0;
+ cairo_bool_t repeat;
+} cairo_xcb_pixmap_t;
+
+static cairo_status_t
+_cairo_xcb_pixmap_finish (void *abstract_surface)
+{
+ cairo_xcb_pixmap_t *surface = abstract_surface;
+ cairo_status_t status;
+
+ if (surface->owner != NULL) {
+ cairo_surface_destroy (surface->owner);
+ } else {
+ status = _cairo_xcb_connection_acquire (surface->connection);
+ if (unlikely (status))
+ return status;
+
+ if (_cairo_xcb_connection_take_socket (surface->connection) == CAIRO_STATUS_SUCCESS) {
+ _cairo_xcb_connection_free_pixmap (surface->connection,
+ surface->pixmap);
+ }
+ _cairo_xcb_connection_release (surface->connection);
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static const cairo_surface_backend_t _cairo_xcb_pixmap_backend = {
+ CAIRO_SURFACE_TYPE_XCB,
+ NULL,
+ _cairo_xcb_pixmap_finish,
+};
+
+static cairo_xcb_pixmap_t *
+_cairo_xcb_pixmap_create (cairo_xcb_surface_t *target,
+ int width, int height)
+{
+ cairo_xcb_pixmap_t *surface;
+
+ surface = malloc (sizeof (cairo_xcb_pixmap_t));
+ if (unlikely (surface == NULL))
+ return (cairo_xcb_pixmap_t *)
+ _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
+
+ _cairo_surface_init (&surface->base,
+ &_cairo_xcb_pixmap_backend,
+ NULL,
+ target->base.content);
+
+ surface->connection = target->connection;
+ surface->screen = target->screen;
+ surface->owner = NULL;
+ surface->width = width;
+ surface->height = height;
+ surface->depth = target->depth;
+ surface->x0 = surface->y0 = 0;
+ surface->repeat = FALSE;
+
+ surface->pixmap =
+ _cairo_xcb_connection_create_pixmap (surface->connection,
+ surface->depth,
+ target->drawable,
+ width, height);
+
+ return surface;
+}
+
+static cairo_xcb_pixmap_t *
+_cairo_xcb_pixmap_copy (cairo_xcb_surface_t *target)
+{
+ cairo_xcb_pixmap_t *surface;
+
+ surface = malloc (sizeof (cairo_xcb_pixmap_t));
+ if (unlikely (surface == NULL))
+ return (cairo_xcb_pixmap_t *)
+ _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
+
+ _cairo_surface_init (&surface->base,
+ &_cairo_xcb_pixmap_backend,
+ NULL,
+ target->base.content);
+
+ surface->connection = target->connection;
+ surface->screen = target->screen;
+ surface->pixmap = target->drawable;
+ surface->owner = cairo_surface_reference (&target->base);
+ surface->width = target->width;
+ surface->height = target->height;
+ surface->depth = target->depth;
+ surface->x0 = surface->y0 = 0;
+ surface->repeat = FALSE;
+
+ return surface;
+}
+
+static cairo_status_t
+_cairo_xcb_shm_image_create (cairo_xcb_connection_t *connection,
+ pixman_format_code_t pixman_format,
+ int width, int height,
+ cairo_image_surface_t **image_out,
+ cairo_xcb_shm_info_t **shm_info_out)
+{
+ cairo_surface_t *image = NULL;
+ cairo_xcb_shm_info_t *shm_info = NULL;
+ cairo_status_t status;
+
+ if ((connection->flags & CAIRO_XCB_HAS_SHM)) {
+ size_t size, stride;
+
+ stride = CAIRO_STRIDE_FOR_WIDTH_BPP (width, PIXMAN_FORMAT_BPP (pixman_format));
+ size = stride * height;
+ if (size > CAIRO_XCB_SHM_SMALL_IMAGE) {
+ status = _cairo_xcb_connection_allocate_shm_info (connection,
+ size, &shm_info);
+ if (unlikely (status))
+ return status;
+
+ image = _cairo_image_surface_create_with_pixman_format (shm_info->mem,
+ pixman_format,
+ width, height,
+ stride);
+ status = image->status;
+ if (unlikely (status)) {
+ _cairo_xcb_shm_info_destroy (shm_info);
+ return status;
+ }
+
+ status = _cairo_user_data_array_set_data (&image->user_data,
+ (const cairo_user_data_key_t *) connection,
+ shm_info,
+ (cairo_destroy_func_t) _cairo_xcb_shm_info_destroy);
+ if (unlikely (status)) {
+ cairo_surface_destroy (image);
+ _cairo_xcb_shm_info_destroy (shm_info);
+ return status;
+ }
+ }
+ }
+
+ if (image == NULL) {
+ image = _cairo_image_surface_create_with_pixman_format (NULL,
+ pixman_format,
+ width, height,
+ 0);
+ status = image->status;
+ if (unlikely (status))
+ return status;
+ }
+
+
+ *image_out = (cairo_image_surface_t *) image;
+ *shm_info_out = shm_info;
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_xcb_pixmap_t *
+_pixmap_from_image (cairo_xcb_surface_t *target,
+ xcb_render_pictformat_t format,
+ cairo_image_surface_t *image,
+ cairo_xcb_shm_info_t *shm_info)
+{
+ xcb_gcontext_t gc;
+ cairo_xcb_pixmap_t *pixmap;
+
+ pixmap = _cairo_xcb_pixmap_create (target,
+ image->width,
+ image->height);
+ if (unlikely (pixmap->base.status))
+ return pixmap;
+
+ gc = _cairo_xcb_screen_get_gc (target->screen, pixmap->pixmap, image->depth);
+
+ if (shm_info != NULL) {
+ shm_info->seqno =
+ _cairo_xcb_connection_shm_put_image (target->connection,
+ pixmap->pixmap, gc,
+ image->width, image->height,
+ 0, 0,
+ image->width, image->height,
+ 0, 0,
+ image->depth,
+ shm_info->shm,
+ shm_info->offset);
+ } else {
+ int len;
+
+ /* Do we need to trim the image? */
+ len = CAIRO_STRIDE_FOR_WIDTH_BPP (image->width,
+ PIXMAN_FORMAT_BPP (image->pixman_format));
+ if (len == image->stride) {
+ _cairo_xcb_connection_put_image (target->connection,
+ pixmap->pixmap, gc,
+ image->width, image->height,
+ 0, 0,
+ image->depth,
+ image->stride,
+ image->data);
+ } else {
+ _cairo_xcb_connection_put_subimage (target->connection,
+ pixmap->pixmap, gc,
+ 0, 0,
+ image->width, image->height,
+ PIXMAN_FORMAT_BPP (image->pixman_format) / 8,
+ image->stride,
+ 0, 0,
+ image->depth,
+ image->data);
+
+ }
+ }
+
+ _cairo_xcb_screen_put_gc (target->screen, image->depth, gc);
+
+ return pixmap;
+}
+
+static cairo_xcb_pixmap_t *
+_render_to_pixmap (cairo_xcb_surface_t *target,
+ const cairo_pattern_t *pattern,
+ const cairo_rectangle_int_t *extents)
+{
+ cairo_image_surface_t *image;
+ cairo_xcb_shm_info_t *shm_info;
+ cairo_pattern_union_t copy;
+ cairo_status_t status;
+ cairo_xcb_pixmap_t *pixmap;
+
+ status = _cairo_xcb_shm_image_create (target->screen->connection,
+ target->pixman_format,
+ extents->width, extents->height,
+ &image, &shm_info);
+ if (unlikely (status))
+ return (cairo_xcb_pixmap_t *) _cairo_surface_create_in_error (status);
+
+ _cairo_pattern_init_static_copy (©.base, pattern);
+ cairo_matrix_translate (©.base.matrix, -extents->x, -extents->y);
+ status = _cairo_surface_paint (&image->base,
+ CAIRO_OPERATOR_SOURCE,
+ ©.base,
+ NULL);
+ if (unlikely (status)) {
+ cairo_surface_destroy (&image->base);
+ return (cairo_xcb_pixmap_t *) _cairo_surface_create_in_error (status);
+ }
+
+ pixmap = _pixmap_from_image (target, target->xrender_format, image, shm_info);
+ cairo_surface_destroy (&image->base);
+
+ if (unlikely (pixmap->base.status))
+ return pixmap;
+
+ pixmap->x0 = -extents->x;
+ pixmap->y0 = -extents->y;
+ return pixmap;
+}
+
+static cairo_xcb_pixmap_t *
+_copy_to_pixmap (cairo_xcb_surface_t *source)
+{
+ cairo_xcb_pixmap_t *pixmap;
+
+ /* If the source may be a window, we need to copy it and its children
+ * via a temporary pixmap so that we can IncludeInferiors on the source
+ * and use ClipByChildren on the destination.
+ */
+ if (source->owns_pixmap) {
+ pixmap = _cairo_xcb_pixmap_copy (source);
+ if (unlikely (pixmap->base.status))
+ return pixmap;
+ } else {
+ uint32_t values[1];
+ xcb_gcontext_t gc;
+
+ pixmap = _cairo_xcb_pixmap_create (source,
+ source->width,
+ source->height);
+ if (unlikely (pixmap->base.status))
+ return pixmap;
+
+ gc = _cairo_xcb_screen_get_gc (source->screen,
+ pixmap->pixmap,
+ pixmap->depth);
+
+ values[0] = TRUE;
+ _cairo_xcb_connection_change_gc (pixmap->connection, gc,
+ XCB_GC_SUBWINDOW_MODE, values);
+
+ _cairo_xcb_connection_copy_area (pixmap->connection,
+ source->drawable,
+ pixmap->pixmap, gc,
+ 0, 0,
+ 0, 0,
+ source->width,
+ source->height);
+
+ values[0] = FALSE;
+ _cairo_xcb_connection_change_gc (pixmap->connection, gc,
+ XCB_GC_SUBWINDOW_MODE, values);
+
+ _cairo_xcb_screen_put_gc (source->screen,
+ pixmap->depth,
+ gc);
+ }
+
+ return pixmap;
+}
+static cairo_xcb_pixmap_t *
+_cairo_xcb_surface_pixmap (cairo_xcb_surface_t *target,
+ const cairo_surface_pattern_t *pattern,
+ const cairo_rectangle_int_t *extents,
+ int tx, int ty)
+{
+ cairo_surface_t *source;
+ cairo_xcb_pixmap_t *pixmap;
+ cairo_status_t status;
+
+ source = pattern->surface;
+ pixmap = (cairo_xcb_pixmap_t *)
+ _cairo_surface_has_snapshot (source, &_cairo_xcb_pixmap_backend);
+ if (pixmap != NULL && pixmap->screen == target->screen)
+ return (cairo_xcb_pixmap_t *) cairo_surface_reference (&pixmap->base);
+
+ if (source->type == CAIRO_SURFACE_TYPE_XCB &&
+ ((cairo_xcb_surface_t *) source)->screen == target->screen)
+ {
+ cairo_xcb_surface_t *xcb_source = (cairo_xcb_surface_t *) source;
+
+ if (xcb_source->depth == target->depth)
+ pixmap = _copy_to_pixmap (xcb_source);
+ }
+#if CAIRO_HAS_XLIB_XCB_FUNCTIONS
+ else if (source->type == CAIRO_SURFACE_TYPE_XLIB &&
+ ((cairo_xlib_xcb_surface_t *) source)->xcb->screen == target->screen)
+ {
+ cairo_xcb_surface_t *xcb_source = ((cairo_xlib_xcb_surface_t *) source)->xcb;
+
+ if (xcb_source->depth == target->depth)
+ pixmap = _copy_to_pixmap (xcb_source);
+ }
+#endif
+
+ if (pixmap == NULL) {
+ cairo_rectangle_int_t rect;
+
+ if (! _cairo_surface_get_extents (source, &rect)) {
+ rect.x = rect.y = 0;
+ rect.width = target->width;
+ rect.height = target->height;
+ }
+
+ pixmap = _render_to_pixmap (target, &pattern->base, &rect);
+ }
+
+ if (unlikely (pixmap->base.status))
+ return pixmap;
+
+ status = _cairo_surface_attach_snapshot (source, &pixmap->base, NULL);
+ if (unlikely (status)) {
+ cairo_surface_destroy (&pixmap->base);
+ return (cairo_xcb_pixmap_t *) _cairo_surface_create_in_error (status);
+ }
+
+ if (pattern->base.extend != CAIRO_EXTEND_NONE) {
+ if (extents->x < 0 || extents->y < 0 ||
+ extents->x + extents->width > pixmap->width ||
+ extents->y + extents->height > pixmap->height)
+ {
+ pixmap->repeat = TRUE;
+ }
+ }
+
+ pixmap->x0 += tx;
+ pixmap->y0 += ty;
+
+ return pixmap;
+}
+
+static cairo_xcb_pixmap_t *
+_cairo_xcb_pixmap_for_pattern (cairo_xcb_surface_t *target,
+ const cairo_pattern_t *pattern,
+ const cairo_rectangle_int_t *extents)
+{
+ int tx, ty;
+
+ switch (pattern->type) {
+ case CAIRO_PATTERN_TYPE_SURFACE:
+ /* Core can only perform a native, unscaled blit, but can handle tiles */
+ if (_cairo_matrix_is_integer_translation (&pattern->matrix, &tx, &ty)) {
+ switch (pattern->extend) {
+ case CAIRO_EXTEND_NONE:
+ case CAIRO_EXTEND_REPEAT:
+ return _cairo_xcb_surface_pixmap (target,
+ (cairo_surface_pattern_t *) pattern,
+ extents, tx, ty);
+
+ default:
+ case CAIRO_EXTEND_PAD:
+ case CAIRO_EXTEND_REFLECT:
+ break;
+ }
+ }
+ /* fallthrough */
+ case CAIRO_PATTERN_TYPE_LINEAR:
+ case CAIRO_PATTERN_TYPE_RADIAL:
+ return _render_to_pixmap (target, pattern, extents);
+
+ default:
+ case CAIRO_PATTERN_TYPE_SOLID:
+ ASSERT_NOT_REACHED;
+ return NULL;
+ }
+}
+
+cairo_status_t
+_cairo_xcb_surface_core_copy_boxes (cairo_xcb_surface_t *dst,
+ const cairo_pattern_t *src_pattern,
+ const cairo_rectangle_int_t *extents,
+ const cairo_boxes_t *boxes)
+{
+ cairo_xcb_pixmap_t *src;
+ const struct _cairo_boxes_chunk *chunk;
+ xcb_gcontext_t gc;
+ cairo_status_t status;
+
+ status = _cairo_xcb_connection_acquire (dst->connection);
+ if (unlikely (status))
+ return status;
+
+ status = _cairo_xcb_connection_take_socket (dst->connection);
+ if (unlikely (status))
+ goto CLEANUP_CONNECTION;
+
+ src = _cairo_xcb_pixmap_for_pattern (dst, src_pattern, extents);
+ status = src->base.status;
+ if (unlikely (status))
+ goto CLEANUP_CONNECTION;
+
+ assert (src->depth == dst->depth);
+
+ gc = _cairo_xcb_screen_get_gc (dst->screen, src->pixmap, src->depth);
+
+ if (src->repeat) {
+ uint32_t mask =
+ XCB_GC_FILL_STYLE |
+ XCB_GC_TILE |
+ XCB_GC_TILE_STIPPLE_ORIGIN_X |
+ XCB_GC_TILE_STIPPLE_ORIGIN_Y;
+ uint32_t values[] = {
+ XCB_FILL_STYLE_TILED,
+ src->pixmap,
+ - src->x0, - src->y0,
+ };
+ xcb_rectangle_t *xcb_rects;
+
+ _cairo_xcb_connection_change_gc (dst->connection, gc, mask, values);
+
+ for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
+ xcb_rects = (xcb_rectangle_t *) chunk->base;
+ int i;
+
+ for (i = 0; i < chunk->count; i++) {
+ int x1 = _cairo_fixed_integer_round (chunk->base[i].p1.x);
+ int x2 = _cairo_fixed_integer_round (chunk->base[i].p2.x);
+ int y1 = _cairo_fixed_integer_round (chunk->base[i].p1.y);
+ int y2 = _cairo_fixed_integer_round (chunk->base[i].p2.y);
+
+ xcb_rects[i].x = x1;
+ xcb_rects[i].y = y1;
+ xcb_rects[i].width = x2 - x1;
+ xcb_rects[i].height = y2 - y1;
+ }
+ _cairo_xcb_connection_poly_fill_rectangle (dst->connection,
+ dst->drawable,
+ gc, chunk->count, xcb_rects);
+ }
+
+ values[0] = 0;
+ _cairo_xcb_connection_change_gc (dst->connection, gc, XCB_GC_FILL_STYLE, values);
+ } else {
+ for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
+ int i;
+
+ for (i = 0; i < chunk->count; i++) {
+ int x1 = _cairo_fixed_integer_round (chunk->base[i].p1.x);
+ int x2 = _cairo_fixed_integer_round (chunk->base[i].p2.x);
+ int y1 = _cairo_fixed_integer_round (chunk->base[i].p1.y);
+ int y2 = _cairo_fixed_integer_round (chunk->base[i].p2.y);
+
+ _cairo_xcb_connection_copy_area (dst->connection,
+ src->pixmap,
+ dst->drawable, gc,
+ src->x0 + x1,
+ src->y0 + y1,
+ x1, y1,
+ x2 - x2, y2 - x2);
+ }
+ }
+ }
+
+ _cairo_xcb_screen_put_gc (dst->screen, src->depth, gc);
+ cairo_surface_destroy (&src->base);
+
+ CLEANUP_CONNECTION:
+ _cairo_xcb_connection_release (dst->connection);
+
+ return status;
+}
+
+cairo_status_t
+_cairo_xcb_surface_core_fill_boxes (cairo_xcb_surface_t *dst,
+ const cairo_color_t *color,
+ cairo_boxes_t *boxes)
+{
+ struct _cairo_boxes_chunk *chunk;
+ xcb_gcontext_t gc;
+ cairo_status_t status;
+
+ status = _cairo_xcb_connection_acquire (dst->connection);
+ if (unlikely (status))
+ return status;
+
+ status = _cairo_xcb_connection_take_socket (dst->connection);
+ if (unlikely (status)) {
+ _cairo_xcb_connection_release (dst->connection);
+ return status;
+ }
+
+ gc = _cairo_xcb_screen_get_gc (dst->screen, dst->drawable, dst->depth);
+
+#if 0
+ xcb_pixmap_t source;
+
+ source = _dither_source (dst, color);
+ XSetTSOrigin (surface->dpy, gc, 0, 0);
+ XSetTile (surface->dpy, gc, source);
+#endif
+
+ for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
+ xcb_rectangle_t *xcb_rects;
+ int i;
+
+ xcb_rects = (xcb_rectangle_t *) chunk->base;
+ for (i = 0; i < chunk->count; i++) {
+ int x1 = _cairo_fixed_integer_round (chunk->base[i].p1.x);
+ int x2 = _cairo_fixed_integer_round (chunk->base[i].p2.x);
+ int y1 = _cairo_fixed_integer_round (chunk->base[i].p1.y);
+ int y2 = _cairo_fixed_integer_round (chunk->base[i].p2.y);
+
+ xcb_rects[i].x = x1;
+ xcb_rects[i].y = y1;
+ xcb_rects[i].width = x2 - x1;
+ xcb_rects[i].height = y2 - y1;
+ }
+
+ _cairo_xcb_connection_poly_fill_rectangle (dst->connection,
+ dst->drawable, gc,
+ chunk->count, xcb_rects);
+ }
+
+ _cairo_xcb_screen_put_gc (dst->screen, dst->depth, gc);
+ _cairo_xcb_connection_release (dst->connection);
+
+ return CAIRO_STATUS_SUCCESS;
+}
diff --git a/src/cairo-xcb-surface-private.h b/src/cairo-xcb-surface-private.h
new file mode 100644
index 0000000..1ef4900
--- /dev/null
+++ b/src/cairo-xcb-surface-private.h
@@ -0,0 +1,37 @@
+/* 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.
+ *
+ * Contributors(s):
+ * Chris Wilson <chris at chris-wilson.co.uk>
+ */
+
+#ifndef CAIRO_XCB_SURFACE_PRIVATE_H
+#define CAIRO_XCB_SURFACE_PRIVATE_H
+
+#include "cairo-xcb-private.h"
+
+#endif
diff --git a/src/cairo-xcb-surface-render.c b/src/cairo-xcb-surface-render.c
new file mode 100644
index 0000000..e07f575
--- /dev/null
+++ b/src/cairo-xcb-surface-render.c
@@ -0,0 +1,4471 @@
+/* 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.
+ *
+ * Contributor(s):
+ * Chris Wilson <chris at chris-wilson.co.uk>
+ */
+
+#include "cairoint.h"
+
+#include "cairo-boxes-private.h"
+#include "cairo-clip-private.h"
+#include "cairo-composite-rectangles-private.h"
+#include "cairo-region-private.h"
+#include "cairo-surface-offset-private.h"
+#include "cairo-surface-snapshot-private.h"
+#include "cairo-surface-subsurface-private.h"
+#include "cairo-xcb-private.h"
+
+#if CAIRO_HAS_XCB_DRM_FUNCTIONS && CAIRO_HAS_DRM_SURFACE
+#include "drm/cairo-drm-private.h"
+#endif
+
+#define PIXMAN_MAX_INT ((pixman_fixed_1 >> 1) - pixman_fixed_e) /* need to ensure deltas also fit */
+
+typedef struct _cairo_xcb_picture {
+ cairo_surface_t base;
+
+ cairo_surface_t *owner;
+
+ cairo_xcb_connection_t *connection;
+ cairo_xcb_screen_t *screen;
+ xcb_render_picture_t picture;
+ xcb_render_pictformat_t xrender_format;
+ pixman_format_code_t pixman_format;
+
+ int width, height;
+
+ cairo_extend_t extend;
+ cairo_filter_t filter;
+ cairo_bool_t has_component_alpha;
+ xcb_render_transform_t transform;
+
+ int x0, y0;
+ int x, y;
+} cairo_xcb_picture_t;
+
+static void
+_cairo_xcb_surface_ensure_picture (cairo_xcb_surface_t *surface);
+
+static uint32_t
+hars_petruska_f54_1_random (void)
+{
+#define rol(x,k) ((x << k) | (x >> (32-k)))
+ static uint32_t x;
+ return x = (x ^ rol (x, 5) ^ rol (x, 24)) + 0x37798849;
+#undef rol
+}
+
+static cairo_status_t
+_cairo_xcb_picture_finish (void *abstract_surface)
+{
+ cairo_xcb_picture_t *surface = abstract_surface;
+ cairo_status_t status;
+
+ if (surface->owner != NULL) {
+ cairo_surface_destroy (surface->owner);
+ } else {
+ status = _cairo_xcb_connection_acquire (surface->connection);
+ if (unlikely (status))
+ return status;
+
+ if (_cairo_xcb_connection_take_socket (surface->connection) == CAIRO_STATUS_SUCCESS) {
+ _cairo_xcb_connection_render_free_picture (surface->connection,
+ surface->picture);
+ }
+ _cairo_xcb_connection_release (surface->connection);
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static const cairo_surface_backend_t _cairo_xcb_picture_backend = {
+ CAIRO_SURFACE_TYPE_XCB,
+ NULL,
+ _cairo_xcb_picture_finish,
+};
+
+static const struct xcb_render_transform_t identity_transform = {
+ 1 << 16, 0, 0,
+ 0, 1 << 16, 0,
+ 0, 0, 1 << 16,
+};
+
+static cairo_xcb_picture_t *
+_cairo_xcb_picture_create (cairo_xcb_screen_t *screen,
+ pixman_format_code_t pixman_format,
+ xcb_render_pictformat_t xrender_format,
+ int width, int height)
+{
+ cairo_xcb_picture_t *surface;
+
+ surface = malloc (sizeof (cairo_xcb_picture_t));
+ if (unlikely (surface == NULL))
+ return (cairo_xcb_picture_t *)
+ _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
+
+ _cairo_surface_init (&surface->base,
+ &_cairo_xcb_picture_backend,
+ NULL,
+ _cairo_content_from_pixman_format (pixman_format));
+
+ surface->connection = screen->connection;
+ surface->screen = screen;
+ surface->owner = NULL;
+ surface->picture = _cairo_xcb_connection_get_xid (screen->connection);
+ surface->pixman_format = pixman_format;
+ surface->xrender_format = xrender_format;
+
+ surface->x0 = surface->y0 = 0;
+ surface->x = surface->y = 0;
+ surface->width = width;
+ surface->height = height;
+
+ surface->transform = identity_transform;
+ surface->extend = CAIRO_EXTEND_NONE;
+ surface->filter = CAIRO_FILTER_NEAREST;
+ surface->has_component_alpha = FALSE;
+
+ return surface;
+}
+
+static cairo_xcb_picture_t *
+_cairo_xcb_picture_copy (cairo_xcb_surface_t *target)
+{
+ cairo_xcb_picture_t *surface;
+
+ surface = malloc (sizeof (cairo_xcb_picture_t));
+ if (unlikely (surface == NULL))
+ return (cairo_xcb_picture_t *)
+ _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
+
+ _cairo_surface_init (&surface->base,
+ &_cairo_xcb_picture_backend,
+ NULL,
+ target->base.content);
+
+ surface->connection = target->connection;
+ surface->screen = target->screen;
+ surface->owner = cairo_surface_reference (&target->base);
+ _cairo_xcb_surface_ensure_picture (target);
+ surface->picture = target->picture;
+ surface->pixman_format = target->pixman_format;
+ surface->xrender_format = target->xrender_format;
+
+ surface->x0 = surface->y0 = 0;
+ surface->x = surface->y = 0;
+ surface->width = target->width;
+ surface->height = target->height;
+
+ surface->transform = identity_transform;
+ surface->extend = CAIRO_EXTEND_NONE;
+ surface->filter = CAIRO_FILTER_NEAREST;
+ surface->has_component_alpha = FALSE;
+
+ return surface;
+}
+
+static inline cairo_bool_t
+_operator_is_supported (uint32_t flags, cairo_operator_t op)
+{
+ if (op <= CAIRO_OPERATOR_SATURATE)
+ return TRUE;
+
+ return flags & CAIRO_XCB_RENDER_HAS_PDF_OPERATORS;
+}
+
+static int
+_render_operator (cairo_operator_t op)
+{
+#define C(x,y) case CAIRO_OPERATOR_##x: return XCB_RENDER_PICT_OP_##y
+ switch (op) {
+ C(CLEAR, CLEAR);
+ C(SOURCE, SRC);
+
+ C(OVER, OVER);
+ C(IN, IN);
+ C(OUT, OUT);
+ C(ATOP, ATOP);
+
+ C(DEST, DST);
+ C(DEST_OVER, OVER_REVERSE);
+ C(DEST_IN, IN_REVERSE);
+ C(DEST_OUT, OUT_REVERSE);
+ C(DEST_ATOP, ATOP_REVERSE);
+
+ C(XOR, XOR);
+ C(ADD, ADD);
+ C(SATURATE, SATURATE);
+
+ case CAIRO_OPERATOR_MULTIPLY:
+ case CAIRO_OPERATOR_SCREEN:
+ case CAIRO_OPERATOR_OVERLAY:
+ case CAIRO_OPERATOR_DARKEN:
+ case CAIRO_OPERATOR_LIGHTEN:
+ case CAIRO_OPERATOR_COLOR_DODGE:
+ case CAIRO_OPERATOR_COLOR_BURN:
+ case CAIRO_OPERATOR_HARD_LIGHT:
+ case CAIRO_OPERATOR_SOFT_LIGHT:
+ case CAIRO_OPERATOR_DIFFERENCE:
+ case CAIRO_OPERATOR_EXCLUSION:
+ case CAIRO_OPERATOR_HSL_HUE:
+ case CAIRO_OPERATOR_HSL_SATURATION:
+ case CAIRO_OPERATOR_HSL_COLOR:
+ case CAIRO_OPERATOR_HSL_LUMINOSITY:
+ default:
+ ASSERT_NOT_REACHED;
+ return XCB_RENDER_PICT_OP_OVER;
+ }
+}
+
+static void
+_cairo_xcb_surface_set_clip_region (cairo_xcb_surface_t *surface,
+ cairo_region_t *region)
+{
+ xcb_rectangle_t rects[CAIRO_STACK_ARRAY_LENGTH (xcb_rectangle_t)];
+ int i, num_rects;
+
+ num_rects = cairo_region_num_rectangles (region);
+ assert (num_rects < ARRAY_LENGTH (rects)); /* XXX somebody will! */
+
+ for (i = 0; i < num_rects; i++) {
+ cairo_rectangle_int_t rect;
+
+ cairo_region_get_rectangle (region, i, &rect);
+
+ rects[i].x = rect.x;
+ rects[i].y = rect.y;
+ rects[i].width = rect.width;
+ rects[i].height = rect.height;
+ }
+
+ _cairo_xcb_connection_render_set_picture_clip_rectangles (surface->connection,
+ surface->picture,
+ 0, 0,
+ num_rects, rects);
+}
+
+static void
+_cairo_xcb_surface_clear_clip_region (cairo_xcb_surface_t *surface)
+{
+ uint32_t values[] = { XCB_NONE };
+ _cairo_xcb_connection_render_change_picture (surface->connection,
+ surface->picture,
+ XCB_RENDER_CP_CLIP_MASK, values);
+}
+
+static void
+_cairo_xcb_surface_ensure_picture (cairo_xcb_surface_t *surface)
+{
+ if (surface->picture == XCB_NONE) {
+ surface->picture = _cairo_xcb_connection_get_xid (surface->connection);
+ _cairo_xcb_connection_render_create_picture (surface->connection,
+ surface->picture,
+ surface->drawable,
+ surface->xrender_format,
+ 0, NULL);
+ }
+}
+
+static cairo_xcb_picture_t *
+_picture_from_image (cairo_xcb_surface_t *target,
+ xcb_render_pictformat_t format,
+ cairo_image_surface_t *image,
+ cairo_xcb_shm_info_t *shm_info)
+{
+ xcb_pixmap_t pixmap;
+ xcb_gcontext_t gc;
+ cairo_xcb_picture_t *picture;
+
+ pixmap = _cairo_xcb_connection_create_pixmap (target->connection,
+ image->depth,
+ target->drawable,
+ image->width, image->height);
+
+ gc = _cairo_xcb_screen_get_gc (target->screen, pixmap, image->depth);
+
+ if (shm_info != NULL) {
+ shm_info->seqno =
+ _cairo_xcb_connection_shm_put_image (target->connection,
+ pixmap, gc,
+ image->width, image->height,
+ 0, 0,
+ image->width, image->height,
+ 0, 0,
+ image->depth,
+ shm_info->shm,
+ shm_info->offset);
+ } else {
+ int len;
+
+ /* Do we need to trim the image? */
+ len = CAIRO_STRIDE_FOR_WIDTH_BPP (image->width, PIXMAN_FORMAT_BPP (image->pixman_format));
+ if (len == image->stride) {
+ _cairo_xcb_connection_put_image (target->connection,
+ pixmap, gc,
+ image->width, image->height,
+ 0, 0,
+ image->depth,
+ image->stride,
+ image->data);
+ } else {
+ _cairo_xcb_connection_put_subimage (target->connection,
+ pixmap, gc,
+ 0, 0,
+ image->width, image->height,
+ PIXMAN_FORMAT_BPP (image->pixman_format) / 8,
+ image->stride,
+ 0, 0,
+ image->depth,
+ image->data);
+
+ }
+ }
+
+ _cairo_xcb_screen_put_gc (target->screen, image->depth, gc);
+
+ picture = _cairo_xcb_picture_create (target->screen,
+ image->pixman_format, format,
+ image->width, image->height);
+ if (likely (picture->base.status == CAIRO_STATUS_SUCCESS)) {
+ _cairo_xcb_connection_render_create_picture (target->connection,
+ picture->picture, pixmap, format,
+ 0, 0);
+ }
+
+ _cairo_xcb_connection_free_pixmap (target->connection, pixmap);
+
+ return picture;
+}
+
+static cairo_bool_t
+_pattern_is_supported (uint32_t flags,
+ const cairo_pattern_t *pattern)
+
+{
+ if (pattern->type == CAIRO_PATTERN_TYPE_SOLID)
+ return TRUE;
+
+ if (! _cairo_matrix_is_integer_translation (&pattern->matrix, NULL, NULL)) {
+ if ((flags & CAIRO_XCB_RENDER_HAS_PICTURE_TRANSFORM) == 0)
+ return FALSE;
+ }
+
+ switch (pattern->extend) {
+ default:
+ ASSERT_NOT_REACHED;
+ case CAIRO_EXTEND_NONE:
+ case CAIRO_EXTEND_REPEAT:
+ break;
+ case CAIRO_EXTEND_PAD:
+ case CAIRO_EXTEND_REFLECT:
+ if ((flags & CAIRO_XCB_RENDER_HAS_EXTENDED_REPEAT) == 0)
+ return FALSE;
+ }
+
+ if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
+ cairo_filter_t filter;
+
+ filter = pattern->filter;
+ if (_cairo_matrix_has_unity_scale (&pattern->matrix) &&
+ _cairo_matrix_is_integer_translation (&pattern->matrix, NULL, NULL))
+ {
+ filter = CAIRO_FILTER_NEAREST;
+ }
+
+ if (! (filter == CAIRO_FILTER_NEAREST || filter == CAIRO_FILTER_FAST)) {
+ if ((flags & CAIRO_XCB_RENDER_HAS_FILTERS) == 0)
+ return FALSE;
+ }
+ } else { /* gradient */
+ if ((flags & CAIRO_XCB_RENDER_HAS_GRADIENTS) == 0)
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static double
+_pixman_nearest_sample (double d)
+{
+ return ceil (d - .5);
+}
+
+static cairo_bool_t
+_nearest_sample (const cairo_matrix_t *m,
+ cairo_filter_t filter,
+ double *tx, double *ty)
+{
+ *tx = m->x0;
+ *ty = m->y0;
+ if ((filter == CAIRO_FILTER_FAST || filter == CAIRO_FILTER_NEAREST)
+ && _cairo_matrix_has_unity_scale (m))
+ {
+ *tx = _pixman_nearest_sample (*tx);
+ *ty = _pixman_nearest_sample (*ty);
+ }
+ else
+ {
+ if (*tx != floor (*tx) || *ty != floor (*ty))
+ return FALSE;
+ }
+ return fabs (*tx) < PIXMAN_MAX_INT && fabs (*ty) < PIXMAN_MAX_INT;
+}
+
+static void
+_cairo_xcb_picture_set_matrix (cairo_xcb_picture_t *picture,
+ const cairo_matrix_t *matrix,
+ cairo_filter_t filter,
+ double xc, double yc)
+{
+ cairo_matrix_t m;
+ double tx, ty;
+
+ m = *matrix;
+ if (_nearest_sample (&m, filter, &tx, &ty))
+ m.x0 = m.y0 = 0;
+ else
+ tx = ty = 0;
+
+ if (! _cairo_matrix_is_identity (&m)) {
+ xcb_render_transform_t transform;
+ cairo_matrix_t inv;
+ cairo_status_t status;
+
+ inv = m;
+ status = cairo_matrix_invert (&inv);
+ assert (status == CAIRO_STATUS_SUCCESS);
+
+ if (m.x0 != 0. || m.y0 != 0.) {
+ double x, y;
+
+ /* pixman also limits the [xy]_offset to 16 bits so evenly
+ * spread the bits between the two.
+ */
+ x = floor (inv.x0 / 2);
+ y = floor (inv.y0 / 2);
+ tx = -x;
+ ty = -y;
+ cairo_matrix_init_translate (&inv, x, y);
+ cairo_matrix_multiply (&m, &inv, &m);
+ } else {
+ if (tx != 0. || ty != 0.)
+ cairo_matrix_transform_point (&inv, &tx, &ty);
+ }
+
+ /* Casting between pixman_transform_t and XTransform is safe because
+ * they happen to be the exact same type.
+ */
+ _cairo_matrix_to_pixman_matrix (&m,
+ (pixman_transform_t *) &transform, xc, yc);
+
+ if (memcmp (&picture->transform, &transform, sizeof (xcb_render_transform_t))) {
+ _cairo_xcb_connection_render_set_picture_transform (picture->connection,
+ picture->picture,
+ &transform);
+
+ picture->transform = transform;
+ }
+ }
+
+ picture->x = picture->x0 + tx;
+ picture->y = picture->y0 + ty;
+}
+
+static void
+_cairo_xcb_picture_set_filter (cairo_xcb_picture_t *picture,
+ cairo_filter_t filter)
+{
+ const char *render_filter;
+ int len;
+
+ if (picture->filter == filter)
+ return;
+
+ switch (filter) {
+ case CAIRO_FILTER_FAST:
+ render_filter = "fast";
+ len = strlen ("fast");
+ break;
+
+ case CAIRO_FILTER_GOOD:
+ render_filter = "good";
+ len = strlen ("good");
+ break;
+
+ case CAIRO_FILTER_BEST:
+ render_filter = "best";
+ len = strlen ("best");
+ break;
+
+ case CAIRO_FILTER_NEAREST:
+ render_filter = "nearest";
+ len = strlen ("nearest");
+ break;
+
+ case CAIRO_FILTER_BILINEAR:
+ render_filter = "bilinear";
+ len = strlen ("bilinear");
+ break;
+
+ default:
+ ASSERT_NOT_REACHED;
+ case CAIRO_FILTER_GAUSSIAN:
+ render_filter = "best";
+ len = strlen ("best");
+ break;
+ }
+
+ _cairo_xcb_connection_render_set_picture_filter (picture->connection,
+ picture->picture,
+ len, (char *) render_filter);
+ picture->filter = filter;
+}
+
+static void
+_cairo_xcb_picture_set_extend (cairo_xcb_picture_t *picture,
+ cairo_extend_t extend)
+{
+ uint32_t pa[1];
+
+ if (picture->extend == extend)
+ return;
+
+ switch (extend) {
+ default:
+ ASSERT_NOT_REACHED;
+ case CAIRO_EXTEND_NONE:
+ pa[0] = XCB_RENDER_REPEAT_NONE;
+ break;
+
+ case CAIRO_EXTEND_REPEAT:
+ pa[0] = XCB_RENDER_REPEAT_NORMAL;
+ break;
+
+ case CAIRO_EXTEND_REFLECT:
+ pa[0] = XCB_RENDER_REPEAT_REFLECT;
+ break;
+
+ case CAIRO_EXTEND_PAD:
+ pa[0] = XCB_RENDER_REPEAT_PAD;
+ break;
+ }
+
+ _cairo_xcb_connection_render_change_picture (picture->connection,
+ picture->picture,
+ XCB_RENDER_CP_REPEAT, pa);
+ picture->extend = extend;
+}
+
+static void
+_cairo_xcb_picture_set_component_alpha (cairo_xcb_picture_t *picture,
+ cairo_bool_t ca)
+{
+ uint32_t pa[1];
+
+ if (picture->has_component_alpha == ca)
+ return;
+
+ pa[0] = ca;
+
+ _cairo_xcb_connection_render_change_picture (picture->connection,
+ picture->picture,
+ XCB_RENDER_CP_COMPONENT_ALPHA,
+ pa);
+ picture->has_component_alpha = ca;
+}
+
+static cairo_xcb_picture_t *
+_solid_picture (cairo_xcb_surface_t *target,
+ const cairo_color_t *color)
+{
+ xcb_render_color_t xcb_color;
+ xcb_render_pictformat_t xrender_format;
+ cairo_xcb_picture_t *picture;
+
+ xcb_color.red = color->red_short;
+ xcb_color.green = color->green_short;
+ xcb_color.blue = color->blue_short;
+ xcb_color.alpha = color->alpha_short;
+
+ xrender_format = target->screen->connection->standard_formats[CAIRO_FORMAT_ARGB32];
+ picture = _cairo_xcb_picture_create (target->screen,
+ PIXMAN_a8r8g8b8,
+ xrender_format,
+ -1, -1);
+ if (unlikely (picture->base.status))
+ return picture;
+
+ if (target->flags & CAIRO_XCB_RENDER_HAS_GRADIENTS) {
+ _cairo_xcb_connection_render_create_solid_fill (target->connection,
+ picture->picture,
+ xcb_color);
+ } else {
+ xcb_pixmap_t pixmap;
+ uint32_t values[] = { XCB_RENDER_REPEAT_NORMAL };
+
+ pixmap = _cairo_xcb_connection_create_pixmap (target->connection,
+ 32, target->drawable, 1, 1);
+ _cairo_xcb_connection_render_create_picture (target->connection,
+ picture->picture,
+ pixmap,
+ xrender_format,
+ XCB_RENDER_CP_REPEAT,
+ values);
+ if (target->flags & CAIRO_XCB_RENDER_HAS_FILL_RECTANGLES) {
+ xcb_rectangle_t rect;
+
+ rect.x = rect.y = 0;
+ rect.width = rect.height = 1;
+
+ _cairo_xcb_connection_render_fill_rectangles (picture->connection,
+ XCB_RENDER_PICT_OP_SRC,
+ picture->picture,
+ xcb_color, 1, &rect);
+ } else {
+ xcb_gcontext_t gc;
+ uint32_t pixel;
+
+ gc = _cairo_xcb_screen_get_gc (target->screen, pixmap, 32);
+
+ /* XXX byte ordering? */
+ pixel = ((color->alpha_short >> 8) << 24) |
+ ((color->red_short >> 8) << 16) |
+ ((color->green_short >> 8) << 8) |
+ ((color->blue_short >> 8) << 0);
+
+ _cairo_xcb_connection_put_image (target->connection,
+ pixmap, gc,
+ 1, 1, 0, 0,
+ 32, 4, &pixel);
+
+ _cairo_xcb_screen_put_gc (target->screen, 32, gc);
+ }
+
+ _cairo_xcb_connection_free_pixmap (target->connection, pixmap);
+ }
+
+ return picture;
+}
+
+static cairo_xcb_picture_t *
+_cairo_xcb_transparent_picture (cairo_xcb_surface_t *target)
+{
+ cairo_xcb_picture_t *picture;
+
+ picture = (cairo_xcb_picture_t *) target->screen->stock_colors[CAIRO_STOCK_TRANSPARENT];
+ if (picture == NULL) {
+ picture = _solid_picture (target, CAIRO_COLOR_TRANSPARENT);
+ target->screen->stock_colors[CAIRO_STOCK_TRANSPARENT] = &picture->base;
+ }
+
+ return (cairo_xcb_picture_t *) cairo_surface_reference (&picture->base);
+}
+
+static cairo_xcb_picture_t *
+_cairo_xcb_black_picture (cairo_xcb_surface_t *target)
+{
+ cairo_xcb_picture_t *picture;
+
+ picture = (cairo_xcb_picture_t *) target->screen->stock_colors[CAIRO_STOCK_BLACK];
+ if (picture == NULL) {
+ picture = _solid_picture (target, CAIRO_COLOR_BLACK);
+ target->screen->stock_colors[CAIRO_STOCK_BLACK] = &picture->base;
+ }
+
+ return (cairo_xcb_picture_t *) cairo_surface_reference (&picture->base);
+}
+
+static cairo_xcb_picture_t *
+_cairo_xcb_white_picture (cairo_xcb_surface_t *target)
+{
+ cairo_xcb_picture_t *picture;
+
+ picture = (cairo_xcb_picture_t *) target->screen->stock_colors[CAIRO_STOCK_WHITE];
+ if (picture == NULL) {
+ picture = _solid_picture (target, CAIRO_COLOR_WHITE);
+ target->screen->stock_colors[CAIRO_STOCK_WHITE] = &picture->base;
+ }
+
+ return (cairo_xcb_picture_t *) cairo_surface_reference (&picture->base);
+}
+
+static cairo_xcb_picture_t *
+_cairo_xcb_solid_picture (cairo_xcb_surface_t *target,
+ const cairo_solid_pattern_t *pattern)
+{
+ cairo_xcb_picture_t *picture;
+ cairo_xcb_screen_t *screen;
+ int i, n_cached;
+
+ if (pattern->color.alpha_short <= 0x00ff)
+ return _cairo_xcb_transparent_picture (target);
+
+ if (pattern->color.alpha_short >= 0xff00) {
+ if (pattern->color.red_short <= 0x00ff &&
+ pattern->color.green_short <= 0x00ff &&
+ pattern->color.blue_short <= 0x00ff)
+ {
+ return _cairo_xcb_black_picture (target);
+ }
+
+ if (pattern->color.red_short >= 0xff00 &&
+ pattern->color.green_short >= 0xff00 &&
+ pattern->color.blue_short >= 0xff00)
+ {
+ return _cairo_xcb_white_picture (target);
+ }
+ }
+
+ screen = target->screen;
+ n_cached = screen->solid_cache_size;
+ for (i = 0; i < n_cached; i++) {
+ if (_cairo_color_equal (&screen->solid_cache[i].color, &pattern->color)) {
+ return (cairo_xcb_picture_t *) cairo_surface_reference (screen->solid_cache[i].picture);
+ }
+ }
+
+ picture = _solid_picture (target, &pattern->color);
+ if (unlikely (picture->base.status))
+ return picture;
+
+ if (screen->solid_cache_size < ARRAY_LENGTH (screen->solid_cache)) {
+ i = screen->solid_cache_size++;
+ } else {
+ i = hars_petruska_f54_1_random () % ARRAY_LENGTH (screen->solid_cache);
+ cairo_surface_destroy (screen->solid_cache[i].picture);
+ }
+ screen->solid_cache[i].picture = cairo_surface_reference (&picture->base);
+ screen->solid_cache[i].color = pattern->color;
+
+ return picture;
+}
+
+static cairo_status_t
+_cairo_xcb_shm_image_create (cairo_xcb_connection_t *connection,
+ pixman_format_code_t pixman_format,
+ int width, int height,
+ cairo_image_surface_t **image_out,
+ cairo_xcb_shm_info_t **shm_info_out)
+{
+ cairo_surface_t *image = NULL;
+ cairo_xcb_shm_info_t *shm_info = NULL;
+ cairo_status_t status;
+
+ if ((connection->flags & CAIRO_XCB_HAS_SHM)) {
+ size_t size, stride;
+
+ stride = CAIRO_STRIDE_FOR_WIDTH_BPP (width, PIXMAN_FORMAT_BPP (pixman_format));
+ size = stride * height;
+ if (size > CAIRO_XCB_SHM_SMALL_IMAGE) {
+ status = _cairo_xcb_connection_allocate_shm_info (connection,
+ size, &shm_info);
+ if (unlikely (status))
+ return status;
+
+ image = _cairo_image_surface_create_with_pixman_format (shm_info->mem,
+ pixman_format,
+ width, height,
+ stride);
+ status = image->status;
+ if (unlikely (status)) {
+ _cairo_xcb_shm_info_destroy (shm_info);
+ return status;
+ }
+
+ status = _cairo_user_data_array_set_data (&image->user_data,
+ (const cairo_user_data_key_t *) connection,
+ shm_info,
+ (cairo_destroy_func_t) _cairo_xcb_shm_info_destroy);
+ if (unlikely (status)) {
+ cairo_surface_destroy (image);
+ _cairo_xcb_shm_info_destroy (shm_info);
+ return status;
+ }
+ }
+ }
+
+ if (image == NULL) {
+ image = _cairo_image_surface_create_with_pixman_format (NULL,
+ pixman_format,
+ width, height,
+ 0);
+ status = image->status;
+ if (unlikely (status))
+ return status;
+ }
+
+ *image_out = (cairo_image_surface_t *) image;
+ *shm_info_out = shm_info;
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_xcb_picture_t *
+_render_to_picture (cairo_xcb_surface_t *target,
+ const cairo_pattern_t *pattern,
+ const cairo_rectangle_int_t *extents)
+{
+ cairo_image_surface_t *image;
+ cairo_xcb_shm_info_t *shm_info;
+ cairo_pattern_union_t copy;
+ cairo_status_t status;
+ cairo_xcb_picture_t *picture;
+ pixman_format_code_t pixman_format;
+ xcb_render_pictformat_t xrender_format;
+
+ /* XXX handle extend modes via tiling? */
+ /* XXX alpha-only masks? */
+
+ pixman_format = PIXMAN_a8r8g8b8;
+ xrender_format = target->screen->connection->standard_formats[CAIRO_FORMAT_ARGB32];
+
+ status = _cairo_xcb_shm_image_create (target->screen->connection,
+ pixman_format,
+ extents->width, extents->height,
+ &image, &shm_info);
+ if (unlikely (status))
+ return (cairo_xcb_picture_t *) _cairo_surface_create_in_error (status);
+
+ _cairo_pattern_init_static_copy (©.base, pattern);
+ cairo_matrix_translate (©.base.matrix, extents->x, extents->y);
+ status = _cairo_surface_paint (&image->base,
+ CAIRO_OPERATOR_SOURCE,
+ ©.base,
+ NULL);
+ if (unlikely (status)) {
+ cairo_surface_destroy (&image->base);
+ return (cairo_xcb_picture_t *) _cairo_surface_create_in_error (status);
+ }
+
+ picture = _picture_from_image (target, xrender_format, image, shm_info);
+ cairo_surface_destroy (&image->base);
+
+ if (unlikely (picture->base.status))
+ return picture;
+
+ _cairo_xcb_picture_set_component_alpha (picture, pattern->has_component_alpha);
+ picture->x = -extents->x;
+ picture->y = -extents->y;
+
+ return picture;
+}
+
+static xcb_render_fixed_t *
+_gradient_to_xcb (const cairo_gradient_pattern_t *gradient,
+ char *buf, unsigned int buflen)
+{
+ xcb_render_fixed_t *stops;
+ xcb_render_color_t *colors;
+ unsigned int i;
+
+ if (gradient->n_stops * (sizeof (xcb_render_fixed_t) + sizeof (xcb_render_color_t)) < buflen)
+ {
+ stops = (xcb_render_fixed_t *) buf;
+ }
+ else
+ {
+ stops =
+ _cairo_malloc_ab (gradient->n_stops,
+ sizeof (xcb_render_fixed_t) + sizeof (xcb_render_color_t));
+ if (unlikely (stops == NULL))
+ return NULL;
+ }
+
+ colors = (xcb_render_color_t *) (stops + gradient->n_stops);
+ for (i = 0; i < gradient->n_stops; i++) {
+ stops[i] =
+ _cairo_fixed_16_16_from_double (gradient->stops[i].offset);
+
+ colors[i].red = gradient->stops[i].color.red_short;
+ colors[i].green = gradient->stops[i].color.green_short;
+ colors[i].blue = gradient->stops[i].color.blue_short;
+ colors[i].alpha = gradient->stops[i].color.alpha_short;
+ }
+
+ return stops;
+}
+
+static cairo_xcb_picture_t *
+_cairo_xcb_linear_picture (cairo_xcb_surface_t *target,
+ const cairo_linear_pattern_t *pattern,
+ const cairo_rectangle_int_t *extents)
+{
+ char buf[CAIRO_STACK_BUFFER_SIZE];
+ cairo_fixed_t xdim, ydim;
+ xcb_render_fixed_t *stops;
+ xcb_render_color_t *colors;
+ xcb_render_pointfix_t p1, p2;
+ cairo_matrix_t matrix = pattern->base.base.matrix;
+ cairo_xcb_picture_t *picture;
+ cairo_status_t status;
+
+ picture = (cairo_xcb_picture_t *)
+ _cairo_xcb_screen_lookup_linear_picture (target->screen, pattern);
+ if (picture != NULL)
+ goto setup_picture;
+
+ stops = _gradient_to_xcb (&pattern->base, buf, sizeof (buf));
+ if (unlikely (stops == NULL))
+ return (cairo_xcb_picture_t *) _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
+
+ picture = _cairo_xcb_picture_create (target->screen,
+ target->screen->connection->standard_formats[CAIRO_FORMAT_ARGB32],
+ PIXMAN_a8r8g8b8,
+ -1, -1);
+ if (unlikely (picture->base.status)) {
+ if (stops != (xcb_render_fixed_t *) buf)
+ free (stops);
+ return picture;
+ }
+ picture->filter = CAIRO_FILTER_DEFAULT;
+
+ xdim = pattern->p2.x - pattern->p1.x;
+ ydim = pattern->p2.y - pattern->p1.y;
+
+ /*
+ * Transform the matrix to avoid overflow when converting between
+ * cairo_fixed_t and pixman_fixed_t (without incurring performance
+ * loss when the transformation is unnecessary).
+ *
+ * XXX: Consider converting out-of-range co-ordinates and transforms.
+ * Having a function to compute the required transformation to
+ * "normalize" a given bounding box would be generally useful -
+ * cf linear patterns, gradient patterns, surface patterns...
+ */
+#define PIXMAN_MAX_INT ((pixman_fixed_1 >> 1) - pixman_fixed_e) /* need to ensure deltas also fit */
+ if (unlikely (_cairo_fixed_integer_ceil (xdim) > PIXMAN_MAX_INT ||
+ _cairo_fixed_integer_ceil (ydim) > PIXMAN_MAX_INT))
+ {
+ double sf;
+
+ if (xdim > ydim)
+ sf = PIXMAN_MAX_INT / _cairo_fixed_to_double (xdim);
+ else
+ sf = PIXMAN_MAX_INT / _cairo_fixed_to_double (ydim);
+
+ p1.x = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (pattern->p1.x) * sf);
+ p1.y = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (pattern->p1.y) * sf);
+ p2.x = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (pattern->p2.x) * sf);
+ p2.y = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (pattern->p2.y) * sf);
+
+ cairo_matrix_scale (&matrix, sf, sf);
+ }
+ else
+ {
+ p1.x = _cairo_fixed_to_16_16 (pattern->p1.x);
+ p1.y = _cairo_fixed_to_16_16 (pattern->p1.y);
+ p2.x = _cairo_fixed_to_16_16 (pattern->p2.x);
+ p2.y = _cairo_fixed_to_16_16 (pattern->p2.y);
+ }
+
+ colors = (xcb_render_color_t *) (stops + pattern->base.n_stops);
+ _cairo_xcb_connection_render_create_linear_gradient (target->connection,
+ picture->picture,
+ p1, p2,
+ pattern->base.n_stops,
+ stops, colors);
+
+ if (stops != (xcb_render_fixed_t *) buf)
+ free (stops);
+
+ status = _cairo_xcb_screen_store_linear_picture (target->screen,
+ pattern,
+ &picture->base);
+ if (unlikely (status)) {
+ cairo_surface_destroy (&picture->base);
+ return (cairo_xcb_picture_t *) _cairo_surface_create_in_error (status);
+ }
+
+setup_picture:
+ _cairo_xcb_picture_set_matrix (picture, &matrix,
+ pattern->base.base.filter,
+ extents->x + extents->width/2.,
+ extents->y + extents->height/2.);
+ _cairo_xcb_picture_set_filter (picture, pattern->base.base.filter);
+ _cairo_xcb_picture_set_extend (picture, pattern->base.base.extend);
+ _cairo_xcb_picture_set_component_alpha (picture,
+ pattern->base.base.has_component_alpha);
+
+ return picture;
+}
+
+static cairo_xcb_picture_t *
+_cairo_xcb_radial_picture (cairo_xcb_surface_t *target,
+ const cairo_radial_pattern_t *pattern,
+ const cairo_rectangle_int_t *extents)
+{
+ char buf[CAIRO_STACK_BUFFER_SIZE];
+ xcb_render_fixed_t *stops;
+ xcb_render_color_t *colors;
+ xcb_render_pointfix_t c1, c2;
+ xcb_render_fixed_t r1, r2;
+ cairo_xcb_picture_t *picture;
+ cairo_status_t status;
+
+ picture = (cairo_xcb_picture_t *)
+ _cairo_xcb_screen_lookup_radial_picture (target->screen, pattern);
+ if (picture != NULL)
+ goto setup_picture;
+
+ stops = _gradient_to_xcb (&pattern->base, buf, sizeof (buf));
+ if (unlikely (stops == NULL))
+ return (cairo_xcb_picture_t *) _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
+
+ picture = _cairo_xcb_picture_create (target->screen,
+ target->screen->connection->standard_formats[CAIRO_FORMAT_ARGB32],
+ PIXMAN_a8r8g8b8,
+ -1, -1);
+ if (unlikely (picture->base.status)) {
+ if (stops != (xcb_render_fixed_t *) buf)
+ free (stops);
+ return picture;
+ }
+ picture->filter = CAIRO_FILTER_DEFAULT;
+
+ c1.x = _cairo_fixed_to_16_16 (pattern->c1.x);
+ c1.y = _cairo_fixed_to_16_16 (pattern->c1.y);
+ r1 = _cairo_fixed_to_16_16 (pattern->r1);
+ c2.x = _cairo_fixed_to_16_16 (pattern->c2.x);
+ c2.y = _cairo_fixed_to_16_16 (pattern->c2.y);
+ r2 = _cairo_fixed_to_16_16 (pattern->r2);
+
+ colors = (xcb_render_color_t *) (stops + pattern->base.n_stops);
+ _cairo_xcb_connection_render_create_radial_gradient (target->connection,
+ picture->picture,
+ c1, c2, r1, r2,
+ pattern->base.n_stops,
+ stops, colors);
+
+ if (stops != (xcb_render_fixed_t *) buf)
+ free (stops);
+
+ status = _cairo_xcb_screen_store_radial_picture (target->screen,
+ pattern,
+ &picture->base);
+ if (unlikely (status)) {
+ cairo_surface_destroy (&picture->base);
+ return (cairo_xcb_picture_t *) _cairo_surface_create_in_error (status);
+ }
+
+setup_picture:
+ _cairo_xcb_picture_set_matrix (picture, &pattern->base.base.matrix,
+ pattern->base.base.filter,
+ extents->x + extents->width/2.,
+ extents->y + extents->height/2.);
+ _cairo_xcb_picture_set_filter (picture, pattern->base.base.filter);
+ _cairo_xcb_picture_set_extend (picture, pattern->base.base.extend);
+ _cairo_xcb_picture_set_component_alpha (picture,
+ pattern->base.base.has_component_alpha);
+
+ return picture;
+}
+
+static void
+_decouple_cached_picture (cairo_surface_t *surface)
+{
+ cairo_xcb_picture_t *picture = (cairo_xcb_picture_t *) surface;
+
+ if (! picture->base.finished)
+ _cairo_xcb_screen_remove_surface_picture (picture->screen, &picture->base);
+}
+
+static cairo_xcb_picture_t *
+_copy_to_picture (cairo_xcb_surface_t *source,
+ cairo_bool_t force)
+{
+ cairo_xcb_picture_t *picture;
+ uint32_t values[] = { 0, 1 };
+
+ /* XXX two level device locking, ensure we release the xcb device mutex? */
+ if (source->drm != NULL)
+ cairo_surface_flush (source->drm);
+
+ if (source->owns_pixmap && ! force) {
+ picture = _cairo_xcb_picture_copy (source);
+ } else {
+ picture = _cairo_xcb_picture_create (source->screen,
+ source->xrender_format,
+ source->pixman_format,
+ source->width,
+ source->height);
+ if (unlikely (picture->base.status))
+ return picture;
+
+ _cairo_xcb_connection_render_create_picture (source->connection,
+ picture->picture,
+ source->drawable,
+ source->xrender_format,
+ XCB_RENDER_CP_GRAPHICS_EXPOSURE |
+ XCB_RENDER_CP_SUBWINDOW_MODE,
+ values);
+ }
+
+ return picture;
+}
+
+static cairo_xcb_picture_t *
+_cairo_xcb_surface_picture (cairo_xcb_surface_t *target,
+ const cairo_surface_pattern_t *pattern,
+ const cairo_rectangle_int_t *extents)
+{
+ cairo_surface_t *source;
+ cairo_xcb_picture_t *picture;
+ cairo_filter_t filter;
+ cairo_extend_t extend;
+ cairo_status_t status;
+
+ source = pattern->surface;
+ if (source->is_clear) {
+ if (source->content & CAIRO_CONTENT_ALPHA)
+ return _cairo_xcb_transparent_picture (target);
+ else
+ return _cairo_xcb_black_picture (target);
+ }
+
+ picture = (cairo_xcb_picture_t *)
+ _cairo_surface_has_snapshot (source, &_cairo_xcb_picture_backend);
+ if (picture != NULL) {
+ if (picture->screen == target->screen) {
+ picture = (cairo_xcb_picture_t *) cairo_surface_reference (&picture->base);
+ goto setup_picture;
+ }
+ }
+
+ if (source->type == CAIRO_SURFACE_TYPE_XCB)
+ {
+ if (source->backend->type == CAIRO_SURFACE_TYPE_XCB) {
+ if (((cairo_xcb_surface_t *) source)->screen == target->screen) {
+ picture = _copy_to_picture ((cairo_xcb_surface_t *) source, FALSE);
+ if (unlikely (picture->base.status))
+ return picture;
+ }
+ } else if (source->backend->type == CAIRO_INTERNAL_SURFACE_TYPE_SUBSURFACE) {
+ cairo_surface_subsurface_t *sub = (cairo_surface_subsurface_t *) source;
+ cairo_xcb_surface_t *xcb = (cairo_xcb_surface_t *) sub->target;
+
+ /* XXX repeat interval with source clipping? */
+ if (FALSE && xcb->screen == target->screen) {
+ xcb_rectangle_t rect;
+
+ picture = _copy_to_picture (xcb, TRUE);
+ if (unlikely (picture->base.status))
+ return picture;
+
+ rect.x = sub->extents.x;
+ rect.y = sub->extents.y;
+ rect.width = sub->extents.width;
+ rect.height = sub->extents.height;
+
+ _cairo_xcb_connection_render_set_picture_clip_rectangles (xcb->connection,
+ picture->picture,
+ 0, 0,
+ 1, &rect);
+ picture->x0 = rect.x;
+ picture->y0 = rect.y;
+ picture->width = rect.width;
+ picture->height = rect.height;
+ }
+ } else if (source->backend->type == CAIRO_INTERNAL_SURFACE_TYPE_SNAPSHOT) {
+ cairo_surface_snapshot_t *snap = (cairo_surface_snapshot_t *) source;
+ cairo_xcb_surface_t *xcb = (cairo_xcb_surface_t *) snap->target;
+
+ if (xcb->screen == target->screen) {
+ picture = _copy_to_picture (xcb, TRUE);
+ if (unlikely (picture->base.status))
+ return picture;
+ }
+ }
+ }
+#if CAIRO_HAS_XLIB_XCB_FUNCTIONS
+ else if (source->type == CAIRO_SURFACE_TYPE_XLIB)
+ {
+ if (source->backend->type == CAIRO_SURFACE_TYPE_XLIB) {
+ if (((cairo_xlib_xcb_surface_t *) source)->xcb->screen == target->screen) {
+ picture = _copy_to_picture (((cairo_xlib_xcb_surface_t *) source)->xcb,
+ FALSE);
+ if (unlikely (picture->base.status))
+ return picture;
+ }
+ } else if (source->backend->type == CAIRO_INTERNAL_SURFACE_TYPE_SUBSURFACE) {
+ cairo_surface_subsurface_t *sub = (cairo_surface_subsurface_t *) source;
+ cairo_xcb_surface_t *xcb = ((cairo_xlib_xcb_surface_t *) sub->target)->xcb;
+
+ if (FALSE && xcb->screen == target->screen) {
+ xcb_rectangle_t rect;
+
+ picture = _copy_to_picture (xcb, TRUE);
+ if (unlikely (picture->base.status))
+ return picture;
+
+ rect.x = sub->extents.x;
+ rect.y = sub->extents.y;
+ rect.width = sub->extents.width;
+ rect.height = sub->extents.height;
+
+ _cairo_xcb_connection_render_set_picture_clip_rectangles (xcb->connection,
+ picture->picture,
+ 0, 0,
+ 1, &rect);
+ picture->x0 = rect.x;
+ picture->y0 = rect.y;
+ picture->width = rect.width;
+ picture->height = rect.height;
+ }
+ } else if (source->backend->type == CAIRO_INTERNAL_SURFACE_TYPE_SNAPSHOT) {
+ cairo_surface_snapshot_t *snap = (cairo_surface_snapshot_t *) source;
+ cairo_xcb_surface_t *xcb = ((cairo_xlib_xcb_surface_t *) snap->target)->xcb;
+
+ if (xcb->screen == target->screen) {
+ picture = _copy_to_picture (xcb, TRUE);
+ if (unlikely (picture->base.status))
+ return picture;
+ }
+ }
+ }
+#endif
+#if CAIRO_HAS_XCB_DRM_FUNCTIONS && CAIRO_HAS_DRM_SURFACE
+ else if (source->type == CAIRO_SURFACE_TYPE_DRM &&
+ target->drm != NULL &&
+ target->drm->device == source->device)
+ {
+ cairo_drm_surface_t *drm = (cairo_drm_surface_t *) source;
+ cairo_xcb_surface_t *tmp;
+ xcb_pixmap_t pixmap;
+ pixman_format_code_t pixman_format;
+ cairo_surface_pattern_t pattern;
+
+ /* XXX XRenderCreatePictureForNative:
+ * Copy the source to a temporary pixmap if possible.
+ * Still cheaper than pushing the image via the CPU.
+ */
+
+ switch (drm->format) {
+ case CAIRO_FORMAT_A1:
+ pixman_format = PIXMAN_a1;
+ break;
+ case CAIRO_FORMAT_A8:
+ pixman_format = PIXMAN_a8;
+ break;
+ case CAIRO_FORMAT_RGB24:
+ pixman_format = PIXMAN_x8r8g8b8;
+ break;
+ default:
+ case CAIRO_FORMAT_ARGB32:
+ pixman_format = PIXMAN_a8r8g8b8;
+ break;
+ }
+
+ pixmap =
+ _cairo_xcb_connection_create_pixmap (target->connection,
+ PIXMAN_FORMAT_DEPTH (pixman_format),
+ target->drawable,
+ drm->width, drm->height);
+
+ tmp = (cairo_xcb_surface_t *)
+ _cairo_xcb_surface_create_internal (target->screen,
+ pixmap, TRUE,
+ pixman_format,
+ target->connection->standard_formats[drm->format],
+ drm->width, drm->height);
+ if (unlikely (tmp->base.status)) {
+ _cairo_xcb_connection_free_pixmap (target->connection, pixmap);
+ return (cairo_xcb_picture_t *) tmp;
+ }
+
+ _cairo_pattern_init_for_surface (&pattern, source);
+ status = _cairo_surface_paint (&tmp->base,
+ CAIRO_OPERATOR_SOURCE,
+ &pattern.base,
+ NULL);
+ _cairo_pattern_fini (&pattern.base);
+
+ if (unlikely (status)) {
+ cairo_surface_destroy (&tmp->base);
+ return (cairo_xcb_picture_t *) _cairo_surface_create_in_error (status);
+ }
+
+ picture = _copy_to_picture (tmp, FALSE);
+ cairo_surface_destroy (&tmp->base);
+
+ if (unlikely (picture->base.status))
+ return picture;
+ }
+#endif
+#if CAIRO_HAS_GL_FUNCTIONS
+ else if (source->type == CAIRO_SURFACE_TYPE_GL)
+ {
+ /* pixmap from texture */
+ }
+#endif
+
+ if (picture == NULL) {
+ cairo_image_surface_t *image;
+ void *image_extra;
+ cairo_status_t status;
+
+ status = _cairo_surface_acquire_source_image (source, &image, &image_extra);
+ if (unlikely (status))
+ return (cairo_xcb_picture_t *) _cairo_surface_create_in_error (status);
+
+ if (image->format != CAIRO_FORMAT_INVALID) {
+ xcb_render_pictformat_t format;
+
+ format = target->screen->connection->standard_formats[image->format];
+
+ picture = _picture_from_image (target, format, image, NULL);
+ _cairo_surface_release_source_image (source, image, image_extra);
+ } else {
+ cairo_image_surface_t *conv;
+ cairo_format_t format;
+ xcb_render_pictformat_t render_format;
+
+ /* XXX XRenderPutImage! */
+
+ switch (image->base.content) {
+ case CAIRO_CONTENT_ALPHA:
+ format = CAIRO_FORMAT_A8;
+ break;
+ case CAIRO_CONTENT_COLOR:
+ format = CAIRO_FORMAT_RGB24;
+ break;
+ case CAIRO_CONTENT_COLOR_ALPHA:
+ format = CAIRO_FORMAT_ARGB32;
+ break;
+ }
+
+ conv = _cairo_image_surface_coerce (image, format);
+ _cairo_surface_release_source_image (source, image, image_extra);
+ if (unlikely (conv->base.status))
+ return (cairo_xcb_picture_t *) conv;
+
+ render_format = target->screen->connection->standard_formats[format];
+ picture = _picture_from_image (target, render_format, conv, NULL);
+ cairo_surface_destroy (&conv->base);
+ }
+
+ if (unlikely (picture->base.status))
+ return picture;
+ }
+
+ status = _cairo_xcb_screen_store_surface_picture (target->screen,
+ &picture->base,
+ CAIRO_STRIDE_FOR_WIDTH_BPP (picture->width,
+ PIXMAN_FORMAT_BPP (picture->pixman_format))
+ * picture->height);
+ if (unlikely (status)) {
+ cairo_surface_destroy (&picture->base);
+ return (cairo_xcb_picture_t *) _cairo_surface_create_in_error (status);
+ }
+
+ status = _cairo_surface_attach_snapshot (source,
+ &picture->base,
+ _decouple_cached_picture);
+ if (unlikely (status)) {
+ cairo_surface_destroy (&picture->base);
+ return (cairo_xcb_picture_t *) _cairo_surface_create_in_error (status);
+ }
+
+setup_picture:
+ filter = pattern->base.filter;
+ if (filter != CAIRO_FILTER_NEAREST &&
+ _cairo_matrix_has_unity_scale (&pattern->base.matrix) &&
+ _cairo_fixed_is_integer (_cairo_fixed_from_double (pattern->base.matrix.x0)) &&
+ _cairo_fixed_is_integer (_cairo_fixed_from_double (pattern->base.matrix.y0)))
+ {
+ filter = CAIRO_FILTER_NEAREST;
+ }
+ _cairo_xcb_picture_set_filter (picture, filter);
+
+ _cairo_xcb_picture_set_matrix (picture,
+ &pattern->base.matrix, filter,
+ extents->x + extents->width/2.,
+ extents->y + extents->height/2.);
+
+
+ extend = pattern->base.extend;
+ if (extents->x >= 0 && extents->x + extents->width <= picture->width &&
+ extents->y >= 0 && extents->y + extents->height <= picture->height)
+ {
+ extend = CAIRO_EXTEND_NONE;
+ }
+ _cairo_xcb_picture_set_extend (picture, extend);
+ _cairo_xcb_picture_set_component_alpha (picture, pattern->base.has_component_alpha);
+
+ return picture;
+}
+
+static cairo_xcb_picture_t *
+_cairo_xcb_picture_for_pattern (cairo_xcb_surface_t *target,
+ const cairo_pattern_t *pattern,
+ const cairo_rectangle_int_t *extents)
+{
+ if (pattern == NULL)
+ return _cairo_xcb_white_picture (target);
+
+ if (! _pattern_is_supported (target->flags, pattern))
+ return _render_to_picture (target, pattern, extents);
+
+ switch (pattern->type) {
+ case CAIRO_PATTERN_TYPE_SOLID:
+ return _cairo_xcb_solid_picture (target, (cairo_solid_pattern_t *) pattern);
+
+ case CAIRO_PATTERN_TYPE_LINEAR:
+ return _cairo_xcb_linear_picture (target,
+ (cairo_linear_pattern_t *) pattern,
+ extents);
+
+ case CAIRO_PATTERN_TYPE_RADIAL:
+ return _cairo_xcb_radial_picture (target,
+ (cairo_radial_pattern_t *) pattern,
+ extents);
+
+ case CAIRO_PATTERN_TYPE_SURFACE:
+ return _cairo_xcb_surface_picture (target,
+ (cairo_surface_pattern_t *) pattern,
+ extents);
+ default:
+ ASSERT_NOT_REACHED;
+ return _render_to_picture (target, pattern, extents);
+ }
+}
+
+COMPILE_TIME_ASSERT (sizeof (xcb_rectangle_t) <= sizeof (cairo_box_t));
+
+static cairo_status_t
+_render_fill_boxes (void *abstract_dst,
+ cairo_operator_t op,
+ const cairo_color_t *color,
+ cairo_boxes_t *boxes)
+{
+ cairo_xcb_surface_t *dst = abstract_dst;
+ xcb_rectangle_t stack_xrects[CAIRO_STACK_ARRAY_LENGTH (sizeof (xcb_rectangle_t))];
+ xcb_rectangle_t *xrects = stack_xrects;
+ xcb_render_color_t render_color;
+ int render_op = _render_operator (op);
+ struct _cairo_boxes_chunk *chunk;
+ int max_count;
+
+ render_color.red = color->red_short;
+ render_color.green = color->green_short;
+ render_color.blue = color->blue_short;
+ render_color.alpha = color->alpha_short;
+
+ max_count = 0;
+ for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
+ if (chunk->count > max_count)
+ max_count = chunk->count;
+ }
+ if (max_count > ARRAY_LENGTH (stack_xrects)) {
+ xrects = _cairo_malloc_ab (max_count, sizeof (xcb_rectangle_t));
+ if (unlikely (xrects == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ }
+
+ for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
+ int i, j;
+
+ for (i = j = 0; i < chunk->count; i++) {
+ int x1 = _cairo_fixed_integer_round (chunk->base[i].p1.x);
+ int y1 = _cairo_fixed_integer_round (chunk->base[i].p1.y);
+ int x2 = _cairo_fixed_integer_round (chunk->base[i].p2.x);
+ int y2 = _cairo_fixed_integer_round (chunk->base[i].p2.y);
+
+ if (x2 > x1 && y2 > y1) {
+ xrects[j].x = x1;
+ xrects[j].y = y1;
+ xrects[j].width = x2 - x1;
+ xrects[j].height = y2 - y1;
+ j++;
+ }
+ }
+
+ if (j) {
+ _cairo_xcb_connection_render_fill_rectangles
+ (dst->connection,
+ render_op, dst->picture,
+ render_color, j, xrects);
+ }
+ }
+
+ if (xrects != stack_xrects)
+ free (xrects);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+_render_composite_boxes (cairo_xcb_surface_t *dst,
+ cairo_operator_t op,
+ const cairo_pattern_t *src_pattern,
+ const cairo_pattern_t *mask_pattern,
+ const cairo_rectangle_int_t *extents,
+ const cairo_boxes_t *boxes)
+{
+ cairo_xcb_picture_t *src, *mask;
+ const struct _cairo_boxes_chunk *chunk;
+ int render_op;
+
+ render_op = _render_operator (op);
+
+ if (src_pattern == NULL) {
+ src_pattern = mask_pattern;
+ mask_pattern = NULL;
+ }
+
+ src = _cairo_xcb_picture_for_pattern (dst, src_pattern, extents);
+ if (unlikely (src->base.status))
+ return src->base.status;
+
+ if (mask_pattern != NULL) {
+ mask = _cairo_xcb_picture_for_pattern (dst, mask_pattern, extents);
+ if (unlikely (mask->base.status)) {
+ cairo_surface_destroy (&src->base);
+ return mask->base.status;
+ }
+
+ for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
+ const cairo_box_t *box = chunk->base;
+ int i;
+
+ for (i = 0; i < chunk->count; i++) {
+ int x = _cairo_fixed_integer_round (box[i].p1.x);
+ int y = _cairo_fixed_integer_round (box[i].p1.y);
+ int width = _cairo_fixed_integer_round (box[i].p2.x) - x;
+ int height = _cairo_fixed_integer_round (box[i].p2.y) - y;
+
+ if (width && height) {
+ _cairo_xcb_connection_render_composite (dst->connection,
+ render_op,
+ src->picture,
+ mask->picture,
+ dst->picture,
+ x + src->x,
+ y + src->y,
+ x + mask->x,
+ y + mask->y,
+ x, y,
+ width, height);
+ }
+ }
+ }
+
+ cairo_surface_destroy (&mask->base);
+ } else {
+ for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
+ const cairo_box_t *box = chunk->base;
+ int i;
+
+ for (i = 0; i < chunk->count; i++) {
+ int x = _cairo_fixed_integer_round (box[i].p1.x);
+ int y = _cairo_fixed_integer_round (box[i].p1.y);
+ int width = _cairo_fixed_integer_round (box[i].p2.x) - x;
+ int height = _cairo_fixed_integer_round (box[i].p2.y) - y;
+
+ if (width && height) {
+ _cairo_xcb_connection_render_composite (dst->connection,
+ render_op,
+ src->picture,
+ XCB_NONE,
+ dst->picture,
+ x + src->x,
+ y + src->y,
+ 0, 0,
+ x, y,
+ width, height);
+ }
+ }
+ }
+ }
+
+ cairo_surface_destroy (&src->base);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+
+#define CAIRO_FIXED_16_16_MIN _cairo_fixed_from_int (-32768)
+#define CAIRO_FIXED_16_16_MAX _cairo_fixed_from_int (32767)
+
+static cairo_bool_t
+_line_exceeds_16_16 (const cairo_line_t *line)
+{
+ return
+ line->p1.x <= CAIRO_FIXED_16_16_MIN ||
+ line->p1.x >= CAIRO_FIXED_16_16_MAX ||
+
+ line->p2.x <= CAIRO_FIXED_16_16_MIN ||
+ line->p2.x >= CAIRO_FIXED_16_16_MAX ||
+
+ line->p1.y <= CAIRO_FIXED_16_16_MIN ||
+ line->p1.y >= CAIRO_FIXED_16_16_MAX ||
+
+ line->p2.y <= CAIRO_FIXED_16_16_MIN ||
+ line->p2.y >= CAIRO_FIXED_16_16_MAX;
+}
+
+static void
+_project_line_x_onto_16_16 (const cairo_line_t *line,
+ cairo_fixed_t top,
+ cairo_fixed_t bottom,
+ xcb_render_linefix_t *out)
+{
+ cairo_point_double_t p1, p2;
+ double m;
+
+ p1.x = _cairo_fixed_to_double (line->p1.x);
+ p1.y = _cairo_fixed_to_double (line->p1.y);
+
+ p2.x = _cairo_fixed_to_double (line->p2.x);
+ p2.y = _cairo_fixed_to_double (line->p2.y);
+
+ m = (p2.x - p1.x) / (p2.y - p1.y);
+ out->p1.x = _cairo_fixed_16_16_from_double (p1.x + m * _cairo_fixed_to_double (top - line->p1.y));
+ out->p2.x = _cairo_fixed_16_16_from_double (p1.x + m * _cairo_fixed_to_double (bottom - line->p1.y));
+}
+
+typedef struct {
+ cairo_traps_t traps;
+ cairo_antialias_t antialias;
+} composite_traps_info_t;
+
+COMPILE_TIME_ASSERT (sizeof (xcb_render_trapezoid_t) <= sizeof (cairo_trapezoid_t));
+
+static cairo_status_t
+_composite_traps (void *closure,
+ cairo_xcb_surface_t *dst,
+ cairo_operator_t op,
+ const cairo_pattern_t *pattern,
+ int dst_x, int dst_y,
+ const cairo_rectangle_int_t *extents,
+ cairo_region_t *clip_region)
+{
+ composite_traps_info_t *info = closure;
+ const cairo_traps_t *traps = &info->traps;
+ cairo_xcb_picture_t *src;
+ cairo_format_t format;
+ xcb_render_pictformat_t xrender_format;
+ xcb_render_trapezoid_t *xtraps;
+ int render_reference_x, render_reference_y;
+ int i;
+
+ src = _cairo_xcb_picture_for_pattern (dst, pattern, extents);
+ if (unlikely (src->base.status))
+ return src->base.status;
+
+ if (info->antialias == CAIRO_ANTIALIAS_NONE)
+ format = CAIRO_FORMAT_A1;
+ else
+ format = CAIRO_FORMAT_A8;
+ xrender_format = dst->screen->connection->standard_formats[format];
+
+ xtraps = (xcb_render_trapezoid_t *) traps->traps;
+ for (i = 0; i < traps->num_traps; i++) {
+ cairo_trapezoid_t t = traps->traps[i];
+
+ /* top/bottom will be clamped to surface bounds */
+ xtraps[i].top = _cairo_fixed_to_16_16 (t.top);
+ xtraps[i].top -= dst_y << 16;
+ xtraps[i].bottom = _cairo_fixed_to_16_16 (t.bottom);
+ xtraps[i].bottom -= dst_y << 16;
+
+ /* However, all the other coordinates will have been left untouched so
+ * as not to introduce numerical error. Recompute them if they
+ * exceed the 16.16 limits.
+ */
+ if (unlikely (_line_exceeds_16_16 (&t.left))) {
+ _project_line_x_onto_16_16 (&t.left,
+ t.top,
+ t.bottom,
+ &xtraps[i].left);
+ xtraps[i].left.p1.y = xtraps[i].top;
+ xtraps[i].left.p2.y = xtraps[i].bottom;
+ } else {
+ xtraps[i].left.p1.x = _cairo_fixed_to_16_16 (t.left.p1.x);
+ xtraps[i].left.p1.y = _cairo_fixed_to_16_16 (t.left.p1.y);
+ xtraps[i].left.p2.x = _cairo_fixed_to_16_16 (t.left.p2.x);
+ xtraps[i].left.p2.y = _cairo_fixed_to_16_16 (t.left.p2.y);
+ }
+ xtraps[i].left.p1.x -= dst_x << 16;
+ xtraps[i].left.p1.y -= dst_y << 16;
+ xtraps[i].left.p2.x -= dst_x << 16;
+ xtraps[i].left.p2.y -= dst_y << 16;
+
+ if (unlikely (_line_exceeds_16_16 (&t.right))) {
+ _project_line_x_onto_16_16 (&t.right,
+ t.top,
+ t.bottom,
+ &xtraps[i].right);
+ xtraps[i].right.p1.y = xtraps[i].top;
+ xtraps[i].right.p2.y = xtraps[i].bottom;
+ } else {
+ xtraps[i].right.p1.x = _cairo_fixed_to_16_16 (t.right.p1.x);
+ xtraps[i].right.p1.y = _cairo_fixed_to_16_16 (t.right.p1.y);
+ xtraps[i].right.p2.x = _cairo_fixed_to_16_16 (t.right.p2.x);
+ xtraps[i].right.p2.y = _cairo_fixed_to_16_16 (t.right.p2.y);
+ }
+ xtraps[i].right.p1.x -= dst_x << 16;
+ xtraps[i].right.p1.y -= dst_y << 16;
+ xtraps[i].right.p2.x -= dst_x << 16;
+ xtraps[i].right.p2.y -= dst_y << 16;
+ }
+
+ if (xtraps[0].left.p1.y < xtraps[0].left.p2.y) {
+ render_reference_x = xtraps[0].left.p1.x >> 16;
+ render_reference_y = xtraps[0].left.p1.y >> 16;
+ } else {
+ render_reference_x = xtraps[0].left.p2.x >> 16;
+ render_reference_y = xtraps[0].left.p2.y >> 16;
+ }
+
+ _cairo_xcb_connection_render_trapezoids (dst->connection,
+ _render_operator (op),
+ src->picture,
+ dst->picture,
+ xrender_format,
+ src->x + render_reference_x,
+ src->y + render_reference_y,
+ traps->num_traps, xtraps);
+
+ cairo_surface_destroy (&src->base);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+/* low-level composite driver */
+
+typedef cairo_status_t
+(*xcb_draw_func_t) (void *closure,
+ cairo_xcb_surface_t *dst,
+ cairo_operator_t op,
+ const cairo_pattern_t *src,
+ int dst_x,
+ int dst_y,
+ const cairo_rectangle_int_t *extents,
+ cairo_region_t *clip_region);
+
+static cairo_xcb_surface_t *
+_create_composite_mask (cairo_clip_t *clip,
+ xcb_draw_func_t draw_func,
+ void *draw_closure,
+ cairo_xcb_surface_t *dst,
+ const cairo_rectangle_int_t*extents)
+{
+ cairo_xcb_surface_t *surface;
+ cairo_bool_t clip_surface = FALSE;
+ cairo_status_t status;
+
+ if (clip != NULL) {
+ cairo_region_t *clip_region;
+
+ status = _cairo_clip_get_region (clip, &clip_region);
+ assert (! _cairo_status_is_error (status));
+ clip_surface = status == CAIRO_INT_STATUS_UNSUPPORTED;
+ }
+
+ surface = (cairo_xcb_surface_t *)
+ _cairo_xcb_surface_create_similar (dst, CAIRO_CONTENT_ALPHA,
+ extents->width, extents->height);
+ if (unlikely (surface->base.status))
+ return surface;
+
+ _cairo_xcb_surface_ensure_picture (surface);
+
+ if (surface->flags & CAIRO_XCB_RENDER_HAS_FILL_RECTANGLES) {
+ xcb_render_color_t clear;
+ xcb_rectangle_t xrect;
+
+ clear.red = clear.green = clear.blue = clear.alpha = 0;
+
+ xrect.x = xrect.y = 0;
+ xrect.width = extents->width;
+ xrect.height = extents->height;
+
+ _cairo_xcb_connection_render_fill_rectangles (surface->connection,
+ XCB_RENDER_PICT_OP_CLEAR,
+ surface->picture,
+ clear, 1, &xrect);
+ } else {
+ status = _cairo_xcb_surface_render_paint (surface,
+ CAIRO_OPERATOR_CLEAR,
+ &_cairo_pattern_clear.base,
+ NULL);
+ if (unlikely (status)) {
+ cairo_surface_destroy (&surface->base);
+ return (cairo_xcb_surface_t *) _cairo_surface_create_in_error (status);
+ }
+ }
+
+ /* Is it worth setting the clip region here? */
+ status = draw_func (draw_closure, surface,
+ CAIRO_OPERATOR_ADD, NULL,
+ extents->x, extents->y,
+ extents, NULL);
+ if (unlikely (status)) {
+ cairo_surface_destroy (&surface->base);
+ return (cairo_xcb_surface_t *) _cairo_surface_create_in_error (status);
+ }
+
+ if (clip_surface) {
+ status = _cairo_clip_combine_with_surface (clip, &surface->base,
+ extents->x, extents->y);
+ if (unlikely (status)) {
+ cairo_surface_destroy (&surface->base);
+ return (cairo_xcb_surface_t *) _cairo_surface_create_in_error (status);
+ }
+ }
+
+ return surface;
+}
+
+/* Handles compositing with a clip surface when the operator allows
+ * us to combine the clip with the mask
+ */
+static cairo_status_t
+_clip_and_composite_with_mask (cairo_clip_t *clip,
+ cairo_operator_t op,
+ const cairo_pattern_t *pattern,
+ xcb_draw_func_t draw_func,
+ void *draw_closure,
+ cairo_xcb_surface_t *dst,
+ const cairo_rectangle_int_t*extents)
+{
+ cairo_xcb_surface_t *mask;
+ cairo_xcb_picture_t *src;
+
+ mask = _create_composite_mask (clip, draw_func, draw_closure, dst, extents);
+ if (unlikely (mask->base.status))
+ return mask->base.status;
+
+ if (pattern != NULL || dst->base.content != CAIRO_CONTENT_ALPHA) {
+ src = _cairo_xcb_picture_for_pattern (dst, pattern, extents);
+ if (unlikely (src->base.status)) {
+ cairo_surface_destroy (&mask->base);
+ return src->base.status;
+ }
+
+ _cairo_xcb_connection_render_composite (dst->connection,
+ _render_operator (op),
+ src->picture,
+ mask->picture,
+ dst->picture,
+ extents->x + src->x, extents->y + src->y,
+ 0, 0,
+ extents->x, extents->y,
+ extents->width, extents->height);
+
+ cairo_surface_destroy (&src->base);
+ } else {
+ _cairo_xcb_connection_render_composite (dst->connection,
+ _render_operator (op),
+ mask->picture,
+ XCB_NONE,
+ dst->picture,
+ 0, 0,
+ 0, 0,
+ extents->x, extents->y,
+ extents->width, extents->height);
+ }
+ cairo_surface_destroy (&mask->base);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+/* Handles compositing with a clip surface when we have to do the operation
+ * in two pieces and combine them together.
+ */
+static cairo_status_t
+_clip_and_composite_combine (cairo_clip_t *clip,
+ cairo_operator_t op,
+ const cairo_pattern_t *pattern,
+ xcb_draw_func_t draw_func,
+ void *draw_closure,
+ cairo_xcb_surface_t *dst,
+ const cairo_rectangle_int_t*extents)
+{
+ cairo_xcb_surface_t *tmp;
+ cairo_surface_t *clip_surface;
+ xcb_render_picture_t clip_picture;
+ cairo_status_t status;
+
+ tmp = (cairo_xcb_surface_t *)
+ _cairo_xcb_surface_create_similar (dst, dst->base.content,
+ extents->width, extents->height);
+ if (unlikely (tmp->base.status))
+ return tmp->base.status;
+
+ _cairo_xcb_surface_ensure_picture (tmp);
+
+ if (pattern == NULL) {
+ status = (*draw_func) (draw_closure, tmp,
+ CAIRO_OPERATOR_ADD, NULL,
+ extents->x, extents->y,
+ extents, NULL);
+ } else {
+ /* Initialize the temporary surface from the destination surface */
+ if (! dst->base.is_clear ||
+ (dst->flags & CAIRO_XCB_RENDER_HAS_FILL_RECTANGLES) == 0)
+ {
+ /* XCopyArea may actually be quicker here.
+ * A good driver should translate if appropriate.
+ */
+ _cairo_xcb_connection_render_composite (dst->connection,
+ XCB_RENDER_PICT_OP_SRC,
+ dst->picture,
+ XCB_NONE,
+ tmp->picture,
+ extents->x, extents->y,
+ 0, 0,
+ 0, 0,
+ extents->width, extents->height);
+ }
+ else
+ {
+ xcb_render_color_t clear;
+ xcb_rectangle_t xrect;
+
+ clear.red = clear.green = clear.blue = clear.alpha = 0;
+
+ xrect.x = xrect.y = 0;
+ xrect.width = extents->width;
+ xrect.height = extents->height;
+
+ _cairo_xcb_connection_render_fill_rectangles (dst->connection,
+ XCB_RENDER_PICT_OP_CLEAR,
+ dst->picture,
+ clear, 1, &xrect);
+ }
+
+ status = (*draw_func) (draw_closure, tmp, op, pattern,
+ extents->x, extents->y,
+ extents, NULL);
+ }
+ if (unlikely (status))
+ goto CLEANUP_SURFACE;
+
+ clip_surface = _cairo_clip_get_surface (clip, &dst->base);
+ if (unlikely (clip_surface->status))
+ goto CLEANUP_SURFACE;
+
+ clip_picture = ((cairo_xcb_surface_t *) clip_surface)->picture;
+ assert (clip_picture != XCB_NONE);
+
+ if (dst->base.is_clear) {
+ _cairo_xcb_connection_render_composite (dst->connection,
+ XCB_RENDER_PICT_OP_SRC,
+ tmp->picture, clip_picture, dst->picture,
+ 0, 0,
+ 0, 0,
+ extents->x, extents->y,
+ extents->width, extents->height);
+ } else {
+ /* Punch the clip out of the destination */
+ _cairo_xcb_connection_render_composite (dst->connection,
+ XCB_RENDER_PICT_OP_OUT_REVERSE,
+ clip_picture, XCB_NONE, dst->picture,
+ extents->x - clip->path->extents.x,
+ extents->y - clip->path->extents.y,
+ 0, 0,
+ extents->x, extents->y,
+ extents->width, extents->height);
+
+ /* Now add the two results together */
+ _cairo_xcb_connection_render_composite (dst->connection,
+ XCB_RENDER_PICT_OP_ADD,
+ tmp->picture, clip_picture, dst->picture,
+ 0, 0,
+ extents->x - clip->path->extents.x,
+ extents->y - clip->path->extents.y,
+ extents->x, extents->y,
+ extents->width, extents->height);
+ }
+
+ CLEANUP_SURFACE:
+ cairo_surface_destroy (&tmp->base);
+
+ return status;
+}
+
+/* Handles compositing for %CAIRO_OPERATOR_SOURCE, which is special; it's
+ * defined as (src IN mask IN clip) ADD (dst OUT (mask IN clip))
+ */
+static cairo_status_t
+_clip_and_composite_source (cairo_clip_t *clip,
+ const cairo_pattern_t *pattern,
+ xcb_draw_func_t draw_func,
+ void *draw_closure,
+ cairo_xcb_surface_t *dst,
+ const cairo_rectangle_int_t *extents)
+{
+ cairo_xcb_surface_t *mask;
+ cairo_xcb_picture_t *src;
+
+ /* Create a surface that is mask IN clip */
+ mask = _create_composite_mask (clip, draw_func, draw_closure, dst, extents);
+ if (unlikely (mask->base.status))
+ return mask->base.status;
+
+ src = _cairo_xcb_picture_for_pattern (dst, pattern, extents);
+ if (unlikely (src->base.status)) {
+ cairo_surface_destroy (&mask->base);
+ return src->base.status;
+ }
+
+ if (dst->base.is_clear) {
+ _cairo_xcb_connection_render_composite (dst->connection,
+ XCB_RENDER_PICT_OP_SRC,
+ src->picture,
+ mask->picture,
+ dst->picture,
+ extents->x + src->x, extents->y + src->y,
+ 0, 0,
+ extents->x, extents->y,
+ extents->width, extents->height);
+ } else {
+ /* Compute dest' = dest OUT (mask IN clip) */
+ _cairo_xcb_connection_render_composite (dst->connection,
+ XCB_RENDER_PICT_OP_OUT_REVERSE,
+ mask->picture,
+ XCB_NONE,
+ dst->picture,
+ 0, 0, 0, 0,
+ extents->x, extents->y,
+ extents->width, extents->height);
+
+ /* Now compute (src IN (mask IN clip)) ADD dest' */
+ _cairo_xcb_connection_render_composite (dst->connection,
+ XCB_RENDER_PICT_OP_ADD,
+ src->picture,
+ mask->picture,
+ dst->picture,
+ extents->x + src->x, extents->y + src->y,
+ 0, 0,
+ extents->x, extents->y,
+ extents->width, extents->height);
+ }
+
+ cairo_surface_destroy (&src->base);
+ cairo_surface_destroy (&mask->base);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_bool_t
+can_reduce_alpha_op (cairo_operator_t op)
+{
+ int iop = op;
+ switch (iop) {
+ case CAIRO_OPERATOR_OVER:
+ case CAIRO_OPERATOR_SOURCE:
+ case CAIRO_OPERATOR_ADD:
+ return TRUE;
+ default:
+ return FALSE;
+ }
+}
+
+static cairo_bool_t
+reduce_alpha_op (cairo_surface_t *dst,
+ cairo_operator_t op,
+ const cairo_pattern_t *pattern)
+{
+ return dst->is_clear &&
+ dst->content == CAIRO_CONTENT_ALPHA &&
+ _cairo_pattern_is_opaque_solid (pattern) &&
+ can_reduce_alpha_op (op);
+}
+
+static cairo_status_t
+_cairo_xcb_surface_fixup_unbounded (cairo_xcb_surface_t *dst,
+ const cairo_composite_rectangles_t *rects)
+{
+ xcb_rectangle_t xrects[4];
+ int n;
+
+ if (rects->bounded.width == rects->unbounded.width &&
+ rects->bounded.height == rects->unbounded.height)
+ {
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+ n = 0;
+ /* top */
+ if (rects->bounded.y != rects->unbounded.y) {
+ xrects[n].x = rects->unbounded.x;
+ xrects[n].width = rects->unbounded.width;
+ xrects[n].y = rects->unbounded.y;
+ xrects[n].height = rects->bounded.y - rects->unbounded.y;
+ n++;
+ }
+ /* left */
+ if (rects->bounded.x != rects->unbounded.x) {
+ xrects[n].x = rects->unbounded.x;
+ xrects[n].width = rects->bounded.x - rects->unbounded.x;
+ xrects[n].y = rects->bounded.y;
+ xrects[n].height = rects->bounded.height;
+ n++;
+ }
+ /* right */
+ if (rects->bounded.x + rects->bounded.width != rects->unbounded.x + rects->unbounded.width) {
+ xrects[n].x = rects->bounded.x + rects->bounded.width;
+ xrects[n].width = rects->unbounded.x + rects->unbounded.width - xrects[n].x;
+ xrects[n].y = rects->bounded.y;
+ xrects[n].height = rects->bounded.height;
+ n++;
+ }
+ /* bottom */
+ if (rects->bounded.y + rects->bounded.height != rects->unbounded.y + rects->unbounded.height) {
+ xrects[n].x = rects->unbounded.x;
+ xrects[n].width = rects->unbounded.width;
+ xrects[n].y = rects->bounded.y + rects->bounded.height;
+ xrects[n].height = rects->unbounded.y + rects->unbounded.height - xrects[n].y;
+ n++;
+ }
+
+ if (dst->flags & CAIRO_XCB_RENDER_HAS_FILL_RECTANGLES) {
+ xcb_render_color_t color;
+
+ color.red = 0;
+ color.green = 0;
+ color.blue = 0;
+ color.alpha = 0;
+
+ _cairo_xcb_connection_render_fill_rectangles (dst->connection,
+ XCB_RENDER_PICT_OP_CLEAR,
+ dst->picture,
+ color, n, xrects);
+ } else {
+ int i;
+ cairo_xcb_picture_t *src;
+
+ src = _cairo_xcb_transparent_picture (dst);
+ if (unlikely (src->base.status))
+ return src->base.status;
+
+ for (i = 0; i < n; i++) {
+ _cairo_xcb_connection_render_composite (dst->connection,
+ XCB_RENDER_PICT_OP_CLEAR,
+ src->picture, XCB_NONE, dst->picture,
+ 0, 0,
+ 0, 0,
+ xrects[i].x, xrects[i].y,
+ xrects[i].width, xrects[i].height);
+ }
+ cairo_surface_destroy (&src->base);
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_xcb_surface_fixup_unbounded_with_mask (cairo_xcb_surface_t *dst,
+ const cairo_composite_rectangles_t *rects,
+ cairo_clip_t *clip)
+{
+ cairo_xcb_surface_t *mask;
+ int mask_x, mask_y;
+
+ mask = (cairo_xcb_surface_t *) _cairo_clip_get_surface (clip, &dst->base);
+ if (unlikely (mask->base.status))
+ return mask->base.status;
+
+ mask_x = - clip->path->extents.x;
+ mask_y = - clip->path->extents.y;
+
+ /* top */
+ if (rects->bounded.y != rects->unbounded.y) {
+ int x = rects->unbounded.x;
+ int y = rects->unbounded.y;
+ int width = rects->unbounded.width;
+ int height = rects->bounded.y - y;
+
+ _cairo_xcb_connection_render_composite (dst->connection,
+ XCB_RENDER_PICT_OP_OUT_REVERSE,
+ mask->picture, XCB_NONE, dst->picture,
+ x + mask_x, y + mask_y,
+ 0, 0,
+ x, y,
+ width, height);
+ }
+
+ /* left */
+ if (rects->bounded.x != rects->unbounded.x) {
+ int x = rects->unbounded.x;
+ int y = rects->bounded.y;
+ int width = rects->bounded.x - x;
+ int height = rects->bounded.height;
+
+ _cairo_xcb_connection_render_composite (dst->connection,
+ XCB_RENDER_PICT_OP_OUT_REVERSE,
+ mask->picture, XCB_NONE, dst->picture,
+ x + mask_x, y + mask_y,
+ 0, 0,
+ x, y,
+ width, height);
+ }
+
+ /* right */
+ if (rects->bounded.x + rects->bounded.width != rects->unbounded.x + rects->unbounded.width) {
+ int x = rects->bounded.x + rects->bounded.width;
+ int y = rects->bounded.y;
+ int width = rects->unbounded.x + rects->unbounded.width - x;
+ int height = rects->bounded.height;
+
+ _cairo_xcb_connection_render_composite (dst->connection,
+ XCB_RENDER_PICT_OP_OUT_REVERSE,
+ mask->picture, XCB_NONE, dst->picture,
+ x + mask_x, y + mask_y,
+ 0, 0,
+ x, y,
+ width, height);
+ }
+
+ /* bottom */
+ if (rects->bounded.y + rects->bounded.height != rects->unbounded.y + rects->unbounded.height) {
+ int x = rects->unbounded.x;
+ int y = rects->bounded.y + rects->bounded.height;
+ int width = rects->unbounded.width;
+ int height = rects->unbounded.y + rects->unbounded.height - y;
+
+ _cairo_xcb_connection_render_composite (dst->connection,
+ XCB_RENDER_PICT_OP_OUT_REVERSE,
+ mask->picture, XCB_NONE, dst->picture,
+ x + mask_x, y + mask_y,
+ 0, 0,
+ x, y,
+ width, height);
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_xcb_surface_fixup_unbounded_boxes (cairo_xcb_surface_t *dst,
+ const cairo_composite_rectangles_t *extents,
+ cairo_region_t *clip_region,
+ cairo_boxes_t *boxes)
+{
+ cairo_boxes_t clear;
+ cairo_box_t box;
+ cairo_status_t status;
+ struct _cairo_boxes_chunk *chunk;
+ int i;
+
+ if (boxes->num_boxes <= 1 && clip_region == NULL)
+ return _cairo_xcb_surface_fixup_unbounded (dst, extents);
+
+ _cairo_boxes_init (&clear);
+
+ box.p1.x = _cairo_fixed_from_int (extents->unbounded.x + extents->unbounded.width);
+ box.p1.y = _cairo_fixed_from_int (extents->unbounded.y);
+ box.p2.x = _cairo_fixed_from_int (extents->unbounded.x);
+ box.p2.y = _cairo_fixed_from_int (extents->unbounded.y + extents->unbounded.height);
+
+ if (clip_region == NULL) {
+ cairo_boxes_t tmp;
+
+ _cairo_boxes_init (&tmp);
+
+ status = _cairo_boxes_add (&tmp, &box);
+ assert (status == CAIRO_STATUS_SUCCESS);
+
+ tmp.chunks.next = &boxes->chunks;
+ tmp.num_boxes += boxes->num_boxes;
+
+ status = _cairo_bentley_ottmann_tessellate_boxes (&tmp,
+ CAIRO_FILL_RULE_WINDING,
+ &clear);
+
+ tmp.chunks.next = NULL;
+ } else {
+ pixman_box32_t *pbox;
+
+ pbox = pixman_region32_rectangles (&clip_region->rgn, &i);
+ _cairo_boxes_limit (&clear, (cairo_box_t *) pbox, i);
+
+ status = _cairo_boxes_add (&clear, &box);
+ assert (status == CAIRO_STATUS_SUCCESS);
+
+ for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
+ for (i = 0; i < chunk->count; i++) {
+ status = _cairo_boxes_add (&clear, &chunk->base[i]);
+ if (unlikely (status)) {
+ _cairo_boxes_fini (&clear);
+ return status;
+ }
+ }
+ }
+
+ status = _cairo_bentley_ottmann_tessellate_boxes (&clear,
+ CAIRO_FILL_RULE_WINDING,
+ &clear);
+ }
+
+ if (likely (status == CAIRO_STATUS_SUCCESS)) {
+ status = _render_fill_boxes (dst,
+ CAIRO_OPERATOR_CLEAR,
+ CAIRO_COLOR_TRANSPARENT,
+ boxes);
+ }
+
+ _cairo_boxes_fini (&clear);
+
+ return status;
+}
+
+static cairo_status_t
+_clip_and_composite (cairo_xcb_surface_t *dst,
+ cairo_operator_t op,
+ const cairo_pattern_t *src,
+ xcb_draw_func_t draw_func,
+ void *draw_closure,
+ const cairo_composite_rectangles_t*extents,
+ cairo_clip_t *clip)
+{
+ cairo_status_t status;
+ cairo_region_t *clip_region = NULL;
+ cairo_bool_t need_clip_surface = FALSE;
+
+ if (clip != NULL) {
+ status = _cairo_clip_get_region (clip, &clip_region);
+ if (unlikely (status == CAIRO_INT_STATUS_NOTHING_TO_DO))
+ return CAIRO_STATUS_SUCCESS;
+
+ assert (! _cairo_status_is_error (status));
+ need_clip_surface = status == CAIRO_INT_STATUS_UNSUPPORTED;
+
+ if (clip_region != NULL && cairo_region_num_rectangles (clip_region) == 1)
+ clip_region = NULL;
+ }
+
+ status = _cairo_xcb_connection_acquire (dst->connection);
+ if (unlikely (status))
+ return status;
+
+ status = _cairo_xcb_connection_take_socket (dst->connection);
+ if (unlikely (status)) {
+ _cairo_xcb_connection_release (dst->connection);
+ return status;
+ }
+
+ _cairo_xcb_surface_ensure_picture (dst);
+
+ if (clip_region != NULL)
+ _cairo_xcb_surface_set_clip_region (dst, clip_region);
+
+ if (reduce_alpha_op (&dst->base, op, src)) {
+ op = CAIRO_OPERATOR_ADD;
+ src = NULL;
+ }
+
+ if (op == CAIRO_OPERATOR_SOURCE) {
+ status = _clip_and_composite_source (clip, src,
+ draw_func, draw_closure,
+ dst, &extents->bounded);
+ } else {
+ if (op == CAIRO_OPERATOR_CLEAR) {
+ op = CAIRO_OPERATOR_DEST_OUT;
+ src = NULL;
+ }
+
+ if (need_clip_surface) {
+ if (extents->is_bounded) {
+ status = _clip_and_composite_with_mask (clip, op, src,
+ draw_func, draw_closure,
+ dst, &extents->bounded);
+ } else {
+ status = _clip_and_composite_combine (clip, op, src,
+ draw_func, draw_closure,
+ dst, &extents->bounded);
+ }
+ } else {
+ status = draw_func (draw_closure,
+ dst, op, src,
+ 0, 0,
+ &extents->bounded,
+ clip_region);
+ }
+ }
+
+ if (status == CAIRO_STATUS_SUCCESS && ! extents->is_bounded) {
+ if (need_clip_surface)
+ status = _cairo_xcb_surface_fixup_unbounded_with_mask (dst, extents, clip);
+ else
+ status = _cairo_xcb_surface_fixup_unbounded (dst, extents);
+ }
+
+ if (clip_region != NULL)
+ _cairo_xcb_surface_clear_clip_region (dst);
+
+ _cairo_xcb_connection_release (dst->connection);
+
+ return status;
+}
+
+static cairo_status_t
+_core_boxes (cairo_xcb_surface_t *dst,
+ cairo_operator_t op,
+ const cairo_pattern_t *src,
+ cairo_boxes_t *boxes,
+ cairo_antialias_t antialias,
+ cairo_clip_t *clip,
+ const cairo_composite_rectangles_t *extents)
+{
+ if (antialias != CAIRO_ANTIALIAS_NONE) {
+ if (! boxes->is_pixel_aligned)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ }
+
+ if (clip != NULL) {
+ cairo_region_t *clip_region;
+ cairo_status_t status;
+
+ status = _cairo_clip_get_region (clip, &clip_region);
+ assert (status == CAIRO_STATUS_SUCCESS || CAIRO_INT_STATUS_UNSUPPORTED);
+
+ if (status == CAIRO_INT_STATUS_UNSUPPORTED)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ }
+
+ if (op == CAIRO_OPERATOR_CLEAR)
+ return _cairo_xcb_surface_core_fill_boxes (dst, CAIRO_COLOR_TRANSPARENT, boxes);
+
+ if (op == CAIRO_OPERATOR_OVER) {
+ if (_cairo_pattern_is_opaque (src, &extents->bounded))
+ op = CAIRO_OPERATOR_SOURCE;
+ }
+ if (op != CAIRO_OPERATOR_SOURCE)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ if (src->type == CAIRO_PATTERN_TYPE_SOLID) {
+ return _cairo_xcb_surface_core_fill_boxes (dst,
+ &((cairo_solid_pattern_t *) src)->color,
+ boxes);
+ }
+
+ return _cairo_xcb_surface_core_copy_boxes (dst, src, &extents->bounded, boxes);
+}
+
+static cairo_status_t
+_composite_boxes (cairo_xcb_surface_t *dst,
+ cairo_operator_t op,
+ const cairo_pattern_t *src,
+ cairo_boxes_t *boxes,
+ cairo_antialias_t antialias,
+ cairo_clip_t *clip,
+ const cairo_composite_rectangles_t *extents)
+{
+ cairo_bool_t need_clip_mask = FALSE;
+ cairo_region_t *clip_region = NULL;
+ cairo_status_t status;
+
+ /* If the boxes are not pixel-aligned, we will need to compute a real mask */
+ if (antialias != CAIRO_ANTIALIAS_NONE) {
+ if (! boxes->is_pixel_aligned)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ }
+
+ if (clip != NULL) {
+ status = _cairo_clip_get_region (clip, &clip_region);
+ assert (status == CAIRO_STATUS_SUCCESS || CAIRO_INT_STATUS_UNSUPPORTED);
+
+ need_clip_mask = status == CAIRO_INT_STATUS_UNSUPPORTED;
+ if (need_clip_mask &&
+ (! extents->is_bounded || op == CAIRO_OPERATOR_SOURCE))
+ {
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ }
+
+ if (clip_region != NULL && cairo_region_num_rectangles (clip_region) == 1)
+ clip_region = NULL;
+ }
+
+ status = _cairo_xcb_connection_acquire (dst->connection);
+ if (unlikely (status))
+ return status;
+
+ status = _cairo_xcb_connection_take_socket (dst->connection);
+ if (unlikely (status)) {
+ _cairo_xcb_connection_release (dst->connection);
+ return status;
+ }
+
+ _cairo_xcb_surface_ensure_picture (dst);
+ if (dst->flags & CAIRO_XCB_RENDER_HAS_FILL_RECTANGLES && ! need_clip_mask &&
+ (op == CAIRO_OPERATOR_CLEAR || src->type == CAIRO_PATTERN_TYPE_SOLID))
+ {
+ const cairo_color_t *color;
+
+ if (op == CAIRO_OPERATOR_CLEAR)
+ color = CAIRO_COLOR_TRANSPARENT;
+ else
+ color = &((cairo_solid_pattern_t *) src)->color;
+
+ if (! (op == CAIRO_OPERATOR_IN && color->alpha >= 0xff00))
+ status = _render_fill_boxes (dst, op, color, boxes);
+ }
+ else
+ {
+ cairo_surface_pattern_t mask;
+
+ if (need_clip_mask) {
+ cairo_surface_t *clip_surface;
+
+ clip_surface = _cairo_clip_get_surface (clip, &dst->base);
+ if (unlikely (clip_surface->status))
+ return clip_surface->status;
+
+ _cairo_pattern_init_for_surface (&mask, clip_surface);
+ mask.base.filter = CAIRO_FILTER_NEAREST;
+ cairo_matrix_init_translate (&mask.base.matrix,
+ -clip->path->extents.x,
+ -clip->path->extents.y);
+
+ if (op == CAIRO_OPERATOR_CLEAR) {
+ src = NULL;
+ op = CAIRO_OPERATOR_DEST_OUT;
+ }
+ }
+
+ status = _render_composite_boxes (dst, op, src,
+ need_clip_mask ? &mask.base : NULL,
+ &extents->bounded, boxes);
+ }
+
+ if (status == CAIRO_STATUS_SUCCESS && ! extents->is_bounded) {
+ status =
+ _cairo_xcb_surface_fixup_unbounded_boxes (dst, extents,
+ clip_region, boxes);
+ }
+
+ _cairo_xcb_connection_release (dst->connection);
+
+ return status;
+}
+
+static cairo_status_t
+_clip_and_composite_boxes (cairo_xcb_surface_t *dst,
+ cairo_operator_t op,
+ const cairo_pattern_t *src,
+ cairo_boxes_t *boxes,
+ cairo_antialias_t antialias,
+ const cairo_composite_rectangles_t *extents,
+ cairo_clip_t *clip)
+{
+ composite_traps_info_t info;
+ cairo_status_t status;
+
+ if (boxes->num_boxes == 0 && extents->is_bounded)
+ return CAIRO_STATUS_SUCCESS;
+
+ if ((dst->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE) == 0)
+ return _core_boxes (dst, op, src, boxes, antialias, clip, extents);
+
+ /* Use a fast path if the boxes are pixel aligned */
+ status = _composite_boxes (dst, op, src, boxes, antialias, clip, extents);
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+ return status;
+
+ if ((dst->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE_TRAPEZOIDS) == 0)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ /* Otherwise render via a mask and composite in the usual fashion. */
+ status = _cairo_traps_init_boxes (&info.traps, boxes);
+ if (unlikely (status))
+ return status;
+
+ info.antialias = antialias;
+ return _clip_and_composite (dst, op, src,
+ _composite_traps, &info,
+ extents, clip);
+}
+
+static cairo_bool_t
+_mono_edge_is_vertical (const cairo_line_t *line)
+{
+ return _cairo_fixed_integer_round (line->p1.x) == _cairo_fixed_integer_round (line->p2.x);
+}
+
+static cairo_bool_t
+_traps_are_pixel_aligned (cairo_traps_t *traps,
+ cairo_antialias_t antialias)
+{
+ int i;
+
+ if (antialias == CAIRO_ANTIALIAS_NONE) {
+ for (i = 0; i < traps->num_traps; i++) {
+ if (! _mono_edge_is_vertical (&traps->traps[i].left) ||
+ ! _mono_edge_is_vertical (&traps->traps[i].right))
+ {
+ traps->maybe_region = FALSE;
+ return FALSE;
+ }
+ }
+ } else {
+ for (i = 0; i < traps->num_traps; i++) {
+ if (traps->traps[i].left.p1.x != traps->traps[i].left.p2.x ||
+ traps->traps[i].right.p1.x != traps->traps[i].right.p2.x ||
+ ! _cairo_fixed_is_integer (traps->traps[i].top) ||
+ ! _cairo_fixed_is_integer (traps->traps[i].bottom) ||
+ ! _cairo_fixed_is_integer (traps->traps[i].left.p1.x) ||
+ ! _cairo_fixed_is_integer (traps->traps[i].right.p1.x))
+ {
+ traps->maybe_region = FALSE;
+ return FALSE;
+ }
+ }
+ }
+
+ return TRUE;
+}
+
+static void
+_boxes_for_traps (cairo_boxes_t *boxes,
+ cairo_traps_t *traps)
+{
+ int i;
+
+ _cairo_boxes_init (boxes);
+
+ boxes->num_boxes = traps->num_traps;
+ boxes->chunks.base = (cairo_box_t *) traps->traps;
+ boxes->chunks.count = traps->num_traps;
+ boxes->chunks.size = traps->num_traps;
+
+ for (i = 0; i < traps->num_traps; i++) {
+ cairo_fixed_t x1 = traps->traps[i].left.p1.x;
+ cairo_fixed_t x2 = traps->traps[i].right.p1.x;
+ cairo_fixed_t y1 = traps->traps[i].top;
+ cairo_fixed_t y2 = traps->traps[i].bottom;
+
+ boxes->chunks.base[i].p1.x = x1;
+ boxes->chunks.base[i].p1.y = y1;
+ boxes->chunks.base[i].p2.x = x2;
+ boxes->chunks.base[i].p2.y = y2;
+
+ if (boxes->is_pixel_aligned) {
+ boxes->is_pixel_aligned =
+ _cairo_fixed_is_integer (x1) && _cairo_fixed_is_integer (y1) &&
+ _cairo_fixed_is_integer (x2) && _cairo_fixed_is_integer (y2);
+ }
+ }
+}
+
+typedef struct _cairo_xcb_surface_span_renderer {
+ cairo_span_renderer_t base;
+
+ void *spans;
+ unsigned len;
+ unsigned size;
+ uint16_t spans_embedded[1024];
+} cairo_xcb_surface_span_renderer_t;
+
+static cairo_status_t
+_cairo_xcb_surface_span_renderer_accumulate (void *abstract_renderer,
+ int y,
+ int height,
+ const cairo_half_open_span_t *spans,
+ unsigned num_spans)
+{
+ cairo_xcb_surface_span_renderer_t *renderer = abstract_renderer;
+ uint16_t *u16;
+ int len;
+
+ len = 4 * (2 + num_spans);
+ if (renderer->size < renderer->len + len) {
+ char *new_spans;
+
+ do {
+ renderer->size <<= 1;
+ } while (renderer->size < renderer->len + len);
+
+ if (renderer->spans == renderer->spans_embedded) {
+ new_spans = malloc (renderer->size);
+ if (unlikely (new_spans == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+ memcpy (new_spans, renderer->spans, renderer->len);
+ } else {
+ new_spans = realloc (renderer->spans, renderer->size);
+ if (unlikely (new_spans == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ }
+
+ renderer->spans = new_spans;
+ }
+
+ u16 = (uint16_t *) ((char *) renderer->spans + renderer->len);
+ *u16++ = y;
+ *u16++ = height;
+ *u16++ = num_spans;
+ *u16++ = 0;
+ while (num_spans--) {
+ *u16++ = spans->x;
+ *u16++ = spans->coverage * 0x0101;
+ spans++;
+ }
+ renderer->len += len;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+typedef struct {
+ cairo_polygon_t *polygon;
+ cairo_fill_rule_t fill_rule;
+ cairo_antialias_t antialias;
+} composite_spans_info_t;
+
+static cairo_status_t
+_composite_spans (void *closure,
+ cairo_xcb_surface_t *dst,
+ cairo_operator_t op,
+ const cairo_pattern_t *pattern,
+ int dst_x,
+ int dst_y,
+ const cairo_rectangle_int_t *extents,
+ cairo_region_t *clip_region)
+{
+ composite_spans_info_t *info = closure;
+ cairo_xcb_surface_span_renderer_t renderer;
+ cairo_scan_converter_t *converter;
+ cairo_status_t status;
+ cairo_xcb_picture_t *src;
+
+ renderer.base.render_rows = _cairo_xcb_surface_span_renderer_accumulate;
+ renderer.spans = renderer.spans_embedded;
+ renderer.size = ARRAY_LENGTH (renderer.spans_embedded);
+ renderer.len = 0;
+
+ converter = _cairo_tor_scan_converter_create (extents->x,
+ extents->x + extents->width,
+ extents->y,
+ extents->y + extents->height,
+ info->fill_rule);
+ status = converter->add_polygon (converter, info->polygon);
+ if (unlikely (status))
+ goto CLEANUP_RENDERER;
+
+ status = converter->generate (converter, &renderer.base);
+ if (unlikely (status))
+ goto CLEANUP_CONVERTER;
+
+ src = _cairo_xcb_picture_for_pattern (dst, pattern, extents);
+ status = src->base.status;
+ if (unlikely (status))
+ goto CLEANUP_CONVERTER;
+
+ _cairo_xcb_connection_render_spans (dst->connection,
+ dst->picture,
+ _render_operator (op),
+ src->picture,
+ extents->x + src->x, extents->y + src->y,
+ extents->x + dst_x, extents->y + dst_y,
+ extents->width, extents->height,
+ renderer.len >> 1, renderer.spans);
+ cairo_surface_destroy (&src->base);
+
+ CLEANUP_CONVERTER:
+ converter->destroy (converter);
+ CLEANUP_RENDERER:
+ if (renderer.spans != renderer.spans_embedded)
+ free (renderer.spans);
+
+ return status;
+}
+
+static cairo_status_t
+_composite_mask (void *closure,
+ cairo_xcb_surface_t *dst,
+ cairo_operator_t op,
+ const cairo_pattern_t *src_pattern,
+ int dst_x,
+ int dst_y,
+ const cairo_rectangle_int_t *extents,
+ cairo_region_t *clip_region)
+{
+ const cairo_pattern_t *mask_pattern = closure;
+ cairo_xcb_picture_t *src, *mask = NULL;
+
+ if (src_pattern != NULL) {
+ src = _cairo_xcb_picture_for_pattern (dst, src_pattern, extents);
+ if (unlikely (src->base.status))
+ return src->base.status;
+
+ mask = _cairo_xcb_picture_for_pattern (dst, mask_pattern, extents);
+ if (unlikely (mask->base.status)) {
+ cairo_surface_destroy (&src->base);
+ return mask->base.status;
+ }
+
+ _cairo_xcb_connection_render_composite (dst->connection,
+ _render_operator (op),
+ src->picture,
+ mask->picture,
+ dst->picture,
+ extents->x + src->x, extents->y + src->y,
+ extents->x + mask->x, extents->y + mask->y,
+ extents->x - dst_x, extents->y - dst_y,
+ extents->width, extents->height);
+ cairo_surface_destroy (&mask->base);
+ cairo_surface_destroy (&src->base);
+ } else {
+ src = _cairo_xcb_picture_for_pattern (dst, mask_pattern, extents);
+ if (unlikely (src->base.status))
+ return src->base.status;
+
+ _cairo_xcb_connection_render_composite (dst->connection,
+ _render_operator (op),
+ src->picture,
+ XCB_NONE,
+ dst->picture,
+ extents->x + src->x, extents->y + src->y,
+ 0, 0,
+ extents->x - dst_x, extents->y - dst_y,
+ extents->width, extents->height);
+ cairo_surface_destroy (&src->base);
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+/* high level rasteriser -> compositor */
+
+static cairo_bool_t
+box_is_aligned (const cairo_box_t *box)
+{
+ return
+ _cairo_fixed_is_integer (box->p1.x) &&
+ _cairo_fixed_is_integer (box->p1.y) &&
+ _cairo_fixed_is_integer (box->p2.x) &&
+ _cairo_fixed_is_integer (box->p2.y);
+}
+
+static inline cairo_status_t
+_clip_to_boxes (cairo_clip_t **clip,
+ const cairo_composite_rectangles_t *extents,
+ cairo_box_t **boxes,
+ int *num_boxes)
+{
+ cairo_status_t status;
+ const cairo_rectangle_int_t *rect;
+
+ rect = extents->is_bounded ? &extents->bounded: &extents->unbounded;
+
+ if (*clip == NULL)
+ goto EXTENTS;
+
+ status = _cairo_clip_rectangle (*clip, rect);
+ if (unlikely (status))
+ return status;
+
+ status = _cairo_clip_get_boxes (*clip, boxes, num_boxes);
+ switch ((int) status) {
+ case CAIRO_STATUS_SUCCESS:
+ if (extents->is_bounded || (*num_boxes == 1 && box_is_aligned (*boxes)))
+ *clip = NULL;
+ goto DONE;
+
+ case CAIRO_INT_STATUS_UNSUPPORTED:
+ goto EXTENTS;
+
+ default:
+ return status;
+ }
+
+ EXTENTS:
+ status = CAIRO_STATUS_SUCCESS;
+ _cairo_box_from_rectangle (&(*boxes)[0], rect);
+ *num_boxes = 1;
+ DONE:
+ return status;
+}
+
+static cairo_clip_path_t *
+_clip_get_single_path (cairo_clip_t *clip)
+{
+ cairo_clip_path_t *iter = clip->path;
+ cairo_clip_path_t *path = NULL;
+
+ do {
+ if ((iter->flags & CAIRO_CLIP_PATH_IS_BOX) == 0) {
+ if (path != NULL)
+ return FALSE;
+
+ path = iter;
+ }
+ iter = iter->prev;
+ } while (iter != NULL);
+
+ return path;
+}
+
+cairo_int_status_t
+_cairo_xcb_surface_render_paint (cairo_xcb_surface_t *surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_clip_t *clip)
+{
+ cairo_composite_rectangles_t extents;
+ cairo_boxes_t boxes;
+ cairo_box_t *clip_boxes = boxes.boxes_embedded;
+ cairo_clip_t local_clip;
+ cairo_clip_path_t *clip_path;
+ cairo_bool_t have_clip = FALSE;
+ int num_boxes = ARRAY_LENGTH (boxes.boxes_embedded);
+ cairo_status_t status;
+
+ if (unlikely (! _operator_is_supported (surface->flags, op)))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ if ((surface->flags & (CAIRO_XCB_RENDER_HAS_COMPOSITE_SPANS |
+ CAIRO_XCB_RENDER_HAS_COMPOSITE_TRAPEZOIDS |
+ CAIRO_XCB_RENDER_HAS_COMPOSITE)) == 0)
+ {
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ }
+
+ status = _cairo_composite_rectangles_init_for_paint (&extents,
+ surface->width,
+ surface->height,
+ op, source,
+ clip);
+ if (unlikely (status))
+ return status;
+
+ if (_cairo_clip_contains_rectangle (clip, &extents))
+ clip = NULL;
+
+ if (clip != NULL) {
+ clip = _cairo_clip_init_copy (&local_clip, clip);
+ have_clip = TRUE;
+ }
+
+ status = _clip_to_boxes (&clip, &extents, &clip_boxes, &num_boxes);
+ if (unlikely (status)) {
+ if (have_clip)
+ _cairo_clip_fini (&local_clip);
+
+ return status;
+ }
+
+ if (clip != NULL &&
+ extents.is_bounded &&
+ (clip_path = _clip_get_single_path (clip)) != NULL)
+ {
+ status = _cairo_xcb_surface_render_fill (surface, op, source,
+ &clip_path->path,
+ clip_path->fill_rule,
+ clip_path->tolerance,
+ clip_path->antialias,
+ NULL);
+ }
+ else
+ {
+ _cairo_boxes_init_for_array (&boxes, clip_boxes, num_boxes);
+ status = _clip_and_composite_boxes (surface, op, source,
+ &boxes, CAIRO_ANTIALIAS_DEFAULT,
+ &extents, clip);
+ if (clip_boxes != boxes.boxes_embedded)
+ free (clip_boxes);
+ }
+
+ if (have_clip)
+ _cairo_clip_fini (&local_clip);
+
+ return status;
+}
+
+cairo_int_status_t
+_cairo_xcb_surface_render_mask (cairo_xcb_surface_t *surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ const cairo_pattern_t *mask,
+ cairo_clip_t *clip)
+{
+ cairo_composite_rectangles_t extents;
+ cairo_clip_t local_clip;
+ cairo_bool_t have_clip = FALSE;
+ cairo_status_t status;
+
+ if (unlikely (! _operator_is_supported (surface->flags, op)))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ if ((surface->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE) == 0)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ status = _cairo_composite_rectangles_init_for_mask (&extents,
+ surface->width, surface->height,
+ op, source, mask, clip);
+ if (unlikely (status))
+ return status;
+
+ if (_cairo_clip_contains_rectangle (clip, &extents))
+ clip = NULL;
+
+ if (clip != NULL && extents.is_bounded) {
+ clip = _cairo_clip_init_copy (&local_clip, clip);
+ status = _cairo_clip_rectangle (clip, &extents.bounded);
+ if (unlikely (status)) {
+ _cairo_clip_fini (&local_clip);
+ return status;
+ }
+ have_clip = TRUE;
+ }
+
+ status = _clip_and_composite (surface, op, source,
+ _composite_mask, (void *) mask,
+ &extents, clip);
+
+ if (have_clip)
+ _cairo_clip_fini (&local_clip);
+
+ return status;
+}
+
+typedef struct {
+ cairo_polygon_t polygon;
+ cairo_fill_rule_t fill_rule;
+ cairo_antialias_t antialias;
+} composite_polygon_info_t;
+
+static cairo_status_t
+_cairo_xcb_surface_render_composite_polygon (cairo_xcb_surface_t *dst,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_polygon_t *polygon,
+ cairo_antialias_t antialias,
+ cairo_fill_rule_t fill_rule,
+ cairo_composite_rectangles_t *extents,
+ cairo_clip_t *clip)
+{
+ composite_traps_info_t traps;
+ cairo_bool_t clip_surface = FALSE;
+ cairo_status_t status;
+ cairo_bool_t is_not_empty;
+
+ if (polygon->num_edges == 0) {
+ status = CAIRO_STATUS_SUCCESS;
+
+ if (! extents->is_bounded) {
+ cairo_region_t *clip_region = NULL;
+
+ if (clip != NULL) {
+ status = _cairo_clip_get_region (clip, &clip_region);
+ clip_surface = status == CAIRO_INT_STATUS_UNSUPPORTED;
+
+ if (clip_region != NULL && cairo_region_num_rectangles (clip_region) == 1)
+ clip_region = NULL;
+ }
+
+ if (clip_surface == FALSE) {
+ if (clip_region != NULL)
+ _cairo_xcb_surface_set_clip_region (dst, clip_region);
+
+ status = _cairo_xcb_surface_fixup_unbounded (dst, extents);
+
+ if (clip_region != NULL)
+ _cairo_xcb_surface_clear_clip_region (dst);
+ } else {
+ status = _cairo_xcb_surface_fixup_unbounded_with_mask (dst,
+ extents,
+ clip);
+ }
+ }
+
+ return status;
+ }
+
+ _cairo_box_round_to_rectangle (&polygon->extents, &extents->mask);
+ is_not_empty = _cairo_rectangle_intersect (&extents->bounded, &extents->mask);
+ if (extents->is_bounded && ! is_not_empty)
+ return CAIRO_STATUS_SUCCESS;
+
+ if (dst->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE_SPANS) {
+ composite_spans_info_t spans;
+
+ spans.polygon = polygon;
+ spans.fill_rule = CAIRO_FILL_RULE_WINDING;
+ spans.antialias = antialias;
+
+ return _clip_and_composite (dst, op, source,
+ _composite_spans, &spans,
+ extents, clip);
+ }
+
+ _cairo_traps_init (&traps.traps);
+
+ status = _cairo_bentley_ottmann_tessellate_polygon (&traps.traps, polygon, fill_rule);
+ if (unlikely (status))
+ goto CLEANUP_TRAPS;
+
+ if (clip != NULL) {
+ cairo_region_t *clip_region;
+
+ status = _cairo_clip_get_region (clip, &clip_region);
+ clip_surface = status == CAIRO_INT_STATUS_UNSUPPORTED;
+ }
+
+ if (traps.traps.has_intersections) {
+ if (traps.traps.is_rectangular)
+ status = _cairo_bentley_ottmann_tessellate_rectangular_traps (&traps.traps, CAIRO_FILL_RULE_WINDING);
+ else if (traps.traps.is_rectilinear)
+ status = _cairo_bentley_ottmann_tessellate_rectilinear_traps (&traps.traps, CAIRO_FILL_RULE_WINDING);
+ else
+ status = _cairo_bentley_ottmann_tessellate_traps (&traps.traps, CAIRO_FILL_RULE_WINDING);
+ if (unlikely (status))
+ goto CLEANUP_TRAPS;
+ }
+
+ /* Use a fast path if the trapezoids consist of a simple region,
+ * but we can only do this if we do not have a clip surface, or can
+ * substitute the mask with the clip.
+ */
+ if (traps.traps.maybe_region &&
+ _traps_are_pixel_aligned (&traps.traps, antialias) &&
+ (! clip_surface ||
+ (extents->is_bounded && op != CAIRO_OPERATOR_SOURCE)))
+ {
+ cairo_boxes_t boxes;
+
+ _boxes_for_traps (&boxes, &traps.traps);
+ status = _clip_and_composite_boxes (dst, op, source,
+ &boxes, antialias,
+ extents, clip);
+ }
+ else
+ {
+ /* Otherwise render the trapezoids to a mask and composite in the usual
+ * fashion.
+ */
+ traps.antialias = antialias;
+ status = _clip_and_composite (dst, op, source,
+ _composite_traps, &traps,
+ extents, clip);
+ }
+
+CLEANUP_TRAPS:
+ _cairo_traps_fini (&traps.traps);
+
+ return status;
+}
+
+static cairo_int_status_t
+_cairo_xcb_surface_render_stroke_as_polygon (cairo_xcb_surface_t *dst,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_path_fixed_t *path,
+ const cairo_stroke_style_t *stroke_style,
+ const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm_inverse,
+ double tolerance,
+ cairo_antialias_t antialias,
+ cairo_clip_t *clip,
+ const cairo_box_t *clip_boxes,
+ int num_boxes,
+ cairo_composite_rectangles_t *extents)
+{
+ cairo_polygon_t polygon;
+ cairo_status_t status;
+
+ _cairo_polygon_init (&polygon);
+ _cairo_polygon_limit (&polygon, clip_boxes, num_boxes);
+
+ status = _cairo_path_fixed_stroke_to_polygon (path,
+ stroke_style,
+ ctm, ctm_inverse,
+ tolerance,
+ &polygon);
+ if (likely (status == CAIRO_STATUS_SUCCESS)) {
+ status = _cairo_xcb_surface_render_composite_polygon (dst, op, source,
+ &polygon, antialias,
+ CAIRO_FILL_RULE_WINDING,
+ extents, clip);
+ }
+
+ _cairo_polygon_fini (&polygon);
+
+ return status;
+}
+
+static void
+_clear_image (cairo_surface_t *surface)
+{
+ cairo_image_surface_t *image = (cairo_image_surface_t *) surface;
+ memset (image->data, 0, image->stride * image->height);
+ surface->is_clear = TRUE;
+}
+
+static cairo_status_t
+_cairo_xcb_surface_render_stroke_via_mask (cairo_xcb_surface_t *dst,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_path_fixed_t *path,
+ const cairo_stroke_style_t *stroke_style,
+ const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm_inverse,
+ double tolerance,
+ cairo_antialias_t antialias,
+ cairo_clip_t *clip,
+ const cairo_composite_rectangles_t *extents)
+{
+ cairo_surface_t *image;
+ cairo_status_t status;
+ int x, y;
+
+ x = extents->bounded.x;
+ y = extents->bounded.y;
+ image = _cairo_xcb_surface_create_similar_image (dst, CAIRO_CONTENT_ALPHA,
+ extents->bounded.width,
+ extents->bounded.height);
+ if (unlikely (image->status))
+ return image->status;
+
+ _clear_image (image);
+
+ status = _cairo_surface_offset_stroke (image, x, y,
+ CAIRO_OPERATOR_ADD,
+ &_cairo_pattern_white.base,
+ path, stroke_style,
+ ctm, ctm_inverse,
+ tolerance, antialias,
+ NULL);
+ if (likely (status == CAIRO_STATUS_SUCCESS)) {
+ cairo_surface_pattern_t mask;
+
+ _cairo_pattern_init_for_surface (&mask, image);
+ mask.base.filter = CAIRO_FILTER_NEAREST;
+
+ cairo_matrix_init_translate (&mask.base.matrix, -x, -y);
+ status = _clip_and_composite (dst, op, source,
+ _composite_mask, (void *) &mask.base,
+ extents, clip);
+ _cairo_pattern_fini (&mask.base);
+ }
+
+ cairo_surface_finish (image);
+ cairo_surface_destroy (image);
+
+ return status;
+}
+
+cairo_int_status_t
+_cairo_xcb_surface_render_stroke (cairo_xcb_surface_t *surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_path_fixed_t *path,
+ const cairo_stroke_style_t *style,
+ const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm_inverse,
+ double tolerance,
+ cairo_antialias_t antialias,
+ cairo_clip_t *clip)
+{
+ cairo_composite_rectangles_t extents;
+ cairo_box_t boxes_stack[32], *clip_boxes = boxes_stack;
+ int num_boxes = ARRAY_LENGTH (boxes_stack);
+ cairo_clip_t local_clip;
+ cairo_bool_t have_clip = FALSE;
+ cairo_status_t status;
+
+ if (unlikely (! _operator_is_supported (surface->flags, op)))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ if ((surface->flags & (CAIRO_XCB_RENDER_HAS_COMPOSITE_SPANS |
+ CAIRO_XCB_RENDER_HAS_COMPOSITE_TRAPEZOIDS |
+ CAIRO_XCB_RENDER_HAS_COMPOSITE)) == 0)
+ {
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ }
+
+ status = _cairo_composite_rectangles_init_for_stroke (&extents,
+ surface->width,
+ surface->height,
+ op, source,
+ path, style, ctm,
+ clip);
+ if (unlikely (status))
+ return status;
+
+ if (_cairo_clip_contains_rectangle (clip, &extents))
+ clip = NULL;
+
+ if (clip != NULL) {
+ clip = _cairo_clip_init_copy (&local_clip, clip);
+ have_clip = TRUE;
+ }
+
+ status = _clip_to_boxes (&clip, &extents, &clip_boxes, &num_boxes);
+ if (unlikely (status)) {
+ if (have_clip)
+ _cairo_clip_fini (&local_clip);
+
+ return status;
+ }
+
+ status = CAIRO_INT_STATUS_UNSUPPORTED;
+ if (path->is_rectilinear) {
+ cairo_boxes_t boxes;
+
+ _cairo_boxes_init (&boxes);
+ _cairo_boxes_limit (&boxes, clip_boxes, num_boxes);
+
+ status = _cairo_path_fixed_stroke_rectilinear_to_boxes (path,
+ style,
+ ctm,
+ &boxes);
+ if (likely (status == CAIRO_STATUS_SUCCESS)) {
+ status = _clip_and_composite_boxes (surface, op, source,
+ &boxes, antialias,
+ &extents, clip);
+ }
+
+ _cairo_boxes_fini (&boxes);
+ }
+
+ if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
+ if (surface->flags & (CAIRO_XCB_RENDER_HAS_COMPOSITE_SPANS | CAIRO_XCB_RENDER_HAS_COMPOSITE_TRAPEZOIDS)) {
+ status = _cairo_xcb_surface_render_stroke_as_polygon (surface, op, source,
+ path, style,
+ ctm, ctm_inverse,
+ tolerance, antialias,
+ clip, clip_boxes, num_boxes,
+ &extents);
+ } else if (surface->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE) {
+ status = _cairo_xcb_surface_render_stroke_via_mask (surface, op, source,
+ path, style,
+ ctm, ctm_inverse,
+ tolerance, antialias,
+ have_clip ? &local_clip : NULL,
+ &extents);
+ } else {
+ ASSERT_NOT_REACHED;
+ }
+ }
+
+ if (clip_boxes != boxes_stack)
+ free (clip_boxes);
+
+ if (have_clip)
+ _cairo_clip_fini (&local_clip);
+
+ return status;
+}
+
+static cairo_status_t
+_cairo_xcb_surface_render_fill_as_polygon (cairo_xcb_surface_t *dst,
+ cairo_operator_t op,
+ const cairo_pattern_t*source,
+ cairo_path_fixed_t *path,
+ cairo_fill_rule_t fill_rule,
+ double tolerance,
+ cairo_antialias_t antialias,
+ cairo_clip_t *clip,
+ cairo_box_t *clip_boxes,
+ int num_boxes,
+ cairo_composite_rectangles_t *extents)
+{
+ cairo_polygon_t polygon;
+ cairo_status_t status;
+
+ _cairo_polygon_init (&polygon);
+ _cairo_polygon_limit (&polygon, clip_boxes, num_boxes);
+
+ status = _cairo_path_fixed_fill_to_polygon (path, tolerance, &polygon);
+ if (likely (status == CAIRO_STATUS_SUCCESS)) {
+ status = _cairo_xcb_surface_render_composite_polygon (dst, op, source,
+ &polygon, antialias,
+ fill_rule,
+ extents, clip);
+ }
+
+ _cairo_polygon_fini (&polygon);
+
+ return status;
+}
+
+static cairo_status_t
+_cairo_xcb_surface_render_fill_via_mask (cairo_xcb_surface_t *dst,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_path_fixed_t *path,
+ cairo_fill_rule_t fill_rule,
+ double tolerance,
+ cairo_antialias_t antialias,
+ cairo_clip_t *clip,
+ const cairo_composite_rectangles_t *extents)
+{
+ cairo_surface_t *image;
+ cairo_status_t status;
+ int x, y;
+
+ x = extents->bounded.x;
+ y = extents->bounded.y;
+ image = _cairo_xcb_surface_create_similar_image (dst,
+ CAIRO_CONTENT_ALPHA,
+ extents->bounded.width,
+ extents->bounded.height);
+ if (unlikely (image->status))
+ return image->status;
+
+ _clear_image (image);
+
+ status = _cairo_surface_offset_fill (image, x, y,
+ CAIRO_OPERATOR_ADD,
+ &_cairo_pattern_white.base,
+ path, fill_rule, tolerance, antialias,
+ NULL);
+ if (likely (status == CAIRO_STATUS_SUCCESS)) {
+ cairo_surface_pattern_t mask;
+
+ _cairo_pattern_init_for_surface (&mask, image);
+ mask.base.filter = CAIRO_FILTER_NEAREST;
+
+ cairo_matrix_init_translate (&mask.base.matrix, -x, -y);
+ status = _clip_and_composite (dst, op, source,
+ _composite_mask, (void *) &mask.base,
+ extents, clip);
+
+ _cairo_pattern_fini (&mask.base);
+ }
+
+ cairo_surface_finish (image);
+ cairo_surface_destroy (image);
+
+ return status;
+}
+
+cairo_int_status_t
+_cairo_xcb_surface_render_fill (cairo_xcb_surface_t *surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_path_fixed_t *path,
+ cairo_fill_rule_t fill_rule,
+ double tolerance,
+ cairo_antialias_t antialias,
+ cairo_clip_t *clip)
+{
+ cairo_composite_rectangles_t extents;
+ cairo_box_t boxes_stack[32], *clip_boxes = boxes_stack;
+ int num_boxes = ARRAY_LENGTH (boxes_stack);
+ cairo_clip_t local_clip;
+ cairo_bool_t have_clip = FALSE;
+ cairo_status_t status;
+
+ if (unlikely (! _operator_is_supported (surface->flags, op)))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ if ((surface->flags & (CAIRO_XCB_RENDER_HAS_COMPOSITE_SPANS |
+ CAIRO_XCB_RENDER_HAS_COMPOSITE_TRAPEZOIDS |
+ CAIRO_XCB_RENDER_HAS_COMPOSITE)) == 0)
+ {
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ }
+
+ status = _cairo_composite_rectangles_init_for_fill (&extents,
+ surface->width,
+ surface->height,
+ op, source, path,
+ clip);
+ if (unlikely (status))
+ return status;
+
+ if (_cairo_clip_contains_rectangle (clip, &extents))
+ clip = NULL;
+
+ if (clip != NULL) {
+ clip = _cairo_clip_init_copy (&local_clip, clip);
+ have_clip = TRUE;
+ }
+
+ status = _clip_to_boxes (&clip, &extents, &clip_boxes, &num_boxes);
+ if (unlikely (status)) {
+ if (have_clip)
+ _cairo_clip_fini (&local_clip);
+
+ return status;
+ }
+
+ status = CAIRO_INT_STATUS_UNSUPPORTED;
+ if (_cairo_path_fixed_is_rectilinear_fill (path)) {
+ cairo_boxes_t boxes;
+
+ _cairo_boxes_init (&boxes);
+ _cairo_boxes_limit (&boxes, clip_boxes, num_boxes);
+
+ status = _cairo_path_fixed_fill_rectilinear_to_boxes (path,
+ fill_rule,
+ &boxes);
+ if (likely (status == CAIRO_STATUS_SUCCESS)) {
+ status = _clip_and_composite_boxes (surface, op, source,
+ &boxes, antialias,
+ &extents, clip);
+ }
+
+ _cairo_boxes_fini (&boxes);
+ }
+
+ if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
+ if (surface->flags & (CAIRO_XCB_RENDER_HAS_COMPOSITE_SPANS | CAIRO_XCB_RENDER_HAS_COMPOSITE_TRAPEZOIDS)) {
+ status = _cairo_xcb_surface_render_fill_as_polygon (surface, op, source, path,
+ fill_rule, tolerance, antialias,
+ clip, clip_boxes, num_boxes,
+ &extents);
+ } else if (surface->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE) {
+ status = _cairo_xcb_surface_render_fill_via_mask (surface, op, source, path,
+ fill_rule, tolerance, antialias,
+ have_clip ? &local_clip : NULL,
+ &extents);
+ } else {
+ ASSERT_NOT_REACHED;
+ }
+ }
+
+ if (clip_boxes != boxes_stack)
+ free (clip_boxes);
+
+ if (have_clip)
+ _cairo_clip_fini (&local_clip);
+
+ return status;
+}
+
+static cairo_status_t
+_cairo_xcb_surface_render_glyphs_via_mask (cairo_xcb_surface_t *dst,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_scaled_font_t *scaled_font,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_clip_t *clip,
+ const cairo_composite_rectangles_t *extents)
+{
+ cairo_surface_t *image;
+ cairo_content_t content;
+ cairo_status_t status;
+ int x, y;
+
+ content = CAIRO_CONTENT_ALPHA;
+ if (scaled_font->options.antialias == CAIRO_ANTIALIAS_SUBPIXEL)
+ content = CAIRO_CONTENT_COLOR_ALPHA;
+
+ x = extents->bounded.x;
+ y = extents->bounded.y;
+ image = _cairo_xcb_surface_create_similar_image (dst, content,
+ extents->bounded.width,
+ extents->bounded.height);
+ if (unlikely (image->status))
+ return image->status;
+
+ _clear_image (image);
+
+ status = _cairo_surface_offset_glyphs (image, x, y,
+ CAIRO_OPERATOR_ADD,
+ &_cairo_pattern_white.base,
+ scaled_font, glyphs, num_glyphs,
+ NULL);
+ if (likely (status == CAIRO_STATUS_SUCCESS)) {
+ cairo_surface_pattern_t mask;
+
+ _cairo_pattern_init_for_surface (&mask, image);
+ mask.base.filter = CAIRO_FILTER_NEAREST;
+ if (content & CAIRO_CONTENT_COLOR)
+ mask.base.has_component_alpha = TRUE;
+
+ cairo_matrix_init_translate (&mask.base.matrix, -x, -y);
+ status = _clip_and_composite (dst, op, source,
+ _composite_mask, (void *) &mask.base,
+ extents, clip);
+
+ _cairo_pattern_fini (&mask.base);
+ }
+
+ cairo_surface_finish (image);
+ cairo_surface_destroy (image);
+
+ return status;
+}
+
+/* Build a struct of the same size of #cairo_glyph_t that can be used both as
+ * an input glyph with double coordinates, and as "working" glyph with
+ * integer from-current-point offsets. */
+typedef union {
+ cairo_glyph_t d;
+ unsigned long index;
+ struct {
+ unsigned long index;
+ int x;
+ int y;
+ } i;
+} cairo_xcb_glyph_t;
+
+/* compile-time assert that #cairo_xcb_glyph_t is the same size as #cairo_glyph_t */
+COMPILE_TIME_ASSERT (sizeof (cairo_xcb_glyph_t) == sizeof (cairo_glyph_t));
+
+typedef struct {
+ cairo_scaled_font_t *font;
+ cairo_xcb_glyph_t *glyphs;
+ int num_glyphs;
+} composite_glyphs_info_t;
+
+static cairo_status_t
+_can_composite_glyphs (cairo_xcb_surface_t *dst,
+ cairo_scaled_font_t *scaled_font,
+ cairo_glyph_t *glyphs,
+ int num_glyphs)
+{
+ cairo_status_t status;
+ const int max_glyph_size = dst->connection->maximum_request_length - 64;
+ int i;
+
+ /* first scan for oversized glyphs, and fallback in that case */
+ for (i = 0; i < num_glyphs; i++) {
+ cairo_scaled_glyph_t *scaled_glyph;
+ int width, height, len;
+
+ status = _cairo_scaled_glyph_lookup (scaled_font,
+ glyphs[i].index,
+ CAIRO_SCALED_GLYPH_INFO_METRICS,
+ &scaled_glyph);
+ if (unlikely (status))
+ return status;
+
+ /* XRenderAddGlyph does not handle a glyph surface larger than
+ * the extended maximum XRequest size.
+ */
+ width =
+ _cairo_fixed_integer_ceil (scaled_glyph->bbox.p2.x - scaled_glyph->bbox.p1.x);
+ height =
+ _cairo_fixed_integer_ceil (scaled_glyph->bbox.p2.y - scaled_glyph->bbox.p1.y);
+ len = CAIRO_STRIDE_FOR_WIDTH_BPP (width, 32) * height;
+ if (len >= max_glyph_size)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+/* Start a new element for the first glyph,
+ * or for any glyph that has unexpected position,
+ * or if current element has too many glyphs
+ * (Xrender limits each element to 252 glyphs, we limit them to 128)
+ *
+ * These same conditions need to be mirrored between
+ * _cairo_xcb_surface_emit_glyphs and _emit_glyph_chunks
+ */
+#define _start_new_glyph_elt(count, glyph) \
+ (((count) & 127) == 0 || (glyph)->i.x || (glyph)->i.y)
+
+/* sz_xGlyphtElt required alignment to a 32-bit boundary, so ensure we have
+ * enough room for padding */
+typedef struct {
+ uint8_t len;
+ uint8_t pad1;
+ uint16_t pad2;
+ int16_t deltax;
+ int16_t deltay;
+} x_glyph_elt_t;
+#define _cairo_sz_x_glyph_elt_t (sizeof (x_glyph_elt_t) + 4)
+
+static cairo_xcb_font_glyphset_info_t *
+_cairo_xcb_scaled_glyph_get_glyphset_info (cairo_scaled_glyph_t *scaled_glyph)
+{
+ return scaled_glyph->surface_private;
+}
+
+static void
+_cairo_xcb_scaled_glyph_set_glyphset_info (cairo_scaled_glyph_t *scaled_glyph,
+ cairo_xcb_font_glyphset_info_t *glyphset_info)
+{
+ scaled_glyph->surface_private = glyphset_info;
+}
+
+static cairo_status_t
+_cairo_xcb_surface_font_init (cairo_xcb_connection_t *connection,
+ cairo_scaled_font_t *scaled_font)
+{
+ cairo_xcb_font_t *font_private;
+ int i;
+
+ font_private = malloc (sizeof (cairo_xcb_font_t));
+ if (unlikely (font_private == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+ font_private->scaled_font = scaled_font;
+ font_private->connection = _cairo_xcb_connection_reference (connection);
+ for (i = 0; i < NUM_GLYPHSETS; i++) {
+ cairo_xcb_font_glyphset_info_t *glyphset_info = &font_private->glyphset_info[i];
+ switch (i) {
+ case GLYPHSET_INDEX_ARGB32: glyphset_info->format = CAIRO_FORMAT_ARGB32; break;
+ case GLYPHSET_INDEX_A8: glyphset_info->format = CAIRO_FORMAT_A8; break;
+ case GLYPHSET_INDEX_A1: glyphset_info->format = CAIRO_FORMAT_A1; break;
+ default: ASSERT_NOT_REACHED; break;
+ }
+ glyphset_info->xrender_format = 0;
+ glyphset_info->glyphset = XCB_NONE;
+ glyphset_info->pending_free_glyphs = NULL;
+ }
+
+ scaled_font->surface_private = font_private;
+ scaled_font->surface_backend = &_cairo_xcb_surface_backend;
+
+ cairo_list_add (&font_private->link, &connection->fonts);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static void
+_cairo_xcb_font_destroy (cairo_xcb_font_t *font)
+{
+ int i;
+
+ for (i = 0; i < NUM_GLYPHSETS; i++) {
+ cairo_xcb_font_glyphset_info_t *glyphset_info;
+
+ glyphset_info = &font->glyphset_info[i];
+
+ if (glyphset_info->pending_free_glyphs != NULL)
+ free (glyphset_info->pending_free_glyphs);
+ }
+
+ cairo_list_del (&font->link);
+ _cairo_xcb_connection_destroy (font->connection);
+
+ free (font);
+}
+
+void
+_cairo_xcb_font_finish (cairo_xcb_font_t *font)
+{
+ cairo_scaled_font_t *scaled_font;
+
+ scaled_font = font->scaled_font;
+
+ CAIRO_MUTEX_LOCK (scaled_font->mutex);
+ scaled_font->surface_private = NULL;
+ _cairo_scaled_font_reset_cache (scaled_font);
+ CAIRO_MUTEX_UNLOCK (scaled_font->mutex);
+
+ _cairo_xcb_font_destroy (font);
+}
+
+void
+_cairo_xcb_surface_scaled_font_fini (cairo_scaled_font_t *scaled_font)
+{
+ cairo_xcb_font_t *font_private;
+ cairo_xcb_connection_t *connection;
+ cairo_bool_t have_connection;
+ cairo_status_t status;
+ int i;
+
+ font_private = scaled_font->surface_private;
+ if (font_private == NULL)
+ return;
+
+ connection = font_private->connection;
+
+ status = _cairo_xcb_connection_acquire (connection);
+ have_connection = status == CAIRO_STATUS_SUCCESS;
+ if (likely (have_connection))
+ status = _cairo_xcb_connection_take_socket (connection);
+
+ for (i = 0; i < NUM_GLYPHSETS; i++) {
+ cairo_xcb_font_glyphset_info_t *glyphset_info;
+
+ glyphset_info = &font_private->glyphset_info[i];
+ if (glyphset_info->glyphset && status == CAIRO_STATUS_SUCCESS) {
+ _cairo_xcb_connection_render_free_glyph_set (connection,
+ glyphset_info->glyphset);
+ }
+ }
+
+ if (have_connection)
+ _cairo_xcb_connection_release (connection);
+
+
+ _cairo_xcb_font_destroy (font_private);
+}
+
+static void
+_cairo_xcb_render_free_glyphs (cairo_xcb_connection_t *connection,
+ cairo_xcb_font_glyphset_free_glyphs_t *to_free)
+{
+ _cairo_xcb_connection_render_free_glyphs (connection,
+ to_free->glyphset,
+ to_free->glyph_count,
+ to_free->glyph_indices);
+}
+
+void
+_cairo_xcb_surface_scaled_glyph_fini (cairo_scaled_glyph_t *scaled_glyph,
+ cairo_scaled_font_t *scaled_font)
+{
+ cairo_xcb_font_t *font_private;
+ cairo_xcb_font_glyphset_info_t *glyphset_info;
+
+ if (scaled_font->finished)
+ return;
+
+ font_private = scaled_font->surface_private;
+ glyphset_info = _cairo_xcb_scaled_glyph_get_glyphset_info (scaled_glyph);
+ if (font_private != NULL && glyphset_info != NULL) {
+ cairo_xcb_font_glyphset_free_glyphs_t *to_free;
+
+ to_free = glyphset_info->pending_free_glyphs;
+ if (to_free != NULL &&
+ to_free->glyph_count == ARRAY_LENGTH (to_free->glyph_indices))
+ {
+ _cairo_xcb_render_free_glyphs (font_private->connection, to_free);
+ to_free = glyphset_info->pending_free_glyphs = NULL;
+ }
+
+ if (to_free == NULL) {
+ to_free = malloc (sizeof (cairo_xcb_font_glyphset_free_glyphs_t));
+ if (unlikely (to_free == NULL)) {
+ _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
+ return; /* XXX cannot propagate failure */
+ }
+
+ to_free->glyphset = glyphset_info->glyphset;
+ to_free->glyph_count = 0;
+ glyphset_info->pending_free_glyphs = to_free;
+ }
+
+ to_free->glyph_indices[to_free->glyph_count++] =
+ _cairo_scaled_glyph_index (scaled_glyph);
+ }
+}
+
+static cairo_bool_t
+_native_byte_order_lsb (void)
+{
+ int x = 1;
+
+ return *((char *) &x) == 1;
+}
+
+static cairo_xcb_font_glyphset_info_t *
+_cairo_xcb_scaled_font_get_glyphset_info_for_format (cairo_scaled_font_t *scaled_font,
+ cairo_format_t format)
+{
+ cairo_xcb_font_t *font_private;
+ cairo_xcb_font_glyphset_info_t *glyphset_info;
+ int glyphset_index;
+
+ switch (format) {
+ default:
+ case CAIRO_FORMAT_RGB24:
+ case CAIRO_FORMAT_ARGB32: glyphset_index = GLYPHSET_INDEX_ARGB32; break;
+ case CAIRO_FORMAT_A8: glyphset_index = GLYPHSET_INDEX_A8; break;
+ case CAIRO_FORMAT_A1: glyphset_index = GLYPHSET_INDEX_A1; break;
+ }
+
+ font_private = scaled_font->surface_private;
+ glyphset_info = &font_private->glyphset_info[glyphset_index];
+ if (glyphset_info->glyphset == XCB_NONE) {
+ cairo_xcb_connection_t *connection = font_private->connection;
+
+ glyphset_info->glyphset = _cairo_xcb_connection_get_xid (font_private->connection);
+ glyphset_info->xrender_format =
+ connection->standard_formats[glyphset_info->format];
+
+ _cairo_xcb_connection_render_create_glyph_set (font_private->connection,
+ glyphset_info->glyphset,
+ glyphset_info->xrender_format);
+ }
+
+ return glyphset_info;
+}
+
+static cairo_bool_t
+_cairo_xcb_glyphset_info_has_pending_free_glyph (
+ cairo_xcb_font_glyphset_info_t *glyphset_info,
+ unsigned long glyph_index)
+{
+ if (glyphset_info->pending_free_glyphs != NULL) {
+ cairo_xcb_font_glyphset_free_glyphs_t *to_free;
+ int i;
+
+ to_free = glyphset_info->pending_free_glyphs;
+ for (i = 0; i < to_free->glyph_count; i++) {
+ if (to_free->glyph_indices[i] == glyph_index) {
+ to_free->glyph_count--;
+ memmove (&to_free->glyph_indices[i],
+ &to_free->glyph_indices[i+1],
+ (to_free->glyph_count - i) * sizeof (to_free->glyph_indices[0]));
+ return TRUE;
+ }
+ }
+ }
+
+ return FALSE;
+}
+
+static cairo_xcb_font_glyphset_info_t *
+_cairo_xcb_scaled_font_get_glyphset_info_for_pending_free_glyph (
+ cairo_scaled_font_t *scaled_font,
+ unsigned long glyph_index,
+ cairo_image_surface_t *surface)
+{
+ cairo_xcb_font_t *font_private;
+ int i;
+
+ font_private = scaled_font->surface_private;
+ if (font_private == NULL)
+ return NULL;
+
+ if (surface != NULL) {
+ switch (surface->format) {
+ default:
+ case CAIRO_FORMAT_RGB24:
+ case CAIRO_FORMAT_ARGB32: i = GLYPHSET_INDEX_ARGB32; break;
+ case CAIRO_FORMAT_A8: i = GLYPHSET_INDEX_A8; break;
+ case CAIRO_FORMAT_A1: i = GLYPHSET_INDEX_A1; break;
+ }
+
+ if (_cairo_xcb_glyphset_info_has_pending_free_glyph (
+ &font_private->glyphset_info[i],
+ glyph_index))
+ {
+ return &font_private->glyphset_info[i];
+ }
+ } else {
+ for (i = 0; i < NUM_GLYPHSETS; i++) {
+ if (_cairo_xcb_glyphset_info_has_pending_free_glyph (
+ &font_private->glyphset_info[i],
+ glyph_index))
+ {
+ return &font_private->glyphset_info[i];
+ }
+ }
+ }
+
+ return NULL;
+}
+static cairo_status_t
+_cairo_xcb_surface_add_glyph (cairo_xcb_connection_t *connection,
+ cairo_scaled_font_t *scaled_font,
+ cairo_scaled_glyph_t **scaled_glyph_out)
+{
+ xcb_render_glyphinfo_t glyph_info;
+ uint32_t glyph_index;
+ uint8_t *data;
+ cairo_status_t status = CAIRO_STATUS_SUCCESS;
+ cairo_scaled_glyph_t *scaled_glyph = *scaled_glyph_out;
+ cairo_image_surface_t *glyph_surface = scaled_glyph->surface;
+ cairo_bool_t already_had_glyph_surface;
+ cairo_xcb_font_glyphset_info_t *glyphset_info;
+
+ glyph_index = _cairo_scaled_glyph_index (scaled_glyph);
+
+ /* check to see if we have a pending XRenderFreeGlyph for this glyph */
+ glyphset_info = _cairo_xcb_scaled_font_get_glyphset_info_for_pending_free_glyph (scaled_font, glyph_index, glyph_surface);
+ if (glyphset_info != NULL) {
+ _cairo_xcb_scaled_glyph_set_glyphset_info (scaled_glyph, glyphset_info);
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+ if (glyph_surface == NULL) {
+ status = _cairo_scaled_glyph_lookup (scaled_font,
+ glyph_index,
+ CAIRO_SCALED_GLYPH_INFO_METRICS |
+ CAIRO_SCALED_GLYPH_INFO_SURFACE,
+ scaled_glyph_out);
+ if (unlikely (status))
+ return status;
+
+ scaled_glyph = *scaled_glyph_out;
+ glyph_surface = scaled_glyph->surface;
+ already_had_glyph_surface = FALSE;
+ } else {
+ already_had_glyph_surface = TRUE;
+ }
+
+ if (scaled_font->surface_private == NULL) {
+ status = _cairo_xcb_surface_font_init (connection, scaled_font);
+ if (unlikely (status))
+ return status;
+ }
+
+ glyphset_info = _cairo_xcb_scaled_font_get_glyphset_info_for_format (scaled_font,
+ glyph_surface->format);
+
+ /* If the glyph surface has zero height or width, we create
+ * a clear 1x1 surface, to avoid various X server bugs.
+ */
+ if (glyph_surface->width == 0 || glyph_surface->height == 0) {
+ cairo_surface_t *tmp_surface;
+
+ tmp_surface = cairo_image_surface_create (glyphset_info->format, 1, 1);
+ status = tmp_surface->status;
+ if (unlikely (status))
+ goto BAIL;
+
+ tmp_surface->device_transform = glyph_surface->base.device_transform;
+ tmp_surface->device_transform_inverse = glyph_surface->base.device_transform_inverse;
+
+ glyph_surface = (cairo_image_surface_t *) tmp_surface;
+ }
+
+ /* If the glyph format does not match the font format, then we
+ * create a temporary surface for the glyph image with the font's
+ * format.
+ */
+ if (glyph_surface->format != glyphset_info->format) {
+ glyph_surface = _cairo_image_surface_coerce (glyph_surface,
+ glyphset_info->format);
+ status = glyph_surface->base.status;
+ if (unlikely (status))
+ goto BAIL;
+ }
+
+ /* XXX: FRAGILE: We're ignore device_transform scaling here. A bug? */
+ glyph_info.x = _cairo_lround (glyph_surface->base.device_transform.x0);
+ glyph_info.y = _cairo_lround (glyph_surface->base.device_transform.y0);
+ glyph_info.width = glyph_surface->width;
+ glyph_info.height = glyph_surface->height;
+ glyph_info.x_off = scaled_glyph->x_advance;
+ glyph_info.y_off = scaled_glyph->y_advance;
+
+ data = glyph_surface->data;
+
+ /* flip formats around */
+ switch (scaled_glyph->surface->format) {
+ case CAIRO_FORMAT_A1:
+ /* local bitmaps are always stored with bit == byte */
+ if (_native_byte_order_lsb() != (connection->root->bitmap_format_bit_order == XCB_IMAGE_ORDER_LSB_FIRST)) {
+ int c = glyph_surface->stride * glyph_surface->height;
+ const uint8_t *d;
+ uint8_t *new, *n;
+
+ new = malloc (c);
+ if (unlikely (new == NULL)) {
+ status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ goto BAIL;
+ }
+
+ n = new;
+ d = data;
+ do {
+ uint8_t b = *d++;
+ b = ((b << 1) & 0xaa) | ((b >> 1) & 0x55);
+ b = ((b << 2) & 0xcc) | ((b >> 2) & 0x33);
+ b = ((b << 4) & 0xf0) | ((b >> 4) & 0x0f);
+ *n++ = b;
+ } while (--c);
+ data = new;
+ }
+ break;
+
+ case CAIRO_FORMAT_A8:
+ break;
+
+ case CAIRO_FORMAT_ARGB32:
+ if (_native_byte_order_lsb() != (connection->root->image_byte_order == XCB_IMAGE_ORDER_LSB_FIRST)) {
+ unsigned int c = glyph_surface->stride * glyph_surface->height / 4;
+ const uint32_t *d;
+ uint32_t *new, *n;
+
+ new = malloc (4 * c);
+ if (unlikely (new == NULL)) {
+ status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ goto BAIL;
+ }
+
+ n = new;
+ d = (uint32_t *) data;
+ do {
+ *n++ = bswap_32 (*d);
+ d++;
+ } while (--c);
+ data = (uint8_t *) new;
+ }
+ break;
+
+ case CAIRO_FORMAT_RGB24:
+ default:
+ ASSERT_NOT_REACHED;
+ break;
+ }
+ /* XXX assume X server wants pixman padding. Xft assumes this as well */
+
+ _cairo_xcb_connection_render_add_glyphs (connection,
+ glyphset_info->glyphset,
+ 1, &glyph_index, &glyph_info,
+ glyph_surface->stride * glyph_surface->height,
+ data);
+
+ if (data != glyph_surface->data)
+ free (data);
+
+ _cairo_xcb_scaled_glyph_set_glyphset_info (scaled_glyph, glyphset_info);
+
+ BAIL:
+ if (glyph_surface != scaled_glyph->surface)
+ cairo_surface_destroy (&glyph_surface->base);
+
+ /* If the scaled glyph didn't already have a surface attached
+ * to it, release the created surface now that we have it
+ * uploaded to the X server. If the surface has already been
+ * there (e.g. because image backend requested it), leave it in
+ * the cache
+ */
+ if (! already_had_glyph_surface)
+ _cairo_scaled_glyph_set_surface (scaled_glyph, scaled_font, NULL);
+
+ return status;
+}
+
+typedef void (*cairo_xcb_render_composite_text_func_t)
+ (cairo_xcb_connection_t *connection,
+ uint8_t op,
+ xcb_render_picture_t src,
+ xcb_render_picture_t dst,
+ xcb_render_pictformat_t mask_format,
+ xcb_render_glyphset_t glyphset,
+ int16_t src_x,
+ int16_t src_y,
+ uint32_t len,
+ uint8_t *cmd);
+
+
+static cairo_status_t
+_emit_glyphs_chunk (cairo_xcb_surface_t *dst,
+ cairo_operator_t op,
+ cairo_xcb_picture_t *src,
+ /* info for this chunk */
+ cairo_xcb_glyph_t *glyphs,
+ int num_glyphs,
+ int width,
+ int estimated_req_size,
+ cairo_xcb_font_glyphset_info_t *glyphset_info)
+{
+ cairo_xcb_render_composite_text_func_t composite_text_func;
+ uint8_t stack_buf[CAIRO_STACK_BUFFER_SIZE];
+ uint8_t *buf = stack_buf;
+ x_glyph_elt_t *elt = NULL; /* silence compiler */
+ uint32_t len;
+ int i;
+
+ if (estimated_req_size > ARRAY_LENGTH (stack_buf)) {
+ buf = malloc (estimated_req_size);
+ if (unlikely (buf == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ }
+
+ len = 0;
+ for (i = 0; i < num_glyphs; i++) {
+ if (_start_new_glyph_elt (i, &glyphs[i])) {
+ if (len & 3)
+ len += 4 - (len & 3);
+
+ elt = (x_glyph_elt_t *) (buf + len);
+ elt->len = 0;
+ elt->deltax = glyphs[i].i.x;
+ elt->deltay = glyphs[i].i.y;
+ len += sizeof (x_glyph_elt_t);
+ }
+
+ switch (width) {
+ case 1: *(uint8_t *) (buf + len) = glyphs[i].index; break;
+ case 2: *(uint16_t *) (buf + len) = glyphs[i].index; break;
+ default:
+ case 4: *(uint32_t *) (buf + len) = glyphs[i].index; break;
+ }
+ len += width;
+ elt->len++;
+ }
+ if (len & 3)
+ len += 4 - (len & 3);
+
+ switch (width) {
+ case 1:
+ composite_text_func = _cairo_xcb_connection_render_composite_glyphs_8;
+ break;
+ case 2:
+ composite_text_func = _cairo_xcb_connection_render_composite_glyphs_16;
+ break;
+ default:
+ case 4:
+ composite_text_func = _cairo_xcb_connection_render_composite_glyphs_32;
+ break;
+ }
+ composite_text_func (dst->connection,
+ _render_operator (op),
+ src->picture,
+ dst->picture,
+ glyphset_info->xrender_format,
+ glyphset_info->glyphset,
+ src->x + glyphs[0].i.x,
+ src->y + glyphs[0].i.y,
+ len, buf);
+
+ if (buf != stack_buf)
+ free (buf);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_composite_glyphs (void *closure,
+ cairo_xcb_surface_t *dst,
+ cairo_operator_t op,
+ const cairo_pattern_t *pattern,
+ int dst_x, int dst_y,
+ const cairo_rectangle_int_t *extents,
+ cairo_region_t *clip_region)
+{
+ composite_glyphs_info_t *info = closure;
+ cairo_scaled_glyph_t *glyph_cache[64];
+ cairo_status_t status = CAIRO_STATUS_SUCCESS;
+ cairo_fixed_t x = 0, y = 0;
+ cairo_xcb_font_glyphset_info_t *glyphset_info = NULL, *this_glyphset_info;
+ const unsigned int max_request_size = dst->connection->maximum_request_length - 64;
+ cairo_xcb_picture_t *src;
+
+ unsigned long max_index = 0;
+ int width = 1;
+
+ unsigned int request_size = 0;
+ int i;
+
+ src = _cairo_xcb_picture_for_pattern (dst, pattern, extents);
+ if (unlikely (src->base.status))
+ return src->base.status;
+
+ memset (glyph_cache, 0, sizeof (glyph_cache));
+
+ for (i = 0; i < info->num_glyphs; i++) {
+ cairo_scaled_glyph_t *scaled_glyph;
+ unsigned long glyph_index = info->glyphs[i].index;
+ int cache_index = glyph_index % ARRAY_LENGTH (glyph_cache);
+ int old_width = width;
+ int this_x, this_y;
+
+ scaled_glyph = glyph_cache[cache_index];
+ if (scaled_glyph == NULL ||
+ _cairo_scaled_glyph_index (scaled_glyph) != glyph_index)
+ {
+ status = _cairo_scaled_glyph_lookup (info->font,
+ glyph_index,
+ CAIRO_SCALED_GLYPH_INFO_METRICS,
+ &scaled_glyph);
+ if (unlikely (status))
+ return status;
+
+ /* Send unseen glyphs to the server */
+ if (_cairo_xcb_scaled_glyph_get_glyphset_info (scaled_glyph) == NULL) {
+ status = _cairo_xcb_surface_add_glyph (dst->connection,
+ info->font,
+ &scaled_glyph);
+ if (unlikely (status))
+ return status;
+ }
+
+ glyph_cache[cache_index] = scaled_glyph;
+ }
+
+ /* Glyph skipping:
+ *
+ * We skip any glyphs that have troublesome coordinates. We want
+ * to make sure that (glyph2.x - (glyph1.x + glyph1.width)) fits in
+ * a signed 16bit integer, otherwise it will overflow in the render
+ * protocol.
+ * To ensure this, we'll make sure that (glyph2.x - glyph1.x) fits in
+ * a signed 15bit integer. The trivial option would be to allow
+ * coordinates -8192..8192, but that's kinda dull. It probably will
+ * take a decade or so to get monitors 8192x4096 or something. A
+ * negative value of -8192 on the other hand, is absolutely useless.
+ * Note that we do want to allow some negative positions. The glyph
+ * may start off the screen but part of it make it to the screen.
+ * Anyway, we will allow positions in the range -4096..122887. That
+ * will buy us a few more years before this stops working.
+ */
+ this_x = _cairo_lround (info->glyphs[i].d.x) - dst_x;
+ this_y = _cairo_lround (info->glyphs[i].d.y) - dst_y;
+ assert (! (((this_x+4096) | (this_y+4096)) & ~0x3fffu));
+
+ this_glyphset_info = _cairo_xcb_scaled_glyph_get_glyphset_info (scaled_glyph);
+ if (glyphset_info == NULL)
+ glyphset_info = this_glyphset_info;
+
+ /* Update max glyph index */
+ if (glyph_index > max_index) {
+ max_index = glyph_index;
+ if (max_index >= 65536)
+ width = 4;
+ else if (max_index >= 256)
+ width = 2;
+ if (width != old_width)
+ request_size += (width - old_width) * i;
+ }
+
+ /* If we will pass the max request size by adding this glyph,
+ * flush current glyphs. Note that we account for a
+ * possible element being added below.
+ *
+ * Also flush if changing glyphsets, as Xrender limits one mask
+ * format per request, so we can either break up, or use a
+ * wide-enough mask format. We do the former. One reason to
+ * prefer the latter is the fact that Xserver ADDs all glyphs
+ * to the mask first, and then composes that to final surface,
+ * though it's not a big deal.
+ */
+ if (request_size + width > max_request_size - _cairo_sz_x_glyph_elt_t ||
+ this_glyphset_info != glyphset_info)
+ {
+ status = _emit_glyphs_chunk (dst, op, src,
+ info->glyphs, i,
+ old_width, request_size,
+ glyphset_info);
+ if (unlikely (status))
+ return status;
+
+ info->glyphs += i;
+ info->num_glyphs -= i;
+ i = 0;
+
+ max_index = info->glyphs[0].index;
+ width = max_index < 256 ? 1 : max_index < 65536 ? 2 : 4;
+
+ request_size = 0;
+
+ x = y = 0;
+ glyphset_info = this_glyphset_info;
+ }
+
+ /* Convert absolute glyph position to relative-to-current-point
+ * position */
+ info->glyphs[i].i.x = this_x - x;
+ info->glyphs[i].i.y = this_y - y;
+
+ /* Start a new element for the first glyph,
+ * or for any glyph that has unexpected position,
+ * or if current element has too many glyphs.
+ *
+ * These same conditions are mirrored in _emit_glyphs_chunk().
+ */
+ if (_start_new_glyph_elt (i, &info->glyphs[i]))
+ request_size += _cairo_sz_x_glyph_elt_t;
+
+ /* adjust current-position */
+ x = this_x + scaled_glyph->x_advance;
+ y = this_y + scaled_glyph->y_advance;
+
+ request_size += width;
+ }
+
+ if (i) {
+ status = _emit_glyphs_chunk (dst, op, src,
+ info->glyphs, i,
+ width, request_size,
+ glyphset_info);
+ }
+
+ return status;
+}
+
+cairo_int_status_t
+_cairo_xcb_surface_render_glyphs (cairo_xcb_surface_t *surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_scaled_font_t *scaled_font,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_clip_t *clip)
+{
+ cairo_composite_rectangles_t extents;
+ cairo_clip_t local_clip;
+ cairo_bool_t have_clip = FALSE;
+ cairo_status_t status;
+
+ if (unlikely (! _operator_is_supported (surface->flags, op)))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ if ((surface->flags & (CAIRO_XCB_RENDER_HAS_COMPOSITE_GLYPHS | CAIRO_XCB_RENDER_HAS_COMPOSITE)) == 0)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ status = _cairo_composite_rectangles_init_for_glyphs (&extents,
+ surface->width,
+ surface->height,
+ op, source,
+ scaled_font,
+ glyphs, num_glyphs,
+ clip, NULL);
+ if (unlikely (status))
+ return status;
+
+ if (_cairo_clip_contains_rectangle (clip, &extents))
+ clip = NULL;
+
+ if (clip != NULL) {
+ clip = _cairo_clip_init_copy (&local_clip, clip);
+ have_clip = TRUE;
+ }
+
+ if (clip != NULL && extents.is_bounded) {
+ clip = _cairo_clip_init_copy (&local_clip, clip);
+ status = _cairo_clip_rectangle (clip, &extents.bounded);
+ if (unlikely (status)) {
+ _cairo_clip_fini (&local_clip);
+ return status;
+ }
+ have_clip = TRUE;
+ }
+
+ status = CAIRO_INT_STATUS_UNSUPPORTED;
+ if (surface->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE_GLYPHS) {
+ _cairo_scaled_font_freeze_cache (scaled_font);
+
+ status = _can_composite_glyphs (surface, scaled_font, glyphs, num_glyphs);
+ if (likely (status == CAIRO_STATUS_SUCCESS)) {
+ composite_glyphs_info_t info;
+
+ info.font = scaled_font;
+ info.glyphs = (cairo_xcb_glyph_t *) glyphs;
+ info.num_glyphs = num_glyphs;
+
+ status = _clip_and_composite (surface, op, source,
+ _composite_glyphs, &info,
+ &extents, clip);
+ }
+
+ _cairo_scaled_font_thaw_cache (scaled_font);
+ }
+
+ if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
+ assert (surface->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE);
+ status =
+ _cairo_xcb_surface_render_glyphs_via_mask (surface, op, source,
+ scaled_font, glyphs, num_glyphs,
+ have_clip ? &local_clip : NULL,
+ &extents);
+ }
+
+ if (have_clip)
+ _cairo_clip_fini (&local_clip);
+
+ return status;
+}
diff --git a/src/cairo-xcb-surface.c b/src/cairo-xcb-surface.c
index 666abc9..2e08c64 100644
--- a/src/cairo-xcb-surface.c
+++ b/src/cairo-xcb-surface.c
@@ -1,6 +1,7 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2002 University of Southern California
+ * 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
@@ -31,308 +32,215 @@
* California.
*
* Contributor(s):
+ * Behdad Esfahbod <behdad at behdad.org>
* Carl D. Worth <cworth at cworth.org>
+ * Chris Wilson <chris at chris-wilson.co.uk>
+ * Karl Tomlinson <karlt+ at karlt.net>, Mozilla Corporation
*/
#include "cairoint.h"
-#include "cairo-xcb.h"
-#include "cairo-xcb-xrender.h"
-#include "cairo-clip-private.h"
-#include "cairo-error-private.h"
-#include "cairo-freelist-private.h"
-#include "cairo-list-private.h"
-#include <xcb/xcb_renderutil.h>
-
-#define AllPlanes ((unsigned long)~0L)
-
-slim_hidden_proto (cairo_xcb_surface_create_with_xrender_format);
-
-/*
- * Instead of taking two round trips for each blending request,
- * assume that if a particular drawable fails GetImage that it will
- * fail for a "while"; use temporary pixmaps to avoid the errors
- */
-
-#define CAIRO_ASSUME_PIXMAP 20
-typedef struct cairo_xcb_surface {
- cairo_surface_t base;
-
- xcb_connection_t *dpy;
- xcb_screen_t *screen;
-
- xcb_gcontext_t gc;
- xcb_drawable_t drawable;
- cairo_bool_t owns_pixmap;
- xcb_visualtype_t *visual;
-
- int use_pixmap;
-
- int render_major;
- int render_minor;
-
- int width;
- int height;
- int depth;
-
- cairo_bool_t have_clip_rects;
- xcb_rectangle_t *clip_rects;
- int num_clip_rects;
- cairo_region_t *clip_region;
-
- xcb_render_picture_t src_picture, dst_picture;
- xcb_render_pictforminfo_t xrender_format;
-
- cairo_list_t to_be_checked;
- cairo_freepool_t cookie_pool;
-} cairo_xcb_surface_t;
-
-typedef struct _cairo_xcb_cookie {
- cairo_list_t link;
- xcb_void_cookie_t xcb;
-} cairo_xcb_cookie_t;
-
-#define CAIRO_SURFACE_RENDER_AT_LEAST(surface, major, minor) \
- (((surface)->render_major > major) || \
- (((surface)->render_major == major) && ((surface)->render_minor >= minor)))
-
-#define CAIRO_SURFACE_RENDER_HAS_CREATE_PICTURE(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 0)
-#define CAIRO_SURFACE_RENDER_HAS_COMPOSITE(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 0)
-#define CAIRO_SURFACE_RENDER_HAS_COMPOSITE_TEXT(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 0)
+#include "cairo-xcb.h"
+#include "cairo-xcb-private.h"
-#define CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLE(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 1)
-#define CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLES(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 1)
+#include <xcb/dri2.h>
-#define CAIRO_SURFACE_RENDER_HAS_DISJOINT(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 2)
-#define CAIRO_SURFACE_RENDER_HAS_CONJOINT(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 2)
+#define AllPlanes ((unsigned) -1)
+#define CAIRO_ASSUME_PIXMAP 20
+#define XLIB_COORD_MAX 32767
-#define CAIRO_SURFACE_RENDER_HAS_TRAPEZOIDS(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4)
-#define CAIRO_SURFACE_RENDER_HAS_TRIANGLES(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4)
-#define CAIRO_SURFACE_RENDER_HAS_TRISTRIP(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4)
-#define CAIRO_SURFACE_RENDER_HAS_TRIFAN(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4)
+#if CAIRO_HAS_XLIB_XCB_FUNCTIONS
+slim_hidden_proto (cairo_xcb_surface_create);
+slim_hidden_proto (cairo_xcb_surface_create_for_bitmap);
+slim_hidden_proto (cairo_xcb_surface_create_with_xrender_format);
+#endif
-#define CAIRO_SURFACE_RENDER_HAS_PICTURE_TRANSFORM(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 6)
-#define CAIRO_SURFACE_RENDER_HAS_FILTERS(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 6)
-#define CAIRO_SURFACE_RENDER_HAS_REPEAT_PAD(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 10)
-#define CAIRO_SURFACE_RENDER_HAS_REPEAT_REFLECT(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 10)
+#if CAIRO_HAS_DRM_SURFACE && CAIRO_HAS_XCB_DRM_FUNCTIONS
+#include "drm/cairo-drm-private.h"
+#endif
static cairo_status_t
-_cairo_xcb_surface_ensure_gc (cairo_xcb_surface_t *surface);
-
-static int
-_CAIRO_FORMAT_DEPTH (cairo_format_t format)
+_cairo_xcb_surface_create_similar_shm (cairo_xcb_surface_t *other,
+ pixman_format_code_t pixman_format,
+ int width, int height,
+ cairo_surface_t **out)
{
- switch (format) {
- case CAIRO_FORMAT_A1:
- return 1;
- case CAIRO_FORMAT_A8:
- return 8;
- case CAIRO_FORMAT_RGB24:
- return 24;
- case CAIRO_FORMAT_ARGB32:
- default:
- return 32;
- }
-}
+ size_t size, stride;
+ cairo_xcb_shm_info_t *shm_info;
+ cairo_status_t status;
+ cairo_surface_t *image;
-static cairo_status_t
-_cairo_xcb_add_cookie_to_be_checked (cairo_xcb_surface_t *surface,
- xcb_void_cookie_t xcb)
-{
- cairo_xcb_cookie_t *cookie;
+ stride = CAIRO_STRIDE_FOR_WIDTH_BPP (width, PIXMAN_FORMAT_BPP (pixman_format));
+ size = stride * height;
+ if (size < CAIRO_XCB_SHM_SMALL_IMAGE)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
- cookie = _cairo_freepool_alloc (&surface->cookie_pool);
- if (unlikely (cookie == NULL))
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ status = _cairo_xcb_connection_allocate_shm_info (other->connection,
+ size, &shm_info);
+ if (unlikely (status))
+ return status;
+
+ image = _cairo_image_surface_create_with_pixman_format (shm_info->mem,
+ pixman_format,
+ width, height,
+ stride);
+ status = image->status;
+ if (unlikely (status)) {
+ _cairo_xcb_shm_info_destroy (shm_info);
+ return status;
+ }
- cookie->xcb = xcb;
- cairo_list_add_tail (&cookie->link, &surface->to_be_checked);
+ status = _cairo_user_data_array_set_data (&image->user_data,
+ (const cairo_user_data_key_t *) other->connection,
+ shm_info,
+ (cairo_destroy_func_t) _cairo_xcb_shm_info_destroy);
+ if (unlikely (status)) {
+ cairo_surface_destroy (image);
+ _cairo_xcb_shm_info_destroy (shm_info);
+ return status;
+ }
+ *out = image;
return CAIRO_STATUS_SUCCESS;
}
-static xcb_render_pictforminfo_t *
-_CAIRO_FORMAT_TO_XRENDER_FORMAT(xcb_connection_t *dpy, cairo_format_t format)
+cairo_surface_t *
+_cairo_xcb_surface_create_similar_image (cairo_xcb_surface_t *other,
+ cairo_content_t content,
+ int width, int height)
{
- xcb_pict_standard_t std_format;
- switch (format) {
- case CAIRO_FORMAT_A1:
- std_format = XCB_PICT_STANDARD_A_1; break;
- case CAIRO_FORMAT_A8:
- std_format = XCB_PICT_STANDARD_A_8; break;
- case CAIRO_FORMAT_RGB24:
- std_format = XCB_PICT_STANDARD_RGB_24; break;
- case CAIRO_FORMAT_ARGB32:
+ cairo_surface_t *image = NULL;
+ pixman_format_code_t pixman_format;
+
+ /* XXX choose pixman_format from connection->image_formats */
+ switch (content) {
+ case CAIRO_CONTENT_ALPHA:
+ pixman_format = PIXMAN_a8;
+ break;
+ case CAIRO_CONTENT_COLOR:
+ pixman_format = PIXMAN_x8r8g8b8;
+ break;
default:
- std_format = XCB_PICT_STANDARD_ARGB_32; break;
+ ASSERT_NOT_REACHED;
+ case CAIRO_CONTENT_COLOR_ALPHA:
+ pixman_format = PIXMAN_a8r8g8b8;
+ break;
}
- return xcb_render_util_find_standard_format (xcb_render_util_query_formats (dpy), std_format);
-}
-static cairo_content_t
-_xcb_render_format_to_content (xcb_render_pictforminfo_t *xrender_format)
-{
- cairo_bool_t xrender_format_has_alpha;
- cairo_bool_t xrender_format_has_color;
-
- /* This only happens when using a non-Render server. Let's punt
- * and say there's no alpha here. */
- if (xrender_format == NULL)
- return CAIRO_CONTENT_COLOR;
-
- xrender_format_has_alpha = (xrender_format->direct.alpha_mask != 0);
- xrender_format_has_color = (xrender_format->direct.red_mask != 0 ||
- xrender_format->direct.green_mask != 0 ||
- xrender_format->direct.blue_mask != 0);
-
- if (xrender_format_has_alpha)
- if (xrender_format_has_color)
- return CAIRO_CONTENT_COLOR_ALPHA;
- else
- return CAIRO_CONTENT_ALPHA;
- else
- return CAIRO_CONTENT_COLOR;
-}
-
-static cairo_status_t
-_cairo_xcb_surface_set_gc_clip_rects (cairo_xcb_surface_t *surface)
-{
- if (surface->have_clip_rects) {
- xcb_void_cookie_t cookie;
+ if (other->flags & CAIRO_XCB_HAS_SHM) {
+ cairo_status_t status;
- cookie = xcb_set_clip_rectangles_checked (surface->dpy,
- XCB_CLIP_ORDERING_YX_SORTED, surface->gc,
- 0, 0,
- surface->num_clip_rects,
- surface->clip_rects);
+ status = _cairo_xcb_surface_create_similar_shm (other,
+ pixman_format,
+ width, height,
+ &image);
+ if (_cairo_status_is_error (status))
+ return _cairo_surface_create_in_error (status);
+ }
- return _cairo_xcb_add_cookie_to_be_checked (surface, cookie);
+ if (image == NULL) {
+ image = _cairo_image_surface_create_with_pixman_format (NULL,
+ pixman_format,
+ width, height,
+ 0);
}
- return CAIRO_STATUS_SUCCESS;
+ return image;
}
-static cairo_status_t
-_cairo_xcb_surface_set_picture_clip_rects (cairo_xcb_surface_t *surface)
+cairo_surface_t *
+_cairo_xcb_surface_create_similar (void *abstract_other,
+ cairo_content_t content,
+ int width,
+ int height)
{
- if (surface->have_clip_rects) {
- xcb_void_cookie_t cookie;
+ cairo_xcb_surface_t *other = abstract_other;
+ cairo_xcb_surface_t *surface;
+ cairo_xcb_connection_t *connection;
+ xcb_pixmap_t pixmap;
+ cairo_status_t status;
- cookie = xcb_render_set_picture_clip_rectangles_checked (surface->dpy,
- surface->dst_picture,
- 0, 0,
- surface->num_clip_rects,
- surface->clip_rects);
+ if (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX)
+ return NULL;
- return _cairo_xcb_add_cookie_to_be_checked (surface, cookie);
- }
+ if (width <= 0 || height <= 0)
+ return NULL;
- return CAIRO_STATUS_SUCCESS;
-}
+#if CAIRO_HAS_DRM_SURFACE && CAIRO_HAS_XCB_DRM_FUNCTIONS
+ if (other->drm != NULL) {
+ cairo_surface_t *drm;
-static cairo_status_t
-_cairo_xcb_surface_set_clip_region (void *abstract_surface,
- cairo_region_t *region)
-{
- cairo_xcb_surface_t *surface = abstract_surface;
+ drm = _cairo_drm_surface_create_similar (other->drm, content, width, height);
+ if (drm != NULL)
+ return drm;
+ }
+#endif
- if (region == surface->clip_region)
- return CAIRO_STATUS_SUCCESS;
+ if ((other->flags & CAIRO_XCB_HAS_RENDER) == 0)
+ return _cairo_xcb_surface_create_similar_image (other, content, width, height);
- cairo_region_destroy (surface->clip_region);
- region = cairo_region_reference (region);
+ connection = other->connection;
+ status = _cairo_xcb_connection_acquire (connection);
+ if (unlikely (status))
+ return _cairo_surface_create_in_error (status);
- if (surface->clip_rects) {
- free (surface->clip_rects);
- surface->clip_rects = NULL;
+ status =_cairo_xcb_connection_take_socket (connection);
+ if (unlikely (status)) {
+ _cairo_xcb_connection_release (connection);
+ return _cairo_surface_create_in_error (status);
}
- surface->have_clip_rects = FALSE;
- surface->num_clip_rects = 0;
-
- if (region == NULL) {
- uint32_t none[] = { XCB_NONE };
- if (surface->gc)
- xcb_change_gc (surface->dpy, surface->gc, XCB_GC_CLIP_MASK, none);
+ if (content == other->base.content) {
+ pixmap = _cairo_xcb_connection_create_pixmap (connection,
+ other->depth,
+ other->drawable,
+ width, height);
- if (surface->xrender_format.id != XCB_NONE && surface->dst_picture)
- xcb_render_change_picture (surface->dpy, surface->dst_picture,
- XCB_RENDER_CP_CLIP_MASK, none);
+ surface = (cairo_xcb_surface_t *)
+ _cairo_xcb_surface_create_internal (other->screen,
+ pixmap, TRUE,
+ other->pixman_format,
+ other->xrender_format,
+ width, height);
} else {
- xcb_rectangle_t *rects = NULL;
- int n_rects, i;
-
- n_rects = cairo_region_num_rectangles (region);
-
- if (n_rects > 0) {
- rects = _cairo_malloc_ab (n_rects, sizeof(xcb_rectangle_t));
- if (rects == NULL)
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
- } else {
- rects = NULL;
- }
-
- for (i = 0; i < n_rects; i++) {
- cairo_rectangle_int_t rect;
-
- cairo_region_get_rectangle (region, i, &rect);
-
- rects[i].x = rect.x;
- rects[i].y = rect.y;
- rects[i].width = rect.width;
- rects[i].height = rect.height;
+ cairo_format_t format;
+ pixman_format_code_t pixman_format;
+
+ /* XXX find a compatible xrender format */
+ switch (content) {
+ case CAIRO_CONTENT_ALPHA:
+ pixman_format = PIXMAN_a8;
+ format = CAIRO_FORMAT_A8;
+ break;
+ case CAIRO_CONTENT_COLOR:
+ pixman_format = PIXMAN_x8r8g8b8;
+ format = CAIRO_FORMAT_RGB24;
+ break;
+ default:
+ ASSERT_NOT_REACHED;
+ case CAIRO_CONTENT_COLOR_ALPHA:
+ pixman_format = PIXMAN_a8r8g8b8;
+ format = CAIRO_FORMAT_ARGB32;
+ break;
}
- surface->have_clip_rects = TRUE;
- surface->clip_rects = rects;
- surface->num_clip_rects = n_rects;
-
- if (surface->gc)
- _cairo_xcb_surface_set_gc_clip_rects (surface);
-
- if (surface->dst_picture)
- _cairo_xcb_surface_set_picture_clip_rects (surface);
- }
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_surface_t *
-_cairo_xcb_surface_create_similar (void *abstract_src,
- cairo_content_t content,
- int width,
- int height)
-{
- cairo_xcb_surface_t *src = abstract_src;
- xcb_connection_t *dpy = src->dpy;
- xcb_pixmap_t pixmap;
- cairo_xcb_surface_t *surface;
- cairo_format_t format = _cairo_format_from_content (content);
- xcb_render_pictforminfo_t *xrender_format;
+ pixmap = _cairo_xcb_connection_create_pixmap (connection,
+ PIXMAN_FORMAT_DEPTH (pixman_format),
+ other->drawable,
+ width, height);
- /* As a good first approximation, if the display doesn't have COMPOSITE,
- * we're better off using image surfaces for all temporary operations
- */
- if (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE (src)) {
- return cairo_image_surface_create (format, width, height);
+ surface = (cairo_xcb_surface_t *)
+ _cairo_xcb_surface_create_internal (other->screen,
+ pixmap, TRUE,
+ pixman_format,
+ connection->standard_formats[format],
+ width, height);
}
- pixmap = xcb_generate_id (dpy);
- xcb_create_pixmap (dpy, _CAIRO_FORMAT_DEPTH (format),
- pixmap, src->drawable,
- width <= 0 ? 1 : width,
- height <= 0 ? 1 : height);
-
- xrender_format = _CAIRO_FORMAT_TO_XRENDER_FORMAT (dpy, format);
- /* XXX: what to do if xrender_format is null? */
- surface = (cairo_xcb_surface_t *)
- cairo_xcb_surface_create_with_xrender_format (dpy, pixmap, src->screen,
- xrender_format,
- width, height);
- if (surface->base.status)
- return &surface->base;
+ if (unlikely (surface->base.status))
+ _cairo_xcb_connection_free_pixmap (connection, pixmap);
- surface->owns_pixmap = TRUE;
+ _cairo_xcb_connection_release (connection);
return &surface->base;
}
@@ -341,1826 +249,958 @@ static cairo_status_t
_cairo_xcb_surface_finish (void *abstract_surface)
{
cairo_xcb_surface_t *surface = abstract_surface;
+ cairo_status_t status;
- if (surface->dst_picture != XCB_NONE)
- xcb_render_free_picture (surface->dpy, surface->dst_picture);
-
- if (surface->src_picture != XCB_NONE)
- xcb_render_free_picture (surface->dpy, surface->src_picture);
-
- if (surface->owns_pixmap)
- xcb_free_pixmap (surface->dpy, surface->drawable);
+ assert (surface->fallback == NULL);
- if (surface->gc != XCB_NONE)
- xcb_free_gc (surface->dpy, surface->gc);
+ cairo_list_del (&surface->link);
- free (surface->clip_rects);
- cairo_region_destroy (surface->clip_region);
+ if (surface->drm != NULL) {
+ cairo_surface_finish (surface->drm);
+ cairo_surface_destroy (surface->drm);
- _cairo_freepool_fini (&surface->cookie_pool);
+ xcb_dri2_destroy_drawable (surface->connection->xcb_connection,
+ surface->drawable);
+ }
- surface->dpy = NULL;
+ status = _cairo_xcb_connection_acquire (surface->connection);
+ if (status == CAIRO_STATUS_SUCCESS) {
+ if (_cairo_xcb_connection_take_socket (surface->connection) == CAIRO_STATUS_SUCCESS) {
+ if (surface->picture != XCB_NONE) {
+ _cairo_xcb_connection_render_free_picture (surface->connection,
+ surface->picture);
+ }
- return CAIRO_STATUS_SUCCESS;
-}
+ if (surface->owns_pixmap)
+ _cairo_xcb_connection_free_pixmap (surface->connection, surface->drawable);
+ }
+ _cairo_xcb_connection_release (surface->connection);
+ }
-static int
-_bits_per_pixel(xcb_connection_t *c, int depth)
-{
- xcb_format_t *fmt = xcb_setup_pixmap_formats(xcb_get_setup(c));
- xcb_format_t *fmtend = fmt + xcb_setup_pixmap_formats_length(xcb_get_setup(c));
-
- for(; fmt != fmtend; ++fmt)
- if(fmt->depth == depth)
- return fmt->bits_per_pixel;
-
- if(depth <= 4)
- return 4;
- if(depth <= 8)
- return 8;
- if(depth <= 16)
- return 16;
- return 32;
-}
+ _cairo_xcb_connection_destroy (surface->connection);
-static int
-_bytes_per_line(xcb_connection_t *c, int width, int bpp)
-{
- int bitmap_pad = xcb_get_setup(c)->bitmap_format_scanline_pad;
- return ((bpp * width + bitmap_pad - 1) & -bitmap_pad) >> 3;
+ return status;
}
-static cairo_bool_t
-_CAIRO_MASK_FORMAT (cairo_format_masks_t *masks, cairo_format_t *format)
+static void
+_destroy_image (pixman_image_t *image, void *data)
{
- switch (masks->bpp) {
- case 32:
- if (masks->alpha_mask == 0xff000000 &&
- masks->red_mask == 0x00ff0000 &&
- masks->green_mask == 0x0000ff00 &&
- masks->blue_mask == 0x000000ff)
- {
- *format = CAIRO_FORMAT_ARGB32;
- return TRUE;
- }
- if (masks->alpha_mask == 0x00000000 &&
- masks->red_mask == 0x00ff0000 &&
- masks->green_mask == 0x0000ff00 &&
- masks->blue_mask == 0x000000ff)
- {
- *format = CAIRO_FORMAT_RGB24;
- return TRUE;
- }
- break;
- case 8:
- if (masks->alpha_mask == 0xff)
- {
- *format = CAIRO_FORMAT_A8;
- return TRUE;
- }
- break;
- case 1:
- if (masks->alpha_mask == 0x1)
- {
- *format = CAIRO_FORMAT_A1;
- return TRUE;
- }
- break;
- }
- return FALSE;
+ free (data);
}
-static cairo_status_t
-_get_image_surface (cairo_xcb_surface_t *surface,
- cairo_rectangle_int_t *interest_rect,
- cairo_image_surface_t **image_out,
- cairo_rectangle_int_t *image_rect)
+static cairo_int_status_t
+_cairo_xcb_surface_create_shm_image (cairo_xcb_surface_t *target,
+ cairo_image_surface_t **image_out,
+ cairo_xcb_shm_info_t **shm_info_out)
{
cairo_image_surface_t *image;
- xcb_get_image_reply_t *imagerep;
- int bpp, bytes_per_line;
- cairo_rectangle_int_t extents;
- unsigned char *data;
- cairo_format_masks_t masks;
- cairo_format_t format;
-
- extents.x = 0;
- extents.y = 0;
- extents.width = surface->width;
- extents.height = surface->height;
-
- if (interest_rect) {
- if (! _cairo_rectangle_intersect (&extents, interest_rect)) {
- *image_out = NULL;
- return CAIRO_STATUS_SUCCESS;
- }
- }
-
- if (image_rect)
- *image_rect = extents;
-
- /* XXX: This should try to use the XShm extension if available */
-
- if (surface->use_pixmap == 0)
- {
- xcb_generic_error_t *error;
-
- imagerep = xcb_get_image_reply (surface->dpy,
- xcb_get_image (surface->dpy,
- XCB_IMAGE_FORMAT_Z_PIXMAP,
- surface->drawable,
- extents.x, extents.y,
- extents.width, extents.height,
- AllPlanes),
- &error);
-
- /* If we get an error, the surface must have been a window,
- * so retry with the safe code path.
- */
- if (error)
- surface->use_pixmap = CAIRO_ASSUME_PIXMAP;
- }
- else
- {
- surface->use_pixmap--;
- imagerep = NULL;
- }
-
- if (!imagerep)
- {
- /* xcb_get_image_t from a window is dangerous because it can
- * produce errors if the window is unmapped or partially
- * outside the screen. We could check for errors and
- * retry, but to keep things simple, we just create a
- * temporary pixmap
- */
- xcb_pixmap_t pixmap;
- cairo_xcb_cookie_t *cookies[2];
- cairo_status_t status;
-
- status = _cairo_xcb_surface_ensure_gc (surface);
- if (unlikely (status))
- return status;
-
- status = _cairo_freepool_alloc_array (&surface->cookie_pool,
- ARRAY_LENGTH (cookies),
- (void **) cookies);
- if (unlikely (status))
- return status;
-
- pixmap = xcb_generate_id (surface->dpy);
- cookies[0]->xcb = xcb_create_pixmap_checked (surface->dpy,
- surface->depth,
- pixmap,
- surface->drawable,
- extents.width, extents.height);
- cairo_list_add_tail (&cookies[0]->link, &surface->to_be_checked);
-
- cookies[1]->xcb = xcb_copy_area_checked (surface->dpy,
- surface->drawable,
- pixmap, surface->gc,
- extents.x, extents.y,
- 0, 0,
- extents.width, extents.height);
- cairo_list_add_tail (&cookies[1]->link, &surface->to_be_checked);
-
- imagerep = xcb_get_image_reply (surface->dpy,
- xcb_get_image (surface->dpy,
- XCB_IMAGE_FORMAT_Z_PIXMAP,
- pixmap,
- extents.x, extents.y,
- extents.width, extents.height,
- AllPlanes),
- 0);
-
- xcb_free_pixmap (surface->dpy, pixmap);
-
- }
- if (unlikely (imagerep == NULL))
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ cairo_xcb_shm_info_t *shm_info;
+ cairo_status_t status;
+ size_t size, stride;
- bpp = _bits_per_pixel(surface->dpy, imagerep->depth);
- bytes_per_line = _bytes_per_line(surface->dpy, surface->width, bpp);
+ if ((target->flags & CAIRO_XCB_HAS_SHM) == 0)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
- data = _cairo_malloc_ab (surface->height, bytes_per_line);
- if (data == NULL) {
- free (imagerep);
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ stride = CAIRO_STRIDE_FOR_WIDTH_BPP (target->width,
+ PIXMAN_FORMAT_BPP (target->pixman_format));
+ size = stride * target->height;
+ if (size < CAIRO_XCB_SHM_SMALL_IMAGE) {
+ target->flags &= ~CAIRO_XCB_HAS_SHM;
+ return CAIRO_INT_STATUS_UNSUPPORTED;
}
- memcpy (data, xcb_get_image_data (imagerep), bytes_per_line * surface->height);
- free (imagerep);
+ status = _cairo_xcb_connection_allocate_shm_info (target->screen->connection,
+ size, &shm_info);
+ if (unlikely (status))
+ return status;
- /*
- * Compute the pixel format masks from either an xcb_visualtype_t or
- * a xcb_render_pctforminfo_t, failing we assume the drawable is an
- * alpha-only pixmap as it could only have been created that way
- * through the cairo_xlib_surface_create_for_bitmap function.
- */
- if (surface->visual) {
- masks.bpp = bpp;
- masks.alpha_mask = 0;
- masks.red_mask = surface->visual->red_mask;
- masks.green_mask = surface->visual->green_mask;
- masks.blue_mask = surface->visual->blue_mask;
- } else if (surface->xrender_format.id != XCB_NONE) {
- masks.bpp = bpp;
- masks.red_mask = (unsigned long)surface->xrender_format.direct.red_mask << surface->xrender_format.direct.red_shift;
- masks.green_mask = (unsigned long)surface->xrender_format.direct.green_mask << surface->xrender_format.direct.green_shift;
- masks.blue_mask = (unsigned long)surface->xrender_format.direct.blue_mask << surface->xrender_format.direct.blue_shift;
- masks.alpha_mask = (unsigned long)surface->xrender_format.direct.alpha_mask << surface->xrender_format.direct.alpha_shift;
- } else {
- masks.bpp = bpp;
- masks.red_mask = 0;
- masks.green_mask = 0;
- masks.blue_mask = 0;
- if (surface->depth < 32)
- masks.alpha_mask = (1 << surface->depth) - 1;
- else
- masks.alpha_mask = 0xffffffff;
+ image = (cairo_image_surface_t *)
+ _cairo_image_surface_create_with_pixman_format (shm_info->mem,
+ target->pixman_format,
+ target->width,
+ target->height,
+ stride);
+ status = image->base.status;
+ if (unlikely (status)) {
+ _cairo_xcb_shm_info_destroy (shm_info);
+ return status;
}
- /*
- * Prefer to use a standard pixman format instead of the
- * general masks case.
- */
- if (_CAIRO_MASK_FORMAT (&masks, &format)) {
- image = (cairo_image_surface_t *)
- cairo_image_surface_create_for_data (data,
- format,
- extents.width,
- extents.height,
- bytes_per_line);
- if (image->base.status)
- goto FAIL;
- } else {
- /*
- * XXX This can't work. We must convert the data to one of the
- * supported pixman formats. Pixman needs another function
- * which takes data in an arbitrary format and converts it
- * to something supported by that library.
- */
- ASSERT_NOT_REACHED;
- goto FAIL;
+ status = _cairo_user_data_array_set_data (&image->base.user_data,
+ (const cairo_user_data_key_t *) target->connection,
+ shm_info,
+ (cairo_destroy_func_t) _cairo_xcb_shm_info_destroy);
+ if (unlikely (status)) {
+ cairo_surface_destroy (&image->base);
+ _cairo_xcb_shm_info_destroy (shm_info);
+ return status;
}
- /* Let the surface take ownership of the data */
- _cairo_image_surface_assume_ownership_of_data (image);
-
*image_out = image;
+ *shm_info_out = shm_info;
return CAIRO_STATUS_SUCCESS;
-
- FAIL:
- free (data);
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
static cairo_status_t
-_cairo_xcb_surface_ensure_src_picture (cairo_xcb_surface_t *surface)
+_get_shm_image (cairo_xcb_surface_t *surface,
+ cairo_image_surface_t **image_out)
{
- if (!surface->src_picture) {
- xcb_void_cookie_t cookie;
+ cairo_image_surface_t *image;
+ cairo_xcb_shm_info_t *shm_info;
+ cairo_status_t status;
- surface->src_picture = xcb_generate_id (surface->dpy);
- cookie = xcb_render_create_picture_checked (surface->dpy,
- surface->src_picture,
- surface->drawable,
- surface->xrender_format.id,
- 0, NULL);
+ status = _cairo_xcb_surface_create_shm_image (surface, &image, &shm_info);
+ if (unlikely (status))
+ return status;
- return _cairo_xcb_add_cookie_to_be_checked (surface, cookie);
+ if (! surface->base.is_clear) {
+ status = _cairo_xcb_connection_shm_get_image (surface->connection,
+ surface->drawable,
+ 0, 0,
+ surface->width,
+ surface->height,
+ shm_info->shm,
+ shm_info->offset);
+ if (unlikely (status))
+ return status;
+ } else {
+ memset (image->data, 0, image->stride * image->height);
}
+ *image_out = image;
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
-_cairo_xcb_surface_ensure_dst_picture (cairo_xcb_surface_t *surface)
+_get_image (cairo_xcb_surface_t *surface,
+ cairo_bool_t use_shm,
+ cairo_image_surface_t **image_out)
{
- if (!surface->dst_picture) {
- xcb_void_cookie_t cookie;
+ cairo_image_surface_t *image;
+ cairo_xcb_connection_t *connection;
+ xcb_get_image_reply_t *reply;
+ cairo_status_t status;
+
+ connection = surface->connection;
+
+ status = _cairo_xcb_connection_acquire (connection);
+ if (unlikely (status))
+ return status;
- surface->dst_picture = xcb_generate_id (surface->dpy);
- cookie = xcb_render_create_picture_checked (surface->dpy,
- surface->dst_picture,
- surface->drawable,
- surface->xrender_format.id,
- 0, NULL);
+ status = _cairo_xcb_connection_take_socket (connection);
+ if (unlikely (status))
+ goto FAIL;
- return _cairo_xcb_add_cookie_to_be_checked (surface, cookie);
+ if (use_shm) {
+ status = _get_shm_image (surface, image_out);
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+ goto FAIL;
}
- return CAIRO_STATUS_SUCCESS;
-}
+ if (surface->base.is_clear) {
+ image = (cairo_image_surface_t *)
+ _cairo_image_surface_create_with_pixman_format (NULL,
+ surface->pixman_format,
+ surface->width,
+ surface->height,
+ 0);
+ status = image->base.status;
+ *image_out = image;
+ goto FAIL;
+ }
-static cairo_status_t
-_cairo_xcb_surface_ensure_gc (cairo_xcb_surface_t *surface)
-{
- xcb_void_cookie_t cookie;
+ if (surface->use_pixmap == 0) {
+ status = _cairo_xcb_connection_get_image (connection,
+ surface->drawable,
+ 0, 0,
+ surface->width,
+ surface->height,
+ &reply);
+ if (unlikely (status))
+ goto FAIL;
+ } else {
+ surface->use_pixmap--;
+ reply = NULL;
+ }
- if (surface->gc)
- return CAIRO_STATUS_SUCCESS;
+ if (reply == NULL && ! surface->owns_pixmap) {
+ /* xcb_get_image_t from a window is dangerous because it can
+ * produce errors if the window is unmapped or partially
+ * outside the screen. We could check for errors and
+ * retry, but to keep things simple, we just create a
+ * temporary pixmap
+ */
+ xcb_pixmap_t pixmap;
+ xcb_gcontext_t gc;
+
+ gc = _cairo_xcb_screen_get_gc (surface->screen,
+ surface->drawable,
+ surface->depth);
+ pixmap = _cairo_xcb_connection_create_pixmap (connection,
+ surface->depth,
+ surface->drawable,
+ surface->width,
+ surface->height);
+
+ /* XXX IncludeInferiors? */
+ _cairo_xcb_connection_copy_area (connection,
+ surface->drawable,
+ pixmap, gc,
+ 0, 0,
+ 0, 0,
+ surface->width,
+ surface->height);
- surface->gc = xcb_generate_id(surface->dpy);
- cookie = xcb_create_gc_checked (surface->dpy, surface->gc, surface->drawable, 0, 0);
- _cairo_xcb_surface_set_gc_clip_rects (surface);
+ _cairo_xcb_screen_put_gc (surface->screen, surface->depth, gc);
- return _cairo_xcb_add_cookie_to_be_checked (surface, cookie);
-}
+ status = _cairo_xcb_connection_get_image (connection,
+ pixmap,
+ 0, 0,
+ surface->width,
+ surface->height,
+ &reply);
+ _cairo_xcb_connection_free_pixmap (connection, pixmap);
-static cairo_status_t
-_draw_image_surface (cairo_xcb_surface_t *surface,
- cairo_image_surface_t *image,
- int src_x,
- int src_y,
- int width,
- int height,
- int dst_x,
- int dst_y)
-{
- int bpp, bpl;
- uint32_t data_len;
- uint8_t *data, left_pad=0;
- xcb_void_cookie_t cookie;
-
- /* equivalent of XPutImage(..., src_x,src_y, dst_x,dst_y, width,height); */
- /* XXX: assumes image and surface formats and depths are the same */
- /* XXX: assumes depth is a multiple of 8 (not bitmap) */
-
- /* fit src_{x,y,width,height} within image->{0,0,width,height} */
- if (src_x < 0) {
- width += src_x;
- src_x = 0;
+ if (unlikely (status))
+ goto FAIL;
}
- if (src_y < 0) {
- height += src_y;
- src_y = 0;
+
+ if (unlikely (reply == NULL)) {
+ status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ goto FAIL;
}
- if (width + src_x > image->width)
- width = image->width - src_x;
- if (height + src_y > image->height)
- height = image->height - src_y;
- if (width <= 0 || height <= 0)
- return CAIRO_STATUS_SUCCESS;
- bpp = _bits_per_pixel(surface->dpy, image->depth);
- /* XXX: could use bpl = image->stride? */
- bpl = _bytes_per_line(surface->dpy, image->width, bpp);
+ /* XXX byte swap */
+ /* XXX format conversion */
+ assert (reply->depth == surface->depth);
- if (src_x == 0 && width == image->width) {
- /* can work in-place */
- data_len = height * bpl;
- data = image->data + src_y * bpl;
- } else {
- /* must copy {src_x,src_y,width,height} into new data */
- int line = 0;
- uint8_t *data_line, *image_line;
- int data_bpl = _bytes_per_line(surface->dpy, width, bpp);
- data_len = height * data_bpl;
- data_line = data = malloc(data_len);
- if (data == NULL)
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
- image_line = image->data + src_y * bpl + (src_x * bpp / 8);
- while (line++ < height) {
- memcpy(data_line, image_line, data_bpl);
- data_line += data_bpl;
- image_line += bpl;
- }
+ image = (cairo_image_surface_t *)
+ _cairo_image_surface_create_with_pixman_format
+ (xcb_get_image_data (reply),
+ surface->pixman_format,
+ surface->width,
+ surface->height,
+ CAIRO_STRIDE_FOR_WIDTH_BPP (surface->width,
+ PIXMAN_FORMAT_BPP (surface->pixman_format)));
+ status = image->base.status;
+ if (unlikely (status)) {
+ free (reply);
+ goto FAIL;
}
- _cairo_xcb_surface_ensure_gc (surface);
- cookie = xcb_put_image_checked (surface->dpy, XCB_IMAGE_FORMAT_Z_PIXMAP,
- surface->drawable, surface->gc,
- width, height,
- dst_x, dst_y,
- left_pad, image->depth,
- data_len, data);
-
- if (data < image->data || data >= image->data + image->height * bpl)
- free (data);
-
- return _cairo_xcb_add_cookie_to_be_checked (surface, cookie);
-}
-static cairo_status_t
-_cairo_xcb_surface_acquire_source_image (void *abstract_surface,
- cairo_image_surface_t **image_out,
- void **image_extra)
-{
- cairo_xcb_surface_t *surface = abstract_surface;
- cairo_image_surface_t *image;
- cairo_status_t status;
+ assert (xcb_get_image_data_length (reply) == image->height * image->stride);
- status = _get_image_surface (surface, NULL, &image, NULL);
- if (status)
- return status;
+ pixman_image_set_destroy_function (image->pixman_image, _destroy_image, reply);
- *image_out = image;
- *image_extra = NULL;
+ _cairo_xcb_connection_release (connection);
+
+ /* synchronisation point */
+ surface->marked_dirty = FALSE;
+ *image_out = image;
return CAIRO_STATUS_SUCCESS;
+
+FAIL:
+ _cairo_xcb_connection_release (connection);
+ return status;
}
-static cairo_surface_t *
-_cairo_xcb_surface_snapshot (void *abstract_surface)
+static cairo_status_t
+_cairo_xcb_surface_acquire_source_image (void *abstract_surface,
+ cairo_image_surface_t **image_out,
+ void **image_extra)
{
cairo_xcb_surface_t *surface = abstract_surface;
cairo_image_surface_t *image;
cairo_status_t status;
- status = _get_image_surface (surface, NULL, &image, NULL);
- if (unlikely (status))
- return _cairo_surface_create_in_error (status);
+ if (surface->drm != NULL && ! surface->marked_dirty) {
+ return _cairo_surface_acquire_source_image (surface->drm,
+ image_out, image_extra);
+ }
- return &image->base;
-}
+ if (surface->fallback != NULL) {
+ image = (cairo_image_surface_t *) cairo_surface_reference (surface->fallback);
+ goto DONE;
+ }
-static void
-_cairo_xcb_surface_release_source_image (void *abstract_surface,
- cairo_image_surface_t *image,
- void *image_extra)
-{
- cairo_surface_destroy (&image->base);
-}
+ image = (cairo_image_surface_t *)
+ _cairo_surface_has_snapshot (&surface->base,
+ &_cairo_image_surface_backend);
+ if (image != NULL) {
+ image = (cairo_image_surface_t *) cairo_surface_reference (&image->base);
+ goto DONE;
+ }
-static cairo_status_t
-_cairo_xcb_surface_acquire_dest_image (void *abstract_surface,
- cairo_rectangle_int_t *interest_rect,
- cairo_image_surface_t **image_out,
- cairo_rectangle_int_t *image_rect_out,
- void **image_extra)
-{
- cairo_xcb_surface_t *surface = abstract_surface;
- cairo_image_surface_t *image;
- cairo_status_t status;
+ status = _get_image (surface, FALSE, &image);
+ if (unlikely (status))
+ return status;
- status = _get_image_surface (surface, interest_rect, &image, image_rect_out);
- if (status)
+ status = _cairo_surface_attach_snapshot (&surface->base, &image->base, NULL);
+ if (unlikely (status)) {
+ cairo_surface_destroy (&image->base);
return status;
+ }
+DONE:
*image_out = image;
*image_extra = NULL;
-
return CAIRO_STATUS_SUCCESS;
}
static void
-_cairo_xcb_surface_release_dest_image (void *abstract_surface,
- cairo_rectangle_int_t *interest_rect,
- cairo_image_surface_t *image,
- cairo_rectangle_int_t *image_rect,
- void *image_extra)
+_cairo_xcb_surface_release_source_image (void *abstract_surface,
+ cairo_image_surface_t *image,
+ void *image_extra)
{
cairo_xcb_surface_t *surface = abstract_surface;
- /* ignore errors */
- _draw_image_surface (surface, image, 0, 0, image->width, image->height,
- image_rect->x, image_rect->y);
+ if (surface->drm != NULL && ! surface->marked_dirty) {
+ return _cairo_surface_release_source_image (surface->drm,
+ image, image_extra);
+ }
cairo_surface_destroy (&image->base);
}
-/*
- * Return whether two xcb surfaces share the same
- * screen. Both core and Render drawing require this
- * when using multiple drawables in an operation.
- */
static cairo_bool_t
-_cairo_xcb_surface_same_screen (cairo_xcb_surface_t *dst,
- cairo_xcb_surface_t *src)
-{
- return dst->dpy == src->dpy && dst->screen == src->screen;
-}
-
-static cairo_status_t
-_cairo_xcb_surface_clone_similar (void *abstract_surface,
- cairo_surface_t *src,
- cairo_content_t content,
- int src_x,
- int src_y,
- int width,
- int height,
- int *clone_offset_x,
- int *clone_offset_y,
- cairo_surface_t **clone_out)
+_cairo_xcb_surface_get_extents (void *abstract_surface,
+ cairo_rectangle_int_t *extents)
{
cairo_xcb_surface_t *surface = abstract_surface;
- cairo_xcb_surface_t *clone;
-
- if (src->backend == surface->base.backend ) {
- cairo_xcb_surface_t *xcb_src = (cairo_xcb_surface_t *)src;
-
- if (_cairo_xcb_surface_same_screen(surface, xcb_src)) {
- *clone_offset_x = 0;
- *clone_offset_y = 0;
- *clone_out = cairo_surface_reference (src);
-
- return CAIRO_STATUS_SUCCESS;
- }
- } else if (_cairo_surface_is_image (src)) {
- cairo_image_surface_t *image_src = (cairo_image_surface_t *)src;
- cairo_content_t content = _cairo_content_from_format (image_src->format);
- cairo_status_t status;
-
- if (surface->base.status)
- return surface->base.status;
-
- clone = (cairo_xcb_surface_t *)
- _cairo_xcb_surface_create_similar (surface, content, width, height);
- if (clone == NULL)
- return CAIRO_INT_STATUS_UNSUPPORTED;
- if (clone->base.status)
- return clone->base.status;
-
- status = _draw_image_surface (clone, image_src,
- src_x, src_y,
- width, height,
- 0, 0);
- if (status) {
- cairo_surface_destroy (&clone->base);
- return status;
- }
-
- *clone_offset_x = src_x;
- *clone_offset_y = src_y;
- *clone_out = &clone->base;
-
- return CAIRO_STATUS_SUCCESS;
- }
- return CAIRO_INT_STATUS_UNSUPPORTED;
+ extents->x = extents->y = 0;
+ extents->width = surface->width;
+ extents->height = surface->height;
+ return TRUE;
}
-static cairo_status_t
-_cairo_xcb_surface_set_matrix (cairo_xcb_surface_t *surface,
- cairo_matrix_t *matrix)
+static void
+_cairo_xcb_surface_get_font_options (void *abstract_surface,
+ cairo_font_options_t *options)
{
- xcb_render_transform_t xtransform;
- xcb_void_cookie_t cookie;
-
- xtransform.matrix11 = _cairo_fixed_16_16_from_double (matrix->xx);
- xtransform.matrix12 = _cairo_fixed_16_16_from_double (matrix->xy);
- xtransform.matrix13 = _cairo_fixed_16_16_from_double (matrix->x0);
-
- xtransform.matrix21 = _cairo_fixed_16_16_from_double (matrix->yx);
- xtransform.matrix22 = _cairo_fixed_16_16_from_double (matrix->yy);
- xtransform.matrix23 = _cairo_fixed_16_16_from_double (matrix->y0);
-
- xtransform.matrix31 = 0;
- xtransform.matrix32 = 0;
- xtransform.matrix33 = 1 << 16;
-
- if (!CAIRO_SURFACE_RENDER_HAS_PICTURE_TRANSFORM (surface))
- {
- static const xcb_render_transform_t identity = {
- 1 << 16, 0x00000, 0x00000,
- 0x00000, 1 << 16, 0x00000,
- 0x00000, 0x00000, 1 << 16
- };
-
- if (memcmp (&xtransform, &identity, sizeof (xcb_render_transform_t)) == 0)
- return CAIRO_STATUS_SUCCESS;
-
- return CAIRO_INT_STATUS_UNSUPPORTED;
- }
-
- cookie = xcb_render_set_picture_transform_checked (surface->dpy,
- surface->src_picture,
- xtransform);
- return _cairo_xcb_add_cookie_to_be_checked (surface, cookie);
+ /* XXX copy from xlib */
+ _cairo_font_options_init_default (options);
}
static cairo_status_t
-_cairo_xcb_surface_set_filter (cairo_xcb_surface_t *surface,
- cairo_filter_t filter)
+_put_shm_image (cairo_xcb_surface_t *surface,
+ xcb_gcontext_t gc,
+ cairo_image_surface_t *image)
{
- const char *render_filter;
- xcb_void_cookie_t cookie;
-
- if (!CAIRO_SURFACE_RENDER_HAS_FILTERS (surface))
- {
- if (filter == CAIRO_FILTER_FAST || filter == CAIRO_FILTER_NEAREST)
- return CAIRO_STATUS_SUCCESS;
+ cairo_xcb_shm_info_t *shm_info;
+ shm_info = _cairo_user_data_array_get_data (&image->base.user_data,
+ (const cairo_user_data_key_t *) surface->connection);
+ if (shm_info == NULL)
return CAIRO_INT_STATUS_UNSUPPORTED;
- }
-
- switch (filter) {
- case CAIRO_FILTER_FAST:
- render_filter = "fast";
- break;
- case CAIRO_FILTER_GOOD:
- render_filter = "good";
- break;
- case CAIRO_FILTER_BEST:
- render_filter = "best";
- break;
- case CAIRO_FILTER_NEAREST:
- render_filter = "nearest";
- break;
- case CAIRO_FILTER_BILINEAR:
- render_filter = "bilinear";
- break;
- case CAIRO_FILTER_GAUSSIAN:
- default:
- render_filter = "best";
- break;
- }
- cookie = xcb_render_set_picture_filter_checked (surface->dpy, surface->src_picture,
- strlen(render_filter), render_filter,
- 0, NULL);
+ shm_info->seqno =
+ _cairo_xcb_connection_shm_put_image (surface->connection,
+ surface->drawable,
+ gc,
+ surface->width, surface->height,
+ 0, 0,
+ image->width, image->height,
+ 0, 0,
+ image->depth,
+ shm_info->shm,
+ shm_info->offset);
- return _cairo_xcb_add_cookie_to_be_checked (surface, cookie);
+ return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
-_cairo_xcb_surface_set_repeat (cairo_xcb_surface_t *surface, cairo_extend_t extend)
+_put_image (cairo_xcb_surface_t *surface,
+ cairo_image_surface_t *image)
{
- uint32_t mask = XCB_RENDER_CP_REPEAT;
- uint32_t pa[1];
- xcb_void_cookie_t cookie;
-
- switch (extend) {
- case CAIRO_EXTEND_NONE:
- pa[0] = XCB_RENDER_REPEAT_NONE;
- break;
-
- case CAIRO_EXTEND_REPEAT:
- pa[0] = XCB_RENDER_REPEAT_NORMAL;
- break;
-
- case CAIRO_EXTEND_REFLECT:
- if (!CAIRO_SURFACE_RENDER_HAS_REPEAT_REFLECT(surface))
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- pa[0] = XCB_RENDER_REPEAT_REFLECT;
- break;
-
- case CAIRO_EXTEND_PAD:
- if (!CAIRO_SURFACE_RENDER_HAS_REPEAT_PAD(surface))
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- pa[0] = XCB_RENDER_REPEAT_PAD;
- break;
-
- default:
- return CAIRO_INT_STATUS_UNSUPPORTED;
- }
-
- cookie = xcb_render_change_picture_checked (surface->dpy, surface->src_picture,
- mask, pa);
- return _cairo_xcb_add_cookie_to_be_checked (surface, cookie);
-}
+ cairo_status_t status = CAIRO_STATUS_SUCCESS;
-static cairo_int_status_t
-_cairo_xcb_surface_set_attributes (cairo_xcb_surface_t *surface,
- cairo_surface_attributes_t *attributes)
-{
- cairo_int_status_t status;
+ /* XXX track damaged region? */
- status = _cairo_xcb_surface_ensure_src_picture (surface);
- if (status)
+ status = _cairo_xcb_connection_acquire (surface->connection);
+ if (unlikely (status))
return status;
- status = _cairo_xcb_surface_set_matrix (surface, &attributes->matrix);
- if (status)
+ status = _cairo_xcb_connection_take_socket (surface->connection);
+ if (unlikely (status)) {
+ _cairo_xcb_connection_release (surface->connection);
return status;
+ }
- status = _cairo_xcb_surface_set_repeat (surface, attributes->extend);
- if (status)
- return status;
+ if (image->pixman_format == surface->pixman_format) {
+ xcb_gcontext_t gc;
+
+ assert (image->width == surface->width);
+ assert (image->height == surface->height);
+ assert (image->depth == surface->depth);
+ assert (image->stride == (int) CAIRO_STRIDE_FOR_WIDTH_BPP (image->width, PIXMAN_FORMAT_BPP (image->pixman_format)));
+
+ gc = _cairo_xcb_screen_get_gc (surface->screen,
+ surface->drawable,
+ surface->depth);
+
+ status = _put_shm_image (surface, gc, image);
+ if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
+ _cairo_xcb_connection_put_image (surface->connection,
+ surface->drawable, gc,
+ image->width, image->height,
+ 0, 0,
+ image->depth,
+ image->stride,
+ image->data);
+ status = CAIRO_STATUS_SUCCESS;
+ }
- status = _cairo_xcb_surface_set_filter (surface, attributes->filter);
- if (status)
- return status;
+ _cairo_xcb_screen_put_gc (surface->screen, surface->depth, gc);
+ } else {
+ ASSERT_NOT_REACHED;
+ }
- return CAIRO_STATUS_SUCCESS;
+ _cairo_xcb_connection_release (surface->connection);
+ return status;
}
-/* Checks whether we can can directly draw from src to dst with
- * the core protocol: either with CopyArea or using src as a
- * a tile in a GC.
- */
-static cairo_bool_t
-_surfaces_compatible (cairo_xcb_surface_t *dst,
- cairo_xcb_surface_t *src)
+static cairo_status_t
+_cairo_xcb_surface_flush (void *abstract_surface)
{
- /* same screen */
- if (!_cairo_xcb_surface_same_screen (dst, src))
- return FALSE;
-
- /* same depth (for core) */
- if (src->depth != dst->depth)
- return FALSE;
+ cairo_xcb_surface_t *surface = abstract_surface;
+ cairo_status_t status = CAIRO_STATUS_SUCCESS;
- /* if Render is supported, match picture formats */
- if (src->xrender_format.id != dst->xrender_format.id)
- return FALSE;
- else if (src->xrender_format.id != XCB_NONE)
- return TRUE;
+ if (surface->drm != NULL && ! surface->marked_dirty)
+ return surface->drm->backend->flush (surface->drm);
- /* Without Render, match visuals instead */
- if (src->visual == dst->visual)
- return TRUE;
+ if (likely (surface->fallback == NULL))
+ return CAIRO_STATUS_SUCCESS;
- return FALSE;
-}
+ if (! surface->base.finished) {
+ status = _put_image (surface,
+ (cairo_image_surface_t *) surface->fallback);
-static cairo_bool_t
-_surface_has_alpha (cairo_xcb_surface_t *surface)
-{
- if (surface->xrender_format.id != XCB_NONE) {
- if (surface->xrender_format.type == XCB_RENDER_PICT_TYPE_DIRECT &&
- surface->xrender_format.direct.alpha_mask != 0)
- return TRUE;
- else
- return FALSE;
- } else {
+ if (status == CAIRO_STATUS_SUCCESS)
+ status = cairo_surface_status (surface->fallback);
- /* In the no-render case, we never have alpha */
- return FALSE;
+ if (status == CAIRO_STATUS_SUCCESS) {
+ status = _cairo_surface_attach_snapshot (&surface->base,
+ surface->fallback,
+ cairo_surface_finish);
+ }
}
-}
-/* Returns true if the given operator and source-alpha combination
- * requires alpha compositing to complete.
- */
-static cairo_bool_t
-_operator_needs_alpha_composite (cairo_operator_t op,
- cairo_bool_t surface_has_alpha)
-{
- if (op == CAIRO_OPERATOR_SOURCE ||
- (!surface_has_alpha &&
- (op == CAIRO_OPERATOR_OVER ||
- op == CAIRO_OPERATOR_ATOP ||
- op == CAIRO_OPERATOR_IN)))
- return FALSE;
+ cairo_surface_destroy (surface->fallback);
+ surface->fallback = NULL;
- return TRUE;
+ return status;
}
-/* There is a bug in most older X servers with compositing using a
- * untransformed repeating source pattern when the source is in off-screen
- * video memory, and another with repeated transformed images using a
- * general transform matrix. When these bugs could be triggered, we need a
- * fallback: in the common case where we have no transformation and the
- * source and destination have the same format/visual, we can do the
- * operation using the core protocol for the first bug, otherwise, we need
- * a software fallback.
- *
- * We can also often optimize a compositing operation by calling XCopyArea
- * for some common cases where there is no alpha compositing to be done.
- * We figure that out here as well.
- */
-typedef enum {
- DO_RENDER, /* use render */
- DO_XCOPYAREA, /* core protocol XCopyArea optimization/fallback */
- DO_XTILE, /* core protocol XSetTile optimization/fallback */
- DO_UNSUPPORTED /* software fallback */
-} composite_operation_t;
-
-/* Initial check for the render bugs; we need to recheck for the
- * offscreen-memory bug after we turn patterns into surfaces, since that
- * may introduce a repeating pattern for gradient patterns. We don't need
- * to check for the repeat+transform bug because gradient surfaces aren't
- * transformed.
- *
- * All we do here is reject cases where we *know* are going to
- * hit the bug and won't be able to use a core protocol fallback.
- */
-static composite_operation_t
-_categorize_composite_operation (cairo_xcb_surface_t *dst,
- cairo_operator_t op,
- const cairo_pattern_t *src_pattern,
- cairo_bool_t have_mask)
-
+static cairo_status_t
+_cairo_xcb_surface_mark_dirty (void *abstract_surface,
+ int x, int y,
+ int width, int height)
{
-#if XXX_BUGGY_REPEAT
- if (!dst->buggy_repeat)
- return DO_RENDER;
-
- if (src_pattern->type == CAIRO_PATTERN_TYPE_SURFACE)
- {
- cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *)src_pattern;
-
- if (_cairo_matrix_is_integer_translation (&src_pattern->matrix, NULL, NULL) &&
- src_pattern->extend == CAIRO_EXTEND_REPEAT)
- {
- /* This is the case where we have the bug involving
- * untransformed repeating source patterns with off-screen
- * video memory; reject some cases where a core protocol
- * fallback is impossible.
- */
- if (have_mask ||
- !(op == CAIRO_OPERATOR_SOURCE || op == CAIRO_OPERATOR_OVER))
- return DO_UNSUPPORTED;
-
- if (_cairo_surface_is_xcb (surface_pattern->surface)) {
- cairo_xcb_surface_t *src = (cairo_xcb_surface_t *)surface_pattern->surface;
-
- if (op == CAIRO_OPERATOR_OVER && _surface_has_alpha (src))
- return DO_UNSUPPORTED;
-
- /* If these are on the same screen but otherwise incompatible,
- * make a copy as core drawing can't cross depths and doesn't
- * work rightacross visuals of the same depth
- */
- if (_cairo_xcb_surface_same_screen (dst, src) &&
- !_surfaces_compatible (dst, src))
- return DO_UNSUPPORTED;
- }
- }
-
- /* Check for the other bug involving repeat patterns with general
- * transforms. */
- if (!_cairo_matrix_is_integer_translation (&src_pattern->matrix, NULL, NULL) &&
- src_pattern->extend == CAIRO_EXTEND_REPEAT)
- return DO_UNSUPPORTED;
- }
-#endif
- return DO_RENDER;
+ cairo_xcb_surface_t *surface = abstract_surface;
+ surface->marked_dirty = TRUE;
+ return CAIRO_STATUS_SUCCESS;
}
-/* Recheck for composite-repeat once we've turned patterns into Xlib surfaces
- * If we end up returning DO_UNSUPPORTED here, we're throwing away work we
- * did to turn gradients into a pattern, but most of the time we can handle
- * that case with core protocol fallback.
- *
- * Also check here if we can just use XCopyArea, instead of going through
- * Render.
- */
-static composite_operation_t
-_recategorize_composite_operation (cairo_xcb_surface_t *dst,
- cairo_operator_t op,
- cairo_xcb_surface_t *src,
- cairo_surface_attributes_t *src_attr,
- cairo_bool_t have_mask)
+static cairo_surface_t *
+_cairo_xcb_surface_map_to_image (cairo_xcb_surface_t *surface)
{
- cairo_bool_t is_integer_translation =
- _cairo_matrix_is_integer_translation (&src_attr->matrix, NULL, NULL);
- cairo_bool_t needs_alpha_composite =
- _operator_needs_alpha_composite (op, _surface_has_alpha (src));
-
- if (!have_mask &&
- is_integer_translation &&
- src_attr->extend == CAIRO_EXTEND_NONE &&
- !needs_alpha_composite &&
- _surfaces_compatible(src, dst))
- {
- return DO_XCOPYAREA;
- }
-#if XXX_BUGGY_REPEAT
- if (!dst->buggy_repeat)
- return DO_RENDER;
-
- if (is_integer_translation &&
- src_attr->extend == CAIRO_EXTEND_REPEAT &&
- (src->width != 1 || src->height != 1))
- {
- if (!have_mask &&
- !needs_alpha_composite &&
- _surfaces_compatible (dst, src))
- {
- return DO_XTILE;
- }
+ cairo_status_t status;
+ cairo_image_surface_t *image;
- return DO_UNSUPPORTED;
- }
-#endif
- return DO_RENDER;
-}
+ status = _get_image (surface, TRUE, &image);
+ if (unlikely (status))
+ return _cairo_surface_create_in_error (status);
-static int
-_render_operator (cairo_operator_t op)
-{
- switch (op) {
- case CAIRO_OPERATOR_CLEAR:
- return XCB_RENDER_PICT_OP_CLEAR;
- case CAIRO_OPERATOR_SOURCE:
- return XCB_RENDER_PICT_OP_SRC;
- case CAIRO_OPERATOR_DEST:
- return XCB_RENDER_PICT_OP_DST;
- case CAIRO_OPERATOR_OVER:
- return XCB_RENDER_PICT_OP_OVER;
- case CAIRO_OPERATOR_DEST_OVER:
- return XCB_RENDER_PICT_OP_OVER_REVERSE;
- case CAIRO_OPERATOR_IN:
- return XCB_RENDER_PICT_OP_IN;
- case CAIRO_OPERATOR_DEST_IN:
- return XCB_RENDER_PICT_OP_IN_REVERSE;
- case CAIRO_OPERATOR_OUT:
- return XCB_RENDER_PICT_OP_OUT;
- case CAIRO_OPERATOR_DEST_OUT:
- return XCB_RENDER_PICT_OP_OUT_REVERSE;
- case CAIRO_OPERATOR_ATOP:
- return XCB_RENDER_PICT_OP_ATOP;
- case CAIRO_OPERATOR_DEST_ATOP:
- return XCB_RENDER_PICT_OP_ATOP_REVERSE;
- case CAIRO_OPERATOR_XOR:
- return XCB_RENDER_PICT_OP_XOR;
- case CAIRO_OPERATOR_ADD:
- return XCB_RENDER_PICT_OP_ADD;
- case CAIRO_OPERATOR_SATURATE:
- return XCB_RENDER_PICT_OP_SATURATE;
- default:
- return XCB_RENDER_PICT_OP_OVER;
- }
+ return &image->base;
}
static cairo_int_status_t
-_cairo_xcb_surface_composite (cairo_operator_t op,
- const cairo_pattern_t *src_pattern,
- const cairo_pattern_t *mask_pattern,
- void *abstract_dst,
- int src_x,
- int src_y,
- int mask_x,
- int mask_y,
- int dst_x,
- int dst_y,
- unsigned int width,
- unsigned int height,
- cairo_region_t *clip_region)
+_cairo_xcb_surface_paint (void *abstract_surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_clip_t *clip)
{
- cairo_surface_attributes_t src_attr, mask_attr;
- cairo_xcb_surface_t *dst = abstract_dst;
- cairo_xcb_surface_t *src;
- cairo_xcb_surface_t *mask;
- cairo_int_status_t status;
- composite_operation_t operation;
- int itx, ity;
- cairo_bool_t is_integer_translation;
- xcb_void_cookie_t cookie;
-
- if (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE (dst))
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- operation = _categorize_composite_operation (dst, op, src_pattern,
- mask_pattern != NULL);
- if (operation == DO_UNSUPPORTED)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- status = _cairo_pattern_acquire_surfaces (src_pattern, mask_pattern,
- &dst->base,
- src_x, src_y,
- mask_x, mask_y,
- width, height,
- CAIRO_PATTERN_ACQUIRE_NO_REFLECT,
- (cairo_surface_t **) &src,
- (cairo_surface_t **) &mask,
- &src_attr, &mask_attr);
- if (status)
- return status;
-
- operation = _recategorize_composite_operation (dst, op, src, &src_attr,
- mask_pattern != NULL);
- if (operation == DO_UNSUPPORTED) {
- status = CAIRO_INT_STATUS_UNSUPPORTED;
- goto BAIL;
- }
-
- status = _cairo_xcb_surface_set_clip_region (dst, clip_region);
- if (unlikely (status))
- goto BAIL;
+ cairo_xcb_surface_t *surface = abstract_surface;
+ cairo_status_t status;
- status = _cairo_xcb_surface_set_attributes (src, &src_attr);
- if (status)
- goto BAIL;
+ if (surface->drm != NULL && ! surface->marked_dirty)
+ return _cairo_surface_paint (surface->drm, op, source, clip);
- switch (operation)
- {
- case DO_RENDER:
- status = _cairo_xcb_surface_ensure_dst_picture (dst);
- if (unlikely (status))
- goto BAIL;
-
- if (mask) {
- status = _cairo_xcb_surface_set_attributes (mask, &mask_attr);
- if (unlikely (status))
- goto BAIL;
-
- cookie = xcb_render_composite_checked (dst->dpy,
- _render_operator (op),
- src->src_picture,
- mask->src_picture,
- dst->dst_picture,
- src_x + src_attr.x_offset,
- src_y + src_attr.y_offset,
- mask_x + mask_attr.x_offset,
- mask_y + mask_attr.y_offset,
- dst_x, dst_y,
- width, height);
- } else {
- static xcb_render_picture_t maskpict = { XCB_NONE };
-
- cookie = xcb_render_composite_checked (dst->dpy,
- _render_operator (op),
- src->src_picture,
- maskpict,
- dst->dst_picture,
- src_x + src_attr.x_offset,
- src_y + src_attr.y_offset,
- 0, 0,
- dst_x, dst_y,
- width, height);
- }
- break;
-
- case DO_XCOPYAREA:
- status = _cairo_xcb_surface_ensure_gc (dst);
- if (unlikely (status))
+ if (surface->fallback == NULL) {
+ status = _cairo_xcb_surface_cairo_paint (surface, op, source, clip);
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED)
return status;
- cookie = xcb_copy_area_checked (dst->dpy,
- src->drawable,
- dst->drawable,
- dst->gc,
- src_x + src_attr.x_offset,
- src_y + src_attr.y_offset,
- dst_x, dst_y,
- width, height);
- break;
-
- case DO_XTILE:
- /* This case is only used for bug fallbacks, though it is theoretically
- * applicable to the case where we don't have the RENDER extension as
- * well.
- *
- * We've checked that we have a repeating unscaled source in
- * _recategorize_composite_operation.
- */
-
- status = _cairo_xcb_surface_ensure_gc (dst);
- if (unlikely (status))
+ status = _cairo_xcb_surface_render_paint (surface, op, source, clip);
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED)
return status;
- is_integer_translation =
- _cairo_matrix_is_integer_translation (&src_attr.matrix, &itx, &ity);
- assert (is_integer_translation == TRUE);
- {
- uint32_t mask = XCB_GC_FILL_STYLE | XCB_GC_TILE
- | XCB_GC_TILE_STIPPLE_ORIGIN_X
- | XCB_GC_TILE_STIPPLE_ORIGIN_Y;
- uint32_t values[] = {
- XCB_FILL_STYLE_TILED, src->drawable,
- - (itx + src_attr.x_offset),
- - (ity + src_attr.y_offset)
- };
- xcb_rectangle_t rect = { dst_x, dst_y, width, height };
-
- xcb_change_gc( dst->dpy, dst->gc, mask, values );
- cookie = xcb_poly_fill_rectangle_checked (dst->dpy,
- dst->drawable,
- dst->gc,
- 1, &rect);
- }
- break;
-
- case DO_UNSUPPORTED:
- default:
- ASSERT_NOT_REACHED;
- }
-
- status = _cairo_xcb_add_cookie_to_be_checked (dst, cookie);
- if (unlikely (status))
- goto BAIL;
-
- if (!_cairo_operator_bounded_by_source (op)) {
- status = _cairo_surface_composite_fixup_unbounded (&dst->base,
- &src_attr, src->width, src->height,
- mask ? &mask_attr : NULL,
- mask ? mask->width : 0,
- mask ? mask->height : 0,
- src_x, src_y,
- mask_x, mask_y,
- dst_x, dst_y, width, height,
- clip_region);
+ surface->fallback = _cairo_xcb_surface_map_to_image (surface);
}
- BAIL:
- if (mask)
- _cairo_pattern_release_surface (mask_pattern, &mask->base, &mask_attr);
-
- _cairo_pattern_release_surface (src_pattern, &src->base, &src_attr);
-
- return status;
+ return _cairo_surface_paint (surface->fallback, op, source, clip);
}
static cairo_int_status_t
-_cairo_xcb_surface_fill_rectangles (void *abstract_surface,
- cairo_operator_t op,
- const cairo_color_t * color,
- cairo_rectangle_int_t *rects,
- int num_rects)
+_cairo_xcb_surface_mask (void *abstract_surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ const cairo_pattern_t *mask,
+ cairo_clip_t *clip)
{
cairo_xcb_surface_t *surface = abstract_surface;
- xcb_render_color_t render_color;
- xcb_rectangle_t static_xrects[16];
- xcb_rectangle_t *xrects = static_xrects;
cairo_status_t status;
- xcb_void_cookie_t cookie;
- int i;
-
- if (!CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLE (surface))
- return CAIRO_INT_STATUS_UNSUPPORTED;
- render_color.red = color->red_short;
- render_color.green = color->green_short;
- render_color.blue = color->blue_short;
- render_color.alpha = color->alpha_short;
+ if (surface->drm != NULL && ! surface->marked_dirty)
+ return _cairo_surface_mask (surface->drm, op, source, mask, clip);
- status = _cairo_xcb_surface_set_clip_region (surface, NULL);
- assert (status == CAIRO_STATUS_SUCCESS);
-
- if (num_rects > ARRAY_LENGTH(static_xrects)) {
- xrects = _cairo_malloc_ab (num_rects, sizeof(xcb_rectangle_t));
- if (xrects == NULL)
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
- }
+ if (surface->fallback == NULL) {
+ status = _cairo_xcb_surface_cairo_mask (surface,
+ op, source, mask, clip);
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+ return status;
- for (i = 0; i < num_rects; i++) {
- xrects[i].x = rects[i].x;
- xrects[i].y = rects[i].y;
- xrects[i].width = rects[i].width;
- xrects[i].height = rects[i].height;
- }
+ status = _cairo_xcb_surface_render_mask (surface,
+ op, source, mask, clip);
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+ return status;
- status = _cairo_xcb_surface_ensure_dst_picture (surface);
- if (unlikely (status)) {
- if (xrects != static_xrects)
- free (xrects);
- return status;
+ surface->fallback = _cairo_xcb_surface_map_to_image (surface);
}
- cookie = xcb_render_fill_rectangles_checked (surface->dpy,
- _render_operator (op),
- surface->dst_picture,
- render_color, num_rects, xrects);
-
- if (xrects != static_xrects)
- free (xrects);
-
- return _cairo_xcb_add_cookie_to_be_checked (surface, cookie);
+ return _cairo_surface_mask (surface->fallback,
+ op, source, mask,
+ clip);
}
-/* Creates an A8 picture of size @width x @height, initialized with @color
- */
-static cairo_status_t
-_create_a8_picture (cairo_xcb_surface_t *surface,
- xcb_render_color_t *color,
- int width,
- int height,
- cairo_bool_t repeat,
- xcb_render_picture_t *out)
-{
- uint32_t values[] = { TRUE };
- uint32_t mask = repeat ? XCB_RENDER_CP_REPEAT : 0;
-
- xcb_pixmap_t pixmap;
- xcb_render_picture_t picture;
- xcb_render_pictforminfo_t *format;
- xcb_rectangle_t rect = { 0, 0, width, height };
-
- cairo_xcb_cookie_t *cookie[3];
- cairo_status_t status;
-
- status = _cairo_freepool_alloc_array (&surface->cookie_pool,
- ARRAY_LENGTH (cookie),
- (void **) cookie);
- if (unlikely (status))
- return status;
-
- pixmap = xcb_generate_id (surface->dpy);
- picture = xcb_generate_id (surface->dpy);
-
- cookie[0]->xcb = xcb_create_pixmap_checked (surface->dpy, 8, pixmap, surface->drawable,
- width <= 0 ? 1 : width,
- height <= 0 ? 1 : height);
- cairo_list_add_tail (&cookie[0]->link, &surface->to_be_checked);
-
- format = _CAIRO_FORMAT_TO_XRENDER_FORMAT (surface->dpy, CAIRO_FORMAT_A8);
- cookie[1]->xcb = xcb_render_create_picture_checked (surface->dpy,
- picture, pixmap, format->id,
- mask, values);
- cairo_list_add_tail (&cookie[1]->link, &surface->to_be_checked);
-
- cookie[2]->xcb = xcb_render_fill_rectangles_checked (surface->dpy,
- XCB_RENDER_PICT_OP_SRC,
- picture, *color, 1, &rect);
- cairo_list_add_tail (&cookie[2]->link, &surface->to_be_checked);
-
- xcb_free_pixmap (surface->dpy, pixmap);
-
- *out = picture;
- return CAIRO_STATUS_SUCCESS;
-}
-
-/* Creates a temporary mask for the trapezoids covering the area
- * [@dst_x, @dst_y, @width, @height] of the destination surface.
- */
-static cairo_status_t
-_create_trapezoid_mask (cairo_xcb_surface_t *dst,
- cairo_trapezoid_t *traps,
- int num_traps,
- int dst_x,
- int dst_y,
- int width,
- int height,
- xcb_render_pictforminfo_t *pict_format,
- xcb_render_picture_t *mask_picture_out)
+static cairo_int_status_t
+_cairo_xcb_surface_stroke (void *abstract_surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_path_fixed_t *path,
+ const cairo_stroke_style_t *style,
+ const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm_inverse,
+ double tolerance,
+ cairo_antialias_t antialias,
+ cairo_clip_t *clip)
{
- xcb_render_color_t transparent = { 0, 0, 0, 0 };
- xcb_render_color_t solid = { 0xffff, 0xffff, 0xffff, 0xffff };
- xcb_render_picture_t mask_picture, solid_picture;
- xcb_render_trapezoid_t *offset_traps;
- xcb_void_cookie_t cookie;
+ cairo_xcb_surface_t *surface = abstract_surface;
cairo_status_t status;
- int i;
-
- /* This would be considerably simpler using XRenderAddTraps(), but since
- * we are only using this in the unbounded-operator case, we stick with
- * XRenderCompositeTrapezoids, which is available on older versions
- * of RENDER rather than conditionalizing. We should still hit an
- * optimization that avoids creating another intermediate surface on
- * the servers that have XRenderAddTraps().
- */
- status = _create_a8_picture (dst, &transparent, width, height, FALSE, &mask_picture);
- if (unlikely (status))
- return status;
- status = _create_a8_picture (dst, &solid, 1, 1, TRUE, &solid_picture);
- if (unlikely (status)) {
- xcb_render_free_picture (dst->dpy, mask_picture);
- return status;
+ if (surface->drm != NULL && ! surface->marked_dirty) {
+ return _cairo_surface_stroke (surface->drm,
+ op, source,
+ path, style,
+ ctm, ctm_inverse,
+ tolerance, antialias,
+ clip);
}
- offset_traps = _cairo_malloc_ab (num_traps, sizeof (xcb_render_trapezoid_t));
- if (offset_traps == NULL) {
- xcb_render_free_picture (dst->dpy, solid_picture);
- xcb_render_free_picture (dst->dpy, mask_picture);
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
- }
+ if (surface->fallback == NULL) {
+ status = _cairo_xcb_surface_cairo_stroke (surface, op, source,
+ path, style,
+ ctm, ctm_inverse,
+ tolerance, antialias,
+ clip);
- for (i = 0; i < num_traps; i++) {
- offset_traps[i].top = _cairo_fixed_to_16_16(traps[i].top) - 0x10000 * dst_y;
- offset_traps[i].bottom = _cairo_fixed_to_16_16(traps[i].bottom) - 0x10000 * dst_y;
- offset_traps[i].left.p1.x = _cairo_fixed_to_16_16(traps[i].left.p1.x) - 0x10000 * dst_x;
- offset_traps[i].left.p1.y = _cairo_fixed_to_16_16(traps[i].left.p1.y) - 0x10000 * dst_y;
- offset_traps[i].left.p2.x = _cairo_fixed_to_16_16(traps[i].left.p2.x) - 0x10000 * dst_x;
- offset_traps[i].left.p2.y = _cairo_fixed_to_16_16(traps[i].left.p2.y) - 0x10000 * dst_y;
- offset_traps[i].right.p1.x = _cairo_fixed_to_16_16(traps[i].right.p1.x) - 0x10000 * dst_x;
- offset_traps[i].right.p1.y = _cairo_fixed_to_16_16(traps[i].right.p1.y) - 0x10000 * dst_y;
- offset_traps[i].right.p2.x = _cairo_fixed_to_16_16(traps[i].right.p2.x) - 0x10000 * dst_x;
- offset_traps[i].right.p2.y = _cairo_fixed_to_16_16(traps[i].right.p2.y) - 0x10000 * dst_y;
- }
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+ return status;
- cookie = xcb_render_trapezoids_checked (dst->dpy, XCB_RENDER_PICT_OP_ADD,
- solid_picture, mask_picture,
- pict_format->id,
- 0, 0,
- num_traps, offset_traps);
+ status = _cairo_xcb_surface_render_stroke (surface, op, source,
+ path, style,
+ ctm, ctm_inverse,
+ tolerance, antialias,
+ clip);
- xcb_render_free_picture (dst->dpy, solid_picture);
- free (offset_traps);
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+ return status;
- status = _cairo_xcb_add_cookie_to_be_checked (dst, cookie);
- if (unlikely (status)) {
- xcb_render_free_picture (dst->dpy, mask_picture);
- return status;
+ surface->fallback = _cairo_xcb_surface_map_to_image (surface);
}
- *mask_picture_out = mask_picture;
- return CAIRO_STATUS_SUCCESS;
+ return _cairo_surface_stroke (surface->fallback,
+ op, source,
+ path, style,
+ ctm, ctm_inverse,
+ tolerance, antialias,
+ clip);
}
static cairo_int_status_t
-_cairo_xcb_surface_composite_trapezoids (cairo_operator_t op,
- const cairo_pattern_t *pattern,
- void *abstract_dst,
- cairo_antialias_t antialias,
- int src_x,
- int src_y,
- int dst_x,
- int dst_y,
- unsigned int width,
- unsigned int height,
- cairo_trapezoid_t *traps,
- int num_traps,
- cairo_region_t *clip_region)
+_cairo_xcb_surface_fill (void *abstract_surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_path_fixed_t *path,
+ cairo_fill_rule_t fill_rule,
+ double tolerance,
+ cairo_antialias_t antialias,
+ cairo_clip_t *clip)
{
- cairo_surface_attributes_t attributes;
- cairo_xcb_surface_t *dst = abstract_dst;
- cairo_xcb_surface_t *src;
- cairo_int_status_t status;
- composite_operation_t operation;
- int render_reference_x, render_reference_y;
- int render_src_x, render_src_y;
- int cairo_format;
- xcb_render_pictforminfo_t *render_format;
-
- if (!CAIRO_SURFACE_RENDER_HAS_TRAPEZOIDS (dst))
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- operation = _categorize_composite_operation (dst, op, pattern, TRUE);
- if (operation == DO_UNSUPPORTED)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- status = _cairo_pattern_acquire_surface (pattern, &dst->base,
- src_x, src_y, width, height,
- CAIRO_PATTERN_ACQUIRE_NO_REFLECT,
- (cairo_surface_t **) &src,
- &attributes);
- if (status)
- return status;
-
- operation = _recategorize_composite_operation (dst, op, src, &attributes, TRUE);
- if (operation == DO_UNSUPPORTED) {
- status = CAIRO_INT_STATUS_UNSUPPORTED;
- goto BAIL;
- }
-
- switch (antialias) {
- case CAIRO_ANTIALIAS_NONE:
- cairo_format = CAIRO_FORMAT_A1;
- break;
- case CAIRO_ANTIALIAS_GRAY:
- case CAIRO_ANTIALIAS_SUBPIXEL:
- case CAIRO_ANTIALIAS_DEFAULT:
- default:
- cairo_format = CAIRO_FORMAT_A8;
- break;
- }
- render_format = _CAIRO_FORMAT_TO_XRENDER_FORMAT (dst->dpy, cairo_format);
- /* XXX: what to do if render_format is null? */
+ cairo_xcb_surface_t *surface = abstract_surface;
+ cairo_status_t status;
- if (traps[0].left.p1.y < traps[0].left.p2.y) {
- render_reference_x = _cairo_fixed_integer_floor (traps[0].left.p1.x);
- render_reference_y = _cairo_fixed_integer_floor (traps[0].left.p1.y);
- } else {
- render_reference_x = _cairo_fixed_integer_floor (traps[0].left.p2.x);
- render_reference_y = _cairo_fixed_integer_floor (traps[0].left.p2.y);
+ if (surface->drm != NULL && ! surface->marked_dirty) {
+ return _cairo_surface_fill (surface->drm,
+ op, source,
+ path, fill_rule,
+ tolerance, antialias,
+ clip);
}
- render_src_x = src_x + render_reference_x - dst_x;
- render_src_y = src_y + render_reference_y - dst_y;
-
- status = _cairo_xcb_surface_ensure_dst_picture (dst);
- if (unlikely (status))
- goto BAIL;
-
- status = _cairo_xcb_surface_set_clip_region (dst, clip_region);
- if (unlikely (status))
- goto BAIL;
-
- status = _cairo_xcb_surface_set_attributes (src, &attributes);
- if (status)
- goto BAIL;
-
- if (!_cairo_operator_bounded_by_mask (op)) {
- xcb_void_cookie_t cookie;
-
- /* xcb_render_composite+trapezoids() creates a mask only large enough for the
- * trapezoids themselves, but if the operator is unbounded, then we need
- * to actually composite all the way out to the bounds, so we create
- * the mask and composite ourselves. There actually would
- * be benefit to doing this in all cases, since RENDER implementations
- * will frequently create a too temporary big mask, ignoring destination
- * bounds and clip. (xcb_render_add_traps() could be used to make creating
- * the mask somewhat cheaper.)
- */
- xcb_render_picture_t mask_picture = 0; /* silence compiler */
-
- status = _create_trapezoid_mask (dst, traps, num_traps,
- dst_x, dst_y, width, height,
- render_format,
- &mask_picture);
- if (status)
- goto BAIL;
-
- cookie = xcb_render_composite_checked (dst->dpy,
- _render_operator (op),
- src->src_picture,
- mask_picture,
- dst->dst_picture,
- src_x + attributes.x_offset,
- src_y + attributes.y_offset,
- 0, 0,
- dst_x, dst_y,
- width, height);
- xcb_render_free_picture (dst->dpy, mask_picture);
-
- status = _cairo_xcb_add_cookie_to_be_checked (dst, cookie);
- if (unlikely (status))
- goto BAIL;
+ if (surface->fallback == NULL) {
+ status = _cairo_xcb_surface_cairo_fill (surface, op, source,
+ path, fill_rule,
+ tolerance, antialias,
+ clip);
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+ return status;
- status = _cairo_surface_composite_shape_fixup_unbounded (&dst->base,
- &attributes, src->width, src->height,
- width, height,
- src_x, src_y,
- 0, 0,
- dst_x, dst_y, width, height,
- clip_region);
+ status = _cairo_xcb_surface_render_fill (surface, op, source,
+ path, fill_rule,
+ tolerance, antialias,
+ clip);
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+ return status;
- } else {
- xcb_render_trapezoid_t xtraps_stack[CAIRO_STACK_ARRAY_LENGTH (xcb_render_trapezoid_t)];
- xcb_render_trapezoid_t *xtraps = xtraps_stack;
- xcb_void_cookie_t cookie;
- int i;
-
- if (num_traps > ARRAY_LENGTH(xtraps_stack)) {
- xtraps = _cairo_malloc_ab (num_traps, sizeof(xcb_render_trapezoid_t));
- if (xtraps == NULL) {
- status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
- goto BAIL;
- }
- }
-
- for (i = 0; i < num_traps; i++) {
- xtraps[i].top = _cairo_fixed_to_16_16(traps[i].top);
- xtraps[i].bottom = _cairo_fixed_to_16_16(traps[i].bottom);
- xtraps[i].left.p1.x = _cairo_fixed_to_16_16(traps[i].left.p1.x);
- xtraps[i].left.p1.y = _cairo_fixed_to_16_16(traps[i].left.p1.y);
- xtraps[i].left.p2.x = _cairo_fixed_to_16_16(traps[i].left.p2.x);
- xtraps[i].left.p2.y = _cairo_fixed_to_16_16(traps[i].left.p2.y);
- xtraps[i].right.p1.x = _cairo_fixed_to_16_16(traps[i].right.p1.x);
- xtraps[i].right.p1.y = _cairo_fixed_to_16_16(traps[i].right.p1.y);
- xtraps[i].right.p2.x = _cairo_fixed_to_16_16(traps[i].right.p2.x);
- xtraps[i].right.p2.y = _cairo_fixed_to_16_16(traps[i].right.p2.y);
- }
-
- cookie = xcb_render_trapezoids_checked (dst->dpy,
- _render_operator (op),
- src->src_picture, dst->dst_picture,
- render_format->id,
- render_src_x + attributes.x_offset,
- render_src_y + attributes.y_offset,
- num_traps, xtraps);
-
- if (xtraps != xtraps_stack)
- free (xtraps);
-
- status = _cairo_xcb_add_cookie_to_be_checked (dst, cookie);
+ surface->fallback = _cairo_xcb_surface_map_to_image (surface);
}
- BAIL:
- _cairo_pattern_release_surface (pattern, &src->base, &attributes);
-
- return status;
+ return _cairo_surface_fill (surface->fallback,
+ op, source,
+ path, fill_rule,
+ tolerance, antialias,
+ clip);
}
-static cairo_bool_t
-_cairo_xcb_surface_get_extents (void *abstract_surface,
- cairo_rectangle_int_t *rectangle)
-{
- cairo_xcb_surface_t *surface = abstract_surface;
-
- rectangle->x = 0;
- rectangle->y = 0;
-
- rectangle->width = surface->width;
- rectangle->height = surface->height;
-
- return TRUE;
-}
-
-static cairo_status_t
-_cairo_xcb_surface_flush (void *abstract_surface)
+static cairo_int_status_t
+_cairo_xcb_surface_glyphs (void *abstract_surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_scaled_font_t *scaled_font,
+ cairo_clip_t *clip,
+ int *num_remaining)
{
cairo_xcb_surface_t *surface = abstract_surface;
- cairo_status_t status = CAIRO_STATUS_SUCCESS;
-
- while (! cairo_list_is_empty (&surface->to_be_checked)) {
- cairo_xcb_cookie_t *cookie;
- xcb_generic_error_t *error;
-
- cookie = cairo_list_first_entry (&surface->to_be_checked,
- cairo_xcb_cookie_t,
- link);
+ cairo_status_t status;
- error = xcb_request_check (surface->dpy, cookie->xcb);
- if (error != NULL) {
-#if 0
- /* XXX */
- fprintf (stderr, "Delayed error detected: %d, major=%d, minor=%d, seqno=%d\n",
- error->error_code,
- error->major_code,
- error->minor_code,
- error->sequence);
-#endif
- if (status == CAIRO_STATUS_SUCCESS)
- status = _cairo_error (CAIRO_STATUS_WRITE_ERROR); /* XXX CAIRO_STATUS_CONNECTION_ERROR */
- }
+ *num_remaining = 0;
- cairo_list_del (&cookie->link);
- _cairo_freepool_free (&surface->cookie_pool, cookie);
+ if (surface->drm != NULL && ! surface->marked_dirty) {
+ return _cairo_surface_show_text_glyphs (surface->drm,
+ op, source,
+ NULL, 0,
+ glyphs, num_glyphs,
+ NULL, 0, 0,
+ scaled_font,
+ clip);
}
- return status;
-}
-
-/* XXX: _cairo_xcb_surface_get_font_options */
-
-static void
-_cairo_xcb_surface_scaled_font_fini (cairo_scaled_font_t *scaled_font);
-
-static void
-_cairo_xcb_surface_scaled_glyph_fini (cairo_scaled_glyph_t *scaled_glyph,
- cairo_scaled_font_t *scaled_font);
-
-static cairo_int_status_t
-_cairo_xcb_surface_show_glyphs (void *abstract_dst,
- cairo_operator_t op,
- const cairo_pattern_t *src_pattern,
- cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_scaled_font_t *scaled_font,
- cairo_clip_t *clip,
- int *remaining_glyphs);
-
-static cairo_bool_t
-_cairo_xcb_surface_is_similar (void *surface_a,
- void *surface_b,
- cairo_content_t content)
-{
- cairo_xcb_surface_t *a = surface_a;
- cairo_xcb_surface_t *b = surface_b;
- xcb_render_pictforminfo_t *xrender_format;
-
- /* XXX: disable caching by the solid pattern cache until we implement
- * display notification to avoid issuing xcb calls from the wrong thread
- * or accessing the surface after the Display has been closed.
- */
- return FALSE;
+ if (surface->fallback == NULL) {
+ status = _cairo_xcb_surface_cairo_glyphs (surface,
+ op, source,
+ scaled_font, glyphs, num_glyphs,
+ clip);
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+ return status;
- if (! _cairo_xcb_surface_same_screen (a, b))
- return FALSE;
+ status = _cairo_xcb_surface_render_glyphs (surface,
+ op, source,
+ scaled_font, glyphs, num_glyphs,
+ clip);
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+ return status;
- /* now check that the target is a similar format */
- xrender_format = _CAIRO_FORMAT_TO_XRENDER_FORMAT (b->dpy,
- _cairo_format_from_content (content));
+ surface->fallback = _cairo_xcb_surface_map_to_image (surface);
+ }
- return a->xrender_format.id == xrender_format->id;
+ return _cairo_surface_show_text_glyphs (surface->fallback,
+ op, source,
+ NULL, 0,
+ glyphs, num_glyphs,
+ NULL, 0, 0,
+ scaled_font,
+ clip);
}
-/* XXX: move this to the bottom of the file, XCB and Xlib */
-
-static const cairo_surface_backend_t cairo_xcb_surface_backend = {
+const cairo_surface_backend_t _cairo_xcb_surface_backend = {
CAIRO_SURFACE_TYPE_XCB,
_cairo_xcb_surface_create_similar,
_cairo_xcb_surface_finish,
_cairo_xcb_surface_acquire_source_image,
_cairo_xcb_surface_release_source_image,
+ NULL, NULL, NULL, /* dest acquire/release/clone */
- _cairo_xcb_surface_acquire_dest_image,
- _cairo_xcb_surface_release_dest_image,
-
- _cairo_xcb_surface_clone_similar,
- _cairo_xcb_surface_composite,
- _cairo_xcb_surface_fill_rectangles,
- _cairo_xcb_surface_composite_trapezoids,
- NULL, /* create_span_renderer */
- NULL, /* check_span_renderer */
+ NULL, /* composite */
+ NULL, /* fill */
+ NULL, /* trapezoids */
+ NULL, /* span */
+ NULL, /* check-span */
NULL, /* copy_page */
NULL, /* show_page */
-
_cairo_xcb_surface_get_extents,
- NULL, /* old_show_glyphs */
- NULL, /* get_font_options */
+ NULL, /* old-glyphs */
+ _cairo_xcb_surface_get_font_options,
+
_cairo_xcb_surface_flush,
- NULL, /* mark_dirty_rectangle */
+ _cairo_xcb_surface_mark_dirty,
_cairo_xcb_surface_scaled_font_fini,
_cairo_xcb_surface_scaled_glyph_fini,
- NULL, /* paint */
- NULL, /* mask */
- NULL, /* stroke */
- NULL, /* fill */
- _cairo_xcb_surface_show_glyphs,
-
- _cairo_xcb_surface_snapshot,
-
- _cairo_xcb_surface_is_similar,
+ _cairo_xcb_surface_paint,
+ _cairo_xcb_surface_mask,
+ _cairo_xcb_surface_stroke,
+ _cairo_xcb_surface_fill,
+ _cairo_xcb_surface_glyphs,
};
-/**
- * _cairo_surface_is_xcb:
- * @surface: a #cairo_surface_t
- *
- * Checks if a surface is a #cairo_xcb_surface_t
- *
- * Return value: True if the surface is an xcb surface
- **/
-static cairo_bool_t
-_cairo_surface_is_xcb (cairo_surface_t *surface)
+#if CAIRO_HAS_DRM_SURFACE && CAIRO_HAS_XCB_DRM_FUNCTIONS
+static cairo_surface_t *
+_xcb_drm_create_surface_for_drawable (cairo_xcb_connection_t *connection,
+ cairo_xcb_screen_t *screen,
+ xcb_drawable_t drawable,
+ pixman_format_code_t pixman_format,
+ int width, int height)
{
- return surface->backend == &cairo_xcb_surface_backend;
+ uint32_t attachments[] = { XCB_DRI2_ATTACHMENT_BUFFER_FRONT_LEFT };
+ xcb_dri2_get_buffers_reply_t *buffers;
+ xcb_dri2_dri2_buffer_t *buffer;
+ cairo_surface_t *surface;
+
+ if (! _cairo_drm_size_is_valid (screen->device, width, height))
+ return NULL;
+
+ xcb_dri2_create_drawable (connection->xcb_connection,
+ drawable);
+
+ buffers = xcb_dri2_get_buffers_reply (connection->xcb_connection,
+ xcb_dri2_get_buffers (connection->xcb_connection,
+ drawable, 1,
+ ARRAY_LENGTH (attachments),
+ attachments),
+ 0);
+ if (buffers == NULL) {
+ xcb_dri2_destroy_drawable (connection->xcb_connection,
+ drawable);
+ return NULL;
+ }
+
+ /* If the drawable is a window, we expect to receive an extra fake front,
+ * which would involve copying on each flush - contrary to the user
+ * expectations. But that is likely to be preferable to mixing drm/xcb
+ * operations.
+ */
+ buffer = xcb_dri2_get_buffers_buffers (buffers);
+ if (buffers->count == 1 && buffer[0].attachment == XCB_DRI2_ATTACHMENT_BUFFER_FRONT_LEFT) {
+ assert (buffer[0].cpp == PIXMAN_FORMAT_BPP (pixman_format) / 8);
+ surface = cairo_drm_surface_create_for_name (screen->device,
+ buffer[0].name,
+ _cairo_format_from_pixman_format (pixman_format),
+ width, height,
+ buffer[0].pitch);
+ } else {
+ xcb_dri2_destroy_drawable (connection->xcb_connection,
+ drawable);
+ surface = NULL;
+ }
+ free (buffers);
+
+ return surface;
}
+#else
+
static cairo_surface_t *
-_cairo_xcb_surface_create_internal (xcb_connection_t *dpy,
- xcb_drawable_t drawable,
- xcb_screen_t *screen,
- xcb_visualtype_t *visual,
- xcb_render_pictforminfo_t *xrender_format,
- int width,
- int height,
- int depth)
+_xcb_drm_create_surface_for_drawable (cairo_xcb_connection_t *connection,
+ cairo_xcb_screen_t *screen,
+ xcb_drawable_t drawable,
+ pixman_format_code_t pixman_format,
+ int width, int height)
+{
+ return NULL;
+}
+
+#endif
+
+cairo_surface_t *
+_cairo_xcb_surface_create_internal (cairo_xcb_screen_t *screen,
+ xcb_drawable_t drawable,
+ cairo_bool_t owns_pixmap,
+ pixman_format_code_t pixman_format,
+ xcb_render_pictformat_t xrender_format,
+ int width,
+ int height)
{
cairo_xcb_surface_t *surface;
- const xcb_query_extension_reply_t *er;
- const xcb_render_query_version_reply_t *r = NULL;
surface = malloc (sizeof (cairo_xcb_surface_t));
- if (surface == NULL)
+ if (unlikely (surface == NULL))
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
- if (xrender_format) {
- depth = xrender_format->depth;
- } else if (visual) {
- xcb_depth_iterator_t depths;
- xcb_visualtype_iterator_t visuals;
-
- /* This is ugly, but we have to walk over all visuals
- * for the screen to find the depth.
- */
- depths = xcb_screen_allowed_depths_iterator(screen);
- for(; depths.rem; xcb_depth_next(&depths))
- {
- visuals = xcb_depth_visuals_iterator(depths.data);
- for(; visuals.rem; xcb_visualtype_next(&visuals))
- {
- if(visuals.data->visual_id == visual->visual_id)
- {
- depth = depths.data->depth;
- goto found;
- }
- }
- }
- found:
- ;
- }
-
- er = xcb_get_extension_data(dpy, &xcb_render_id);
- if(er && er->present) {
- r = xcb_render_util_query_version(dpy);
- }
- if (r) {
- surface->render_major = r->major_version;
- surface->render_minor = r->minor_version;
- } else {
- surface->render_major = -1;
- surface->render_minor = -1;
- }
-
- if (CAIRO_SURFACE_RENDER_HAS_CREATE_PICTURE (surface)) {
- if (!xrender_format) {
- if (visual) {
- const xcb_render_query_pict_formats_reply_t *formats;
- xcb_render_pictvisual_t *pict_visual;
- formats = xcb_render_util_query_formats (dpy);
- pict_visual = xcb_render_util_find_visual_format (formats, visual->visual_id);
- if (pict_visual) {
- xcb_render_pictforminfo_t template;
- template.id = pict_visual->format;
- xrender_format = xcb_render_util_find_format (formats, XCB_PICT_FORMAT_ID, &template, 0);
- }
- } else if (depth == 1) {
- xrender_format = _CAIRO_FORMAT_TO_XRENDER_FORMAT (dpy, CAIRO_FORMAT_A1);
- }
- }
- } else {
- xrender_format = NULL;
- }
-
_cairo_surface_init (&surface->base,
- &cairo_xcb_surface_backend,
- NULL, /* device */
- _xcb_render_format_to_content (xrender_format));
+ &_cairo_xcb_surface_backend,
+ &screen->connection->device,
+ _cairo_content_from_pixman_format (pixman_format));
+
+ surface->connection = _cairo_xcb_connection_reference (screen->connection);
+ surface->screen = screen;
+ cairo_list_add (&surface->link, &screen->surfaces);
- surface->dpy = dpy;
+ surface->fallback = NULL;
- surface->gc = XCB_NONE;
surface->drawable = drawable;
- surface->screen = screen;
- surface->owns_pixmap = FALSE;
+ surface->owns_pixmap = owns_pixmap;
surface->use_pixmap = 0;
- surface->width = width;
- surface->height = height;
- /* XXX: set buggy_repeat based on ServerVendor and VendorRelease */
+ surface->width = width;
+ surface->height = height;
+ surface->depth = PIXMAN_FORMAT_DEPTH (pixman_format);
- surface->dst_picture = XCB_NONE;
- surface->src_picture = XCB_NONE;
+ surface->picture = XCB_NONE;
- surface->visual = visual;
- surface->xrender_format.id = XCB_NONE;
- if (xrender_format) surface->xrender_format = *xrender_format;
- surface->depth = depth;
+ surface->pixman_format = pixman_format;
+ surface->xrender_format = xrender_format;
- surface->have_clip_rects = FALSE;
- surface->clip_rects = NULL;
- surface->num_clip_rects = 0;
- surface->clip_region = NULL;
+ surface->flags = screen->connection->flags;
- cairo_list_init (&surface->to_be_checked);
- _cairo_freepool_init (&surface->cookie_pool,
- sizeof (cairo_xcb_cookie_t));
+ surface->marked_dirty = FALSE;
+ surface->drm = NULL;
+ if (screen->device != NULL) {
+ surface->drm = _xcb_drm_create_surface_for_drawable (surface->connection,
+ surface->screen,
+ drawable,
+ pixman_format,
+ width, height);
+ }
return &surface->base;
}
static xcb_screen_t *
-_cairo_xcb_screen_from_visual (xcb_connection_t *c, xcb_visualtype_t *visual)
+_cairo_xcb_screen_from_visual (xcb_connection_t *connection,
+ xcb_visualtype_t *visual,
+ int *depth)
{
xcb_depth_iterator_t d;
- xcb_screen_iterator_t s = xcb_setup_roots_iterator(xcb_get_setup(c));
- for (; s.rem; xcb_screen_next(&s))
- {
- if (s.data->root_visual == visual->visual_id)
+ xcb_screen_iterator_t s;
+
+ s = xcb_setup_roots_iterator (xcb_get_setup (connection));
+ for (; s.rem; xcb_screen_next (&s)) {
+ if (s.data->root_visual == visual->visual_id) {
+ *depth = s.data->root_depth;
return s.data;
+ }
d = xcb_screen_allowed_depths_iterator(s.data);
- for (; d.rem; xcb_depth_next(&d))
- {
- xcb_visualtype_iterator_t v = xcb_depth_visuals_iterator(d.data);
- for (; v.rem; xcb_visualtype_next(&v))
- {
- if (v.data->visual_id == visual->visual_id)
+ for (; d.rem; xcb_depth_next (&d)) {
+ xcb_visualtype_iterator_t v = xcb_depth_visuals_iterator (d.data);
+
+ for (; v.rem; xcb_visualtype_next (&v)) {
+ if (v.data->visual_id == visual->visual_id) {
+ *depth = d.data->depth;
return s.data;
+ }
}
}
}
+
return NULL;
}
-/**
- * cairo_xcb_surface_create:
- * @c: an XCB connection
- * @drawable: an XCB drawable
- * @visual: the visual to use for drawing to @drawable. The depth
- * of the visual must match the depth of the drawable.
- * Currently, only TrueColor visuals are fully supported.
- * @width: the current width of @drawable.
- * @height: the current height of @drawable.
- *
- * Creates an XCB surface that draws to the given drawable.
- * The way that colors are represented in the drawable is specified
- * by the provided visual.
- *
- * Note: If @drawable is a window, then the function
- * cairo_xcb_surface_set_size() must be called whenever the size of the
- * window changes.
- *
- * Return value: the newly created surface
- **/
cairo_surface_t *
-cairo_xcb_surface_create (xcb_connection_t *c,
- xcb_drawable_t drawable,
- xcb_visualtype_t *visual,
- int width,
- int height)
+cairo_xcb_surface_create (xcb_connection_t *xcb_connection,
+ xcb_drawable_t drawable,
+ xcb_visualtype_t *visual,
+ int width,
+ int height)
{
- xcb_screen_t *screen = _cairo_xcb_screen_from_visual (c, visual);
+ cairo_xcb_screen_t *screen;
+ xcb_screen_t *xcb_screen;
+ cairo_format_masks_t image_masks;
+ pixman_format_code_t pixman_format;
+ xcb_render_pictformat_t xrender_format;
+ int depth;
- if (screen == NULL)
- return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_VISUAL));
+ if (xcb_connection_has_error (xcb_connection))
+ return _cairo_surface_create_in_error (CAIRO_STATUS_WRITE_ERROR);
+
+ if (unlikely (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX))
+ return _cairo_surface_create_in_error (CAIRO_STATUS_INVALID_SIZE);
+
+ xcb_screen = _cairo_xcb_screen_from_visual (xcb_connection, visual, &depth);
+ if (unlikely (xcb_screen == NULL))
+ return _cairo_surface_create_in_error (CAIRO_STATUS_INVALID_VISUAL);
+
+ image_masks.alpha_mask = 0;
+ image_masks.red_mask = visual->red_mask;
+ image_masks.green_mask = visual->green_mask;
+ image_masks.blue_mask = visual->blue_mask;
+ if (depth > 16)
+ image_masks.bpp = 32;
+ else if (depth > 8)
+ image_masks.bpp = 16;
+ else if (depth > 1)
+ image_masks.bpp = 8;
+ else
+ image_masks.bpp = 1;
- return _cairo_xcb_surface_create_internal (c, drawable, screen,
- visual, NULL,
- width, height, 0);
+ if (! _pixman_format_from_masks (&image_masks, &pixman_format))
+ return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT));
+
+ screen = _cairo_xcb_screen_get (xcb_connection, xcb_screen);
+ if (unlikely (screen == NULL))
+ return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
+
+ xrender_format =
+ _cairo_xcb_connection_get_xrender_format_for_visual (screen->connection,
+ visual->visual_id);
+
+ return _cairo_xcb_surface_create_internal (screen, drawable, FALSE,
+ pixman_format,
+ xrender_format,
+ width, height);
}
+#if CAIRO_HAS_XLIB_XCB_FUNCTIONS
+slim_hidden_def (cairo_xcb_surface_create);
+#endif
-/**
- * cairo_xcb_surface_create_for_bitmap:
- * @c: an XCB connection
- * @bitmap: an XCB Pixmap (a depth-1 pixmap)
- * @screen: an XCB Screen
- * @width: the current width of @bitmap
- * @height: the current height of @bitmap
- *
- * Creates an XCB surface that draws to the given bitmap.
- * This will be drawn to as a %CAIRO_FORMAT_A1 object.
- *
- * Return value: the newly created surface
- **/
cairo_surface_t *
-cairo_xcb_surface_create_for_bitmap (xcb_connection_t *c,
- xcb_pixmap_t bitmap,
- xcb_screen_t *screen,
- int width,
- int height)
+cairo_xcb_surface_create_for_bitmap (xcb_connection_t *xcb_connection,
+ xcb_screen_t *xcb_screen,
+ xcb_pixmap_t bitmap,
+ int width,
+ int height)
{
- return _cairo_xcb_surface_create_internal (c, bitmap, screen,
- NULL, NULL,
- width, height, 1);
+ cairo_xcb_screen_t *screen;
+
+ if (xcb_connection_has_error (xcb_connection))
+ return _cairo_surface_create_in_error (CAIRO_STATUS_WRITE_ERROR);
+
+ if (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX)
+ return _cairo_surface_create_in_error (CAIRO_STATUS_INVALID_SIZE);
+
+ screen = _cairo_xcb_screen_get (xcb_connection, xcb_screen);
+ if (unlikely (screen == NULL))
+ return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
+
+ return _cairo_xcb_surface_create_internal (screen, bitmap, FALSE,
+ PIXMAN_a1,
+ screen->connection->standard_formats[CAIRO_FORMAT_A1],
+ width, height);
}
+#if CAIRO_HAS_XLIB_XCB_FUNCTIONS
+slim_hidden_def (cairo_xcb_surface_create_for_bitmap);
+#endif
/**
* cairo_xcb_surface_create_with_xrender_format:
- * @c: an XCB connection
+ * @connection: an XCB connection
* @drawable: an XCB drawable
* @screen: the XCB screen associated with @drawable
* @format: the picture format to use for drawing to @drawable. The
@@ -2179,18 +1219,61 @@ cairo_xcb_surface_create_for_bitmap (xcb_connection_t *c,
* Return value: the newly created surface.
**/
cairo_surface_t *
-cairo_xcb_surface_create_with_xrender_format (xcb_connection_t *c,
+cairo_xcb_surface_create_with_xrender_format (xcb_connection_t *xcb_connection,
+ xcb_screen_t *xcb_screen,
xcb_drawable_t drawable,
- xcb_screen_t *screen,
xcb_render_pictforminfo_t *format,
int width,
int height)
{
- return _cairo_xcb_surface_create_internal (c, drawable, screen,
- NULL, format,
- width, height, 0);
+ cairo_xcb_screen_t *screen;
+ cairo_format_masks_t image_masks;
+ pixman_format_code_t pixman_format;
+
+ if (xcb_connection_has_error (xcb_connection))
+ return _cairo_surface_create_in_error (CAIRO_STATUS_WRITE_ERROR);
+
+ if (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX)
+ return _cairo_surface_create_in_error (CAIRO_STATUS_INVALID_SIZE);
+
+ image_masks.alpha_mask =
+ (unsigned long) format->direct.alpha_mask << format->direct.alpha_shift;
+ image_masks.red_mask =
+ (unsigned long) format->direct.red_mask << format->direct.red_shift;
+ image_masks.green_mask =
+ (unsigned long) format->direct.green_mask << format->direct.green_shift;
+ image_masks.blue_mask =
+ (unsigned long) format->direct.blue_mask << format->direct.blue_shift;
+#if 0
+ image_masks.bpp = format->depth;
+#else
+ if (format->depth > 16)
+ image_masks.bpp = 32;
+ else if (format->depth > 8)
+ image_masks.bpp = 16;
+ else if (format->depth > 1)
+ image_masks.bpp = 8;
+ else
+ image_masks.bpp = 1;
+#endif
+
+ if (! _pixman_format_from_masks (&image_masks, &pixman_format))
+ return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT));
+
+ screen = _cairo_xcb_screen_get (xcb_connection, xcb_screen);
+ if (unlikely (screen == NULL))
+ return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
+
+ return _cairo_xcb_surface_create_internal (screen,
+ drawable,
+ FALSE,
+ pixman_format,
+ format->id,
+ width, height);
}
+#if CAIRO_HAS_XLIB_XCB_FUNCTIONS
slim_hidden_def (cairo_xcb_surface_create_with_xrender_format);
+#endif
/**
* cairo_xcb_surface_set_size:
@@ -2210,613 +1293,28 @@ slim_hidden_def (cairo_xcb_surface_create_with_xrender_format);
**/
void
cairo_xcb_surface_set_size (cairo_surface_t *abstract_surface,
- int width,
- int height)
+ int width,
+ int height)
{
- cairo_xcb_surface_t *surface = (cairo_xcb_surface_t *) abstract_surface;
+ cairo_xcb_surface_t *surface;
cairo_status_t status_ignored;
- if (! _cairo_surface_is_xcb (abstract_surface)) {
+ if (abstract_surface->type != CAIRO_SURFACE_TYPE_XCB) {
status_ignored = _cairo_surface_set_error (abstract_surface,
- CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
+ CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
return;
}
- surface->width = width;
- surface->height = height;
-}
-
-/*
- * Glyph rendering support
- */
-
-typedef struct _cairo_xcb_surface_font_private {
- xcb_connection_t *dpy;
- xcb_render_glyphset_t glyphset;
- cairo_format_t format;
- xcb_render_pictforminfo_t *xrender_format;
-} cairo_xcb_surface_font_private_t;
-
-static cairo_status_t
-_cairo_xcb_surface_font_init (xcb_connection_t *dpy,
- cairo_scaled_font_t *scaled_font,
- cairo_format_t format)
-{
- cairo_xcb_surface_font_private_t *font_private;
-
- font_private = malloc (sizeof (cairo_xcb_surface_font_private_t));
- if (!font_private)
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
- font_private->dpy = dpy;
- font_private->format = format;
- font_private->xrender_format = _CAIRO_FORMAT_TO_XRENDER_FORMAT(dpy, format);
- font_private->glyphset = xcb_generate_id(dpy);
-
- /* XXX checking, adding to CloseDisplay */
- xcb_render_create_glyph_set (dpy,
- font_private->glyphset,
- font_private->xrender_format->id);
-
- scaled_font->surface_private = font_private;
- scaled_font->surface_backend = &cairo_xcb_surface_backend;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static void
-_cairo_xcb_surface_scaled_font_fini (cairo_scaled_font_t *scaled_font)
-{
- cairo_xcb_surface_font_private_t *font_private = scaled_font->surface_private;
-
- if (font_private) {
- xcb_render_free_glyph_set (font_private->dpy, font_private->glyphset);
- free (font_private);
- }
-}
-
-static void
-_cairo_xcb_surface_scaled_glyph_fini (cairo_scaled_glyph_t *scaled_glyph,
- cairo_scaled_font_t *scaled_font)
-{
- cairo_xcb_surface_font_private_t *font_private = scaled_font->surface_private;
-
- if (font_private != NULL && scaled_glyph->surface_private != NULL) {
- xcb_render_glyph_t glyph_index = _cairo_scaled_glyph_index(scaled_glyph);
- xcb_render_free_glyphs (font_private->dpy,
- font_private->glyphset,
- 1, &glyph_index);
- }
-}
-
-static cairo_bool_t
-_native_byte_order_lsb (void)
-{
- int x = 1;
-
- return *((char *) &x) == 1;
-}
-
-static cairo_status_t
-_cairo_xcb_surface_add_glyph (cairo_xcb_surface_t *dst,
- cairo_scaled_font_t *scaled_font,
- cairo_scaled_glyph_t *scaled_glyph)
-{
- xcb_render_glyphinfo_t glyph_info;
- xcb_render_glyph_t glyph_index;
- unsigned char *data;
- cairo_status_t status = CAIRO_STATUS_SUCCESS;
- cairo_xcb_surface_font_private_t *font_private;
- cairo_image_surface_t *glyph_surface = scaled_glyph->surface;
- xcb_void_cookie_t cookie;
-
- if (scaled_font->surface_private == NULL) {
- status = _cairo_xcb_surface_font_init (dst->dpy, scaled_font,
- glyph_surface->format);
- if (status)
- return status;
- }
- font_private = scaled_font->surface_private;
-
- /* If the glyph format does not match the font format, then we
- * create a temporary surface for the glyph image with the font's
- * format.
- */
- if (glyph_surface->format != font_private->format) {
- cairo_surface_pattern_t pattern;
- cairo_surface_t *tmp_surface;
-
- tmp_surface = cairo_image_surface_create (font_private->format,
- glyph_surface->width,
- glyph_surface->height);
- status = tmp_surface->status;
- if (unlikely (status))
- goto BAIL;
-
- tmp_surface->device_transform = glyph_surface->base.device_transform;
- tmp_surface->device_transform_inverse = glyph_surface->base.device_transform_inverse;
-
- _cairo_pattern_init_for_surface (&pattern, &glyph_surface->base);
- status = _cairo_surface_paint (tmp_surface,
- CAIRO_OPERATOR_SOURCE, &pattern.base,
- NULL);
- _cairo_pattern_fini (&pattern.base);
-
- glyph_surface = (cairo_image_surface_t *) tmp_surface;
-
- if (unlikely (status))
- goto BAIL;
- }
-
- /* XXX: FRAGILE: We're ignore device_transform scaling here. A bug? */
- glyph_info.x = _cairo_lround (glyph_surface->base.device_transform.x0);
- glyph_info.y = _cairo_lround (glyph_surface->base.device_transform.y0);
- glyph_info.width = glyph_surface->width;
- glyph_info.height = glyph_surface->height;
- glyph_info.x_off = 0;
- glyph_info.y_off = 0;
-
- data = glyph_surface->data;
-
- /* flip formats around */
- switch (scaled_glyph->surface->format) {
- case CAIRO_FORMAT_A1:
- /* local bitmaps are always stored with bit == byte */
- if (_native_byte_order_lsb() != (xcb_get_setup(dst->dpy)->bitmap_format_bit_order == XCB_IMAGE_ORDER_LSB_FIRST)) {
- int c = glyph_surface->stride * glyph_surface->height;
- unsigned char *d;
- unsigned char *new, *n;
-
- new = malloc (c);
- if (!new) {
- status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
- goto BAIL;
- }
- n = new;
- d = data;
- while (c--)
- {
- char b = *d++;
- b = ((b << 1) & 0xaa) | ((b >> 1) & 0x55);
- b = ((b << 2) & 0xcc) | ((b >> 2) & 0x33);
- b = ((b << 4) & 0xf0) | ((b >> 4) & 0x0f);
- *n++ = b;
- }
- data = new;
- }
- break;
- case CAIRO_FORMAT_A8:
- break;
- case CAIRO_FORMAT_ARGB32:
- if (_native_byte_order_lsb() != (xcb_get_setup(dst->dpy)->image_byte_order == XCB_IMAGE_ORDER_LSB_FIRST)) {
- unsigned int c = glyph_surface->stride * glyph_surface->height;
- unsigned char *d;
- unsigned char *new, *n;
-
- new = malloc (c);
- if (new == NULL) {
- status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
- goto BAIL;
- }
- n = new;
- d = data;
- while (c >= 4)
- {
- n[3] = d[0];
- n[2] = d[1];
- n[1] = d[2];
- n[0] = d[3];
- d += 4;
- n += 4;
- c -= 4;
- }
- data = new;
- }
- break;
- case CAIRO_FORMAT_RGB24:
- default:
- ASSERT_NOT_REACHED;
- break;
- }
- /* XXX assume X server wants pixman padding. Xft assumes this as well */
-
- glyph_index = _cairo_scaled_glyph_index (scaled_glyph);
-
- cookie = xcb_render_add_glyphs_checked (dst->dpy, font_private->glyphset,
- 1, &glyph_index, &glyph_info,
- glyph_surface->stride * glyph_surface->height,
- data);
-
- if (data != glyph_surface->data)
- free (data);
-
- status = _cairo_xcb_add_cookie_to_be_checked (dst, cookie);
-
- BAIL:
- if (glyph_surface != scaled_glyph->surface)
- cairo_surface_destroy (&glyph_surface->base);
-
- return status;
-}
-
-#define N_STACK_BUF 1024
-
-static cairo_status_t
-_cairo_xcb_surface_show_glyphs_8 (cairo_xcb_surface_t *dst,
- cairo_operator_t op,
- cairo_xcb_surface_t *src,
- int src_x_offset, int src_y_offset,
- const cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_scaled_font_t *scaled_font)
-{
- cairo_xcb_surface_font_private_t *font_private = scaled_font->surface_private;
- xcb_render_util_composite_text_stream_t *stream;
- xcb_void_cookie_t cookie;
- int i;
- int thisX, thisY;
- int lastX = 0, lastY = 0;
- uint8_t glyph;
-
- stream = xcb_render_util_composite_text_stream (font_private->glyphset, num_glyphs, 0);
-
- for (i = 0; i < num_glyphs; ++i) {
- thisX = _cairo_lround (glyphs[i].x);
- thisY = _cairo_lround (glyphs[i].y);
- glyph = glyphs[i].index;
- xcb_render_util_glyphs_8 (stream, thisX - lastX, thisY - lastY, 1, &glyph);
- lastX = thisX;
- lastY = thisY;
- }
-
- cookie = xcb_render_util_composite_text_checked (dst->dpy,
- _render_operator (op),
- src->src_picture,
- dst->dst_picture,
- font_private->xrender_format->id,
- src_x_offset + _cairo_lround (glyphs[0].x),
- src_y_offset + _cairo_lround (glyphs[0].y),
- stream);
-
- xcb_render_util_composite_text_free (stream);
-
- return _cairo_xcb_add_cookie_to_be_checked (dst, cookie);
-}
-
-static cairo_status_t
-_cairo_xcb_surface_show_glyphs_16 (cairo_xcb_surface_t *dst,
- cairo_operator_t op,
- cairo_xcb_surface_t *src,
- int src_x_offset, int src_y_offset,
- const cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_scaled_font_t *scaled_font)
-{
- cairo_xcb_surface_font_private_t *font_private = scaled_font->surface_private;
- xcb_render_util_composite_text_stream_t *stream;
- xcb_void_cookie_t cookie;
- int i;
- int thisX, thisY;
- int lastX = 0, lastY = 0;
- uint16_t glyph;
-
- stream = xcb_render_util_composite_text_stream (font_private->glyphset, num_glyphs, 0);
-
- for (i = 0; i < num_glyphs; ++i) {
- thisX = _cairo_lround (glyphs[i].x);
- thisY = _cairo_lround (glyphs[i].y);
- glyph = glyphs[i].index;
- xcb_render_util_glyphs_16 (stream, thisX - lastX, thisY - lastY, 1, &glyph);
- lastX = thisX;
- lastY = thisY;
- }
-
- cookie = xcb_render_util_composite_text_checked (dst->dpy,
- _render_operator (op),
- src->src_picture,
- dst->dst_picture,
- font_private->xrender_format->id,
- src_x_offset + _cairo_lround (glyphs[0].x),
- src_y_offset + _cairo_lround (glyphs[0].y),
- stream);
-
- xcb_render_util_composite_text_free (stream);
-
- return _cairo_xcb_add_cookie_to_be_checked (dst, cookie);
-}
-
-static cairo_status_t
-_cairo_xcb_surface_show_glyphs_32 (cairo_xcb_surface_t *dst,
- cairo_operator_t op,
- cairo_xcb_surface_t *src,
- int src_x_offset, int src_y_offset,
- const cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_scaled_font_t *scaled_font)
-{
- cairo_xcb_surface_font_private_t *font_private = scaled_font->surface_private;
- xcb_render_util_composite_text_stream_t *stream;
- xcb_void_cookie_t cookie;
- int i;
- int thisX, thisY;
- int lastX = 0, lastY = 0;
- uint32_t glyph;
-
- stream = xcb_render_util_composite_text_stream (font_private->glyphset, num_glyphs, 0);
-
- for (i = 0; i < num_glyphs; ++i) {
- thisX = _cairo_lround (glyphs[i].x);
- thisY = _cairo_lround (glyphs[i].y);
- glyph = glyphs[i].index;
- xcb_render_util_glyphs_32 (stream, thisX - lastX, thisY - lastY, 1, &glyph);
- lastX = thisX;
- lastY = thisY;
- }
-
- cookie = xcb_render_util_composite_text_checked (dst->dpy,
- _render_operator (op),
- src->src_picture,
- dst->dst_picture,
- font_private->xrender_format->id,
- src_x_offset + _cairo_lround (glyphs[0].x),
- src_y_offset + _cairo_lround (glyphs[0].y),
- stream);
-
- xcb_render_util_composite_text_free (stream);
-
- return _cairo_xcb_add_cookie_to_be_checked (dst, cookie);
-}
-
-typedef cairo_status_t (*cairo_xcb_surface_show_glyphs_func_t)
- (cairo_xcb_surface_t *, cairo_operator_t, cairo_xcb_surface_t *, int, int,
- const cairo_glyph_t *, int, cairo_scaled_font_t *);
-
-static cairo_bool_t
-_cairo_xcb_surface_owns_font (cairo_xcb_surface_t *dst,
- cairo_scaled_font_t *scaled_font)
-{
- cairo_xcb_surface_font_private_t *font_private;
-
- font_private = scaled_font->surface_private;
- if ((scaled_font->surface_backend != NULL &&
- scaled_font->surface_backend != &cairo_xcb_surface_backend) ||
- (font_private != NULL && font_private->dpy != dst->dpy))
- {
- return FALSE;
- }
-
- return TRUE;
-}
-
-static cairo_status_t
-_cairo_xcb_surface_emit_glyphs (cairo_xcb_surface_t *dst,
- cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_scaled_font_t *scaled_font,
- cairo_operator_t op,
- cairo_xcb_surface_t *src,
- cairo_surface_attributes_t *attributes,
- int *remaining_glyphs)
-{
- cairo_scaled_glyph_t *scaled_glyph;
- int i, o;
- unsigned long max_index = 0;
- cairo_status_t status;
- cairo_glyph_t *output_glyphs;
- const cairo_glyph_t *glyphs_chunk;
- int glyphs_remaining, chunk_size, max_chunk_size;
- cairo_xcb_surface_show_glyphs_func_t show_glyphs_func;
-
- /* We make a copy of the glyphs so that we can elide any size-zero
- * glyphs to workaround an X server bug, (present in at least Xorg
- * 7.1 without EXA). */
- output_glyphs = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t));
- if (output_glyphs == NULL)
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
- for (i = 0, o = 0; i < num_glyphs; i++) {
- if (glyphs[i].index > max_index)
- max_index = glyphs[i].index;
- status = _cairo_scaled_glyph_lookup (scaled_font,
- glyphs[i].index,
- CAIRO_SCALED_GLYPH_INFO_SURFACE,
- &scaled_glyph);
- if (status) {
- free (output_glyphs);
- return status;
- }
-
- /* Don't put any size-zero glyphs into output_glyphs to avoid
- * an X server bug which stops rendering glyphs after the
- * first size-zero glyph. */
- if (scaled_glyph->surface->width && scaled_glyph->surface->height) {
- output_glyphs[o++] = glyphs[i];
- if (scaled_glyph->surface_private == NULL) {
- _cairo_xcb_surface_add_glyph (dst, scaled_font, scaled_glyph);
- scaled_glyph->surface_private = (void *) 1;
- }
- }
- }
- num_glyphs = o;
-
- status = _cairo_xcb_surface_ensure_dst_picture (dst);
- if (status) {
- free (output_glyphs);
- return status;
- }
-
- max_chunk_size = xcb_get_maximum_request_length (dst->dpy);
- if (max_index < 256) {
- /* XXX: these are all the same size! (28) */
- max_chunk_size -= sizeof(xcb_render_composite_glyphs_8_request_t);
- show_glyphs_func = _cairo_xcb_surface_show_glyphs_8;
- } else if (max_index < 65536) {
- max_chunk_size -= sizeof(xcb_render_composite_glyphs_16_request_t);
- show_glyphs_func = _cairo_xcb_surface_show_glyphs_16;
- } else {
- max_chunk_size -= sizeof(xcb_render_composite_glyphs_32_request_t);
- show_glyphs_func = _cairo_xcb_surface_show_glyphs_32;
- }
- /* XXX: I think this is wrong; this is only the header size (2 longs) */
- /* but should also include the glyph (1 long) */
- /* max_chunk_size /= sz_xGlyphElt; */
- max_chunk_size /= 3*sizeof(uint32_t);
-
- for (glyphs_remaining = num_glyphs, glyphs_chunk = output_glyphs;
- glyphs_remaining;
- glyphs_remaining -= chunk_size, glyphs_chunk += chunk_size)
- {
- chunk_size = MIN (glyphs_remaining, max_chunk_size);
-
- status = show_glyphs_func (dst, op, src,
- attributes->x_offset, attributes->y_offset,
- glyphs_chunk, chunk_size, scaled_font);
- if (status) {
- free (output_glyphs);
- return status;
- }
- }
-
- /* We wouldn't want to leak memory, would we? */
- free(output_glyphs);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_int_status_t
-_cairo_xcb_surface_show_glyphs (void *abstract_dst,
- cairo_operator_t op,
- const cairo_pattern_t *src_pattern,
- cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_scaled_font_t *scaled_font,
- cairo_clip_t *clip,
- int *remaining_glyphs)
-{
- cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
- cairo_xcb_surface_t *dst = abstract_dst;
-
- composite_operation_t operation;
- cairo_surface_attributes_t attributes;
- cairo_xcb_surface_t *src = NULL;
-
- cairo_region_t *clip_region = NULL;
-
- if (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE_TEXT (dst) || dst->xrender_format.id == XCB_NONE)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- /* Just let unbounded operators go through the fallback code
- * instead of trying to do the fixups here */
- if (!_cairo_operator_bounded_by_mask (op))
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- /* Render <= 0.10 seems to have a bug with PictOpSrc and glyphs --
- * the solid source seems to be multiplied by the glyph mask, and
- * then the entire thing is copied to the destination surface,
- * including the fully transparent "background" of the rectangular
- * glyph surface. */
- if (op == CAIRO_OPERATOR_SOURCE &&
- !CAIRO_SURFACE_RENDER_AT_LEAST(dst, 0, 11))
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- /* We can only use our code if we either have no clip or
- * have a real native clip region set. If we're using
- * fallback clip masking, we have to go through the full
- * fallback path.
- */
- if (clip != NULL) {
- status = _cairo_clip_get_region (clip, &clip_region);
- assert (status != CAIRO_INT_STATUS_NOTHING_TO_DO);
- if (status)
- return status;
- }
-
- operation = _categorize_composite_operation (dst, op, src_pattern, TRUE);
- if (operation == DO_UNSUPPORTED)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- if (! _cairo_xcb_surface_owns_font (dst, scaled_font))
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- /* After passing all those tests, we're now committed to rendering
- * these glyphs or to fail trying. We first upload any glyphs to
- * the X server that it doesn't have already, then we draw
- * them. We tie into the scaled_font's glyph cache and remove
- * glyphs from the X server when they are ejected from the
- * scaled_font cache.
- */
-
- /* PictOpClear doesn't seem to work with CompositeText; it seems to ignore
- * the mask (the glyphs). This code below was executed as a side effect
- * of going through the _clip_and_composite fallback code for old_show_glyphs,
- * so PictOpClear was never used with CompositeText before.
- */
- if (op == CAIRO_OPERATOR_CLEAR) {
- src_pattern = &_cairo_pattern_white.base;
- op = CAIRO_OPERATOR_DEST_OUT;
- }
-
- if (src_pattern->type == CAIRO_PATTERN_TYPE_SOLID) {
- status = _cairo_pattern_acquire_surface (src_pattern, &dst->base,
- 0, 0, 1, 1,
- CAIRO_PATTERN_ACQUIRE_NONE,
- (cairo_surface_t **) &src,
- &attributes);
- } else {
- cairo_rectangle_int_t glyph_extents;
-
- status = _cairo_scaled_font_glyph_device_extents (scaled_font,
- glyphs,
- num_glyphs,
- &glyph_extents,
- NULL);
- if (status)
- goto BAIL;
-
- status = _cairo_pattern_acquire_surface (src_pattern, &dst->base,
- glyph_extents.x, glyph_extents.y,
- glyph_extents.width, glyph_extents.height,
- CAIRO_PATTERN_ACQUIRE_NO_REFLECT,
- (cairo_surface_t **) &src,
- &attributes);
- }
-
- if (status)
- goto BAIL;
-
- operation = _recategorize_composite_operation (dst, op, src, &attributes, TRUE);
- if (operation == DO_UNSUPPORTED) {
- status = CAIRO_INT_STATUS_UNSUPPORTED;
- goto BAIL;
- }
-
- status = _cairo_xcb_surface_set_clip_region (dst, clip_region);
- if (unlikely (status))
- goto BAIL;
-
- status = _cairo_xcb_surface_set_attributes (src, &attributes);
- if (status)
- goto BAIL;
-
- /* Send all unsent glyphs to the server, and count the max of the glyph indices */
- _cairo_scaled_font_freeze_cache (scaled_font);
-
- if (_cairo_xcb_surface_owns_font (dst, scaled_font)) {
- status = _cairo_xcb_surface_emit_glyphs (dst,
- glyphs, num_glyphs,
- scaled_font,
- op,
- src,
- &attributes,
- remaining_glyphs);
- } else {
- status = CAIRO_INT_STATUS_UNSUPPORTED;
+ if (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX) {
+ status_ignored = _cairo_surface_set_error (abstract_surface,
+ CAIRO_STATUS_INVALID_SIZE);
+ return;
}
- _cairo_scaled_font_thaw_cache (scaled_font);
-
- BAIL:
- if (src)
- _cairo_pattern_release_surface (src_pattern, &src->base, &attributes);
- return status;
+ surface = (cairo_xcb_surface_t *) abstract_surface;
+ surface->width = width;
+ surface->height = height;
}
+#if CAIRO_HAS_XLIB_XCB_FUNCTIONS
+slim_hidden_def (cairo_xcb_surface_set_size);
+#endif
diff --git a/src/cairo-xcb-xrender.h b/src/cairo-xcb-xrender.h
deleted file mode 100644
index 09c6097..0000000
--- a/src/cairo-xcb-xrender.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/* cairo - a vector graphics library with display and print output
- *
- * Copyright © 2002 University of Southern California
- *
- * 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 University of Southern
- * California.
- *
- * Contributor(s):
- * Carl D. Worth <cworth at cworth.org>
- */
-
-#ifndef CAIRO_XCB_XRENDER_H
-#define CAIRO_XCB_XRENDER_H
-
-#include "cairo.h"
-
-#if CAIRO_HAS_XCB_SURFACE
-
-#include <xcb/xcb.h>
-#include <xcb/render.h>
-
-CAIRO_BEGIN_DECLS
-
-cairo_public cairo_surface_t *
-cairo_xcb_surface_create_with_xrender_format (xcb_connection_t *c,
- xcb_drawable_t drawable,
- xcb_screen_t *screen,
- xcb_render_pictforminfo_t *format,
- int width,
- int height);
-
-CAIRO_END_DECLS
-
-#else /* CAIRO_HAS_XCB_SURFACE */
-# error Cairo was not compiled with support for the xcb backend
-#endif /* CAIRO_HAS_XCB_SURFACE */
-
-#endif /* CAIRO_XCB_XRENDER_H */
diff --git a/src/cairo-xcb.h b/src/cairo-xcb.h
index 1b6d2e6..a1e9da1 100644
--- a/src/cairo-xcb.h
+++ b/src/cairo-xcb.h
@@ -1,6 +1,7 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2002 University of Southern California
+ * 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
@@ -32,6 +33,7 @@
*
* Contributor(s):
* Carl D. Worth <cworth at cworth.org>
+ * Chris Wilson <chris at chris-wilson.co.uk>
*/
#ifndef CAIRO_XCB_H
@@ -42,28 +44,49 @@
#if CAIRO_HAS_XCB_SURFACE
#include <xcb/xcb.h>
+#include <xcb/render.h>
CAIRO_BEGIN_DECLS
cairo_public cairo_surface_t *
-cairo_xcb_surface_create (xcb_connection_t *c,
+cairo_xcb_surface_create (xcb_connection_t *connection,
xcb_drawable_t drawable,
- xcb_visualtype_t *visual,
- int width,
- int height);
+ xcb_visualtype_t *visual,
+ int width,
+ int height);
cairo_public cairo_surface_t *
-cairo_xcb_surface_create_for_bitmap (xcb_connection_t *c,
- xcb_pixmap_t bitmap,
- xcb_screen_t *screen,
- int width,
- int height);
+cairo_xcb_surface_create_for_bitmap (xcb_connection_t *connection,
+ xcb_screen_t *screen,
+ xcb_pixmap_t bitmap,
+ int width,
+ int height);
+
+cairo_public cairo_surface_t *
+cairo_xcb_surface_create_with_xrender_format (xcb_connection_t *connection,
+ xcb_screen_t *screen,
+ xcb_drawable_t drawable,
+ xcb_render_pictforminfo_t *format,
+ int width,
+ int height);
cairo_public void
cairo_xcb_surface_set_size (cairo_surface_t *surface,
int width,
int height);
+/* debug interface */
+
+cairo_public void
+cairo_xcb_device_debug_cap_xshm_version (cairo_device_t *device,
+ int major_version,
+ int minor_version);
+
+cairo_public void
+cairo_xcb_device_debug_cap_xrender_version (cairo_device_t *device,
+ int major_version,
+ int minor_version);
+
CAIRO_END_DECLS
#else /* CAIRO_HAS_XCB_SURFACE */
diff --git a/src/cairo-xlib-xcb-surface.c b/src/cairo-xlib-xcb-surface.c
new file mode 100644
index 0000000..a8e0cde
--- /dev/null
+++ b/src/cairo-xlib-xcb-surface.c
@@ -0,0 +1,515 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2002 University of Southern California
+ * 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 University of Southern
+ * California.
+ *
+ * Contributor(s):
+ * Carl D. Worth <cworth at cworth.org>
+ * Chris Wilson <chris at chris-wilson.co.uk>
+ */
+
+#include "cairoint.h"
+
+#include "cairo-xlib.h"
+#include "cairo-xcb.h"
+
+#include "cairo-xcb-private.h"
+#include "cairo-xlib-xrender-private.h"
+
+#include <X11/Xlib-xcb.h>
+
+static cairo_surface_t *
+_cairo_xlib_xcb_surface_create (void *dpy,
+ void *scr,
+ void *visual,
+ void *format,
+ cairo_surface_t *xcb);
+
+static cairo_surface_t *
+_cairo_xlib_xcb_surface_create_similar (void *abstract_other,
+ cairo_content_t content,
+ int width,
+ int height)
+{
+ cairo_xlib_xcb_surface_t *other = abstract_other;
+ cairo_surface_t *xcb;
+
+ xcb = other->xcb->base.backend->create_similar (other->xcb, content, width, height);
+ if (unlikely (xcb == NULL || xcb->status))
+ return xcb;
+
+ return _cairo_xlib_xcb_surface_create (other->display, other->screen, NULL, NULL, xcb);
+}
+
+static cairo_status_t
+_cairo_xlib_xcb_surface_finish (void *abstract_surface)
+{
+ cairo_xlib_xcb_surface_t *surface = abstract_surface;
+ cairo_status_t status;
+
+ cairo_surface_finish (&surface->xcb->base);
+ status = surface->xcb->base.status;
+ cairo_surface_destroy (&surface->xcb->base);
+
+ return status;
+}
+
+static cairo_status_t
+_cairo_xlib_xcb_surface_acquire_source_image (void *abstract_surface,
+ cairo_image_surface_t **image_out,
+ void **image_extra)
+{
+ cairo_xlib_xcb_surface_t *surface = abstract_surface;
+ return _cairo_surface_acquire_source_image (&surface->xcb->base,
+ image_out, image_extra);
+}
+
+static void
+_cairo_xlib_xcb_surface_release_source_image (void *abstract_surface,
+ cairo_image_surface_t *image_out,
+ void *image_extra)
+{
+ cairo_xlib_xcb_surface_t *surface = abstract_surface;
+ _cairo_surface_release_source_image (&surface->xcb->base, image_out, image_extra);
+}
+
+static cairo_bool_t
+_cairo_xlib_xcb_surface_get_extents (void *abstract_surface,
+ cairo_rectangle_int_t *extents)
+{
+ cairo_xlib_xcb_surface_t *surface = abstract_surface;
+ return _cairo_surface_get_extents (&surface->xcb->base, extents);
+}
+
+static void
+_cairo_xlib_xcb_surface_get_font_options (void *abstract_surface,
+ cairo_font_options_t *options)
+{
+ cairo_xlib_xcb_surface_t *surface = abstract_surface;
+ surface->xcb->base.backend->get_font_options (surface->xcb, options);
+}
+
+static cairo_int_status_t
+_cairo_xlib_xcb_surface_paint (void *abstract_surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_clip_t *clip)
+{
+ cairo_xlib_xcb_surface_t *surface = abstract_surface;
+ return surface->xcb->base.backend->paint (surface->xcb, op, source, clip);
+}
+
+static cairo_int_status_t
+_cairo_xlib_xcb_surface_mask (void *abstract_surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ const cairo_pattern_t *mask,
+ cairo_clip_t *clip)
+{
+ cairo_xlib_xcb_surface_t *surface = abstract_surface;
+ return surface->xcb->base.backend->mask (surface->xcb, op, source, mask, clip);
+}
+
+static cairo_int_status_t
+_cairo_xlib_xcb_surface_stroke (void *abstract_surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_path_fixed_t *path,
+ const cairo_stroke_style_t *style,
+ const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm_inverse,
+ double tolerance,
+ cairo_antialias_t antialias,
+ cairo_clip_t *clip)
+{
+ cairo_xlib_xcb_surface_t *surface = abstract_surface;
+ return surface->xcb->base.backend->stroke (surface->xcb,
+ op, source, path, style,
+ ctm, ctm_inverse,
+ tolerance, antialias, clip);
+}
+
+static cairo_int_status_t
+_cairo_xlib_xcb_surface_fill (void *abstract_surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_path_fixed_t *path,
+ cairo_fill_rule_t fill_rule,
+ double tolerance,
+ cairo_antialias_t antialias,
+ cairo_clip_t *clip)
+{
+ cairo_xlib_xcb_surface_t *surface = abstract_surface;
+ return surface->xcb->base.backend->fill (surface->xcb,
+ op, source, path,
+ fill_rule, tolerance, antialias,
+ clip);
+}
+
+static cairo_int_status_t
+_cairo_xlib_xcb_surface_glyphs (void *abstract_surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_scaled_font_t *scaled_font,
+ cairo_clip_t *clip,
+ int *num_remaining)
+{
+ cairo_xlib_xcb_surface_t *surface = abstract_surface;
+ return surface->xcb->base.backend->show_glyphs (surface->xcb, op, source,
+ glyphs, num_glyphs, scaled_font,
+ clip, num_remaining);
+}
+
+static cairo_status_t
+_cairo_xlib_xcb_surface_flush (void *abstract_surface)
+{
+ cairo_xlib_xcb_surface_t *surface = abstract_surface;
+ return surface->xcb->base.backend->flush (surface->xcb);
+}
+
+static cairo_status_t
+_cairo_xlib_xcb_surface_mark_dirty (void *abstract_surface,
+ int x, int y,
+ int width, int height)
+{
+ cairo_xlib_xcb_surface_t *surface = abstract_surface;
+ return surface->xcb->base.backend->mark_dirty_rectangle (surface->xcb, x, y, width, height);
+}
+
+static const cairo_surface_backend_t _cairo_xlib_xcb_surface_backend = {
+ CAIRO_SURFACE_TYPE_XLIB,
+ _cairo_xlib_xcb_surface_create_similar,
+ _cairo_xlib_xcb_surface_finish,
+ _cairo_xlib_xcb_surface_acquire_source_image,
+ _cairo_xlib_xcb_surface_release_source_image,
+ NULL, NULL, NULL, /* dest acquire/release/clone */
+
+ NULL, /* composite */
+ NULL, /* fill */
+ NULL, /* trapezoids */
+ NULL, /* span */
+ NULL, /* check-span */
+
+ NULL, /* copy_page */
+ NULL, /* show_page */
+ _cairo_xlib_xcb_surface_get_extents,
+ NULL, /* old-glyphs */
+ _cairo_xlib_xcb_surface_get_font_options,
+
+ _cairo_xlib_xcb_surface_flush,
+ _cairo_xlib_xcb_surface_mark_dirty,
+ NULL, NULL, /* font/glyph fini */
+
+ _cairo_xlib_xcb_surface_paint,
+ _cairo_xlib_xcb_surface_mask,
+ _cairo_xlib_xcb_surface_stroke,
+ _cairo_xlib_xcb_surface_fill,
+ _cairo_xlib_xcb_surface_glyphs,
+};
+
+static cairo_surface_t *
+_cairo_xlib_xcb_surface_create (void *dpy,
+ void *scr,
+ void *visual,
+ void *format,
+ cairo_surface_t *xcb)
+{
+ cairo_xlib_xcb_surface_t *surface;
+
+ if (unlikely (xcb->status))
+ return xcb;
+
+ surface = malloc (sizeof (*surface));
+ if (unlikely (surface == NULL)) {
+ cairo_surface_destroy (xcb);
+ return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
+ }
+
+ _cairo_surface_init (&surface->base,
+ &_cairo_xlib_xcb_surface_backend,
+ xcb->device,
+ xcb->content);
+
+ surface->display = dpy;
+ surface->screen = scr;
+ surface->visual = visual;
+ surface->format = format;
+ surface->xcb = (cairo_xcb_surface_t *) xcb;
+
+ return &surface->base;
+}
+
+static Screen *
+_cairo_xlib_screen_from_visual (Display *dpy, Visual *visual)
+{
+ int s, d, v;
+
+ for (s = 0; s < ScreenCount (dpy); s++) {
+ Screen *screen;
+
+ screen = ScreenOfDisplay (dpy, s);
+ if (visual == DefaultVisualOfScreen (screen))
+ return screen;
+
+ for (d = 0; d < screen->ndepths; d++) {
+ Depth *depth;
+
+ depth = &screen->depths[d];
+ for (v = 0; v < depth->nvisuals; v++)
+ if (visual == &depth->visuals[v])
+ return screen;
+ }
+ }
+
+ return NULL;
+}
+
+cairo_surface_t *
+cairo_xlib_surface_create (Display *dpy,
+ Drawable drawable,
+ Visual *visual,
+ int width,
+ int height)
+{
+ Screen *scr;
+ xcb_visualtype_t xcb_visual;
+
+ scr = _cairo_xlib_screen_from_visual (dpy, visual);
+ if (scr == NULL)
+ return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_VISUAL));
+
+ xcb_visual.visual_id = visual->visualid;
+#if defined(__cplusplus) || defined(c_plusplus)
+ xcb_visual._class = visual->c_class;
+#else
+ xcb_visual._class = visual->class;
+#endif
+ xcb_visual.bits_per_rgb_value = visual->bits_per_rgb;
+ xcb_visual.colormap_entries = visual->map_entries;
+ xcb_visual.red_mask = visual->red_mask;
+ xcb_visual.green_mask = visual->green_mask;
+ xcb_visual.blue_mask = visual->blue_mask;
+
+ return _cairo_xlib_xcb_surface_create (dpy, scr, visual, NULL,
+ cairo_xcb_surface_create (XGetXCBConnection (dpy),
+ drawable,
+ &xcb_visual,
+ width, height));
+}
+
+cairo_surface_t *
+cairo_xlib_surface_create_for_bitmap (Display *dpy,
+ Pixmap bitmap,
+ Screen *scr,
+ int width,
+ int height)
+{
+ return _cairo_xlib_xcb_surface_create (dpy, scr, NULL, NULL,
+ cairo_xcb_surface_create_for_bitmap (XGetXCBConnection (dpy),
+ (xcb_screen_t *) scr,
+ bitmap,
+ width, height));
+}
+
+#if CAIRO_HAS_XLIB_XRENDER_SURFACE
+cairo_surface_t *
+cairo_xlib_surface_create_with_xrender_format (Display *dpy,
+ Drawable drawable,
+ Screen *scr,
+ XRenderPictFormat *format,
+ int width,
+ int height)
+{
+ xcb_render_pictforminfo_t xcb_format;
+
+ xcb_format.id = format->id;
+ xcb_format.type = format->type;
+ xcb_format.depth = format->depth;
+ xcb_format.direct.red_shift = format->direct.red;
+ xcb_format.direct.red_mask = format->direct.redMask;
+ xcb_format.direct.green_shift = format->direct.green;
+ xcb_format.direct.green_mask = format->direct.greenMask;
+ xcb_format.direct.blue_shift = format->direct.blue;
+ xcb_format.direct.blue_mask = format->direct.blueMask;
+ xcb_format.direct.alpha_shift = format->direct.alpha;
+ xcb_format.direct.alpha_mask = format->direct.alphaMask;
+ xcb_format.colormap = format->colormap;
+
+ return _cairo_xlib_xcb_surface_create (dpy, scr, NULL, format,
+ cairo_xcb_surface_create_with_xrender_format (XGetXCBConnection (dpy),
+ (xcb_screen_t *) scr,
+ drawable,
+ &xcb_format,
+ width, height));
+}
+
+XRenderPictFormat *
+cairo_xlib_surface_get_xrender_format (cairo_surface_t *surface)
+{
+ cairo_xlib_xcb_surface_t *xlib_surface = (cairo_xlib_xcb_surface_t *) surface;
+
+ /* Throw an error for a non-xlib surface */
+ if (surface->type != CAIRO_SURFACE_TYPE_XLIB) {
+ _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
+ return NULL;
+ }
+
+ return xlib_surface->format;
+}
+#endif
+
+void
+cairo_xlib_surface_set_size (cairo_surface_t *abstract_surface,
+ int width,
+ int height)
+{
+ cairo_xlib_xcb_surface_t *surface = (cairo_xlib_xcb_surface_t *) abstract_surface;
+ cairo_status_t status;
+
+ if (surface->base.type != CAIRO_SURFACE_TYPE_XLIB) {
+ status = _cairo_surface_set_error (abstract_surface,
+ CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
+ return;
+ }
+
+ cairo_xcb_surface_set_size (&surface->xcb->base, width, height);
+}
+
+void
+cairo_xlib_surface_set_drawable (cairo_surface_t *abstract_surface,
+ Drawable drawable,
+ int width,
+ int height)
+{
+ cairo_xlib_xcb_surface_t *surface = (cairo_xlib_xcb_surface_t *)abstract_surface;
+ cairo_status_t status;
+
+ if (surface->base.type != CAIRO_SURFACE_TYPE_XLIB) {
+ status = _cairo_surface_set_error (abstract_surface,
+ CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
+ return;
+ }
+
+ ASSERT_NOT_REACHED;
+}
+
+Display *
+cairo_xlib_surface_get_display (cairo_surface_t *abstract_surface)
+{
+ cairo_xlib_xcb_surface_t *surface = (cairo_xlib_xcb_surface_t *) abstract_surface;
+
+ if (surface->base.type != CAIRO_SURFACE_TYPE_XLIB) {
+ _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
+ return NULL;
+ }
+
+ return surface->display;
+}
+
+Drawable
+cairo_xlib_surface_get_drawable (cairo_surface_t *abstract_surface)
+{
+ cairo_xlib_xcb_surface_t *surface = (cairo_xlib_xcb_surface_t *) abstract_surface;
+
+ if (surface->base.type != CAIRO_SURFACE_TYPE_XLIB) {
+ _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
+ return 0;
+ }
+
+ return surface->xcb->drawable;
+}
+
+Screen *
+cairo_xlib_surface_get_screen (cairo_surface_t *abstract_surface)
+{
+ cairo_xlib_xcb_surface_t *surface = (cairo_xlib_xcb_surface_t *) abstract_surface;
+
+ if (surface->base.type != CAIRO_SURFACE_TYPE_XLIB) {
+ _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
+ return NULL;
+ }
+
+ return surface->screen;
+}
+
+Visual *
+cairo_xlib_surface_get_visual (cairo_surface_t *abstract_surface)
+{
+ cairo_xlib_xcb_surface_t *surface = (cairo_xlib_xcb_surface_t *) abstract_surface;
+
+ if (surface->base.type != CAIRO_SURFACE_TYPE_XLIB) {
+ _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
+ return NULL;
+ }
+
+ return surface->visual;
+}
+
+int
+cairo_xlib_surface_get_depth (cairo_surface_t *abstract_surface)
+{
+ cairo_xlib_xcb_surface_t *surface = (cairo_xlib_xcb_surface_t *) abstract_surface;
+
+ if (surface->base.type != CAIRO_SURFACE_TYPE_XLIB) {
+ _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
+ return 0;
+ }
+
+ return surface->xcb->depth;
+}
+
+int
+cairo_xlib_surface_get_width (cairo_surface_t *abstract_surface)
+{
+ cairo_xlib_xcb_surface_t *surface = (cairo_xlib_xcb_surface_t *) abstract_surface;
+
+ if (surface->base.type != CAIRO_SURFACE_TYPE_XLIB) {
+ _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
+ return 0;
+ }
+
+ return surface->xcb->width;
+}
+
+int
+cairo_xlib_surface_get_height (cairo_surface_t *abstract_surface)
+{
+ cairo_xlib_xcb_surface_t *surface = (cairo_xlib_xcb_surface_t *) abstract_surface;
+
+ if (surface->base.type != CAIRO_SURFACE_TYPE_XLIB) {
+ _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
+ return 0;
+ }
+
+ return surface->xcb->height;
+}
diff --git a/src/cairoint.h b/src/cairoint.h
index 0892bbb..acc5769 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -2555,9 +2555,25 @@ cairo_private unsigned long
_cairo_pattern_hash (const cairo_pattern_t *pattern);
cairo_private unsigned long
+_cairo_linear_pattern_hash (unsigned long hash,
+ const cairo_linear_pattern_t *linear);
+
+cairo_private unsigned long
+_cairo_radial_pattern_hash (unsigned long hash,
+ const cairo_radial_pattern_t *radial);
+
+cairo_private cairo_bool_t
+_cairo_linear_pattern_equal (const cairo_linear_pattern_t *a,
+ const cairo_linear_pattern_t *b);
+
+cairo_private unsigned long
_cairo_pattern_size (const cairo_pattern_t *pattern);
cairo_private cairo_bool_t
+_cairo_radial_pattern_equal (const cairo_radial_pattern_t *a,
+ const cairo_radial_pattern_t *b);
+
+cairo_private cairo_bool_t
_cairo_pattern_equal (const cairo_pattern_t *a,
const cairo_pattern_t *b);
diff --git a/test/xcb-surface-source.c b/test/xcb-surface-source.c
index debe93e..d359cf2 100644
--- a/test/xcb-surface-source.c
+++ b/test/xcb-surface-source.c
@@ -26,7 +26,6 @@
#include "cairo-test.h"
#if CAIRO_HAS_XCB_SURFACE
#include <cairo-xcb.h>
-#include <cairo-xcb-xrender.h>
#endif
#include "surface-source.c"
commit 77afe8491ed7038a8399c01f10d8f062a7239225
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Fri Jan 22 20:48:54 2010 +0000
drm: Add backends for i915 and i965.
As proof-of-principle add the nearly working demonstrations of using DRM
to render directly with the GPU bypassing both RENDER and GL for
performance whilst preserving high quality rendering.
The basis behind developing these chip specific backends is that this is
the idealised interface that we desire for this chips, and so a target
for cairo-gl as we continue to develop both it and our GL stack.
Note that this backends do not yet fully pass the test suite, so only
use if you are brave and willing to help develop them further.
diff --git a/boilerplate/cairo-boilerplate-drm.c b/boilerplate/cairo-boilerplate-drm.c
index 34d67b5..77a052d 100644
--- a/boilerplate/cairo-boilerplate-drm.c
+++ b/boilerplate/cairo-boilerplate-drm.c
@@ -45,7 +45,7 @@ _cairo_boilerplate_drm_create_surface (const char *name,
int id,
void **closure)
{
- cairo_drm_device_t *device;
+ cairo_device_t *device;
device = cairo_drm_device_default ();
if (device == NULL)
diff --git a/src/Makefile.sources b/src/Makefile.sources
index 8d68860..f6d4fe3 100644
--- a/src/Makefile.sources
+++ b/src/Makefile.sources
@@ -310,12 +310,29 @@ cairo_directfb_sources = cairo-directfb-surface.c
cairo_drm_headers = cairo-drm.h
cairo_drm_private = drm/cairo-drm-private.h \
drm/cairo-drm-intel-private.h \
+ drm/cairo-drm-i915-private.h \
+ drm/cairo-drm-i965-private.h \
+ drm/cairo-drm-intel-brw-defines.h \
+ drm/cairo-drm-intel-brw-structs.h \
+ drm/cairo-drm-intel-brw-eu.h \
drm/cairo-drm-radeon-private.h
cairo_drm_sources = drm/cairo-drm.c \
drm/cairo-drm-bo.c \
drm/cairo-drm-surface.c \
drm/cairo-drm-intel.c \
+ drm/cairo-drm-intel-debug.c \
drm/cairo-drm-intel-surface.c \
+ drm/cairo-drm-i915-surface.c \
+ drm/cairo-drm-i915-glyphs.c \
+ drm/cairo-drm-i915-shader.c \
+ drm/cairo-drm-i915-spans.c \
+ drm/cairo-drm-i965-surface.c \
+ drm/cairo-drm-i965-glyphs.c \
+ drm/cairo-drm-i965-shader.c \
+ drm/cairo-drm-i965-spans.c \
+ drm/cairo-drm-intel-brw-eu.c \
+ drm/cairo-drm-intel-brw-eu-emit.c \
+ drm/cairo-drm-intel-brw-eu-util.c \
drm/cairo-drm-radeon.c \
drm/cairo-drm-radeon-surface.c
cairo_gallium_sources = drm/cairo-drm-gallium-surface.c
diff --git a/src/cairo-drm.h b/src/cairo-drm.h
index 1b50b1b..52b9de2 100644
--- a/src/cairo-drm.h
+++ b/src/cairo-drm.h
@@ -39,56 +39,41 @@
CAIRO_BEGIN_DECLS
-typedef struct _cairo_drm_device cairo_drm_device_t;
-
struct udev_device;
-cairo_public cairo_drm_device_t *
+cairo_public cairo_device_t *
cairo_drm_device_get (struct udev_device *device);
-cairo_public cairo_drm_device_t *
+cairo_public cairo_device_t *
cairo_drm_device_get_for_fd (int fd);
-cairo_public cairo_drm_device_t *
+cairo_public cairo_device_t *
cairo_drm_device_default (void);
-cairo_public cairo_drm_device_t *
-cairo_drm_device_reference (cairo_drm_device_t *device);
-
-cairo_public cairo_status_t
-cairo_drm_device_status (cairo_drm_device_t *device);
-
cairo_public int
-cairo_drm_device_get_fd (cairo_drm_device_t *device);
+cairo_drm_device_get_fd (cairo_device_t *device);
cairo_public void
-cairo_drm_device_throttle (cairo_drm_device_t *device);
-
-cairo_public void
-cairo_drm_device_destroy (cairo_drm_device_t *device);
-
+cairo_drm_device_throttle (cairo_device_t *device);
cairo_public cairo_surface_t *
-cairo_drm_surface_create (cairo_drm_device_t *device,
+cairo_drm_surface_create (cairo_device_t *device,
cairo_content_t content,
int width, int height);
cairo_public cairo_surface_t *
-cairo_drm_surface_create_for_name (cairo_drm_device_t *device,
+cairo_drm_surface_create_for_name (cairo_device_t *device,
unsigned int name,
cairo_format_t format,
int width, int height, int stride);
cairo_public cairo_surface_t *
-cairo_drm_surface_create_from_cacheable_image (cairo_drm_device_t *device,
+cairo_drm_surface_create_from_cacheable_image (cairo_device_t *device,
cairo_surface_t *surface);
cairo_public cairo_status_t
cairo_drm_surface_enable_scan_out (cairo_surface_t *surface);
-cairo_public cairo_drm_device_t *
-cairo_drm_surface_get_device (cairo_surface_t *abstract_surface);
-
cairo_public unsigned int
cairo_drm_surface_get_handle (cairo_surface_t *surface);
diff --git a/src/cairo-misc.c b/src/cairo-misc.c
index cd1032a..56409af 100644
--- a/src/cairo-misc.c
+++ b/src/cairo-misc.c
@@ -674,6 +674,63 @@ _cairo_lround (double d)
#undef LSW
}
+/* Convert a 32-bit IEEE single precision floating point number to a
+ * 'half' representation (s10.5)
+ */
+uint16_t
+_cairo_half_from_float (float f)
+{
+ union {
+ uint32_t ui;
+ float f;
+ } u;
+ int s, e, m;
+
+ u.f = f;
+ s = (u.ui >> 16) & 0x00008000;
+ e = ((u.ui >> 23) & 0x000000ff) - (127 - 15);
+ m = u.ui & 0x007fffff;
+ if (e <= 0) {
+ if (e < -10) {
+ /* underflow */
+ return 0;
+ }
+
+ m = (m | 0x00800000) >> (1 - e);
+
+ /* round to nearest, round 0.5 up. */
+ if (m & 0x00001000)
+ m += 0x00002000;
+ return s | (m >> 13);
+ } else if (e == 0xff - (127 - 15)) {
+ if (m == 0) {
+ /* infinity */
+ return s | 0x7c00;
+ } else {
+ /* nan */
+ m >>= 13;
+ return s | 0x7c00 | m | (m == 0);
+ }
+ } else {
+ /* round to nearest, round 0.5 up. */
+ if (m & 0x00001000) {
+ m += 0x00002000;
+
+ if (m & 0x00800000) {
+ m = 0;
+ e += 1;
+ }
+ }
+
+ if (e > 30) {
+ /* overflow -> infinity */
+ return s | 0x7c00;
+ }
+
+ return s | (e << 10) | (m >> 13);
+ }
+}
+
#ifdef _WIN32
diff --git a/src/cairoint.h b/src/cairoint.h
index 6e059c4..0892bbb 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -949,6 +949,8 @@ _cairo_round (double r)
cairo_private int
_cairo_lround (double d) cairo_const;
+cairo_private uint16_t
+_cairo_half_from_float (float f) cairo_const;
/* cairo-gstate.c */
cairo_private cairo_status_t
diff --git a/src/drm/cairo-drm-bo.c b/src/drm/cairo-drm-bo.c
index 980484a..cb74bac 100644
--- a/src/drm/cairo-drm-bo.c
+++ b/src/drm/cairo-drm-bo.c
@@ -31,11 +31,14 @@
#include "cairo-drm-private.h"
#include "cairo-drm-ioctl-private.h"
+
#include "cairo-error-private.h"
#include <sys/ioctl.h>
#include <errno.h>
+#define ERR_DEBUG(x) x
+
struct drm_gem_close {
/** Handle of the object to be closed. */
uint32_t handle;
@@ -79,8 +82,11 @@ _cairo_drm_bo_open_for_name (const cairo_drm_device_t *dev,
do {
ret = ioctl (dev->fd, DRM_IOCTL_GEM_OPEN, &open);
} while (ret == -1 && errno == EINTR);
- if (ret == -1)
+ if (ret == -1) {
+ ERR_DEBUG((fprintf (stderr, "Failed to open bo for name %d: %s\n",
+ name, strerror (errno))));
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ }
bo->name = name;
bo->size = open.size;
@@ -99,8 +105,11 @@ _cairo_drm_bo_flink (const cairo_drm_device_t *dev,
memset (&flink, 0, sizeof (flink));
flink.handle = bo->handle;
ret = ioctl (dev->fd, DRM_IOCTL_GEM_FLINK, &flink);
- if (ret == -1)
+ if (ret == -1) {
+ ERR_DEBUG((fprintf (stderr, "Failed to flink bo: %s\n",
+ strerror (errno))));
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ }
bo->name = flink.name;
diff --git a/src/drm/cairo-drm-gallium-surface.c b/src/drm/cairo-drm-gallium-surface.c
index c2f331b..73d7547 100644
--- a/src/drm/cairo-drm-gallium-surface.c
+++ b/src/drm/cairo-drm-gallium-surface.c
@@ -444,7 +444,6 @@ gallium_surface_create_internal (gallium_device_t *device,
_cairo_surface_init (&surface->base.base,
&gallium_surface_backend,
- NULL, /* device */
content);
_cairo_drm_surface_init (&surface->base, &device->base);
@@ -551,7 +550,6 @@ gallium_surface_create_for_name (cairo_drm_device_t *base_dev,
content = _cairo_content_from_format (format);
_cairo_surface_init (&surface->base.base,
&gallium_surface_backend,
- NULL, /* device */
content);
_cairo_drm_surface_init (&surface->base, base_dev);
@@ -659,6 +657,7 @@ _cairo_drm_gallium_device_create (int fd, dev_t dev, int vendor_id, int chip_id)
device->base.surface.enable_scan_out = NULL;
device->base.surface.flink = gallium_surface_flink;
+ device->base.device.flush = NULL;
device->base.device.throttle = NULL;
device->base.device.destroy = gallium_device_destroy;
diff --git a/src/drm/cairo-drm-i915-glyphs.c b/src/drm/cairo-drm-i915-glyphs.c
new file mode 100644
index 0000000..babd59e
--- /dev/null
+++ b/src/drm/cairo-drm-i915-glyphs.c
@@ -0,0 +1,534 @@
+/* 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 Red Hat, Inc.
+ *
+ * Contributor(s):
+ * Chris Wilson <chris at chris-wilson.co.uk>
+ */
+
+#include "cairoint.h"
+
+#include "cairo-composite-rectangles-private.h"
+#include "cairo-drm-i915-private.h"
+#include "cairo-error-private.h"
+#include "cairo-rtree-private.h"
+
+static void
+i915_emit_glyph_rectangle_constant (i915_device_t *device,
+ i915_shader_t *shader,
+ int x1, int y1,
+ int x2, int y2,
+ intel_glyph_t *glyph)
+{
+ float *v;
+
+ /* Each vertex is:
+ * 2 vertex coordinates
+ * 2 glyph texture coordinates
+ */
+
+ v = i915_add_rectangle (device);
+
+ /* bottom right */
+ *v++ = x2; *v++ = y2;
+ *v++ = glyph->texcoord[0];
+
+ /* bottom left */
+ *v++ = x1; *v++ = y2;
+ *v++ = glyph->texcoord[1];
+
+ /* top left */
+ *v++ = x1; *v++ = y1;
+ *v++ = glyph->texcoord[2];
+}
+
+static void
+i915_emit_glyph_rectangle_general (i915_device_t *device,
+ i915_shader_t *shader,
+ int x1, int y1,
+ int x2, int y2,
+ intel_glyph_t *glyph)
+{
+ double s, t;
+ float *v;
+
+ /* Each vertex is:
+ * 2 vertex coordinates
+ * [0-2] source texture coordinates
+ * 2 glyph texture coordinates
+ */
+
+ v = i915_add_rectangle (device);
+
+ /* bottom right */
+ *v++ = x2; *v++ = y2;
+ s = x2, t = y2;
+ switch (shader->source.type.vertex) {
+ case VS_CONSTANT:
+ break;
+ case VS_LINEAR:
+ *v++ = i915_shader_linear_texcoord (&shader->source.linear, s, t);
+ break;
+ case VS_RADIAL:
+ cairo_matrix_transform_point (&shader->source.base.matrix, &s, &t);
+ *v++ = s; *v++ = t;
+ break;
+ case VS_TEXTURE:
+ cairo_matrix_transform_point (&shader->source.base.matrix, &s, &t);
+ *v++ = s; *v++ = t;
+ break;
+ case VS_TEXTURE_16:
+ cairo_matrix_transform_point (&shader->source.base.matrix, &s, &t);
+ *v++ = texcoord_2d_16 (s, t);
+ break;
+ }
+ *v++ = glyph->texcoord[0];
+
+ /* bottom left */
+ *v++ = x1; *v++ = y2;
+ s = x1, t = y2;
+ switch (shader->source.type.vertex) {
+ case VS_CONSTANT:
+ break;
+ case VS_LINEAR:
+ *v++ = i915_shader_linear_texcoord (&shader->source.linear, s, t);
+ break;
+ case VS_RADIAL:
+ cairo_matrix_transform_point (&shader->source.base.matrix, &s, &t);
+ *v++ = s; *v++ = t;
+ break;
+ case VS_TEXTURE:
+ cairo_matrix_transform_point (&shader->source.base.matrix, &s, &t);
+ *v++ = s; *v++ = t;
+ break;
+ case VS_TEXTURE_16:
+ cairo_matrix_transform_point (&shader->source.base.matrix, &s, &t);
+ *v++ = texcoord_2d_16 (s, t);
+ break;
+ }
+ *v++ = glyph->texcoord[1];
+
+ /* top left */
+ *v++ = x1; *v++ = y1;
+ s = x1, t = y2;
+ switch (shader->source.type.vertex) {
+ case VS_CONSTANT:
+ break;
+ case VS_LINEAR:
+ *v++ = i915_shader_linear_texcoord (&shader->source.linear, s, t);
+ break;
+ case VS_RADIAL:
+ cairo_matrix_transform_point (&shader->source.base.matrix, &s, &t);
+ *v++ = s; *v++ = t;
+ break;
+ case VS_TEXTURE:
+ cairo_matrix_transform_point (&shader->source.base.matrix, &s, &t);
+ *v++ = s; *v++ = t;
+ break;
+ case VS_TEXTURE_16:
+ cairo_matrix_transform_point (&shader->source.base.matrix, &s, &t);
+ *v++ = texcoord_2d_16 (s, t);
+ break;
+ }
+ *v++ = glyph->texcoord[2];
+}
+
+typedef void
+(*i915_emit_glyph_rectangle_func_t) (i915_device_t *device,
+ i915_shader_t *shader,
+ int x1, int y1,
+ int x2, int y2,
+ intel_glyph_t *glyph);
+
+static cairo_status_t
+i915_surface_mask_internal (i915_surface_t *dst,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ i915_surface_t *mask,
+ cairo_clip_t *clip,
+ const cairo_composite_rectangles_t *extents)
+{
+ i915_device_t *device;
+ i915_shader_t shader;
+ cairo_region_t *clip_region = NULL;
+ cairo_status_t status;
+
+ i915_shader_init (&shader, dst, op);
+
+ status = i915_shader_acquire_pattern (&shader, &shader.source,
+ source, &extents->bounded);
+ if (unlikely (status))
+ return status;
+
+ shader.mask.type.vertex = VS_TEXTURE_16;
+ shader.mask.type.fragment = FS_TEXTURE;
+ shader.mask.base.content = mask->intel.drm.base.content;
+ shader.mask.base.texfmt = TEXCOORDFMT_2D_16;
+ shader.mask.base.n_samplers = 1;
+ shader.mask.base.sampler[0] =
+ (MIPFILTER_NONE << SS2_MIP_FILTER_SHIFT) |
+ i915_texture_filter (CAIRO_FILTER_NEAREST);
+ shader.mask.base.sampler[1] =
+ SS3_NORMALIZED_COORDS |
+ i915_texture_extend (CAIRO_EXTEND_NONE);
+
+ cairo_matrix_init_translate (&shader.mask.base.matrix,
+ -extents->bounded.x + NEAREST_BIAS,
+ -extents->bounded.y + NEAREST_BIAS);
+ cairo_matrix_scale (&shader.mask.base.matrix,
+ 1. / mask->intel.drm.width,
+ 1. / mask->intel.drm.height);
+
+ shader.mask.base.bo = to_intel_bo (mask->intel.drm.bo);
+ shader.mask.base.offset[0] = 0;
+ shader.mask.base.map[0] = mask->map0;
+ shader.mask.base.map[1] = mask->map1;
+
+ if (clip != NULL) {
+ status = _cairo_clip_get_region (clip, &clip_region);
+ assert (status == CAIRO_STATUS_SUCCESS || status == CAIRO_INT_STATUS_UNSUPPORTED);
+
+ if (clip_region != NULL && cairo_region_num_rectangles (clip_region) == 1)
+ clip_region = NULL;
+
+ if (status == CAIRO_INT_STATUS_UNSUPPORTED)
+ i915_shader_set_clip (&shader, clip);
+ }
+
+ status = cairo_device_acquire (dst->intel.drm.base.device);
+ if (unlikely (status))
+ goto CLEANUP_SHADER;
+
+ device = i915_device (dst);
+
+ status = i915_shader_commit (&shader, device);
+ if (unlikely (status))
+ goto CLEANUP_DEVICE;
+
+ if (clip_region != NULL) {
+ unsigned int n, num_rectangles;
+
+ num_rectangles = cairo_region_num_rectangles (clip_region);
+ for (n = 0; n < num_rectangles; n++) {
+ cairo_rectangle_int_t rect;
+
+ cairo_region_get_rectangle (clip_region, n, &rect);
+
+ shader.add_rectangle (&shader,
+ rect.x, rect.y,
+ rect.x + rect.width, rect.y + rect.height);
+ }
+ } else {
+ shader.add_rectangle (&shader,
+ extents->bounded.x, extents->bounded.y,
+ extents->bounded.x + extents->bounded.width,
+ extents->bounded.y + extents->bounded.height);
+ }
+
+ if ((extents->is_bounded & CAIRO_OPERATOR_BOUND_BY_MASK) == 0)
+ status = i915_fixup_unbounded (dst, extents, clip);
+
+CLEANUP_DEVICE:
+ cairo_device_release (&device->intel.base.base);
+CLEANUP_SHADER:
+ i915_shader_fini (&shader);
+ return status;
+}
+
+cairo_int_status_t
+i915_surface_glyphs (void *abstract_surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_scaled_font_t *scaled_font,
+ cairo_clip_t *clip,
+ int *num_remaining)
+{
+ i915_surface_t *surface = abstract_surface;
+ i915_surface_t *mask = NULL;
+ i915_device_t *device;
+ i915_shader_t shader;
+ cairo_composite_rectangles_t extents;
+ cairo_clip_t local_clip;
+ cairo_bool_t have_clip = FALSE;
+ cairo_bool_t overlap;
+ cairo_region_t *clip_region = NULL;
+ intel_bo_t *last_bo = NULL;
+ i915_emit_glyph_rectangle_func_t emit_func;
+ cairo_scaled_glyph_t *glyph_cache[64];
+ cairo_status_t status;
+ int mask_x = 0, mask_y = 0;
+ int i = 0;
+
+ *num_remaining = 0;
+ status = _cairo_composite_rectangles_init_for_glyphs (&extents,
+ surface->intel.drm.width,
+ surface->intel.drm.height,
+ op, source,
+ scaled_font,
+ glyphs, num_glyphs,
+ clip,
+ &overlap);
+ if (unlikely (status))
+ return status;
+
+ if (_cairo_clip_contains_rectangle (clip, &extents))
+ clip = NULL;
+
+ if (clip != NULL && extents.is_bounded) {
+ clip = _cairo_clip_init_copy (&local_clip, clip);
+ status = _cairo_clip_rectangle (clip, &extents.bounded);
+ if (unlikely (status))
+ return status;
+
+ have_clip = TRUE;
+ }
+
+ if (overlap || (extents.is_bounded & CAIRO_OPERATOR_BOUND_BY_MASK) == 0) {
+ cairo_content_t content;
+
+ content = CAIRO_CONTENT_ALPHA;
+ if (scaled_font->options.antialias == CAIRO_ANTIALIAS_SUBPIXEL)
+ content |= CAIRO_CONTENT_COLOR;
+
+ mask = (i915_surface_t *)
+ i915_surface_create_internal (&i915_device (surface)->intel.base,
+ CAIRO_CONTENT_ALPHA,
+ extents.bounded.width,
+ extents.bounded.height,
+ I915_TILING_DEFAULT,
+ TRUE);
+ if (unlikely (mask->intel.drm.base.status))
+ return mask->intel.drm.base.status;
+
+ status = _cairo_surface_paint (&mask->intel.drm.base,
+ CAIRO_OPERATOR_CLEAR,
+ &_cairo_pattern_clear.base,
+ NULL);
+ if (unlikely (status)) {
+ cairo_surface_destroy (&mask->intel.drm.base);
+ return status;
+ }
+
+ i915_shader_init (&shader, mask, CAIRO_OPERATOR_ADD);
+
+ status = i915_shader_acquire_pattern (&shader, &shader.source,
+ &_cairo_pattern_white.base,
+ &extents.bounded);
+ if (unlikely (status)) {
+ cairo_surface_destroy (&mask->intel.drm.base);
+ return status;
+ }
+
+ mask_x = -extents.bounded.x;
+ mask_y = -extents.bounded.y;
+ } else {
+ i915_shader_init (&shader, surface, op);
+
+ status = i915_shader_acquire_pattern (&shader, &shader.source,
+ source, &extents.bounded);
+ if (unlikely (status))
+ return status;
+
+ if (clip != NULL) {
+ status = _cairo_clip_get_region (clip, &clip_region);
+ assert (status == CAIRO_STATUS_SUCCESS || status == CAIRO_INT_STATUS_UNSUPPORTED);
+
+ if (clip_region != NULL && cairo_region_num_rectangles (clip_region) == 1)
+ clip_region = NULL;
+
+ if (status == CAIRO_INT_STATUS_UNSUPPORTED)
+ i915_shader_set_clip (&shader, clip);
+ }
+ }
+
+ shader.mask.type.fragment = FS_TEXTURE;
+ shader.mask.base.content = CAIRO_CONTENT_ALPHA; /* XXX */
+ shader.mask.base.texfmt = TEXCOORDFMT_2D_16;
+ shader.mask.base.n_samplers = 1;
+ shader.mask.base.sampler[0] =
+ (MIPFILTER_NONE << SS2_MIP_FILTER_SHIFT) |
+ i915_texture_filter (CAIRO_FILTER_NEAREST);
+ shader.mask.base.sampler[1] =
+ SS3_NORMALIZED_COORDS |
+ i915_texture_extend (CAIRO_EXTEND_NONE);
+
+ switch (shader.source.type.vertex) {
+ case VS_CONSTANT:
+ emit_func = i915_emit_glyph_rectangle_constant;
+ break;
+ default:
+ case VS_LINEAR:
+ case VS_RADIAL:
+ case VS_TEXTURE:
+ case VS_TEXTURE_16:
+ emit_func = i915_emit_glyph_rectangle_general;
+ break;
+ }
+
+ status = cairo_device_acquire (surface->intel.drm.base.device);
+ if (unlikely (status))
+ goto CLEANUP_SHADER;
+
+ device = i915_device (surface);
+
+ _cairo_scaled_font_freeze_cache (scaled_font);
+ if (scaled_font->surface_private == NULL) {
+ /* XXX couple into list to remove on context destruction */
+ scaled_font->surface_private = device;
+ scaled_font->surface_backend = surface->intel.drm.base.backend;
+ }
+
+ memset (glyph_cache, 0, sizeof (glyph_cache));
+
+ for (i = 0; i < num_glyphs; i++) {
+ cairo_scaled_glyph_t *scaled_glyph;
+ int x, y, x1, x2, y1, y2;
+ int cache_index = glyphs[i].index % ARRAY_LENGTH (glyph_cache);
+ intel_glyph_t *glyph;
+
+ scaled_glyph = glyph_cache[cache_index];
+ if (scaled_glyph == NULL ||
+ _cairo_scaled_glyph_index (scaled_glyph) != glyphs[i].index)
+ {
+ status = _cairo_scaled_glyph_lookup (scaled_font,
+ glyphs[i].index,
+ CAIRO_SCALED_GLYPH_INFO_METRICS,
+ &scaled_glyph);
+ if (unlikely (status))
+ goto FINISH;
+
+ glyph_cache[cache_index] = scaled_glyph;
+ }
+
+ if (unlikely (scaled_glyph->metrics.width == 0 ||
+ scaled_glyph->metrics.height == 0))
+ {
+ continue;
+ }
+
+ /* XXX glyph images are snapped to pixel locations */
+ x = _cairo_lround (glyphs[i].x);
+ y = _cairo_lround (glyphs[i].y);
+
+ x1 = x + _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.x);
+ y1 = y + _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.y);
+ x2 = x + _cairo_fixed_integer_ceil (scaled_glyph->bbox.p2.x);
+ y2 = y + _cairo_fixed_integer_ceil (scaled_glyph->bbox.p2.y);
+
+ if (x2 < extents.bounded.x ||
+ y2 < extents.bounded.y ||
+ x1 > extents.bounded.x + extents.bounded.width ||
+ y1 > extents.bounded.y + extents.bounded.height)
+ {
+ continue;
+ }
+
+ if (scaled_glyph->surface_private == NULL) {
+ status = intel_get_glyph (&device->intel, scaled_font, scaled_glyph);
+ if (unlikely (status == CAIRO_INT_STATUS_NOTHING_TO_DO)) {
+ status = CAIRO_STATUS_SUCCESS;
+ continue;
+ }
+ if (unlikely (status))
+ goto FINISH;
+ }
+ glyph = intel_glyph_pin (scaled_glyph->surface_private);
+
+ if (glyph->cache->buffer.bo != last_bo) {
+ intel_buffer_cache_t *cache = glyph->cache;
+
+ shader.mask.base.bo = cache->buffer.bo;
+ shader.mask.base.offset[0] = cache->buffer.offset;
+ shader.mask.base.map[0] = cache->buffer.map0;
+ shader.mask.base.map[1] = cache->buffer.map1;
+ shader.mask.base.content = CAIRO_CONTENT_ALPHA; /* XXX */
+
+ status = i915_shader_commit (&shader, device);
+ if (unlikely (status))
+ goto FINISH;
+
+ last_bo = cache->buffer.bo;
+ }
+
+ x1 += mask_x; x2 += mask_x;
+ y1 += mask_y; y2 += mask_y;
+
+ /* XXX clip glyph */
+ emit_func (device, &shader, x1, y1, x2, y2, glyph);
+ }
+
+ status = CAIRO_STATUS_SUCCESS;
+ FINISH:
+ _cairo_scaled_font_thaw_cache (scaled_font);
+ cairo_device_release (surface->intel.drm.base.device);
+ CLEANUP_SHADER:
+ i915_shader_fini (&shader);
+
+ if (unlikely (status == CAIRO_INT_STATUS_UNSUPPORTED)) {
+ cairo_path_fixed_t path;
+
+ _cairo_path_fixed_init (&path);
+ status = _cairo_scaled_font_glyph_path (scaled_font,
+ glyphs + i, num_glyphs - i,
+ &path);
+ if (mask_x | mask_y) {
+ _cairo_path_fixed_translate (&path,
+ _cairo_fixed_from_int (mask_x),
+ _cairo_fixed_from_int (mask_y));
+ }
+ if (likely (status == CAIRO_STATUS_SUCCESS)) {
+ status = surface->intel.drm.base.backend->fill (shader.target,
+ shader.op,
+ mask != NULL ? &_cairo_pattern_white.base : source,
+ &path,
+ CAIRO_FILL_RULE_WINDING,
+ 0,
+ scaled_font->options.antialias,
+ clip);
+ }
+ _cairo_path_fixed_fini (&path);
+ }
+
+ if (mask != NULL) {
+ if (likely (status == CAIRO_STATUS_SUCCESS)) {
+ status = i915_surface_mask_internal (surface, op, source, mask,
+ clip, &extents);
+ }
+ cairo_surface_finish (&mask->intel.drm.base);
+ cairo_surface_destroy (&mask->intel.drm.base);
+ }
+
+ if (have_clip)
+ _cairo_clip_fini (&local_clip);
+
+ return status;
+}
diff --git a/src/drm/cairo-drm-i915-private.h b/src/drm/cairo-drm-i915-private.h
new file mode 100644
index 0000000..060c21c
--- /dev/null
+++ b/src/drm/cairo-drm-i915-private.h
@@ -0,0 +1,1169 @@
+/*
+ * Copyright © 2006, 2009 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Authors:
+ * Eric Anholt <eric at anholt.net>
+ * Chris Wilson <chris at chris-wilson.co.uk>
+ */
+
+#ifndef CAIRO_DRM_I915_PRIVATE_H
+#define CAIRO_DRM_I915_PRIVATE_H
+
+#include "cairo-types-private.h"
+
+#include "cairo-drm-private.h"
+#include "cairo-drm-intel-private.h"
+#include "cairo-drm-intel-command-private.h"
+#include "cairo-drm-intel-ioctl-private.h"
+#include "cairo-freelist-private.h"
+
+#define I915_VERBOSE 1
+
+#define I915_MAX_TEX_INDIRECT 4
+#define I915_MAX_TEX_INSN 32
+#define I915_MAX_ALU_INSN 64
+#define I915_MAX_DECL_INSN 27
+#define I915_MAX_TEMPORARY 16
+
+/* Each instruction is 3 dwords long, though most don't require all
+ * this space. Maximum of 123 instructions. Smaller maxes per insn
+ * type.
+ */
+#define _3DSTATE_PIXEL_SHADER_PROGRAM (CMD_3D|(0x1d<<24)|(0x5<<16))
+
+#define REG_TYPE_R 0 /* temporary regs, no need to
+ * dcl, must be written before
+ * read -- Preserved between
+ * phases.
+ */
+#define REG_TYPE_T 1 /* Interpolated values, must be
+ * dcl'ed before use.
+ *
+ * 0..7: texture coord,
+ * 8: diffuse spec,
+ * 9: specular color,
+ * 10: fog parameter in w.
+ */
+#define REG_TYPE_CONST 2 /* Restriction: only one const
+ * can be referenced per
+ * instruction, though it may be
+ * selected for multiple inputs.
+ * Constants not initialized
+ * default to zero.
+ */
+#define REG_TYPE_S 3 /* sampler */
+#define REG_TYPE_OC 4 /* output color (rgba) */
+#define REG_TYPE_OD 5 /* output depth (w), xyz are
+ * temporaries. If not written,
+ * interpolated depth is used?
+ */
+#define REG_TYPE_U 6 /* unpreserved temporaries */
+#define REG_TYPE_MASK 0x7
+#define REG_TYPE_SHIFT 4
+#define REG_NR_MASK 0xf
+
+/* REG_TYPE_T:
+ */
+#define T_TEX0 0
+#define T_TEX1 1
+#define T_TEX2 2
+#define T_TEX3 3
+#define T_TEX4 4
+#define T_TEX5 5
+#define T_TEX6 6
+#define T_TEX7 7
+#define T_DIFFUSE 8
+#define T_SPECULAR 9
+#define T_FOG_W 10 /* interpolated fog is in W coord */
+
+/* Arithmetic instructions */
+
+/* .replicate_swizzle == selection and replication of a particular
+ * scalar channel, ie., .xxxx, .yyyy, .zzzz or .wwww
+ */
+#define A0_NOP (0x0<<24) /* no operation */
+#define A0_ADD (0x1<<24) /* dst = src0 + src1 */
+#define A0_MOV (0x2<<24) /* dst = src0 */
+#define A0_MUL (0x3<<24) /* dst = src0 * src1 */
+#define A0_MAD (0x4<<24) /* dst = src0 * src1 + src2 */
+#define A0_DP2ADD (0x5<<24) /* dst.xyzw = src0.xy dot src1.xy + src2.replicate_swizzle */
+#define A0_DP3 (0x6<<24) /* dst.xyzw = src0.xyz dot src1.xyz */
+#define A0_DP4 (0x7<<24) /* dst.xyzw = src0.xyzw dot src1.xyzw */
+#define A0_FRC (0x8<<24) /* dst = src0 - floor(src0) */
+#define A0_RCP (0x9<<24) /* dst.xyzw = 1/(src0.replicate_swizzle) */
+#define A0_RSQ (0xa<<24) /* dst.xyzw = 1/(sqrt(abs(src0.replicate_swizzle))) */
+#define A0_EXP (0xb<<24) /* dst.xyzw = exp2(src0.replicate_swizzle) */
+#define A0_LOG (0xc<<24) /* dst.xyzw = log2(abs(src0.replicate_swizzle)) */
+#define A0_CMP (0xd<<24) /* dst = (src0 >= 0.0) ? src1 : src2 */
+#define A0_MIN (0xe<<24) /* dst = (src0 < src1) ? src0 : src1 */
+#define A0_MAX (0xf<<24) /* dst = (src0 >= src1) ? src0 : src1 */
+#define A0_FLR (0x10<<24) /* dst = floor(src0) */
+#define A0_MOD (0x11<<24) /* dst = src0 fmod 1.0 */
+#define A0_TRC (0x12<<24) /* dst = int(src0) */
+#define A0_SGE (0x13<<24) /* dst = src0 >= src1 ? 1.0 : 0.0 */
+#define A0_SLT (0x14<<24) /* dst = src0 < src1 ? 1.0 : 0.0 */
+#define A0_DEST_SATURATE (1<<22)
+#define A0_DEST_TYPE_SHIFT 19
+/* Allow: R, OC, OD, U */
+#define A0_DEST_NR_SHIFT 14
+/* Allow R: 0..15, OC,OD: 0..0, U: 0..2 */
+#define A0_DEST_CHANNEL_X (1<<10)
+#define A0_DEST_CHANNEL_Y (2<<10)
+#define A0_DEST_CHANNEL_Z (4<<10)
+#define A0_DEST_CHANNEL_W (8<<10)
+#define A0_DEST_CHANNEL_ALL (0xf<<10)
+#define A0_DEST_CHANNEL_SHIFT 10
+#define A0_SRC0_TYPE_SHIFT 7
+#define A0_SRC0_NR_SHIFT 2
+
+#define A0_DEST_CHANNEL_XY (A0_DEST_CHANNEL_X|A0_DEST_CHANNEL_Y)
+#define A0_DEST_CHANNEL_XYZ (A0_DEST_CHANNEL_XY|A0_DEST_CHANNEL_Z)
+
+#define SRC_X 0
+#define SRC_Y 1
+#define SRC_Z 2
+#define SRC_W 3
+#define SRC_ZERO 4
+#define SRC_ONE 5
+
+#define A1_SRC0_CHANNEL_X_NEGATE (1<<31)
+#define A1_SRC0_CHANNEL_X_SHIFT 28
+#define A1_SRC0_CHANNEL_Y_NEGATE (1<<27)
+#define A1_SRC0_CHANNEL_Y_SHIFT 24
+#define A1_SRC0_CHANNEL_Z_NEGATE (1<<23)
+#define A1_SRC0_CHANNEL_Z_SHIFT 20
+#define A1_SRC0_CHANNEL_W_NEGATE (1<<19)
+#define A1_SRC0_CHANNEL_W_SHIFT 16
+#define A1_SRC1_TYPE_SHIFT 13
+#define A1_SRC1_NR_SHIFT 8
+#define A1_SRC1_CHANNEL_X_NEGATE (1<<7)
+#define A1_SRC1_CHANNEL_X_SHIFT 4
+#define A1_SRC1_CHANNEL_Y_NEGATE (1<<3)
+#define A1_SRC1_CHANNEL_Y_SHIFT 0
+
+#define A2_SRC1_CHANNEL_Z_NEGATE (1<<31)
+#define A2_SRC1_CHANNEL_Z_SHIFT 28
+#define A2_SRC1_CHANNEL_W_NEGATE (1<<27)
+#define A2_SRC1_CHANNEL_W_SHIFT 24
+#define A2_SRC2_TYPE_SHIFT 21
+#define A2_SRC2_NR_SHIFT 16
+#define A2_SRC2_CHANNEL_X_NEGATE (1<<15)
+#define A2_SRC2_CHANNEL_X_SHIFT 12
+#define A2_SRC2_CHANNEL_Y_NEGATE (1<<11)
+#define A2_SRC2_CHANNEL_Y_SHIFT 8
+#define A2_SRC2_CHANNEL_Z_NEGATE (1<<7)
+#define A2_SRC2_CHANNEL_Z_SHIFT 4
+#define A2_SRC2_CHANNEL_W_NEGATE (1<<3)
+#define A2_SRC2_CHANNEL_W_SHIFT 0
+
+/* Texture instructions */
+#define T0_TEXLD (0x15<<24) /* Sample texture using predeclared
+ * sampler and address, and output
+ * filtered texel data to destination
+ * register */
+#define T0_TEXLDP (0x16<<24) /* Same as texld but performs a
+ * perspective divide of the texture
+ * coordinate .xyz values by .w before
+ * sampling. */
+#define T0_TEXLDB (0x17<<24) /* Same as texld but biases the
+ * computed LOD by w. Only S4.6 two's
+ * comp is used. This implies that a
+ * float to fixed conversion is
+ * done. */
+#define T0_TEXKILL (0x18<<24) /* Does not perform a sampling
+ * operation. Simply kills the pixel
+ * if any channel of the address
+ * register is < 0.0. */
+#define T0_DEST_TYPE_SHIFT 19
+/* Allow: R, OC, OD, U */
+/* Note: U (unpreserved) regs do not retain their values between
+ * phases (cannot be used for feedback)
+ *
+ * Note: oC and OD registers can only be used as the destination of a
+ * texture instruction once per phase (this is an implementation
+ * restriction).
+ */
+#define T0_DEST_NR_SHIFT 14
+/* Allow R: 0..15, OC,OD: 0..0, U: 0..2 */
+#define T0_SAMPLER_NR_SHIFT 0 /* This field ignored for TEXKILL */
+#define T0_SAMPLER_NR_MASK (0xf<<0)
+
+#define T1_ADDRESS_REG_TYPE_SHIFT 24 /* Reg to use as texture coord */
+/* Allow R, T, OC, OD -- R, OC, OD are 'dependent' reads, new program phase */
+#define T1_ADDRESS_REG_NR_SHIFT 17
+#define T2_MBZ 0
+
+/* Declaration instructions */
+#define D0_DCL (0x19<<24) /* Declare a t (interpolated attrib)
+ * register or an s (sampler)
+ * register. */
+#define D0_SAMPLE_TYPE_SHIFT 22
+#define D0_SAMPLE_TYPE_2D (0x0<<22)
+#define D0_SAMPLE_TYPE_CUBE (0x1<<22)
+#define D0_SAMPLE_TYPE_VOLUME (0x2<<22)
+#define D0_SAMPLE_TYPE_MASK (0x3<<22)
+
+#define D0_TYPE_SHIFT 19
+/* Allow: T, S */
+#define D0_NR_SHIFT 14
+/* Allow T: 0..10, S: 0..15 */
+#define D0_CHANNEL_X (1<<10)
+#define D0_CHANNEL_Y (2<<10)
+#define D0_CHANNEL_Z (4<<10)
+#define D0_CHANNEL_W (8<<10)
+#define D0_CHANNEL_ALL (0xf<<10)
+#define D0_CHANNEL_NONE (0<<10)
+
+#define D0_CHANNEL_XY (D0_CHANNEL_X|D0_CHANNEL_Y)
+#define D0_CHANNEL_XYZ (D0_CHANNEL_XY|D0_CHANNEL_Z)
+
+/* I915 Errata: Do not allow (xz), (xw), (xzw) combinations for diffuse
+ * or specular declarations.
+ *
+ * For T dcls, only allow: (x), (xy), (xyz), (w), (xyzw)
+ *
+ * Must be zero for S (sampler) dcls
+ */
+#define D1_MBZ 0
+#define D2_MBZ 0
+
+
+/* MASK_* are the unshifted bitmasks of the destination mask in arithmetic
+ * operations
+ */
+#define MASK_X 0x1
+#define MASK_Y 0x2
+#define MASK_Z 0x4
+#define MASK_W 0x8
+#define MASK_XYZ (MASK_X | MASK_Y | MASK_Z)
+#define MASK_XYZW (MASK_XYZ | MASK_W)
+#define MASK_SATURATE 0x10
+
+/* Temporary, undeclared regs. Preserved between phases */
+#define FS_R0 ((REG_TYPE_R << REG_TYPE_SHIFT) | 0)
+#define FS_R1 ((REG_TYPE_R << REG_TYPE_SHIFT) | 1)
+#define FS_R2 ((REG_TYPE_R << REG_TYPE_SHIFT) | 2)
+#define FS_R3 ((REG_TYPE_R << REG_TYPE_SHIFT) | 3)
+
+/* Texture coordinate regs. Must be declared. */
+#define FS_T0 ((REG_TYPE_T << REG_TYPE_SHIFT) | 0)
+#define FS_T1 ((REG_TYPE_T << REG_TYPE_SHIFT) | 1)
+#define FS_T2 ((REG_TYPE_T << REG_TYPE_SHIFT) | 2)
+#define FS_T3 ((REG_TYPE_T << REG_TYPE_SHIFT) | 3)
+#define FS_T4 ((REG_TYPE_T << REG_TYPE_SHIFT) | 4)
+#define FS_T5 ((REG_TYPE_T << REG_TYPE_SHIFT) | 5)
+#define FS_T6 ((REG_TYPE_T << REG_TYPE_SHIFT) | 6)
+#define FS_T7 ((REG_TYPE_T << REG_TYPE_SHIFT) | 7)
+#define FS_T8 ((REG_TYPE_T << REG_TYPE_SHIFT) | 8)
+#define FS_T9 ((REG_TYPE_T << REG_TYPE_SHIFT) | 9)
+#define FS_T10 ((REG_TYPE_T << REG_TYPE_SHIFT) | 10)
+
+/* Constant values */
+#define FS_C0 ((REG_TYPE_CONST << REG_TYPE_SHIFT) | 0)
+#define FS_C1 ((REG_TYPE_CONST << REG_TYPE_SHIFT) | 1)
+#define FS_C2 ((REG_TYPE_CONST << REG_TYPE_SHIFT) | 2)
+#define FS_C3 ((REG_TYPE_CONST << REG_TYPE_SHIFT) | 3)
+#define FS_C4 ((REG_TYPE_CONST << REG_TYPE_SHIFT) | 4)
+#define FS_C5 ((REG_TYPE_CONST << REG_TYPE_SHIFT) | 5)
+#define FS_C6 ((REG_TYPE_CONST << REG_TYPE_SHIFT) | 6)
+#define FS_C7 ((REG_TYPE_CONST << REG_TYPE_SHIFT) | 7)
+
+/* Sampler regs */
+#define FS_S0 ((REG_TYPE_S << REG_TYPE_SHIFT) | 0)
+#define FS_S1 ((REG_TYPE_S << REG_TYPE_SHIFT) | 1)
+#define FS_S2 ((REG_TYPE_S << REG_TYPE_SHIFT) | 2)
+#define FS_S3 ((REG_TYPE_S << REG_TYPE_SHIFT) | 3)
+
+/* Output color */
+#define FS_OC ((REG_TYPE_OC << REG_TYPE_SHIFT) | 0)
+
+/* Output depth */
+#define FS_OD ((REG_TYPE_OD << REG_TYPE_SHIFT) | 0)
+
+/* Unpreserved temporary regs */
+#define FS_U0 ((REG_TYPE_U << REG_TYPE_SHIFT) | 0)
+#define FS_U1 ((REG_TYPE_U << REG_TYPE_SHIFT) | 1)
+#define FS_U2 ((REG_TYPE_U << REG_TYPE_SHIFT) | 2)
+#define FS_U3 ((REG_TYPE_U << REG_TYPE_SHIFT) | 3)
+
+#define X_CHANNEL_SHIFT (REG_TYPE_SHIFT + 3)
+#define Y_CHANNEL_SHIFT (X_CHANNEL_SHIFT + 3)
+#define Z_CHANNEL_SHIFT (Y_CHANNEL_SHIFT + 3)
+#define W_CHANNEL_SHIFT (Z_CHANNEL_SHIFT + 3)
+
+#define REG_CHANNEL_MASK 0x7
+
+#define REG_NR(reg) ((reg) & REG_NR_MASK)
+#define REG_TYPE(reg) (((reg) >> REG_TYPE_SHIFT) & REG_TYPE_MASK)
+#define REG_X(reg) (((reg) >> X_CHANNEL_SHIFT) & REG_CHANNEL_MASK)
+#define REG_Y(reg) (((reg) >> Y_CHANNEL_SHIFT) & REG_CHANNEL_MASK)
+#define REG_Z(reg) (((reg) >> Z_CHANNEL_SHIFT) & REG_CHANNEL_MASK)
+#define REG_W(reg) (((reg) >> W_CHANNEL_SHIFT) & REG_CHANNEL_MASK)
+
+enum i915_fs_channel {
+ X_CHANNEL_VAL = 1,
+ Y_CHANNEL_VAL,
+ Z_CHANNEL_VAL,
+ W_CHANNEL_VAL,
+ ZERO_CHANNEL_VAL,
+ ONE_CHANNEL_VAL
+};
+
+#define i915_fs_operand(reg, x, y, z, w) \
+ (reg) | \
+ (x##_CHANNEL_VAL << X_CHANNEL_SHIFT) | \
+ (y##_CHANNEL_VAL << Y_CHANNEL_SHIFT) | \
+ (z##_CHANNEL_VAL << Z_CHANNEL_SHIFT) | \
+ (w##_CHANNEL_VAL << W_CHANNEL_SHIFT)
+
+/**
+ * Construct an operand description for using a register with no swizzling
+ */
+#define i915_fs_operand_reg(reg) \
+ i915_fs_operand(reg, X, Y, Z, W)
+
+#define i915_fs_operand_reg_negate(reg) \
+ i915_fs_operand(reg, -X, -Y, -Z, -W)
+
+/**
+ * Returns an operand containing (0.0, 0.0, 0.0, 0.0).
+ */
+#define i915_fs_operand_zero() i915_fs_operand(FS_R0, ZERO, ZERO, ZERO, ZERO)
+
+/**
+ * Returns an unused operand
+ */
+#define i915_fs_operand_none() i915_fs_operand_zero()
+
+/**
+ * Returns an operand containing (1.0, 1.0, 1.0, 1.0).
+ */
+#define i915_fs_operand_one() i915_fs_operand(FS_R0, ONE, ONE, ONE, ONE)
+
+#define i915_get_hardware_channel_val(val, shift, negate) \
+ (((int) val < 0) ? (~val << shift) | negate : (val - 1) << shift)
+
+/**
+ * Outputs a fragment shader command to declare a sampler or texture register.
+ */
+#define i915_fs_dcl(reg) \
+do { \
+ OUT_DWORD (D0_DCL | \
+ (REG_TYPE(reg) << D0_TYPE_SHIFT) | \
+ (REG_NR(reg) << D0_NR_SHIFT) | \
+ ((REG_TYPE(reg) != REG_TYPE_S) ? D0_CHANNEL_ALL : 0)); \
+ OUT_DWORD (0); \
+ OUT_DWORD (0); \
+} while (0)
+
+#define i915_fs_texld(dest_reg, sampler_reg, address_reg) \
+do { \
+ OUT_DWORD (T0_TEXLD | \
+ (REG_TYPE(dest_reg) << T0_DEST_TYPE_SHIFT) | \
+ (REG_NR(dest_reg) << T0_DEST_NR_SHIFT) | \
+ (REG_NR(sampler_reg) << T0_SAMPLER_NR_SHIFT)); \
+ OUT_DWORD((REG_TYPE(address_reg) << T1_ADDRESS_REG_TYPE_SHIFT) | \
+ (REG_NR(address_reg) << T1_ADDRESS_REG_NR_SHIFT)); \
+ OUT_DWORD (0); \
+} while (0)
+
+#define i915_fs_arith_masked(op, dest_reg, dest_mask, operand0, operand1, operand2) \
+ _i915_fs_arith_masked(A0_##op, dest_reg, dest_mask, operand0, operand1, operand2)
+
+#define i915_fs_arith(op, dest_reg, operand0, operand1, operand2) \
+ _i915_fs_arith(A0_##op, dest_reg, operand0, operand1, operand2)
+
+#define _i915_fs_arith_masked(cmd, dest_reg, dest_mask, operand0, operand1, operand2) \
+do { \
+ /* Set up destination register and write mask */ \
+ OUT_DWORD (cmd | \
+ (REG_TYPE(dest_reg) << A0_DEST_TYPE_SHIFT) | \
+ (REG_NR(dest_reg) << A0_DEST_NR_SHIFT) | \
+ (((dest_mask) & ~MASK_SATURATE) << A0_DEST_CHANNEL_SHIFT) | \
+ (((dest_mask) & MASK_SATURATE) ? A0_DEST_SATURATE : 0) | \
+ /* Set up operand 0 */ \
+ (REG_TYPE(operand0) << A0_SRC0_TYPE_SHIFT) | \
+ (REG_NR(operand0) << A0_SRC0_NR_SHIFT)); \
+ OUT_DWORD (i915_get_hardware_channel_val(REG_X(operand0), \
+ A1_SRC0_CHANNEL_X_SHIFT, \
+ A1_SRC0_CHANNEL_X_NEGATE) | \
+ i915_get_hardware_channel_val(REG_Y(operand0), \
+ A1_SRC0_CHANNEL_Y_SHIFT, \
+ A1_SRC0_CHANNEL_Y_NEGATE) | \
+ i915_get_hardware_channel_val(REG_Z(operand0), \
+ A1_SRC0_CHANNEL_Z_SHIFT, \
+ A1_SRC0_CHANNEL_Z_NEGATE) | \
+ i915_get_hardware_channel_val(REG_W(operand0), \
+ A1_SRC0_CHANNEL_W_SHIFT, \
+ A1_SRC0_CHANNEL_W_NEGATE) | \
+ /* Set up operand 1 */ \
+ (REG_TYPE(operand1) << A1_SRC1_TYPE_SHIFT) | \
+ (REG_NR(operand1) << A1_SRC1_NR_SHIFT) | \
+ i915_get_hardware_channel_val(REG_X(operand1), \
+ A1_SRC1_CHANNEL_X_SHIFT, \
+ A1_SRC1_CHANNEL_X_NEGATE) | \
+ i915_get_hardware_channel_val(REG_Y(operand1), \
+ A1_SRC1_CHANNEL_Y_SHIFT, \
+ A1_SRC1_CHANNEL_Y_NEGATE)); \
+ OUT_DWORD (i915_get_hardware_channel_val(REG_Z(operand1), \
+ A2_SRC1_CHANNEL_Z_SHIFT, \
+ A2_SRC1_CHANNEL_Z_NEGATE) | \
+ i915_get_hardware_channel_val(REG_W(operand1), \
+ A2_SRC1_CHANNEL_W_SHIFT, \
+ A2_SRC1_CHANNEL_W_NEGATE) | \
+ /* Set up operand 2 */ \
+ (REG_TYPE(operand2) << A2_SRC2_TYPE_SHIFT) | \
+ (REG_NR(operand2) << A2_SRC2_NR_SHIFT) | \
+ i915_get_hardware_channel_val(REG_X(operand2), \
+ A2_SRC2_CHANNEL_X_SHIFT, \
+ A2_SRC2_CHANNEL_X_NEGATE) | \
+ i915_get_hardware_channel_val(REG_Y(operand2), \
+ A2_SRC2_CHANNEL_Y_SHIFT, \
+ A2_SRC2_CHANNEL_Y_NEGATE) | \
+ i915_get_hardware_channel_val(REG_Z(operand2), \
+ A2_SRC2_CHANNEL_Z_SHIFT, \
+ A2_SRC2_CHANNEL_Z_NEGATE) | \
+ i915_get_hardware_channel_val(REG_W(operand2), \
+ A2_SRC2_CHANNEL_W_SHIFT, \
+ A2_SRC2_CHANNEL_W_NEGATE)); \
+} while (0)
+
+#define _i915_fs_arith(cmd, dest_reg, operand0, operand1, operand2) do {\
+ /* Set up destination register and write mask */ \
+ OUT_DWORD (cmd | \
+ (REG_TYPE(dest_reg) << A0_DEST_TYPE_SHIFT) | \
+ (REG_NR(dest_reg) << A0_DEST_NR_SHIFT) | \
+ (A0_DEST_CHANNEL_ALL) | \
+ /* Set up operand 0 */ \
+ (REG_TYPE(operand0) << A0_SRC0_TYPE_SHIFT) | \
+ (REG_NR(operand0) << A0_SRC0_NR_SHIFT)); \
+ OUT_DWORD (i915_get_hardware_channel_val(REG_X(operand0), \
+ A1_SRC0_CHANNEL_X_SHIFT, \
+ A1_SRC0_CHANNEL_X_NEGATE) | \
+ i915_get_hardware_channel_val(REG_Y(operand0), \
+ A1_SRC0_CHANNEL_Y_SHIFT, \
+ A1_SRC0_CHANNEL_Y_NEGATE) | \
+ i915_get_hardware_channel_val(REG_Z(operand0), \
+ A1_SRC0_CHANNEL_Z_SHIFT, \
+ A1_SRC0_CHANNEL_Z_NEGATE) | \
+ i915_get_hardware_channel_val(REG_W(operand0), \
+ A1_SRC0_CHANNEL_W_SHIFT, \
+ A1_SRC0_CHANNEL_W_NEGATE) | \
+ /* Set up operand 1 */ \
+ (REG_TYPE(operand1) << A1_SRC1_TYPE_SHIFT) | \
+ (REG_NR(operand1) << A1_SRC1_NR_SHIFT) | \
+ i915_get_hardware_channel_val(REG_X(operand1), \
+ A1_SRC1_CHANNEL_X_SHIFT, \
+ A1_SRC1_CHANNEL_X_NEGATE) | \
+ i915_get_hardware_channel_val(REG_Y(operand1), \
+ A1_SRC1_CHANNEL_Y_SHIFT, \
+ A1_SRC1_CHANNEL_Y_NEGATE)); \
+ OUT_DWORD (i915_get_hardware_channel_val(REG_Z(operand1), \
+ A2_SRC1_CHANNEL_Z_SHIFT, \
+ A2_SRC1_CHANNEL_Z_NEGATE) | \
+ i915_get_hardware_channel_val(REG_W(operand1), \
+ A2_SRC1_CHANNEL_W_SHIFT, \
+ A2_SRC1_CHANNEL_W_NEGATE) | \
+ /* Set up operand 2 */ \
+ (REG_TYPE(operand2) << A2_SRC2_TYPE_SHIFT) | \
+ (REG_NR(operand2) << A2_SRC2_NR_SHIFT) | \
+ i915_get_hardware_channel_val(REG_X(operand2), \
+ A2_SRC2_CHANNEL_X_SHIFT, \
+ A2_SRC2_CHANNEL_X_NEGATE) | \
+ i915_get_hardware_channel_val(REG_Y(operand2), \
+ A2_SRC2_CHANNEL_Y_SHIFT, \
+ A2_SRC2_CHANNEL_Y_NEGATE) | \
+ i915_get_hardware_channel_val(REG_Z(operand2), \
+ A2_SRC2_CHANNEL_Z_SHIFT, \
+ A2_SRC2_CHANNEL_Z_NEGATE) | \
+ i915_get_hardware_channel_val(REG_W(operand2), \
+ A2_SRC2_CHANNEL_W_SHIFT, \
+ A2_SRC2_CHANNEL_W_NEGATE)); \
+} while (0)
+
+#define i915_fs_mov(dest_reg, operand0) \
+ i915_fs_arith(MOV, dest_reg, \
+ operand0, \
+ i915_fs_operand_none(), \
+ i915_fs_operand_none())
+
+#define i915_fs_mov_masked(dest_reg, dest_mask, operand0) \
+ i915_fs_arith_masked (MOV, dest_reg, dest_mask, \
+ operand0, \
+ i915_fs_operand_none(), \
+ i915_fs_operand_none())
+
+
+#define i915_fs_frc(dest_reg, operand0) \
+ i915_fs_arith (FRC, dest_reg, \
+ operand0, \
+ i915_fs_operand_none(), \
+ i915_fs_operand_none())
+
+/** Add operand0 and operand1 and put the result in dest_reg */
+#define i915_fs_add(dest_reg, operand0, operand1) \
+ i915_fs_arith (ADD, dest_reg, \
+ operand0, operand1, \
+ i915_fs_operand_none())
+
+/** Multiply operand0 and operand1 and put the result in dest_reg */
+#define i915_fs_mul(dest_reg, operand0, operand1) \
+ i915_fs_arith (MUL, dest_reg, \
+ operand0, operand1, \
+ i915_fs_operand_none())
+
+/** Computes 1/sqrt(operand0.replicate_swizzle) puts the result in dest_reg */
+#define i915_fs_rsq(dest_reg, dest_mask, operand0) \
+do { \
+ if (dest_mask) { \
+ i915_fs_arith_masked (RSQ, dest_reg, dest_mask, \
+ operand0, \
+ i915_fs_operand_none (), \
+ i915_fs_operand_none ()); \
+ } else { \
+ i915_fs_arith (RSQ, dest_reg, \
+ operand0, \
+ i915_fs_operand_none (), \
+ i915_fs_operand_none ()); \
+ } \
+} while (0)
+
+/** Puts the minimum of operand0 and operand1 in dest_reg */
+#define i915_fs_min(dest_reg, operand0, operand1) \
+ i915_fs_arith (MIN, dest_reg, \
+ operand0, operand1, \
+ i915_fs_operand_none())
+
+/** Puts the maximum of operand0 and operand1 in dest_reg */
+#define i915_fs_max(dest_reg, operand0, operand1) \
+ i915_fs_arith (MAX, dest_reg, \
+ operand0, operand1, \
+ i915_fs_operand_none())
+
+#define i915_fs_cmp(dest_reg, operand0, operand1, operand2) \
+ i915_fs_arith (CMP, dest_reg, operand0, operand1, operand2)
+
+/** Perform operand0 * operand1 + operand2 and put the result in dest_reg */
+#define i915_fs_mad(dest_reg, dest_mask, op0, op1, op2) \
+do { \
+ if (dest_mask) { \
+ i915_fs_arith_masked (MAD, dest_reg, dest_mask, op0, op1, op2); \
+ } else { \
+ i915_fs_arith (MAD, dest_reg, op0, op1, op2); \
+ } \
+} while (0)
+
+#define i915_fs_dp2add(dest_reg, dest_mask, op0, op1, op2) \
+do { \
+ if (dest_mask) { \
+ i915_fs_arith_masked (DP2ADD, dest_reg, dest_mask, op0, op1, op2); \
+ } else { \
+ i915_fs_arith (DP2ADD, dest_reg, op0, op1, op2); \
+ } \
+} while (0)
+
+/**
+ * Perform a 3-component dot-product of operand0 and operand1 and put the
+ * resulting scalar in the channels of dest_reg specified by the dest_mask.
+ */
+#define i915_fs_dp3(dest_reg, dest_mask, op0, op1) \
+do { \
+ if (dest_mask) { \
+ i915_fs_arith_masked (DP3, dest_reg, dest_mask, \
+ op0, op1,\
+ i915_fs_operand_none()); \
+ } else { \
+ i915_fs_arith (DP3, dest_reg, op0, op1,\
+ i915_fs_operand_none()); \
+ } \
+} while (0)
+
+static inline uint32_t cairo_const
+i915_fs_operand_pure_alpha (int pure)
+{
+ if (pure & (1 << 3))
+ return i915_fs_operand_one ();
+ else
+ return i915_fs_operand_zero ();
+}
+
+#define I915_TILING_DEFAULT I915_TILING_Y
+#define I915_BO_CACHE_BUCKETS 13 /* cache surfaces up to 16 MiB */
+
+typedef struct i915_surface i915_surface_t;
+typedef struct i915_device i915_device_t;
+typedef struct i915_shader i915_shader_t;
+
+typedef void (*i915_add_rectangle_func_t) (const i915_shader_t *shader,
+ int x, int y,
+ int w, int h);
+
+#define IMAGE_CACHE_WIDTH 1024
+#define IMAGE_CACHE_HEIGHT 1024
+
+typedef struct i915_image_private {
+ cairo_rtree_node_t node;
+ intel_buffer_cache_t *container;
+} i915_image_private_t;
+
+#define I915_BATCH_SIZE (64*1024)
+#define I915_VBO_SIZE (512*1024)
+#define I915_MAX_RELOCS 2048
+
+enum {
+ I915_DEBUG_EXEC = 0x1,
+ I915_DEBUG_SYNC = 0x2,
+ I915_DEBUG_BATCH = 0x4,
+ I915_DEBUG_BUFFER = 0x8,
+ I915_DEBUG_BUFFER_CACHE = 0x10,
+ I915_DEBUG_BUFFER_ALLOC = 0x20,
+ I915_DEBUG_GLYPHS = 0x40,
+ I915_DEBUG_MAP = 0x80,
+ I915_DEBUG_THROTTLE = 0x100,
+};
+
+struct i915_device {
+ intel_device_t intel;
+
+ cairo_bool_t debug;
+
+ struct i915_batch {
+ intel_bo_t *target_bo[I915_MAX_RELOCS];
+ size_t gtt_size;
+
+ struct drm_i915_gem_exec_object2 exec[I915_MAX_RELOCS];
+ int exec_count;
+
+ struct drm_i915_gem_relocation_entry reloc[I915_MAX_RELOCS];
+ uint16_t reloc_count;
+
+ uint16_t used;
+ } batch;
+
+ uint32_t vbo;
+ uint32_t vbo_offset;
+ uint32_t vbo_used;
+ uint32_t vbo_max_index;
+ uint32_t vertex_index;
+ uint32_t vertex_count;
+ uint32_t floats_per_vertex;
+ uint32_t rectangle_size;
+ intel_bo_t *last_vbo;
+ uint32_t last_vbo_offset;
+ uint32_t last_vbo_space;
+
+ i915_shader_t *current_shader;
+
+ i915_surface_t *current_target;
+ uint32_t current_size;
+ uint32_t current_diffuse;
+ uint32_t current_colorbuf;
+ uint32_t *current_source;
+ uint32_t *current_mask;
+ uint32_t *current_clip;
+ uint32_t current_program;
+ uint32_t current_texcoords;
+ uint32_t current_blend;
+ uint32_t current_constants[8*4];
+ uint32_t current_n_constants;
+ uint32_t current_samplers[2*(3+3*4)];
+ uint32_t current_n_samplers;
+ uint32_t last_source_fragment;
+
+ cairo_list_t image_caches[2];
+
+ uint32_t batch_header[18];
+ uint32_t batch_base[I915_BATCH_SIZE / sizeof (uint32_t)];
+ uint8_t vbo_base[I915_VBO_SIZE];
+};
+
+enum {
+ CURRENT_SOURCE = 0x1,
+ CURRENT_MASK = 0x2,
+ CURRENT_CLIP = 0x4
+};
+
+typedef enum {
+ VS_CONSTANT,
+ VS_LINEAR,
+ VS_RADIAL,
+ VS_TEXTURE,
+ VS_TEXTURE_16,
+} i915_vertex_shader_t;
+
+typedef enum {
+ FS_ZERO,
+ FS_ONE,
+ FS_PURE,
+ FS_CONSTANT,
+ FS_DIFFUSE,
+ FS_LINEAR,
+ FS_RADIAL,
+ FS_TEXTURE,
+ FS_YUV,
+ FS_SPANS,
+} i915_fragment_shader_t;
+
+#define FS_DETAILS_SHIFT 4
+
+typedef enum {
+ PATTERN_BASE,
+ PATTERN_CONSTANT,
+ PATTERN_LINEAR,
+ PATTERN_RADIAL,
+ PATTERN_TEXTURE,
+} i915_shader_channel_t;
+
+struct i915_surface {
+ intel_surface_t intel;
+
+ uint32_t map0, map1;
+ uint32_t colorbuf;
+
+ uint32_t offset;
+ uint32_t is_current_texture;
+
+ i915_image_private_t *cache;
+
+ intel_bo_t *stencil;
+ uint32_t stencil_stride;
+ uint32_t stencil_offset;
+};
+
+typedef enum {
+ NONE = 0,
+ YUV_I420,
+ /* XXX */
+ YUV_YV12,
+ YUV_YUY2,
+ YUV_UYVY,
+} i915_packed_pixel_t;
+
+/* read-only container */
+#define I915_PACKED_PIXEL_SURFACE_TYPE 0x1000
+typedef struct i915_packed_pixel_surface {
+ cairo_surface_t base;
+
+ i915_packed_pixel_t pixel;
+
+ i915_device_t *device;
+ intel_bo_t *bo;
+ uint32_t is_current_texture;
+
+ uint32_t offset[4];
+ uint32_t stride[4];
+ uint32_t width[4];
+ uint32_t height[4];
+ uint32_t map0[4], map1[4];
+} i915_packed_pixel_surface_t;
+
+struct i915_shader {
+ i915_device_t *device;
+ i915_surface_t *target;
+
+ cairo_operator_t op;
+ uint32_t blend;
+ cairo_content_t content;
+
+ cairo_bool_t need_combine;
+
+ i915_add_rectangle_func_t add_rectangle;
+
+ union i915_shader_channel {
+ struct {
+ i915_vertex_shader_t vertex;
+ i915_fragment_shader_t fragment;
+ i915_shader_channel_t pattern;
+ } type;
+ struct i915_shader_base {
+ i915_vertex_shader_t vertex;
+ i915_fragment_shader_t fragment;
+ i915_shader_channel_t pattern;
+ uint32_t texfmt;
+ cairo_content_t content;
+ uint32_t mode;
+ intel_bo_t *bo;
+ uint32_t n_samplers;
+ uint32_t offset[4];
+ uint32_t map[2*4];
+ uint32_t sampler[2];
+ cairo_matrix_t matrix;
+ } base;
+ struct i915_shader_solid {
+ struct i915_shader_base base;
+ cairo_color_t color;
+ int pure;
+ } solid;
+ struct i915_shader_linear {
+ struct i915_shader_base base;
+ struct {
+ float red, green, blue, alpha;
+ } color0, color1;
+ float dx, dy, offset;
+ } linear;
+ struct i915_shader_radial {
+ struct i915_shader_base base;
+ float constants[8];
+ } radial;
+ struct i915_shader_surface {
+ struct i915_shader_base base;
+ i915_packed_pixel_t pixel;
+ } surface;
+ } source, mask, clip, dst;
+};
+
+enum i915_shader_linear_mode {
+ /* XXX REFLECT */
+ LINEAR_TEXTURE,
+ LINEAR_NONE,
+ LINEAR_REPEAT,
+ LINEAR_PAD,
+};
+
+enum i915_shader_radial_mode {
+ RADIAL_ONE,
+ RADIAL_TWO
+};
+
+typedef cairo_status_t
+(*i915_spans_func_t) (void *closure,
+ cairo_span_renderer_t *renderer,
+ const cairo_rectangle_int_t *extents);
+
+cairo_private cairo_status_t
+i915_clip_and_composite_spans (i915_surface_t *dst,
+ cairo_operator_t op,
+ const cairo_pattern_t *pattern,
+ cairo_antialias_t antialias,
+ i915_spans_func_t draw_func,
+ void *draw_closure,
+ const cairo_composite_rectangles_t*extents,
+ cairo_clip_t *clip);
+
+cairo_private cairo_surface_t *
+i915_surface_create_internal (cairo_drm_device_t *base_dev,
+ cairo_content_t content,
+ int width, int height,
+ uint32_t tiling,
+ cairo_bool_t gpu_target);
+
+cairo_private i915_surface_t *
+i915_surface_create_from_cacheable_image_internal (i915_device_t *device,
+ cairo_image_surface_t *image);
+
+cairo_private void
+i915_surface_scaled_font_fini (cairo_scaled_font_t *scaled_font);
+
+cairo_private cairo_int_status_t
+i915_surface_glyphs (void *abstract_surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_scaled_font_t *scaled_font,
+ cairo_clip_t *clip,
+ int *num_remaining);
+
+static inline int cairo_const
+i915_tiling_height (uint32_t tiling, int height)
+{
+ switch (tiling) {
+ default:
+ case I915_TILING_NONE: return (height + 1) & -2;
+ case I915_TILING_X: return (height + 7) & -8;
+ case I915_TILING_Y: return (height + 31) & -32;
+ }
+}
+
+static inline uint32_t cairo_const
+i915_tiling_stride (int format, uint32_t stride)
+{
+ uint32_t tile_width;
+
+ if (format == I915_TILING_NONE)
+ return (stride + 31) & -32;
+
+ tile_width = 512;
+ /* XXX Currently the kernel enforces a tile_width of 512 for TILING_Y.
+
+ <jbarnes> the docs are a bit confused on that front
+ <jbarnes> once we enable it on 915 we'll find out what the tile width size should be in the fence setup
+ <jbarnes> it could be that 915 has y tiling but that the minimum width is 512 or something
+ <jbarnes> yeah it's probably 128 on 915 also
+ <jbarnes> it's just that we haven't tested
+ <jbarnes> but I wasn't thinking that the tile widths were the same
+ <jbarnes> only that in order to fence y tiles on 915 you needed pitch to be a multiple of 4 y tiles (or something like that)
+
+ tile_width = format == I915_TILING_Y ? 128 : 512;
+ */
+
+ /* needs a pot tile width */
+ while (tile_width < stride)
+ tile_width <<= 1;
+
+ return tile_width;
+}
+
+static inline uint32_t cairo_const
+i915_tiling_size (uint32_t tiling, uint32_t size)
+{
+ uint32_t fence;
+
+ if (tiling == I915_TILING_NONE)
+ return (size + 4095) & -4096;
+
+ fence = 1024 * 1024; /* 1 MiB */
+ while (fence < size)
+ fence <<= 1;
+
+ return fence;
+}
+
+static inline cairo_bool_t cairo_pure
+i915_texture_filter_is_nearest (cairo_filter_t filter)
+{
+ switch (filter) {
+ case CAIRO_FILTER_BEST:
+ case CAIRO_FILTER_GOOD:
+ case CAIRO_FILTER_BILINEAR:
+ case CAIRO_FILTER_GAUSSIAN:
+ return FALSE;
+ default:
+ case CAIRO_FILTER_FAST:
+ case CAIRO_FILTER_NEAREST:
+ return TRUE;
+ }
+}
+
+static inline uint32_t cairo_pure
+i915_texture_filter (cairo_filter_t filter)
+{
+ switch (filter) {
+ case CAIRO_FILTER_BEST:
+ case CAIRO_FILTER_GOOD:
+ case CAIRO_FILTER_BILINEAR:
+ case CAIRO_FILTER_GAUSSIAN:
+ return
+ (FILTER_LINEAR << SS2_MAG_FILTER_SHIFT) |
+ (FILTER_LINEAR << SS2_MIN_FILTER_SHIFT);
+ default:
+ case CAIRO_FILTER_FAST:
+ case CAIRO_FILTER_NEAREST:
+ return
+ (FILTER_NEAREST << SS2_MAG_FILTER_SHIFT) |
+ (FILTER_NEAREST << SS2_MIN_FILTER_SHIFT);
+ }
+}
+
+static inline uint32_t cairo_pure
+i915_texture_extend (cairo_extend_t extend)
+{
+ switch (extend) {
+ default:
+ case CAIRO_EXTEND_NONE:
+ return
+ (TEXCOORDMODE_CLAMP_BORDER << SS3_TCX_ADDR_MODE_SHIFT) |
+ (TEXCOORDMODE_CLAMP_BORDER << SS3_TCY_ADDR_MODE_SHIFT);
+ case CAIRO_EXTEND_REPEAT:
+ return
+ (TEXCOORDMODE_WRAP << SS3_TCX_ADDR_MODE_SHIFT) |
+ (TEXCOORDMODE_WRAP << SS3_TCY_ADDR_MODE_SHIFT);
+ case CAIRO_EXTEND_PAD:
+ return
+ (TEXCOORDMODE_CLAMP_EDGE << SS3_TCX_ADDR_MODE_SHIFT) |
+ (TEXCOORDMODE_CLAMP_EDGE << SS3_TCY_ADDR_MODE_SHIFT);
+ case CAIRO_EXTEND_REFLECT:
+ return
+ (TEXCOORDMODE_MIRROR << SS3_TCX_ADDR_MODE_SHIFT) |
+ (TEXCOORDMODE_MIRROR << SS3_TCY_ADDR_MODE_SHIFT);
+ }
+}
+
+static inline uint32_t cairo_pure
+BUF_tiling (uint32_t tiling)
+{
+ switch (tiling) {
+ default:
+ case I915_TILING_NONE: return 0;
+ case I915_TILING_X: return BUF_3D_TILED_SURFACE | BUF_3D_TILE_WALK_X;
+ case I915_TILING_Y: return BUF_3D_TILED_SURFACE | BUF_3D_TILE_WALK_Y;
+ }
+}
+
+#define OUT_DWORD(dword) i915_batch_emit_dword (device, dword)
+#define OUT_RELOC(surface, read, write) i915_batch_emit_reloc (device, to_intel_bo (surface->intel.drm.bo), surface->offset, read, write)
+
+#define FS_LOCALS \
+ uint32_t *_shader_start
+
+#define FS_BEGIN() \
+do { \
+ _shader_start = BATCH_PTR (device); \
+ OUT_DWORD (_3DSTATE_PIXEL_SHADER_PROGRAM); \
+} while (0)
+
+#define FS_END() \
+do { \
+ *_shader_start |= BATCH_PTR (device) - _shader_start - 2; \
+} while (0);
+
+static inline int32_t
+i915_batch_space (i915_device_t *device)
+{
+ /* leave room for RECTLIST(4) + MI_BUFFER_END + MI_NOOP */
+ return sizeof (device->batch_base) - (device->batch.used << 2) - 32;
+}
+
+static inline cairo_bool_t
+i915_check_aperture_size (const i915_device_t *device, int relocs, size_t size)
+{
+ return device->batch.reloc_count + relocs < I915_MAX_RELOCS &&
+ device->batch.gtt_size + size <= device->intel.gtt_avail_size;
+}
+
+static inline cairo_bool_t
+i915_check_aperture (const i915_device_t *device, intel_bo_t **bo_array, int count)
+{
+ uint32_t relocs = 0, size = 0;
+
+ while (count--) {
+ const intel_bo_t *bo = *bo_array++;
+ if (bo->exec == NULL) {
+ relocs++;
+ size += bo->base.size;
+ }
+ }
+
+ return i915_check_aperture_size (device, relocs, size);
+}
+
+#define BATCH_PTR(device) &(device)->batch_base[(device)->batch.used]
+static inline void
+i915_batch_emit_dword (i915_device_t *device, uint32_t dword)
+{
+ device->batch_base[device->batch.used++] = dword;
+}
+
+cairo_private void
+i915_batch_add_reloc (i915_device_t *device, uint32_t pos,
+ intel_bo_t *bo,
+ uint32_t offset,
+ uint32_t read_domains,
+ uint32_t write_domain);
+
+static inline void
+i915_batch_fill_reloc (i915_device_t *device, uint32_t pos,
+ intel_bo_t *bo,
+ uint32_t offset,
+ uint32_t read_domains,
+ uint32_t write_domain)
+{
+ i915_batch_add_reloc (device, pos,
+ bo, offset,
+ read_domains, write_domain);
+ device->batch_base[pos] = bo->offset + offset;
+}
+
+static inline void
+i915_batch_emit_reloc (i915_device_t *device,
+ intel_bo_t *bo,
+ uint32_t offset,
+ uint32_t read_domains,
+ uint32_t write_domain)
+{
+ i915_batch_add_reloc (device, device->batch.used,
+ bo, offset,
+ read_domains, write_domain);
+ i915_batch_emit_dword (device, bo->offset + offset);
+}
+
+cairo_private cairo_status_t
+i915_vbo_flush (i915_device_t *device);
+
+cairo_private void
+i915_vbo_finish (i915_device_t *device);
+
+cairo_private cairo_status_t
+i915_batch_flush (i915_device_t *device);
+
+static inline float *
+i915_add_rectangle (i915_device_t *device)
+{
+ float *vertices;
+ uint32_t size;
+
+ assert (device->floats_per_vertex);
+
+ size = device->rectangle_size;
+ if (unlikely (device->vbo_offset + size > I915_VBO_SIZE))
+ i915_vbo_finish (device);
+
+ vertices = (float *) (device->vbo_base + device->vbo_offset);
+ device->vbo_used = device->vbo_offset += size;
+ device->vertex_count += 3;
+ return vertices;
+}
+
+static inline i915_device_t *
+i915_device (i915_surface_t *surface)
+{
+ return (i915_device_t *) surface->intel.drm.base.device;
+}
+
+cairo_private void
+i915_shader_init (i915_shader_t *shader,
+ i915_surface_t *dst,
+ cairo_operator_t op);
+
+cairo_private cairo_status_t
+i915_shader_acquire_pattern (i915_shader_t *shader,
+ union i915_shader_channel *src,
+ const cairo_pattern_t *pattern,
+ const cairo_rectangle_int_t *extents);
+
+cairo_private void
+i915_shader_set_clip (i915_shader_t *shader,
+ cairo_clip_t *clip);
+
+cairo_private int
+i915_shader_num_texcoords (const i915_shader_t *shader);
+
+static inline double cairo_const
+i915_shader_linear_texcoord (const struct i915_shader_linear *l,
+ double src_x, double src_y)
+{
+ return l->dx * src_x + l->dy * src_y + l->offset;
+}
+
+cairo_private cairo_status_t
+i915_shader_commit (i915_shader_t *shader,
+ i915_device_t *device);
+
+cairo_private void
+i915_shader_fini (i915_shader_t *shader);
+
+cairo_private cairo_status_t
+i915_fixup_unbounded (i915_surface_t *dst,
+ const cairo_composite_rectangles_t *extents,
+ cairo_clip_t *clip);
+
+#endif /* CAIRO_DRM_I915_PRIVATE_H */
diff --git a/src/drm/cairo-drm-i915-shader.c b/src/drm/cairo-drm-i915-shader.c
new file mode 100644
index 0000000..afcbd42
--- /dev/null
+++ b/src/drm/cairo-drm-i915-shader.c
@@ -0,0 +1,2674 @@
+/* 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.
+ *
+ * Contributor(s):
+ * Chris Wilson <chris at chris-wilson.co.uk>
+ */
+
+#include "cairoint.h"
+
+#include "cairo-error-private.h"
+#include "cairo-drm-i915-private.h"
+#include "cairo-surface-subsurface-private.h"
+#include "cairo-surface-snapshot-private.h"
+
+#if CAIRO_HAS_XCB_SURFACE && CAIRO_HAS_XCB_DRM_FUNCTIONS
+/* for DRI2/DRM interoperability */
+#include "cairo-xcb-private.h"
+#endif
+
+#if 0
+static cairo_status_t
+i915_packed_pixel_surface_finish (void *abstract_surface)
+{
+ i915_packed_pixel_surface_t *surface = abstract_surface;
+ i915_device_t *device;
+
+ device = i915_device_acquire (&surface->device->intel.base);
+
+ intel_bo_destroy (&device->intel, surface->bo);
+
+ if (surface->is_current_texture) {
+ if (surface->is_current_texture & CURRENT_SOURCE)
+ device->current_source = NULL;
+ if (surface->is_current_texture & CURRENT_MASK)
+ device->current_mask = NULL;
+ device->current_n_samplers = 0;
+ }
+
+ i915_device_release (device);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static const cairo_surface_backend_t i915_packed_pixel_surface_backend = {
+ I915_PACKED_PIXEL_SURFACE_TYPE,
+ i915_packed_pixel_surface_finish,
+};
+
+static cairo_surface_t *
+i915_packed_pixel_surface_create (i915_device_t *device,
+ i915_packed_pixel_t pixel,
+ const uint8_t *data,
+ uint32_t length,
+ uint32_t width, uint32_t height)
+{
+ i915_packed_pixel_surface_t *surface;
+ cairo_content_t content;
+ uint32_t tiling, size;
+ uint32_t stride, half_stride;
+ uint32_t i;
+
+ if (width > 2048 || height > 2048)
+ return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE));
+
+ surface = malloc (sizeof (i915_packed_pixel_surface_t));
+ if (unlikely (surface == NULL))
+ return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
+
+ tiling = I915_TILING_NONE; /* XXX */
+ half_stride = stride = i915_tiling_stride (tiling, width/2);
+ if (stride < width)
+ stride *= 2 ;
+ height = i915_tiling_height (tiling, height);
+
+ switch (surface->pixel = pixel) {
+ case YUV_I420:
+ content = CAIRO_CONTENT_COLOR;
+
+ surface->offset[0] = 0;
+ surface->width[0] = width;
+ surface->height[0] = height;
+ surface->stride[0] = stride;
+ surface->map0[0] = MAPSURF_8BIT | MT_8BIT_I8 | MS3_tiling (tiling);
+ surface->map0[0] |= ((height - 1) << MS3_HEIGHT_SHIFT) |
+ ((width - 1) << MS3_WIDTH_SHIFT);
+ surface->map1[0] = (stride / 4 - 1) << MS4_PITCH_SHIFT;
+
+ surface->offset[1] = stride * height;
+ surface->width[1] = width / 2;
+ surface->height[1] = height / 2;
+ surface->stride[1] = half_stride;
+ surface->map0[1] = MAPSURF_8BIT | MT_8BIT_I8 | MS3_tiling (tiling);
+ surface->map0[1] |= ((height/2 - 1) << MS3_HEIGHT_SHIFT) |
+ ((width/2 - 1) << MS3_WIDTH_SHIFT);
+ surface->map1[1] = (half_stride / 4 - 1) << MS4_PITCH_SHIFT;
+
+ if (width < half_stride) {
+ surface->offset[2] = stride * height + half_stride / 2;
+ size = stride * height + half_stride * height / 2;
+ } else {
+ surface->offset[2] = stride * height + half_stride * height / 2;
+ size = stride * height + half_stride * height;
+ }
+ surface->width[2] = width / 2;
+ surface->height[2] = height / 2;
+ surface->stride[2] = half_stride;
+ surface->map0[2] = MAPSURF_8BIT | MT_8BIT_I8 | MS3_tiling (tiling);
+ surface->map0[2] |= ((height/2 - 1) << MS3_HEIGHT_SHIFT) |
+ ((width/2 - 1) << MS3_WIDTH_SHIFT);
+ surface->map1[2] = (half_stride / 4 - 1) << MS4_PITCH_SHIFT;
+ break;
+
+ case NONE:
+ case YUV_YV12:
+ case YUV_YUY2:
+ case YUV_UYVY:
+ ASSERT_NOT_REACHED;
+ break;
+ }
+
+ _cairo_surface_init (&surface->base,
+ &i915_packed_pixel_surface_backend,
+ content);
+
+ surface->bo = intel_bo_create (&device->intel, size, FALSE);
+ assert (tiling == I915_TILING_NONE);
+ if (unlikely (surface->bo == NULL)) {
+ free (surface);
+ return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
+ }
+
+ if (tiling == I915_TILING_NONE) {
+ intel_bo_t *bo = surface->bo;
+ uint32_t dst;
+ int uv;
+
+ dst = surface->offset[0];
+ if (width == stride) {
+ size = stride * height;
+ intel_bo_write (&device->intel, bo, dst, size, data);
+ data += size;
+ } else {
+ for (i = 0; i < height; i++) {
+ intel_bo_write (&device->intel, bo, dst, width, data);
+ dst += stride;
+ data += width;
+ }
+ }
+
+ for (uv = 1; uv <= 2; uv++) {
+ dst = surface->offset[uv];
+ if (width / 2 == half_stride) {
+ size = half_stride * height / 2;
+ intel_bo_write (&device->intel, bo, dst, size, data);
+ data += size;
+ } else {
+ size = width / 2;
+ for (i = 0; i < height / 2; i++) {
+ intel_bo_write (&device->intel, bo, dst, size, data);
+ dst += half_stride;
+ data += size;
+ }
+ }
+ }
+ } else {
+ uint8_t *dst, *base;
+
+ base = intel_bo_map (&device->intel, surface->bo);
+
+ dst = base + surface->offset[0];
+ if (width == stride) {
+ size = stride * height;
+ memcpy (dst, data, size);
+ data += size;
+ } else {
+ for (i = 0; i < height; i++) {
+ memcpy (dst, data, width);
+ dst += stride;
+ data += width;
+ }
+ }
+
+ dst = base + surface->offset[1];
+ if (width / 2 == half_stride) {
+ size = half_stride * height / 2;
+ memcpy (dst, data, size);
+ data += size;
+ } else {
+ size = width / 2;
+ for (i = 0; i < height / 2; i++) {
+ memcpy (dst, data, size);
+ dst += half_stride;
+ data += size;
+ }
+ }
+
+ dst = base + surface->offset[2];
+ if (width / 2 == half_stride) {
+ size = half_stride * height / 2;
+ memcpy (dst, data, size);
+ data += size;
+ } else {
+ size = width / 2;
+ for (i = 0; i < height / 2; i++) {
+ memcpy (dst, data, size);
+ dst += half_stride;
+ data += size;
+ }
+ }
+
+ intel_bo_unmap (surface->bo);
+ }
+
+ surface->device = device;
+ surface->is_current_texture = 0;
+
+ return &surface->base;
+}
+
+static cairo_int_status_t
+i915_clone_yuv (i915_surface_t *surface,
+ cairo_surface_t *source,
+ int width, int height,
+ cairo_surface_t **clone_out)
+{
+ const uint8_t *mime_data = NULL;
+ unsigned int mime_data_length;
+ cairo_surface_t *clone;
+
+ cairo_surface_get_mime_data (source, "video/x-raw-yuv/i420",
+ &mime_data, &mime_data_length);
+ if (mime_data == NULL)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ clone =
+ i915_packed_pixel_surface_create ((i915_device_t *) surface->base.device,
+ YUV_I420,
+ mime_data, mime_data_length,
+ width, height);
+ if (clone == NULL)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ if (unlikely (clone->status))
+ return clone->status;
+
+ *clone_out = clone;
+ return CAIRO_STATUS_SUCCESS;
+}
+#endif
+
+/* Max instruction count: 4 */
+static void
+i915_shader_linear_color (i915_device_t *device,
+ enum i915_shader_linear_mode mode,
+ int in, int c0, int c1, int out)
+{
+ int tmp = FS_U0;
+
+ switch (mode) {
+ case LINEAR_TEXTURE:
+ ASSERT_NOT_REACHED;
+ case LINEAR_NONE:
+ tmp = in;
+ break;
+
+ case LINEAR_REPEAT:
+ i915_fs_frc (tmp, i915_fs_operand (in, X, X, X, X));
+ break;
+#if 0
+ case LINEAR_REFLECT:
+ /* XXX needs an extra constant: C2 [0.5, 2.0, x, x] */
+ i915_fs_mul (tmp, in, 0.5);
+ i915_fs_frc (tmp, i915_fs_operand_reg (tmp));
+ i915_fs_mul (tmp, tmp, 2.0);
+ i915_fs_add (tmp, i915_fs_operand_one (),
+ i915_fs_operand_reg_negate (tmp));
+ i915_fs_cmp (tmp,
+ i915_fs_operand_reg (tmp),
+ i915_fs_operand_reg (tmp),
+ i915_fs_operand_reg_negate (tmp));
+ i915_fs_add (tmp, i915_fs_operand_one (),
+ i915_fs_operand_reg_negate (tmp));
+#endif
+ case LINEAR_PAD:
+ i915_fs_max (tmp,
+ i915_fs_operand_zero (),
+ i915_fs_operand (in, X, X, X, X));
+ i915_fs_min (tmp,
+ i915_fs_operand_one (),
+ i915_fs_operand_reg (tmp));
+ break;
+ }
+
+ /* interpolate */
+ i915_fs_mad (out, 0,
+ i915_fs_operand (tmp, -X, -X, -X, -X),
+ i915_fs_operand_reg (c0),
+ i915_fs_operand_reg (c0));
+ i915_fs_mad (out, 0,
+ i915_fs_operand (tmp, X, X, X, X),
+ i915_fs_operand_reg (c1),
+ i915_fs_operand_reg (out));
+}
+
+static void
+i915_shader_radial_init (struct i915_shader_radial *r,
+ const cairo_radial_pattern_t *radial)
+{
+ double dx, dy, dr, r1;
+
+ dx = _cairo_fixed_to_double (radial->c2.x - radial->c1.x);
+ dy = _cairo_fixed_to_double (radial->c2.y - radial->c1.y);
+ dr = _cairo_fixed_to_double (radial->r2 - radial->r1);
+
+ r1 = _cairo_fixed_to_double (radial->r1);
+
+ if (radial->c2.x == radial->c1.x && radial->c2.y == radial->c1.y) {
+ /* XXX dr == 0, meaningless with anything other than PAD */
+ r->constants[0] = _cairo_fixed_to_double (radial->c1.x) / dr;
+ r->constants[1] = _cairo_fixed_to_double (radial->c1.y) / dr;
+ r->constants[2] = 1. / dr;
+ r->constants[3] = -r1 / dr;
+
+ r->constants[4] = 0;
+ r->constants[5] = 0;
+ r->constants[6] = 0;
+ r->constants[7] = 0;
+
+ r->base.mode = RADIAL_ONE;
+ } else {
+ r->constants[0] = -_cairo_fixed_to_double (radial->c1.x);
+ r->constants[1] = -_cairo_fixed_to_double (radial->c1.y);
+ r->constants[2] = r1;
+ r->constants[3] = -4 * (dx*dx + dy*dy - dr*dr);
+
+ r->constants[4] = -2 * dx;
+ r->constants[5] = -2 * dy;
+ r->constants[6] = -2 * r1 * dr;
+ r->constants[7] = 1 / (2 * (dx*dx + dy*dy - dr*dr));
+
+ r->base.mode = RADIAL_TWO;
+ }
+
+ r->base.matrix = radial->base.base.matrix;
+}
+
+/* Max instruction count: 10 */
+static void
+i915_shader_radial_coord (i915_device_t *device,
+ enum i915_shader_radial_mode mode,
+ int in, int g0, int g1, int out)
+{
+ switch (mode) {
+ case RADIAL_ONE:
+ /*
+ pdx = (x - c1x) / dr, pdy = (y - c1y) / dr;
+ r² = pdx*pdx + pdy*pdy
+ t = r²/sqrt(r²) - r1/dr;
+ */
+ i915_fs_mad (FS_U0, MASK_X | MASK_Y,
+ i915_fs_operand (in, X, Y, ZERO, ZERO),
+ i915_fs_operand (g0, Z, Z, ZERO, ZERO),
+ i915_fs_operand (g0, -X, -Y, ZERO, ZERO));
+ i915_fs_dp2add (FS_U0, MASK_X,
+ i915_fs_operand (FS_U0, X, Y, ZERO, ZERO),
+ i915_fs_operand (FS_U0, X, Y, ZERO, ZERO),
+ i915_fs_operand_zero ());
+ i915_fs_rsq (out, MASK_X, i915_fs_operand (FS_U0, X, X, X, X));
+ i915_fs_mad (out, MASK_X,
+ i915_fs_operand (FS_U0, X, ZERO, ZERO, ZERO),
+ i915_fs_operand (out, X, ZERO, ZERO, ZERO),
+ i915_fs_operand (g0, W, ZERO, ZERO, ZERO));
+ break;
+
+ case RADIAL_TWO:
+ /*
+ pdx = x - c1x, pdy = y - c1y;
+ A = dx² + dy² - dr²
+ B = -2*(pdx*dx + pdy*dy + r1*dr);
+ C = pdx² + pdy² - r1²;
+ det = B*B - 4*A*C;
+ t = (-B + sqrt (det)) / (2 * A)
+ */
+
+ /* u0.x = pdx, u0.y = pdy, u[0].z = r1; */
+ i915_fs_add (FS_U0,
+ i915_fs_operand (in, X, Y, ZERO, ZERO),
+ i915_fs_operand (g0, X, Y, Z, ZERO));
+ /* u0.x = pdx, u0.y = pdy, u[0].z = r1, u[0].w = B; */
+ i915_fs_dp3 (FS_U0, MASK_W,
+ i915_fs_operand (FS_U0, X, Y, ONE, ZERO),
+ i915_fs_operand (g1, X, Y, Z, ZERO));
+ /* u1.x = pdx² + pdy² - r1²; [C] */
+ i915_fs_dp3 (FS_U1, MASK_X,
+ i915_fs_operand (FS_U0, X, Y, Z, ZERO),
+ i915_fs_operand (FS_U0, X, Y, -Z, ZERO));
+ /* u1.x = C, u1.y = B, u1.z=-4*A; */
+ i915_fs_mov_masked (FS_U1, MASK_Y, i915_fs_operand (FS_U0, W, W, W, W));
+ i915_fs_mov_masked (FS_U1, MASK_Z, i915_fs_operand (g0, W, W, W, W));
+ /* u1.x = B² - 4*A*C */
+ i915_fs_dp2add (FS_U1, MASK_X,
+ i915_fs_operand (FS_U1, X, Y, ZERO, ZERO),
+ i915_fs_operand (FS_U1, Z, Y, ZERO, ZERO),
+ i915_fs_operand_zero ());
+ /* out.x = -B + sqrt (B² - 4*A*C),
+ * out.y = -B - sqrt (B² - 4*A*C),
+ */
+ i915_fs_rsq (out, MASK_X, i915_fs_operand (FS_U1, X, X, X, X));
+ i915_fs_mad (out, MASK_X | MASK_Y,
+ i915_fs_operand (out, X, X, ZERO, ZERO),
+ i915_fs_operand (FS_U1, X, -X, ZERO, ZERO),
+ i915_fs_operand (FS_U0, -W, -W, ZERO, ZERO));
+ /* out.x = (-B + sqrt (B² - 4*A*C)) / (2 * A),
+ * out.y = (-B - sqrt (B² - 4*A*C)) / (2 * A)
+ */
+ i915_fs_mul (out,
+ i915_fs_operand (out, X, Y, ZERO, ZERO),
+ i915_fs_operand (g1, W, W, ZERO, ZERO));
+ /* if (A > 0)
+ * out = (-B + sqrt (B² - 4*A*C)) / (2 * A),
+ * else
+ * out = (-B - sqrt (B² - 4*A*C)) / (2 * A)
+ */
+ i915_fs_cmp (out,
+ i915_fs_operand (g1, W, ZERO, ZERO, ZERO),
+ i915_fs_operand (out, X, ZERO, ZERO, ZERO),
+ i915_fs_operand (out, Y, ZERO, ZERO, ZERO));
+ break;
+ }
+}
+
+/* Max instruction count: 7 */
+static inline void
+i915_shader_yuv_color (i915_device_t *device,
+ int y, int u, int v,
+ int c0, int c1, int c2,
+ int out)
+{
+ i915_fs_mov_masked (FS_U0, MASK_X, i915_fs_operand_reg (y));
+ i915_fs_mov_masked (FS_U0, MASK_Y, i915_fs_operand_reg (u));
+ i915_fs_mov_masked (FS_U0, MASK_Z, i915_fs_operand_reg (v));
+
+ i915_fs_add (FS_U0,
+ i915_fs_operand_reg (FS_U0),
+ i915_fs_operand_reg (c0));
+ i915_fs_dp3 (out, MASK_X,
+ i915_fs_operand_reg (FS_U0),
+ i915_fs_operand (c1, X, ZERO, Y, ZERO));
+ i915_fs_dp3 (out, MASK_Z,
+ i915_fs_operand_reg (FS_U0),
+ i915_fs_operand (c1, Z, W, ZERO, ZERO));
+ i915_fs_dp3 (out, MASK_Y,
+ i915_fs_operand_reg (FS_U0),
+ i915_fs_operand_reg (c2));
+}
+
+static inline uint32_t
+i915_shader_channel_key (const union i915_shader_channel *channel)
+{
+ return (channel->type.fragment & 0x0f) | (channel->base.mode << FS_DETAILS_SHIFT);
+}
+
+static uint32_t
+i915_shader_channel_get_num_tex_coords (const union i915_shader_channel *channel)
+{
+ switch (channel->type.fragment) {
+ default:
+ case FS_ZERO:
+ case FS_ONE:
+ case FS_CONSTANT:
+ case FS_PURE:
+ case FS_DIFFUSE:
+ return 0;
+
+ case FS_LINEAR:
+ case FS_RADIAL:
+ case FS_TEXTURE:
+ case FS_SPANS:
+ case FS_YUV:
+ return 1;
+ }
+}
+
+static uint32_t
+i915_shader_get_num_tex_coords (const i915_shader_t *shader)
+{
+ uint32_t num_tex_coords;
+
+ num_tex_coords = 0;
+
+ num_tex_coords += i915_shader_channel_get_num_tex_coords (&shader->source);
+ num_tex_coords += i915_shader_channel_get_num_tex_coords (&shader->mask);
+ num_tex_coords += i915_shader_channel_get_num_tex_coords (&shader->clip);
+ num_tex_coords += i915_shader_channel_get_num_tex_coords (&shader->dst);
+
+ return num_tex_coords;
+}
+
+#define i915_fs_operand_impure(reg, channel, pure) \
+ (reg | \
+ (((pure & (1 << 0)) ? channel##_CHANNEL_VAL : ZERO_CHANNEL_VAL) << X_CHANNEL_SHIFT) | \
+ (((pure & (1 << 1)) ? channel##_CHANNEL_VAL : ZERO_CHANNEL_VAL) << Y_CHANNEL_SHIFT) | \
+ (((pure & (1 << 2)) ? channel##_CHANNEL_VAL : ZERO_CHANNEL_VAL) << Z_CHANNEL_SHIFT) | \
+ (((pure & (1 << 3)) ? channel##_CHANNEL_VAL : ZERO_CHANNEL_VAL) << W_CHANNEL_SHIFT))
+
+#define i915_fs_operand_pure(pure) \
+ (FS_R0 | \
+ (((pure & (1 << 0)) ? ONE_CHANNEL_VAL : ZERO_CHANNEL_VAL) << X_CHANNEL_SHIFT) | \
+ (((pure & (1 << 1)) ? ONE_CHANNEL_VAL : ZERO_CHANNEL_VAL) << Y_CHANNEL_SHIFT) | \
+ (((pure & (1 << 2)) ? ONE_CHANNEL_VAL : ZERO_CHANNEL_VAL) << Z_CHANNEL_SHIFT) | \
+ (((pure & (1 << 3)) ? ONE_CHANNEL_VAL : ZERO_CHANNEL_VAL) << W_CHANNEL_SHIFT))
+
+#define i915_fs_operand_reg_pure(reg, pure) \
+ (reg | \
+ (((pure & (1 << 0)) ? X_CHANNEL_VAL : ZERO_CHANNEL_VAL) << X_CHANNEL_SHIFT) | \
+ (((pure & (1 << 1)) ? Y_CHANNEL_VAL : ZERO_CHANNEL_VAL) << Y_CHANNEL_SHIFT) | \
+ (((pure & (1 << 2)) ? Z_CHANNEL_VAL : ZERO_CHANNEL_VAL) << Z_CHANNEL_SHIFT) | \
+ (((pure & (1 << 3)) ? W_CHANNEL_VAL : ZERO_CHANNEL_VAL) << W_CHANNEL_SHIFT))
+
+static void
+i915_set_shader_program (i915_device_t *device,
+ const i915_shader_t *shader)
+{
+ uint32_t num_tex_coords;
+ uint32_t num_samplers;
+ uint32_t n;
+ uint32_t texture_offset = 0;
+ uint32_t constant_offset = 0;
+ uint32_t sampler_offset = 0;
+ uint32_t source_reg;
+ uint32_t source_pure;
+ uint32_t mask_reg;
+ uint32_t out_reg;
+ uint32_t dest_reg;
+ FS_LOCALS;
+
+ n = (i915_shader_channel_key (&shader->source) << 0) |
+ (i915_shader_channel_key (&shader->mask) << 8) |
+ (i915_shader_channel_key (&shader->clip) << 16) |
+ (shader->op << 24) |
+ (((shader->content & CAIRO_CONTENT_ALPHA) == CAIRO_CONTENT_ALPHA) << 31);
+ if (n == device->current_program)
+ return;
+ device->current_program = n;
+
+ FS_BEGIN ();
+
+ if (shader->source.type.fragment == FS_ZERO) {
+ if (shader->clip.type.fragment == FS_TEXTURE) {
+ /* XXX need_combine */
+ assert (shader->mask.type.fragment == (i915_fragment_shader_t) -1);
+ i915_fs_dcl (FS_T0);
+ i915_fs_texld (FS_U0, FS_S0, FS_T0);
+ if ((shader->content & CAIRO_CONTENT_COLOR) == 0)
+ i915_fs_mov (FS_OC, i915_fs_operand (FS_U0, W, W, W, W));
+ else
+ i915_fs_mov (FS_OC, i915_fs_operand (FS_U0, ZERO, ZERO, ZERO, W));
+ } else {
+ i915_fs_mov (FS_OC, i915_fs_operand_zero ());
+ }
+
+ FS_END ();
+ return;
+ }
+
+ num_tex_coords = i915_shader_get_num_tex_coords (shader);
+ for (n = 0; n < num_tex_coords; n++)
+ i915_fs_dcl (FS_T0 + n);
+
+ num_samplers =
+ shader->source.base.n_samplers +
+ shader->mask.base.n_samplers +
+ shader->clip.base.n_samplers +
+ shader->dst.base.n_samplers;
+ for (n = 0; n < num_samplers; n++)
+ i915_fs_dcl (FS_S0 + n);
+
+ source_reg = ~0;
+ source_pure = 0;
+ out_reg = FS_R0;
+ if (! shader->need_combine &&
+ shader->mask.type.fragment == (i915_fragment_shader_t) -1 &&
+ shader->clip.type.fragment != FS_TEXTURE &&
+ shader->content != CAIRO_CONTENT_ALPHA)
+ {
+ out_reg = FS_OC;
+ }
+
+ switch (shader->source.type.fragment) {
+ default:
+ case FS_ZERO:
+ case FS_SPANS:
+ ASSERT_NOT_REACHED;
+
+ case FS_PURE:
+ source_pure = shader->source.solid.pure;
+ case FS_ONE:
+ break;
+
+ case FS_CONSTANT:
+ source_reg = FS_C0;
+ constant_offset += 1;
+ break;
+
+ case FS_DIFFUSE:
+ i915_fs_dcl (FS_T8);
+ source_reg = FS_T8;
+ break;
+
+ case FS_LINEAR:
+ i915_shader_linear_color (device, shader->source.base.mode,
+ FS_T0, /* input */
+ FS_C0, FS_C1, /* colour ramp */
+ FS_U3); /* unpremultiplied output */
+ /* XXX can we defer premultiplication? */
+ i915_fs_mul (out_reg,
+ i915_fs_operand_reg (FS_U3),
+ i915_fs_operand (FS_U3, W, W, W, W));
+
+ constant_offset += 2;
+ texture_offset += 1;
+ source_reg = out_reg;
+ break;
+
+ case FS_RADIAL:
+ i915_shader_radial_coord (device, shader->source.base.mode,
+ FS_T0, /* input */
+ FS_C0, FS_C1, /* gradient constants */
+ FS_U3); /* coordinate */
+
+ i915_fs_texld (out_reg, FS_S0, FS_U3);
+ constant_offset += 2;
+ texture_offset += 1;
+ sampler_offset += 1;
+ source_reg = out_reg;
+ break;
+
+ case FS_TEXTURE:
+ i915_fs_texld (out_reg, FS_S0, FS_T0);
+ texture_offset += 1;
+ sampler_offset += 1;
+ source_reg = out_reg;
+ break;
+
+ case FS_YUV:
+ /* Load samplers to temporaries. */
+ i915_fs_texld (FS_R0, FS_S0, FS_T0);
+ i915_fs_texld (FS_R1, FS_S1, FS_T0);
+ i915_fs_texld (FS_R2, FS_S2, FS_T0);
+
+ i915_shader_yuv_color (device,
+ FS_R0, FS_R1, FS_R2, /* y, u, v */
+ FS_C0, FS_C1, FS_C2, /* coefficients */
+ out_reg);
+
+ constant_offset += 3;
+ texture_offset += 1;
+ sampler_offset += 3;
+ source_reg = out_reg;
+ break;
+ }
+
+ mask_reg = ~0;
+ switch (shader->mask.type.fragment) {
+ case FS_PURE:
+ case FS_ZERO:
+ case FS_YUV:
+ case FS_DIFFUSE:
+ ASSERT_NOT_REACHED;
+ case FS_ONE:
+ default:
+ break;
+
+ case FS_SPANS:
+ mask_reg = FS_T0 + texture_offset;
+ texture_offset += 1;
+ break;
+
+ case FS_CONSTANT:
+ mask_reg = FS_C0 + constant_offset;
+ constant_offset += 1;
+ break;
+
+ case FS_LINEAR:
+ i915_shader_linear_color (device, shader->source.base.mode,
+ FS_T0 + texture_offset, /* input */
+ FS_C0 + constant_offset,
+ FS_C0 + constant_offset + 1, /* colour ramp */
+ FS_U3); /* unpremultiplied output */
+ i915_fs_mul (FS_R1,
+ i915_fs_operand_reg (FS_U3),
+ i915_fs_operand (source_reg, W, W, W, W));
+
+ constant_offset += 2;
+ texture_offset += 1;
+ mask_reg = FS_R1;
+ break;
+
+ case FS_RADIAL:
+ i915_shader_radial_coord (device, shader->source.base.mode,
+ FS_T0 + texture_offset, /* input */
+ FS_C0 + constant_offset,
+ FS_C0 + constant_offset + 1, /* gradient constants */
+ FS_U3); /* coordinate */
+
+ i915_fs_texld (FS_R1, FS_S0 + sampler_offset, FS_U3);
+ constant_offset += 2;
+ texture_offset += 1;
+ sampler_offset += 1;
+ mask_reg = FS_R1;
+ break;
+
+ case FS_TEXTURE:
+ i915_fs_texld (FS_R1, FS_S0 + sampler_offset, FS_T0 + texture_offset);
+ texture_offset += 1;
+ sampler_offset += 1;
+ mask_reg = FS_R1;
+ break;
+ }
+
+ if (mask_reg != ~0U) {
+ if (! shader->need_combine &&
+ shader->clip.type.fragment != FS_TEXTURE &&
+ shader->content != CAIRO_CONTENT_ALPHA)
+ {
+ out_reg = FS_OC;
+ }
+ if (source_reg == ~0U) {
+ if (source_pure) {
+ if (shader->mask.type.fragment == FS_SPANS) {
+ i915_fs_mov (out_reg,
+ i915_fs_operand_impure (mask_reg, X, source_pure));
+ } else {
+ /* XXX ComponentAlpha
+ i915_fs_mov (out_reg,
+ i915_fs_operand_pure (mask_reg,
+ shader->source.solid.pure));
+ */
+ i915_fs_mov (out_reg,
+ i915_fs_operand_impure (mask_reg, W, source_pure));
+ }
+ source_reg = out_reg;
+ } else if (shader->mask.type.fragment == FS_SPANS) {
+ i915_fs_mov (out_reg,
+ i915_fs_operand (mask_reg, X, X, X, X));
+ source_reg = out_reg;
+ } else {
+ source_reg = mask_reg;
+ }
+ } else {
+ if (shader->mask.type.fragment == FS_SPANS) {
+ i915_fs_mul (out_reg,
+ i915_fs_operand_reg (source_reg),
+ i915_fs_operand (mask_reg, X, X, X, X));
+ } else {
+ /* XXX ComponentAlpha
+ i915_fs_mul (FS_R0,
+ i915_fs_operand_reg (source_reg),
+ i915_fs_operand_reg (mask_reg));
+ */
+ i915_fs_mul (out_reg,
+ i915_fs_operand_reg (source_reg),
+ i915_fs_operand (mask_reg, W, W, W, W));
+ }
+
+ source_reg = out_reg;
+ }
+ }
+
+ /* need to preserve order of src, mask, clip, dst */
+ mask_reg = ~0;
+ if (shader->clip.type.fragment == FS_TEXTURE) {
+ i915_fs_texld (FS_R1, FS_S0 + sampler_offset, FS_T0 + texture_offset);
+ texture_offset += 1;
+ sampler_offset += 1;
+ mask_reg = FS_R1;
+ }
+
+ if (shader->need_combine) {
+ assert (shader->dst.type.fragment == FS_TEXTURE);
+
+ i915_fs_texld (FS_R2, FS_S0 + sampler_offset, FS_T0 + texture_offset);
+ texture_offset += 1;
+ sampler_offset += 1;
+ dest_reg = FS_R2;
+
+ switch (shader->op) {
+ case CAIRO_OPERATOR_CLEAR:
+ case CAIRO_OPERATOR_SOURCE:
+ ASSERT_NOT_REACHED;
+
+ case CAIRO_OPERATOR_OVER:
+ if (source_reg == ~0U) {
+ /* XXX shader->source.type.fragment == FS_PURE */
+ dest_reg = FS_OC;
+ } else {
+ i915_fs_add (FS_U0,
+ i915_fs_operand (source_reg, -W, -W, -W, -W),
+ i915_fs_operand_one ());
+ i915_fs_mul (FS_U0,
+ i915_fs_operand_reg (FS_U0),
+ dest_reg);
+ i915_fs_add (FS_R3,
+ i915_fs_operand_reg (source_reg),
+ i915_fs_operand_reg (FS_U0));
+ source_reg = FS_R3;
+ }
+ break;
+
+ case CAIRO_OPERATOR_IN:
+ if (source_reg == ~0U) {
+ /* XXX shader->source.type.fragment == FS_PURE */
+ source_reg = dest_reg;
+ } else {
+ i915_fs_mul (FS_R3,
+ i915_fs_operand_reg (source_reg),
+ dest_reg);
+ source_reg = FS_R3;
+ }
+ break;
+
+ case CAIRO_OPERATOR_OUT:
+ if (source_reg == ~0U) {
+ /* XXX shader->source.type.fragment == FS_PURE */
+ i915_fs_mov (FS_R3, i915_fs_operand_zero ());
+ source_reg = FS_R3;
+ } else {
+ i915_fs_add (FS_U0,
+ i915_fs_operand (source_reg, -W, -W, -W, -W),
+ i915_fs_operand_one ());
+ i915_fs_mul (FS_R3,
+ i915_fs_operand_reg (FS_U0),
+ dest_reg);
+ source_reg = FS_R3;
+ }
+ break;
+
+ case CAIRO_OPERATOR_ATOP:
+
+ case CAIRO_OPERATOR_DEST:
+ case CAIRO_OPERATOR_DEST_OVER:
+ case CAIRO_OPERATOR_DEST_IN:
+ case CAIRO_OPERATOR_DEST_OUT:
+ case CAIRO_OPERATOR_DEST_ATOP:
+
+ case CAIRO_OPERATOR_XOR:
+ case CAIRO_OPERATOR_ADD:
+ case CAIRO_OPERATOR_SATURATE:
+
+ case CAIRO_OPERATOR_MULTIPLY:
+ case CAIRO_OPERATOR_SCREEN:
+ case CAIRO_OPERATOR_OVERLAY:
+ case CAIRO_OPERATOR_DARKEN:
+ case CAIRO_OPERATOR_LIGHTEN:
+ case CAIRO_OPERATOR_COLOR_DODGE:
+ case CAIRO_OPERATOR_COLOR_BURN:
+ case CAIRO_OPERATOR_HARD_LIGHT:
+ case CAIRO_OPERATOR_SOFT_LIGHT:
+ case CAIRO_OPERATOR_DIFFERENCE:
+ case CAIRO_OPERATOR_EXCLUSION:
+ case CAIRO_OPERATOR_HSL_HUE:
+ case CAIRO_OPERATOR_HSL_SATURATION:
+ case CAIRO_OPERATOR_HSL_COLOR:
+ case CAIRO_OPERATOR_HSL_LUMINOSITY:
+ ASSERT_NOT_REACHED;
+ break;
+ }
+ }
+
+ if (shader->clip.type.fragment == FS_TEXTURE) {
+ assert (mask_reg != ~0U);
+
+ if (! shader->need_combine) {
+ /* (source IN clip) */
+ if (source_reg == ~0U) {
+ if (source_pure == 0) {
+ source_reg = mask_reg;
+ } else {
+ out_reg = FS_OC;
+ if (shader->content == CAIRO_CONTENT_ALPHA)
+ out_reg = FS_U0;
+ i915_fs_mov (out_reg,
+ i915_fs_operand_reg_pure (mask_reg, source_pure));
+ source_reg = out_reg;
+ }
+ } else if (mask_reg) {
+ out_reg = FS_OC;
+ if (shader->content == CAIRO_CONTENT_ALPHA)
+ out_reg = FS_U0;
+ i915_fs_mul (out_reg,
+ i915_fs_operand_reg (source_reg),
+ i915_fs_operand (mask_reg, W, W, W, W));
+
+ source_reg = out_reg;
+ }
+ } else {
+ /* (source OP dest) LERP_clip dest */
+ if (source_reg == ~0U) {
+ if (source_pure == 0) {
+ i915_fs_mov (FS_U0,
+ i915_fs_operand (mask_reg, W, W, W, W));
+ } else {
+ i915_fs_mov (FS_U0,
+ i915_fs_operand_impure (mask_reg, W, source_pure));
+ }
+ } else {
+ i915_fs_mul (FS_U0,
+ i915_fs_operand_reg (source_reg),
+ i915_fs_operand (mask_reg, W, W, W, W));
+ }
+
+ i915_fs_add (mask_reg,
+ i915_fs_operand_one (),
+ i915_fs_operand (mask_reg, -W, -W, -W, -W));
+
+ if (dest_reg != FS_OC) {
+ if (dest_reg == ~0U) {
+ assert (shader->dst.type.fragment == FS_TEXTURE);
+
+ i915_fs_texld (FS_R2, FS_S0 + sampler_offset, FS_T0 + texture_offset);
+ texture_offset += 1;
+ sampler_offset += 1;
+ dest_reg = FS_R2;
+ }
+
+ i915_fs_mul (FS_U1,
+ i915_fs_operand_reg (dest_reg),
+ i915_fs_operand_reg (mask_reg));
+ mask_reg = FS_U1;
+ }
+
+ source_reg = FS_OC;
+ if (shader->content != CAIRO_CONTENT_COLOR_ALPHA)
+ source_reg = FS_U0;
+ i915_fs_add (source_reg,
+ i915_fs_operand_reg (FS_U0),
+ i915_fs_operand_reg (mask_reg));
+ }
+ }
+
+ if (source_reg != FS_OC) {
+ if (source_reg == ~0U)
+ if (source_pure)
+ i915_fs_mov (FS_OC, i915_fs_operand_pure (source_pure));
+ else
+ i915_fs_mov (FS_OC, i915_fs_operand_one ());
+ else if ((shader->content & CAIRO_CONTENT_COLOR) == 0)
+ i915_fs_mov (FS_OC, i915_fs_operand (source_reg, W, W, W, W));
+ else
+ i915_fs_mov (FS_OC, i915_fs_operand_reg (source_reg));
+ } else {
+ if ((shader->content & CAIRO_CONTENT_COLOR) == 0)
+ i915_fs_mov (FS_OC, i915_fs_operand (FS_OC, W, W, W, W));
+ }
+
+ FS_END ();
+}
+
+static void
+i915_shader_linear_init (struct i915_shader_linear *l,
+ const cairo_linear_pattern_t *linear)
+{
+ double x0, y0, sf;
+ double dx, dy, offset;
+
+ dx = _cairo_fixed_to_double (linear->p2.x - linear->p1.x);
+ dy = _cairo_fixed_to_double (linear->p2.y - linear->p1.y);
+ sf = 1. / (dx * dx + dy * dy);
+ dx *= sf;
+ dy *= sf;
+
+ x0 = _cairo_fixed_to_double (linear->p1.x);
+ y0 = _cairo_fixed_to_double (linear->p1.y);
+ offset = dx*x0 + dy*y0;
+
+ if (_cairo_matrix_is_identity (&linear->base.base.matrix)) {
+ l->dx = dx;
+ l->dy = dy;
+ l->offset = -offset;
+ } else {
+ cairo_matrix_t m;
+
+ cairo_matrix_init (&m, dx, 0, dy, 0, -offset, 0);
+ cairo_matrix_multiply (&m, &linear->base.base.matrix, &m);
+ l->dx = m.xx;
+ l->dy = m.xy;
+ l->offset = m.x0;
+ }
+}
+
+static cairo_bool_t
+i915_shader_linear_contains_rectangle (struct i915_shader_linear *l,
+ const cairo_rectangle_int_t *extents)
+{
+ double v;
+
+ v = i915_shader_linear_texcoord (l,
+ extents->x,
+ extents->y);
+ if (v < 0.)
+ return FALSE;
+ if (v > 1.)
+ return FALSE;
+
+ v = i915_shader_linear_texcoord (l,
+ extents->x + extents->width,
+ extents->y);
+ if (v < 0.)
+ return FALSE;
+ if (v > 1.)
+ return FALSE;
+
+ v = i915_shader_linear_texcoord (l,
+ extents->x,
+ extents->y + extents->height);
+ if (v < 0.)
+ return FALSE;
+ if (v > 1.)
+ return FALSE;
+
+ v = i915_shader_linear_texcoord (l,
+ extents->x + extents->width,
+ extents->y + extents->height);
+ if (v < 0.)
+ return FALSE;
+ if (v > 1.)
+ return FALSE;
+
+ return TRUE;
+}
+
+#define is_pure(C,mask) (((mask) == 0) || (C) <= 0x00ff || (C) >= 0xff00)
+#define is_one(C,mask) (((mask) != 0) && (C) >= 0xff00)
+#define is_zero(C,mask) (((mask) != 0) && (C) <= 0x00ff)
+
+static cairo_status_t
+i915_shader_acquire_solid (i915_shader_t *shader,
+ union i915_shader_channel *src,
+ const cairo_solid_pattern_t *solid,
+ const cairo_rectangle_int_t *extents)
+{
+ cairo_content_t content;
+
+ content = solid->content;
+ src->solid.color = solid->color;
+ if (content == 0 || solid->color.alpha_short <= 0x00ff)
+ {
+ src->base.content = CAIRO_CONTENT_ALPHA;
+ src->type.fragment = FS_ZERO;
+ }
+ else if ((((content & CAIRO_CONTENT_COLOR) == 0) ||
+ (solid->color.red_short >= 0xff00 &&
+ solid->color.green_short >= 0xff00 &&
+ solid->color.blue_short >= 0xff00)) &&
+ ((content & CAIRO_CONTENT_ALPHA) == 0 ||
+ solid->color.alpha_short >= 0xff00))
+ {
+ src->base.content = CAIRO_CONTENT_ALPHA;
+ src->type.fragment = FS_ONE;
+ }
+ else if (is_pure (solid->color.red_short, content & CAIRO_CONTENT_COLOR) &&
+ is_pure (solid->color.green_short, content & CAIRO_CONTENT_COLOR) &&
+ is_pure (solid->color.blue_short, content & CAIRO_CONTENT_COLOR) &&
+ is_pure (solid->color.alpha_short, content & CAIRO_CONTENT_ALPHA))
+ {
+ src->solid.pure = 0;
+ src->solid.pure |= is_one (solid->color.red_short, content & CAIRO_CONTENT_COLOR) << 0;
+ src->solid.pure |= is_one (solid->color.green_short, content & CAIRO_CONTENT_COLOR) << 1;
+ src->solid.pure |= is_one (solid->color.blue_short, content & CAIRO_CONTENT_COLOR) << 2;
+ src->solid.pure |= (! is_zero (solid->color.alpha_short, content & CAIRO_CONTENT_ALPHA)) << 3;
+
+ if (src->solid.pure == 0) {
+ src->base.content = CAIRO_CONTENT_ALPHA;
+ src->type.fragment = FS_ZERO;
+ } else if (src->solid.pure == 0x7) {
+ src->base.content = CAIRO_CONTENT_ALPHA;
+ src->type.fragment = FS_ONE;
+ } else {
+ src->base.content = content;
+ src->type.fragment = FS_PURE;
+ src->base.mode = src->solid.pure;
+ }
+ }
+ else
+ {
+ src->base.content = content;
+ src->type.fragment = src == &shader->source ? FS_DIFFUSE : FS_CONSTANT;
+ }
+ src->type.vertex = VS_CONSTANT;
+ src->type.pattern = PATTERN_CONSTANT;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+i915_shader_acquire_linear (i915_shader_t *shader,
+ union i915_shader_channel *src,
+ const cairo_linear_pattern_t *linear,
+ const cairo_rectangle_int_t *extents)
+{
+ cairo_bool_t mode = LINEAR_TEXTURE;
+ cairo_status_t status;
+
+ i915_shader_linear_init (&src->linear, linear);
+ if (linear->base.n_stops == 2 &&
+ linear->base.stops[0].offset == 0.0 &&
+ linear->base.stops[1].offset == 1.0)
+ {
+ if (i915_shader_linear_contains_rectangle (&src->linear,
+ extents))
+ {
+ /* XXX can also lerp if contained within offset range */
+ mode = LINEAR_NONE;
+ }
+ else switch (linear->base.base.extend) {
+ case CAIRO_EXTEND_REPEAT:
+ mode = LINEAR_REPEAT;
+ break;
+ case CAIRO_EXTEND_PAD:
+ mode = LINEAR_PAD;
+ break;
+ case CAIRO_EXTEND_NONE:
+ break;
+ case CAIRO_EXTEND_REFLECT:
+ break;
+ default:
+ ASSERT_NOT_REACHED;
+ break;
+ }
+ }
+
+ src->type.vertex = VS_LINEAR;
+ src->type.pattern = PATTERN_LINEAR;
+ src->base.texfmt = TEXCOORDFMT_1D;
+ src->base.content = CAIRO_CONTENT_COLOR_ALPHA;
+ src->base.mode = mode;
+ if (mode == LINEAR_TEXTURE) {
+ intel_buffer_t buffer;
+
+ status = intel_gradient_render ((intel_device_t *) shader->target->intel.drm.base.device,
+ &linear->base, &buffer);
+ if (unlikely (status))
+ return status;
+
+ src->type.fragment = FS_TEXTURE;
+ src->base.bo = intel_bo_reference (buffer.bo);
+ src->base.n_samplers = 1;
+ src->base.offset[0] = buffer.offset;
+ src->base.map[0] = buffer.map0;
+ src->base.map[1] = buffer.map1;
+ src->base.sampler[0] =
+ (MIPFILTER_NONE << SS2_MIP_FILTER_SHIFT) |
+ i915_texture_filter (CAIRO_FILTER_BILINEAR);
+ src->base.sampler[1] =
+ SS3_NORMALIZED_COORDS |
+ i915_texture_extend (linear->base.base.extend);
+ } else {
+ src->type.fragment = FS_LINEAR;
+ src->linear.color0.red = linear->base.stops[0].color.red;
+ src->linear.color0.green = linear->base.stops[0].color.green;
+ src->linear.color0.blue = linear->base.stops[0].color.blue;
+ src->linear.color0.alpha = linear->base.stops[0].color.alpha;
+
+ src->linear.color1.red = linear->base.stops[1].color.red;
+ src->linear.color1.green = linear->base.stops[1].color.green;
+ src->linear.color1.blue = linear->base.stops[1].color.blue;
+ src->linear.color1.alpha = linear->base.stops[1].color.alpha;
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+i915_shader_acquire_radial (i915_shader_t *shader,
+ union i915_shader_channel *src,
+ const cairo_radial_pattern_t *radial,
+ const cairo_rectangle_int_t *extents)
+{
+ intel_buffer_t buffer;
+ cairo_status_t status;
+
+ status = intel_gradient_render ((intel_device_t *) shader->target->intel.drm.base.device,
+ &radial->base, &buffer);
+ if (unlikely (status))
+ return status;
+
+ i915_shader_radial_init (&src->radial, radial);
+
+ src->type.vertex = VS_RADIAL;
+ src->type.fragment = FS_RADIAL;
+ src->type.pattern = PATTERN_RADIAL;
+ src->base.texfmt = TEXCOORDFMT_2D;
+
+ src->base.content = CAIRO_CONTENT_COLOR_ALPHA;
+ src->base.bo = intel_bo_reference (buffer.bo);
+ src->base.n_samplers = 1;
+ src->base.offset[0] = buffer.offset;
+ src->base.map[0] = buffer.map0;
+ src->base.map[1] = buffer.map1;
+ src->base.sampler[0] =
+ (MIPFILTER_NONE << SS2_MIP_FILTER_SHIFT) |
+ i915_texture_filter (CAIRO_FILTER_BILINEAR);
+ src->base.sampler[1] =
+ SS3_NORMALIZED_COORDS |
+ i915_texture_extend (radial->base.base.extend);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+i915_surface_clone (i915_device_t *device,
+ cairo_image_surface_t *image,
+ i915_surface_t **clone_out)
+{
+ i915_surface_t *clone;
+ cairo_status_t status;
+
+ clone =
+ i915_surface_create_from_cacheable_image_internal (device, image);
+ if (unlikely (clone->intel.drm.base.status))
+ return clone->intel.drm.base.status;
+
+ status = _cairo_surface_attach_snapshot (&image->base,
+ &clone->intel.drm.base,
+ intel_surface_detach_snapshot);
+ if (likely (status == CAIRO_STATUS_SUCCESS))
+ status = intel_snapshot_cache_insert (&device->intel, &clone->intel);
+
+ if (unlikely (status)) {
+ cairo_surface_destroy (&clone->intel.drm.base);
+ return status;
+ }
+
+ *clone_out = clone;
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+i915_surface_clone_subimage (i915_device_t *device,
+ cairo_image_surface_t *image,
+ const cairo_rectangle_int_t *extents,
+ i915_surface_t **clone_out)
+{
+ i915_surface_t *clone;
+ cairo_status_t status;
+
+ clone = (i915_surface_t *)
+ i915_surface_create_internal (&device->intel.base,
+ image->base.content,
+ extents->width,
+ extents->height,
+ I915_TILING_DEFAULT,
+ FALSE);
+ if (unlikely (clone->intel.drm.base.status))
+ return clone->intel.drm.base.status;
+
+ status = intel_bo_put_image (to_intel_device (clone->intel.drm.base.device),
+ to_intel_bo (clone->intel.drm.bo),
+ clone->intel.drm.stride,
+ image,
+ extents->x, extents->y,
+ extents->width, extents->height,
+ 0, 0);
+
+ if (unlikely (status))
+ return status;
+
+ *clone_out = clone;
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+i915_shader_acquire_solid_surface (i915_shader_t *shader,
+ union i915_shader_channel *src,
+ cairo_surface_t *surface,
+ const cairo_rectangle_int_t *extents)
+{
+ cairo_surface_pattern_t pattern;
+ cairo_surface_t *pixel;
+ cairo_image_surface_t *image;
+ void *image_extra;
+ cairo_status_t status;
+ uint32_t argb;
+
+ status = _cairo_surface_acquire_source_image (surface, &image, &image_extra);
+ if (unlikely (status))
+ return status;
+
+ /* extract the pixel as argb32 */
+ pixel = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 1, 1);
+ _cairo_pattern_init_for_surface (&pattern, &image->base);
+ cairo_matrix_init_translate (&pattern.base.matrix, extents->x, extents->y);
+ pattern.base.filter = CAIRO_FILTER_NEAREST;
+ status = _cairo_surface_paint (pixel, CAIRO_OPERATOR_SOURCE, &pattern.base, NULL);
+ _cairo_pattern_fini (&pattern.base);
+
+ _cairo_surface_release_source_image (surface, image, image_extra);
+
+ if (unlikely (status)) {
+ cairo_surface_destroy (pixel);
+ return status;
+ }
+
+ image = (cairo_image_surface_t *) pixel;
+ argb = *(uint32_t *) image->data;
+ cairo_surface_destroy (pixel);
+
+ if (argb >> 24 == 0) {
+ _cairo_color_init_rgba (&src->solid.color, 0, 0, 0, 0);
+ } else {
+ uint8_t alpha = argb >> 24;
+
+ _cairo_color_init_rgba (&src->solid.color,
+ ((((argb >> 16) & 0xff) * 255 + alpha / 2) / alpha) / 255.,
+ ((((argb >> 8) & 0xff) * 255 + alpha / 2) / alpha) / 255.,
+ ((((argb >> 0) & 0xff) * 255 + alpha / 2) / alpha) / 255.,
+ alpha / 255.);
+ }
+
+ src->base.content = CAIRO_CONTENT_COLOR_ALPHA;
+ src->type.fragment = FS_CONSTANT;
+ src->type.vertex = VS_CONSTANT;
+ src->type.pattern = PATTERN_CONSTANT;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+i915_shader_acquire_surface (i915_shader_t *shader,
+ union i915_shader_channel *src,
+ const cairo_surface_pattern_t *pattern,
+ const cairo_rectangle_int_t *extents)
+{
+ int surface_width, surface_height;
+ cairo_surface_t *surface, *drm;
+ cairo_extend_t extend;
+ cairo_filter_t filter;
+ cairo_matrix_t m;
+ int src_x = 0, src_y = 0;
+
+ assert (src->type.fragment == (i915_fragment_shader_t) -1);
+ drm = surface = pattern->surface;
+
+#if CAIRO_HAS_XCB_SURFACE && CAIRO_HAS_XCB_DRM_FUNCTIONS
+ if (surface->type == CAIRO_SURFACE_TYPE_XCB) {
+ cairo_surface_t *xcb = surface;
+
+ if (xcb->backend->type == CAIRO_INTERNAL_SURFACE_TYPE_SUBSURFACE) {
+ xcb = ((cairo_surface_subsurface_t *) surface)->target;
+ } else if (xcb->backend->type == CAIRO_INTERNAL_SURFACE_TYPE_SNAPSHOT) {
+ xcb = ((cairo_surface_snapshot_t *) surface)->target;
+ }
+
+ /* XXX copy windows (IncludeInferiors) to a pixmap/drm surface
+ * xcb = _cairo_xcb_surface_to_drm (xcb)
+ */
+ xcb = ((cairo_xcb_surface_t *) xcb)->drm;
+ if (xcb != NULL)
+ drm = xcb;
+ }
+#endif
+
+ if (surface->type == CAIRO_SURFACE_TYPE_DRM) {
+ if (surface->backend->type == CAIRO_INTERNAL_SURFACE_TYPE_SUBSURFACE) {
+ drm = ((cairo_surface_subsurface_t *) surface)->target;
+ } else if (surface->backend->type == CAIRO_INTERNAL_SURFACE_TYPE_SNAPSHOT) {
+ drm = ((cairo_surface_snapshot_t *) surface)->target;
+ }
+ }
+
+ if (drm->type == CAIRO_SURFACE_TYPE_DRM) {
+ i915_surface_t *s = (i915_surface_t *) drm;
+
+ if (surface->backend->type == CAIRO_INTERNAL_SURFACE_TYPE_SUBSURFACE) {
+ if (s->intel.drm.base.device == shader->target->intel.drm.base.device &&
+ s != shader->target)
+ {
+ cairo_surface_subsurface_t *sub = (cairo_surface_subsurface_t *) surface;
+ int x;
+
+ if (to_intel_bo (s->intel.drm.bo)->batch_write_domain) {
+ /* XXX pipelined flush of RENDER/TEXTURE cache */
+ }
+
+ src->type.fragment = FS_TEXTURE;
+ src->surface.pixel = NONE;
+ surface_width = sub->extents.width;
+ surface_height = sub->extents.height;
+
+ src->base.bo = intel_bo_reference (to_intel_bo (s->intel.drm.bo));
+ src->base.n_samplers = 1;
+
+ x = sub->extents.x;
+ if (s->intel.drm.format != CAIRO_FORMAT_A8)
+ x *= 4;
+
+ /* XXX tiling restrictions upon offset? */
+ src->base.offset[0] = s->offset + sub->extents.y * s->intel.drm.stride + x;
+ src->base.map[0] = s->map0;
+ src->base.map[0] &= ~((2047 << MS3_HEIGHT_SHIFT) | (2047 << MS3_WIDTH_SHIFT));
+ src->base.map[0] |=
+ ((sub->extents.height - 1) << MS3_HEIGHT_SHIFT) |
+ ((sub->extents.width - 1) << MS3_WIDTH_SHIFT);
+ src->base.map[1] = (s->intel.drm.stride / 4 - 1) << MS4_PITCH_SHIFT;
+ }
+ } else {
+ /* XXX if s == shader->dst allow if FILTER_NEAREST, EXTEND_NONE? */
+ if (s->intel.drm.base.device == shader->target->intel.drm.base.device &&
+ s != shader->target)
+ {
+ src->type.fragment = FS_TEXTURE;
+ src->surface.pixel = NONE;
+ surface_width = s->intel.drm.width;
+ surface_height = s->intel.drm.height;
+
+ src->base.bo = intel_bo_reference (to_intel_bo (s->intel.drm.bo));
+ src->base.n_samplers = 1;
+ src->base.offset[0] = s->offset;
+ src->base.map[0] = s->map0;
+ src->base.map[1] = s->map1;
+ }
+ }
+ }
+
+ if (src->type.fragment == (i915_fragment_shader_t) -1) {
+ i915_surface_t *s;
+
+ if (extents->width == 1 && extents->height == 1) {
+ return i915_shader_acquire_solid_surface (shader, src,
+ surface, extents);
+ }
+
+ s = (i915_surface_t *)
+ _cairo_surface_has_snapshot (surface,
+ shader->target->intel.drm.base.backend);
+ if (s == NULL) {
+ cairo_image_surface_t *image;
+ void *image_extra;
+ cairo_status_t status;
+
+#if 0
+ /* XXX hackity hack hack */
+ status = i915_clone_yuv (surface, src,
+ image->width, image->height,
+ clone_out);
+#endif
+
+ status = _cairo_surface_acquire_source_image (surface, &image, &image_extra);
+ if (unlikely (status))
+ return status;
+
+ if (image->width < 2048 && image->height < 2048) {
+ status = i915_surface_clone ((i915_device_t *) shader->target->intel.drm.base.device,
+ image, &s);
+ } else {
+ status = i915_surface_clone_subimage ((i915_device_t *) shader->target->intel.drm.base.device,
+ image, extents, &s);
+ src_x = -extents->x;
+ src_y = -extents->y;
+ }
+
+ surface_width = image->width;
+ surface_height = image->height;
+
+ _cairo_surface_release_source_image (surface, image, image_extra);
+
+ if (unlikely (status))
+ return status;
+ }
+
+ src->type.fragment = FS_TEXTURE;
+ src->surface.pixel = NONE;
+
+ src->base.bo = intel_bo_reference (to_intel_bo (s->intel.drm.bo));
+ src->base.n_samplers = 1;
+ src->base.offset[0] = s->offset;
+ src->base.map[0] = s->map0;
+ src->base.map[1] = s->map1;
+
+ drm = &s->intel.drm.base;
+ }
+
+ /* XXX transform nx1 or 1xn surfaces to 1D */
+
+ src->type.pattern = PATTERN_TEXTURE;
+ extend = pattern->base.extend;
+ if (extend != CAIRO_EXTEND_NONE &&
+ extents->x >= 0 && extents->y >= 0 &&
+ extents->x + extents->width <= surface_width &&
+ extents->y + extents->height <= surface_height)
+ {
+ extend = CAIRO_EXTEND_NONE;
+ }
+ if (extend == CAIRO_EXTEND_NONE) {
+ src->type.vertex = VS_TEXTURE_16;
+ src->base.texfmt = TEXCOORDFMT_2D_16;
+ } else {
+ src->type.vertex = VS_TEXTURE;
+ src->base.texfmt = TEXCOORDFMT_2D;
+ }
+ src->base.content = drm->content;
+
+ filter = pattern->base.filter;
+ if (_cairo_matrix_is_pixel_exact (&pattern->base.matrix))
+ filter = CAIRO_FILTER_NEAREST;
+
+ src->base.sampler[0] =
+ (MIPFILTER_NONE << SS2_MIP_FILTER_SHIFT) |
+ i915_texture_filter (filter);
+ src->base.sampler[1] =
+ SS3_NORMALIZED_COORDS |
+ i915_texture_extend (extend);
+
+ /* tweak the src matrix to map from dst to texture coordinates */
+ src->base.matrix = pattern->base.matrix;
+ if (src_x | src_y)
+ cairo_matrix_translate (&src->base.matrix, src_x, src_x);
+ if (i915_texture_filter_is_nearest (filter))
+ cairo_matrix_translate (&src->base.matrix, NEAREST_BIAS, NEAREST_BIAS);
+ cairo_matrix_init_scale (&m, 1. / surface_width, 1. / surface_height);
+ cairo_matrix_multiply (&src->base.matrix, &src->base.matrix, &m);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+cairo_status_t
+i915_shader_acquire_pattern (i915_shader_t *shader,
+ union i915_shader_channel *src,
+ const cairo_pattern_t *pattern,
+ const cairo_rectangle_int_t *extents)
+{
+ switch (pattern->type) {
+ case CAIRO_PATTERN_TYPE_SOLID:
+ return i915_shader_acquire_solid (shader, src,
+ (cairo_solid_pattern_t *) pattern,
+ extents);
+
+ case CAIRO_PATTERN_TYPE_LINEAR:
+ return i915_shader_acquire_linear (shader, src,
+ (cairo_linear_pattern_t *) pattern,
+ extents);
+
+ case CAIRO_PATTERN_TYPE_RADIAL:
+ return i915_shader_acquire_radial (shader, src,
+ (cairo_radial_pattern_t *) pattern,
+ extents);
+
+ case CAIRO_PATTERN_TYPE_SURFACE:
+ return i915_shader_acquire_surface (shader, src,
+ (cairo_surface_pattern_t *) pattern,
+ extents);
+
+ default:
+ ASSERT_NOT_REACHED;
+ return CAIRO_STATUS_SUCCESS;
+ }
+}
+
+static uint32_t
+i915_get_blend (cairo_operator_t op,
+ i915_surface_t *dst)
+{
+#define SBLEND(X) ((BLENDFACT_##X) << S6_CBUF_SRC_BLEND_FACT_SHIFT)
+#define DBLEND(X) ((BLENDFACT_##X) << S6_CBUF_DST_BLEND_FACT_SHIFT)
+ static const struct blendinfo {
+ cairo_bool_t dst_alpha;
+ uint32_t src_blend;
+ uint32_t dst_blend;
+ enum {
+ BOUNDED,
+ SIMPLE,
+ XRENDER,
+ } kind;
+ } i915_blend_op[] = {
+ {0, SBLEND (ZERO), DBLEND (ZERO), BOUNDED}, /* Clear */
+ {0, SBLEND (ONE), DBLEND (ZERO), BOUNDED}, /* Src */
+
+ {0, SBLEND (ONE), DBLEND (INV_SRC_ALPHA), SIMPLE}, /* Over */
+ {1, SBLEND (DST_ALPHA), DBLEND (ZERO), XRENDER}, /* In */
+ {1, SBLEND (INV_DST_ALPHA), DBLEND (ZERO), XRENDER}, /* Out */
+ {1, SBLEND (DST_ALPHA), DBLEND (INV_SRC_ALPHA), SIMPLE}, /* Atop */
+
+ {0, SBLEND (ZERO), DBLEND (ONE), SIMPLE}, /* Dst */
+ {1, SBLEND (INV_DST_ALPHA), DBLEND (ONE), SIMPLE}, /* OverReverse */
+ {0, SBLEND (ZERO), DBLEND (SRC_ALPHA), XRENDER}, /* InReverse */
+ {0, SBLEND (ZERO), DBLEND (INV_SRC_ALPHA), SIMPLE}, /* OutReverse */
+ {1, SBLEND (INV_DST_ALPHA), DBLEND (SRC_ALPHA), XRENDER}, /* AtopReverse */
+
+ {1, SBLEND (INV_DST_ALPHA), DBLEND (INV_SRC_ALPHA), SIMPLE}, /* Xor */
+ {0, SBLEND (ONE), DBLEND (ONE), SIMPLE}, /* Add */
+ //{0, 0, SBLEND (SRC_ALPHA_SATURATE), DBLEND (ONE), SIMPLE}, /* XXX Saturate */
+ };
+ uint32_t sblend, dblend;
+
+ if (op >= ARRAY_LENGTH (i915_blend_op))
+ return 0;
+
+ if (i915_blend_op[op].kind == BOUNDED)
+ return 0;
+
+ sblend = i915_blend_op[op].src_blend;
+ dblend = i915_blend_op[op].dst_blend;
+
+ /* If there's no dst alpha channel, adjust the blend op so that we'll treat
+ * it as always 1.
+ */
+ if ((dst->intel.drm.base.content & CAIRO_CONTENT_ALPHA) == 0 &&
+ i915_blend_op[op].dst_alpha)
+ {
+ if (sblend == SBLEND (DST_ALPHA))
+ sblend = SBLEND (ONE);
+ else if (sblend == SBLEND (INV_DST_ALPHA))
+ sblend = SBLEND (ZERO);
+ }
+
+ /* i915 engine reads 8bit color buffer into green channel in cases
+ like color buffer blending etc., and also writes back green channel.
+ So with dst_alpha blend we should use color factor. See spec on
+ "8-bit rendering" */
+ if (dst->intel.drm.format == CAIRO_FORMAT_A8 && i915_blend_op[op].dst_alpha) {
+ if (sblend == SBLEND (DST_ALPHA))
+ sblend = SBLEND (DST_COLR);
+ else if (sblend == SBLEND (INV_DST_ALPHA))
+ sblend = SBLEND (INV_DST_COLR);
+ }
+
+ return sblend | dblend;
+#undef SBLEND
+#undef DBLEND
+}
+
+static void
+i915_shader_channel_init (union i915_shader_channel *channel)
+{
+ channel->type.vertex = (i915_vertex_shader_t) -1;
+ channel->type.fragment = (i915_fragment_shader_t) -1;
+ channel->type.pattern = (i915_shader_channel_t) -1;
+ channel->base.texfmt = TEXCOORDFMT_NOT_PRESENT;
+ channel->base.bo = NULL;
+ channel->base.n_samplers = 0;
+ channel->base.mode = 0;
+}
+
+void
+i915_shader_init (i915_shader_t *shader,
+ i915_surface_t *dst,
+ cairo_operator_t op)
+{
+ shader->device = i915_device (dst);
+ shader->target = dst;
+ shader->op = op;
+
+ shader->blend = i915_get_blend (op, dst);
+ shader->need_combine = FALSE;
+
+ shader->content = dst->intel.drm.base.content;
+
+ i915_shader_channel_init (&shader->source);
+ i915_shader_channel_init (&shader->mask);
+ i915_shader_channel_init (&shader->clip);
+ i915_shader_channel_init (&shader->dst);
+}
+
+static void
+i915_set_shader_samplers (i915_device_t *device,
+ const i915_shader_t *shader)
+{
+ uint32_t n_samplers, n;
+ uint32_t samplers[4 * (1+2+8)];
+ uint32_t mask, tu;
+
+ n_samplers =
+ shader->source.base.n_samplers +
+ shader->mask.base.n_samplers +
+ shader->clip.base.n_samplers +
+ shader->dst.base.n_samplers;
+ assert (n_samplers <= 4);
+
+ if (n_samplers == 0)
+ return;
+
+ mask = (1 << n_samplers) - 1;
+
+ /* We check for repeated setting of sample state mainly to catch
+ * continuation of text strings across multiple show-glyphs.
+ */
+ tu = 0;
+ if (shader->source.base.bo != NULL) {
+ samplers[tu++] = shader->source.base.bo->base.handle;
+ samplers[tu++] = shader->source.base.sampler[0];
+ samplers[tu++] = shader->source.base.sampler[1];
+ for (n = 0; n < shader->source.base.n_samplers; n++) {
+ samplers[tu++] = shader->source.base.offset[n];
+ samplers[tu++] = shader->source.base.map[2*n+0];
+ samplers[tu++] = shader->source.base.map[2*n+1];
+ }
+ }
+ if (shader->mask.base.bo != NULL) {
+ samplers[tu++] = shader->mask.base.bo->base.handle;
+ samplers[tu++] = shader->mask.base.sampler[0];
+ samplers[tu++] = shader->mask.base.sampler[1];
+ for (n = 0; n < shader->mask.base.n_samplers; n++) {
+ samplers[tu++] = shader->mask.base.offset[n];
+ samplers[tu++] = shader->mask.base.map[2*n+0];
+ samplers[tu++] = shader->mask.base.map[2*n+1];
+ }
+ }
+ if (shader->clip.base.bo != NULL) {
+ samplers[tu++] = shader->clip.base.bo->base.handle;
+ samplers[tu++] = shader->clip.base.sampler[0];
+ samplers[tu++] = shader->clip.base.sampler[1];
+ for (n = 0; n < shader->clip.base.n_samplers; n++) {
+ samplers[tu++] = shader->clip.base.offset[n];
+ samplers[tu++] = shader->clip.base.map[2*n+0];
+ samplers[tu++] = shader->clip.base.map[2*n+1];
+ }
+ }
+ if (shader->dst.base.bo != NULL) {
+ samplers[tu++] = shader->dst.base.bo->base.handle;
+ samplers[tu++] = shader->dst.base.sampler[0];
+ samplers[tu++] = shader->dst.base.sampler[1];
+ for (n = 0; n < shader->dst.base.n_samplers; n++) {
+ samplers[tu++] = shader->dst.base.offset[n];
+ samplers[tu++] = shader->dst.base.map[2*n+0];
+ samplers[tu++] = shader->dst.base.map[2*n+1];
+ }
+ }
+
+ if (tu == device->current_n_samplers &&
+ memcmp (device->current_samplers,
+ samplers,
+ tu * sizeof (uint32_t)) == 0)
+ {
+ return;
+ }
+ device->current_n_samplers = tu;
+ memcpy (device->current_samplers, samplers, tu * sizeof (uint32_t));
+
+ if (device->current_source != NULL)
+ *device->current_source = 0;
+ if (device->current_mask != NULL)
+ *device->current_mask = 0;
+ if (device->current_clip != NULL)
+ *device->current_clip = 0;
+
+#if 0
+ if (shader->source.type.pattern == PATTERN_TEXTURE) {
+ switch ((int) shader->source.surface.surface->type) {
+ case CAIRO_SURFACE_TYPE_DRM:
+ {
+ i915_surface_t *surface =
+ (i915_surface_t *) shader->source.surface.surface;
+ device->current_source = &surface->is_current_texture;
+ surface->is_current_texture |= CURRENT_SOURCE;
+ break;
+ }
+
+ case I915_PACKED_PIXEL_SURFACE_TYPE:
+ {
+ i915_packed_pixel_surface_t *surface =
+ (i915_packed_pixel_surface_t *) shader->source.surface.surface;
+ device->current_source = &surface->is_current_texture;
+ surface->is_current_texture |= CURRENT_SOURCE;
+ break;
+ }
+
+ default:
+ device->current_source = NULL;
+ break;
+ }
+ } else
+ device->current_source = NULL;
+
+ if (shader->mask.type.pattern == PATTERN_TEXTURE) {
+ switch ((int) shader->mask.surface.surface->type) {
+ case CAIRO_SURFACE_TYPE_DRM:
+ {
+ i915_surface_t *surface =
+ (i915_surface_t *) shader->mask.surface.surface;
+ device->current_mask = &surface->is_current_texture;
+ surface->is_current_texture |= CURRENT_MASK;
+ break;
+ }
+
+ case I915_PACKED_PIXEL_SURFACE_TYPE:
+ {
+ i915_packed_pixel_surface_t *surface =
+ (i915_packed_pixel_surface_t *) shader->mask.surface.surface;
+ device->current_mask = &surface->is_current_texture;
+ surface->is_current_texture |= CURRENT_MASK;
+ break;
+ }
+
+ default:
+ device->current_mask = NULL;
+ break;
+ }
+ } else
+ device->current_mask = NULL;
+#endif
+
+ OUT_DWORD (_3DSTATE_MAP_STATE | (3 * n_samplers));
+ OUT_DWORD (mask);
+ if (shader->source.base.bo != NULL) {
+ for (n = 0; n < shader->source.base.n_samplers; n++) {
+ i915_batch_emit_reloc (device, shader->source.base.bo,
+ shader->source.base.offset[n],
+ I915_GEM_DOMAIN_SAMPLER, 0);
+ OUT_DWORD (shader->source.base.map[2*n+0]);
+ OUT_DWORD (shader->source.base.map[2*n+1]);
+ }
+ }
+ if (shader->mask.base.bo != NULL) {
+ for (n = 0; n < shader->mask.base.n_samplers; n++) {
+ i915_batch_emit_reloc (device, shader->mask.base.bo,
+ shader->mask.base.offset[n],
+ I915_GEM_DOMAIN_SAMPLER, 0);
+ OUT_DWORD (shader->mask.base.map[2*n+0]);
+ OUT_DWORD (shader->mask.base.map[2*n+1]);
+ }
+ }
+ if (shader->clip.base.bo != NULL) {
+ for (n = 0; n < shader->clip.base.n_samplers; n++) {
+ i915_batch_emit_reloc (device, shader->clip.base.bo,
+ shader->clip.base.offset[n],
+ I915_GEM_DOMAIN_SAMPLER, 0);
+ OUT_DWORD (shader->clip.base.map[2*n+0]);
+ OUT_DWORD (shader->clip.base.map[2*n+1]);
+ }
+ }
+ if (shader->dst.base.bo != NULL) {
+ for (n = 0; n < shader->dst.base.n_samplers; n++) {
+ i915_batch_emit_reloc (device, shader->dst.base.bo,
+ shader->dst.base.offset[n],
+ I915_GEM_DOMAIN_SAMPLER, 0);
+ OUT_DWORD (shader->dst.base.map[2*n+0]);
+ OUT_DWORD (shader->dst.base.map[2*n+1]);
+ }
+ }
+
+ OUT_DWORD (_3DSTATE_SAMPLER_STATE | (3 * n_samplers));
+ OUT_DWORD (mask);
+ tu = 0;
+ if (shader->source.base.bo != NULL) {
+ for (n = 0; n < shader->source.base.n_samplers; n++) {
+ OUT_DWORD (shader->source.base.sampler[0]);
+ OUT_DWORD (shader->source.base.sampler[1] |
+ (tu << SS3_TEXTUREMAP_INDEX_SHIFT));
+ OUT_DWORD (0x0);
+ tu++;
+ }
+ }
+ if (shader->mask.base.bo != NULL) {
+ for (n = 0; n < shader->mask.base.n_samplers; n++) {
+ OUT_DWORD (shader->mask.base.sampler[0]);
+ OUT_DWORD (shader->mask.base.sampler[1] |
+ (tu << SS3_TEXTUREMAP_INDEX_SHIFT));
+ OUT_DWORD (0x0);
+ tu++;
+ }
+ }
+ if (shader->clip.base.bo != NULL) {
+ for (n = 0; n < shader->clip.base.n_samplers; n++) {
+ OUT_DWORD (shader->clip.base.sampler[0]);
+ OUT_DWORD (shader->clip.base.sampler[1] |
+ (tu << SS3_TEXTUREMAP_INDEX_SHIFT));
+ OUT_DWORD (0x0);
+ tu++;
+ }
+ }
+ if (shader->dst.base.bo != NULL) {
+ for (n = 0; n < shader->dst.base.n_samplers; n++) {
+ OUT_DWORD (shader->dst.base.sampler[0]);
+ OUT_DWORD (shader->dst.base.sampler[1] |
+ (tu << SS3_TEXTUREMAP_INDEX_SHIFT));
+ OUT_DWORD (0x0);
+ tu++;
+ }
+ }
+}
+
+static uint32_t
+i915_shader_get_texcoords (const i915_shader_t *shader)
+{
+ uint32_t texcoords;
+ uint32_t tu;
+
+ texcoords = S2_TEXCOORD_NONE;
+ tu = 0;
+ if (shader->source.base.texfmt != TEXCOORDFMT_NOT_PRESENT) {
+ texcoords &= ~S2_TEXCOORD_FMT (tu, S2_TEXCOORD_FMT0_MASK);
+ texcoords |= S2_TEXCOORD_FMT (tu, shader->source.base.texfmt);
+ tu++;
+ }
+ if (shader->mask.base.texfmt != TEXCOORDFMT_NOT_PRESENT) {
+ texcoords &= ~S2_TEXCOORD_FMT (tu, S2_TEXCOORD_FMT0_MASK);
+ texcoords |= S2_TEXCOORD_FMT (tu, shader->mask.base.texfmt);
+ tu++;
+ }
+ if (shader->clip.base.texfmt != TEXCOORDFMT_NOT_PRESENT) {
+ texcoords &= ~S2_TEXCOORD_FMT (tu, S2_TEXCOORD_FMT0_MASK);
+ texcoords |= S2_TEXCOORD_FMT (tu, shader->clip.base.texfmt);
+ tu++;
+ }
+ if (shader->dst.base.texfmt != TEXCOORDFMT_NOT_PRESENT) {
+ texcoords &= ~S2_TEXCOORD_FMT (tu, S2_TEXCOORD_FMT0_MASK);
+ texcoords |= S2_TEXCOORD_FMT (tu, shader->dst.base.texfmt);
+ tu++;
+ }
+
+ return texcoords;
+}
+
+static void
+i915_set_shader_mode (i915_device_t *device,
+ const i915_shader_t *shader)
+{
+ uint32_t texcoords;
+ uint32_t mask, cnt;
+
+ texcoords = i915_shader_get_texcoords (shader);
+
+ mask = cnt = 0;
+
+ if (device->current_texcoords != texcoords)
+ mask |= I1_LOAD_S (2), cnt++;
+
+ if (device->current_blend != shader->blend)
+ mask |= I1_LOAD_S (6), cnt++;
+
+ if (cnt == 0)
+ return;
+
+ OUT_DWORD (_3DSTATE_LOAD_STATE_IMMEDIATE_1 | mask | (cnt-1));
+
+ if (device->current_texcoords != texcoords) {
+ OUT_DWORD (texcoords);
+ device->current_texcoords = texcoords;
+ }
+
+ if (device->current_blend != shader->blend) {
+ if (shader->blend) {
+ OUT_DWORD (S6_CBUF_BLEND_ENABLE | S6_COLOR_WRITE_ENABLE |
+ (BLENDFUNC_ADD << S6_CBUF_BLEND_FUNC_SHIFT) |
+ shader->blend);
+ } else {
+ OUT_DWORD (S6_COLOR_WRITE_ENABLE);
+ }
+
+ device->current_blend = shader->blend;
+ }
+}
+
+static void
+i915_set_constants (i915_device_t *device,
+ const uint32_t *constants,
+ uint32_t n_constants)
+{
+ uint32_t n;
+
+ OUT_DWORD (_3DSTATE_PIXEL_SHADER_CONSTANTS | n_constants);
+ OUT_DWORD ((1 << (n_constants >> 2)) - 1);
+
+ for (n = 0; n < n_constants; n++)
+ OUT_DWORD (constants[n]);
+
+ device->current_n_constants = n_constants;
+ memcpy (device->current_constants, constants, n_constants*4);
+}
+
+static inline uint32_t
+pack_float (float f)
+{
+ union {
+ float f;
+ uint32_t ui;
+ } t;
+ t.f = f;
+ return t.ui;
+}
+
+static uint32_t
+pack_constants (const union i915_shader_channel *channel,
+ uint32_t *constants)
+{
+ uint32_t count = 0, n;
+
+ switch (channel->type.fragment) {
+ case FS_ZERO:
+ case FS_ONE:
+ case FS_PURE:
+ case FS_DIFFUSE:
+ break;
+
+ case FS_CONSTANT:
+ constants[count++] = pack_float (channel->solid.color.red);
+ constants[count++] = pack_float (channel->solid.color.green);
+ constants[count++] = pack_float (channel->solid.color.blue);
+ constants[count++] = pack_float (channel->solid.color.alpha);
+ break;
+
+ case FS_LINEAR:
+ constants[count++] = pack_float (channel->linear.color0.red);
+ constants[count++] = pack_float (channel->linear.color0.green);
+ constants[count++] = pack_float (channel->linear.color0.blue);
+ constants[count++] = pack_float (channel->linear.color0.alpha);
+
+ constants[count++] = pack_float (channel->linear.color1.red);
+ constants[count++] = pack_float (channel->linear.color1.green);
+ constants[count++] = pack_float (channel->linear.color1.blue);
+ constants[count++] = pack_float (channel->linear.color1.alpha);
+ break;
+
+ case FS_RADIAL:
+ for (n = 0; n < ARRAY_LENGTH (channel->radial.constants); n++)
+ constants[count++] = pack_float (channel->radial.constants[n]);
+ break;
+
+ case FS_TEXTURE:
+ case FS_YUV:
+ case FS_SPANS:
+ break;
+ }
+
+ return count;
+}
+
+static void
+i915_set_shader_constants (i915_device_t *device,
+ const i915_shader_t *shader)
+{
+ uint32_t constants[4*4*3];
+ unsigned n_constants;
+
+ n_constants = 0;
+ if (shader->source.type.fragment == FS_DIFFUSE) {
+ uint32_t diffuse;
+
+ diffuse =
+ ((shader->source.solid.color.alpha_short >> 8) << 24) |
+ ((shader->source.solid.color.red_short >> 8) << 16) |
+ ((shader->source.solid.color.green_short >> 8) << 8) |
+ ((shader->source.solid.color.blue_short >> 8) << 0);
+
+ if (diffuse != device->current_diffuse) {
+ OUT_DWORD (_3DSTATE_DFLT_DIFFUSE_CMD);
+ OUT_DWORD (diffuse);
+ device->current_diffuse = diffuse;
+ }
+ } else {
+ n_constants += pack_constants (&shader->source, constants + n_constants);
+ }
+ n_constants += pack_constants (&shader->mask, constants + n_constants);
+
+ if (n_constants != 0 &&
+ (device->current_n_constants != n_constants ||
+ memcmp (device->current_constants, constants, n_constants*4)))
+ {
+ i915_set_constants (device, constants, n_constants);
+ }
+}
+
+static cairo_bool_t
+i915_shader_needs_update (const i915_shader_t *shader,
+ const i915_device_t *device)
+{
+ uint32_t count, n;
+ uint32_t buf[64];
+
+ if (device->current_target != shader->target)
+ return TRUE;
+
+ count =
+ shader->source.base.n_samplers +
+ shader->mask.base.n_samplers +
+ shader->clip.base.n_samplers +
+ shader->dst.base.n_samplers;
+ if (count > 4)
+ return TRUE;
+
+ if (count != 0) {
+ count *= 3;
+ if (shader->source.base.bo != NULL)
+ count += 3;
+ if (shader->mask.base.bo != NULL)
+ count += 3;
+ if (shader->clip.base.bo != NULL)
+ count += 3;
+ if (shader->dst.base.bo != NULL)
+ count += 3;
+
+ if (count != device->current_n_samplers)
+ return TRUE;
+
+ if (count != 0) {
+ count = 0;
+ if (shader->source.base.bo != NULL) {
+ buf[count++] = shader->source.base.bo->base.handle;
+ buf[count++] = shader->source.base.sampler[0];
+ buf[count++] = shader->source.base.sampler[1];
+ for (n = 0; n < shader->source.base.n_samplers; n++) {
+ buf[count++] = shader->source.base.offset[n];
+ buf[count++] = shader->source.base.map[2*n+0];
+ buf[count++] = shader->source.base.map[2*n+1];
+ }
+ }
+ if (shader->mask.base.bo != NULL) {
+ buf[count++] = shader->mask.base.bo->base.handle;
+ buf[count++] = shader->mask.base.sampler[0];
+ buf[count++] = shader->mask.base.sampler[1];
+ for (n = 0; n < shader->mask.base.n_samplers; n++) {
+ buf[count++] = shader->mask.base.offset[n];
+ buf[count++] = shader->mask.base.map[2*n+0];
+ buf[count++] = shader->mask.base.map[2*n+1];
+ }
+ }
+ if (shader->clip.base.bo != NULL) {
+ buf[count++] = shader->clip.base.bo->base.handle;
+ buf[count++] = shader->clip.base.sampler[0];
+ buf[count++] = shader->clip.base.sampler[1];
+ for (n = 0; n < shader->clip.base.n_samplers; n++) {
+ buf[count++] = shader->clip.base.offset[n];
+ buf[count++] = shader->clip.base.map[2*n+0];
+ buf[count++] = shader->clip.base.map[2*n+1];
+ }
+ }
+ if (shader->dst.base.bo != NULL) {
+ buf[count++] = shader->dst.base.bo->base.handle;
+ buf[count++] = shader->dst.base.sampler[0];
+ buf[count++] = shader->dst.base.sampler[1];
+ for (n = 0; n < shader->dst.base.n_samplers; n++) {
+ buf[count++] = shader->dst.base.offset[n];
+ buf[count++] = shader->dst.base.map[2*n+0];
+ buf[count++] = shader->dst.base.map[2*n+1];
+ }
+ }
+
+ assert (count == device->current_n_samplers);
+ if (memcmp (device->current_samplers, buf, count * sizeof (uint32_t)))
+ return TRUE;
+ }
+ }
+
+ if (i915_shader_get_texcoords (shader) != device->current_texcoords)
+ return TRUE;
+ if (device->current_blend != shader->blend)
+ return TRUE;
+
+ count = 0;
+ if (shader->source.type.fragment == FS_DIFFUSE) {
+ uint32_t diffuse;
+
+ diffuse =
+ ((shader->source.solid.color.alpha_short >> 8) << 24) |
+ ((shader->source.solid.color.red_short >> 8) << 16) |
+ ((shader->source.solid.color.green_short >> 8) << 8) |
+ ((shader->source.solid.color.blue_short >> 8) << 0);
+
+ if (diffuse != device->current_diffuse)
+ return TRUE;
+ } else {
+ count += pack_constants (&shader->source, buf + count);
+ }
+ count += pack_constants (&shader->mask, buf + count);
+
+ if (count &&
+ (device->current_n_constants != count ||
+ memcmp (device->current_constants, buf, count*4)))
+ {
+ return TRUE;
+ }
+
+ n = (i915_shader_channel_key (&shader->source) << 0) |
+ (i915_shader_channel_key (&shader->mask) << 8) |
+ (i915_shader_channel_key (&shader->clip) << 16) |
+ (shader->op << 24) |
+ (((shader->content & CAIRO_CONTENT_ALPHA) == CAIRO_CONTENT_ALPHA) << 31);
+ return n != device->current_program;
+}
+
+static void
+i915_set_shader_target (i915_device_t *device,
+ const i915_shader_t *shader)
+{
+ i915_surface_t *dst;
+ intel_bo_t *bo;
+ uint32_t size;
+
+ dst = shader->target;
+ if (device->current_target == dst)
+ return;
+
+ bo = to_intel_bo (dst->intel.drm.bo);
+ assert (bo != NULL);
+
+ OUT_DWORD (_3DSTATE_BUF_INFO_CMD);
+ OUT_DWORD (BUF_3D_ID_COLOR_BACK |
+ BUF_tiling (bo->tiling) |
+ BUF_3D_PITCH (dst->intel.drm.stride));
+ OUT_RELOC (dst, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER);
+
+ if (dst->colorbuf != device->current_colorbuf) {
+ OUT_DWORD (_3DSTATE_DST_BUF_VARS_CMD);
+ OUT_DWORD (dst->colorbuf);
+ device->current_colorbuf = dst->colorbuf;
+ }
+
+ size = DRAW_YMAX (dst->intel.drm.height) | DRAW_XMAX (dst->intel.drm.width);
+ if (size != device->current_size) {
+ OUT_DWORD (_3DSTATE_DRAW_RECT_CMD);
+ OUT_DWORD (0); /* dither */
+ OUT_DWORD (0); /* top-left */
+ OUT_DWORD (size);
+ OUT_DWORD (0); /* origin */
+ device->current_size = size;
+ }
+
+ device->current_target = dst;
+}
+
+int
+i915_shader_num_texcoords (const i915_shader_t *shader)
+{
+ int cnt = 0;
+
+ switch (shader->source.base.texfmt) {
+ default:
+ ASSERT_NOT_REACHED;
+ case TEXCOORDFMT_NOT_PRESENT: break;
+ case TEXCOORDFMT_2D: cnt += 2; break;
+ case TEXCOORDFMT_3D: cnt += 3; break;
+ case TEXCOORDFMT_4D: cnt += 4; break;
+ case TEXCOORDFMT_1D: cnt += 1; break;
+ case TEXCOORDFMT_2D_16: cnt += 1; break;
+ }
+
+ switch (shader->mask.base.texfmt) {
+ default:
+ ASSERT_NOT_REACHED;
+ case TEXCOORDFMT_NOT_PRESENT: break;
+ case TEXCOORDFMT_2D: cnt += 2; break;
+ case TEXCOORDFMT_3D: cnt += 3; break;
+ case TEXCOORDFMT_4D: cnt += 4; break;
+ case TEXCOORDFMT_1D: cnt += 1; break;
+ case TEXCOORDFMT_2D_16: cnt += 1; break;
+ }
+
+ switch (shader->clip.base.texfmt) {
+ default:
+ ASSERT_NOT_REACHED;
+ case TEXCOORDFMT_NOT_PRESENT: break;
+ case TEXCOORDFMT_2D: cnt += 2; break;
+ case TEXCOORDFMT_3D: cnt += 3; break;
+ case TEXCOORDFMT_4D: cnt += 4; break;
+ case TEXCOORDFMT_1D: cnt += 1; break;
+ case TEXCOORDFMT_2D_16: cnt += 1; break;
+ }
+
+ switch (shader->dst.base.texfmt) {
+ default:
+ ASSERT_NOT_REACHED;
+ case TEXCOORDFMT_NOT_PRESENT: break;
+ case TEXCOORDFMT_2D: cnt += 2; break;
+ case TEXCOORDFMT_3D: cnt += 3; break;
+ case TEXCOORDFMT_4D: cnt += 4; break;
+ case TEXCOORDFMT_1D: cnt += 1; break;
+ case TEXCOORDFMT_2D_16: cnt += 1; break;
+ }
+
+ return cnt;
+}
+
+void
+i915_shader_fini (i915_shader_t *shader)
+{
+ i915_device_t *device = i915_device (shader->target);
+
+ switch (shader->source.type.pattern) {
+ case PATTERN_TEXTURE:
+ case PATTERN_BASE:
+ case PATTERN_LINEAR:
+ case PATTERN_RADIAL:
+ if (shader->source.base.bo != NULL)
+ cairo_drm_bo_destroy (&device->intel.base.base, &shader->source.base.bo->base);
+ break;
+
+ default:
+ case PATTERN_CONSTANT:
+ break;
+ }
+
+ switch (shader->mask.type.pattern) {
+ case PATTERN_TEXTURE:
+ case PATTERN_BASE:
+ case PATTERN_LINEAR:
+ case PATTERN_RADIAL:
+ if (shader->mask.base.bo != NULL)
+ cairo_drm_bo_destroy (&device->intel.base.base, &shader->mask.base.bo->base);
+ break;
+
+ default:
+ case PATTERN_CONSTANT:
+ break;
+ }
+
+ switch (shader->clip.type.pattern) {
+ case PATTERN_TEXTURE:
+ case PATTERN_BASE:
+ case PATTERN_LINEAR:
+ case PATTERN_RADIAL:
+ if (shader->clip.base.bo != NULL)
+ cairo_drm_bo_destroy (&device->intel.base.base, &shader->clip.base.bo->base);
+ break;
+
+ default:
+ case PATTERN_CONSTANT:
+ break;
+ }
+}
+
+void
+i915_shader_set_clip (i915_shader_t *shader,
+ cairo_clip_t *clip)
+{
+ cairo_surface_t *clip_surface;
+ const cairo_rectangle_int_t *clip_extents;
+ union i915_shader_channel *channel;
+ i915_surface_t *s;
+
+ clip_surface = _cairo_clip_get_surface (clip, &shader->target->intel.drm.base);
+ assert (clip_surface->status == CAIRO_STATUS_SUCCESS);
+ assert (clip_surface->type == CAIRO_SURFACE_TYPE_DRM);
+
+ channel = &shader->clip;
+ channel->type.pattern = PATTERN_TEXTURE;
+ channel->type.vertex = VS_TEXTURE_16;
+ channel->base.texfmt = TEXCOORDFMT_2D_16;
+ channel->base.content = CAIRO_CONTENT_ALPHA;
+
+ channel->type.fragment = FS_TEXTURE;
+ channel->surface.pixel = NONE;
+
+ s = (i915_surface_t *) clip_surface;
+ channel->base.bo = intel_bo_reference (to_intel_bo (s->intel.drm.bo));
+ channel->base.n_samplers = 1;
+ channel->base.offset[0] = s->offset;
+ channel->base.map[0] = s->map0;
+ channel->base.map[1] = s->map1;
+
+ channel->base.sampler[0] =
+ (MIPFILTER_NONE << SS2_MIP_FILTER_SHIFT) |
+ i915_texture_filter (CAIRO_FILTER_NEAREST);
+ channel->base.sampler[1] =
+ SS3_NORMALIZED_COORDS |
+ i915_texture_extend (CAIRO_EXTEND_NONE);
+
+ cairo_matrix_init_scale (&shader->clip.base.matrix,
+ 1. / s->intel.drm.width,
+ 1. / s->intel.drm.height);
+
+ clip_extents = _cairo_clip_get_extents (clip);
+ cairo_matrix_translate (&shader->clip.base.matrix,
+ NEAREST_BIAS + clip_extents->x,
+ NEAREST_BIAS + clip_extents->y);
+}
+
+static cairo_status_t
+i915_shader_check_aperture (i915_shader_t *shader,
+ i915_device_t *device)
+{
+ cairo_status_t status;
+ intel_bo_t *bo_array[4];
+ uint32_t n = 0;
+
+ if (shader->target != device->current_target)
+ bo_array[n++] = to_intel_bo (shader->target->intel.drm.bo);
+
+ if (shader->source.base.bo != NULL)
+ bo_array[n++] = shader->source.base.bo;
+
+ if (shader->mask.base.bo != NULL)
+ bo_array[n++] = shader->mask.base.bo;
+
+ if (shader->clip.base.bo != NULL)
+ bo_array[n++] = shader->clip.base.bo;
+
+ if (n == 0 || i915_check_aperture (device, bo_array, n))
+ return CAIRO_STATUS_SUCCESS;
+
+ status = i915_batch_flush (device);
+ if (unlikely (status))
+ return status;
+
+ assert (i915_check_aperture (device, bo_array, n));
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static void
+i915_shader_combine_mask (i915_shader_t *shader)
+{
+ if (shader->mask.type.fragment == (i915_fragment_shader_t) -1 ||
+ shader->mask.type.fragment == FS_CONSTANT)
+ {
+ return;
+ }
+
+ if (shader->mask.type.fragment == FS_PURE) {
+ if (shader->mask.solid.pure & (1<<3)) {
+ shader->mask.type.fragment = FS_ONE;
+ } else {
+ shader->mask.type.fragment = FS_ZERO;
+ }
+ }
+
+ if (shader->mask.type.fragment == FS_ONE ||
+ (shader->mask.base.content & CAIRO_CONTENT_ALPHA) == 0)
+ {
+ shader->mask.type.vertex = (i915_vertex_shader_t) -1;
+ shader->mask.type.fragment = (i915_fragment_shader_t) -1;
+ shader->mask.base.texfmt = TEXCOORDFMT_NOT_PRESENT;
+ shader->mask.base.mode = 0;
+ }
+
+ if (shader->mask.type.fragment == FS_ZERO) {
+ shader->source.type.fragment = FS_ZERO;
+ shader->source.type.vertex = VS_CONSTANT;
+ shader->source.base.texfmt = TEXCOORDFMT_NOT_PRESENT;
+ shader->source.base.mode = 0;
+ }
+
+ if (shader->source.type.fragment == FS_ZERO) {
+ shader->mask.type.vertex = (i915_vertex_shader_t) -1;
+ shader->mask.type.fragment = (i915_fragment_shader_t) -1;
+ shader->mask.base.texfmt = TEXCOORDFMT_NOT_PRESENT;
+ shader->mask.base.mode = 0;
+ }
+}
+
+static void
+i915_shader_setup_dst (i915_shader_t *shader)
+{
+ union i915_shader_channel *channel;
+ i915_surface_t *s;
+
+ /* We need to manual blending if we have a clip surface and an unbounded op,
+ * or an extended blend mode.
+ */
+ if (shader->need_combine ||
+ (shader->op < CAIRO_OPERATOR_SATURATE &&
+ (shader->clip.type.fragment == (i915_fragment_shader_t) -1 ||
+ _cairo_operator_bounded_by_mask (shader->op))))
+ {
+ return;
+ }
+
+ shader->need_combine = TRUE;
+
+ channel = &shader->dst;
+ channel->type.pattern = PATTERN_TEXTURE;
+ channel->type.vertex = VS_TEXTURE_16;
+ channel->base.texfmt = TEXCOORDFMT_2D_16;
+ channel->base.content = shader->content;
+
+ channel->type.fragment = FS_TEXTURE;
+ channel->surface.pixel = NONE;
+
+ s = shader->target;
+ channel->base.bo = to_intel_bo (s->intel.drm.bo);
+ channel->base.n_samplers = 1;
+ channel->base.offset[0] = s->offset;
+ channel->base.map[0] = s->map0;
+ channel->base.map[1] = s->map1;
+
+ channel->base.sampler[0] =
+ (MIPFILTER_NONE << SS2_MIP_FILTER_SHIFT) |
+ i915_texture_filter (CAIRO_FILTER_NEAREST);
+ channel->base.sampler[1] =
+ SS3_NORMALIZED_COORDS |
+ i915_texture_extend (CAIRO_EXTEND_NONE);
+
+ cairo_matrix_init_scale (&shader->dst.base.matrix,
+ 1. / s->intel.drm.width,
+ 1. / s->intel.drm.height);
+
+ cairo_matrix_translate (&shader->dst.base.matrix,
+ NEAREST_BIAS,
+ NEAREST_BIAS);
+}
+
+static void
+i915_shader_combine_source (i915_shader_t *shader,
+ i915_device_t *device)
+{
+ if (device->last_source_fragment == shader->source.type.fragment)
+ return;
+
+ if (device->last_source_fragment == FS_DIFFUSE) {
+ switch (shader->source.type.fragment) {
+ case FS_ONE:
+ case FS_PURE:
+ case FS_CONSTANT:
+ case FS_DIFFUSE:
+ shader->source.type.fragment = FS_DIFFUSE;
+ shader->source.base.mode = 0;
+ break;
+ case FS_ZERO:
+ case FS_LINEAR:
+ case FS_RADIAL:
+ case FS_TEXTURE:
+ case FS_YUV:
+ case FS_SPANS:
+ default:
+ break;
+ }
+ }
+
+ device->last_source_fragment = shader->source.type.fragment;
+}
+
+static inline float *
+i915_composite_vertex (float *v,
+ const i915_shader_t *shader,
+ double x, double y)
+{
+ double s, t;
+
+ /* Each vertex is:
+ * 2 vertex coordinates
+ * [0-2] source texture coordinates
+ * [0-2] mask texture coordinates
+ */
+
+ *v++ = x; *v++ = y;
+ switch (shader->source.type.vertex) {
+ case VS_CONSTANT:
+ break;
+ case VS_LINEAR:
+ *v++ = i915_shader_linear_texcoord (&shader->source.linear, x, y);
+ break;
+ case VS_RADIAL:
+ case VS_TEXTURE:
+ s = x, t = y;
+ cairo_matrix_transform_point (&shader->source.base.matrix, &s, &t);
+ *v++ = s; *v++ = t;
+ break;
+ case VS_TEXTURE_16:
+ s = x, t = y;
+ cairo_matrix_transform_point (&shader->source.base.matrix, &s, &t);
+ *v++ = texcoord_2d_16 (s, t);
+ break;
+ }
+ switch (shader->mask.type.vertex) {
+ case VS_CONSTANT:
+ break;
+ case VS_LINEAR:
+ *v++ = i915_shader_linear_texcoord (&shader->mask.linear, x, y);
+ break;
+ case VS_RADIAL:
+ s = x, t = y;
+ cairo_matrix_transform_point (&shader->mask.base.matrix, &s, &t);
+ *v++ = s; *v++ = t;
+ break;
+ case VS_TEXTURE:
+ s = x, t = y;
+ cairo_matrix_transform_point (&shader->mask.base.matrix, &s, &t);
+ *v++ = s; *v++ = t;
+ break;
+ case VS_TEXTURE_16:
+ s = x, t = y;
+ cairo_matrix_transform_point (&shader->mask.base.matrix, &s, &t);
+ *v++ = texcoord_2d_16 (s, t);
+ break;
+ }
+
+ return v;
+}
+
+static inline void
+i915_shader_add_rectangle_general (const i915_shader_t *shader,
+ int x, int y,
+ int w, int h)
+{
+ float *vertices;
+
+ vertices = i915_add_rectangle (shader->device);
+ vertices = i915_composite_vertex (vertices, shader, x + w, y + h);
+ vertices = i915_composite_vertex (vertices, shader, x, y + h);
+ vertices = i915_composite_vertex (vertices, shader, x, y);
+ /* XXX overflow! */
+}
+
+cairo_status_t
+i915_shader_commit (i915_shader_t *shader,
+ i915_device_t *device)
+{
+ unsigned floats_per_vertex;
+ cairo_status_t status;
+
+ i915_shader_combine_source (shader, device);
+ i915_shader_combine_mask (shader);
+ i915_shader_setup_dst (shader);
+
+ if (i915_shader_needs_update (shader, device)) {
+ if (device->vertex_count) {
+ status = i915_vbo_flush (device);
+ if (unlikely (status))
+ return status;
+ }
+
+ status = i915_shader_check_aperture (shader, device);
+ if (unlikely (status))
+ return status;
+
+ i915_set_shader_target (device, shader);
+ i915_set_shader_mode (device, shader);
+ i915_set_shader_samplers (device, shader);
+ i915_set_shader_constants (device, shader);
+ i915_set_shader_program (device, shader);
+ }
+
+ device->current_shader = shader;
+ shader->add_rectangle = i915_shader_add_rectangle_general;
+
+ floats_per_vertex = 2 + i915_shader_num_texcoords (shader);
+ if (device->floats_per_vertex == floats_per_vertex)
+ return CAIRO_STATUS_SUCCESS;
+
+ if (device->vertex_count) {
+ status = i915_vbo_flush (device);
+ if (unlikely (status))
+ return status;
+ }
+
+ if (device->vbo) {
+ device->batch_base[device->vbo_max_index] |= device->vertex_index;
+ OUT_DWORD (_3DSTATE_LOAD_STATE_IMMEDIATE_1 | I1_LOAD_S (1) | 0);
+ device->vbo_max_index = device->batch.used;
+ OUT_DWORD ((floats_per_vertex << S1_VERTEX_WIDTH_SHIFT) |
+ (floats_per_vertex << S1_VERTEX_PITCH_SHIFT));
+ }
+
+ device->floats_per_vertex = floats_per_vertex;
+ device->rectangle_size = floats_per_vertex * 3 * sizeof (float);
+ device->vertex_index =
+ (device->vbo_used + 4*floats_per_vertex - 1) / (4 * floats_per_vertex);
+ device->vbo_offset = 4 * device->vertex_index * floats_per_vertex;
+
+ return CAIRO_STATUS_SUCCESS;
+}
diff --git a/src/drm/cairo-drm-i915-spans.c b/src/drm/cairo-drm-i915-spans.c
new file mode 100644
index 0000000..0f1617d
--- /dev/null
+++ b/src/drm/cairo-drm-i915-spans.c
@@ -0,0 +1,708 @@
+/* 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 Red Hat, Inc.
+ *
+ * Contributor(s):
+ * Chris Wilson <chris at chris-wilson.co.uk>
+ */
+
+#include "cairoint.h"
+
+#include "cairo-composite-rectangles-private.h"
+#include "cairo-boxes-private.h"
+#include "cairo-error-private.h"
+#include "cairo-drm-i915-private.h"
+
+/* Operates in either immediate or retained mode.
+ * When given a clip region we record the sequence of vbo and then
+ * replay them for each clip rectangle, otherwise we simply emit
+ * the vbo straight into the command stream.
+ */
+
+typedef struct _i915_spans i915_spans_t;
+
+typedef float *
+(*i915_get_rectangle_func_t) (i915_spans_t *spans);
+
+typedef void
+(*i915_span_func_t) (i915_spans_t *spans,
+ int x0, int x1, int y0, int y1,
+ int alpha);
+
+struct _i915_spans {
+ cairo_span_renderer_t renderer;
+
+ i915_device_t *device;
+
+ int xmin, xmax;
+ cairo_bool_t is_bounded;
+ const cairo_rectangle_int_t *extents;
+
+ i915_get_rectangle_func_t get_rectangle;
+ i915_span_func_t span;
+ i915_shader_t shader;
+
+ cairo_region_t *clip_region;
+ cairo_bool_t need_clip_surface;
+
+ struct vbo {
+ struct vbo *next;
+ intel_bo_t *bo;
+ unsigned int count;
+ } head, *tail;
+
+ int rectangle_size;
+
+ unsigned int vbo_offset;
+ float *vbo_base;
+};
+
+static float *
+i915_emit_rectangle (i915_spans_t *spans)
+{
+ return i915_add_rectangle (spans->device);
+}
+
+static float *
+i915_accumulate_rectangle (i915_spans_t *spans)
+{
+ float *vertices;
+ uint32_t size;
+
+ size = spans->rectangle_size;
+ if (unlikely (spans->vbo_offset + size > I915_VBO_SIZE)) {
+ struct vbo *vbo;
+
+ intel_bo_unmap (spans->tail->bo);
+
+ vbo = malloc (sizeof (struct vbo));
+ if (unlikely (vbo == NULL)) {
+ /* throw error! */
+ }
+
+ spans->tail->next = vbo;
+ spans->tail = vbo;
+
+ vbo->next = NULL;
+ vbo->bo = intel_bo_create (&spans->device->intel, I915_VBO_SIZE, FALSE);
+ vbo->count = 0;
+
+ spans->vbo_offset = 0;
+ spans->vbo_base = intel_bo_map (&spans->device->intel, vbo->bo);
+ }
+
+ vertices = spans->vbo_base + spans->vbo_offset;
+ spans->vbo_offset += size;
+ spans->tail->count += 3;
+
+ return vertices;
+}
+
+static void
+i915_span_constant (i915_spans_t *spans,
+ int x0, int x1, int y0, int y1,
+ int alpha)
+{
+ float *vertices;
+ float a = alpha / 255.;
+
+ vertices = spans->get_rectangle (spans);
+
+ *vertices++ = x1;
+ *vertices++ = y1;
+ *vertices++ = a;
+
+ *vertices++ = x0;
+ *vertices++ = y1;
+ *vertices++ = a;
+
+ *vertices++ = x0;
+ *vertices++ = y0;
+ *vertices++ = a;
+}
+
+static void
+i915_span_linear (i915_spans_t *spans,
+ int x0, int x1, int y0, int y1,
+ int alpha)
+{
+ float *vertices;
+ float a = alpha / 255.;
+ double s, t;
+
+ vertices = spans->get_rectangle (spans);
+
+ *vertices++ = x1;
+ *vertices++ = y1;
+ s = x0, t = y0;
+ *vertices++ = i915_shader_linear_texcoord (&spans->shader.source.linear, s, t);
+ *vertices++ = a;
+
+ *vertices++ = x0;
+ *vertices++ = y1;
+ s = x1, t = y0;
+ *vertices++ = i915_shader_linear_texcoord (&spans->shader.source.linear, s, t);
+ *vertices++ = a;
+
+ *vertices++ = x0;
+ *vertices++ = y0;
+ s = x1, t = y1;
+ *vertices++ = i915_shader_linear_texcoord (&spans->shader.source.linear, s, t);
+ *vertices++ = a;
+}
+
+static void
+i915_span_radial (i915_spans_t *spans,
+ int x0, int x1, int y0, int y1,
+ int alpha)
+{
+ float *vertices;
+ float a = alpha / 255.;
+ double s, t;
+
+ vertices = spans->get_rectangle (spans);
+
+ *vertices++ = x1;
+ *vertices++ = y1;
+ s = x0, t = y0;
+ cairo_matrix_transform_point (&spans->shader.source.base.matrix, &s, &t);
+ *vertices++ = s; *vertices++ = t;
+ *vertices++ = a;
+
+ *vertices++ = x0;
+ *vertices++ = y1;
+ s = x1, t = y0;
+ cairo_matrix_transform_point (&spans->shader.source.base.matrix, &s, &t);
+ *vertices++ = s; *vertices++ = t;
+ *vertices++ = a;
+
+ *vertices++ = x0;
+ *vertices++ = y0;
+ s = x1, t = y1;
+ cairo_matrix_transform_point (&spans->shader.source.base.matrix, &s, &t);
+ *vertices++ = s; *vertices++ = t;
+ *vertices++ = a;
+}
+
+static void
+i915_span_texture (i915_spans_t *spans,
+ int x0, int x1, int y0, int y1, int alpha)
+{
+ float *vertices;
+ float a = alpha / 255.;
+ double s, t;
+
+ vertices = spans->get_rectangle (spans);
+
+ *vertices++ = x1;
+ *vertices++ = y1;
+ s = x0, t = y0;
+ cairo_matrix_transform_point (&spans->shader.source.base.matrix, &s, &t);
+ *vertices++ = s; *vertices++ = t;
+ *vertices++ = a;
+
+ *vertices++ = x0;
+ *vertices++ = y1;
+ s = x1, t = y0;
+ cairo_matrix_transform_point (&spans->shader.source.base.matrix, &s, &t);
+ *vertices++ = s; *vertices++ = t;
+ *vertices++ = a;
+
+ *vertices++ = x0;
+ *vertices++ = y0;
+ s = x1, t = y1;
+ cairo_matrix_transform_point (&spans->shader.source.base.matrix, &s, &t);
+ *vertices++ = s; *vertices++ = t;
+ *vertices++ = a;
+}
+
+static void
+i915_span_texture16 (i915_spans_t *spans,
+ int x0, int x1, int y0, int y1, int alpha)
+{
+ float *vertices;
+ float a = alpha / 255.;
+ double s, t;
+
+ vertices = spans->get_rectangle (spans);
+
+ *vertices++ = x1;
+ *vertices++ = y1;
+ s = x0, t = y0;
+ cairo_matrix_transform_point (&spans->shader.source.base.matrix, &s, &t);
+ *vertices++ = texcoord_2d_16 (s, t);
+ *vertices++ = a;
+
+ *vertices++ = x0;
+ *vertices++ = y1;
+ s = x1, t = y0;
+ cairo_matrix_transform_point (&spans->shader.source.base.matrix, &s, &t);
+ *vertices++ = texcoord_2d_16 (s, t);
+ *vertices++ = a;
+
+ *vertices++ = x0;
+ *vertices++ = y0;
+ s = x1, t = y1;
+ cairo_matrix_transform_point (&spans->shader.source.base.matrix, &s, &t);
+ *vertices++ = texcoord_2d_16 (s, t);
+ *vertices++ = a;
+}
+
+static void
+i915_span_generic (i915_spans_t *spans,
+ int x0, int x1, int y0, int y1, int alpha)
+{
+ double s, t;
+ float *vertices;
+
+ /* Each vertex is:
+ * 2 vertex coordinates
+ * [0-2] source texture coordinates
+ * 1 alpha value.
+ * [0,2] clip mask coordinates
+ */
+
+ vertices = spans->get_rectangle (spans);
+
+ /* bottom right */
+ *vertices++ = x1; *vertices++ = y1;
+ s = x1, t = y1;
+ switch (spans->shader.source.type.vertex) {
+ case VS_CONSTANT:
+ break;
+ case VS_LINEAR:
+ *vertices++ = i915_shader_linear_texcoord (&spans->shader.source.linear, s, t);
+ break;
+ case VS_RADIAL:
+ case VS_TEXTURE:
+ cairo_matrix_transform_point (&spans->shader.source.base.matrix, &s, &t);
+ *vertices++ = s; *vertices++ = t;
+ break;
+ case VS_TEXTURE_16:
+ cairo_matrix_transform_point (&spans->shader.source.base.matrix, &s, &t);
+ *vertices++ = texcoord_2d_16 (s, t);
+ break;
+ }
+ *vertices++ = alpha;
+ if (spans->need_clip_surface) {
+ s = x1, t = y1;
+ cairo_matrix_transform_point (&spans->shader.source.base.matrix, &s, &t);
+ *vertices++ = s; *vertices++ = t;
+ }
+
+ /* bottom left */
+ *vertices++ = x0; *vertices++ = y1;
+ s = x0, t = y1;
+ switch (spans->shader.source.type.vertex) {
+ case VS_CONSTANT:
+ break;
+ case VS_LINEAR:
+ *vertices++ = i915_shader_linear_texcoord (&spans->shader.source.linear, s, t);
+ break;
+ case VS_RADIAL:
+ case VS_TEXTURE:
+ cairo_matrix_transform_point (&spans->shader.source.base.matrix, &s, &t);
+ *vertices++ = s; *vertices++ = t;
+ break;
+ case VS_TEXTURE_16:
+ cairo_matrix_transform_point (&spans->shader.source.base.matrix, &s, &t);
+ *vertices++ = texcoord_2d_16 (s, t);
+ break;
+ }
+ *vertices++ = alpha;
+ if (spans->need_clip_surface) {
+ s = x0, t = y1;
+ cairo_matrix_transform_point (&spans->shader.source.base.matrix, &s, &t);
+ *vertices++ = s; *vertices++ = t;
+ }
+
+ /* top left */
+ *vertices++ = x0; *vertices++ = y0;
+ s = x0, t = y0;
+ switch (spans->shader.source.type.vertex) {
+ case VS_CONSTANT:
+ break;
+ case VS_LINEAR:
+ *vertices++ = i915_shader_linear_texcoord (&spans->shader.source.linear, s, t);
+ break;
+ case VS_RADIAL:
+ case VS_TEXTURE:
+ cairo_matrix_transform_point (&spans->shader.source.base.matrix, &s, &t);
+ *vertices++ = s; *vertices++ = t;
+ break;
+ case VS_TEXTURE_16:
+ cairo_matrix_transform_point (&spans->shader.source.base.matrix, &s, &t);
+ *vertices++ = texcoord_2d_16 (s, t);
+ break;
+ }
+ *vertices++ = alpha;
+ if (spans->need_clip_surface) {
+ s = x0, t = y0;
+ cairo_matrix_transform_point (&spans->shader.source.base.matrix, &s, &t);
+ *vertices++ = s; *vertices++ = t;
+ }
+}
+
+static cairo_status_t
+i915_bounded_spans_mono (void *abstract_renderer,
+ int y, int height,
+ const cairo_half_open_span_t *half,
+ unsigned num_spans)
+{
+ i915_spans_t *spans = abstract_renderer;
+
+ if (num_spans == 0)
+ return CAIRO_STATUS_SUCCESS;
+
+ do {
+ if (half[0].coverage >= 128) {
+ spans->span (spans,
+ half[0].x, half[1].x,
+ y, y + height,
+ 255);
+ }
+ half++;
+ } while (--num_spans > 1);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+i915_bounded_spans (void *abstract_renderer,
+ int y, int height,
+ const cairo_half_open_span_t *half,
+ unsigned num_spans)
+{
+ i915_spans_t *spans = abstract_renderer;
+
+ if (num_spans == 0)
+ return CAIRO_STATUS_SUCCESS;
+
+ do {
+ if (half[0].coverage) {
+ spans->span (spans,
+ half[0].x, half[1].x,
+ y, y + height,
+ half[0].coverage);
+ }
+ half++;
+ } while (--num_spans > 1);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+i915_unbounded_spans (void *abstract_renderer,
+ int y, int height,
+ const cairo_half_open_span_t *half,
+ unsigned num_spans)
+{
+ i915_spans_t *spans = abstract_renderer;
+
+ if (num_spans == 0) {
+ spans->span (spans,
+ spans->xmin, spans->xmax,
+ y, y + height,
+ 0);
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+ if (half[0].x != spans->xmin) {
+ spans->span (spans,
+ spans->xmin, half[0].x,
+ y, y + height,
+ 0);
+ }
+
+ do {
+ spans->span (spans,
+ half[0].x, half[1].x,
+ y, y + height,
+ half[0].coverage);
+ half++;
+ } while (--num_spans > 1);
+
+ if (half[0].x != spans->xmax) {
+ spans->span (spans,
+ half[0].x, spans->xmax,
+ y, y + height,
+ 0);
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+i915_unbounded_spans_mono (void *abstract_renderer,
+ int y, int height,
+ const cairo_half_open_span_t *half,
+ unsigned num_spans)
+{
+ i915_spans_t *spans = abstract_renderer;
+
+ if (num_spans == 0) {
+ spans->span (spans,
+ spans->xmin, spans->xmax,
+ y, y + height,
+ 0);
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+ if (half[0].x != spans->xmin) {
+ spans->span (spans,
+ spans->xmin, half[0].x,
+ y, y + height,
+ 0);
+ }
+
+ do {
+ int alpha = 0;
+ if (half[0].coverage >= 128)
+ alpha = 255;
+ spans->span (spans,
+ half[0].x, half[1].x,
+ y, y + height,
+ alpha);
+ half++;
+ } while (--num_spans > 1);
+
+ if (half[0].x != spans->xmax) {
+ spans->span (spans,
+ half[0].x, spans->xmax,
+ y, y + height,
+ 0);
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+i915_spans_init (i915_spans_t *spans,
+ i915_surface_t *dst,
+ cairo_operator_t op,
+ const cairo_pattern_t *pattern,
+ cairo_antialias_t antialias,
+ cairo_clip_t *clip,
+ const cairo_composite_rectangles_t *extents)
+{
+ cairo_status_t status;
+
+ spans->device = (i915_device_t *) dst->intel.drm.base.device;
+
+ spans->is_bounded = extents->is_bounded;
+ if (extents->is_bounded) {
+ if (antialias == CAIRO_ANTIALIAS_NONE)
+ spans->renderer.render_rows = i915_bounded_spans_mono;
+ else
+ spans->renderer.render_rows = i915_bounded_spans;
+
+ spans->extents = &extents->bounded;
+ } else {
+ if (antialias == CAIRO_ANTIALIAS_NONE)
+ spans->renderer.render_rows = i915_unbounded_spans_mono;
+ else
+ spans->renderer.render_rows = i915_unbounded_spans;
+
+ spans->extents = &extents->unbounded;
+ }
+ spans->xmin = spans->extents->x;
+ spans->xmax = spans->extents->x + spans->extents->width;
+
+ spans->clip_region = NULL;
+ spans->need_clip_surface = FALSE;
+ if (clip != NULL) {
+ cairo_region_t *clip_region = NULL;
+
+ status = _cairo_clip_get_region (clip, &clip_region);
+ assert (status == CAIRO_STATUS_SUCCESS || status == CAIRO_INT_STATUS_UNSUPPORTED);
+
+ if (clip_region != NULL && cairo_region_num_rectangles (clip_region) == 1)
+ clip_region = NULL;
+
+ spans->clip_region = clip_region;
+ spans->need_clip_surface = status == CAIRO_INT_STATUS_UNSUPPORTED;
+ }
+
+ spans->head.next = NULL;
+ spans->head.bo = NULL;
+ spans->head.count = 0;
+ spans->tail = &spans->head;
+
+ if (spans->clip_region == NULL) {
+ spans->get_rectangle = i915_emit_rectangle;
+ } else {
+ assert (! extents->is_bounded);
+ spans->get_rectangle = i915_accumulate_rectangle;
+ spans->head.bo = intel_bo_create (&spans->device->intel,
+ I915_VBO_SIZE, FALSE);
+ if (unlikely (spans->head.bo == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+ spans->vbo_base = intel_bo_map (&spans->device->intel, spans->head.bo);
+ }
+ spans->vbo_offset = 0;
+
+ i915_shader_init (&spans->shader, dst, op);
+ if (spans->need_clip_surface)
+ i915_shader_set_clip (&spans->shader, clip);
+
+ status = i915_shader_acquire_pattern (&spans->shader, &spans->shader.source,
+ pattern, &extents->bounded);
+ if (unlikely (status))
+ return status;
+
+ if (! spans->need_clip_surface) {
+ switch (spans->shader.source.type.vertex) {
+ case VS_CONSTANT:
+ spans->span = i915_span_constant;
+ break;
+ case VS_LINEAR:
+ spans->span = i915_span_linear;
+ break;
+ case VS_RADIAL:
+ spans->span = i915_span_radial;
+ break;
+ case VS_TEXTURE:
+ spans->span = i915_span_texture;
+ break;
+ case VS_TEXTURE_16:
+ spans->span = i915_span_texture16;
+ break;
+ default:
+ spans->span = i915_span_generic;
+ break;
+ }
+ } else {
+ spans->span = i915_span_generic;
+ }
+
+ spans->rectangle_size = 3 * (2 + i915_shader_num_texcoords (&spans->shader));
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static void
+i915_spans_fini (i915_spans_t *spans)
+{
+ i915_shader_fini (&spans->shader);
+
+ if (spans->head.bo != NULL) {
+ struct vbo *vbo, *next;
+
+ intel_bo_destroy (&spans->device->intel, spans->head.bo);
+ for (vbo = spans->head.next; vbo != NULL; vbo = next) {
+ next = vbo->next;
+ intel_bo_destroy (&spans->device->intel, vbo->bo);
+ free (vbo);
+ }
+ }
+}
+
+cairo_status_t
+i915_clip_and_composite_spans (i915_surface_t *dst,
+ cairo_operator_t op,
+ const cairo_pattern_t *pattern,
+ cairo_antialias_t antialias,
+ i915_spans_func_t draw_func,
+ void *draw_closure,
+ const cairo_composite_rectangles_t*extents,
+ cairo_clip_t *clip)
+{
+ i915_spans_t spans;
+ i915_device_t *device;
+ cairo_status_t status;
+ struct vbo *vbo;
+
+ if (op == CAIRO_OPERATOR_CLEAR) {
+ pattern = &_cairo_pattern_white.base;
+ op = CAIRO_OPERATOR_DEST_OUT;
+ }
+
+ status = i915_spans_init (&spans, dst, op, pattern, antialias, clip, extents);
+ if (unlikely (status))
+ return status;
+
+ spans.shader.mask.base.texfmt = TEXCOORDFMT_1D;
+ spans.shader.mask.base.content = CAIRO_CONTENT_ALPHA;
+ spans.shader.mask.type.fragment = FS_SPANS;
+
+ status = cairo_device_acquire (dst->intel.drm.base.device);
+ if (unlikely (status))
+ goto CLEANUP_SPANS;
+
+ device = i915_device (dst);
+ status = i915_shader_commit (&spans.shader, device);
+ if (unlikely (status))
+ goto CLEANUP_DEVICE;
+
+ status = draw_func (draw_closure, &spans.renderer, spans.extents);
+ if (spans.clip_region != NULL && status == CAIRO_STATUS_SUCCESS) {
+ intel_bo_unmap (spans.tail->bo);
+
+ i915_vbo_finish (device);
+
+ OUT_DWORD (_3DSTATE_SCISSOR_ENABLE_CMD | ENABLE_SCISSOR_RECT);
+ for (vbo = &spans.head; vbo != NULL; vbo = vbo->next) {
+ int i, num_rectangles;
+
+ /* XXX require_space & batch_flush */
+
+ OUT_DWORD (_3DSTATE_LOAD_STATE_IMMEDIATE_1 | I1_LOAD_S (0) | I1_LOAD_S (1) | 1);
+ i915_batch_emit_reloc (device, vbo->bo, 0,
+ I915_GEM_DOMAIN_VERTEX, 0);
+ OUT_DWORD ((device->floats_per_vertex << S1_VERTEX_WIDTH_SHIFT) |
+ (device->floats_per_vertex << S1_VERTEX_PITCH_SHIFT) |
+ vbo->count);
+
+ num_rectangles = cairo_region_num_rectangles (spans.clip_region);
+ for (i = 0; i < num_rectangles; i++) {
+ cairo_rectangle_int_t rect;
+
+ cairo_region_get_rectangle (spans.clip_region, i, &rect);
+
+ OUT_DWORD (_3DSTATE_SCISSOR_RECT_0_CMD);
+ OUT_DWORD (SCISSOR_RECT_0_XMIN (rect.x) |
+ SCISSOR_RECT_0_YMIN (rect.y));
+ OUT_DWORD (SCISSOR_RECT_0_XMAX (rect.x + rect.width) |
+ SCISSOR_RECT_0_YMAX (rect.y + rect.height));
+
+ OUT_DWORD (PRIM3D_RECTLIST | PRIM3D_INDIRECT_SEQUENTIAL | vbo->count);
+ OUT_DWORD (0);
+ }
+ }
+ OUT_DWORD (_3DSTATE_SCISSOR_ENABLE_CMD | DISABLE_SCISSOR_RECT);
+ }
+
+CLEANUP_DEVICE:
+ cairo_device_release (dst->intel.drm.base.device);
+CLEANUP_SPANS:
+ i915_spans_fini (&spans);
+
+ return status;
+}
diff --git a/src/drm/cairo-drm-i915-surface.c b/src/drm/cairo-drm-i915-surface.c
new file mode 100644
index 0000000..2079ac9
--- /dev/null
+++ b/src/drm/cairo-drm-i915-surface.c
@@ -0,0 +1,1996 @@
+/* Cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2009 Chris Wilson
+ *
+ * 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.
+ *
+ * **************************************************************************
+ * This work was initially based upon xf86-video-intel/src/i915_render.c:
+ * Copyright © 2006 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Authors:
+ * Wang Zhenyu <zhenyu.z.wang at intel.com>
+ * Eric Anholt <eric at anholt.net>
+ *
+ * **************************************************************************
+ * and also upon libdrm/intel/intel_bufmgr_gem.c:
+ * Copyright © 2007 Red Hat Inc.
+ * Copyright © 2007 Intel Corporation
+ * Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND., USA
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * Authors: Thomas Hellström <thomas-at-tungstengraphics-dot-com>
+ * Keith Whitwell <keithw-at-tungstengraphics-dot-com>
+ * Eric Anholt <eric at anholt.net>
+ * Dave Airlie <airlied at linux.ie>
+ */
+
+/* XXX
+ *
+ * - Per thread context? Would it actually avoid many locks?
+ *
+ */
+
+#include "cairoint.h"
+
+#include "cairo-drm-private.h"
+#include "cairo-drm-ioctl-private.h"
+#include "cairo-drm-intel-private.h"
+#include "cairo-drm-intel-command-private.h"
+#include "cairo-drm-intel-ioctl-private.h"
+#include "cairo-drm-i915-private.h"
+
+#include "cairo-boxes-private.h"
+#include "cairo-cache-private.h"
+#include "cairo-composite-rectangles-private.h"
+#include "cairo-error-private.h"
+#include "cairo-freelist-private.h"
+#include "cairo-list-private.h"
+#include "cairo-path-fixed-private.h"
+#include "cairo-region-private.h"
+#include "cairo-surface-offset-private.h"
+
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <errno.h>
+
+static cairo_int_status_t
+i915_surface_fill (void *abstract_dst,
+ cairo_operator_t op,
+ const cairo_pattern_t*source,
+ cairo_path_fixed_t *path,
+ cairo_fill_rule_t fill_rule,
+ double tolerance,
+ cairo_antialias_t antialias,
+ cairo_clip_t *clip);
+
+static const uint32_t i915_batch_setup[] = {
+ /* Disable line anti-aliasing */
+ _3DSTATE_AA_CMD,
+
+ /* Disable independent alpha blend */
+ _3DSTATE_INDEPENDENT_ALPHA_BLEND_CMD |
+ IAB_MODIFY_ENABLE |
+ IAB_MODIFY_FUNC | (BLENDFUNC_ADD << IAB_FUNC_SHIFT) |
+ IAB_MODIFY_SRC_FACTOR | (BLENDFACT_ONE << IAB_SRC_FACTOR_SHIFT) |
+ IAB_MODIFY_DST_FACTOR | (BLENDFACT_ZERO << IAB_DST_FACTOR_SHIFT),
+
+ /* Disable texture crossbar */
+ _3DSTATE_COORD_SET_BINDINGS |
+ CSB_TCB (0, 0) |
+ CSB_TCB (1, 1) |
+ CSB_TCB (2, 2) |
+ CSB_TCB (3, 3) |
+ CSB_TCB (4, 4) |
+ CSB_TCB (5, 5) |
+ CSB_TCB (6, 6) |
+ CSB_TCB (7, 7),
+
+ _3DSTATE_RASTER_RULES_CMD |
+ ENABLE_POINT_RASTER_RULE | OGL_POINT_RASTER_RULE |
+ ENABLE_LINE_STRIP_PROVOKE_VRTX | LINE_STRIP_PROVOKE_VRTX (1) |
+ ENABLE_TRI_FAN_PROVOKE_VRTX | TRI_FAN_PROVOKE_VRTX (2) |
+ ENABLE_TEXKILL_3D_4D | TEXKILL_4D,
+
+ _3DSTATE_MODES_4_CMD | ENABLE_LOGIC_OP_FUNC | LOGIC_OP_FUNC (LOGICOP_COPY),
+
+ _3DSTATE_LOAD_STATE_IMMEDIATE_1 |
+ I1_LOAD_S (2) |
+ I1_LOAD_S (3) |
+ I1_LOAD_S (4) |
+ I1_LOAD_S (5) |
+ I1_LOAD_S (6) |
+ 4,
+ S2_TEXCOORD_NONE,
+ 0, /* Disable texture coordinate wrap-shortest */
+ (1 << S4_POINT_WIDTH_SHIFT) |
+ S4_LINE_WIDTH_ONE |
+ S4_FLATSHADE_ALPHA |
+ S4_FLATSHADE_FOG |
+ S4_FLATSHADE_SPECULAR |
+ S4_FLATSHADE_COLOR |
+ S4_CULLMODE_NONE |
+ S4_VFMT_XY,
+ 0, /* Disable stencil buffer */
+ S6_COLOR_WRITE_ENABLE,
+
+ _3DSTATE_SCISSOR_ENABLE_CMD | DISABLE_SCISSOR_RECT,
+ _3DSTATE_DEPTH_SUBRECT_DISABLE,
+
+ /* disable indirect state */
+ _3DSTATE_LOAD_INDIRECT,
+ 0,
+
+ _3DSTATE_STIPPLE,
+ 0,
+
+ _3DSTATE_BACKFACE_STENCIL_OPS | BFO_ENABLE_STENCIL_TWO_SIDE,
+};
+
+static const cairo_surface_backend_t i915_surface_backend;
+
+#define NEAREST_BIAS (-.375)
+
+static cairo_surface_t *
+i915_surface_create_from_cacheable_image (cairo_drm_device_t *base_dev,
+ cairo_surface_t *source);
+
+static cairo_status_t
+i915_bo_exec (i915_device_t *device, intel_bo_t *bo, uint32_t offset)
+{
+ struct drm_i915_gem_execbuffer2 execbuf;
+ int ret, cnt, i;
+
+ /* Add the batch buffer to the validation list. */
+ cnt = device->batch.exec_count;
+ if (cnt > 0 && bo->base.handle == device->batch.exec[cnt-1].handle)
+ i = cnt - 1;
+ else
+ i = device->batch.exec_count++;
+ device->batch.exec[i].handle = bo->base.handle;
+ device->batch.exec[i].relocation_count = device->batch.reloc_count;
+ device->batch.exec[i].relocs_ptr = (uintptr_t) device->batch.reloc;
+ device->batch.exec[i].alignment = 0;
+ device->batch.exec[i].offset = 0;
+ device->batch.exec[i].flags = 0;
+ device->batch.exec[i].rsvd1 = 0;
+ device->batch.exec[i].rsvd2 = 0;
+
+ execbuf.buffers_ptr = (uintptr_t) device->batch.exec;
+ execbuf.buffer_count = device->batch.exec_count;
+ execbuf.batch_start_offset = offset;
+ execbuf.batch_len = (device->batch.used << 2) + sizeof (device->batch_header);
+ execbuf.DR1 = 0;
+ execbuf.DR4 = 0;
+ execbuf.num_cliprects = 0;
+ execbuf.cliprects_ptr = 0;
+ execbuf.flags = 0;
+ execbuf.rsvd1 = 0;
+ execbuf.rsvd2 = 0;
+
+ if (I915_VERBOSE && device->debug & I915_DEBUG_EXEC) {
+ int n;
+ fprintf (stderr,
+ "Executing batch: %d+%d bytes, %d buffers, %d relocations\n",
+ execbuf.batch_start_offset,
+ execbuf.batch_len,
+ device->batch.exec_count,
+ device->batch.reloc_count);
+ for (n = 0; n < device->batch.exec_count; n++) {
+ fprintf (stderr, " exec[%d] = %d\n", n,
+ device->batch.exec[n].handle);
+ }
+ for (n = 0; n < device->batch.reloc_count; n++) {
+ fprintf (stderr, " reloc[%d] = %d @ %qx\n", n,
+ device->batch.reloc[n].target_handle,
+ (unsigned long long) device->batch.reloc[n].offset);
+ }
+ }
+
+ do {
+ ret = ioctl (device->intel.base.fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, &execbuf);
+ } while (ret != 0 && errno == EINTR);
+
+ if (I915_VERBOSE && ret) {
+ int n;
+
+ fprintf (stderr, "Batch submission failed: %d\n", errno);
+ fprintf (stderr, " relocation entries: %d/%d\n",
+ device->batch.reloc_count, I915_MAX_RELOCS);
+ fprintf (stderr, " gtt size: %zd/%zd\n",
+ device->batch.gtt_size, device->intel.gtt_avail_size);
+
+ fprintf (stderr, " buffers:\n");
+ for (n = 0; n < cnt; n++) {
+ fprintf (stderr, " exec[%d] = %d\n",
+ n, device->batch.target_bo[n]->base.size);
+ }
+
+ intel_dump_batchbuffer (device->batch_header,
+ device->batch.used,
+ device->intel.base.chip_id);
+ }
+
+ VG (VALGRIND_MAKE_MEM_DEFINED (device->batch.exec, sizeof (device->batch.exec[0]) * i));
+
+ bo->offset = device->batch.exec[i].offset;
+ while (cnt--) {
+ device->batch.target_bo[cnt]->offset = device->batch.exec[cnt].offset;
+ device->batch.target_bo[cnt]->exec = NULL;
+ device->batch.target_bo[cnt]->batch_read_domains = 0;
+ device->batch.target_bo[cnt]->batch_write_domain = 0;
+ intel_bo_destroy (&device->intel, device->batch.target_bo[cnt]);
+ }
+
+ device->batch.exec_count = 0;
+ device->batch.reloc_count = 0;
+
+ device->batch.gtt_size = I915_BATCH_SIZE;
+
+ return ret == 0 ? CAIRO_STATUS_SUCCESS : _cairo_error (CAIRO_STATUS_NO_MEMORY);
+}
+
+void
+i915_batch_add_reloc (i915_device_t *device,
+ uint32_t pos,
+ intel_bo_t *bo,
+ uint32_t offset,
+ uint32_t read_domains,
+ uint32_t write_domain)
+{
+ int index;
+
+ if (bo->exec == NULL) {
+ device->batch.gtt_size += bo->base.size;
+
+ index = device->batch.exec_count++;
+ device->batch.exec[index].handle = bo->base.handle;
+ device->batch.exec[index].relocation_count = 0;
+ device->batch.exec[index].relocs_ptr = 0;
+ device->batch.exec[index].alignment = 0;
+ device->batch.exec[index].offset = 0;
+ device->batch.exec[index].flags = 0;
+ device->batch.exec[index].rsvd1 = 0;
+ device->batch.exec[index].rsvd2 = 0;
+
+ device->batch.target_bo[index] = intel_bo_reference (bo);
+
+ bo->exec = &device->batch.exec[index];
+ }
+
+ index = device->batch.reloc_count++;
+ device->batch.reloc[index].offset = (pos << 2) + sizeof (device->batch_header);
+ device->batch.reloc[index].delta = offset;
+ device->batch.reloc[index].target_handle = bo->base.handle;
+ device->batch.reloc[index].read_domains = read_domains;
+ device->batch.reloc[index].write_domain = write_domain;
+ device->batch.reloc[index].presumed_offset = bo->offset;
+
+ assert (write_domain == 0 || bo->batch_write_domain == 0 || bo->batch_write_domain == write_domain);
+ bo->batch_read_domains |= read_domains;
+ bo->batch_write_domain |= write_domain;
+}
+
+void
+i915_vbo_finish (i915_device_t *device)
+{
+ if (device->vbo_used == 0)
+ return;
+
+ if (device->vbo || i915_batch_space (device) < (int32_t) device->vbo_used) {
+ intel_bo_t *vbo;
+
+ if (device->vertex_count) {
+ if (device->vbo == 0) {
+ /* XXX unchecked, must fit! */
+ /* XXX batch_flush and i915_shader_commit (device, device->shader)); */
+ assert (i915_check_aperture_size (device, 1,
+ (device->vbo_used + 4095) & -4096));
+ OUT_DWORD (_3DSTATE_LOAD_STATE_IMMEDIATE_1 |
+ I1_LOAD_S (0) |
+ I1_LOAD_S (1) |
+ 1);
+ device->vbo = device->batch.used++;
+ device->vbo_max_index = device->batch.used;
+ OUT_DWORD ((device->floats_per_vertex << S1_VERTEX_WIDTH_SHIFT) |
+ (device->floats_per_vertex << S1_VERTEX_PITCH_SHIFT));
+ }
+
+ OUT_DWORD (PRIM3D_RECTLIST |
+ PRIM3D_INDIRECT_SEQUENTIAL |
+ device->vertex_count);
+ OUT_DWORD (device->vertex_index);
+ }
+
+ if (I915_VERBOSE && device->debug & I915_DEBUG_BUFFER) {
+ fprintf (stderr, "Creating vertex buffer: %d bytes\n",
+ device->vbo_used);
+ }
+
+ if (device->last_vbo != NULL)
+ intel_bo_destroy (&device->intel, device->last_vbo);
+
+ device->batch_base[device->vbo_max_index] |= device->vertex_index + device->vertex_count;
+
+ /* will include a few bytes of inter-array padding */
+ vbo = intel_bo_create (&device->intel, device->vbo_used, FALSE);
+ i915_batch_fill_reloc (device, device->vbo,
+ vbo, 0,
+ I915_GEM_DOMAIN_VERTEX, 0);
+ intel_bo_write (&device->intel, vbo, 0, device->vbo_used, device->vbo_base);
+ device->last_vbo = vbo;
+ device->last_vbo_offset = (device->vbo_used+7)&-8;
+ device->last_vbo_space = vbo->base.size - device->last_vbo_offset;
+
+ device->vbo = 0;
+ }
+ else
+ {
+ /* Only a single rectlist in this batch, and no active vertex buffer. */
+ OUT_DWORD (PRIM3D_RECTLIST | (device->vbo_used / 4 - 1));
+
+ memcpy (BATCH_PTR (device), device->vbo_base, device->vbo_used);
+ device->batch.used += device->vbo_used >> 2;
+ }
+
+ device->vbo_used = device->vbo_offset = 0;
+ device->vertex_index = device->vertex_count = 0;
+}
+
+/* XXX improve state tracker/difference and flush state on vertex emission */
+static void
+i915_device_reset (i915_device_t *device)
+{
+ if (device->current_source != NULL)
+ *device->current_source = 0;
+ if (device->current_mask != NULL)
+ *device->current_mask = 0;
+ if (device->current_clip != NULL)
+ *device->current_clip = 0;
+
+ device->current_target = NULL;
+ device->current_size = 0;
+ device->current_source = NULL;
+ device->current_mask = NULL;
+ device->current_clip = NULL;
+ device->current_shader = 0;
+ device->current_texcoords = ~0;
+ device->current_blend = 0;
+ device->current_n_constants = 0;
+ device->current_n_samplers = 0;
+ device->current_colorbuf = 0;
+ device->current_diffuse = 0;
+ device->current_program = ~0;
+
+ device->last_source_fragment = ~0;
+
+ device->floats_per_vertex = 0;
+}
+
+static void
+i915_batch_cleanup (i915_device_t *device)
+{
+ int i;
+
+ for (i = 0; i < device->batch.exec_count; i++)
+ intel_bo_destroy (&device->intel, device->batch.target_bo[i]);
+
+ device->batch.exec_count = 0;
+ device->batch.reloc_count = 0;
+}
+
+cairo_status_t
+i915_batch_flush (i915_device_t *device)
+{
+ intel_bo_t *batch;
+ cairo_status_t status;
+ uint32_t length, offset;
+ int n;
+
+ i915_vbo_finish (device);
+
+ if (device->batch.used == 0)
+ return CAIRO_STATUS_SUCCESS;
+
+ i915_batch_emit_dword (device, MI_BATCH_BUFFER_END);
+ if ((device->batch.used & 1) != (sizeof (device->batch_header) & 4))
+ i915_batch_emit_dword (device, MI_NOOP);
+
+ length = (device->batch.used << 2) + sizeof (device->batch_header);
+
+ if (I915_VERBOSE && device->debug & I915_DEBUG_BATCH)
+ intel_dump_batchbuffer (device->batch_header, length, device->intel.base.chip_id);
+
+ intel_glyph_cache_unmap(&device->intel);
+
+ /* NB: it is faster to copy the data then map/unmap the batch,
+ * presumably because we frequently only use a small part of the buffer.
+ */
+ batch = NULL;
+ if (device->last_vbo) {
+ if (length <= device->last_vbo_space) {
+ if (I915_VERBOSE && device->debug & I915_DEBUG_BATCH) {
+ fprintf (stderr, "Packing batch buffer into last vbo: %d+%d bytes\n", length, device->last_vbo_offset);
+ }
+ batch = device->last_vbo;
+ offset = device->last_vbo_offset;
+
+ /* fixup the relocations */
+ for (n = 0; n < device->batch.reloc_count; n++)
+ device->batch.reloc[n].offset += offset;
+ } else
+ intel_bo_destroy (&device->intel, device->last_vbo);
+ device->last_vbo = NULL;
+ }
+ if (batch == NULL) {
+ if (I915_VERBOSE && device->debug & I915_DEBUG_BUFFER) {
+ fprintf (stderr, "Creating batch buffer: %d bytes\n", length);
+ }
+ batch = intel_bo_create (&device->intel, length, FALSE);
+ if (unlikely (batch == NULL)) {
+ status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ i915_batch_cleanup (device);
+ goto BAIL;
+ }
+
+ offset = 0;
+ }
+ intel_bo_write (&device->intel, batch, offset, length, device->batch_header);
+ status = i915_bo_exec (device, batch, offset);
+
+ if (device->debug & I915_DEBUG_SYNC && status == CAIRO_STATUS_SUCCESS)
+ intel_bo_wait (&device->intel, batch);
+
+ intel_bo_destroy (&device->intel, batch);
+
+BAIL:
+ device->batch.used = 0;
+
+ intel_glyph_cache_unpin (&device->intel);
+ intel_snapshot_cache_thaw (&device->intel);
+
+ i915_device_reset (device);
+
+ return status;
+}
+
+cairo_status_t
+i915_vbo_flush (i915_device_t *device)
+{
+ assert (device->vertex_count);
+
+ if (device->vbo == 0) {
+ assert (device->floats_per_vertex);
+
+ if (i915_batch_space (device) < 9 ||
+ ! i915_check_aperture_size (device, 1, I915_VBO_SIZE))
+ {
+ return i915_batch_flush (device);
+ }
+
+ OUT_DWORD (_3DSTATE_LOAD_STATE_IMMEDIATE_1 |
+ I1_LOAD_S (0) |
+ I1_LOAD_S (1) |
+ 1);
+ device->vbo = device->batch.used++;
+ device->vbo_max_index = device->batch.used;
+ OUT_DWORD ((device->floats_per_vertex << S1_VERTEX_WIDTH_SHIFT) |
+ (device->floats_per_vertex << S1_VERTEX_PITCH_SHIFT));
+ }
+
+ OUT_DWORD (PRIM3D_RECTLIST |
+ PRIM3D_INDIRECT_SEQUENTIAL |
+ device->vertex_count);
+ OUT_DWORD (device->vertex_index);
+
+ device->vertex_index += device->vertex_count;
+ device->vertex_count = 0;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+#if 0
+static float *
+i915_add_rectangles (i915_device_t *device, int num_rects, int *count)
+{
+ float *vertices;
+ uint32_t size;
+ int cnt;
+
+ assert (device->floats_per_vertex);
+
+ size = device->rectangle_size;
+ if (unlikely (device->vbo_offset + size > I915_VBO_SIZE))
+ i915_vbo_finish (device);
+
+ vertices = (float *) (device->vbo_base + device->vbo_offset);
+ cnt = (I915_VBO_SIZE - device->vbo_offset) / size;
+ if (cnt > num_rects)
+ cnt = num_rects;
+ device->vbo_used = device->vbo_offset += size * cnt;
+ device->vertex_count += 3 * cnt;
+ *count = cnt;
+ return vertices;
+}
+#endif
+
+static cairo_status_t
+i915_surface_finish (void *abstract_surface)
+{
+ i915_surface_t *surface = abstract_surface;
+ i915_device_t *device = i915_device (surface);
+
+ if (surface->stencil != NULL)
+ intel_bo_destroy (&device->intel, surface->stencil);
+
+ if (surface->is_current_texture) {
+ if (surface->is_current_texture & CURRENT_SOURCE)
+ device->current_source = NULL;
+ if (surface->is_current_texture & CURRENT_MASK)
+ device->current_mask = NULL;
+ if (surface->is_current_texture & CURRENT_CLIP)
+ device->current_clip = NULL;
+ device->current_n_samplers = 0;
+ }
+
+ if (surface == device->current_target)
+ device->current_target = NULL;
+
+ if (surface->cache != NULL) {
+ i915_image_private_t *node = surface->cache;
+ intel_buffer_cache_t *cache = node->container;
+
+ if (--cache->ref_count == 0) {
+ intel_bo_destroy (&device->intel, cache->buffer.bo);
+ _cairo_rtree_fini (&cache->rtree);
+ cairo_list_del (&cache->link);
+ free (cache);
+ } else {
+ node->node.state = CAIRO_RTREE_NODE_AVAILABLE;
+ cairo_list_move (&node->node.link, &cache->rtree.available);
+ _cairo_rtree_node_collapse (&cache->rtree, node->node.parent);
+ }
+ }
+
+ return _cairo_drm_surface_finish (&surface->intel.drm);
+}
+
+static cairo_status_t
+i915_surface_batch_flush (i915_surface_t *surface)
+{
+ cairo_status_t status;
+ intel_bo_t *bo;
+
+ assert (surface->intel.drm.fallback == NULL);
+
+ bo = to_intel_bo (surface->intel.drm.bo);
+ if (bo == NULL || bo->batch_write_domain == 0)
+ return CAIRO_STATUS_SUCCESS;
+
+ status = cairo_device_acquire (surface->intel.drm.base.device);
+ if (unlikely (status))
+ return status;
+
+ status = i915_batch_flush (i915_device (surface));
+ cairo_device_release (surface->intel.drm.base.device);
+
+ return status;
+}
+
+static cairo_status_t
+i915_surface_flush (void *abstract_surface)
+{
+ i915_surface_t *surface = abstract_surface;
+
+ if (surface->intel.drm.fallback == NULL) {
+ if (surface->intel.drm.base.finished) {
+ /* Forgo flushing on finish as the user cannot access the surface directly. */
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+ return i915_surface_batch_flush (surface);
+ }
+
+ return intel_surface_flush (abstract_surface);
+}
+
+/* rasterisation */
+
+static cairo_status_t
+_composite_boxes_spans (void *closure,
+ cairo_span_renderer_t *renderer,
+ const cairo_rectangle_int_t *extents)
+{
+ cairo_boxes_t *boxes = closure;
+ cairo_rectangular_scan_converter_t converter;
+ struct _cairo_boxes_chunk *chunk;
+ cairo_status_t status;
+ int i;
+
+ _cairo_rectangular_scan_converter_init (&converter, extents);
+ for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
+ cairo_box_t *box = chunk->base;
+ for (i = 0; i < chunk->count; i++) {
+ status = _cairo_rectangular_scan_converter_add_box (&converter, &box[i], 1);
+ if (unlikely (status))
+ goto CLEANUP;
+ }
+ }
+
+ status = converter.base.generate (&converter.base, renderer);
+
+ CLEANUP:
+ converter.base.destroy (&converter.base);
+ return status;
+}
+
+cairo_status_t
+i915_fixup_unbounded (i915_surface_t *dst,
+ const cairo_composite_rectangles_t *extents,
+ cairo_clip_t *clip)
+{
+ i915_shader_t shader;
+ cairo_status_t status;
+
+ i915_shader_init (&shader, dst, CAIRO_OPERATOR_CLEAR);
+
+ if (clip != NULL) {
+ cairo_region_t *clip_region = NULL;
+
+ status = _cairo_clip_get_region (clip, &clip_region);
+ assert (status == CAIRO_STATUS_SUCCESS || CAIRO_INT_STATUS_UNSUPPORTED);
+ assert (clip_region == NULL);
+
+ if (status == CAIRO_INT_STATUS_UNSUPPORTED)
+ i915_shader_set_clip (&shader, clip);
+ } else {
+ if (extents->bounded.width == extents->unbounded.width &&
+ extents->bounded.height == extents->unbounded.height)
+ {
+ return CAIRO_STATUS_SUCCESS;
+ }
+ }
+
+ status = i915_shader_commit (&shader,
+ (i915_device_t *) dst->intel.drm.base.device);
+ if (unlikely (status))
+ return status;
+
+ /* top */
+ if (extents->bounded.y != extents->unbounded.y) {
+ shader.add_rectangle (&shader,
+ extents->unbounded.x,
+ extents->unbounded.y,
+ extents->unbounded.width,
+ extents->bounded.y - extents->unbounded.y);
+ }
+
+ /* left */
+ if (extents->bounded.x != extents->unbounded.x) {
+ shader.add_rectangle (&shader,
+ extents->unbounded.x,
+ extents->bounded.y,
+ extents->bounded.x - extents->unbounded.x,
+ extents->bounded.height);
+ }
+
+ /* right */
+ if (extents->bounded.x + extents->bounded.width != extents->unbounded.x + extents->unbounded.width) {
+ shader.add_rectangle (&shader,
+ extents->bounded.x + extents->bounded.width,
+ extents->bounded.y,
+ extents->unbounded.x + extents->unbounded.width - (extents->bounded.x + extents->bounded.width),
+ extents->bounded.height);
+ }
+
+ /* bottom */
+ if (extents->bounded.y + extents->bounded.height != extents->unbounded.y + extents->unbounded.height) {
+ shader.add_rectangle (&shader,
+ extents->unbounded.x,
+ extents->bounded.y + extents->bounded.height,
+ extents->unbounded.width,
+ extents->unbounded.y + extents->unbounded.height - (extents->bounded.y + extents->bounded.height));
+ }
+
+ i915_shader_fini (&shader);
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+i915_fixup_unbounded_boxes (i915_surface_t *dst,
+ const cairo_composite_rectangles_t *extents,
+ cairo_clip_t *clip,
+ cairo_boxes_t *boxes)
+{
+ cairo_boxes_t clear;
+ cairo_box_t box;
+ cairo_region_t *clip_region = NULL;
+ cairo_status_t status;
+ struct _cairo_boxes_chunk *chunk;
+ i915_shader_t shader;
+ int i;
+
+ if (boxes->num_boxes <= 1)
+ return i915_fixup_unbounded (dst, extents, clip);
+
+ i915_shader_init (&shader, dst, CAIRO_OPERATOR_CLEAR);
+ _cairo_boxes_init (&clear);
+
+ box.p1.x = _cairo_fixed_from_int (extents->unbounded.x + extents->unbounded.width);
+ box.p1.y = _cairo_fixed_from_int (extents->unbounded.y);
+ box.p2.x = _cairo_fixed_from_int (extents->unbounded.x);
+ box.p2.y = _cairo_fixed_from_int (extents->unbounded.y + extents->unbounded.height);
+
+ if (clip != NULL) {
+ status = _cairo_clip_get_region (clip, &clip_region);
+ assert (status == CAIRO_STATUS_SUCCESS || CAIRO_INT_STATUS_UNSUPPORTED);
+ if (status == CAIRO_INT_STATUS_UNSUPPORTED)
+ i915_shader_set_clip (&shader, clip);
+ }
+
+ if (clip_region == NULL) {
+ cairo_boxes_t tmp;
+
+ _cairo_boxes_init (&tmp);
+
+ status = _cairo_boxes_add (&tmp, &box);
+ assert (status == CAIRO_STATUS_SUCCESS);
+
+ tmp.chunks.next = &boxes->chunks;
+ tmp.num_boxes += boxes->num_boxes;
+
+ status = _cairo_bentley_ottmann_tessellate_boxes (&tmp,
+ CAIRO_FILL_RULE_WINDING,
+ &clear);
+
+ tmp.chunks.next = NULL;
+ } else {
+ pixman_box32_t *pbox;
+
+ pbox = pixman_region32_rectangles (&clip_region->rgn, &i);
+ _cairo_boxes_limit (&clear, (cairo_box_t *) pbox, i);
+
+ status = _cairo_boxes_add (&clear, &box);
+ assert (status == CAIRO_STATUS_SUCCESS);
+
+ for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
+ for (i = 0; i < chunk->count; i++) {
+ status = _cairo_boxes_add (&clear, &chunk->base[i]);
+ if (unlikely (status)) {
+ _cairo_boxes_fini (&clear);
+ return status;
+ }
+ }
+ }
+
+ status = _cairo_bentley_ottmann_tessellate_boxes (&clear,
+ CAIRO_FILL_RULE_WINDING,
+ &clear);
+ }
+
+ if (likely (status == CAIRO_STATUS_SUCCESS && clear.num_boxes)) {
+ status = i915_shader_commit (&shader,
+ (i915_device_t *) dst->intel.drm.base.device);
+ if (likely (status == CAIRO_STATUS_SUCCESS)) {
+ for (chunk = &clear.chunks; chunk != NULL; chunk = chunk->next) {
+ for (i = 0; i < chunk->count; i++) {
+ int x1 = _cairo_fixed_integer_part (chunk->base[i].p1.x);
+ int y1 = _cairo_fixed_integer_part (chunk->base[i].p1.y);
+ int x2 = _cairo_fixed_integer_part (chunk->base[i].p2.x);
+ int y2 = _cairo_fixed_integer_part (chunk->base[i].p2.y);
+
+ shader.add_rectangle (&shader, x1, y1, x2 - x1, y2 - y1);
+ }
+ }
+ }
+ i915_shader_fini (&shader);
+ }
+
+ _cairo_boxes_fini (&clear);
+
+ return status;
+}
+
+static cairo_status_t
+_composite_boxes (i915_surface_t *dst,
+ cairo_operator_t op,
+ const cairo_pattern_t *pattern,
+ cairo_boxes_t *boxes,
+ cairo_antialias_t antialias,
+ cairo_clip_t *clip,
+ const cairo_composite_rectangles_t *extents)
+{
+ cairo_bool_t need_clip_surface = FALSE;
+ cairo_region_t *clip_region = NULL;
+ const struct _cairo_boxes_chunk *chunk;
+ cairo_status_t status;
+ i915_shader_t shader;
+ int i;
+
+ /* If the boxes are not pixel-aligned, we will need to compute a real mask */
+ if (antialias != CAIRO_ANTIALIAS_NONE) {
+ if (! boxes->is_pixel_aligned)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ }
+
+ i915_shader_init (&shader, dst, op);
+
+ status = i915_shader_acquire_pattern (&shader,
+ &shader.source,
+ pattern,
+ &extents->bounded);
+ if (unlikely (status))
+ return status;
+
+ if (clip != NULL) {
+ status = _cairo_clip_get_region (clip, &clip_region);
+ assert (status == CAIRO_STATUS_SUCCESS || CAIRO_INT_STATUS_UNSUPPORTED);
+ need_clip_surface = status == CAIRO_INT_STATUS_UNSUPPORTED;
+ if (need_clip_surface)
+ i915_shader_set_clip (&shader, clip);
+ }
+
+ status = i915_shader_commit (&shader,
+ (i915_device_t *) dst->intel.drm.base.device);
+ if (likely (status == CAIRO_STATUS_SUCCESS)) {
+ for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
+ cairo_box_t *box = chunk->base;
+ for (i = 0; i < chunk->count; i++) {
+ int x1 = _cairo_fixed_integer_round (box[i].p1.x);
+ int y1 = _cairo_fixed_integer_round (box[i].p1.y);
+ int x2 = _cairo_fixed_integer_round (box[i].p2.x);
+ int y2 = _cairo_fixed_integer_round (box[i].p2.y);
+
+ if (x2 > x1 && y2 > y1)
+ shader.add_rectangle (&shader, x1, y1, x2 - x1, y2 - y1);
+ }
+ }
+
+ if (! extents->is_bounded)
+ status = i915_fixup_unbounded_boxes (dst, extents, clip, boxes);
+ }
+ i915_shader_fini (&shader);
+
+ return status;
+}
+
+static cairo_status_t
+_clip_and_composite_boxes (i915_surface_t *dst,
+ cairo_operator_t op,
+ const cairo_pattern_t *src,
+ cairo_boxes_t *boxes,
+ cairo_antialias_t antialias,
+ const cairo_composite_rectangles_t *extents,
+ cairo_clip_t *clip)
+{
+ cairo_status_t status;
+
+ if (boxes->num_boxes == 0) {
+ if (extents->is_bounded)
+ return CAIRO_STATUS_SUCCESS;
+
+ return i915_fixup_unbounded (dst, extents, clip);
+ }
+
+ /* Use a fast path if the boxes are pixel aligned */
+ status = _composite_boxes (dst, op, src, boxes, antialias, clip, extents);
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+ return status;
+
+ /* Otherwise render the boxes via an implicit mask and composite in the usual
+ * fashion.
+ */
+ return i915_clip_and_composite_spans (dst, op, src, antialias,
+ _composite_boxes_spans, boxes,
+ extents, clip);
+}
+
+static cairo_bool_t
+box_is_aligned (const cairo_box_t *box)
+{
+ return
+ _cairo_fixed_is_integer (box->p1.x) &&
+ _cairo_fixed_is_integer (box->p1.y) &&
+ _cairo_fixed_is_integer (box->p2.x) &&
+ _cairo_fixed_is_integer (box->p2.y);
+}
+
+static inline cairo_status_t
+_clip_to_boxes (cairo_clip_t **clip,
+ const cairo_composite_rectangles_t *extents,
+ cairo_box_t **boxes,
+ int *num_boxes)
+{
+ cairo_status_t status;
+ const cairo_rectangle_int_t *rect;
+
+ rect = extents->is_bounded ? &extents->bounded: &extents->unbounded;
+
+ if (*clip == NULL)
+ goto EXTENTS;
+
+ status = _cairo_clip_rectangle (*clip, rect);
+ if (unlikely (status))
+ return status;
+
+ status = _cairo_clip_get_boxes (*clip, boxes, num_boxes);
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED) {
+ if (extents->is_bounded || (*num_boxes == 1 && box_is_aligned (*boxes)))
+ *clip = NULL;
+ return status;
+ }
+
+ EXTENTS:
+ _cairo_box_from_rectangle (&(*boxes)[0], rect);
+ *num_boxes = 1;
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_clip_path_t *
+_clip_get_solitary_path (cairo_clip_t *clip)
+{
+ cairo_clip_path_t *iter = clip->path;
+ cairo_clip_path_t *path = NULL;
+
+ do {
+ if ((iter->flags & CAIRO_CLIP_PATH_IS_BOX) == 0) {
+ if (path != NULL)
+ return FALSE;
+
+ path = iter;
+ }
+ iter = iter->prev;
+ } while (iter != NULL);
+
+ return path;
+}
+
+static cairo_int_status_t
+i915_surface_paint (void *abstract_dst,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_clip_t *clip)
+{
+ i915_surface_t *dst = abstract_dst;
+ cairo_composite_rectangles_t extents;
+ cairo_clip_t local_clip;
+ cairo_bool_t have_clip = FALSE;
+ cairo_clip_path_t *clip_path;
+ cairo_boxes_t boxes;
+ int num_boxes = ARRAY_LENGTH (boxes.boxes_embedded);
+ cairo_box_t *clip_boxes = boxes.boxes_embedded;
+ cairo_status_t status;
+
+ /* XXX unsupported operators? use pixel shader blending, eventually */
+
+ status = _cairo_composite_rectangles_init_for_paint (&extents,
+ dst->intel.drm.width,
+ dst->intel.drm.height,
+ op, source,
+ clip);
+ if (unlikely (status))
+ return status;
+
+ if (_cairo_clip_contains_rectangle (clip, &extents))
+ clip = NULL;
+
+ if (clip != NULL) {
+ clip = _cairo_clip_init_copy (&local_clip, clip);
+ have_clip = TRUE;
+ }
+
+ status = _clip_to_boxes (&clip, &extents, &clip_boxes, &num_boxes);
+ if (unlikely (status)) {
+ if (have_clip)
+ _cairo_clip_fini (&local_clip);
+
+ return status;
+ }
+
+ /* If the clip cannot be reduced to a set of boxes, we will need to
+ * use a clipmask. Paint is special as it is the only operation that
+ * does not implicitly use a mask, so we may be able to reduce this
+ * operation to a fill...
+ */
+ if (clip != NULL &&
+ extents.is_bounded &&
+ (clip_path = _clip_get_solitary_path (clip)) != NULL)
+ {
+ status = i915_surface_fill (dst, op, source,
+ &clip_path->path,
+ clip_path->fill_rule,
+ clip_path->tolerance,
+ clip_path->antialias,
+ NULL);
+ }
+ else
+ {
+ _cairo_boxes_init_for_array (&boxes, clip_boxes, num_boxes);
+ status = _clip_and_composite_boxes (dst, op, source,
+ &boxes, CAIRO_ANTIALIAS_DEFAULT,
+ &extents, clip);
+ }
+ if (clip_boxes != boxes.boxes_embedded)
+ free (clip_boxes);
+
+ if (have_clip)
+ _cairo_clip_fini (&local_clip);
+
+ return status;
+}
+
+static cairo_int_status_t
+i915_surface_mask (void *abstract_dst,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ const cairo_pattern_t *mask,
+ cairo_clip_t *clip)
+{
+ i915_surface_t *dst = abstract_dst;
+ cairo_composite_rectangles_t extents;
+ i915_shader_t shader;
+ cairo_clip_t local_clip;
+ cairo_region_t *clip_region = NULL;
+ cairo_bool_t need_clip_surface = FALSE;
+ cairo_bool_t have_clip = FALSE;
+ cairo_status_t status;
+
+ status = _cairo_composite_rectangles_init_for_mask (&extents,
+ dst->intel.drm.width,
+ dst->intel.drm.height,
+ op, source, mask, clip);
+ if (unlikely (status))
+ return status;
+
+ if (_cairo_clip_contains_rectangle (clip, &extents))
+ clip = NULL;
+
+ if (clip != NULL && extents.is_bounded) {
+ clip = _cairo_clip_init_copy (&local_clip, clip);
+ status = _cairo_clip_rectangle (clip, &extents.bounded);
+ if (unlikely (status)) {
+ _cairo_clip_fini (&local_clip);
+ return status;
+ }
+
+ have_clip = TRUE;
+ }
+
+ i915_shader_init (&shader, dst, op);
+
+ status = i915_shader_acquire_pattern (&shader,
+ &shader.source,
+ source,
+ &extents.bounded);
+ if (unlikely (status))
+ goto BAIL;
+
+ status = i915_shader_acquire_pattern (&shader,
+ &shader.mask,
+ mask,
+ &extents.bounded);
+ if (unlikely (status))
+ goto BAIL;
+
+ if (clip != NULL) {
+ status = _cairo_clip_get_region (clip, &clip_region);
+ assert (status == CAIRO_STATUS_SUCCESS || CAIRO_INT_STATUS_UNSUPPORTED);
+ need_clip_surface = status == CAIRO_INT_STATUS_UNSUPPORTED;
+ if (need_clip_surface)
+ i915_shader_set_clip (&shader, clip);
+ }
+
+ status = i915_shader_commit (&shader,
+ (i915_device_t *) dst->intel.drm.base.device);
+ if (unlikely (status))
+ goto BAIL;
+
+ if (clip_region != NULL) {
+ unsigned int n, num_rectangles;
+
+ num_rectangles = cairo_region_num_rectangles (clip_region);
+ for (n = 0; n < num_rectangles; n++) {
+ cairo_rectangle_int_t rect;
+
+ cairo_region_get_rectangle (clip_region, n, &rect);
+
+ shader.add_rectangle (&shader,
+ rect.x, rect.y,
+ rect.x + rect.width, rect.y + rect.height);
+ }
+ } else {
+ shader.add_rectangle (&shader,
+ extents.bounded.x, extents.bounded.y,
+ extents.bounded.x + extents.bounded.width,
+ extents.bounded.y + extents.bounded.height);
+ }
+
+ if (! extents.is_bounded)
+ status = i915_fixup_unbounded (dst, &extents, clip);
+
+ BAIL:
+ i915_shader_fini (&shader);
+ if (have_clip)
+ _cairo_clip_fini (&local_clip);
+
+ return status;
+}
+
+typedef struct {
+ cairo_polygon_t polygon;
+ cairo_fill_rule_t fill_rule;
+ cairo_antialias_t antialias;
+} composite_polygon_info_t;
+
+static cairo_status_t
+_composite_polygon_spans (void *closure,
+ cairo_span_renderer_t *renderer,
+ const cairo_rectangle_int_t *extents)
+{
+ composite_polygon_info_t *info = closure;
+ cairo_botor_scan_converter_t converter;
+ cairo_status_t status;
+ cairo_box_t box;
+
+ box.p1.x = _cairo_fixed_from_int (extents->x);
+ box.p1.y = _cairo_fixed_from_int (extents->y);
+ box.p2.x = _cairo_fixed_from_int (extents->x + extents->width);
+ box.p2.y = _cairo_fixed_from_int (extents->y + extents->height);
+
+ _cairo_botor_scan_converter_init (&converter, &box, info->fill_rule);
+
+ status = converter.base.add_polygon (&converter.base, &info->polygon);
+ if (likely (status == CAIRO_STATUS_SUCCESS))
+ status = converter.base.generate (&converter.base, renderer);
+
+ converter.base.destroy (&converter.base);
+
+ return status;
+}
+
+static cairo_int_status_t
+i915_surface_stroke (void *abstract_dst,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_path_fixed_t *path,
+ const cairo_stroke_style_t *stroke_style,
+ const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm_inverse,
+ double tolerance,
+ cairo_antialias_t antialias,
+ cairo_clip_t *clip)
+{
+ i915_surface_t *dst = abstract_dst;
+ cairo_composite_rectangles_t extents;
+ composite_polygon_info_t info;
+ cairo_box_t boxes_stack[32], *clip_boxes = boxes_stack;
+ int num_boxes = ARRAY_LENGTH (boxes_stack);
+ cairo_clip_t local_clip;
+ cairo_bool_t have_clip = FALSE;
+ cairo_status_t status;
+
+ status = _cairo_composite_rectangles_init_for_stroke (&extents,
+ dst->intel.drm.width,
+ dst->intel.drm.height,
+ op, source,
+ path, stroke_style, ctm,
+ clip);
+ if (unlikely (status))
+ return status;
+
+ if (_cairo_clip_contains_rectangle (clip, &extents))
+ clip = NULL;
+
+ if (clip != NULL) {
+ clip = _cairo_clip_init_copy (&local_clip, clip);
+ have_clip = TRUE;
+ }
+
+ status = _clip_to_boxes (&clip, &extents, &clip_boxes, &num_boxes);
+ if (unlikely (status)) {
+ if (have_clip)
+ _cairo_clip_fini (&local_clip);
+
+ return status;
+ }
+
+ if (path->is_rectilinear) {
+ cairo_boxes_t boxes;
+
+ _cairo_boxes_init (&boxes);
+ _cairo_boxes_limit (&boxes, clip_boxes, num_boxes);
+ status = _cairo_path_fixed_stroke_rectilinear_to_boxes (path,
+ stroke_style,
+ ctm,
+ &boxes);
+ if (likely (status == CAIRO_STATUS_SUCCESS)) {
+ status = _clip_and_composite_boxes (dst, op, source,
+ &boxes, antialias,
+ &extents, clip);
+ }
+
+ _cairo_boxes_fini (&boxes);
+
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+ goto CLEANUP_BOXES;
+ }
+
+ _cairo_polygon_init (&info.polygon);
+ _cairo_polygon_limit (&info.polygon, clip_boxes, num_boxes);
+
+ status = _cairo_path_fixed_stroke_to_polygon (path,
+ stroke_style,
+ ctm, ctm_inverse,
+ tolerance,
+ &info.polygon);
+ if (unlikely (status))
+ goto CLEANUP_POLYGON;
+
+ if (extents.is_bounded) {
+ cairo_rectangle_int_t rect;
+
+ _cairo_box_round_to_rectangle (&info.polygon.extents, &rect);
+ if (! _cairo_rectangle_intersect (&extents.bounded, &rect))
+ goto CLEANUP_POLYGON;
+ }
+
+ if (info.polygon.num_edges == 0) {
+ if (! extents.is_bounded)
+ status = i915_fixup_unbounded (dst, &extents, clip);
+
+ goto CLEANUP_POLYGON;
+ }
+
+ info.fill_rule = CAIRO_FILL_RULE_WINDING;
+ info.antialias = antialias;
+ status = i915_clip_and_composite_spans (dst, op, source, antialias,
+ _composite_polygon_spans, &info,
+ &extents, clip);
+
+CLEANUP_POLYGON:
+ _cairo_polygon_fini (&info.polygon);
+
+CLEANUP_BOXES:
+ if (clip_boxes != boxes_stack)
+ free (clip_boxes);
+
+ if (have_clip)
+ _cairo_clip_fini (&local_clip);
+
+ return status;
+}
+
+static cairo_int_status_t
+i915_surface_fill (void *abstract_dst,
+ cairo_operator_t op,
+ const cairo_pattern_t*source,
+ cairo_path_fixed_t *path,
+ cairo_fill_rule_t fill_rule,
+ double tolerance,
+ cairo_antialias_t antialias,
+ cairo_clip_t *clip)
+{
+ i915_surface_t *dst = abstract_dst;
+ cairo_composite_rectangles_t extents;
+ composite_polygon_info_t info;
+ cairo_box_t boxes_stack[32], *clip_boxes = boxes_stack;
+ cairo_clip_t local_clip;
+ cairo_bool_t have_clip = FALSE;
+ int num_boxes = ARRAY_LENGTH (boxes_stack);
+ cairo_status_t status;
+
+ status = _cairo_composite_rectangles_init_for_fill (&extents,
+ dst->intel.drm.width,
+ dst->intel.drm.height,
+ op, source, path,
+ clip);
+ if (unlikely (status))
+ return status;
+
+ if (_cairo_clip_contains_rectangle (clip, &extents))
+ clip = NULL;
+
+ if (clip != NULL) {
+ clip = _cairo_clip_init_copy (&local_clip, clip);
+ have_clip = TRUE;
+ }
+
+ status = _clip_to_boxes (&clip, &extents, &clip_boxes, &num_boxes);
+ if (unlikely (status)) {
+ if (have_clip)
+ _cairo_clip_fini (&local_clip);
+
+ return status;
+ }
+
+ assert (! path->is_empty_fill);
+
+ if (_cairo_path_fixed_is_rectilinear_fill (path)) {
+ cairo_boxes_t boxes;
+
+ _cairo_boxes_init (&boxes);
+ _cairo_boxes_limit (&boxes, clip_boxes, num_boxes);
+ status = _cairo_path_fixed_fill_rectilinear_to_boxes (path,
+ fill_rule,
+ &boxes);
+ if (likely (status == CAIRO_STATUS_SUCCESS)) {
+ status = _clip_and_composite_boxes (dst, op, source,
+ &boxes, antialias,
+ &extents, clip);
+ }
+
+ _cairo_boxes_fini (&boxes);
+
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+ goto CLEANUP_BOXES;
+ }
+
+ _cairo_polygon_init (&info.polygon);
+ _cairo_polygon_limit (&info.polygon, clip_boxes, num_boxes);
+
+ status = _cairo_path_fixed_fill_to_polygon (path, tolerance, &info.polygon);
+ if (unlikely (status))
+ goto CLEANUP_POLYGON;
+
+ if (extents.is_bounded) {
+ cairo_rectangle_int_t rect;
+
+ _cairo_box_round_to_rectangle (&info.polygon.extents, &rect);
+ if (! _cairo_rectangle_intersect (&extents.bounded, &rect))
+ goto CLEANUP_POLYGON;
+ }
+
+ if (info.polygon.num_edges == 0) {
+ if (! extents.is_bounded)
+ status = i915_fixup_unbounded (dst, &extents, clip);
+
+ goto CLEANUP_POLYGON;
+ }
+
+ info.fill_rule = fill_rule;
+ info.antialias = antialias;
+ status = i915_clip_and_composite_spans (dst, op, source, antialias,
+ _composite_polygon_spans, &info,
+ &extents, clip);
+
+CLEANUP_POLYGON:
+ _cairo_polygon_fini (&info.polygon);
+
+CLEANUP_BOXES:
+ if (clip_boxes != boxes_stack)
+ free (clip_boxes);
+
+ if (have_clip)
+ _cairo_clip_fini (&local_clip);
+
+ return status;
+}
+
+static const cairo_surface_backend_t i915_surface_backend = {
+ CAIRO_SURFACE_TYPE_DRM,
+
+ _cairo_drm_surface_create_similar,
+ i915_surface_finish,
+ intel_surface_acquire_source_image,
+ intel_surface_release_source_image,
+
+ NULL, NULL, NULL,
+ NULL, /* composite */
+ NULL, /* fill */
+ NULL, /* trapezoids */
+ NULL, /* span */
+ NULL, /* check-span */
+
+ NULL, /* copy_page */
+ NULL, /* show_page */
+ _cairo_drm_surface_get_extents,
+ NULL, /* old-glyphs */
+ _cairo_drm_surface_get_font_options,
+
+ i915_surface_flush,
+ NULL, /* mark_dirty */
+ intel_scaled_font_fini,
+ intel_scaled_glyph_fini,
+
+ i915_surface_paint,
+ i915_surface_mask,
+ i915_surface_stroke,
+ i915_surface_fill,
+ i915_surface_glyphs,
+};
+
+static void
+i915_surface_init (i915_surface_t *surface,
+ cairo_content_t content,
+ cairo_drm_device_t *device)
+{
+ intel_surface_init (&surface->intel, &i915_surface_backend, device, content);
+
+ switch (content) {
+ default:
+ ASSERT_NOT_REACHED;
+ case CAIRO_CONTENT_COLOR_ALPHA:
+ surface->map0 = MAPSURF_32BIT | MT_32BIT_ARGB8888;
+ surface->colorbuf = COLR_BUF_ARGB8888 | DEPTH_FRMT_24_FIXED_8_OTHER;
+ break;
+ case CAIRO_CONTENT_COLOR:
+ surface->map0 = MAPSURF_32BIT | MT_32BIT_XRGB8888;
+ surface->colorbuf = COLR_BUF_ARGB8888 | DEPTH_FRMT_24_FIXED_8_OTHER;
+ break;
+ case CAIRO_CONTENT_ALPHA:
+ surface->map0 = MAPSURF_8BIT | MT_8BIT_A8;
+ surface->colorbuf = COLR_BUF_8BIT | DEPTH_FRMT_24_FIXED_8_OTHER;
+ break;
+ }
+ surface->colorbuf |= DSTORG_HORT_BIAS (0x8) | DSTORG_VERT_BIAS (0x8);
+
+ surface->map1 = 0;
+
+ surface->is_current_texture = 0;
+
+ surface->offset = 0;
+
+ surface->stencil = NULL;
+ surface->cache = NULL;
+}
+
+cairo_surface_t *
+i915_surface_create_internal (cairo_drm_device_t *base_dev,
+ cairo_content_t content,
+ int width, int height,
+ uint32_t tiling,
+ cairo_bool_t gpu_target)
+{
+ i915_surface_t *surface;
+ cairo_status_t status_ignored;
+
+ surface = malloc (sizeof (i915_surface_t));
+ if (unlikely (surface == NULL))
+ return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
+
+ i915_surface_init (surface, content, base_dev);
+
+ if (width && height) {
+ uint32_t size;
+
+ surface->intel.drm.width = width;
+ surface->intel.drm.height = height;
+ surface->map0 |= ((height - 1) << MS3_HEIGHT_SHIFT) |
+ ((width - 1) << MS3_WIDTH_SHIFT);
+
+ width = (width + 3) & -4;
+ surface->intel.drm.stride = cairo_format_stride_for_width (surface->intel.drm.format,
+ width);
+ /* check for tiny surfaces for which tiling is irrelevant */
+ if (height * surface->intel.drm.stride < 4096)
+ tiling = I915_TILING_NONE;
+
+ surface->intel.drm.stride = i915_tiling_stride (tiling,
+ surface->intel.drm.stride);
+ assert (surface->intel.drm.stride <= 8192);
+ assert (surface->intel.drm.stride >= cairo_format_stride_for_width (surface->intel.drm.format, width));
+ height = i915_tiling_height (tiling, height);
+ assert (height <= 2048);
+
+ size = i915_tiling_size (tiling, surface->intel.drm.stride * height);
+
+ surface->intel.drm.bo = &intel_bo_create (to_intel_device (&base_dev->base),
+ size, gpu_target)->base;
+ if (surface->intel.drm.bo == NULL) {
+ status_ignored = _cairo_drm_surface_finish (&surface->intel.drm);
+ free (surface);
+ return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
+ }
+
+ intel_bo_set_tiling (to_intel_device (&base_dev->base),
+ to_intel_bo (surface->intel.drm.bo),
+ tiling, surface->intel.drm.stride);
+
+ assert (surface->intel.drm.bo->size >= (size_t) surface->intel.drm.stride*height);
+
+ surface->map0 |= MS3_tiling (to_intel_bo (surface->intel.drm.bo)->tiling);
+ surface->map1 = (surface->intel.drm.stride/4 - 1) << MS4_PITCH_SHIFT;
+ }
+
+ return &surface->intel.drm.base;
+}
+
+static cairo_surface_t *
+i915_surface_create (cairo_drm_device_t *base_dev,
+ cairo_content_t content,
+ int width, int height)
+{
+ return i915_surface_create_internal (base_dev, content, width, height,
+ I915_TILING_DEFAULT, TRUE);
+}
+
+static cairo_surface_t *
+i915_surface_create_for_name (cairo_drm_device_t *base_dev,
+ unsigned int name,
+ cairo_format_t format,
+ int width, int height, int stride)
+{
+ i915_surface_t *surface;
+ cairo_content_t content;
+
+ /* Vol I, p134: size restrictions for textures */
+ /* Vol I, p129: destination surface stride must be a multiple of 32 bytes */
+ if (stride < cairo_format_stride_for_width (format, (width + 3) & -4) ||
+ stride & 31)
+ {
+ return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_STRIDE));
+ }
+
+ switch (format) {
+ default:
+ case CAIRO_FORMAT_A1:
+ return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT));
+ case CAIRO_FORMAT_ARGB32:
+ content = CAIRO_CONTENT_COLOR_ALPHA;
+ break;
+ case CAIRO_FORMAT_RGB24:
+ content = CAIRO_CONTENT_COLOR;
+ break;
+ case CAIRO_FORMAT_A8:
+ content = CAIRO_CONTENT_ALPHA;
+ break;
+ }
+
+ surface = malloc (sizeof (i915_surface_t));
+ if (unlikely (surface == NULL))
+ return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
+
+ i915_surface_init (surface, content, base_dev);
+
+ if (width && height) {
+ surface->intel.drm.width = width;
+ surface->intel.drm.height = height;
+ surface->intel.drm.stride = stride;
+
+ surface->map0 |= ((height - 1) << MS3_HEIGHT_SHIFT) |
+ ((width - 1) << MS3_WIDTH_SHIFT);
+ surface->map1 = (surface->intel.drm.stride/4 - 1) << MS4_PITCH_SHIFT;
+
+ surface->intel.drm.bo =
+ &intel_bo_create_for_name (to_intel_device (&base_dev->base),
+ name)->base;
+ if (unlikely (surface->intel.drm.bo == NULL)) {
+ free (surface);
+ return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
+ }
+ to_intel_bo (surface->intel.drm.bo)->stride = stride;
+
+ surface->map0 |= MS3_tiling (to_intel_bo (surface->intel.drm.bo)->tiling);
+ }
+
+ return &surface->intel.drm.base;
+}
+
+static cairo_status_t
+i915_buffer_cache_init (intel_buffer_cache_t *cache,
+ i915_device_t *device,
+ cairo_format_t format,
+ int width, int height)
+{
+ const uint32_t tiling = I915_TILING_Y;
+
+ assert ((width & 3) == 0);
+ assert ((height & 1) == 0);
+ cache->buffer.width = width;
+ cache->buffer.height = height;
+
+ switch (format) {
+ case CAIRO_FORMAT_A1:
+ case CAIRO_FORMAT_RGB24:
+ ASSERT_NOT_REACHED;
+ case CAIRO_FORMAT_ARGB32:
+ cache->buffer.map0 = MAPSURF_32BIT | MT_32BIT_ARGB8888;
+ cache->buffer.stride = width * 4;
+ break;
+ case CAIRO_FORMAT_A8:
+ cache->buffer.map0 = MAPSURF_8BIT | MT_8BIT_I8;
+ cache->buffer.stride = width;
+ break;
+ }
+ cache->buffer.map0 |= ((height - 1) << MS3_HEIGHT_SHIFT) |
+ ((width - 1) << MS3_WIDTH_SHIFT);
+ cache->buffer.map1 = ((cache->buffer.stride / 4) - 1) << MS4_PITCH_SHIFT;
+
+ assert ((cache->buffer.stride & 7) == 0);
+ assert (i915_tiling_stride (tiling, cache->buffer.stride) == cache->buffer.stride);
+ assert (i915_tiling_height (tiling, height) == height);
+
+ cache->buffer.bo = intel_bo_create (&device->intel,
+ height * cache->buffer.stride,
+ FALSE);
+ if (unlikely (cache->buffer.bo == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+ intel_bo_set_tiling (&device->intel, cache->buffer.bo, tiling, cache->buffer.stride);
+ cache->buffer.map0 |= MS3_tiling (cache->buffer.bo->tiling);
+
+ cache->ref_count = 0;
+ cairo_list_init (&cache->link);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+i915_surface_t *
+i915_surface_create_from_cacheable_image_internal (i915_device_t *device,
+ cairo_image_surface_t *image)
+{
+ i915_surface_t *surface;
+ cairo_status_t status;
+ cairo_list_t *caches;
+ intel_buffer_cache_t *cache;
+ cairo_rtree_node_t *node;
+ cairo_format_t format;
+ int width, height, bpp;
+
+ width = image->width;
+ height = image->height;
+ if (width > IMAGE_CACHE_WIDTH/2 || height > IMAGE_CACHE_HEIGHT/2) {
+ surface = (i915_surface_t *)
+ i915_surface_create_internal (&device->intel.base,
+ image->base.content,
+ width, height,
+ I915_TILING_NONE, FALSE);
+ if (unlikely (surface->intel.drm.base.status))
+ return surface;
+
+ status = intel_bo_put_image (&device->intel,
+ to_intel_bo (surface->intel.drm.bo),
+ surface->intel.drm.stride,
+ image,
+ 0, 0,
+ width, height,
+ 0, 0);
+
+ if (unlikely (status)) {
+ cairo_surface_destroy (&surface->intel.drm.base);
+ return (i915_surface_t *) _cairo_surface_create_in_error (status);
+ }
+
+ return surface;
+ }
+
+ status = cairo_device_acquire (&device->intel.base.base);
+ if (unlikely (status))
+ return (i915_surface_t *) _cairo_surface_create_in_error (status);
+
+ switch (image->format) {
+ case CAIRO_FORMAT_ARGB32:
+ case CAIRO_FORMAT_RGB24:
+ caches = &device->image_caches[0];
+ format = CAIRO_FORMAT_ARGB32;
+ bpp = 4;
+ break;
+ case CAIRO_FORMAT_A8:
+ case CAIRO_FORMAT_A1:
+ caches = &device->image_caches[1];
+ format = CAIRO_FORMAT_A8;
+ bpp = 1;
+ break;
+ default:
+ ASSERT_NOT_REACHED;
+ status = _cairo_error (CAIRO_STATUS_INVALID_FORMAT);
+ goto CLEANUP_DEVICE;
+ }
+
+ node = NULL;
+ cairo_list_foreach_entry (cache, intel_buffer_cache_t, caches, link) {
+ if (! intel_bo_is_inactive (&device->intel, cache->buffer.bo))
+ continue;
+
+ status = _cairo_rtree_insert (&cache->rtree, width, height, &node);
+ if (unlikely (_cairo_status_is_error (status)))
+ goto CLEANUP_DEVICE;
+ if (status == CAIRO_STATUS_SUCCESS)
+ break;
+ }
+ if (node == NULL) {
+ cache = malloc (sizeof (intel_buffer_cache_t));
+ if (unlikely (cache == NULL)) {
+ status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ goto CLEANUP_DEVICE;
+ }
+
+ status = i915_buffer_cache_init (cache, device, format,
+ IMAGE_CACHE_WIDTH,
+ IMAGE_CACHE_HEIGHT);
+ if (unlikely (status)) {
+ free (cache);
+ goto CLEANUP_DEVICE;
+ }
+
+ _cairo_rtree_init (&cache->rtree,
+ IMAGE_CACHE_WIDTH,
+ IMAGE_CACHE_HEIGHT,
+ 4,
+ sizeof (i915_image_private_t),
+ NULL);
+
+ status = _cairo_rtree_insert (&cache->rtree, width, height, &node);
+ assert (status == CAIRO_STATUS_SUCCESS);
+
+ cairo_list_init (&cache->link);
+ }
+ cairo_list_move (&cache->link, caches);
+ ((i915_image_private_t *) node)->container = cache;
+
+ status = intel_bo_put_image (&device->intel,
+ cache->buffer.bo, cache->buffer.stride,
+ image,
+ 0, 0,
+ width, height,
+ node->x, node->y);
+ if (unlikely (status))
+ goto CLEANUP_CACHE;
+
+ surface = malloc (sizeof (i915_surface_t));
+ if (unlikely (surface == NULL)) {
+ status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ goto CLEANUP_CACHE;
+ }
+
+ i915_surface_init (surface, image->base.content, &device->intel.base);
+
+ surface->intel.drm.width = width;
+ surface->intel.drm.height = height;
+ surface->intel.drm.stride = cache->buffer.stride;
+
+ surface->map0 |= MS3_tiling (cache->buffer.bo->tiling) |
+ ((height - 1) << MS3_HEIGHT_SHIFT) |
+ ((width - 1) << MS3_WIDTH_SHIFT);
+ surface->map1 = (surface->intel.drm.stride/4 - 1) << MS4_PITCH_SHIFT;
+
+ surface->intel.drm.bo = &intel_bo_reference (cache->buffer.bo)->base;
+ surface->offset = node->y * cache->buffer.stride + bpp * node->x;
+
+ surface->cache = (i915_image_private_t *) node;
+ cache->ref_count++;
+
+ cairo_device_release (&device->intel.base.base);
+
+ return surface;
+
+CLEANUP_CACHE:
+ _cairo_rtree_node_destroy (&cache->rtree, node);
+ if (cache->ref_count == 0) {
+ intel_bo_destroy (&device->intel, cache->buffer.bo);
+ _cairo_rtree_fini (&cache->rtree);
+ cairo_list_del (&cache->link);
+ free (cache);
+ }
+CLEANUP_DEVICE:
+ cairo_device_release (&device->intel.base.base);
+ return (i915_surface_t *) _cairo_surface_create_in_error (status);
+}
+
+static cairo_surface_t *
+i915_surface_create_from_cacheable_image (cairo_drm_device_t *device,
+ cairo_surface_t *source)
+{
+ i915_surface_t *surface;
+ cairo_image_surface_t *image;
+ void *image_extra;
+ cairo_status_t status;
+
+ status = _cairo_surface_acquire_source_image (source, &image, &image_extra);
+ if (unlikely (status))
+ return _cairo_surface_create_in_error (status);
+
+ surface = i915_surface_create_from_cacheable_image_internal ((i915_device_t *) device, image);
+
+ _cairo_surface_release_source_image (source, image, image_extra);
+
+ return &surface->intel.drm.base;
+}
+
+static cairo_status_t
+i915_surface_enable_scan_out (void *abstract_surface)
+{
+ i915_surface_t *surface = abstract_surface;
+ intel_bo_t *bo;
+ cairo_status_t status;
+
+ if (unlikely (surface->intel.drm.bo == NULL))
+ return _cairo_error (CAIRO_STATUS_INVALID_SIZE);
+
+ bo = to_intel_bo (surface->intel.drm.bo);
+ if (bo->tiling == I915_TILING_Y) {
+ status = i915_surface_batch_flush (surface);
+ if (unlikely (status))
+ return status;
+
+ intel_bo_set_tiling (to_intel_device (surface->intel.drm.base.device),
+ bo, I915_TILING_X, surface->intel.drm.stride);
+ if (bo->tiling == I915_TILING_X) {
+ surface->map0 &= ~MS3_tiling (I915_TILING_Y);
+ surface->map0 |= MS3_tiling (I915_TILING_X);
+ }
+ }
+
+ if (unlikely (bo->tiling == I915_TILING_Y))
+ return _cairo_error (CAIRO_STATUS_INVALID_FORMAT); /* XXX */
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+i915_device_flush (cairo_drm_device_t *device)
+{
+ cairo_status_t status;
+
+ if (unlikely (device->base.finished))
+ return CAIRO_STATUS_SUCCESS;
+
+ status = cairo_device_acquire (&device->base);
+ if (likely (status == CAIRO_STATUS_SUCCESS)) {
+ status = i915_batch_flush ((i915_device_t *) device);
+ cairo_device_release (&device->base);
+ }
+
+ return status;
+}
+
+static cairo_int_status_t
+i915_device_throttle (cairo_drm_device_t *device)
+{
+ cairo_status_t status;
+
+ status = cairo_device_acquire (&device->base);
+ if (unlikely (status))
+ return status;
+
+ status = i915_batch_flush ((i915_device_t *) device);
+ intel_throttle ((intel_device_t *) device);
+
+ cairo_device_release (&device->base);
+
+ return status;
+}
+
+static void
+i915_device_destroy (void *data)
+{
+ i915_device_t *device = data;
+
+ if (device->last_vbo)
+ intel_bo_destroy (&device->intel, device->last_vbo);
+
+ i915_batch_cleanup (device);
+
+ intel_device_fini (&device->intel);
+ free (device);
+}
+
+COMPILE_TIME_ASSERT (sizeof (i915_batch_setup) == sizeof (((i915_device_t *)0)->batch_header));
+COMPILE_TIME_ASSERT (offsetof (i915_device_t, batch_base) == offsetof (i915_device_t, batch_header) + sizeof (i915_batch_setup));
+
+cairo_drm_device_t *
+_cairo_drm_i915_device_create (int fd, dev_t dev_id, int vendor_id, int chip_id)
+{
+ i915_device_t *device;
+ cairo_status_t status;
+ uint64_t gtt_size;
+ int n;
+
+ if (! intel_info (fd, >t_size))
+ return NULL;
+
+ device = malloc (sizeof (i915_device_t));
+ if (device == NULL)
+ return (cairo_drm_device_t *) _cairo_device_create_in_error (CAIRO_STATUS_NO_MEMORY);
+
+ status = intel_device_init (&device->intel, fd);
+ if (unlikely (status)) {
+ free (device);
+ return (cairo_drm_device_t *) _cairo_device_create_in_error (status);
+ }
+
+ device->debug = 0;
+ if (getenv ("CAIRO_DEBUG_DRM") != NULL)
+ device->debug = I915_DEBUG_BATCH;
+
+ device->batch.gtt_size = I915_BATCH_SIZE;
+ device->batch.exec_count = 0;
+ device->batch.reloc_count = 0;
+ device->batch.used = 0;
+
+ memcpy (device->batch_header, i915_batch_setup, sizeof (i915_batch_setup));
+ device->vbo = 0;
+ device->vbo_offset = 0;
+ device->vbo_used = 0;
+ device->vertex_index = 0;
+ device->vertex_count = 0;
+ device->last_vbo = NULL;
+
+ device->current_n_samplers = 0;
+ device->current_target = NULL;
+ device->current_source = NULL;
+ device->current_mask = NULL;
+ device->current_clip = NULL;
+ device->current_colorbuf = 0;
+
+ for (n = 0; n < ARRAY_LENGTH (device->image_caches); n++)
+ cairo_list_init (&device->image_caches[n]);
+
+ device->intel.base.surface.create = i915_surface_create;
+ device->intel.base.surface.create_for_name = i915_surface_create_for_name;
+ device->intel.base.surface.create_from_cacheable_image = i915_surface_create_from_cacheable_image;
+
+ device->intel.base.surface.flink = _cairo_drm_surface_flink;
+ device->intel.base.surface.enable_scan_out = i915_surface_enable_scan_out;
+ device->intel.base.surface.map_to_image = intel_surface_map_to_image;
+
+ device->intel.base.device.flush = i915_device_flush;
+ device->intel.base.device.throttle = i915_device_throttle;
+ device->intel.base.device.destroy = i915_device_destroy;
+
+ i915_device_reset (device);
+
+ return _cairo_drm_device_init (&device->intel.base,
+ fd, dev_id, vendor_id, chip_id,
+ 2048);
+}
diff --git a/src/drm/cairo-drm-i965-glyphs.c b/src/drm/cairo-drm-i965-glyphs.c
new file mode 100644
index 0000000..fa86e34
--- /dev/null
+++ b/src/drm/cairo-drm-i965-glyphs.c
@@ -0,0 +1,500 @@
+/* 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 Red Hat, Inc.
+ *
+ * Contributor(s):
+ * Chris Wilson <chris at chris-wilson.co.uk>
+ */
+
+#include "cairoint.h"
+
+#include "cairo-composite-rectangles-private.h"
+#include "cairo-drm-i965-private.h"
+#include "cairo-error-private.h"
+#include "cairo-rtree-private.h"
+
+typedef struct _i965_glyphs i965_glyphs_t;
+
+typedef float *
+(*i965_get_rectangle_func_t) (i965_glyphs_t *glyphs);
+
+struct _i965_glyphs {
+ i965_get_rectangle_func_t get_rectangle;
+ i965_shader_t shader;
+
+ struct i965_vbo head, *tail;
+
+ unsigned int vbo_offset;
+ float *vbo_base;
+};
+
+static float *
+i965_glyphs_emit_rectangle (i965_glyphs_t *glyphs)
+{
+ return i965_add_rectangle (glyphs->shader.device);
+}
+
+static float *
+i965_glyphs_accumulate_rectangle (i965_glyphs_t *glyphs)
+{
+ float *vertices;
+ uint32_t size;
+
+ size = glyphs->shader.device->rectangle_size;
+ if (unlikely (glyphs->vbo_offset + size > I965_VERTEX_SIZE)) {
+ struct i965_vbo *vbo;
+
+ intel_bo_unmap (glyphs->tail->bo);
+
+ vbo = malloc (sizeof (struct i965_vbo));
+ if (unlikely (vbo == NULL)) {
+ /* throw error! */
+ }
+
+ glyphs->tail->next = vbo;
+ glyphs->tail = vbo;
+
+ vbo->next = NULL;
+ vbo->bo = intel_bo_create (&glyphs->shader.device->intel,
+ I965_VERTEX_SIZE, FALSE);
+ vbo->count = 0;
+
+ glyphs->vbo_offset = 0;
+ glyphs->vbo_base = intel_bo_map (&glyphs->shader.device->intel, vbo->bo);
+ }
+
+ vertices = glyphs->vbo_base + glyphs->vbo_offset;
+ glyphs->vbo_offset += size;
+ glyphs->tail->count += 3;
+
+ return vertices;
+}
+
+static void
+i965_add_glyph_rectangle (i965_glyphs_t *glyphs,
+ int x1, int y1,
+ int x2, int y2,
+ intel_glyph_t *glyph)
+{
+ float *v;
+
+ /* Each vertex is:
+ * 2 vertex coordinates
+ * 1 glyph texture coordinate
+ */
+
+ v = glyphs->get_rectangle (glyphs);
+
+ /* bottom right */
+ *v++ = x2; *v++ = y2;
+ *v++ = glyph->texcoord[0];
+
+ /* bottom left */
+ *v++ = x1; *v++ = y2;
+ *v++ = glyph->texcoord[1];
+
+ /* top left */
+ *v++ = x1; *v++ = y1;
+ *v++ = glyph->texcoord[2];
+}
+
+static cairo_status_t
+i965_surface_mask_internal (i965_surface_t *dst,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ i965_surface_t *mask,
+ cairo_clip_t *clip,
+ const cairo_composite_rectangles_t *extents)
+{
+ i965_device_t *device;
+ i965_shader_t shader;
+ cairo_region_t *clip_region = NULL;
+ cairo_status_t status;
+
+ i965_shader_init (&shader, dst, op);
+
+ status = i965_shader_acquire_pattern (&shader, &shader.source,
+ source, &extents->bounded);
+ if (unlikely (status))
+ return status;
+
+ shader.mask.type.vertex = VS_NONE;
+ shader.mask.type.fragment = FS_SURFACE;
+ shader.mask.base.content = mask->intel.drm.base.content;
+ shader.mask.base.filter = i965_filter (CAIRO_FILTER_NEAREST);
+ shader.mask.base.extend = i965_extend (CAIRO_EXTEND_NONE);
+
+ cairo_matrix_init_translate (&shader.mask.base.matrix,
+ -extents->bounded.x + NEAREST_BIAS,
+ -extents->bounded.y + NEAREST_BIAS);
+ cairo_matrix_scale (&shader.mask.base.matrix,
+ 1. / mask->intel.drm.width,
+ 1. / mask->intel.drm.height);
+
+ shader.mask.base.bo = to_intel_bo (mask->intel.drm.bo);
+ shader.mask.base.format = mask->intel.drm.format;
+ shader.mask.base.width = mask->intel.drm.width;
+ shader.mask.base.height = mask->intel.drm.height;
+ shader.mask.base.stride = mask->intel.drm.stride;
+
+ if (clip != NULL) {
+ status = _cairo_clip_get_region (clip, &clip_region);
+ assert (status == CAIRO_STATUS_SUCCESS || status == CAIRO_INT_STATUS_UNSUPPORTED);
+
+ if (clip_region != NULL && cairo_region_num_rectangles (clip_region) == 1)
+ clip_region = NULL;
+
+ if (status == CAIRO_INT_STATUS_UNSUPPORTED)
+ i965_shader_set_clip (&shader, clip);
+ }
+
+ status = cairo_device_acquire (dst->intel.drm.base.device);
+ if (unlikely (status))
+ goto CLEANUP_SHADER;
+
+ device = i965_device (dst);
+
+ status = i965_shader_commit (&shader, device);
+ if (unlikely (status))
+ goto CLEANUP_DEVICE;
+
+ if (clip_region != NULL) {
+ unsigned int n, num_rectangles;
+
+ num_rectangles = cairo_region_num_rectangles (clip_region);
+ for (n = 0; n < num_rectangles; n++) {
+ cairo_rectangle_int_t rect;
+
+ cairo_region_get_rectangle (clip_region, n, &rect);
+
+ i965_shader_add_rectangle (&shader,
+ rect.x, rect.y,
+ rect.width, rect.height);
+ }
+ } else {
+ i965_shader_add_rectangle (&shader,
+ extents->bounded.x,
+ extents->bounded.y,
+ extents->bounded.width,
+ extents->bounded.height);
+ }
+
+ if (! extents->is_bounded)
+ status = i965_fixup_unbounded (dst, extents, clip);
+
+ CLEANUP_DEVICE:
+ cairo_device_release (&device->intel.base.base);
+ CLEANUP_SHADER:
+ i965_shader_fini (&shader);
+ return status;
+}
+
+cairo_int_status_t
+i965_surface_glyphs (void *abstract_surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_glyph_t *g,
+ int num_glyphs,
+ cairo_scaled_font_t *scaled_font,
+ cairo_clip_t *clip,
+ int *num_remaining)
+{
+ i965_surface_t *surface = abstract_surface;
+ i965_surface_t *mask = NULL;
+ i965_device_t *device;
+ i965_glyphs_t glyphs;
+ cairo_composite_rectangles_t extents;
+ cairo_clip_t local_clip;
+ cairo_bool_t have_clip = FALSE;
+ cairo_bool_t overlap;
+ cairo_region_t *clip_region = NULL;
+ intel_bo_t *last_bo = NULL;
+ cairo_scaled_glyph_t *glyph_cache[64];
+ cairo_status_t status;
+ int mask_x = 0, mask_y = 0;
+ int i = 0;
+
+ *num_remaining = 0;
+ status = _cairo_composite_rectangles_init_for_glyphs (&extents,
+ surface->intel.drm.width,
+ surface->intel.drm.height,
+ op, source,
+ scaled_font,
+ g, num_glyphs,
+ clip,
+ &overlap);
+ if (unlikely (status))
+ return status;
+
+ if (clip != NULL && _cairo_clip_contains_rectangle (clip, &extents))
+ clip = NULL;
+
+ if (clip != NULL && extents.is_bounded) {
+ clip = _cairo_clip_init_copy (&local_clip, clip);
+ status = _cairo_clip_rectangle (clip, &extents.bounded);
+ if (unlikely (status))
+ return status;
+
+ have_clip = TRUE;
+ }
+
+ if (overlap || ! extents.is_bounded) {
+ cairo_content_t content;
+
+ content = CAIRO_CONTENT_ALPHA;
+ if (scaled_font->options.antialias == CAIRO_ANTIALIAS_SUBPIXEL)
+ content |= CAIRO_CONTENT_COLOR;
+
+ mask = (i965_surface_t *)
+ i965_surface_create_internal (&i965_device (surface)->intel.base,
+ content,
+ extents.bounded.width,
+ extents.bounded.height,
+ I965_TILING_DEFAULT,
+ TRUE);
+ if (unlikely (mask->intel.drm.base.status))
+ return mask->intel.drm.base.status;
+
+ status = _cairo_surface_paint (&mask->intel.drm.base,
+ CAIRO_OPERATOR_CLEAR,
+ &_cairo_pattern_clear.base,
+ NULL);
+ if (unlikely (status)) {
+ cairo_surface_destroy (&mask->intel.drm.base);
+ return status;
+ }
+
+ i965_shader_init (&glyphs.shader, mask, CAIRO_OPERATOR_ADD);
+
+ status = i965_shader_acquire_pattern (&glyphs.shader, &glyphs.shader.source,
+ &_cairo_pattern_white.base,
+ &extents.bounded);
+ if (unlikely (status)) {
+ cairo_surface_destroy (&mask->intel.drm.base);
+ return status;
+ }
+
+ mask_x = -extents.bounded.x;
+ mask_y = -extents.bounded.y;
+ } else {
+ i965_shader_init (&glyphs.shader, surface, op);
+
+ status = i965_shader_acquire_pattern (&glyphs.shader, &glyphs.shader.source,
+ source, &extents.bounded);
+ if (unlikely (status))
+ return status;
+
+ if (clip != NULL) {
+ status = _cairo_clip_get_region (clip, &clip_region);
+ assert (status == CAIRO_STATUS_SUCCESS || status == CAIRO_INT_STATUS_UNSUPPORTED);
+
+ if (status == CAIRO_INT_STATUS_UNSUPPORTED)
+ i965_shader_set_clip (&glyphs.shader, clip);
+ }
+ }
+
+ glyphs.head.next = NULL;
+ glyphs.head.bo = NULL;
+ glyphs.head.count = 0;
+ glyphs.tail = &glyphs.head;
+
+ device = i965_device (surface);
+ if (mask != NULL || clip_region == NULL) {
+ glyphs.get_rectangle = i965_glyphs_emit_rectangle;
+ } else {
+ glyphs.get_rectangle = i965_glyphs_accumulate_rectangle;
+ glyphs.head.bo = intel_bo_create (&device->intel,
+ I965_VERTEX_SIZE, FALSE);
+ if (unlikely (glyphs.head.bo == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+ glyphs.vbo_base = intel_bo_map (&device->intel, glyphs.head.bo);
+ }
+ glyphs.vbo_offset = 0;
+
+ status = cairo_device_acquire (&device->intel.base.base);
+ if (unlikely (status))
+ goto CLEANUP_GLYPHS;
+
+ _cairo_scaled_font_freeze_cache (scaled_font);
+ //private = _cairo_scaled_font_get_device (scaled_font, device);
+ if (scaled_font->surface_private == NULL) {
+ /* XXX couple into list to remove on context destruction */
+ scaled_font->surface_private = device;
+ scaled_font->surface_backend = surface->intel.drm.base.backend;
+ }
+
+ memset (glyph_cache, 0, sizeof (glyph_cache));
+
+ for (i = 0; i < num_glyphs; i++) {
+ cairo_scaled_glyph_t *scaled_glyph;
+ int x, y, x1, x2, y1, y2;
+ int cache_index = g[i].index % ARRAY_LENGTH (glyph_cache);
+ intel_glyph_t *glyph;
+
+ scaled_glyph = glyph_cache[cache_index];
+ if (scaled_glyph == NULL ||
+ _cairo_scaled_glyph_index (scaled_glyph) != g[i].index)
+ {
+ status = _cairo_scaled_glyph_lookup (scaled_font,
+ g[i].index,
+ CAIRO_SCALED_GLYPH_INFO_METRICS,
+ &scaled_glyph);
+ if (unlikely (status))
+ goto FINISH;
+
+ glyph_cache[cache_index] = scaled_glyph;
+ }
+
+ if (unlikely (scaled_glyph->metrics.width == 0 ||
+ scaled_glyph->metrics.height == 0))
+ {
+ continue;
+ }
+
+ /* XXX glyph images are snapped to pixel locations */
+ x = _cairo_lround (g[i].x);
+ y = _cairo_lround (g[i].y);
+
+ x1 = x + _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.x);
+ y1 = y + _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.y);
+ x2 = x + _cairo_fixed_integer_ceil (scaled_glyph->bbox.p2.x);
+ y2 = y + _cairo_fixed_integer_ceil (scaled_glyph->bbox.p2.y);
+
+ if (x2 < extents.bounded.x ||
+ y2 < extents.bounded.y ||
+ x1 > extents.bounded.x + extents.bounded.width ||
+ y1 > extents.bounded.y + extents.bounded.height)
+ {
+ continue;
+ }
+
+ if (scaled_glyph->surface_private == NULL) {
+ status = intel_get_glyph (&device->intel, scaled_font, scaled_glyph);
+ if (unlikely (status == CAIRO_INT_STATUS_NOTHING_TO_DO)) {
+ status = CAIRO_STATUS_SUCCESS;
+ continue;
+ }
+ if (unlikely (status))
+ goto FINISH;
+ }
+ glyph = intel_glyph_pin (scaled_glyph->surface_private);
+
+ if (glyph->cache->buffer.bo != last_bo) {
+ intel_buffer_cache_t *cache = glyph->cache;
+
+ glyphs.shader.mask.type.vertex = VS_GLYPHS;
+ glyphs.shader.mask.type.fragment = FS_GLYPHS;
+ glyphs.shader.mask.type.pattern = PATTERN_BASE;
+
+ glyphs.shader.mask.base.bo = cache->buffer.bo;
+ glyphs.shader.mask.base.format = cache->buffer.format;
+ glyphs.shader.mask.base.width = cache->buffer.width;
+ glyphs.shader.mask.base.height = cache->buffer.height;
+ glyphs.shader.mask.base.stride = cache->buffer.stride;
+ glyphs.shader.mask.base.filter = i965_filter (CAIRO_FILTER_NEAREST);
+ glyphs.shader.mask.base.extend = i965_extend (CAIRO_EXTEND_NONE);
+ glyphs.shader.mask.base.content = CAIRO_CONTENT_ALPHA; /* XXX */
+
+ glyphs.shader.committed = FALSE;
+ status = i965_shader_commit (&glyphs.shader, device);
+ if (unlikely (status))
+ goto FINISH;
+
+ last_bo = cache->buffer.bo;
+ }
+
+ x1 += mask_x; x2 += mask_x;
+ y1 += mask_y; y2 += mask_y;
+
+ i965_add_glyph_rectangle (&glyphs, x1, y1, x2, y2, glyph);
+ }
+
+ if (mask != NULL && clip_region != NULL) {
+ intel_bo_unmap (glyphs.tail->bo);
+ i965_clipped_vertices (device, &glyphs.head, clip_region);
+ }
+
+ status = CAIRO_STATUS_SUCCESS;
+ FINISH:
+ _cairo_scaled_font_thaw_cache (scaled_font);
+ cairo_device_release (surface->intel.drm.base.device);
+ CLEANUP_GLYPHS:
+ i965_shader_fini (&glyphs.shader);
+ if (glyphs.head.bo != NULL) {
+ struct i965_vbo *vbo, *next;
+
+ intel_bo_destroy (&device->intel, glyphs.head.bo);
+ for (vbo = glyphs.head.next; vbo != NULL; vbo = next) {
+ next = vbo->next;
+ intel_bo_destroy (&device->intel, vbo->bo);
+ free (vbo);
+ }
+ }
+
+ if (unlikely (status == CAIRO_INT_STATUS_UNSUPPORTED)) {
+ cairo_path_fixed_t path;
+
+ _cairo_path_fixed_init (&path);
+ status = _cairo_scaled_font_glyph_path (scaled_font,
+ g + i, num_glyphs - i,
+ &path);
+ if (mask_x | mask_y) {
+ _cairo_path_fixed_translate (&path,
+ _cairo_fixed_from_int (mask_x),
+ _cairo_fixed_from_int (mask_y));
+ }
+ if (likely (status == CAIRO_STATUS_SUCCESS)) {
+ status = surface->intel.drm.base.backend->fill (glyphs.shader.target,
+ glyphs.shader.op,
+ mask != NULL ? &_cairo_pattern_white.base : source,
+ &path,
+ CAIRO_FILL_RULE_WINDING,
+ 0,
+ scaled_font->options.antialias,
+ clip);
+ }
+ _cairo_path_fixed_fini (&path);
+ }
+
+ if (mask != NULL) {
+ if (likely (status == CAIRO_STATUS_SUCCESS)) {
+ status = i965_surface_mask_internal (surface, op, source, mask,
+ clip, &extents);
+ }
+ cairo_surface_finish (&mask->intel.drm.base);
+ cairo_surface_destroy (&mask->intel.drm.base);
+ }
+
+ if (have_clip)
+ _cairo_clip_fini (&local_clip);
+
+ return status;
+}
diff --git a/src/drm/cairo-drm-i965-private.h b/src/drm/cairo-drm-i965-private.h
new file mode 100644
index 0000000..14fabe9
--- /dev/null
+++ b/src/drm/cairo-drm-i965-private.h
@@ -0,0 +1,742 @@
+#ifndef CAIRO_DRM_I965_PRIVATE_H
+#define CAIRO_DRM_I965_PRIVATE_H
+
+#include "cairo-drm-intel-private.h"
+
+#include "cairo-hash-private.h"
+#include "cairo-freelist-private.h"
+
+#include "cairo-drm-intel-brw-defines.h"
+
+#include <setjmp.h>
+
+#define BRW_MI_GLOBAL_SNAPSHOT_RESET (1 << 3)
+
+/*
+ * New regs for broadwater -- we need to split this file up sensibly somehow.
+ */
+#define BRW_3D(Pipeline,Opcode,Subopcode) ((3 << 29) | \
+ ((Pipeline) << 27) | \
+ ((Opcode) << 24) | \
+ ((Subopcode) << 16))
+
+#define BRW_URB_FENCE BRW_3D(0, 0, 0)
+#define BRW_CS_URB_STATE BRW_3D(0, 0, 1)
+#define BRW_CONSTANT_BUFFER BRW_3D(0, 0, 2)
+#define BRW_STATE_PREFETCH BRW_3D(0, 0, 3)
+
+#define BRW_STATE_BASE_ADDRESS BRW_3D(0, 1, 1)
+#define BRW_STATE_SIP BRW_3D(0, 1, 2)
+#define BRW_PIPELINE_SELECT BRW_3D(0, 1, 4)
+
+#define NEW_PIPELINE_SELECT BRW_3D(1, 1, 4)
+
+#define BRW_MEDIA_STATE_POINTERS BRW_3D(2, 0, 0)
+#define BRW_MEDIA_OBJECT BRW_3D(2, 1, 0)
+
+#define BRW_3DSTATE_PIPELINED_POINTERS BRW_3D(3, 0, 0)
+#define BRW_3DSTATE_BINDING_TABLE_POINTERS BRW_3D(3, 0, 1)
+#define BRW_3DSTATE_VERTEX_BUFFERS BRW_3D(3, 0, 8)
+#define BRW_3DSTATE_VERTEX_ELEMENTS BRW_3D(3, 0, 9)
+#define BRW_3DSTATE_INDEX_BUFFER BRW_3D(3, 0, 0xa)
+#define BRW_3DSTATE_VF_STATISTICS BRW_3D(3, 0, 0xb)
+
+#define BRW_3DSTATE_DRAWING_RECTANGLE BRW_3D(3, 1, 0)
+#define BRW_3DSTATE_CONSTANT_COLOR BRW_3D(3, 1, 1)
+#define BRW_3DSTATE_SAMPLER_PALETTE_LOAD BRW_3D(3, 1, 2)
+#define BRW_3DSTATE_CHROMA_KEY BRW_3D(3, 1, 4)
+#define BRW_3DSTATE_DEPTH_BUFFER BRW_3D(3, 1, 5)
+#define BRW_3DSTATE_POLY_STIPPLE_OFFSET BRW_3D(3, 1, 6)
+#define BRW_3DSTATE_POLY_STIPPLE_PATTERN BRW_3D(3, 1, 7)
+#define BRW_3DSTATE_LINE_STIPPLE BRW_3D(3, 1, 8)
+#define BRW_3DSTATE_GLOBAL_DEPTH_OFFSET_CLAMP BRW_3D(3, 1, 9)
+/* These two are BLC and CTG only, not BW or CL */
+#define BRW_3DSTATE_AA_LINE_PARAMS BRW_3D(3, 1, 0xa)
+#define BRW_3DSTATE_GS_SVB_INDEX BRW_3D(3, 1, 0xb)
+
+#define BRW_PIPE_CONTROL BRW_3D(3, 2, 0)
+
+#define BRW_3DPRIMITIVE BRW_3D(3, 3, 0)
+
+#define PIPELINE_SELECT_3D 0
+#define PIPELINE_SELECT_MEDIA 1
+
+#define UF0_CS_REALLOC (1 << 13)
+#define UF0_VFE_REALLOC (1 << 12)
+#define UF0_SF_REALLOC (1 << 11)
+#define UF0_CLIP_REALLOC (1 << 10)
+#define UF0_GS_REALLOC (1 << 9)
+#define UF0_VS_REALLOC (1 << 8)
+#define UF1_CLIP_FENCE_SHIFT 20
+#define UF1_GS_FENCE_SHIFT 10
+#define UF1_VS_FENCE_SHIFT 0
+#define UF2_CS_FENCE_SHIFT 20
+#define UF2_VFE_FENCE_SHIFT 10
+#define UF2_SF_FENCE_SHIFT 0
+
+/* for BRW_STATE_BASE_ADDRESS */
+#define BASE_ADDRESS_MODIFY (1 << 0)
+
+/* for BRW_3DSTATE_PIPELINED_POINTERS */
+#define BRW_GS_DISABLE 0
+#define BRW_GS_ENABLE 1
+#define BRW_CLIP_DISABLE 0
+#define BRW_CLIP_ENABLE 1
+
+/* for BRW_PIPE_CONTROL */
+#define BRW_PIPE_CONTROL_NOWRITE (0 << 14)
+#define BRW_PIPE_CONTROL_WRITE_QWORD (1 << 14)
+#define BRW_PIPE_CONTROL_WRITE_DEPTH (2 << 14)
+#define BRW_PIPE_CONTROL_WRITE_TIME (3 << 14)
+#define BRW_PIPE_CONTROL_DEPTH_STALL (1 << 13)
+#define BRW_PIPE_CONTROL_WC_FLUSH (1 << 12)
+#define BRW_PIPE_CONTROL_IS_FLUSH (1 << 11)
+#define BRW_PIPE_CONTROL_NOTIFY_ENABLE (1 << 8)
+#define BRW_PIPE_CONTROL_GLOBAL_GTT (1 << 2)
+#define BRW_PIPE_CONTROL_LOCAL_PGTT (0 << 2)
+
+/* VERTEX_BUFFER_STATE Structure */
+#define VB0_BUFFER_INDEX_SHIFT 27
+#define VB0_VERTEXDATA (0 << 26)
+#define VB0_INSTANCEDATA (1 << 26)
+#define VB0_BUFFER_PITCH_SHIFT 0
+
+/* VERTEX_ELEMENT_STATE Structure */
+#define VE0_VERTEX_BUFFER_INDEX_SHIFT 27
+#define VE0_VALID (1 << 26)
+#define VE0_FORMAT_SHIFT 16
+#define VE0_OFFSET_SHIFT 0
+#define VE1_VFCOMPONENT_0_SHIFT 28
+#define VE1_VFCOMPONENT_1_SHIFT 24
+#define VE1_VFCOMPONENT_2_SHIFT 20
+#define VE1_VFCOMPONENT_3_SHIFT 16
+#define VE1_DESTINATION_ELEMENT_OFFSET_SHIFT 0
+
+/* 3DPRIMITIVE bits */
+#define BRW_3DPRIMITIVE_VERTEX_SEQUENTIAL (0 << 15)
+#define BRW_3DPRIMITIVE_VERTEX_RANDOM (1 << 15)
+/* Primitive types are in brw_defines.h */
+#define BRW_3DPRIMITIVE_TOPOLOGY_SHIFT 10
+
+#define BRW_SVG_CTL 0x7400
+
+#define BRW_SVG_CTL_GS_BA (0 << 8)
+#define BRW_SVG_CTL_SS_BA (1 << 8)
+#define BRW_SVG_CTL_IO_BA (2 << 8)
+#define BRW_SVG_CTL_GS_AUB (3 << 8)
+#define BRW_SVG_CTL_IO_AUB (4 << 8)
+#define BRW_SVG_CTL_SIP (5 << 8)
+
+#define BRW_SVG_RDATA 0x7404
+#define BRW_SVG_WORK_CTL 0x7408
+
+#define BRW_VF_CTL 0x7500
+
+#define BRW_VF_CTL_SNAPSHOT_COMPLETE (1 << 31)
+#define BRW_VF_CTL_SNAPSHOT_MUX_SELECT_THREADID (0 << 8)
+#define BRW_VF_CTL_SNAPSHOT_MUX_SELECT_VF_DEBUG (1 << 8)
+#define BRW_VF_CTL_SNAPSHOT_TYPE_VERTEX_SEQUENCE (0 << 4)
+#define BRW_VF_CTL_SNAPSHOT_TYPE_VERTEX_INDEX (1 << 4)
+#define BRW_VF_CTL_SKIP_INITIAL_PRIMITIVES (1 << 3)
+#define BRW_VF_CTL_MAX_PRIMITIVES_LIMIT_ENABLE (1 << 2)
+#define BRW_VF_CTL_VERTEX_RANGE_LIMIT_ENABLE (1 << 1)
+#define BRW_VF_CTL_SNAPSHOT_ENABLE (1 << 0)
+
+#define BRW_VF_STRG_VAL 0x7504
+#define BRW_VF_STR_VL_OVR 0x7508
+#define BRW_VF_VC_OVR 0x750c
+#define BRW_VF_STR_PSKIP 0x7510
+#define BRW_VF_MAX_PRIM 0x7514
+#define BRW_VF_RDATA 0x7518
+
+#define BRW_VS_CTL 0x7600
+#define BRW_VS_CTL_SNAPSHOT_COMPLETE (1 << 31)
+#define BRW_VS_CTL_SNAPSHOT_MUX_VERTEX_0 (0 << 8)
+#define BRW_VS_CTL_SNAPSHOT_MUX_VERTEX_1 (1 << 8)
+#define BRW_VS_CTL_SNAPSHOT_MUX_VALID_COUNT (2 << 8)
+#define BRW_VS_CTL_SNAPSHOT_MUX_VS_KERNEL_POINTER (3 << 8)
+#define BRW_VS_CTL_SNAPSHOT_ALL_THREADS (1 << 2)
+#define BRW_VS_CTL_THREAD_SNAPSHOT_ENABLE (1 << 1)
+#define BRW_VS_CTL_SNAPSHOT_ENABLE (1 << 0)
+
+#define BRW_VS_STRG_VAL 0x7604
+#define BRW_VS_RDATA 0x7608
+
+#define BRW_SF_CTL 0x7b00
+#define BRW_SF_CTL_SNAPSHOT_COMPLETE (1 << 31)
+#define BRW_SF_CTL_SNAPSHOT_MUX_VERTEX_0_FF_ID (0 << 8)
+#define BRW_SF_CTL_SNAPSHOT_MUX_VERTEX_0_REL_COUNT (1 << 8)
+#define BRW_SF_CTL_SNAPSHOT_MUX_VERTEX_1_FF_ID (2 << 8)
+#define BRW_SF_CTL_SNAPSHOT_MUX_VERTEX_1_REL_COUNT (3 << 8)
+#define BRW_SF_CTL_SNAPSHOT_MUX_VERTEX_2_FF_ID (4 << 8)
+#define BRW_SF_CTL_SNAPSHOT_MUX_VERTEX_2_REL_COUNT (5 << 8)
+#define BRW_SF_CTL_SNAPSHOT_MUX_VERTEX_COUNT (6 << 8)
+#define BRW_SF_CTL_SNAPSHOT_MUX_SF_KERNEL_POINTER (7 << 8)
+#define BRW_SF_CTL_MIN_MAX_PRIMITIVE_RANGE_ENABLE (1 << 4)
+#define BRW_SF_CTL_DEBUG_CLIP_RECTANGLE_ENABLE (1 << 3)
+#define BRW_SF_CTL_SNAPSHOT_ALL_THREADS (1 << 2)
+#define BRW_SF_CTL_THREAD_SNAPSHOT_ENABLE (1 << 1)
+#define BRW_SF_CTL_SNAPSHOT_ENABLE (1 << 0)
+
+#define BRW_SF_STRG_VAL 0x7b04
+#define BRW_SF_RDATA 0x7b18
+
+#define BRW_WIZ_CTL 0x7c00
+#define BRW_WIZ_CTL_SNAPSHOT_COMPLETE (1 << 31)
+#define BRW_WIZ_CTL_SUBSPAN_INSTANCE_SHIFT 16
+#define BRW_WIZ_CTL_SNAPSHOT_MUX_WIZ_KERNEL_POINTER (0 << 8)
+#define BRW_WIZ_CTL_SNAPSHOT_MUX_SUBSPAN_INSTANCE (1 << 8)
+#define BRW_WIZ_CTL_SNAPSHOT_MUX_PRIMITIVE_SEQUENCE (2 << 8)
+#define BRW_WIZ_CTL_SINGLE_SUBSPAN_DISPATCH (1 << 6)
+#define BRW_WIZ_CTL_IGNORE_COLOR_SCOREBOARD_STALLS (1 << 5)
+#define BRW_WIZ_CTL_ENABLE_SUBSPAN_INSTANCE_COMPARE (1 << 4)
+#define BRW_WIZ_CTL_USE_UPSTREAM_SNAPSHOT_FLAG (1 << 3)
+#define BRW_WIZ_CTL_SNAPSHOT_ALL_THREADS (1 << 2)
+#define BRW_WIZ_CTL_THREAD_SNAPSHOT_ENABLE (1 << 1)
+#define BRW_WIZ_CTL_SNAPSHOT_ENABLE (1 << 0)
+
+#define BRW_WIZ_STRG_VAL 0x7c04
+#define BRW_WIZ_RDATA 0x7c18
+
+#define BRW_TS_CTL 0x7e00
+#define BRW_TS_CTL_SNAPSHOT_COMPLETE (1 << 31)
+#define BRW_TS_CTL_SNAPSHOT_MESSAGE_ERROR (0 << 8)
+#define BRW_TS_CTL_SNAPSHOT_INTERFACE_DESCRIPTOR (3 << 8)
+#define BRW_TS_CTL_SNAPSHOT_ALL_CHILD_THREADS (1 << 2)
+#define BRW_TS_CTL_SNAPSHOT_ALL_ROOT_THREADS (1 << 1)
+#define BRW_TS_CTL_SNAPSHOT_ENABLE (1 << 0)
+
+#define BRW_TS_STRG_VAL 0x7e04
+#define BRW_TS_RDATA 0x7e08
+
+#define BRW_TD_CTL 0x8000
+#define BRW_TD_CTL_MUX_SHIFT 8
+#define BRW_TD_CTL_EXTERNAL_HALT_R0_DEBUG_MATCH (1 << 7)
+#define BRW_TD_CTL_FORCE_EXTERNAL_HALT (1 << 6)
+#define BRW_TD_CTL_EXCEPTION_MASK_OVERRIDE (1 << 5)
+#define BRW_TD_CTL_FORCE_THREAD_BREAKPOINT_ENABLE (1 << 4)
+#define BRW_TD_CTL_BREAKPOINT_ENABLE (1 << 2)
+#define BRW_TD_CTL2 0x8004
+#define BRW_TD_CTL2_ILLEGAL_OPCODE_EXCEPTION_OVERRIDE (1 << 28)
+#define BRW_TD_CTL2_MASKSTACK_EXCEPTION_OVERRIDE (1 << 26)
+#define BRW_TD_CTL2_SOFTWARE_EXCEPTION_OVERRIDE (1 << 25)
+#define BRW_TD_CTL2_ACTIVE_THREAD_LIMIT_SHIFT 16
+#define BRW_TD_CTL2_ACTIVE_THREAD_LIMIT_ENABLE (1 << 8)
+#define BRW_TD_CTL2_THREAD_SPAWNER_EXECUTION_MASK_ENABLE (1 << 7)
+#define BRW_TD_CTL2_WIZ_EXECUTION_MASK_ENABLE (1 << 6)
+#define BRW_TD_CTL2_SF_EXECUTION_MASK_ENABLE (1 << 5)
+#define BRW_TD_CTL2_CLIPPER_EXECUTION_MASK_ENABLE (1 << 4)
+#define BRW_TD_CTL2_GS_EXECUTION_MASK_ENABLE (1 << 3)
+#define BRW_TD_CTL2_VS_EXECUTION_MASK_ENABLE (1 << 0)
+#define BRW_TD_VF_VS_EMSK 0x8008
+#define BRW_TD_GS_EMSK 0x800c
+#define BRW_TD_CLIP_EMSK 0x8010
+#define BRW_TD_SF_EMSK 0x8014
+#define BRW_TD_WIZ_EMSK 0x8018
+#define BRW_TD_0_6_EHTRG_VAL 0x801c
+#define BRW_TD_0_7_EHTRG_VAL 0x8020
+#define BRW_TD_0_6_EHTRG_MSK 0x8024
+#define BRW_TD_0_7_EHTRG_MSK 0x8028
+#define BRW_TD_RDATA 0x802c
+#define BRW_TD_TS_EMSK 0x8030
+
+#define BRW_EU_CTL 0x8800
+#define BRW_EU_CTL_SELECT_SHIFT 16
+#define BRW_EU_CTL_DATA_MUX_SHIFT 8
+#define BRW_EU_ATT_0 0x8810
+#define BRW_EU_ATT_1 0x8814
+#define BRW_EU_ATT_DATA_0 0x8820
+#define BRW_EU_ATT_DATA_1 0x8824
+#define BRW_EU_ATT_CLR_0 0x8830
+#define BRW_EU_ATT_CLR_1 0x8834
+#define BRW_EU_RDATA 0x8840
+
+typedef struct i965_device i965_device_t;
+typedef struct i965_surface i965_surface_t;
+typedef struct i965_shader i965_shader_t;
+typedef struct i965_stream i965_stream_t;
+
+struct i965_sf_state {
+ cairo_hash_entry_t entry;
+ uint32_t offset;
+};
+
+cairo_private cairo_bool_t
+i965_sf_state_equal (const void *, const void *);
+
+struct i965_cc_state {
+ cairo_hash_entry_t entry;
+ uint32_t offset;
+};
+
+cairo_private cairo_bool_t
+i965_cc_state_equal (const void *, const void *);
+
+struct i965_wm_kernel {
+ cairo_hash_entry_t entry;
+ uint32_t offset;
+};
+
+struct i965_wm_state {
+ cairo_hash_entry_t entry;
+ uint32_t kernel;
+ uint32_t sampler;
+ uint32_t offset;
+};
+
+cairo_private cairo_bool_t
+i965_wm_state_equal (const void *, const void *);
+
+struct i965_wm_binding {
+ cairo_hash_entry_t entry;
+ uint32_t table[4];
+ int size;
+ uint32_t offset;
+};
+
+cairo_private cairo_bool_t
+i965_wm_binding_equal (const void *, const void *);
+
+struct i965_sampler {
+ cairo_hash_entry_t entry;
+ uint32_t offset;
+};
+
+struct i965_vbo {
+ struct i965_vbo *next;
+ intel_bo_t *bo;
+ unsigned int count;
+};
+
+struct i965_surface {
+ intel_surface_t intel;
+
+ uint32_t stream;
+ uint32_t offset;
+};
+
+struct i965_pending_relocation {
+ uint32_t offset;
+ uint32_t read_domains;
+ uint32_t write_domain;
+ uint32_t delta;
+};
+
+struct i965_stream {
+ uint32_t used;
+ uint32_t committed;
+ uint32_t size;
+ uint8_t *data;
+ uint32_t serial;
+
+ int num_pending_relocations;
+ int max_pending_relocations;
+ struct i965_pending_relocation *pending_relocations;
+
+ int num_relocations;
+ int max_relocations;
+ struct drm_i915_gem_relocation_entry *relocations;
+};
+
+#define I965_BATCH_SIZE (16 * 4096)
+#define I965_SURFACE_SIZE (16 * 4096)
+#define I965_GENERAL_SIZE (16 * 4096)
+#define I965_CONSTANT_SIZE (16 * 4096)
+#define I965_VERTEX_SIZE (128 * 4096)
+
+#define I965_TILING_DEFAULT I915_TILING_Y
+
+
+struct i965_device {
+ intel_device_t intel;
+
+ cairo_bool_t is_g4x;
+
+ i965_shader_t *shader; /* note: only valid during geometry emission */
+
+ /* track state changes */
+ struct i965_sf_state sf_state;
+ struct i965_cc_state cc_state;
+ struct i965_wm_state wm_state;
+ struct i965_wm_binding wm_binding;
+
+ i965_surface_t *target;
+ uint32_t target_offset;
+
+ intel_bo_t *source;
+ uint32_t source_offset;
+
+ intel_bo_t *mask;
+ uint32_t mask_offset;
+
+ intel_bo_t *clip;
+ uint32_t clip_offset;
+
+ uint32_t draw_rectangle;
+
+ uint32_t vs_offset;
+ uint32_t border_color_offset;
+ cairo_hash_table_t *sf_states;
+ cairo_hash_table_t *cc_states;
+ cairo_hash_table_t *wm_kernels;
+ cairo_hash_table_t *wm_states;
+ cairo_hash_table_t *wm_bindings;
+ cairo_hash_table_t *samplers;
+ intel_bo_t *general_state;
+
+ cairo_freelist_t sf_freelist;
+ cairo_freelist_t cc_freelist;
+ cairo_freelist_t wm_kernel_freelist;
+ cairo_freelist_t wm_state_freelist;
+ cairo_freelist_t wm_binding_freelist;
+ cairo_freelist_t sampler_freelist;
+
+ uint32_t vertex_type;
+ uint32_t vertex_size;
+ uint32_t rectangle_size;
+ uint32_t last_vertex_size;
+
+ float *constants; /* 4 x matrix + 2 x source */
+ unsigned constants_size;
+ cairo_bool_t have_urb_fences;
+
+ i965_stream_t batch;
+ uint8_t batch_base[I965_BATCH_SIZE];
+ struct drm_i915_gem_relocation_entry batch_relocations[1024];
+
+ i965_stream_t surface;
+ uint8_t surface_base[I965_SURFACE_SIZE];
+ struct i965_pending_relocation surface_pending_relocations[1];
+ struct drm_i915_gem_relocation_entry surface_relocations[512];
+
+ i965_stream_t general;
+ uint8_t general_base[I965_GENERAL_SIZE];
+ struct i965_pending_relocation general_pending_relocations[1];
+
+ i965_stream_t vertex;
+ uint8_t vertex_base[I965_VERTEX_SIZE];
+ struct i965_pending_relocation vertex_pending_relocations[512];
+
+ i965_stream_t constant;
+ uint8_t constant_base[I965_CONSTANT_SIZE];
+ struct i965_pending_relocation constant_pending_relocations[512];
+
+ struct {
+ size_t gtt_size;
+
+ intel_bo_t *bo[1024];
+ int count;
+
+ struct drm_i915_gem_exec_object2 exec[1024];
+ } exec;
+ cairo_list_t flush;
+};
+
+typedef enum {
+ VS_NONE = 0,
+ VS_GLYPHS,
+ VS_SPANS,
+} i965_vertex_shader_t;
+
+typedef enum {
+ FS_NONE = 0,
+ FS_CONSTANT,
+ FS_LINEAR,
+ FS_RADIAL,
+ FS_SURFACE,
+ FS_GLYPHS,
+ FS_SPANS,
+} i965_fragment_shader_t;
+
+typedef enum {
+ PATTERN_BASE,
+ PATTERN_SOLID,
+ PATTERN_LINEAR,
+ PATTERN_RADIAL,
+ PATTERN_SURFACE,
+} i965_shader_channel_t;
+#define PATTERN_NONE (i965_shader_channel_t)-1
+
+struct i965_shader {
+ i965_device_t *device;
+ i965_surface_t *target;
+
+ cairo_operator_t op;
+
+ cairo_bool_t committed;
+ cairo_bool_t need_combine;
+
+ float constants[4*8 + 2*8]; /* 4 x matrix + 2 x source */
+ unsigned constants_size;
+
+ union i965_shader_channel {
+ struct {
+ i965_vertex_shader_t vertex;
+ i965_fragment_shader_t fragment;
+ i965_shader_channel_t pattern;
+ } type;
+ struct i965_shader_base {
+ i965_vertex_shader_t vertex;
+ i965_fragment_shader_t fragment;
+ i965_shader_channel_t pattern;
+
+ uint32_t mode;
+
+ float constants[8];
+ unsigned constants_size;
+
+ intel_bo_t *bo;
+ cairo_format_t format;
+ cairo_content_t content;
+ int width, height, stride;
+ int filter, extend;
+ cairo_matrix_t matrix;
+ cairo_bool_t has_component_alpha;
+ } base;
+ struct i965_shader_solid {
+ struct i965_shader_base base;
+ } solid;
+ struct i965_shader_linear {
+ struct i965_shader_base base;
+ } linear;
+ struct i965_shader_radial {
+ struct i965_shader_base base;
+ } radial;
+ struct i965_shader_surface {
+ struct i965_shader_base base;
+ cairo_surface_t *surface;
+ } surface;
+ } source, mask, clip, dst;
+
+ jmp_buf unwind;
+};
+
+enum i965_shader_linear_mode {
+ /* XXX REFLECT */
+ LINEAR_TEXTURE,
+ LINEAR_NONE,
+ LINEAR_REPEAT,
+ LINEAR_PAD,
+};
+
+enum i965_shader_radial_mode {
+ RADIAL_ONE,
+ RADIAL_TWO
+};
+
+typedef cairo_status_t
+(*i965_spans_func_t) (void *closure,
+ cairo_span_renderer_t *renderer,
+ const cairo_rectangle_int_t *extents);
+
+static inline i965_device_t *
+i965_device (i965_surface_t *surface)
+{
+ return (i965_device_t *) surface->intel.drm.base.device;
+}
+
+cairo_private void
+i965_emit_relocation (i965_device_t *device,
+ i965_stream_t *stream,
+ intel_bo_t *target,
+ uint32_t target_offset,
+ uint32_t read_domains,
+ uint32_t write_domain,
+ uint32_t offset);
+
+static always_inline uint32_t
+i965_stream_emit (i965_stream_t *stream, const void *data, size_t size)
+{
+ uint32_t offset;
+
+ offset = stream->used;
+ assert (offset + size <= stream->size);
+ memcpy (stream->data + offset, data, size);
+ stream->used += size;
+
+ return offset;
+}
+
+static always_inline void
+i965_stream_align (i965_stream_t *stream, uint32_t size)
+{
+ stream->used = (stream->used + size - 1) & -size;
+}
+
+static always_inline void *
+i965_stream_alloc (i965_stream_t *stream, uint32_t align, uint32_t size)
+{
+ void *ptr;
+
+ if (align)
+ i965_stream_align (stream, align);
+
+ assert (stream->used + size <= stream->size);
+ ptr = stream->data + stream->used;
+ stream->used += size;
+
+ return ptr;
+}
+
+static always_inline uint32_t
+i965_stream_offsetof (i965_stream_t *stream, const void *ptr)
+{
+ return (char *) ptr - (char *) stream->data;
+}
+
+cairo_private void
+i965_stream_commit (i965_device_t *device,
+ i965_stream_t *stream);
+
+cairo_private void
+i965_general_state_reset (i965_device_t *device);
+
+static inline void
+i965_batch_emit_dword (i965_device_t *device, uint32_t dword)
+{
+ *(uint32_t *) (device->batch.data + device->batch.used) = dword;
+ device->batch.used += 4;
+}
+
+#define OUT_BATCH(dword) i965_batch_emit_dword(device, dword)
+
+cairo_private void
+i965_clipped_vertices (i965_device_t *device,
+ struct i965_vbo *vbo,
+ cairo_region_t *clip_region);
+
+cairo_private void
+i965_flush_vertices (i965_device_t *device);
+
+cairo_private void
+i965_finish_vertices (i965_device_t *device);
+
+static inline float *
+i965_add_rectangle (i965_device_t *device)
+{
+ float *vertices;
+ uint32_t size;
+
+ size = device->rectangle_size;
+ if (unlikely (device->vertex.used + size > device->vertex.size))
+ i965_finish_vertices (device);
+
+ vertices = (float *) (device->vertex.data + device->vertex.used);
+ device->vertex.used += size;
+
+ return vertices;
+}
+
+static inline void
+i965_shader_add_rectangle (const i965_shader_t *shader,
+ int x, int y,
+ int w, int h)
+{
+ float *v;
+
+ v= i965_add_rectangle (shader->device);
+
+ /* bottom-right */
+ *v++ = x + w;
+ *v++ = y + h;
+
+ /* bottom-left */
+ *v++ = x;
+ *v++ = y + h;
+
+ /* top-left */
+ *v++ = x;
+ *v++ = y;
+}
+
+cairo_private cairo_surface_t *
+i965_surface_create_internal (cairo_drm_device_t *base_dev,
+ cairo_content_t content,
+ int width, int height,
+ uint32_t tiling,
+ cairo_bool_t gpu_target);
+
+cairo_private cairo_status_t
+i965_clip_and_composite_spans (i965_surface_t *dst,
+ cairo_operator_t op,
+ const cairo_pattern_t *pattern,
+ cairo_antialias_t antialias,
+ i965_spans_func_t draw_func,
+ void *draw_closure,
+ const cairo_composite_rectangles_t*extents,
+ cairo_clip_t *clip);
+
+cairo_private cairo_int_status_t
+i965_surface_glyphs (void *abstract_surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_scaled_font_t *scaled_font,
+ cairo_clip_t *clip,
+ int *num_remaining);
+
+cairo_private void
+i965_shader_init (i965_shader_t *shader,
+ i965_surface_t *dst,
+ cairo_operator_t op);
+
+cairo_private cairo_status_t
+i965_shader_acquire_pattern (i965_shader_t *shader,
+ union i965_shader_channel *src,
+ const cairo_pattern_t *pattern,
+ const cairo_rectangle_int_t *extents);
+
+cairo_private void
+i965_shader_set_clip (i965_shader_t *shader,
+ cairo_clip_t *clip);
+
+cairo_private cairo_status_t
+i965_shader_commit (i965_shader_t *shader,
+ i965_device_t *device);
+
+cairo_private void
+i965_shader_fini (i965_shader_t *shader);
+
+cairo_private cairo_status_t
+i965_device_flush (i965_device_t *device);
+
+cairo_private cairo_status_t
+i965_fixup_unbounded (i965_surface_t *dst,
+ const cairo_composite_rectangles_t *extents,
+ cairo_clip_t *clip);
+
+static inline int
+i965_filter (cairo_filter_t filter)
+{
+ switch (filter) {
+ default:
+ case CAIRO_FILTER_FAST:
+ case CAIRO_FILTER_NEAREST:
+ return BRW_MAPFILTER_NEAREST;
+
+ case CAIRO_FILTER_GOOD:
+ case CAIRO_FILTER_BEST:
+ case CAIRO_FILTER_BILINEAR:
+ case CAIRO_FILTER_GAUSSIAN:
+ return BRW_MAPFILTER_LINEAR;
+ }
+}
+
+static inline int
+i965_extend (cairo_extend_t extend)
+{
+ switch (extend) {
+ default:
+ case CAIRO_EXTEND_NONE:
+ return BRW_TEXCOORDMODE_CLAMP_BORDER;
+ case CAIRO_EXTEND_REPEAT:
+ return BRW_TEXCOORDMODE_WRAP;
+ case CAIRO_EXTEND_PAD:
+ return BRW_TEXCOORDMODE_CLAMP;
+ case CAIRO_EXTEND_REFLECT:
+ return BRW_TEXCOORDMODE_MIRROR;
+ }
+}
+
+#endif /* CAIRO_DRM_I965_PRIVATE_H */
diff --git a/src/drm/cairo-drm-i965-shader.c b/src/drm/cairo-drm-i965-shader.c
new file mode 100644
index 0000000..fc9ae57
--- /dev/null
+++ b/src/drm/cairo-drm-i965-shader.c
@@ -0,0 +1,2852 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2009 Kristian Høgsberg
+ * Copyright © 2009 Chris Wilson
+ * 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.
+ *
+ * Contributor(s):
+ * Chris Wilson <chris at chris-wilson.co.uk>
+ * Kristian Høgsberg <krh at bitplanet.net>
+ */
+
+#include "cairoint.h"
+
+#include "cairo-error-private.h"
+#include "cairo-drm-i965-private.h"
+#include "cairo-surface-subsurface-private.h"
+#include "cairo-surface-snapshot-private.h"
+
+#include "cairo-drm-intel-brw-eu.h"
+
+#if CAIRO_HAS_XCB_SURFACE && CAIRO_HAS_XCB_DRM_FUNCTIONS
+/* for DRI2/DRM interoperability */
+#include "cairo-xcb-private.h"
+#endif
+
+/* Theory of shaders:
+ *
+ * 3 types of rectangular inputs:
+ * (a) standard composite: x,y, use source, mask matrices to compute texcoords
+ * (b) spans: x,y, alpha, use source matrix
+ * (c) glyphs: x,y, s,t, use source matrix
+ *
+ * 5 types of pixel shaders:
+ * (a) Solid colour
+ * (b) Linear gradient (via 1D texture, with precomputed tex)
+ * (c) Radial gradient (per-pixel s computation, 1D texture)
+ * (d) Spans (mask only): apply opacity
+ * (e) Texture (includes glyphs).
+ *
+ * Clip masks are limited to 2D textures only.
+ */
+
+/* XXX dual source blending for LERP + ComponentAlpha!!! */
+
+#define BRW_GRF_BLOCKS(nreg) ((nreg + 15) / 16 - 1)
+
+#define SF_KERNEL_NUM_GRF 1
+#define SF_MAX_THREADS 24
+
+#define PS_MAX_THREADS_CTG 50
+#define PS_MAX_THREADS_BRW 32
+
+#define URB_CS_ENTRY_SIZE 3 /* We need 4 matrices + 2 sources */
+#define URB_CS_ENTRIES 4 /* 4x sets of CONSTANT_BUFFER */
+
+#define URB_VS_ENTRY_SIZE 1
+#define URB_VS_ENTRIES 8
+
+#define URB_GS_ENTRY_SIZE 0
+#define URB_GS_ENTRIES 0
+
+#define URB_CLIP_ENTRY_SIZE 0
+#define URB_CLIP_ENTRIES 0
+
+#define URB_SF_ENTRY_SIZE 1
+#define URB_SF_ENTRIES (SF_MAX_THREADS + 1)
+
+static void
+i965_pipelined_flush (i965_device_t *device)
+{
+ intel_bo_t *bo, *next;
+
+ if (device->batch.used == 0)
+ return;
+
+ OUT_BATCH (BRW_PIPE_CONTROL |
+ BRW_PIPE_CONTROL_NOWRITE |
+ BRW_PIPE_CONTROL_WC_FLUSH |
+ 2);
+ OUT_BATCH(0); /* Destination address */
+ OUT_BATCH(0); /* Immediate data low DW */
+ OUT_BATCH(0); /* Immediate data high DW */
+
+ cairo_list_foreach_entry_safe (bo, next, intel_bo_t, &device->flush, link) {
+ bo->batch_write_domain = 0;
+ cairo_list_init (&bo->link);
+ }
+ cairo_list_init (&device->flush);
+}
+
+static cairo_status_t
+i965_shader_acquire_solid (i965_shader_t *shader,
+ union i965_shader_channel *src,
+ const cairo_solid_pattern_t *solid,
+ const cairo_rectangle_int_t *extents)
+{
+ src->type.fragment = FS_CONSTANT;
+ src->type.vertex = VS_NONE;
+ src->type.pattern = PATTERN_SOLID;
+
+ src->base.content = solid->content;
+ if (CAIRO_COLOR_IS_OPAQUE(&solid->color))
+ src->base.content &= ~CAIRO_CONTENT_ALPHA;
+
+ src->base.constants[0] = solid->color.red * solid->color.alpha;
+ src->base.constants[1] = solid->color.green * solid->color.alpha;
+ src->base.constants[2] = solid->color.blue * solid->color.alpha;
+ src->base.constants[3] = solid->color.alpha;
+ src->base.constants_size = 4;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+i965_shader_acquire_linear (i965_shader_t *shader,
+ union i965_shader_channel *src,
+ const cairo_linear_pattern_t *linear,
+ const cairo_rectangle_int_t *extents)
+{
+ intel_buffer_t buffer;
+ cairo_status_t status;
+ double x0, y0, sf;
+ double dx, dy, offset;
+
+ status = intel_gradient_render (&i965_device (shader->target)->intel,
+ &linear->base, &buffer);
+ if (unlikely (status))
+ return status;
+
+ src->type.vertex = VS_NONE;
+ src->type.pattern = PATTERN_LINEAR;
+ src->type.fragment = FS_LINEAR;
+ src->base.bo = buffer.bo;
+ src->base.content = CAIRO_CONTENT_COLOR_ALPHA;
+ src->base.format = buffer.format;
+ src->base.width = buffer.width;
+ src->base.height = buffer.height;
+ src->base.stride = buffer.stride;
+ src->base.filter = i965_filter (CAIRO_FILTER_BILINEAR);
+ src->base.extend = i965_extend (linear->base.base.extend);
+
+ dx = _cairo_fixed_to_double (linear->p2.x - linear->p1.x);
+ dy = _cairo_fixed_to_double (linear->p2.y - linear->p1.y);
+ sf = 1. / (dx * dx + dy * dy);
+ dx *= sf;
+ dy *= sf;
+
+ x0 = _cairo_fixed_to_double (linear->p1.x);
+ y0 = _cairo_fixed_to_double (linear->p1.y);
+ offset = dx*x0 + dy*y0;
+
+ if (_cairo_matrix_is_identity (&linear->base.base.matrix)) {
+ src->base.matrix.xx = dx;
+ src->base.matrix.xy = dy;
+ src->base.matrix.x0 = -offset;
+ } else {
+ cairo_matrix_t m;
+
+ cairo_matrix_init (&m, dx, 0, dy, 0, -offset, 0);
+ cairo_matrix_multiply (&src->base.matrix, &linear->base.base.matrix, &m);
+ }
+ src->base.matrix.yx = 0.;
+ src->base.matrix.yy = 1.;
+ src->base.matrix.y0 = 0.;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+i965_shader_acquire_radial (i965_shader_t *shader,
+ union i965_shader_channel *src,
+ const cairo_radial_pattern_t *radial,
+ const cairo_rectangle_int_t *extents)
+{
+ intel_buffer_t buffer;
+ cairo_status_t status;
+ double dx, dy, dr, r1;
+
+ status = intel_gradient_render (&i965_device (shader->target)->intel,
+ &radial->base, &buffer);
+ if (unlikely (status))
+ return status;
+
+ src->type.vertex = VS_NONE;
+ src->type.pattern = PATTERN_RADIAL;
+ src->type.fragment = FS_RADIAL;
+ src->base.bo = buffer.bo;
+ src->base.content = CAIRO_CONTENT_COLOR_ALPHA;
+ src->base.format = buffer.format;
+ src->base.width = buffer.width;
+ src->base.height = buffer.height;
+ src->base.stride = buffer.stride;
+ src->base.filter = i965_filter (CAIRO_FILTER_BILINEAR);
+ src->base.extend = i965_extend (radial->base.base.extend);
+
+ dx = _cairo_fixed_to_double (radial->c2.x - radial->c1.x);
+ dy = _cairo_fixed_to_double (radial->c2.y - radial->c1.y);
+ dr = _cairo_fixed_to_double (radial->r2 - radial->r1);
+
+ r1 = _cairo_fixed_to_double (radial->r1);
+
+ if (FALSE && radial->c2.x == radial->c1.x && radial->c2.y == radial->c1.y) {
+ /* XXX dr == 0, meaningless with anything other than PAD */
+ src->base.constants[0] = _cairo_fixed_to_double (radial->c1.x) / dr;
+ src->base.constants[1] = _cairo_fixed_to_double (radial->c1.y) / dr;
+ src->base.constants[2] = 1. / dr;
+ src->base.constants[3] = -r1 / dr;
+
+ src->base.constants_size = 4;
+ src->base.mode = RADIAL_ONE;
+ } else {
+ src->base.constants[0] = -_cairo_fixed_to_double (radial->c1.x);
+ src->base.constants[1] = -_cairo_fixed_to_double (radial->c1.y);
+ src->base.constants[2] = r1;
+ src->base.constants[3] = -4 * (dx*dx + dy*dy - dr*dr);
+
+ src->base.constants[4] = -2 * dx;
+ src->base.constants[5] = -2 * dy;
+ src->base.constants[6] = -2 * r1 * dr;
+ src->base.constants[7] = 1 / (2 * (dx*dx + dy*dy - dr*dr));
+
+ src->base.constants_size = 8;
+ src->base.mode = RADIAL_TWO;
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+i965_surface_clone (i965_device_t *device,
+ cairo_image_surface_t *image,
+ i965_surface_t **clone_out)
+{
+ i965_surface_t *clone;
+ cairo_status_t status;
+
+ clone = (i965_surface_t *)
+ i965_surface_create_internal (&device->intel.base,
+ image->base.content,
+ image->width,
+ image->height,
+ I965_TILING_DEFAULT,
+ FALSE);
+ if (unlikely (clone->intel.drm.base.status))
+ return clone->intel.drm.base.status;
+
+ status = intel_bo_put_image (&device->intel,
+ to_intel_bo (clone->intel.drm.bo),
+ clone->intel.drm.stride,
+ image,
+ 0, 0,
+ image->width, image->height,
+ 0, 0);
+
+ if (unlikely (status)) {
+ cairo_surface_destroy (&clone->intel.drm.base);
+ return status;
+ }
+
+ status = _cairo_surface_attach_snapshot (&image->base,
+ &clone->intel.drm.base,
+ intel_surface_detach_snapshot);
+ if (likely (status == CAIRO_STATUS_SUCCESS))
+ status = intel_snapshot_cache_insert (&device->intel, &clone->intel);
+
+ if (unlikely (status)) {
+ cairo_surface_destroy (&clone->intel.drm.base);
+ return status;
+ }
+
+ *clone_out = clone;
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+i965_surface_clone_subimage (i965_device_t *device,
+ cairo_image_surface_t *image,
+ const cairo_rectangle_int_t *extents,
+ i965_surface_t **clone_out)
+{
+ i965_surface_t *clone;
+ cairo_status_t status;
+
+ clone = (i965_surface_t *)
+ i965_surface_create_internal (&device->intel.base,
+ image->base.content,
+ extents->width,
+ extents->height,
+ I965_TILING_DEFAULT,
+ FALSE);
+ if (unlikely (clone->intel.drm.base.status))
+ return clone->intel.drm.base.status;
+
+ status = intel_bo_put_image (to_intel_device (clone->intel.drm.base.device),
+ to_intel_bo (clone->intel.drm.bo),
+ clone->intel.drm.stride,
+ image,
+ extents->x, extents->y,
+ extents->width, extents->height,
+ 0, 0);
+ if (unlikely (status))
+ return status;
+
+ *clone_out = clone;
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+i965_shader_acquire_solid_surface (i965_shader_t *shader,
+ union i965_shader_channel *src,
+ cairo_surface_t *surface,
+ const cairo_rectangle_int_t *extents)
+{
+ cairo_image_surface_t *image;
+ void *image_extra;
+ cairo_status_t status;
+ uint32_t argb;
+
+ status = _cairo_surface_acquire_source_image (surface, &image, &image_extra);
+ if (unlikely (status))
+ return status;
+
+ if (image->format != CAIRO_FORMAT_ARGB32) {
+ cairo_surface_t *pixel;
+ cairo_surface_pattern_t pattern;
+
+ /* extract the pixel as argb32 */
+ pixel = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 1, 1);
+ _cairo_pattern_init_for_surface (&pattern, &image->base);
+ cairo_matrix_init_translate (&pattern.base.matrix, extents->x, extents->y);
+ pattern.base.filter = CAIRO_FILTER_NEAREST;
+ status = _cairo_surface_paint (pixel, CAIRO_OPERATOR_SOURCE, &pattern.base, NULL);
+ _cairo_pattern_fini (&pattern.base);
+
+ if (unlikely (status)) {
+ _cairo_surface_release_source_image (surface, image, image_extra);
+ cairo_surface_destroy (pixel);
+ return status;
+ }
+
+ argb = *(uint32_t *) ((cairo_image_surface_t *) pixel)->data;
+ cairo_surface_destroy (pixel);
+ } else {
+ argb = ((uint32_t *) (image->data + extents->y * image->stride))[extents->x];
+ }
+
+ _cairo_surface_release_source_image (surface, image, image_extra);
+
+ if (argb >> 24 == 0)
+ argb = 0;
+
+ src->base.constants[0] = ((argb >> 16) & 0xff) / 255.;
+ src->base.constants[1] = ((argb >> 8) & 0xff) / 255.;
+ src->base.constants[2] = ((argb >> 0) & 0xff) / 255.;
+ src->base.constants[3] = ((argb >> 24) & 0xff) / 255.;
+ src->base.constants_size = 4;
+
+ src->base.content = CAIRO_CONTENT_COLOR_ALPHA;
+ if (CAIRO_ALPHA_IS_OPAQUE(src->base.constants[3]))
+ src->base.content &= ~CAIRO_CONTENT_ALPHA;
+ src->type.fragment = FS_CONSTANT;
+ src->type.vertex = VS_NONE;
+ src->type.pattern = PATTERN_SOLID;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+i965_shader_acquire_surface (i965_shader_t *shader,
+ union i965_shader_channel *src,
+ const cairo_surface_pattern_t *pattern,
+ const cairo_rectangle_int_t *extents)
+{
+ cairo_surface_t *surface, *drm;
+ cairo_matrix_t m;
+ cairo_status_t status;
+ int src_x = 0, src_y = 0;
+
+ assert (src->type.fragment == FS_NONE);
+ drm = surface = pattern->surface;
+
+#if CAIRO_HAS_XCB_SURFACE && CAIRO_HAS_XCB_DRM_FUNCTIONS
+ if (surface->type == CAIRO_SURFACE_TYPE_XCB) {
+ cairo_surface_t *xcb = surface;
+
+ if (xcb->backend->type == CAIRO_INTERNAL_SURFACE_TYPE_SUBSURFACE) {
+ xcb = ((cairo_surface_subsurface_t *) surface)->target;
+ } else if (xcb->backend->type == CAIRO_INTERNAL_SURFACE_TYPE_SNAPSHOT) {
+ xcb = ((cairo_surface_snapshot_t *) surface)->target;
+ }
+
+ /* XXX copy windows (IncludeInferiors) to a pixmap/drm surface
+ * xcb = _cairo_xcb_surface_to_drm (xcb)
+ */
+ xcb = ((cairo_xcb_surface_t *) xcb)->drm;
+ if (xcb != NULL)
+ drm = xcb;
+ }
+#endif
+
+ if (surface->type == CAIRO_SURFACE_TYPE_DRM) {
+ if (surface->backend->type == CAIRO_INTERNAL_SURFACE_TYPE_SUBSURFACE) {
+ drm = ((cairo_surface_subsurface_t *) surface)->target;
+ } else if (surface->backend->type == CAIRO_INTERNAL_SURFACE_TYPE_SNAPSHOT) {
+ drm = ((cairo_surface_snapshot_t *) surface)->target;
+ }
+ }
+
+ src->type.pattern = PATTERN_SURFACE;
+ src->surface.surface = NULL;
+ if (drm->type == CAIRO_SURFACE_TYPE_DRM) {
+ i965_surface_t *s = (i965_surface_t *) drm;
+
+ if (surface->backend->type == CAIRO_INTERNAL_SURFACE_TYPE_SUBSURFACE) {
+ if (s->intel.drm.base.device == shader->target->intel.drm.base.device) {
+ cairo_surface_subsurface_t *sub = (cairo_surface_subsurface_t *) surface;
+ if (s != shader->target) {
+ int x;
+
+ if (to_intel_bo (s->intel.drm.bo)->batch_write_domain)
+ i965_pipelined_flush (i965_device (s));
+
+ src->type.fragment = FS_SURFACE;
+
+ src->base.bo = to_intel_bo (s->intel.drm.bo);
+ src->base.format = s->intel.drm.format;
+ src->base.content = s->intel.drm.base.content;
+ src->base.width = sub->extents.width;
+ src->base.height = sub->extents.height;
+ src->base.stride = s->intel.drm.stride;
+
+ x = sub->extents.x;
+ if (s->intel.drm.format != CAIRO_FORMAT_A8)
+ x *= 4;
+
+ /* XXX tiling restrictions upon offset? */
+ //src->base.offset[0] = s->offset + sub->extents.y * s->intel.drm.stride + x;
+ } else {
+ i965_surface_t *clone;
+ cairo_surface_pattern_t pattern;
+
+ clone = (i965_surface_t *)
+ i965_surface_create_internal ((cairo_drm_device_t *) s->intel.drm.base.device,
+ s->intel.drm.base.content,
+ sub->extents.width,
+ sub->extents.height,
+ I965_TILING_DEFAULT,
+ TRUE);
+ if (unlikely (clone->intel.drm.base.status))
+ return clone->intel.drm.base.status;
+
+ _cairo_pattern_init_for_surface (&pattern, &s->intel.drm.base);
+ pattern.base.filter = CAIRO_FILTER_NEAREST;
+ cairo_matrix_init_translate (&pattern.base.matrix,
+ sub->extents.x, sub->extents.y);
+
+ status = _cairo_surface_paint (&clone->intel.drm.base,
+ CAIRO_OPERATOR_SOURCE,
+ &pattern.base,
+ NULL);
+
+ _cairo_pattern_fini (&pattern.base);
+
+ if (unlikely (status)) {
+ cairo_surface_destroy (&clone->intel.drm.base);
+ return status;
+ }
+
+ i965_pipelined_flush (i965_device (s));
+ src->type.fragment = FS_SURFACE;
+
+ src->base.bo = to_intel_bo (clone->intel.drm.bo);
+ src->base.format = clone->intel.drm.format;
+ src->base.content = clone->intel.drm.base.content;
+ src->base.width = clone->intel.drm.width;
+ src->base.height = clone->intel.drm.height;
+ src->base.stride = clone->intel.drm.stride;
+
+ src->surface.surface = &clone->intel.drm.base;
+ }
+
+ src_x = sub->extents.x;
+ src_y = sub->extents.y;
+ }
+ } else {
+ if (s->intel.drm.base.device == shader->target->intel.drm.base.device) {
+ if (s != shader->target) {
+ if (to_intel_bo (s->intel.drm.bo)->batch_write_domain)
+ i965_pipelined_flush (i965_device (s));
+
+ src->type.fragment = FS_SURFACE;
+
+ src->base.bo = to_intel_bo (s->intel.drm.bo);
+ src->base.format = s->intel.drm.format;
+ src->base.content = s->intel.drm.base.content;
+ src->base.width = s->intel.drm.width;
+ src->base.height = s->intel.drm.height;
+ src->base.stride = s->intel.drm.stride;
+ } else {
+ i965_surface_t *clone;
+ cairo_surface_pattern_t pattern;
+
+ clone = (i965_surface_t *)
+ i965_surface_create_internal ((cairo_drm_device_t *) s->intel.drm.base.device,
+ s->intel.drm.base.content,
+ s->intel.drm.width,
+ s->intel.drm.height,
+ I965_TILING_DEFAULT,
+ TRUE);
+ if (unlikely (clone->intel.drm.base.status))
+ return clone->intel.drm.base.status;
+
+ _cairo_pattern_init_for_surface (&pattern, &s->intel.drm.base);
+ pattern.base.filter = CAIRO_FILTER_NEAREST;
+ status = _cairo_surface_paint (&clone->intel.drm.base,
+ CAIRO_OPERATOR_SOURCE,
+ &pattern.base,
+ NULL);
+
+ _cairo_pattern_fini (&pattern.base);
+
+ if (unlikely (status)) {
+ cairo_surface_destroy (&clone->intel.drm.base);
+ return status;
+ }
+
+ i965_pipelined_flush (i965_device (s));
+ src->type.fragment = FS_SURFACE;
+
+ src->base.bo = to_intel_bo (clone->intel.drm.bo);
+ src->base.format = clone->intel.drm.format;
+ src->base.content = clone->intel.drm.base.content;
+ src->base.width = clone->intel.drm.width;
+ src->base.height = clone->intel.drm.height;
+ src->base.stride = clone->intel.drm.stride;
+
+ src->surface.surface = &clone->intel.drm.base;
+ }
+ }
+ }
+ }
+
+ if (src->type.fragment == FS_NONE) {
+ i965_surface_t *s;
+
+ if (extents->width == 1 && extents->height == 1) {
+ return i965_shader_acquire_solid_surface (shader, src,
+ surface, extents);
+ }
+
+ s = (i965_surface_t *)
+ _cairo_surface_has_snapshot (surface,
+ shader->target->intel.drm.base.backend);
+ if (s != NULL) {
+ i965_device_t *device = i965_device (shader->target);
+ intel_bo_t *bo = to_intel_bo (s->intel.drm.bo);
+
+ if (bo->purgeable &&
+ ! intel_bo_madvise (&device->intel, bo, I915_MADV_WILLNEED))
+ {
+ _cairo_surface_detach_snapshot (&s->intel.drm.base);
+ s = NULL;
+ }
+
+ if (s != NULL)
+ cairo_surface_reference (&s->intel.drm.base);
+ }
+
+ if (s == NULL) {
+ cairo_image_surface_t *image;
+ void *image_extra;
+ cairo_status_t status;
+
+ status = _cairo_surface_acquire_source_image (surface, &image, &image_extra);
+ if (unlikely (status))
+ return status;
+
+ if (image->width < 8192 && image->height < 8192) {
+ status = i965_surface_clone (i965_device (shader->target), image, &s);
+ } else {
+ status = i965_surface_clone_subimage (i965_device (shader->target),
+ image, extents, &s);
+ src_x = -extents->x;
+ src_y = -extents->y;
+ }
+
+ _cairo_surface_release_source_image (surface, image, image_extra);
+
+ if (unlikely (status))
+ return status;
+
+ /* XXX? */
+ //intel_bo_mark_purgeable (to_intel_bo (s->intel.drm.bo), TRUE);
+ }
+
+ src->type.fragment = FS_SURFACE;
+
+ src->base.bo = to_intel_bo (s->intel.drm.bo);
+ src->base.content = s->intel.drm.base.content;
+ src->base.format = s->intel.drm.format;
+ src->base.width = s->intel.drm.width;
+ src->base.height = s->intel.drm.height;
+ src->base.stride = s->intel.drm.stride;
+
+ src->surface.surface = &s->intel.drm.base;
+
+ drm = &s->intel.drm.base;
+ }
+
+ /* XXX transform nx1 or 1xn surfaces to 1D? */
+
+ src->type.vertex = VS_NONE;
+
+ src->base.extend = i965_extend (pattern->base.extend);
+ if (pattern->base.extend == CAIRO_EXTEND_NONE &&
+ extents->x >= 0 && extents->y >= 0 &&
+ extents->x + extents->width <= src->base.width &&
+ extents->y + extents->height <= src->base.height)
+ {
+ /* Convert a wholly contained NONE to a REFLECT as the contiguous sampler
+ * cannot not handle CLAMP_BORDER textures.
+ */
+ src->base.extend = i965_extend (CAIRO_EXTEND_REFLECT);
+ /* XXX also need to check |u,v| < 3 */
+ }
+
+ src->base.filter = i965_filter (pattern->base.filter);
+ if (_cairo_matrix_is_pixel_exact (&pattern->base.matrix))
+ src->base.filter = i965_filter (CAIRO_FILTER_NEAREST);
+
+ /* tweak the src matrix to map from dst to texture coordinates */
+ src->base.matrix = pattern->base.matrix;
+ if (src_x | src_y)
+ cairo_matrix_translate (&src->base.matrix, src_x, src_x);
+ if (src->base.filter == BRW_MAPFILTER_NEAREST)
+ cairo_matrix_translate (&src->base.matrix, NEAREST_BIAS, NEAREST_BIAS);
+ cairo_matrix_init_scale (&m, 1. / src->base.width, 1. / src->base.height);
+ cairo_matrix_multiply (&src->base.matrix, &src->base.matrix, &m);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+cairo_status_t
+i965_shader_acquire_pattern (i965_shader_t *shader,
+ union i965_shader_channel *src,
+ const cairo_pattern_t *pattern,
+ const cairo_rectangle_int_t *extents)
+{
+ switch (pattern->type) {
+ case CAIRO_PATTERN_TYPE_SOLID:
+ return i965_shader_acquire_solid (shader, src,
+ (cairo_solid_pattern_t *) pattern,
+ extents);
+
+ case CAIRO_PATTERN_TYPE_LINEAR:
+ return i965_shader_acquire_linear (shader, src,
+ (cairo_linear_pattern_t *) pattern,
+ extents);
+
+ case CAIRO_PATTERN_TYPE_RADIAL:
+ return i965_shader_acquire_radial (shader, src,
+ (cairo_radial_pattern_t *) pattern,
+ extents);
+
+ case CAIRO_PATTERN_TYPE_SURFACE:
+ return i965_shader_acquire_surface (shader, src,
+ (cairo_surface_pattern_t *) pattern,
+ extents);
+
+ default:
+ ASSERT_NOT_REACHED;
+ return CAIRO_STATUS_SUCCESS;
+ }
+}
+
+static void
+i965_shader_channel_init (union i965_shader_channel *channel)
+{
+ channel->type.vertex = VS_NONE;
+ channel->type.fragment = FS_NONE;
+ channel->type.pattern = PATTERN_NONE;
+
+ channel->base.mode = 0;
+ channel->base.bo = NULL;
+ channel->base.filter = i965_extend (CAIRO_FILTER_NEAREST);
+ channel->base.extend = i965_extend (CAIRO_EXTEND_NONE);
+ channel->base.has_component_alpha = 0;
+ channel->base.constants_size = 0;
+}
+
+void
+i965_shader_init (i965_shader_t *shader,
+ i965_surface_t *dst,
+ cairo_operator_t op)
+{
+ shader->committed = FALSE;
+ shader->device = i965_device (dst);
+ shader->target = dst;
+ shader->op = op;
+ shader->constants_size = 0;
+
+ shader->need_combine = FALSE;
+
+ i965_shader_channel_init (&shader->source);
+ i965_shader_channel_init (&shader->mask);
+ i965_shader_channel_init (&shader->clip);
+ i965_shader_channel_init (&shader->dst);
+}
+
+void
+i965_shader_fini (i965_shader_t *shader)
+{
+ if (shader->source.type.pattern == PATTERN_SURFACE)
+ cairo_surface_destroy (shader->source.surface.surface);
+ if (shader->mask.type.pattern == PATTERN_SURFACE)
+ cairo_surface_destroy (shader->mask.surface.surface);
+ if (shader->clip.type.pattern == PATTERN_SURFACE)
+ cairo_surface_destroy (shader->clip.surface.surface);
+ if (shader->dst.type.pattern == PATTERN_SURFACE)
+ cairo_surface_destroy (shader->dst.surface.surface);
+}
+
+void
+i965_shader_set_clip (i965_shader_t *shader,
+ cairo_clip_t *clip)
+{
+ cairo_surface_t *clip_surface;
+ union i965_shader_channel *channel;
+ i965_surface_t *s;
+
+ clip_surface = _cairo_clip_get_surface (clip, &shader->target->intel.drm.base);
+ assert (clip_surface->status == CAIRO_STATUS_SUCCESS);
+ assert (clip_surface->type == CAIRO_SURFACE_TYPE_DRM);
+ s = (i965_surface_t *) clip_surface;
+
+ if (to_intel_bo (s->intel.drm.bo)->batch_write_domain)
+ i965_pipelined_flush (i965_device (s));
+
+ channel = &shader->clip;
+ channel->type.pattern = PATTERN_BASE;
+ channel->type.vertex = VS_NONE;
+ channel->type.fragment = FS_SURFACE;
+
+ channel->base.bo = to_intel_bo (s->intel.drm.bo);
+ channel->base.content = CAIRO_CONTENT_ALPHA;
+ channel->base.format = CAIRO_FORMAT_A8;
+ channel->base.width = s->intel.drm.width;
+ channel->base.height = s->intel.drm.height;
+ channel->base.stride = s->intel.drm.stride;
+
+ channel->base.extend = i965_extend (CAIRO_EXTEND_NONE);
+ channel->base.filter = i965_filter (CAIRO_FILTER_NEAREST);
+
+ cairo_matrix_init_scale (&shader->clip.base.matrix,
+ 1. / s->intel.drm.width,
+ 1. / s->intel.drm.height);
+
+ cairo_matrix_translate (&shader->clip.base.matrix,
+ NEAREST_BIAS + clip->path->extents.x,
+ NEAREST_BIAS + clip->path->extents.y);
+}
+
+static cairo_bool_t
+i965_shader_check_aperture (i965_shader_t *shader,
+ i965_device_t *device)
+{
+ uint32_t size = device->exec.gtt_size;
+
+ if (shader->target != device->target) {
+ const intel_bo_t *bo = to_intel_bo (shader->target->intel.drm.bo);
+ if (bo->exec == NULL)
+ size += bo->base.size;
+ }
+
+ if (shader->source.base.bo != NULL && shader->source.base.bo != device->source) {
+ const intel_bo_t *bo = to_intel_bo (shader->target->intel.drm.bo);
+ if (bo->exec == NULL)
+ size += bo->base.size;
+ }
+
+ if (shader->mask.base.bo != NULL && shader->mask.base.bo != device->mask) {
+ const intel_bo_t *bo = to_intel_bo (shader->target->intel.drm.bo);
+ if (bo->exec == NULL)
+ size += bo->base.size;
+ }
+
+ if (shader->clip.base.bo != NULL && shader->clip.base.bo != device->clip) {
+ const intel_bo_t *bo = to_intel_bo (shader->target->intel.drm.bo);
+ if (bo->exec == NULL)
+ size += bo->base.size;
+ }
+
+ return size <= device->intel.gtt_avail_size;
+}
+
+static cairo_status_t
+i965_shader_setup_dst (i965_shader_t *shader)
+{
+ union i965_shader_channel *channel;
+ i965_surface_t *s, *clone;
+
+ /* We need to manual blending if we have a clip surface and an unbounded op,
+ * or an extended blend mode.
+ */
+ if (shader->need_combine ||
+ (shader->op < CAIRO_OPERATOR_SATURATE &&
+ (shader->clip.type.fragment == FS_NONE ||
+ _cairo_operator_bounded_by_mask (shader->op))))
+ {
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+ shader->need_combine = TRUE;
+
+ s = shader->target;
+
+ /* we need to allocate a new render target and use the original as a source */
+ clone = (i965_surface_t *)
+ i965_surface_create_internal ((cairo_drm_device_t *) s->intel.drm.base.device,
+ s->intel.drm.base.content,
+ s->intel.drm.width,
+ s->intel.drm.height,
+ I965_TILING_DEFAULT,
+ TRUE);
+ if (unlikely (clone->intel.drm.base.status))
+ return clone->intel.drm.base.status;
+
+ if (to_intel_bo (s->intel.drm.bo)->batch_write_domain)
+ i965_pipelined_flush (i965_device (s));
+
+ channel = &shader->dst;
+
+ channel->type.vertex = VS_NONE;
+ channel->type.fragment = FS_SURFACE;
+ channel->type.pattern = PATTERN_SURFACE;
+
+ /* swap buffer objects */
+ channel->base.bo = to_intel_bo (s->intel.drm.bo);
+ s->intel.drm.bo = ((cairo_drm_surface_t *) clone)->bo;
+ ((cairo_drm_surface_t *) clone)->bo = &channel->base.bo->base;
+
+ channel->base.content = s->intel.drm.base.content;
+ channel->base.format = s->intel.drm.format;
+ channel->base.width = s->intel.drm.width;
+ channel->base.height = s->intel.drm.height;
+ channel->base.stride = s->intel.drm.stride;
+
+ channel->base.filter = i965_filter (CAIRO_FILTER_NEAREST);
+ channel->base.extend = i965_extend (CAIRO_EXTEND_NONE);
+
+ cairo_matrix_init_scale (&channel->base.matrix,
+ 1. / s->intel.drm.width,
+ 1. / s->intel.drm.height);
+ cairo_matrix_translate (&channel->base.matrix,
+ NEAREST_BIAS,
+ NEAREST_BIAS);
+
+ channel->surface.surface = &clone->intel.drm.base;
+
+ s->intel.drm.base.content = clone->intel.drm.base.content;
+ s->intel.drm.format = clone->intel.drm.format;
+ assert (s->intel.drm.width == clone->intel.drm.width);
+ assert (s->intel.drm.height == clone->intel.drm.height);
+ s->intel.drm.stride = clone->intel.drm.stride;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static inline void
+constant_add_float (i965_shader_t *shader, float v)
+{
+ shader->constants[shader->constants_size++] = v;
+}
+
+static inline void
+i965_shader_copy_channel_constants (i965_shader_t *shader,
+ const union i965_shader_channel *channel)
+{
+ if (channel->base.constants_size) {
+ assert (shader->constants_size + channel->base.constants_size < ARRAY_LENGTH (shader->constants));
+
+ memcpy (shader->constants + shader->constants_size,
+ channel->base.constants,
+ sizeof (float) * channel->base.constants_size);
+ shader->constants_size += channel->base.constants_size;
+ }
+}
+
+static void
+i965_shader_setup_channel_constants (i965_shader_t *shader,
+ const union i965_shader_channel *channel)
+{
+ switch (channel->type.fragment) {
+ case FS_NONE:
+ case FS_CONSTANT:
+ /* no plane equations */
+ break;
+
+ case FS_LINEAR:
+ constant_add_float (shader, channel->base.matrix.xx);
+ constant_add_float (shader, channel->base.matrix.xy);
+ constant_add_float (shader, 0);
+ constant_add_float (shader, channel->base.matrix.x0);
+ break;
+
+ case FS_RADIAL:
+ case FS_SURFACE:
+ constant_add_float (shader, channel->base.matrix.xx);
+ constant_add_float (shader, channel->base.matrix.xy);
+ constant_add_float (shader, 0);
+ constant_add_float (shader, channel->base.matrix.x0);
+
+ constant_add_float (shader, channel->base.matrix.yx);
+ constant_add_float (shader, channel->base.matrix.yy);
+ constant_add_float (shader, 0);
+ constant_add_float (shader, channel->base.matrix.y0);
+ break;
+
+ case FS_SPANS:
+ case FS_GLYPHS:
+ /* use pue from SF */
+ break;
+ }
+
+ i965_shader_copy_channel_constants (shader, channel);
+}
+
+static void
+i965_shader_setup_constants (i965_shader_t *shader)
+{
+ i965_shader_setup_channel_constants (shader, &shader->source);
+ i965_shader_setup_channel_constants (shader, &shader->mask);
+ i965_shader_setup_channel_constants (shader, &shader->clip);
+ i965_shader_setup_channel_constants (shader, &shader->dst);
+ assert (shader->constants_size < ARRAY_LENGTH (shader->constants));
+}
+
+/**
+ * Highest-valued BLENDFACTOR used in i965_blend_op.
+ *
+ * This leaves out BRW_BLENDFACTOR_INV_DST_COLOR,
+ * BRW_BLENDFACTOR_INV_CONST_{COLOR,ALPHA},
+ * BRW_BLENDFACTOR_INV_SRC1_{COLOR,ALPHA}
+ */
+#define BRW_BLENDFACTOR_COUNT (BRW_BLENDFACTOR_INV_DST_ALPHA + 1)
+
+static void
+i965_shader_get_blend_cntl (const i965_shader_t *shader,
+ uint32_t *sblend, uint32_t *dblend)
+{
+ static const struct blendinfo {
+ cairo_bool_t dst_alpha;
+ cairo_bool_t src_alpha;
+ uint32_t src_blend;
+ uint32_t dst_blend;
+ } i965_blend_op[] = {
+ /* CAIRO_OPERATOR_CLEAR treat as SOURCE with transparent */
+ {0, 0, BRW_BLENDFACTOR_ONE, BRW_BLENDFACTOR_ZERO},
+ /* CAIRO_OPERATOR_SOURCE */
+ {0, 0, BRW_BLENDFACTOR_ONE, BRW_BLENDFACTOR_ZERO},
+ /* CAIRO_OPERATOR_OVER */
+ {0, 1, BRW_BLENDFACTOR_ONE, BRW_BLENDFACTOR_INV_SRC_ALPHA},
+ /* CAIRO_OPERATOR_IN */
+ {1, 0, BRW_BLENDFACTOR_DST_ALPHA, BRW_BLENDFACTOR_ZERO},
+ /* CAIRO_OPERATOR_OUT */
+ {1, 0, BRW_BLENDFACTOR_INV_DST_ALPHA, BRW_BLENDFACTOR_ZERO},
+ /* CAIRO_OPERATOR_ATOP */
+ {1, 1, BRW_BLENDFACTOR_DST_ALPHA, BRW_BLENDFACTOR_INV_SRC_ALPHA},
+
+ /* CAIRO_OPERATOR_DEST */
+ {0, 0, BRW_BLENDFACTOR_ZERO, BRW_BLENDFACTOR_ONE},
+ /* CAIRO_OPERATOR_DEST_OVER */
+ {1, 0, BRW_BLENDFACTOR_INV_DST_ALPHA, BRW_BLENDFACTOR_ONE},
+ /* CAIRO_OPERATOR_DEST_IN */
+ {0, 1, BRW_BLENDFACTOR_ZERO, BRW_BLENDFACTOR_SRC_ALPHA},
+ /* CAIRO_OPERATOR_DEST_OUT */
+ {0, 1, BRW_BLENDFACTOR_ZERO, BRW_BLENDFACTOR_INV_SRC_ALPHA},
+ /* CAIRO_OPERATOR_DEST_ATOP */
+ {1, 1, BRW_BLENDFACTOR_INV_DST_ALPHA, BRW_BLENDFACTOR_SRC_ALPHA},
+ /* CAIRO_OPERATOR_XOR */
+ {1, 1, BRW_BLENDFACTOR_INV_DST_ALPHA, BRW_BLENDFACTOR_INV_SRC_ALPHA},
+ /* CAIRO_OPERATOR_ADD */
+ {0, 0, BRW_BLENDFACTOR_ONE, BRW_BLENDFACTOR_ONE},
+ };
+ const struct blendinfo *op = &i965_blend_op[shader->op];
+
+ *sblend = op->src_blend;
+ *dblend = op->dst_blend;
+
+ /* If there's no dst alpha channel, adjust the blend op so that we'll treat
+ * it as always 1.
+ */
+ if (shader->target->intel.drm.base.content == CAIRO_CONTENT_COLOR &&
+ op->dst_alpha)
+ {
+ if (*sblend == BRW_BLENDFACTOR_DST_ALPHA)
+ *sblend = BRW_BLENDFACTOR_ONE;
+ else if (*sblend == BRW_BLENDFACTOR_INV_DST_ALPHA)
+ *sblend = BRW_BLENDFACTOR_ZERO;
+ }
+}
+
+static void
+emit_wm_subpans_to_pixels (struct brw_compile *compile,
+ int tmp)
+{
+ /* Inputs:
+ * R1.5 x/y of upper-left pixel of subspan 3
+ * R1.4 x/y of upper-left pixel of subspan 2
+ * R1.3 x/y of upper-left pixel of subspan 1
+ * R1.2 x/y of upper-left pixel of subspan 0
+ *
+ * Outputs:
+ * M1,2: u
+ * M3,4: v
+ *
+ * upper left, upper right, lower left, lower right.
+ */
+
+ /* compute pixel locations for each subspan */
+ brw_set_compression_control (compile, BRW_COMPRESSION_NONE);
+ brw_ADD (compile,
+ brw_vec8_grf (tmp),
+ brw_reg (BRW_GENERAL_REGISTER_FILE, 1, 4,
+ BRW_REGISTER_TYPE_UW,
+ BRW_VERTICAL_STRIDE_2,
+ BRW_WIDTH_4,
+ BRW_HORIZONTAL_STRIDE_0,
+ BRW_SWIZZLE_NOOP,
+ WRITEMASK_XYZW),
+ brw_imm_vf4 (VF_ZERO, VF_ONE, VF_ZERO, VF_ONE));
+ brw_ADD (compile,
+ brw_vec8_grf (tmp+1),
+ brw_reg (BRW_GENERAL_REGISTER_FILE, 1, 8,
+ BRW_REGISTER_TYPE_UW,
+ BRW_VERTICAL_STRIDE_2,
+ BRW_WIDTH_4,
+ BRW_HORIZONTAL_STRIDE_0,
+ BRW_SWIZZLE_NOOP,
+ WRITEMASK_XYZW),
+ brw_imm_vf4 (VF_ZERO, VF_ONE, VF_ZERO, VF_ONE));
+ brw_ADD (compile,
+ brw_vec8_grf (tmp+2),
+ brw_reg (BRW_GENERAL_REGISTER_FILE, 1, 5,
+ BRW_REGISTER_TYPE_UW,
+ BRW_VERTICAL_STRIDE_2,
+ BRW_WIDTH_4,
+ BRW_HORIZONTAL_STRIDE_0,
+ BRW_SWIZZLE_NOOP,
+ WRITEMASK_XYZW),
+ brw_imm_vf4 (VF_ZERO, VF_ZERO, VF_ONE, VF_ONE));
+ brw_ADD (compile,
+ brw_vec8_grf (tmp+3),
+ brw_reg (BRW_GENERAL_REGISTER_FILE, 1, 9,
+ BRW_REGISTER_TYPE_UW,
+ BRW_VERTICAL_STRIDE_2,
+ BRW_WIDTH_4,
+ BRW_HORIZONTAL_STRIDE_0,
+ BRW_SWIZZLE_NOOP,
+ WRITEMASK_XYZW),
+ brw_imm_vf4 (VF_ZERO, VF_ZERO, VF_ONE, VF_ONE));
+ brw_set_compression_control (compile, BRW_COMPRESSION_COMPRESSED);
+}
+
+static void
+emit_wm_affine (struct brw_compile *compile,
+ int tmp, int reg, int msg)
+{
+ emit_wm_subpans_to_pixels (compile, tmp);
+
+ brw_LINE (compile,
+ brw_null_reg (),
+ brw_vec1_grf (reg, 0),
+ brw_vec8_grf (tmp));
+ brw_MAC (compile,
+ brw_message_reg (msg + 1),
+ brw_vec1_grf (reg, 1),
+ brw_vec8_grf (tmp+2));
+
+ brw_LINE (compile,
+ brw_null_reg (),
+ brw_vec1_grf (reg, 4),
+ brw_vec8_grf (tmp));
+ brw_MAC (compile,
+ brw_message_reg (msg + 3),
+ brw_vec1_grf (reg, 5),
+ brw_vec8_grf (tmp+2));
+}
+
+static void
+emit_wm_glyph (struct brw_compile *compile,
+ int tmp, int vue, int msg)
+{
+ emit_wm_subpans_to_pixels (compile, tmp);
+
+ brw_MUL (compile,
+ brw_null_reg (),
+ brw_vec8_grf (tmp),
+ brw_imm_f (1./1024));
+ brw_ADD (compile,
+ brw_message_reg (msg + 1),
+ brw_acc_reg (),
+ brw_vec1_grf (vue, 0));
+
+ brw_MUL (compile,
+ brw_null_reg (),
+ brw_vec8_grf (tmp + 2),
+ brw_imm_f (1./1024));
+ brw_ADD (compile,
+ brw_message_reg (msg + 3),
+ brw_acc_reg (),
+ brw_vec1_grf (vue, 1));
+}
+
+static void
+emit_wm_load_constant (struct brw_compile *compile,
+ int reg,
+ struct brw_reg *result)
+{
+ int n;
+
+ for (n = 0; n < 4; n++) {
+ result[n] = result[n+4] = brw_reg (BRW_GENERAL_REGISTER_FILE, reg, n,
+ BRW_REGISTER_TYPE_F,
+ BRW_VERTICAL_STRIDE_0,
+ BRW_WIDTH_1,
+ BRW_HORIZONTAL_STRIDE_0,
+ BRW_SWIZZLE_XXXX,
+ WRITEMASK_XYZW);
+ }
+}
+
+static void
+emit_wm_load_opacity (struct brw_compile *compile,
+ int reg,
+ struct brw_reg *result)
+{
+ result[0] = result[1] = result[2] = result[3] =
+ result[4] = result[5] = result[6] = result[7] =
+ brw_reg (BRW_GENERAL_REGISTER_FILE, reg, 0,
+ BRW_REGISTER_TYPE_F,
+ BRW_VERTICAL_STRIDE_0,
+ BRW_WIDTH_1,
+ BRW_HORIZONTAL_STRIDE_1,
+ BRW_SWIZZLE_XXXX,
+ WRITEMASK_XYZW);
+}
+
+static void
+emit_wm_load_linear (struct brw_compile *compile,
+ int tmp, int reg, int msg)
+{
+ emit_wm_subpans_to_pixels (compile, tmp);
+
+ brw_LINE (compile,
+ brw_null_reg(),
+ brw_vec1_grf (reg, 0),
+ brw_vec8_grf (tmp));
+ brw_MAC (compile,
+ brw_message_reg(msg + 1),
+ brw_vec1_grf (reg, 1),
+ brw_vec8_grf (tmp + 2));
+}
+
+static void
+emit_wm_load_radial (struct brw_compile *compile,
+ int reg, int msg)
+
+{
+ struct brw_reg c1x = brw_vec1_grf (reg, 0);
+ struct brw_reg c1y = brw_vec1_grf (reg, 1);
+ struct brw_reg minus_r_sq = brw_vec1_grf (reg, 3);
+ struct brw_reg cdx = brw_vec1_grf (reg, 4);
+ struct brw_reg cdy = brw_vec1_grf (reg, 5);
+ struct brw_reg neg_4a = brw_vec1_grf (reg + 1, 0);
+ struct brw_reg inv_2a = brw_vec1_grf (reg + 1, 1);
+
+ struct brw_reg tmp_x = brw_uw16_grf (30, 0);
+ struct brw_reg tmp_y = brw_uw16_grf (28, 0);
+ struct brw_reg det = brw_vec8_grf (22);
+ struct brw_reg b = brw_vec8_grf (20);
+ struct brw_reg c = brw_vec8_grf (18);
+ struct brw_reg pdx = brw_vec8_grf (16);
+ struct brw_reg pdy = brw_vec8_grf (14);
+ struct brw_reg t = brw_message_reg (msg + 1);
+
+ /* cdx = (câx - câx)
+ * cdy = (cây - cây)
+ * dr = râ-râ
+ * pdx = px - câx
+ * pdy = py - cây
+ *
+ * A = cdx² + cdy² - dr²
+ * B = -2·(pdx·cdx + pdy·cdy + râ·dr)
+ * C = pdx² + pdy² - râ²
+ *
+ * t = (-2·B ± â·(B² - 4·A·C)) / 2·A
+ */
+
+ brw_ADD (compile, pdx, vec8 (tmp_x), negate (c1x));
+ brw_ADD (compile, pdy, vec8 (tmp_y), negate (c1y));
+
+ brw_LINE (compile, brw_null_reg (), cdx, pdx);
+ brw_MAC (compile, b, cdy, pdy);
+
+ brw_MUL (compile, brw_null_reg (), pdx, pdx);
+ brw_MAC (compile, c, pdy, pdy);
+ brw_ADD (compile, c, c, minus_r_sq);
+
+ brw_MUL (compile, brw_null_reg (), b, b);
+ brw_MAC (compile, det, neg_4a, c);
+
+ /* XXX use rsqrt like i915?, it's faster and we need to mac anyway */
+ brw_math (compile,
+ det,
+ BRW_MATH_FUNCTION_SQRT,
+ BRW_MATH_SATURATE_NONE,
+ 2,
+ det,
+ BRW_MATH_DATA_VECTOR,
+ BRW_MATH_PRECISION_FULL);
+
+ /* XXX cmp, +- */
+
+ brw_ADD (compile, det, negate (det), negate (b));
+ brw_ADD (compile, det, det, negate (b));
+ brw_MUL (compile, t, det, inv_2a);
+}
+
+static int
+emit_wm_sample (struct brw_compile *compile,
+ union i965_shader_channel *channel,
+ int sampler,
+ int msg_base, int msg_len,
+ int dst,
+ struct brw_reg *result)
+{
+ int response_len, mask;
+
+ if (channel->base.content == CAIRO_CONTENT_ALPHA) {
+ mask = 0x7000;
+ response_len = 2;
+ result[0] = result[1] = result[2] = result[3] = brw_vec8_grf (dst);
+ result[4] = result[5] = result[6] = result[7] = brw_vec8_grf (dst + 1);
+ } else {
+ mask = 0;
+ response_len = 8;
+ result[0] = brw_vec8_grf (dst + 0);
+ result[1] = brw_vec8_grf (dst + 2);
+ result[2] = brw_vec8_grf (dst + 4);
+ result[3] = brw_vec8_grf (dst + 6);
+ result[4] = brw_vec8_grf (dst + 1);
+ result[5] = brw_vec8_grf (dst + 3);
+ result[6] = brw_vec8_grf (dst + 5);
+ result[7] = brw_vec8_grf (dst + 7);
+ }
+
+ brw_set_compression_control (compile, BRW_COMPRESSION_NONE);
+
+ brw_set_mask_control (compile, BRW_MASK_DISABLE);
+ brw_MOV (compile,
+ get_element_ud (brw_vec8_grf (0), 2),
+ brw_imm_ud (mask));
+ brw_set_mask_control (compile, BRW_MASK_ENABLE);
+
+ brw_SAMPLE (compile,
+ brw_uw16_grf (dst, 0),
+ msg_base,
+ brw_uw8_grf (0, 0),
+ sampler + 1, /* binding table */
+ sampler,
+ WRITEMASK_XYZW,
+ BRW_SAMPLER_MESSAGE_SIMD16_SAMPLE,
+ response_len,
+ msg_len,
+ 0 /* eot */);
+
+ brw_set_compression_control (compile, BRW_COMPRESSION_COMPRESSED);
+
+ return response_len;
+}
+
+#define MAX_MSG_REGISTER 16
+
+static void
+emit_wm_load_channel (struct brw_compile *compile,
+ union i965_shader_channel *channel,
+ int *vue,
+ int *cue,
+ int *msg,
+ int *sampler,
+ int *grf,
+ struct brw_reg *result)
+{
+ switch (channel->type.fragment) {
+ case FS_NONE:
+ break;
+
+ case FS_CONSTANT:
+ emit_wm_load_constant (compile, *cue, result);
+ *cue += 1;
+ break;
+
+ case FS_RADIAL:
+ emit_wm_load_radial (compile, *cue, *msg);
+ *cue += 2;
+
+ if (*msg + 3 > MAX_MSG_REGISTER)
+ *msg = 1;
+
+ *grf += emit_wm_sample (compile, channel, *sampler, *msg, 3, *grf, result);
+ *sampler += 1;
+ *msg += 3;
+ break;
+
+ case FS_LINEAR:
+ emit_wm_load_linear (compile, *grf, *cue, *msg);
+ *cue += 1;
+
+ if (*msg + 3 > MAX_MSG_REGISTER)
+ *msg = 1;
+
+ *grf += emit_wm_sample (compile, channel, *sampler, *msg, 3, *grf, result);
+ *sampler += 1;
+ *msg += 3;
+ break;
+
+ case FS_SURFACE:
+ emit_wm_affine (compile, *grf, *cue, *msg);
+ *cue += 2;
+
+ if (*msg + 5 > MAX_MSG_REGISTER)
+ *msg = 1;
+
+ *grf += emit_wm_sample (compile, channel, *sampler, *msg, 5, *grf, result);
+ *sampler += 1;
+ *msg += 5;
+ break;
+
+ case FS_SPANS:
+ emit_wm_load_opacity (compile, *vue, result);
+ *vue += 1;
+ break;
+
+ case FS_GLYPHS:
+ emit_wm_glyph (compile, *grf, *vue, *msg);
+ *vue += 1;
+
+ if (*msg + 5 > MAX_MSG_REGISTER)
+ *msg = 1;
+
+ *grf += emit_wm_sample (compile, channel, *sampler, *msg, 5, *grf, result);
+ *sampler += 1;
+ *msg += 5;
+ break;
+ }
+}
+
+static unsigned long
+i965_wm_kernel_hash (const i965_shader_t *shader)
+{
+ unsigned long hash;
+
+ hash =
+ (shader->source.type.fragment & 0xff) |
+ (shader->mask.type.fragment & 0xff) << 8 |
+ (shader->clip.type.fragment & 0xff) << 16;
+ if (shader->need_combine)
+ hash |= (1 + shader->op) << 24;
+
+ return hash;
+}
+
+static void
+i965_wm_kernel_init (struct i965_wm_kernel *key,
+ const i965_shader_t *shader)
+{
+ key->entry.hash = i965_wm_kernel_hash (shader);
+}
+
+static uint32_t
+i965_shader_const_urb_length (i965_shader_t *shader)
+{
+ const int lengths[] = { 0, 1, 1, 4, 2, 0, 0 };
+ int count = 0; /* 128-bit/16-byte increments */
+
+ count += lengths[shader->source.type.fragment];
+ count += lengths[shader->mask.type.fragment];
+ count += lengths[shader->clip.type.fragment];
+ count += lengths[shader->dst.type.fragment];
+
+ return (count + 1) / 2; /* 256-bit/32-byte increments */
+}
+
+static uint32_t
+i965_shader_pue_length (i965_shader_t *shader)
+{
+ return 1 + (shader->mask.type.vertex != VS_NONE);
+}
+
+static uint32_t
+create_wm_kernel (i965_device_t *device,
+ i965_shader_t *shader,
+ int *num_reg)
+{
+ struct brw_compile compile;
+ struct brw_reg source[8], mask[8], clip[8], dst[8];
+ const uint32_t *program;
+ uint32_t size;
+ int msg, cue, vue, grf, sampler;
+ int i;
+
+ struct i965_wm_kernel key, *cache;
+ cairo_status_t status;
+ uint32_t offset;
+
+ i965_wm_kernel_init (&key, shader);
+ cache = _cairo_hash_table_lookup (device->wm_kernels, &key.entry);
+ if (cache != NULL)
+ return cache->offset;
+
+ brw_compile_init (&compile, device->is_g4x);
+
+ if (key.entry.hash == FS_CONSTANT &&
+ to_intel_bo (shader->target->intel.drm.bo)->tiling)
+ {
+ struct brw_instruction *insn;
+
+ assert (i965_shader_const_urb_length (shader) == 1);
+ brw_MOV (&compile, brw_message4_reg (2), brw_vec4_grf (2, 0));
+ grf = 3;
+
+ brw_push_insn_state (&compile);
+ brw_set_mask_control (&compile, BRW_MASK_DISABLE); /* ? */
+ brw_MOV (&compile,
+ retype (brw_message_reg (1), BRW_REGISTER_TYPE_UD),
+ retype (brw_vec8_grf (1), BRW_REGISTER_TYPE_UD));
+ brw_pop_insn_state (&compile);
+
+ insn = brw_next_instruction (&compile, BRW_OPCODE_SEND);
+ insn->header.predicate_control = 0;
+ insn->header.compression_control = BRW_COMPRESSION_NONE;
+ insn->header.destreg__conditonalmod = 0;
+
+ brw_instruction_set_destination (insn,
+ retype (vec16 (brw_acc_reg ()),
+ BRW_REGISTER_TYPE_UW));
+
+ brw_instruction_set_source0 (insn,
+ retype (brw_vec8_grf (0),
+ BRW_REGISTER_TYPE_UW));
+
+ brw_instruction_set_dp_write_message (insn,
+ 0,
+ BRW_DATAPORT_RENDER_TARGET_WRITE_SIMD16_SINGLE_SOURCE_REPLICATED, /* msg_control */
+ BRW_DATAPORT_WRITE_MESSAGE_RENDER_TARGET_WRITE, /* msg_type */
+ 3,
+ 1, /* pixel scoreboard */
+ 0,
+ TRUE);
+ }
+ else
+ {
+ msg = 1;
+ cue = 2;
+ vue = cue + i965_shader_const_urb_length (shader);
+ grf = vue + i965_shader_pue_length (shader);
+ sampler = 0;
+
+ brw_set_compression_control (&compile, BRW_COMPRESSION_COMPRESSED);
+ emit_wm_load_channel (&compile, &shader->source,
+ &vue, &cue, &msg, &sampler, &grf,
+ source);
+ emit_wm_load_channel (&compile, &shader->mask,
+ &vue, &cue, &msg, &sampler, &grf,
+ mask);
+ emit_wm_load_channel (&compile, &shader->clip,
+ &vue, &cue, &msg, &sampler, &grf,
+ clip);
+ emit_wm_load_channel (&compile, &shader->dst,
+ &vue, &cue, &msg, &sampler, &grf,
+ dst);
+ brw_set_compression_control (&compile, BRW_COMPRESSION_NONE);
+
+ if (shader->need_combine) {
+ if (shader->mask.type.fragment != FS_NONE &&
+ shader->clip.type.fragment != FS_NONE)
+ {
+ for (i = 0; i < 8; i++)
+ brw_MUL (&compile, mask[i], mask[i], clip[i]);
+ }
+
+ /* XXX LERP ! */
+ for (i = 0; i < 8; i++)
+ brw_MOV (&compile, brw_message_reg (2 + i), source[i]);
+ } else {
+ if (shader->mask.type.fragment != FS_NONE) {
+ if (shader->clip.type.fragment != FS_NONE) {
+ for (i = 0; i < 8; i++)
+ brw_MUL (&compile, mask[i], mask[i], clip[i]);
+ }
+
+ for (i = 0; i < 8; i++)
+ brw_MUL (&compile, brw_message_reg (2 + i), source[i], mask[i]);
+ } else {
+ if (shader->clip.type.fragment != FS_NONE) {
+ for (i = 0; i < 8; i++)
+ brw_MUL (&compile, brw_message_reg (2 + i), source[i], clip[i]);
+ } else {
+ for (i = 0; i < 8; i++)
+ brw_MOV (&compile, brw_message_reg (2 + i), source[i]);
+ }
+ }
+ }
+
+ brw_push_insn_state (&compile);
+ brw_set_mask_control (&compile, BRW_MASK_DISABLE); /* ? */
+ brw_MOV (&compile,
+ retype (brw_message_reg (1), BRW_REGISTER_TYPE_UD),
+ retype (brw_vec8_grf (1), BRW_REGISTER_TYPE_UD));
+ brw_pop_insn_state (&compile);
+
+ brw_fb_WRITE (&compile,
+ retype (vec16 (brw_acc_reg ()), BRW_REGISTER_TYPE_UW),
+ 0, /* base reg */
+ retype (brw_vec8_grf (0), BRW_REGISTER_TYPE_UW),
+ 0, /* binding table index */
+ 2 + 8, /* msg length */
+ 0, /* response length */
+ TRUE); /* EOT */
+ }
+
+ program = brw_get_program (&compile, &size);
+ *num_reg = grf;
+
+ i965_stream_align (&device->general, 64);
+ offset = i965_stream_emit (&device->general, program, size);
+
+ cache = _cairo_freelist_alloc (&device->wm_kernel_freelist);
+ if (likely (cache != NULL)) {
+ i965_wm_kernel_init (cache, shader);
+ cache->offset = offset;
+ status = _cairo_hash_table_insert (device->wm_kernels, &cache->entry);
+ if (unlikely (status))
+ _cairo_freelist_free (&device->wm_kernel_freelist, cache);
+ }
+
+ return offset;
+}
+
+static uint32_t
+create_sf_kernel (i965_device_t *device,
+ i965_shader_t *shader)
+{
+ struct brw_compile compile;
+ const uint32_t *program;
+ uint32_t size;
+ int msg_len;
+
+ brw_compile_init (&compile, device->is_g4x);
+
+ switch (shader->mask.type.vertex) {
+ default:
+ case VS_NONE:
+ /* use curb plane eq in WM */
+ msg_len = 1;
+ break;
+
+ case VS_SPANS:
+ /* just a constant opacity */
+ brw_MOV (&compile,
+ brw_message4_reg (1),
+ brw_vec4_grf (3, 0));
+ msg_len = 2;
+ break;
+
+ case VS_GLYPHS:
+ /* an offset+sf into the glyph cache */
+ brw_MOV (&compile,
+ brw_acc_reg (),
+ brw_vec2_grf (3, 0));
+ brw_MAC (&compile,
+ brw_message4_reg (1),
+ negate (brw_vec2_grf (1, 4)),
+ brw_imm_f (1./1024));
+ msg_len = 2;
+ break;
+ }
+
+ brw_urb_WRITE (&compile,
+ brw_null_reg (),
+ 0,
+ brw_vec8_grf (0), /* r0, will be copied to m0 */
+ 0, /* allocate */
+ 1, /* used */
+ msg_len,
+ 0, /* response len */
+ 1, /* eot */
+ 1, /* writes complete */
+ 0, /* offset */
+ BRW_URB_SWIZZLE_NONE);
+
+ program = brw_get_program (&compile, &size);
+
+ i965_stream_align (&device->general, 64);
+ return i965_stream_emit (&device->general, program, size);
+}
+
+static uint32_t
+i965_sf_kernel (const i965_shader_t *shader)
+{
+ return shader->mask.type.vertex;
+}
+
+static void
+i965_sf_state_init (struct i965_sf_state *key,
+ const i965_shader_t *shader)
+{
+ key->entry.hash = i965_sf_kernel (shader);
+}
+
+cairo_bool_t
+i965_sf_state_equal (const void *A, const void *B)
+{
+ const cairo_hash_entry_t *a = A, *b = B;
+ return a->hash == b->hash;
+}
+
+/**
+ * Sets up the SF state pointing at an SF kernel.
+ *
+ * The SF kernel does coord interp: for each attribute,
+ * calculate dA/dx and dA/dy. Hand these interpolation coefficients
+ * back to SF which then hands pixels off to WM.
+ */
+static uint32_t
+gen4_create_sf_state (i965_device_t *device,
+ i965_shader_t *shader)
+{
+ struct brw_sf_unit_state *state;
+ struct i965_sf_state key, *cache;
+ cairo_status_t status;
+ uint32_t offset;
+
+ i965_sf_state_init (&key, shader);
+ if (i965_sf_state_equal (&key, &device->sf_state))
+ return device->sf_state.offset;
+
+ cache = _cairo_hash_table_lookup (device->sf_states, &key.entry);
+ if (cache != NULL) {
+ offset = cache->offset;
+ goto DONE;
+ }
+
+ offset = create_sf_kernel (device, shader);
+
+ state = i965_stream_alloc (&device->general, 32, sizeof (*state));
+ memset (state, 0, sizeof (*state));
+
+ state->thread0.grf_reg_count = BRW_GRF_BLOCKS (3);
+ assert ((offset & 63) == 0);
+ state->thread0.kernel_start_pointer = offset >> 6;
+ state->sf1.single_program_flow = 1;
+ state->thread3.urb_entry_read_length = 1; /* 1 URB per vertex */
+ state->thread3.urb_entry_read_offset = 1;
+ state->thread3.dispatch_grf_start_reg = 3;
+ state->thread4.max_threads = SF_MAX_THREADS - 1;
+ state->thread4.urb_entry_allocation_size = URB_SF_ENTRY_SIZE - 1;
+ state->thread4.nr_urb_entries = URB_SF_ENTRIES;
+ state->sf6.dest_org_vbias = 0x8;
+ state->sf6.dest_org_hbias = 0x8;
+
+ offset = i965_stream_offsetof (&device->general, state);
+
+ cache = _cairo_freelist_alloc (&device->sf_freelist);
+ if (likely (cache != NULL)) {
+ i965_sf_state_init (cache, shader);
+ cache->offset = offset;
+ status = _cairo_hash_table_insert (device->sf_states, &cache->entry);
+ if (unlikely (status))
+ _cairo_freelist_free (&device->sf_freelist, cache);
+ }
+
+ DONE:
+ i965_sf_state_init (&device->sf_state, shader);
+ device->sf_state.offset = offset;
+
+ return offset;
+}
+
+static unsigned long
+i965_shader_sampler_hash (const i965_shader_t *shader)
+{
+ unsigned long hash = 0;
+ unsigned int offset = 0;
+
+ if (shader->source.base.bo != NULL) {
+ hash |= (shader->source.base.filter << offset) |
+ (shader->source.base.extend << (offset + 4));
+ offset += 8;
+ }
+
+ if (shader->mask.base.bo != NULL) {
+ hash |= (shader->mask.base.filter << offset) |
+ (shader->mask.base.extend << (offset + 4));
+ offset += 8;
+ }
+
+ if (shader->clip.base.bo != NULL) {
+ hash |= (shader->clip.base.filter << offset) |
+ (shader->clip.base.extend << (offset + 4));
+ offset += 8;
+ }
+
+ if (shader->dst.base.bo != NULL) {
+ hash |= (shader->dst.base.filter << offset) |
+ (shader->dst.base.extend << (offset + 4));
+ offset += 8;
+ }
+
+ return hash;
+}
+
+static void
+i965_sampler_init (struct i965_sampler *key,
+ const i965_shader_t *shader)
+{
+ key->entry.hash = i965_shader_sampler_hash (shader);
+}
+
+static void
+emit_sampler_channel (i965_device_t *device,
+ const union i965_shader_channel *channel,
+ uint32_t border_color)
+{
+ struct brw_sampler_state *state;
+
+ state = i965_stream_alloc (&device->general, 0, sizeof (*state));
+ memset (state, 0, sizeof (*state));
+
+ state->ss0.lod_preclamp = 1; /* GL mode */
+
+ state->ss0.border_color_mode = BRW_BORDER_COLOR_MODE_LEGACY;
+
+ state->ss0.min_filter = channel->base.filter;
+ state->ss0.mag_filter = channel->base.filter;
+
+ state->ss1.r_wrap_mode = channel->base.extend;
+ state->ss1.s_wrap_mode = channel->base.extend;
+ state->ss1.t_wrap_mode = channel->base.extend;
+
+ assert ((border_color & 31) == 0);
+ state->ss2.border_color_pointer = border_color >> 5;
+}
+
+static uint32_t
+emit_sampler_state_table (i965_device_t *device,
+ i965_shader_t *shader)
+{
+ struct i965_sampler key, *cache;
+ cairo_status_t status;
+ uint32_t offset;
+
+ if (device->border_color_offset == (uint32_t) -1) {
+ struct brw_sampler_legacy_border_color *border_color;
+
+ border_color = i965_stream_alloc (&device->general, 32,
+ sizeof (*border_color));
+ border_color->color[0] = 0; /* R */
+ border_color->color[1] = 0; /* G */
+ border_color->color[2] = 0; /* B */
+ border_color->color[3] = 0; /* A */
+
+ device->border_color_offset = i965_stream_offsetof (&device->general,
+ border_color);
+ } else {
+ i965_sampler_init (&key, shader);
+ cache = _cairo_hash_table_lookup (device->samplers, &key.entry);
+ if (cache != NULL)
+ return cache->offset;
+ }
+
+ i965_stream_align (&device->general, 32);
+ offset = device->general.used;
+ if (shader->source.base.bo != NULL) {
+ emit_sampler_channel (device,
+ &shader->source,
+ device->border_color_offset);
+ }
+ if (shader->mask.base.bo != NULL) {
+ emit_sampler_channel (device,
+ &shader->mask,
+ device->border_color_offset);
+ }
+ if (shader->clip.base.bo != NULL) {
+ emit_sampler_channel (device,
+ &shader->clip,
+ device->border_color_offset);
+ }
+ if (shader->dst.base.bo != NULL) {
+ emit_sampler_channel (device,
+ &shader->dst,
+ device->border_color_offset);
+ }
+
+ cache = _cairo_freelist_alloc (&device->sampler_freelist);
+ if (likely (cache != NULL)) {
+ i965_sampler_init (cache, shader);
+ cache->offset = offset;
+ status = _cairo_hash_table_insert (device->samplers, &cache->entry);
+ if (unlikely (status))
+ _cairo_freelist_free (&device->sampler_freelist, cache);
+ }
+
+ return offset;
+}
+
+static void
+i965_cc_state_init (struct i965_cc_state *key,
+ const i965_shader_t *shader)
+{
+ uint32_t src_blend, dst_blend;
+
+ if (shader->need_combine)
+ src_blend = dst_blend = 0;
+ else
+ i965_shader_get_blend_cntl (shader, &src_blend, &dst_blend);
+
+ key->entry.hash = src_blend | ((dst_blend & 0xffff) << 16);
+}
+
+cairo_bool_t
+i965_cc_state_equal (const void *A, const void *B)
+{
+ const cairo_hash_entry_t *a = A, *b = B;
+ return a->hash == b->hash;
+}
+
+static uint32_t
+cc_state_emit (i965_device_t *device, i965_shader_t *shader)
+{
+ struct brw_cc_unit_state *state;
+ struct i965_cc_state key, *cache;
+ cairo_status_t status;
+ uint32_t src_blend, dst_blend;
+ uint32_t offset;
+
+ i965_cc_state_init (&key, shader);
+ if (i965_cc_state_equal (&key, &device->cc_state))
+ return device->cc_state.offset;
+
+ cache = _cairo_hash_table_lookup (device->cc_states, &key.entry);
+ if (cache != NULL) {
+ offset = cache->offset;
+ goto DONE;
+ }
+
+ if (shader->need_combine)
+ src_blend = dst_blend = 0;
+ else
+ i965_shader_get_blend_cntl (shader, &src_blend, &dst_blend);
+
+ state = i965_stream_alloc (&device->general, 64, sizeof (*state));
+ memset (state, 0, sizeof (*state));
+
+ /* XXX Note errata, need to flush render cache when blend_enable 0 -> 1 */
+ /* XXX 2 source blend */
+ state->cc3.blend_enable = ! shader->need_combine;
+ state->cc5.ia_blend_function = BRW_BLENDFUNCTION_ADD;
+ state->cc5.ia_src_blend_factor = src_blend;
+ state->cc5.ia_dest_blend_factor = dst_blend;
+ state->cc6.blend_function = BRW_BLENDFUNCTION_ADD;
+ state->cc6.clamp_post_alpha_blend = 1;
+ state->cc6.clamp_pre_alpha_blend = 1;
+ state->cc6.src_blend_factor = src_blend;
+ state->cc6.dest_blend_factor = dst_blend;
+
+ offset = i965_stream_offsetof (&device->general, state);
+
+ cache = _cairo_freelist_alloc (&device->cc_freelist);
+ if (likely (cache != NULL)) {
+ i965_cc_state_init (cache, shader);
+ cache->offset = offset;
+ status = _cairo_hash_table_insert (device->cc_states, &cache->entry);
+ if (unlikely (status))
+ _cairo_freelist_free (&device->cc_freelist, cache);
+ }
+
+ DONE:
+ i965_cc_state_init (&device->cc_state, shader);
+ device->cc_state.offset = offset;
+
+ return offset;
+}
+
+static void
+i965_wm_state_init (struct i965_wm_state *key,
+ const i965_shader_t *shader)
+{
+ key->kernel = i965_wm_kernel_hash (shader);
+ key->sampler = i965_shader_sampler_hash (shader);
+
+ key->entry.hash = key->kernel ^ ((key->sampler) << 16 | (key->sampler >> 16));
+}
+
+cairo_bool_t
+i965_wm_state_equal (const void *A, const void *B)
+{
+ const struct i965_wm_state *a = A, *b = B;
+
+ if (a->entry.hash != b->entry.hash)
+ return FALSE;
+
+ return a->kernel == b->kernel && a->sampler == b->sampler;
+}
+
+static int
+i965_shader_binding_table_count (i965_shader_t *shader)
+{
+ int count;
+
+ count = 1;
+ if (shader->source.type.fragment != FS_CONSTANT)
+ count++;
+ switch (shader->mask.type.fragment) {
+ case FS_NONE:
+ case FS_CONSTANT:
+ case FS_SPANS:
+ break;
+ case FS_LINEAR:
+ case FS_RADIAL:
+ case FS_SURFACE:
+ case FS_GLYPHS:
+ count++;
+ }
+ if (shader->clip.type.fragment == FS_SURFACE)
+ count++;
+ if (shader->dst.type.fragment == FS_SURFACE)
+ count++;
+
+ return count;
+}
+
+static uint32_t
+gen4_create_wm_state (i965_device_t *device,
+ i965_shader_t *shader)
+{
+ struct brw_wm_unit_state *state;
+ uint32_t sampler;
+ uint32_t kernel;
+
+ struct i965_wm_state key, *cache;
+ cairo_status_t status;
+ int num_reg;
+
+ i965_wm_state_init (&key, shader);
+ if (i965_wm_state_equal (&key, &device->wm_state))
+ return device->wm_state.offset;
+
+ cache = _cairo_hash_table_lookup (device->wm_states, &key.entry);
+ if (cache != NULL) {
+ device->wm_state = *cache;
+ return cache->offset;
+ }
+
+ kernel = create_wm_kernel (device, shader, &num_reg);
+ sampler = emit_sampler_state_table (device, shader);
+
+ state = i965_stream_alloc (&device->general, 32, sizeof (*state));
+ memset (state, 0, sizeof (*state));
+ state->thread0.grf_reg_count = BRW_GRF_BLOCKS (num_reg);
+ assert ((kernel & 63) == 0);
+ state->thread0.kernel_start_pointer = kernel >> 6;
+
+ state->thread3.dispatch_grf_start_reg = 2;
+
+ state->wm4.sampler_count = 1; /* 1-4 samplers used */
+ assert ((sampler & 31) == 0);
+ state->wm4.sampler_state_pointer = sampler >> 5;
+ if (device->is_g4x)
+ state->wm5.max_threads = PS_MAX_THREADS_CTG - 1;
+ else
+ state->wm5.max_threads = PS_MAX_THREADS_BRW - 1;
+ state->wm5.thread_dispatch_enable = 1;
+
+ if (device->is_g4x) {
+ /* XXX contiguous 32 pixel dispatch */
+ }
+ state->wm5.enable_16_pix = 1;
+ /* 8 pixel dispatch and friends */
+ //state->wm5.early_depth_test = 1;
+
+ state->thread1.binding_table_entry_count = i965_shader_binding_table_count(shader);
+ state->thread3.urb_entry_read_length = i965_shader_pue_length (shader);
+ state->thread3.const_urb_entry_read_length = i965_shader_const_urb_length (shader);
+
+ key.offset = i965_stream_offsetof (&device->general, state);
+
+ cache = _cairo_freelist_alloc (&device->wm_state_freelist);
+ if (likely (cache != NULL)) {
+ *cache = key;
+ status = _cairo_hash_table_insert (device->wm_states, &cache->entry);
+ if (unlikely (status))
+ _cairo_freelist_free (&device->wm_state_freelist, cache);
+ }
+
+ device->wm_state = key;
+ return key.offset;
+}
+
+static uint32_t
+vs_unit_state_emit (i965_device_t *device)
+{
+ if (device->vs_offset == (uint32_t) -1) {
+ struct brw_vs_unit_state *state;
+
+ /* Set up the vertex shader to be disabled (passthrough) */
+ state = i965_stream_alloc (&device->general, 32, sizeof (*state));
+ memset (state, 0, sizeof (*state));
+
+ state->thread4.nr_urb_entries = URB_VS_ENTRIES;
+ state->thread4.urb_entry_allocation_size = URB_VS_ENTRY_SIZE - 1;
+ state->vs6.vert_cache_disable = 1;
+
+ device->vs_offset = i965_stream_offsetof (&device->general, state);
+ }
+
+ return device->vs_offset;
+}
+
+static uint32_t
+i965_get_card_format (cairo_format_t format)
+{
+ switch (format) {
+ case CAIRO_FORMAT_ARGB32:
+ return BRW_SURFACEFORMAT_B8G8R8A8_UNORM;
+ case CAIRO_FORMAT_RGB24:
+ return BRW_SURFACEFORMAT_B8G8R8X8_UNORM;
+ case CAIRO_FORMAT_A8:
+ return BRW_SURFACEFORMAT_A8_UNORM;
+ case CAIRO_FORMAT_A1:
+ default:
+ ASSERT_NOT_REACHED;
+ return 0;
+ }
+}
+
+static uint32_t
+i965_get_dest_format (cairo_format_t format)
+{
+ switch (format) {
+ case CAIRO_FORMAT_ARGB32:
+ case CAIRO_FORMAT_RGB24:
+ return BRW_SURFACEFORMAT_B8G8R8A8_UNORM;
+ case CAIRO_FORMAT_A8:
+ return BRW_SURFACEFORMAT_A8_UNORM;
+ case CAIRO_FORMAT_A1:
+ default:
+ ASSERT_NOT_REACHED;
+ return 0;
+ }
+}
+
+/* XXX silly inline due to compiler bug... */
+static inline void
+i965_stream_add_pending_relocation (i965_stream_t *stream,
+ uint32_t target_offset,
+ uint32_t read_domains,
+ uint32_t write_domain,
+ uint32_t delta)
+{
+ int n;
+
+ n = stream->num_pending_relocations++;
+ assert (n < stream->max_pending_relocations);
+
+ stream->pending_relocations[n].offset = target_offset;
+ stream->pending_relocations[n].read_domains = read_domains;
+ stream->pending_relocations[n].write_domain = write_domain;;
+ stream->pending_relocations[n].delta = delta;
+}
+
+static uint32_t
+emit_surface_state (i965_device_t *device,
+ cairo_bool_t is_target,
+ intel_bo_t *bo,
+ cairo_format_t format,
+ int width, int height, int stride,
+ int type)
+{
+ struct brw_surface_state *state;
+ uint32_t write_domain, read_domains;
+ uint32_t offset;
+
+ state = i965_stream_alloc (&device->surface, 32, sizeof (*state));
+ memset (state, 0, sizeof (*state));
+
+ state->ss0.surface_type = type;
+ if (is_target)
+ state->ss0.surface_format = i965_get_dest_format (format);
+ else
+ state->ss0.surface_format = i965_get_card_format (format);
+
+ state->ss0.data_return_format = BRW_SURFACERETURNFORMAT_FLOAT32;
+ state->ss0.color_blend = 1;
+ if (is_target && device->is_g4x)
+ state->ss0.render_cache_read_mode = 1;
+
+ state->ss1.base_addr = bo->offset;
+
+ state->ss2.height = height - 1;
+ state->ss2.width = width - 1;
+ state->ss3.pitch = stride - 1;
+ state->ss3.tile_walk = bo->tiling == I915_TILING_Y;
+ state->ss3.tiled_surface = bo->tiling != I915_TILING_NONE;
+
+ if (is_target) {
+ read_domains = I915_GEM_DOMAIN_RENDER;
+ write_domain = I915_GEM_DOMAIN_RENDER;
+ } else {
+ read_domains = I915_GEM_DOMAIN_SAMPLER;
+ write_domain = 0;
+ }
+
+ offset = i965_stream_offsetof (&device->surface, state);
+ i965_emit_relocation (device, &device->surface,
+ bo, 0,
+ read_domains, write_domain,
+ offset + offsetof (struct brw_surface_state, ss1.base_addr));
+ return offset;
+}
+
+static uint32_t
+emit_surface_state_for_shader (i965_device_t *device,
+ const union i965_shader_channel *channel)
+{
+ int type = BRW_SURFACE_2D;
+
+ assert (channel->type.fragment != FS_NONE);
+ assert (channel->type.fragment != FS_CONSTANT);
+
+ if (channel->type.fragment != FS_SURFACE)
+ type = BRW_SURFACE_1D;
+
+ return emit_surface_state (device, FALSE,
+ channel->base.bo,
+ channel->base.format,
+ channel->base.width,
+ channel->base.height,
+ channel->base.stride,
+ type);
+}
+
+cairo_bool_t
+i965_wm_binding_equal (const void *A,
+ const void *B)
+{
+ const struct i965_wm_binding *a = A, *b = B;
+
+ if (a->entry.hash != b->entry.hash)
+ return FALSE;
+
+ if (a->size != b->size)
+ return FALSE;
+
+ return memcmp (a->table, b->table, sizeof (uint32_t) * a->size) == 0;
+}
+
+static void
+i965_wm_binding_init (struct i965_wm_binding *state,
+ const uint32_t *table,
+ int size)
+{
+ int n;
+
+ state->entry.hash = size;
+ state->size = size;
+
+ for (n = 0; n < size; n++) {
+ state->table[n] = table[n];
+ state->entry.hash ^= (table[n] << (8 * n)) |
+ (table[n] >> (32 - (8*n)));
+ }
+}
+
+static uint32_t
+emit_binding_table (i965_device_t *device,
+ i965_shader_t *shader)
+{
+ intel_bo_t *bo;
+ struct i965_wm_binding key, *cache;
+ uint32_t *table;
+ int n = 0;
+
+ table = i965_stream_alloc (&device->surface, 32, 5 * sizeof (uint32_t));
+ if (shader->target->stream != device->surface.serial) {
+ shader->target->stream = device->surface.serial;
+ shader->target->offset = emit_surface_state (device,
+ TRUE,
+ to_intel_bo (shader->target->intel.drm.bo),
+ shader->target->intel.drm.format,
+ shader->target->intel.drm.width,
+ shader->target->intel.drm.height,
+ shader->target->intel.drm.stride,
+ BRW_SURFACE_2D);
+ }
+ table[n++] = shader->target->offset;
+
+ bo = shader->source.base.bo;
+ if (bo != NULL) {
+ if (bo->opaque0 != device->surface.serial) {
+ bo->opaque0 = device->surface.serial;
+ bo->opaque1 = emit_surface_state_for_shader (device, &shader->source);
+ }
+ table[n++] = bo->opaque1;
+ }
+
+ bo = shader->mask.base.bo;
+ if (bo != NULL) {
+ if (bo->opaque0 != device->surface.serial) {
+ bo->opaque0 = device->surface.serial;
+ bo->opaque1 = emit_surface_state_for_shader (device, &shader->mask);
+ }
+ table[n++] = bo->opaque1;
+ }
+
+ bo = shader->clip.base.bo;
+ if (bo != NULL) {
+ if (bo->opaque0 != device->surface.serial) {
+ bo->opaque0 = device->surface.serial;
+ bo->opaque1 = emit_surface_state_for_shader (device, &shader->clip);
+ }
+ table[n++] = bo->opaque1;
+ }
+
+ bo = shader->dst.base.bo;
+ if (bo != NULL) {
+ if (bo->opaque0 != device->surface.serial) {
+ bo->opaque0 = device->surface.serial;
+ bo->opaque1 = emit_surface_state_for_shader (device, &shader->dst);
+ }
+ table[n++] = bo->opaque1;
+ }
+
+ i965_wm_binding_init (&key, table, n);
+ key.offset = i965_stream_offsetof (&device->surface, table);
+
+ if (i965_wm_binding_equal (&key, &device->wm_binding)) {
+ device->surface.used = key.offset;
+ return device->wm_binding.offset;
+ }
+
+ cache = _cairo_hash_table_lookup (device->wm_bindings, &key.entry);
+ if (cache != NULL) {
+ device->surface.used = key.offset;
+ key.offset = cache->offset;
+ }
+
+ device->wm_binding = key;
+ return key.offset;
+}
+
+static void
+i965_emit_invariants (i965_device_t *device)
+{
+ OUT_BATCH (BRW_CS_URB_STATE | 0);
+ OUT_BATCH (((URB_CS_ENTRY_SIZE-1) << 4) | (URB_CS_ENTRIES << 0));
+}
+
+static void
+i965_emit_urb_fences (i965_device_t *device)
+{
+ int urb_vs_start, urb_vs_size;
+ int urb_gs_start, urb_gs_size;
+ int urb_clip_start, urb_clip_size;
+ int urb_sf_start, urb_sf_size;
+ int urb_cs_start, urb_cs_size;
+
+ if (device->have_urb_fences)
+ return;
+
+ /* URB fence */
+ urb_vs_start = 0;
+ urb_vs_size = URB_VS_ENTRIES * URB_VS_ENTRY_SIZE;
+ urb_gs_start = urb_vs_start + urb_vs_size;
+ urb_gs_size = URB_GS_ENTRIES * URB_GS_ENTRY_SIZE;
+ urb_clip_start = urb_gs_start + urb_gs_size;
+ urb_clip_size = URB_CLIP_ENTRIES * URB_CLIP_ENTRY_SIZE;
+ urb_sf_start = urb_clip_start + urb_clip_size;
+ urb_sf_size = URB_SF_ENTRIES * URB_SF_ENTRY_SIZE;
+ urb_cs_start = urb_sf_start + urb_sf_size;
+ urb_cs_size = URB_CS_ENTRIES * URB_CS_ENTRY_SIZE;
+
+ /* erratum: URB_FENCE must not cross a 64-byte cache-line */
+ while ((device->batch.used & 63) > 64-12)
+ OUT_BATCH (MI_NOOP);
+ OUT_BATCH (BRW_URB_FENCE |
+ UF0_CS_REALLOC |
+ UF0_SF_REALLOC |
+ UF0_CLIP_REALLOC |
+ UF0_GS_REALLOC |
+ UF0_VS_REALLOC |
+ 1);
+ OUT_BATCH (((urb_clip_start + urb_clip_size) << UF1_CLIP_FENCE_SHIFT) |
+ ((urb_gs_start + urb_gs_size) << UF1_GS_FENCE_SHIFT) |
+ ((urb_vs_start + urb_vs_size) << UF1_VS_FENCE_SHIFT));
+ OUT_BATCH (((urb_cs_start + urb_cs_size) << UF2_CS_FENCE_SHIFT) |
+ ((urb_sf_start + urb_sf_size) << UF2_SF_FENCE_SHIFT));
+
+ device->have_urb_fences = TRUE;
+ device->constants_size = 0;
+}
+
+static void
+i965_emit_base (i965_device_t *device)
+{
+ OUT_BATCH (BRW_STATE_BASE_ADDRESS | 4);
+ if (likely (device->general.num_pending_relocations == 0)) {
+ i965_stream_add_pending_relocation (&device->general,
+ device->batch.used,
+ I915_GEM_DOMAIN_INSTRUCTION, 0,
+ BASE_ADDRESS_MODIFY);
+ }
+ OUT_BATCH (0); /* pending relocation */
+
+ if (likely (device->surface.num_pending_relocations == 0)) {
+ i965_stream_add_pending_relocation (&device->surface,
+ device->batch.used,
+ I915_GEM_DOMAIN_INSTRUCTION, 0,
+ BASE_ADDRESS_MODIFY);
+ }
+ OUT_BATCH (0); /* pending relocation */
+
+ OUT_BATCH (0 | BASE_ADDRESS_MODIFY);
+ /* general state max addr, disabled */
+ OUT_BATCH (0x10000000 | BASE_ADDRESS_MODIFY);
+ /* media object state max addr, disabled */
+ OUT_BATCH (0x10000000 | BASE_ADDRESS_MODIFY);
+}
+
+static void
+i965_emit_vertex_element (i965_device_t *device,
+ i965_shader_t *shader)
+{
+ uint32_t offset;
+ uint32_t type;
+ int nelem;
+
+ type = 0;
+ nelem = 1;
+ if (shader->mask.type.vertex == VS_SPANS ||
+ shader->mask.type.vertex == VS_GLYPHS)
+ {
+ type = shader->mask.type.vertex;
+ nelem++;
+ }
+
+ if (type == device->vertex_type)
+ return;
+ device->vertex_type = type;
+
+ offset = 0;
+
+ OUT_BATCH (BRW_3DSTATE_VERTEX_ELEMENTS | ((2 * nelem) - 1));
+ OUT_BATCH ((0 << VE0_VERTEX_BUFFER_INDEX_SHIFT) |
+ VE0_VALID |
+ (BRW_SURFACEFORMAT_R32G32_FLOAT << VE0_FORMAT_SHIFT) |
+ (offset << VE0_OFFSET_SHIFT));
+ OUT_BATCH ((BRW_VFCOMPONENT_STORE_SRC << VE1_VFCOMPONENT_0_SHIFT) |
+ (BRW_VFCOMPONENT_STORE_SRC << VE1_VFCOMPONENT_1_SHIFT) |
+ (BRW_VFCOMPONENT_STORE_0 << VE1_VFCOMPONENT_2_SHIFT) |
+ (BRW_VFCOMPONENT_STORE_1_FLT << VE1_VFCOMPONENT_3_SHIFT) |
+ (4 << VE1_DESTINATION_ELEMENT_OFFSET_SHIFT));
+ offset += 8;
+
+ assert (shader->source.type.vertex == VS_NONE);
+ switch (shader->mask.type.vertex) {
+ default:
+ case VS_NONE:
+ break;
+
+ case VS_SPANS:
+ OUT_BATCH((0 << VE0_VERTEX_BUFFER_INDEX_SHIFT) |
+ VE0_VALID |
+ (BRW_SURFACEFORMAT_R32_FLOAT << VE0_FORMAT_SHIFT) |
+ (offset << VE0_OFFSET_SHIFT));
+ OUT_BATCH((BRW_VFCOMPONENT_STORE_SRC << VE1_VFCOMPONENT_0_SHIFT) |
+ (BRW_VFCOMPONENT_NOSTORE << VE1_VFCOMPONENT_1_SHIFT) |
+ (BRW_VFCOMPONENT_NOSTORE << VE1_VFCOMPONENT_2_SHIFT) |
+ (BRW_VFCOMPONENT_NOSTORE << VE1_VFCOMPONENT_3_SHIFT) |
+ (8 << VE1_DESTINATION_ELEMENT_OFFSET_SHIFT));
+
+ offset += 4;
+ break;
+
+ case VS_GLYPHS:
+ OUT_BATCH((0 << VE0_VERTEX_BUFFER_INDEX_SHIFT) |
+ VE0_VALID |
+ (BRW_SURFACEFORMAT_R16G16_FLOAT << VE0_FORMAT_SHIFT) |
+ (offset << VE0_OFFSET_SHIFT));
+ OUT_BATCH((BRW_VFCOMPONENT_STORE_SRC << VE1_VFCOMPONENT_0_SHIFT) |
+ (BRW_VFCOMPONENT_STORE_SRC << VE1_VFCOMPONENT_1_SHIFT) |
+ (BRW_VFCOMPONENT_NOSTORE << VE1_VFCOMPONENT_2_SHIFT) |
+ (BRW_VFCOMPONENT_NOSTORE << VE1_VFCOMPONENT_3_SHIFT) |
+ (8 << VE1_DESTINATION_ELEMENT_OFFSET_SHIFT));
+
+ offset += 4;
+ break;
+ }
+ assert (shader->clip.type.vertex == VS_NONE);
+ assert (shader->dst.type.vertex == VS_NONE);
+
+ device->vertex_size = offset;
+ i965_stream_align (&device->vertex, device->vertex_size);
+ device->vertex.committed = device->vertex.used;
+
+ device->rectangle_size = 3 * offset;
+}
+
+static cairo_bool_t
+i965_shader_needs_surface_update (const i965_shader_t *shader,
+ const i965_device_t *device)
+{
+ return device->target != shader->target || shader->target->stream == 0 ||
+ (shader->source.base.bo != NULL && device->source != shader->source.base.bo) ||
+ (shader->mask.base.bo != NULL && device->mask != shader->mask.base.bo) ||
+ (shader->clip.base.bo != NULL && device->clip != shader->clip.base.bo);
+}
+
+static cairo_bool_t
+i965_shader_needs_constants_update (const i965_shader_t *shader,
+ const i965_device_t *device)
+{
+ if (shader->constants_size == 0)
+ return FALSE;
+
+ if (device->constants_size != shader->constants_size)
+ return TRUE;
+
+ return memcmp (device->constants,
+ shader->constants,
+ sizeof (float) * shader->constants_size);
+}
+
+static cairo_bool_t
+i965_shader_needs_state_update (const i965_shader_t *shader,
+ const i965_device_t *device)
+{
+ union {
+ struct i965_sf_state sf;
+ struct i965_wm_state wm;
+ struct i965_cc_state cc;
+ } state;
+
+ i965_sf_state_init (&state.sf, shader);
+ if (! i965_sf_state_equal (&state.sf, &device->sf_state))
+ return TRUE;
+
+ i965_wm_state_init (&state.wm, shader);
+ if (! i965_wm_state_equal (&state.wm, &device->wm_state))
+ return TRUE;
+
+ i965_cc_state_init (&state.cc, shader);
+ if (! i965_cc_state_equal (&state.cc, &device->cc_state))
+ return TRUE;
+
+ return FALSE;
+}
+
+static void
+i965_emit_composite (i965_device_t *device,
+ i965_shader_t *shader)
+{
+ uint32_t draw_rectangle;
+
+ if (i965_shader_needs_surface_update (shader, device)) {
+ /* Binding table pointers */
+ OUT_BATCH (BRW_3DSTATE_BINDING_TABLE_POINTERS | 4);
+ OUT_BATCH (0); /* vs */
+ OUT_BATCH (0); /* gs */
+ OUT_BATCH (0); /* clip */
+ OUT_BATCH (0); /* sf */
+ /* Only the PS uses the binding table */
+ OUT_BATCH (emit_binding_table (device, shader));
+
+ device->target = shader->target;
+ device->source = shader->source.base.bo;
+ device->mask = shader->mask.base.bo;
+ device->clip = shader->clip.base.bo;
+ }
+
+ /* The drawing rectangle clipping is always on. Set it to values that
+ * shouldn't do any clipping.
+ */
+ draw_rectangle = DRAW_YMAX (shader->target->intel.drm.height - 1) |
+ DRAW_XMAX (shader->target->intel.drm.width - 1);
+ if (draw_rectangle != device->draw_rectangle) {
+ OUT_BATCH (BRW_3DSTATE_DRAWING_RECTANGLE | 2);
+ OUT_BATCH (0x00000000); /* ymin, xmin */
+ OUT_BATCH (draw_rectangle);
+ OUT_BATCH (0x00000000); /* yorigin, xorigin */
+ device->draw_rectangle = draw_rectangle;
+ }
+
+ /* skip the depth buffer */
+ /* skip the polygon stipple */
+ /* skip the polygon stipple offset */
+ /* skip the line stipple */
+
+ /* Set the pointers to the 3d pipeline state */
+ if (i965_shader_needs_state_update (shader, device)) {
+ OUT_BATCH (BRW_3DSTATE_PIPELINED_POINTERS | 5);
+ OUT_BATCH (vs_unit_state_emit (device));
+ OUT_BATCH (BRW_GS_DISABLE);
+ OUT_BATCH (BRW_CLIP_DISABLE);
+ OUT_BATCH (gen4_create_sf_state (device, shader));
+ OUT_BATCH (gen4_create_wm_state (device, shader));
+ OUT_BATCH (cc_state_emit (device, shader));
+
+ /* Once the units are initialized, we need to setup the fences */
+ i965_emit_urb_fences (device);
+ }
+
+ if (i965_shader_needs_constants_update (shader, device)) {
+ uint32_t size = (sizeof (float) * shader->constants_size + 63) & -64;
+
+ /* XXX reuse clear/black/white
+ * ht!
+ */
+
+ /* XXX CONSTANT_BUFFER Address Offset Disable? INSTPM? */
+
+ assert (size <= 64 * URB_CS_ENTRY_SIZE);
+ assert (((sizeof (float) * shader->constants_size + 31) & -32) == 32 * i965_shader_const_urb_length (shader));
+
+ OUT_BATCH (BRW_CONSTANT_BUFFER | (1 << 8));
+ assert ((device->constant.used & 63) == 0);
+ i965_stream_add_pending_relocation (&device->constant,
+ device->batch.used,
+ I915_GEM_DOMAIN_INSTRUCTION, 0,
+ device->constant.used + size / 64 - 1);
+ OUT_BATCH (0); /* pending relocation */
+
+ device->constants = i965_stream_alloc (&device->constant, 0, size);
+ memcpy (device->constants, shader->constants, size);
+ device->constants_size = shader->constants_size;
+ }
+
+ i965_emit_vertex_element (device, shader);
+}
+
+void
+i965_flush_vertices (i965_device_t *device)
+{
+ int vertex_count, vertex_start;
+
+ if (device->vertex.used == device->vertex.committed)
+ return;
+
+ vertex_start = device->vertex.committed / device->vertex_size;
+ vertex_count =
+ (device->vertex.used - device->vertex.committed) / device->vertex_size;
+
+ assert (vertex_count);
+
+ if (device->vertex_size != device->last_vertex_size) {
+ i965_stream_add_pending_relocation (&device->vertex,
+ device->batch.used + 8,
+ I915_GEM_DOMAIN_VERTEX, 0,
+ 0);
+
+ OUT_BATCH (BRW_3DSTATE_VERTEX_BUFFERS | 3);
+ OUT_BATCH ((0 << VB0_BUFFER_INDEX_SHIFT) |
+ VB0_VERTEXDATA |
+ (device->vertex_size << VB0_BUFFER_PITCH_SHIFT));
+ OUT_BATCH (0); /* pending relocation */
+ OUT_BATCH (0);
+ OUT_BATCH (0);
+ device->last_vertex_size = device->vertex_size;
+ }
+
+ OUT_BATCH (BRW_3DPRIMITIVE |
+ BRW_3DPRIMITIVE_VERTEX_SEQUENTIAL |
+ (_3DPRIM_RECTLIST << BRW_3DPRIMITIVE_TOPOLOGY_SHIFT) |
+ (0 << 9) |
+ 4);
+ OUT_BATCH (vertex_count); /* vertex count per instance */
+ OUT_BATCH (vertex_start); /* start vertex offset */
+ OUT_BATCH (1); /* single instance */
+ OUT_BATCH (0);
+ OUT_BATCH (0);
+
+ device->vertex.committed = device->vertex.used;
+
+#if 1
+ OUT_BATCH (MI_FLUSH);
+#endif
+}
+
+void
+i965_finish_vertices (i965_device_t *device)
+{
+ cairo_status_t status;
+
+ i965_flush_vertices (device);
+
+ i965_stream_commit (device, &device->vertex);
+
+ if (! i965_shader_check_aperture (device->shader, device)) {
+ status = i965_device_flush (device);
+ if (unlikely (status))
+ longjmp (device->shader->unwind, status);
+
+ status = i965_shader_commit (device->shader, device);
+ assert (status == CAIRO_STATUS_SUCCESS);
+ }
+
+ device->last_vertex_size = 0;
+}
+
+static cairo_bool_t
+i965_shader_needs_update (const i965_shader_t *shader,
+ const i965_device_t *device)
+{
+ if (i965_shader_needs_surface_update (shader, device))
+ return TRUE;
+
+ if (i965_shader_needs_constants_update (shader, device))
+ return TRUE;
+
+ return i965_shader_needs_state_update (shader, device);
+}
+
+static void
+i965_shader_reduce (i965_shader_t *shader,
+ const i965_device_t *device)
+{
+ if (shader->op == CAIRO_OPERATOR_OVER &&
+ (i965_wm_kernel_hash (shader) & ~0xff) == 0 &&
+ (shader->source.base.content & CAIRO_CONTENT_ALPHA) == 0)
+ {
+ shader->op = CAIRO_OPERATOR_SOURCE;
+ }
+}
+
+cairo_status_t
+i965_shader_commit (i965_shader_t *shader,
+ i965_device_t *device)
+{
+ cairo_status_t status;
+
+ if (! shader->committed) {
+ device->shader = shader;
+
+ status = i965_shader_setup_dst (shader);
+ if (unlikely (status))
+ return status;
+
+ i965_shader_setup_constants (shader);
+ i965_shader_reduce (shader, device);
+
+ if ((status = setjmp (shader->unwind)))
+ return status;
+
+ shader->committed = TRUE;
+ }
+
+ if (! i965_shader_needs_update (shader, device))
+ return CAIRO_STATUS_SUCCESS;
+
+ /* XXX too many guestimates about likely maximum sizes */
+recheck:
+ if (device->batch.used + 128 > device->batch.size ||
+ ! i965_shader_check_aperture (shader, device))
+ {
+ status = i965_device_flush (device);
+ if (unlikely (status))
+ longjmp (shader->unwind, status);
+ }
+
+ i965_flush_vertices (device);
+
+ if (unlikely (device->surface.used + 128 > device->surface.size ||
+ device->surface.num_relocations + 4 > device->surface.max_relocations))
+ {
+ i965_stream_commit (device, &device->surface);
+ goto recheck;
+ }
+
+ if (unlikely (device->constant.used + sizeof (device->constants) > device->constant.size ||
+ device->constant.num_pending_relocations == device->constant.max_pending_relocations))
+ {
+ i965_stream_commit (device, &device->constant);
+ goto recheck;
+ }
+
+ if (unlikely (device->general.used + 512 > device->general.size)) {
+ i965_stream_commit (device, &device->general);
+ i965_general_state_reset (device);
+ goto recheck;
+ }
+
+ if (unlikely (device->batch.used == 0))
+ i965_emit_invariants (device);
+
+ if (unlikely (device->surface.num_pending_relocations == 0 ||
+ device->general.num_pending_relocations == 0))
+ {
+ i965_emit_base (device);
+ }
+
+ i965_emit_composite (device, shader);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+void
+i965_clipped_vertices (i965_device_t *device,
+ struct i965_vbo *vbo,
+ cairo_region_t *clip_region)
+{
+ int i, num_rectangles, size;
+ cairo_status_t status;
+
+ if (vbo->count == 0)
+ return;
+
+ num_rectangles = cairo_region_num_rectangles (clip_region);
+ assert (num_rectangles);
+
+ if (vbo->next ||
+ vbo->count * device->vertex_size + device->vertex.used > device->vertex.size)
+ {
+ i965_finish_vertices (device);
+
+ size = device->rectangle_size;
+ do {
+ for (i = 0; i < num_rectangles; i++) {
+ cairo_rectangle_int_t rect;
+
+ cairo_region_get_rectangle (clip_region, i, &rect);
+
+ if (unlikely (device->vertex.used + size > device->vertex.size ||
+ device->batch.used + 64 > device->batch.size ||
+ ! i965_shader_check_aperture (device->shader, device)))
+ {
+ status = i965_device_flush (device);
+ if (unlikely (status))
+ longjmp (device->shader->unwind, status);
+
+ status = i965_shader_commit (device->shader, device);
+ assert (status == CAIRO_STATUS_SUCCESS);
+ }
+
+ i965_emit_relocation (device, &device->batch,
+ vbo->bo, 0,
+ I915_GEM_DOMAIN_VERTEX, 0,
+ device->batch.used + 8);
+
+ OUT_BATCH (BRW_3DSTATE_VERTEX_BUFFERS | 3);
+ OUT_BATCH ((0 << VB0_BUFFER_INDEX_SHIFT) |
+ VB0_VERTEXDATA |
+ (device->vertex_size << VB0_BUFFER_PITCH_SHIFT));
+ OUT_BATCH (vbo->bo->offset);
+ OUT_BATCH (0);
+ OUT_BATCH (0);
+
+ /* XXX scissor? */
+ OUT_BATCH (BRW_3DSTATE_DRAWING_RECTANGLE | 2);
+ OUT_BATCH (DRAW_YMIN (rect.y) | DRAW_XMIN (rect.x));
+ OUT_BATCH (DRAW_YMAX (rect.y + rect.height - 1) |
+ DRAW_XMIN (rect.x + rect.width - 1));
+ OUT_BATCH (0x00000000); /* yorigin, xorigin */
+
+ OUT_BATCH (BRW_3DPRIMITIVE |
+ BRW_3DPRIMITIVE_VERTEX_SEQUENTIAL |
+ (_3DPRIM_RECTLIST << BRW_3DPRIMITIVE_TOPOLOGY_SHIFT) |
+ (0 << 9) |
+ 4);
+ OUT_BATCH (vbo->count); /* vertex count per instance */
+ OUT_BATCH (0); /* start vertex offset */
+ OUT_BATCH (1); /* single instance */
+ OUT_BATCH (0);
+ OUT_BATCH (0);
+ }
+ } while ((vbo = vbo->next) != NULL);
+ assert (device->last_vertex_size == 0);
+ } else {
+ int vertex_start, vertex_count;
+ void *ptr;
+
+ vertex_start = device->vertex.committed / device->vertex_size;
+ vertex_count = vbo->count;
+
+ size = vertex_count * device->vertex_size;
+ ptr = intel_bo_map (&device->intel, vbo->bo);
+ memcpy (device->vertex.data + device->vertex.used, ptr, size);
+ intel_bo_unmap (vbo->bo);
+ device->vertex.committed = device->vertex.used += size;
+
+ for (i = 0; i < num_rectangles; i++) {
+ cairo_rectangle_int_t rect;
+
+ cairo_region_get_rectangle (clip_region, i, &rect);
+
+ /* XXX scissor? */
+ OUT_BATCH (BRW_3DSTATE_DRAWING_RECTANGLE | 2);
+ OUT_BATCH (DRAW_YMIN (rect.y) | DRAW_XMIN (rect.x));
+ OUT_BATCH (DRAW_YMAX (rect.y + rect.height - 1) |
+ DRAW_XMIN (rect.x + rect.width - 1));
+ OUT_BATCH (0x00000000); /* yorigin, xorigin */
+
+ OUT_BATCH (BRW_3DPRIMITIVE |
+ BRW_3DPRIMITIVE_VERTEX_SEQUENTIAL |
+ (_3DPRIM_RECTLIST << BRW_3DPRIMITIVE_TOPOLOGY_SHIFT) |
+ (0 << 9) |
+ 4);
+ OUT_BATCH (vertex_count); /* vertex count per instance */
+ OUT_BATCH (vertex_start); /* start vertex offset */
+ OUT_BATCH (1); /* single instance */
+ OUT_BATCH (0);
+ OUT_BATCH (0);
+ }
+ }
+
+ device->draw_rectangle = 0;
+}
diff --git a/src/drm/cairo-drm-i965-spans.c b/src/drm/cairo-drm-i965-spans.c
new file mode 100644
index 0000000..9cf6d00
--- /dev/null
+++ b/src/drm/cairo-drm-i965-spans.c
@@ -0,0 +1,408 @@
+/* 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 Red Hat, Inc.
+ *
+ * Contributor(s):
+ * Chris Wilson <chris at chris-wilson.co.uk>
+ */
+
+#include "cairoint.h"
+
+#include "cairo-composite-rectangles-private.h"
+#include "cairo-boxes-private.h"
+#include "cairo-error-private.h"
+#include "cairo-drm-i965-private.h"
+
+/* Operates in either immediate or retained mode.
+ * When given a clip region we record the sequence of vbo and then
+ * replay them for each clip rectangle, otherwise we simply emit
+ * the vbo straight into the command stream.
+ */
+
+typedef struct _i965_spans i965_spans_t;
+
+typedef float *
+(*i965_get_rectangle_func_t) (i965_spans_t *spans);
+
+struct _i965_spans {
+ cairo_span_renderer_t renderer;
+
+ i965_device_t *device;
+
+ int xmin, xmax;
+ cairo_bool_t is_bounded;
+ const cairo_rectangle_int_t *extents;
+
+ i965_get_rectangle_func_t get_rectangle;
+ i965_shader_t shader;
+
+ cairo_region_t *clip_region;
+
+ struct i965_vbo head, *tail;
+
+ unsigned int vbo_offset;
+ float *vbo_base;
+};
+
+static float *
+i965_spans_emit_rectangle (i965_spans_t *spans)
+{
+ return i965_add_rectangle (spans->device);
+}
+
+static float *
+i965_spans_accumulate_rectangle (i965_spans_t *spans)
+{
+ float *vertices;
+ uint32_t size;
+
+ size = spans->device->rectangle_size;
+ if (unlikely (spans->vbo_offset + size > I965_VERTEX_SIZE)) {
+ struct i965_vbo *vbo;
+
+ intel_bo_unmap (spans->tail->bo);
+
+ vbo = malloc (sizeof (struct i965_vbo));
+ if (unlikely (vbo == NULL)) {
+ /* throw error! */
+ }
+
+ spans->tail->next = vbo;
+ spans->tail = vbo;
+
+ vbo->next = NULL;
+ vbo->bo = intel_bo_create (&spans->device->intel, I965_VERTEX_SIZE, FALSE);
+ vbo->count = 0;
+
+ spans->vbo_offset = 0;
+ spans->vbo_base = intel_bo_map (&spans->device->intel, vbo->bo);
+ }
+
+ vertices = spans->vbo_base + spans->vbo_offset;
+ spans->vbo_offset += size;
+ spans->tail->count += 3;
+
+ return vertices;
+}
+
+static void
+i965_span_rectangle (i965_spans_t *spans,
+ int x0, int x1, int y0, int y1,
+ int alpha)
+{
+ float *vertices;
+ float a = alpha / 255.;
+
+ vertices = spans->get_rectangle (spans);
+
+ *vertices++ = x1;
+ *vertices++ = y1;
+ *vertices++ = a;
+
+ *vertices++ = x0;
+ *vertices++ = y1;
+ *vertices++ = a;
+
+ *vertices++ = x0;
+ *vertices++ = y0;
+ *vertices++ = a;
+}
+
+static cairo_status_t
+i965_bounded_spans_mono (void *abstract_renderer,
+ int y, int height,
+ const cairo_half_open_span_t *half,
+ unsigned num_spans)
+{
+ i965_spans_t *spans = abstract_renderer;
+
+ if (num_spans == 0)
+ return CAIRO_STATUS_SUCCESS;
+
+ do {
+ if (half[0].coverage >= 128) {
+ i965_span_rectangle (spans,
+ half[0].x, half[1].x,
+ y, y + height,
+ 255);
+ }
+ half++;
+ } while (--num_spans > 1);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+i965_bounded_spans (void *abstract_renderer,
+ int y, int height,
+ const cairo_half_open_span_t *half,
+ unsigned num_spans)
+{
+ i965_spans_t *spans = abstract_renderer;
+
+ if (num_spans == 0)
+ return CAIRO_STATUS_SUCCESS;
+
+ do {
+ if (half[0].coverage) {
+ i965_span_rectangle (spans,
+ half[0].x, half[1].x,
+ y, y + height,
+ half[0].coverage);
+ }
+ half++;
+ } while (--num_spans > 1);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+i965_unbounded_spans (void *abstract_renderer,
+ int y, int height,
+ const cairo_half_open_span_t *half,
+ unsigned num_spans)
+{
+ i965_spans_t *spans = abstract_renderer;
+
+ if (num_spans == 0) {
+ i965_span_rectangle (spans,
+ spans->xmin, spans->xmax,
+ y, y + height,
+ 0);
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+ if (half[0].x != spans->xmin) {
+ i965_span_rectangle (spans,
+ spans->xmin, half[0].x,
+ y, y + height,
+ 0);
+ }
+
+ do {
+ i965_span_rectangle (spans,
+ half[0].x, half[1].x,
+ y, y + height,
+ half[0].coverage);
+ half++;
+ } while (--num_spans > 1);
+
+ if (half[0].x != spans->xmax) {
+ i965_span_rectangle (spans,
+ half[0].x, spans->xmax,
+ y, y + height,
+ 0);
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+i965_unbounded_spans_mono (void *abstract_renderer,
+ int y, int height,
+ const cairo_half_open_span_t *half,
+ unsigned num_spans)
+{
+ i965_spans_t *spans = abstract_renderer;
+
+ if (num_spans == 0) {
+ i965_span_rectangle (spans,
+ spans->xmin, spans->xmax,
+ y, y + height,
+ 0);
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+ if (half[0].x != spans->xmin) {
+ i965_span_rectangle (spans,
+ spans->xmin, half[0].x,
+ y, y + height,
+ 0);
+ }
+
+ do {
+ int alpha = 0;
+ if (half[0].coverage >= 128)
+ alpha = 255;
+ i965_span_rectangle (spans,
+ half[0].x, half[1].x,
+ y, y + height,
+ alpha);
+ half++;
+ } while (--num_spans > 1);
+
+ if (half[0].x != spans->xmax) {
+ i965_span_rectangle (spans,
+ half[0].x, spans->xmax,
+ y, y + height,
+ 0);
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+i965_spans_init (i965_spans_t *spans,
+ i965_surface_t *dst,
+ cairo_operator_t op,
+ const cairo_pattern_t *pattern,
+ cairo_antialias_t antialias,
+ cairo_clip_t *clip,
+ const cairo_composite_rectangles_t *extents)
+{
+ cairo_status_t status;
+
+ spans->device = i965_device (dst);
+ i965_shader_init (&spans->shader, dst, op);
+
+ spans->is_bounded = extents->is_bounded;
+ if (extents->is_bounded) {
+ if (antialias == CAIRO_ANTIALIAS_NONE)
+ spans->renderer.render_rows = i965_bounded_spans_mono;
+ else
+ spans->renderer.render_rows = i965_bounded_spans;
+
+ spans->extents = &extents->bounded;
+ } else {
+ if (antialias == CAIRO_ANTIALIAS_NONE)
+ spans->renderer.render_rows = i965_unbounded_spans_mono;
+ else
+ spans->renderer.render_rows = i965_unbounded_spans;
+
+ spans->extents = &extents->unbounded;
+ }
+ spans->xmin = spans->extents->x;
+ spans->xmax = spans->extents->x + spans->extents->width;
+
+ spans->clip_region = NULL;
+ if (clip != NULL) {
+ cairo_region_t *clip_region = NULL;
+
+ status = _cairo_clip_get_region (clip, &clip_region);
+ assert (status == CAIRO_STATUS_SUCCESS || status == CAIRO_INT_STATUS_UNSUPPORTED);
+
+ if (clip_region != NULL && cairo_region_num_rectangles (clip_region) == 1)
+ clip_region = NULL;
+
+ spans->clip_region = clip_region;
+ if (status == CAIRO_INT_STATUS_UNSUPPORTED)
+ i965_shader_set_clip (&spans->shader, clip);
+ }
+
+ spans->head.next = NULL;
+ spans->head.bo = NULL;
+ spans->head.count = 0;
+ spans->tail = &spans->head;
+
+ if (spans->clip_region == NULL) {
+ spans->get_rectangle = i965_spans_emit_rectangle;
+ } else {
+ spans->get_rectangle = i965_spans_accumulate_rectangle;
+ spans->head.bo = intel_bo_create (&spans->device->intel,
+ I965_VERTEX_SIZE, FALSE);
+ if (unlikely (spans->head.bo == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+ spans->vbo_base = intel_bo_map (&spans->device->intel, spans->head.bo);
+ }
+ spans->vbo_offset = 0;
+
+ return i965_shader_acquire_pattern (&spans->shader,
+ &spans->shader.source,
+ pattern, &extents->bounded);
+}
+
+static void
+i965_spans_fini (i965_spans_t *spans)
+{
+ i965_shader_fini (&spans->shader);
+
+ if (spans->head.bo != NULL) {
+ struct i965_vbo *vbo, *next;
+
+ intel_bo_destroy (&spans->device->intel, spans->head.bo);
+ for (vbo = spans->head.next; vbo != NULL; vbo = next) {
+ next = vbo->next;
+ intel_bo_destroy (&spans->device->intel, vbo->bo);
+ free (vbo);
+ }
+ }
+}
+
+cairo_status_t
+i965_clip_and_composite_spans (i965_surface_t *dst,
+ cairo_operator_t op,
+ const cairo_pattern_t *pattern,
+ cairo_antialias_t antialias,
+ i965_spans_func_t draw_func,
+ void *draw_closure,
+ const cairo_composite_rectangles_t*extents,
+ cairo_clip_t *clip)
+{
+ i965_spans_t spans;
+ i965_device_t *device;
+ cairo_status_t status;
+
+ if (op == CAIRO_OPERATOR_CLEAR) {
+ pattern = &_cairo_pattern_white.base;
+ op = CAIRO_OPERATOR_DEST_OUT;
+ }
+
+ status = i965_spans_init (&spans, dst, op, pattern, antialias, clip, extents);
+ if (unlikely (status))
+ return status;
+
+ spans.shader.mask.base.content = CAIRO_CONTENT_ALPHA;
+ spans.shader.mask.type.fragment = FS_SPANS;
+ spans.shader.mask.type.vertex = VS_SPANS;
+ spans.shader.mask.type.pattern = PATTERN_BASE;
+
+ status = cairo_device_acquire (dst->intel.drm.base.device);
+ if (unlikely (status))
+ goto CLEANUP_SPANS;
+
+ device = i965_device (dst);
+ status = i965_shader_commit (&spans.shader, device);
+ if (unlikely (status))
+ goto CLEANUP_DEVICE;
+
+ status = draw_func (draw_closure, &spans.renderer, spans.extents);
+ if (spans.clip_region != NULL && status == CAIRO_STATUS_SUCCESS) {
+ intel_bo_unmap (spans.tail->bo);
+ i965_clipped_vertices (device, &spans.head, spans.clip_region);
+ }
+
+ CLEANUP_DEVICE:
+ cairo_device_release (dst->intel.drm.base.device);
+ CLEANUP_SPANS:
+ i965_spans_fini (&spans);
+
+ return status;
+}
diff --git a/src/drm/cairo-drm-i965-surface.c b/src/drm/cairo-drm-i965-surface.c
new file mode 100644
index 0000000..0e0def8
--- /dev/null
+++ b/src/drm/cairo-drm-i965-surface.c
@@ -0,0 +1,1949 @@
+/* Cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2009 Kristian Høgsberg
+ * Copyright © 2009 Chris Wilson
+ * 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 Kristian Høgsberg.
+ *
+ * Based on the xf86-intel-driver i965 render acceleration code,
+ * authored by:
+ * Wang Zhenyu <zhenyu.z.wang at intel.com>
+ * Eric Anholt <eric at anholt.net>
+ * Carl Worth <cworth at redhat.com>
+ * Keith Packard <keithp at keithp.com>
+ */
+
+/* XXX
+ *
+ * FIXME: Use brw_PLN for [DevCTG-B+]
+ *
+ */
+
+#include "cairoint.h"
+
+#include "cairo-drm-private.h"
+#include "cairo-drm-ioctl-private.h"
+#include "cairo-drm-intel-private.h"
+#include "cairo-drm-intel-command-private.h"
+#include "cairo-drm-intel-ioctl-private.h"
+#include "cairo-drm-i965-private.h"
+
+#include "cairo-boxes-private.h"
+#include "cairo-composite-rectangles-private.h"
+#include "cairo-error-private.h"
+#include "cairo-region-private.h"
+#include "cairo-surface-offset-private.h"
+
+#include <sys/ioctl.h>
+#include <errno.h>
+
+#define I965_MAX_SIZE 8192
+
+static const cairo_surface_backend_t i965_surface_backend;
+
+static void
+i965_stream_init (i965_stream_t *stream,
+ uint8_t *data, uint32_t size,
+ struct i965_pending_relocation *pending, int max_pending,
+ struct drm_i915_gem_relocation_entry *relocations, int max_relocations)
+
+{
+ stream->used = stream->committed = 0;
+ stream->data = data;
+ stream->size = size;
+ stream->serial = 1;
+
+ stream->num_pending_relocations = 0;
+ stream->max_pending_relocations = max_pending;
+ stream->pending_relocations = pending;
+
+ stream->num_relocations = 0;
+ stream->max_relocations = max_relocations;
+ stream->relocations = relocations;
+}
+
+static void
+i965_add_relocation (i965_device_t *device,
+ intel_bo_t *bo,
+ uint32_t read_domains,
+ uint32_t write_domain)
+{
+ if (bo->exec == NULL) {
+ int i;
+
+ device->exec.gtt_size += bo->base.size;
+
+ i = device->exec.count++;
+ assert (i < ARRAY_LENGTH (device->exec.exec));
+
+ device->exec.exec[i].handle = bo->base.handle;
+ device->exec.exec[i].relocation_count = 0;
+ device->exec.exec[i].relocs_ptr = 0;
+ device->exec.exec[i].alignment = 0;
+ device->exec.exec[i].offset = 0;
+ device->exec.exec[i].flags = 0;
+ device->exec.exec[i].rsvd1 = 0;
+ device->exec.exec[i].rsvd2 = 0;
+
+ device->exec.bo[i] = intel_bo_reference (bo);
+ bo->exec = &device->exec.exec[i];
+ }
+
+ if (cairo_list_is_empty (&bo->link))
+ cairo_list_add_tail (&device->flush, &bo->link);
+
+ assert (write_domain == 0 || bo->batch_write_domain == 0 || bo->batch_write_domain == write_domain);
+ bo->batch_read_domains |= read_domains;
+ bo->batch_write_domain |= write_domain;
+}
+
+void
+i965_emit_relocation (i965_device_t *device,
+ i965_stream_t *stream,
+ intel_bo_t *target,
+ uint32_t target_offset,
+ uint32_t read_domains,
+ uint32_t write_domain,
+ uint32_t offset)
+{
+ int n;
+
+ assert (target_offset < target->base.size);
+
+ i965_add_relocation (device, target, read_domains, write_domain);
+
+ n = stream->num_relocations++;
+ assert (n < stream->max_relocations);
+
+ stream->relocations[n].offset = offset;
+ stream->relocations[n].delta = target_offset;
+ stream->relocations[n].target_handle = target->base.handle;
+ stream->relocations[n].read_domains = read_domains;
+ stream->relocations[n].write_domain = write_domain;
+ stream->relocations[n].presumed_offset = target->offset;
+}
+
+static void
+i965_stream_reset (i965_stream_t *stream)
+{
+ stream->used = stream->committed = 0;
+ stream->num_relocations = 0;
+ stream->num_pending_relocations = 0;
+ if (++stream->serial == 0)
+ stream->serial = 1;
+}
+
+void
+i965_stream_commit (i965_device_t *device,
+ i965_stream_t *stream)
+{
+ intel_bo_t *bo;
+ int n;
+
+ assert (stream->used);
+
+ bo = intel_bo_create (&device->intel, stream->used, FALSE);
+
+ /* apply pending relocations */
+ for (n = 0; n < stream->num_pending_relocations; n++) {
+ struct i965_pending_relocation *p = &stream->pending_relocations[n];
+
+ i965_emit_relocation (device, &device->batch, bo,
+ p->delta,
+ p->read_domains,
+ p->write_domain,
+ p->offset);
+ if (bo->offset)
+ *(uint32_t *) (device->batch.data + p->offset) = bo->offset + p->delta;
+ }
+
+ intel_bo_write (&device->intel, bo, 0, stream->used, stream->data);
+
+ if (stream->num_relocations) {
+ assert (bo->exec != NULL);
+ bo->exec->relocs_ptr = (uintptr_t) stream->relocations;
+ bo->exec->relocation_count = stream->num_relocations;
+ }
+
+ intel_bo_destroy (&device->intel, bo);
+
+ i965_stream_reset (stream);
+}
+
+static void
+sf_states_pluck (void *entry, void *closure)
+{
+ i965_device_t *device = closure;
+
+ _cairo_hash_table_remove (device->sf_states, entry);
+ _cairo_freelist_free (&device->sf_freelist, entry);
+}
+
+static void
+cc_offsets_pluck (void *entry, void *closure)
+{
+ i965_device_t *device = closure;
+
+ _cairo_hash_table_remove (device->cc_states, entry);
+ _cairo_freelist_free (&device->cc_freelist, entry);
+}
+
+static void
+wm_kernels_pluck (void *entry, void *closure)
+{
+ i965_device_t *device = closure;
+
+ _cairo_hash_table_remove (device->wm_kernels, entry);
+ _cairo_freelist_free (&device->wm_kernel_freelist, entry);
+}
+
+static void
+wm_states_pluck (void *entry, void *closure)
+{
+ i965_device_t *device = closure;
+
+ _cairo_hash_table_remove (device->wm_states, entry);
+ _cairo_freelist_free (&device->wm_state_freelist, entry);
+}
+
+static void
+wm_bindings_pluck (void *entry, void *closure)
+{
+ i965_device_t *device = closure;
+
+ _cairo_hash_table_remove (device->wm_bindings, entry);
+ _cairo_freelist_free (&device->wm_binding_freelist, entry);
+}
+
+static void
+samplers_pluck (void *entry, void *closure)
+{
+ i965_device_t *device = closure;
+
+ _cairo_hash_table_remove (device->samplers, entry);
+ _cairo_freelist_free (&device->sampler_freelist, entry);
+}
+
+void
+i965_general_state_reset (i965_device_t *device)
+{
+ _cairo_hash_table_foreach (device->sf_states,
+ sf_states_pluck,
+ device);
+
+ _cairo_hash_table_foreach (device->cc_states,
+ cc_offsets_pluck,
+ device);
+
+ _cairo_hash_table_foreach (device->wm_kernels,
+ wm_kernels_pluck,
+ device);
+
+ _cairo_hash_table_foreach (device->wm_states,
+ wm_states_pluck,
+ device);
+
+ _cairo_hash_table_foreach (device->wm_bindings,
+ wm_bindings_pluck,
+ device);
+
+ _cairo_hash_table_foreach (device->samplers,
+ samplers_pluck,
+ device);
+
+ device->vs_offset = (uint32_t) -1;
+ device->border_color_offset = (uint32_t) -1;
+
+ if (device->general_state != NULL) {
+ intel_bo_destroy (&device->intel, device->general_state);
+ device->general_state = NULL;
+ }
+}
+
+static void
+i965_device_reset (i965_device_t *device)
+{
+ device->exec.count = 0;
+ device->exec.gtt_size = I965_CONSTANT_SIZE +
+ I965_VERTEX_SIZE +
+ I965_SURFACE_SIZE +
+ I965_GENERAL_SIZE +
+ I965_BATCH_SIZE;
+
+ device->sf_state.entry.hash = (uint32_t) -1;
+ device->wm_state.entry.hash = (uint32_t) -1;
+ device->wm_binding.entry.hash = (uint32_t) -1;
+ device->cc_state.entry.hash = (uint32_t) -1;
+
+ device->target = NULL;
+ device->source = NULL;
+ device->mask = NULL;
+ device->clip = NULL;
+
+ device->draw_rectangle = (uint32_t) -1;
+
+ device->vertex_type = (uint32_t) -1;
+ device->vertex_size = 0;
+ device->rectangle_size = 0;
+ device->last_vertex_size = 0;
+
+ device->constants = NULL;
+ device->constants_size = 0;
+
+ device->have_urb_fences = FALSE;
+}
+
+static cairo_status_t
+i965_exec (i965_device_t *device, uint32_t offset)
+{
+ struct drm_i915_gem_execbuffer2 execbuf;
+ cairo_status_t status = CAIRO_STATUS_SUCCESS;
+ int ret, i;
+
+ execbuf.buffers_ptr = (uintptr_t) device->exec.exec;
+ execbuf.buffer_count = device->exec.count;
+ execbuf.batch_start_offset = offset;
+ execbuf.batch_len = device->batch.used;
+ execbuf.DR1 = 0;
+ execbuf.DR4 = 0;
+ execbuf.num_cliprects = 0;
+ execbuf.cliprects_ptr = 0;
+ execbuf.flags = I915_GEM_3D_PIPELINE;
+ execbuf.rsvd1 = 0;
+ execbuf.rsvd2 = 0;
+
+#if 0
+ printf ("exec: offset=%d, length=%d, buffers=%d\n",
+ offset, device->batch.used, device->exec.count);
+ intel_dump_batchbuffer ((uint32_t *) device->batch.data,
+ device->batch.used,
+ device->intel.base.chip_id);
+#endif
+
+ ret = 0;
+ do {
+ ret = ioctl (device->intel.base.fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, &execbuf);
+ } while (ret != 0 && errno == EINTR);
+ if (unlikely (ret)) {
+ int n;
+
+ if (errno == ENOMEM)
+ status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ else
+ status = _cairo_error (CAIRO_STATUS_DEVICE_ERROR);
+
+ fprintf (stderr, "Batch submission failed: %d\n", errno);
+ fprintf (stderr, " gtt size: %zd/%zd\n",
+ device->exec.gtt_size, device->intel.gtt_avail_size);
+
+ fprintf (stderr, " %d buffers:\n",
+ device->exec.count);
+ for (n = 0; n < i; n++) {
+ fprintf (stderr, " exec[%d] = %d\n",
+ n, device->exec.bo[n]->base.size);
+ }
+
+ intel_dump_batchbuffer ((uint32_t *) device->batch.data,
+ device->batch.used,
+ device->intel.base.chip_id);
+ }
+
+ /* XXX any write target within the batch should now be in error */
+ for (i = 0; i < device->exec.count; i++) {
+ cairo_bool_t ret;
+
+ device->exec.bo[i]->offset = device->exec.exec[i].offset;
+ device->exec.bo[i]->exec = NULL;
+ device->exec.bo[i]->batch_read_domains = 0;
+ device->exec.bo[i]->batch_write_domain = 0;
+
+ if (device->exec.bo[i]->purgeable) {
+ ret = intel_bo_madvise (&device->intel,
+ device->exec.bo[i],
+ I915_MADV_DONTNEED);
+ /* ignore immediate notification of purging */
+ }
+
+ cairo_list_init (&device->exec.bo[i]->link);
+ intel_bo_destroy (&device->intel, device->exec.bo[i]);
+ }
+ cairo_list_init (&device->flush);
+
+ device->exec.count = 0;
+
+ return status;
+}
+
+static inline uint32_t
+next_bo_size (uint32_t v)
+{
+ v = (v + 8191) / 8192;
+
+ v--;
+ v |= v >> 1;
+ v |= v >> 2;
+ v |= v >> 4;
+ v |= v >> 8;
+ v |= v >> 16;
+ v++;
+
+ return v * 8192;
+}
+
+static void
+_copy_to_bo_and_apply_relocations (i965_device_t *device,
+ intel_bo_t *bo,
+ i965_stream_t *stream,
+ uint32_t offset)
+{
+ int n;
+
+ intel_bo_write (&device->intel, bo,
+ offset, stream->used,
+ stream->data);
+
+ for (n = 0; n < stream->num_pending_relocations; n++) {
+ struct i965_pending_relocation *p = &stream->pending_relocations[n];
+
+ i965_emit_relocation (device, &device->batch, bo,
+ p->delta + offset,
+ p->read_domains,
+ p->write_domain,
+ p->offset);
+
+ if (bo->offset) {
+ *(uint32_t *) (device->batch.data + p->offset) =
+ bo->offset + p->delta + offset;
+ }
+ }
+}
+
+cairo_status_t
+i965_device_flush (i965_device_t *device)
+{
+ cairo_status_t status;
+ uint32_t aligned, max;
+ intel_bo_t *bo;
+ int n;
+
+ if (device->batch.used == 0)
+ return CAIRO_STATUS_SUCCESS;
+
+ i965_flush_vertices (device);
+
+ OUT_BATCH (MI_BATCH_BUFFER_END);
+ /* Emit a padding dword if we aren't going to be quad-word aligned. */
+ if (device->batch.used & 4)
+ OUT_BATCH (MI_NOOP);
+
+#if 0
+ printf ("device flush: vertex=%d, constant=%d, surface=%d, general=%d, batch=%d\n",
+ device->vertex.used,
+ device->constant.used,
+ device->surface.used,
+ device->general.used,
+ device->batch.used);
+#endif
+
+ /* can we pack the surface state into the tail of the general state? */
+ if (device->general.used == device->general.committed) {
+ if (device->general.used) {
+ assert (device->general.num_pending_relocations == 1);
+ assert (device->general_state != NULL);
+ i965_emit_relocation (device, &device->batch,
+ device->general_state,
+ device->general.pending_relocations[0].delta,
+ device->general.pending_relocations[0].read_domains,
+ device->general.pending_relocations[0].write_domain,
+ device->general.pending_relocations[0].offset);
+
+ if (device->general_state->offset) {
+ *(uint32_t *) (device->batch.data +
+ device->general.pending_relocations[0].offset) =
+ device->general_state->offset +
+ device->general.pending_relocations[0].delta;
+ }
+ }
+ } else {
+ assert (device->general.num_pending_relocations == 1);
+ if (device->general_state != NULL) {
+ intel_bo_destroy (&device->intel, device->general_state);
+ device->general_state = NULL;
+ }
+
+ bo = intel_bo_create (&device->intel,
+ device->general.used,
+ FALSE);
+ if (unlikely (bo == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+ aligned = (device->general.used + 31) & -32;
+ if (device->surface.used &&
+ aligned + device->surface.used <= bo->base.size)
+ {
+ _copy_to_bo_and_apply_relocations (device, bo, &device->general, 0);
+ _copy_to_bo_and_apply_relocations (device, bo, &device->surface, aligned);
+
+ if (device->surface.num_relocations) {
+ for (n = 0; n < device->surface.num_relocations; n++)
+ device->surface.relocations[n].offset += aligned;
+
+ assert (bo->exec != NULL);
+ bo->exec->relocs_ptr = (uintptr_t) device->surface.relocations;
+ bo->exec->relocation_count = device->surface.num_relocations;
+ }
+
+ i965_stream_reset (&device->surface);
+ }
+ else
+ {
+ _copy_to_bo_and_apply_relocations (device, bo, &device->general, 0);
+ }
+
+ /* Note we don't reset the general state, just mark what data we've committed. */
+ device->general.committed = device->general.used;
+ device->general_state = bo;
+ }
+ device->general.num_pending_relocations = 0;
+
+ /* Combine vertex+constant+surface+batch streams? */
+ max = aligned = device->vertex.used;
+ if (device->constant.used) {
+ aligned = (aligned + 63) & -64;
+ aligned += device->constant.used;
+ if (device->constant.used > max)
+ max = device->constant.used;
+ }
+ if (device->surface.used) {
+ aligned = (aligned + 31) & -32;
+ aligned += device->surface.used;
+ if (device->surface.used > max)
+ max = device->surface.used;
+ }
+ aligned = (aligned + 63) & -64;
+ aligned += device->batch.used;
+ if (device->batch.used > max)
+ max = device->batch.used;
+ if (aligned <= next_bo_size (max)) {
+ int batch_num_relocations;
+
+ if (aligned <= 8192)
+ max = aligned;
+
+ bo = intel_bo_create (&device->intel, max, FALSE);
+ if (unlikely (bo == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+ assert (aligned <= bo->base.size);
+
+ if (device->vertex.used)
+ _copy_to_bo_and_apply_relocations (device, bo, &device->vertex, 0);
+
+ aligned = device->vertex.used;
+ if (device->constant.used) {
+ aligned = (aligned + 63) & -64;
+ _copy_to_bo_and_apply_relocations (device, bo, &device->constant, aligned);
+ aligned += device->constant.used;
+ }
+
+ batch_num_relocations = device->batch.num_relocations;
+ if (device->surface.used) {
+ aligned = (aligned + 31) & -32;
+ _copy_to_bo_and_apply_relocations (device, bo, &device->surface, aligned);
+
+ batch_num_relocations = device->batch.num_relocations;
+ if (device->surface.num_relocations) {
+ assert (device->batch.num_relocations + device->surface.num_relocations < device->batch.max_relocations);
+
+ memcpy (device->batch.relocations + device->batch.num_relocations,
+ device->surface.relocations,
+ sizeof (device->surface.relocations[0]) * device->surface.num_relocations);
+
+ for (n = 0; n < device->surface.num_relocations; n++)
+ device->batch.relocations[device->batch.num_relocations + n].offset += aligned;
+
+ device->batch.num_relocations += device->surface.num_relocations;
+ }
+
+ aligned += device->surface.used;
+ }
+
+ aligned = (aligned + 63) & -64;
+ intel_bo_write (&device->intel, bo,
+ aligned, device->batch.used,
+ device->batch.data);
+
+ for (n = 0; n < batch_num_relocations; n++)
+ device->batch.relocations[n].offset += aligned;
+
+ if (device->exec.bo[device->exec.count-1] == bo) {
+ assert (bo->exec == &device->exec.exec[device->exec.count-1]);
+
+ bo->exec->relocation_count = device->batch.num_relocations;
+ bo->exec->relocs_ptr = (uintptr_t) device->batch.relocations;
+ intel_bo_destroy (&device->intel, bo);
+ } else {
+ assert (bo->exec == NULL);
+
+ n = device->exec.count++;
+ device->exec.exec[n].handle = bo->base.handle;
+ device->exec.exec[n].relocation_count = device->batch.num_relocations;
+ device->exec.exec[n].relocs_ptr = (uintptr_t) device->batch.relocations;
+ device->exec.exec[n].alignment = 0;
+ device->exec.exec[n].offset = 0;
+ device->exec.exec[n].flags = 0;
+ device->exec.exec[n].rsvd1 = 0;
+ device->exec.exec[n].rsvd2 = 0;
+
+ /* transfer ownership to the exec */
+ device->exec.bo[n] = bo;
+ }
+ } else {
+ i965_stream_commit (device, &device->vertex);
+
+ if (device->constant.used && device->surface.used){
+ aligned = (device->constant.used + 31) & -32;
+ aligned += device->surface.used;
+
+ max = MAX (device->constant.used, device->surface.used);
+ if (aligned <= next_bo_size (max)) {
+ if (aligned <= 8192)
+ max = aligned;
+
+ bo = intel_bo_create (&device->intel, max, FALSE);
+ if (unlikely (bo == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+ assert (aligned <= bo->base.size);
+
+ _copy_to_bo_and_apply_relocations (device, bo, &device->constant, 0);
+
+ aligned = (device->constant.used + 31) & -32;
+
+ _copy_to_bo_and_apply_relocations (device, bo, &device->surface, aligned);
+
+ if (device->surface.num_relocations) {
+ assert (bo->exec != NULL);
+
+ for (n = 0; n < device->surface.num_relocations; n++)
+ device->surface.relocations[n].offset += aligned;
+
+ bo->exec->relocs_ptr = (uintptr_t) device->surface.relocations;
+ bo->exec->relocation_count = device->surface.num_relocations;
+ }
+
+ i965_stream_reset (&device->surface);
+ i965_stream_reset (&device->constant);
+
+ intel_bo_destroy (&device->intel, bo);
+ }
+ } else {
+ if (device->constant.used)
+ i965_stream_commit (device, &device->constant);
+ if (device->surface.used)
+ i965_stream_commit (device, &device->surface);
+ }
+
+ bo = intel_bo_create (&device->intel, device->batch.used, FALSE);
+ if (unlikely (bo == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+ intel_bo_write (&device->intel, bo,
+ 0, device->batch.used,
+ device->batch.data);
+
+ n = device->exec.count++;
+ device->exec.exec[n].handle = bo->base.handle;
+ device->exec.exec[n].relocation_count = device->batch.num_relocations;
+ device->exec.exec[n].relocs_ptr = (uintptr_t) device->batch.relocations;
+ device->exec.exec[n].alignment = 0;
+ device->exec.exec[n].offset = 0;
+ device->exec.exec[n].flags = 0;
+ device->exec.exec[n].rsvd1 = 0;
+ device->exec.exec[n].rsvd2 = 0;
+
+ /* transfer ownership to the exec */
+ device->exec.bo[n] = bo;
+ aligned = 0;
+ }
+
+ intel_glyph_cache_unmap (&device->intel);
+
+ status = i965_exec (device, aligned);
+
+ i965_stream_reset (&device->vertex);
+ i965_stream_reset (&device->surface);
+ i965_stream_reset (&device->constant);
+ i965_stream_reset (&device->batch);
+
+ intel_glyph_cache_unpin (&device->intel);
+ intel_snapshot_cache_thaw (&device->intel);
+
+ i965_device_reset (device);
+
+ return status;
+}
+
+static cairo_status_t
+i965_surface_finish (void *abstract_surface)
+{
+ i965_surface_t *surface = abstract_surface;
+
+ return intel_surface_finish (&surface->intel);
+}
+
+static cairo_status_t
+i965_surface_flush (void *abstract_surface)
+{
+ i965_surface_t *surface = abstract_surface;
+ cairo_status_t status = CAIRO_STATUS_SUCCESS;
+
+ if (surface->intel.drm.fallback != NULL)
+ return intel_surface_flush (abstract_surface);
+
+ /* Forgo flushing on finish as the user cannot access the surface directly. */
+ if (! surface->intel.drm.base.finished &&
+ to_intel_bo (surface->intel.drm.bo)->exec != NULL)
+ {
+ status = cairo_device_acquire (surface->intel.drm.base.device);
+ if (likely (status == CAIRO_STATUS_SUCCESS)) {
+ i965_device_t *device;
+
+ device = i965_device (surface);
+ status = i965_device_flush (device);
+ cairo_device_release (&device->intel.base.base);
+ }
+ }
+
+ return status;
+}
+
+/* rasterisation */
+
+static cairo_status_t
+_composite_boxes_spans (void *closure,
+ cairo_span_renderer_t *renderer,
+ const cairo_rectangle_int_t *extents)
+{
+ cairo_boxes_t *boxes = closure;
+ cairo_rectangular_scan_converter_t converter;
+ struct _cairo_boxes_chunk *chunk;
+ cairo_status_t status;
+
+ _cairo_rectangular_scan_converter_init (&converter, extents);
+ for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
+ cairo_box_t *box = chunk->base;
+ int i;
+
+ for (i = 0; i < chunk->count; i++) {
+ status = _cairo_rectangular_scan_converter_add_box (&converter, &box[i], 1);
+ if (unlikely (status))
+ goto CLEANUP;
+ }
+ }
+
+ status = converter.base.generate (&converter.base, renderer);
+
+ CLEANUP:
+ converter.base.destroy (&converter.base);
+ return status;
+}
+
+cairo_status_t
+i965_fixup_unbounded (i965_surface_t *dst,
+ const cairo_composite_rectangles_t *extents,
+ cairo_clip_t *clip)
+{
+ i965_shader_t shader;
+ cairo_status_t status;
+
+ i965_shader_init (&shader, dst, CAIRO_OPERATOR_CLEAR);
+
+ if (clip != NULL) {
+ cairo_region_t *clip_region = NULL;
+
+ status = _cairo_clip_get_region (clip, &clip_region);
+ assert (status == CAIRO_STATUS_SUCCESS || CAIRO_INT_STATUS_UNSUPPORTED);
+ assert (clip_region == NULL);
+
+ if (status == CAIRO_INT_STATUS_UNSUPPORTED)
+ i965_shader_set_clip (&shader, clip);
+ } else {
+ if (extents->bounded.width == extents->unbounded.width &&
+ extents->bounded.height == extents->unbounded.height)
+ {
+ return CAIRO_STATUS_SUCCESS;
+ }
+ }
+
+ status = i965_shader_acquire_pattern (&shader,
+ &shader.source,
+ &_cairo_pattern_clear.base,
+ &extents->unbounded);
+ if (unlikely (status)) {
+ i965_shader_fini (&shader);
+ return status;
+ }
+
+ status = i965_shader_commit (&shader, i965_device (dst));
+ if (unlikely (status)) {
+ i965_shader_fini (&shader);
+ return status;
+ }
+
+ /* top */
+ if (extents->bounded.y != extents->unbounded.y) {
+ cairo_rectangle_int_t rect;
+
+ rect.x = extents->unbounded.x;
+ rect.y = extents->unbounded.y;
+ rect.width = extents->unbounded.width;
+ rect.height = extents->bounded.y - rect.y;
+
+ i965_shader_add_rectangle (&shader,
+ rect.x, rect.y,
+ rect.width, rect.height);
+ }
+
+ /* left */
+ if (extents->bounded.x != extents->unbounded.x) {
+ cairo_rectangle_int_t rect;
+
+ rect.x = extents->unbounded.x;
+ rect.y = extents->bounded.y;
+ rect.width = extents->bounded.x - extents->unbounded.x;
+ rect.height = extents->bounded.height;
+
+ i965_shader_add_rectangle (&shader,
+ rect.x, rect.y,
+ rect.width, rect.height);
+ }
+
+ /* right */
+ if (extents->bounded.x + extents->bounded.width != extents->unbounded.x + extents->unbounded.width) {
+ cairo_rectangle_int_t rect;
+
+ rect.x = extents->bounded.x + extents->bounded.width;
+ rect.y = extents->bounded.y;
+ rect.width = extents->unbounded.x + extents->unbounded.width - rect.x;
+ rect.height = extents->bounded.height;
+
+ i965_shader_add_rectangle (&shader,
+ rect.x, rect.y,
+ rect.width, rect.height);
+ }
+
+ /* bottom */
+ if (extents->bounded.y + extents->bounded.height != extents->unbounded.y + extents->unbounded.height) {
+ cairo_rectangle_int_t rect;
+
+ rect.x = extents->unbounded.x;
+ rect.y = extents->bounded.y + extents->bounded.height;
+ rect.width = extents->unbounded.width;
+ rect.height = extents->unbounded.y + extents->unbounded.height - rect.y;
+
+ i965_shader_add_rectangle (&shader,
+ rect.x, rect.y,
+ rect.width, rect.height);
+ }
+
+ i965_shader_fini (&shader);
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+i965_fixup_unbounded_boxes (i965_surface_t *dst,
+ const cairo_composite_rectangles_t *extents,
+ cairo_clip_t *clip,
+ cairo_boxes_t *boxes)
+{
+ cairo_boxes_t clear;
+ cairo_box_t box;
+ cairo_region_t *clip_region = NULL;
+ cairo_status_t status;
+ struct _cairo_boxes_chunk *chunk;
+ i965_shader_t shader;
+ int i;
+
+ if (boxes->num_boxes <= 1)
+ return i965_fixup_unbounded (dst, extents, clip);
+
+ i965_shader_init (&shader, dst, CAIRO_OPERATOR_CLEAR);
+ if (clip != NULL) {
+ status = _cairo_clip_get_region (clip, &clip_region);
+ assert (status == CAIRO_STATUS_SUCCESS || CAIRO_INT_STATUS_UNSUPPORTED);
+ if (status == CAIRO_INT_STATUS_UNSUPPORTED)
+ i965_shader_set_clip (&shader, clip);
+ }
+
+ status = i965_shader_acquire_pattern (&shader,
+ &shader.source,
+ &_cairo_pattern_clear.base,
+ &extents->unbounded);
+ if (unlikely (status)) {
+ i965_shader_fini (&shader);
+ return status;
+ }
+
+ _cairo_boxes_init (&clear);
+
+ box.p1.x = _cairo_fixed_from_int (extents->unbounded.x + extents->unbounded.width);
+ box.p1.y = _cairo_fixed_from_int (extents->unbounded.y);
+ box.p2.x = _cairo_fixed_from_int (extents->unbounded.x);
+ box.p2.y = _cairo_fixed_from_int (extents->unbounded.y + extents->unbounded.height);
+
+ if (clip_region == NULL) {
+ cairo_boxes_t tmp;
+
+ _cairo_boxes_init (&tmp);
+
+ status = _cairo_boxes_add (&tmp, &box);
+ assert (status == CAIRO_STATUS_SUCCESS);
+
+ tmp.chunks.next = &boxes->chunks;
+ tmp.num_boxes += boxes->num_boxes;
+
+ status = _cairo_bentley_ottmann_tessellate_boxes (&tmp,
+ CAIRO_FILL_RULE_WINDING,
+ &clear);
+
+ tmp.chunks.next = NULL;
+ } else {
+ pixman_box32_t *pbox;
+
+ pbox = pixman_region32_rectangles (&clip_region->rgn, &i);
+ _cairo_boxes_limit (&clear, (cairo_box_t *) pbox, i);
+
+ status = _cairo_boxes_add (&clear, &box);
+ assert (status == CAIRO_STATUS_SUCCESS);
+
+ for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
+ for (i = 0; i < chunk->count; i++) {
+ status = _cairo_boxes_add (&clear, &chunk->base[i]);
+ if (unlikely (status)) {
+ _cairo_boxes_fini (&clear);
+ return status;
+ }
+ }
+ }
+
+ status = _cairo_bentley_ottmann_tessellate_boxes (&clear,
+ CAIRO_FILL_RULE_WINDING,
+ &clear);
+ }
+
+ if (likely (status == CAIRO_STATUS_SUCCESS && clear.num_boxes)) {
+ status = i965_shader_commit (&shader, i965_device (dst));
+ if (likely (status == CAIRO_STATUS_SUCCESS)) {
+ for (chunk = &clear.chunks; chunk != NULL; chunk = chunk->next) {
+ for (i = 0; i < chunk->count; i++) {
+ int x1 = _cairo_fixed_integer_part (chunk->base[i].p1.x);
+ int y1 = _cairo_fixed_integer_part (chunk->base[i].p1.y);
+ int x2 = _cairo_fixed_integer_part (chunk->base[i].p2.x);
+ int y2 = _cairo_fixed_integer_part (chunk->base[i].p2.y);
+
+ i965_shader_add_rectangle (&shader, x1, y1, x2 - x1, y2 - y1);
+ }
+ }
+ }
+ i965_shader_fini (&shader);
+ }
+
+ _cairo_boxes_fini (&clear);
+
+ return status;
+}
+
+static cairo_status_t
+_composite_boxes (i965_surface_t *dst,
+ cairo_operator_t op,
+ const cairo_pattern_t *pattern,
+ cairo_boxes_t *boxes,
+ cairo_antialias_t antialias,
+ cairo_clip_t *clip,
+ const cairo_composite_rectangles_t *extents)
+{
+ cairo_bool_t need_clip_surface = FALSE;
+ cairo_region_t *clip_region = NULL;
+ const struct _cairo_boxes_chunk *chunk;
+ cairo_status_t status;
+ i965_shader_t shader;
+ int i;
+
+ /* If the boxes are not pixel-aligned, we will need to compute a real mask */
+ if (antialias != CAIRO_ANTIALIAS_NONE) {
+ if (! boxes->is_pixel_aligned)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ }
+
+ i965_shader_init (&shader, dst, op);
+
+ status = i965_shader_acquire_pattern (&shader,
+ &shader.source,
+ pattern,
+ &extents->bounded);
+ if (unlikely (status))
+ return status;
+
+ if (clip != NULL) {
+ status = _cairo_clip_get_region (clip, &clip_region);
+ assert (status == CAIRO_STATUS_SUCCESS || CAIRO_INT_STATUS_UNSUPPORTED);
+ need_clip_surface = status == CAIRO_INT_STATUS_UNSUPPORTED;
+ if (need_clip_surface)
+ i965_shader_set_clip (&shader, clip);
+ }
+
+ status = i965_shader_commit (&shader, i965_device (dst));
+ if (likely (status == CAIRO_STATUS_SUCCESS)) {
+ for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
+ cairo_box_t *box = chunk->base;
+ for (i = 0; i < chunk->count; i++) {
+ int x1 = _cairo_fixed_integer_round (box[i].p1.x);
+ int y1 = _cairo_fixed_integer_round (box[i].p1.y);
+ int x2 = _cairo_fixed_integer_round (box[i].p2.x);
+ int y2 = _cairo_fixed_integer_round (box[i].p2.y);
+
+ if (x2 > x1 && y2 > y1)
+ i965_shader_add_rectangle (&shader, x1, y1, x2 - x1, y2 - y1);
+ }
+ }
+ }
+ i965_shader_fini (&shader);
+
+ if (status == CAIRO_STATUS_SUCCESS && ! extents->is_bounded)
+ status = i965_fixup_unbounded_boxes (dst, extents, clip, boxes);
+
+ return status;
+}
+
+static cairo_status_t
+_clip_and_composite_boxes (i965_surface_t *dst,
+ cairo_operator_t op,
+ const cairo_pattern_t *src,
+ cairo_boxes_t *boxes,
+ cairo_antialias_t antialias,
+ const cairo_composite_rectangles_t *extents,
+ cairo_clip_t *clip)
+{
+ cairo_status_t status;
+
+ if (boxes->num_boxes == 0) {
+ if (extents->is_bounded)
+ return CAIRO_STATUS_SUCCESS;
+
+ return i965_fixup_unbounded (dst, extents, clip);
+ }
+
+ /* Use a fast path if the boxes are pixel aligned */
+ status = _composite_boxes (dst, op, src, boxes, antialias, clip, extents);
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+ return status;
+
+ /* Otherwise render the boxes via an implicit mask and composite in the usual
+ * fashion.
+ */
+ return i965_clip_and_composite_spans (dst, op, src, antialias,
+ _composite_boxes_spans, boxes,
+ extents, clip);
+}
+
+static cairo_bool_t
+box_is_aligned (const cairo_box_t *box)
+{
+ return
+ _cairo_fixed_is_integer (box->p1.x) &&
+ _cairo_fixed_is_integer (box->p1.y) &&
+ _cairo_fixed_is_integer (box->p2.x) &&
+ _cairo_fixed_is_integer (box->p2.y);
+}
+
+static inline cairo_status_t
+_clip_to_boxes (cairo_clip_t **clip,
+ const cairo_composite_rectangles_t *extents,
+ cairo_box_t **boxes,
+ int *num_boxes)
+{
+ cairo_status_t status;
+ const cairo_rectangle_int_t *rect;
+
+ rect = extents->is_bounded ? &extents->bounded: &extents->unbounded;
+
+ if (*clip == NULL)
+ goto EXTENTS;
+
+ status = _cairo_clip_rectangle (*clip, rect);
+ if (unlikely (status))
+ return status;
+
+ status = _cairo_clip_get_boxes (*clip, boxes, num_boxes);
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED) {
+ if (extents->is_bounded || (*num_boxes == 1 && box_is_aligned (*boxes)))
+ *clip = NULL;
+ return status;
+ }
+
+ EXTENTS:
+ _cairo_box_from_rectangle (&(*boxes)[0], rect);
+ *num_boxes = 1;
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+i965_surface_paint (void *abstract_dst,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_clip_t *clip)
+{
+ i965_surface_t *dst = abstract_dst;
+ cairo_composite_rectangles_t extents;
+ cairo_boxes_t boxes;
+ cairo_box_t *clip_boxes = boxes.boxes_embedded;
+ cairo_clip_t local_clip;
+ cairo_bool_t have_clip = FALSE;
+ int num_boxes = ARRAY_LENGTH (boxes.boxes_embedded);
+ cairo_status_t status;
+
+ /* XXX unsupported operators? use pixel shader blending, eventually */
+
+ status = _cairo_composite_rectangles_init_for_paint (&extents,
+ dst->intel.drm.width,
+ dst->intel.drm.height,
+ op, source,
+ clip);
+ if (unlikely (status))
+ return status;
+
+ if (clip != NULL && _cairo_clip_contains_rectangle (clip, &extents))
+ clip = NULL;
+
+ if (clip != NULL) {
+ clip = _cairo_clip_init_copy (&local_clip, clip);
+ have_clip = TRUE;
+ }
+
+ status = _clip_to_boxes (&clip, &extents, &clip_boxes, &num_boxes);
+ if (unlikely (status)) {
+ if (have_clip)
+ _cairo_clip_fini (&local_clip);
+
+ return status;
+ }
+
+ _cairo_boxes_init_for_array (&boxes, clip_boxes, num_boxes);
+ status = _clip_and_composite_boxes (dst, op, source,
+ &boxes, CAIRO_ANTIALIAS_DEFAULT,
+ &extents, clip);
+ if (clip_boxes != boxes.boxes_embedded)
+ free (clip_boxes);
+
+ if (have_clip)
+ _cairo_clip_fini (&local_clip);
+
+ return status;
+}
+
+static cairo_int_status_t
+i965_surface_mask (void *abstract_dst,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ const cairo_pattern_t *mask,
+ cairo_clip_t *clip)
+{
+ i965_surface_t *dst = abstract_dst;
+ cairo_composite_rectangles_t extents;
+ i965_shader_t shader;
+ cairo_clip_t local_clip;
+ cairo_region_t *clip_region = NULL;
+ cairo_bool_t need_clip_surface = FALSE;
+ cairo_bool_t have_clip = FALSE;
+ cairo_status_t status;
+
+ status = _cairo_composite_rectangles_init_for_mask (&extents,
+ dst->intel.drm.width,
+ dst->intel.drm.height,
+ op, source, mask, clip);
+ if (unlikely (status))
+ return status;
+
+ if (clip != NULL && _cairo_clip_contains_rectangle (clip, &extents))
+ clip = NULL;
+
+ if (clip != NULL && extents.is_bounded) {
+ clip = _cairo_clip_init_copy (&local_clip, clip);
+ status = _cairo_clip_rectangle (clip, &extents.bounded);
+ if (unlikely (status)) {
+ _cairo_clip_fini (&local_clip);
+ return status;
+ }
+
+ have_clip = TRUE;
+ }
+
+ i965_shader_init (&shader, dst, op);
+
+ status = i965_shader_acquire_pattern (&shader,
+ &shader.source,
+ source,
+ &extents.bounded);
+ if (unlikely (status))
+ goto BAIL;
+
+ status = i965_shader_acquire_pattern (&shader,
+ &shader.mask,
+ mask,
+ &extents.bounded);
+ if (unlikely (status))
+ goto BAIL;
+
+ if (clip != NULL) {
+ status = _cairo_clip_get_region (clip, &clip_region);
+ assert (status == CAIRO_STATUS_SUCCESS || CAIRO_INT_STATUS_UNSUPPORTED);
+ need_clip_surface = status == CAIRO_INT_STATUS_UNSUPPORTED;
+ if (need_clip_surface)
+ i965_shader_set_clip (&shader, clip);
+ }
+
+ status = i965_shader_commit (&shader, i965_device (dst));
+ if (unlikely (status))
+ goto BAIL;
+
+ if (clip_region != NULL) {
+ unsigned int n, num_rectangles;
+
+ num_rectangles = cairo_region_num_rectangles (clip_region);
+ for (n = 0; n < num_rectangles; n++) {
+ cairo_rectangle_int_t rect;
+
+ cairo_region_get_rectangle (clip_region, n, &rect);
+
+ i965_shader_add_rectangle (&shader,
+ rect.x, rect.y,
+ rect.width, rect.height);
+ }
+ } else {
+ i965_shader_add_rectangle (&shader,
+ extents.bounded.x,
+ extents.bounded.y,
+ extents.bounded.width,
+ extents.bounded.height);
+ }
+
+ if (! extents.is_bounded)
+ status = i965_fixup_unbounded (dst, &extents, clip);
+
+ BAIL:
+ i965_shader_fini (&shader);
+ if (have_clip)
+ _cairo_clip_fini (&local_clip);
+
+ return status;
+}
+
+typedef struct {
+ cairo_polygon_t polygon;
+ cairo_fill_rule_t fill_rule;
+ cairo_antialias_t antialias;
+} composite_polygon_info_t;
+
+static cairo_status_t
+_composite_polygon_spans (void *closure,
+ cairo_span_renderer_t *renderer,
+ const cairo_rectangle_int_t *extents)
+{
+ composite_polygon_info_t *info = closure;
+ cairo_botor_scan_converter_t converter;
+ cairo_status_t status;
+ cairo_box_t box;
+
+ box.p1.x = _cairo_fixed_from_int (extents->x);
+ box.p1.y = _cairo_fixed_from_int (extents->y);
+ box.p2.x = _cairo_fixed_from_int (extents->x + extents->width);
+ box.p2.y = _cairo_fixed_from_int (extents->y + extents->height);
+
+ _cairo_botor_scan_converter_init (&converter, &box, info->fill_rule);
+
+ status = converter.base.add_polygon (&converter.base, &info->polygon);
+ if (likely (status == CAIRO_STATUS_SUCCESS))
+ status = converter.base.generate (&converter.base, renderer);
+
+ converter.base.destroy (&converter.base);
+
+ return status;
+}
+
+static cairo_int_status_t
+i965_surface_stroke (void *abstract_dst,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_path_fixed_t *path,
+ const cairo_stroke_style_t *stroke_style,
+ const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm_inverse,
+ double tolerance,
+ cairo_antialias_t antialias,
+ cairo_clip_t *clip)
+{
+ i965_surface_t *dst = abstract_dst;
+ cairo_composite_rectangles_t extents;
+ composite_polygon_info_t info;
+ cairo_box_t boxes_stack[32], *clip_boxes = boxes_stack;
+ int num_boxes = ARRAY_LENGTH (boxes_stack);
+ cairo_clip_t local_clip;
+ cairo_bool_t have_clip = FALSE;
+ cairo_status_t status;
+
+ status = _cairo_composite_rectangles_init_for_stroke (&extents,
+ dst->intel.drm.width,
+ dst->intel.drm.height,
+ op, source,
+ path, stroke_style, ctm,
+ clip);
+ if (unlikely (status))
+ return status;
+
+ if (clip != NULL && _cairo_clip_contains_rectangle (clip, &extents))
+ clip = NULL;
+
+ if (clip != NULL) {
+ clip = _cairo_clip_init_copy (&local_clip, clip);
+ have_clip = TRUE;
+ }
+
+ status = _clip_to_boxes (&clip, &extents, &clip_boxes, &num_boxes);
+ if (unlikely (status)) {
+ if (have_clip)
+ _cairo_clip_fini (&local_clip);
+
+ return status;
+ }
+
+ if (path->is_rectilinear) {
+ cairo_boxes_t boxes;
+
+ _cairo_boxes_init (&boxes);
+ _cairo_boxes_limit (&boxes, clip_boxes, num_boxes);
+ status = _cairo_path_fixed_stroke_rectilinear_to_boxes (path,
+ stroke_style,
+ ctm,
+ &boxes);
+ if (likely (status == CAIRO_STATUS_SUCCESS)) {
+ status = _clip_and_composite_boxes (dst, op, source,
+ &boxes, antialias,
+ &extents, clip);
+ }
+
+ _cairo_boxes_fini (&boxes);
+
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+ goto CLEANUP_BOXES;
+ }
+
+ _cairo_polygon_init (&info.polygon);
+ _cairo_polygon_limit (&info.polygon, clip_boxes, num_boxes);
+
+ status = _cairo_path_fixed_stroke_to_polygon (path,
+ stroke_style,
+ ctm, ctm_inverse,
+ tolerance,
+ &info.polygon);
+ if (unlikely (status))
+ goto CLEANUP_POLYGON;
+
+ if (extents.is_bounded) {
+ cairo_rectangle_int_t rect;
+
+ _cairo_box_round_to_rectangle (&info.polygon.extents, &rect);
+ if (! _cairo_rectangle_intersect (&extents.bounded, &rect))
+ goto CLEANUP_POLYGON;
+ }
+
+ if (info.polygon.num_edges == 0) {
+ if (! extents.is_bounded)
+ status = i965_fixup_unbounded (dst, &extents, clip);
+ } else {
+ info.fill_rule = CAIRO_FILL_RULE_WINDING;
+ info.antialias = antialias;
+ status = i965_clip_and_composite_spans (dst, op, source, antialias,
+ _composite_polygon_spans, &info,
+ &extents, clip);
+ }
+
+CLEANUP_POLYGON:
+ _cairo_polygon_fini (&info.polygon);
+
+CLEANUP_BOXES:
+ if (clip_boxes != boxes_stack)
+ free (clip_boxes);
+
+ if (have_clip)
+ _cairo_clip_fini (&local_clip);
+
+ return status;
+}
+
+static cairo_int_status_t
+i965_surface_fill (void *abstract_dst,
+ cairo_operator_t op,
+ const cairo_pattern_t*source,
+ cairo_path_fixed_t *path,
+ cairo_fill_rule_t fill_rule,
+ double tolerance,
+ cairo_antialias_t antialias,
+ cairo_clip_t *clip)
+{
+ i965_surface_t *dst = abstract_dst;
+ cairo_composite_rectangles_t extents;
+ composite_polygon_info_t info;
+ cairo_box_t boxes_stack[32], *clip_boxes = boxes_stack;
+ cairo_clip_t local_clip;
+ cairo_bool_t have_clip = FALSE;
+ int num_boxes = ARRAY_LENGTH (boxes_stack);
+ cairo_status_t status;
+
+ status = _cairo_composite_rectangles_init_for_fill (&extents,
+ dst->intel.drm.width,
+ dst->intel.drm.height,
+ op, source, path,
+ clip);
+ if (unlikely (status))
+ return status;
+
+ if (clip != NULL && _cairo_clip_contains_rectangle (clip, &extents))
+ clip = NULL;
+
+ if (clip != NULL) {
+ clip = _cairo_clip_init_copy (&local_clip, clip);
+ have_clip = TRUE;
+ }
+
+ status = _clip_to_boxes (&clip, &extents, &clip_boxes, &num_boxes);
+ if (unlikely (status)) {
+ if (have_clip)
+ _cairo_clip_fini (&local_clip);
+
+ return status;
+ }
+
+ assert (! path->is_empty_fill);
+
+ if (_cairo_path_fixed_is_rectilinear_fill (path)) {
+ cairo_boxes_t boxes;
+
+ _cairo_boxes_init (&boxes);
+ _cairo_boxes_limit (&boxes, clip_boxes, num_boxes);
+ status = _cairo_path_fixed_fill_rectilinear_to_boxes (path,
+ fill_rule,
+ &boxes);
+ if (likely (status == CAIRO_STATUS_SUCCESS)) {
+ status = _clip_and_composite_boxes (dst, op, source,
+ &boxes, antialias,
+ &extents, clip);
+ }
+
+ _cairo_boxes_fini (&boxes);
+
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+ goto CLEANUP_BOXES;
+ }
+
+ _cairo_polygon_init (&info.polygon);
+ _cairo_polygon_limit (&info.polygon, clip_boxes, num_boxes);
+
+ status = _cairo_path_fixed_fill_to_polygon (path, tolerance, &info.polygon);
+ if (unlikely (status))
+ goto CLEANUP_POLYGON;
+
+ if (extents.is_bounded) {
+ cairo_rectangle_int_t rect;
+
+ _cairo_box_round_to_rectangle (&info.polygon.extents, &rect);
+ if (! _cairo_rectangle_intersect (&extents.bounded, &rect))
+ goto CLEANUP_POLYGON;
+ }
+
+ if (info.polygon.num_edges == 0) {
+ if (! extents.is_bounded)
+ status = i965_fixup_unbounded (dst, &extents, clip);
+ } else {
+ info.fill_rule = fill_rule;
+ info.antialias = antialias;
+ status = i965_clip_and_composite_spans (dst, op, source, antialias,
+ _composite_polygon_spans, &info,
+ &extents, clip);
+ }
+
+CLEANUP_POLYGON:
+ _cairo_polygon_fini (&info.polygon);
+
+CLEANUP_BOXES:
+ if (clip_boxes != boxes_stack)
+ free (clip_boxes);
+
+ if (have_clip)
+ _cairo_clip_fini (&local_clip);
+
+ return status;
+}
+
+static const cairo_surface_backend_t i965_surface_backend = {
+ CAIRO_SURFACE_TYPE_DRM,
+
+ _cairo_drm_surface_create_similar,
+ i965_surface_finish,
+ intel_surface_acquire_source_image,
+ intel_surface_release_source_image,
+
+ NULL, NULL, NULL,
+ NULL, /* composite */
+ NULL, /* fill */
+ NULL, /* trapezoids */
+ NULL, /* span */
+ NULL, /* check-span */
+
+ NULL, /* copy_page */
+ NULL, /* show_page */
+ _cairo_drm_surface_get_extents,
+ NULL, /* old-glyphs */
+ _cairo_drm_surface_get_font_options,
+
+ i965_surface_flush,
+ NULL, /* mark_dirty */
+ intel_scaled_font_fini,
+ intel_scaled_glyph_fini,
+
+ i965_surface_paint,
+ i965_surface_mask,
+ i965_surface_stroke,
+ i965_surface_fill,
+ i965_surface_glyphs,
+};
+
+static void
+i965_surface_init (i965_surface_t *surface,
+ cairo_content_t content,
+ cairo_drm_device_t *device)
+{
+ intel_surface_init (&surface->intel, &i965_surface_backend, device, content);
+ surface->stream = 0;
+}
+
+static inline int cairo_const
+i965_tiling_stride (uint32_t tiling, int stride)
+{
+ if (tiling == I915_TILING_NONE)
+ return stride;
+
+ return (stride + 127) & -128;
+}
+
+static inline int cairo_const
+i965_tiling_height (uint32_t tiling, int height)
+{
+ switch (tiling) {
+ default:
+ case I915_TILING_NONE: return (height + 1) & -2;
+ case I915_TILING_X: return (height + 7) & -8;
+ case I915_TILING_Y: return (height + 31) & -32;
+ }
+}
+
+cairo_surface_t *
+i965_surface_create_internal (cairo_drm_device_t *base_dev,
+ cairo_content_t content,
+ int width, int height,
+ uint32_t tiling,
+ cairo_bool_t gpu_target)
+{
+ i965_surface_t *surface;
+ cairo_status_t status_ignored;
+
+ surface = malloc (sizeof (i965_surface_t));
+ if (unlikely (surface == NULL))
+ return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
+
+ i965_surface_init (surface, content, base_dev);
+
+ if (width && height) {
+ uint32_t size;
+
+ surface->intel.drm.width = width;
+ surface->intel.drm.height = height;
+
+ width = (width + 3) & -4;
+ surface->intel.drm.stride = cairo_format_stride_for_width (surface->intel.drm.format,
+ width);
+ surface->intel.drm.stride = (surface->intel.drm.stride + 63) & ~63;
+
+#if 0
+ /* check for tiny surfaces for which tiling is irrelevant */
+ if (height * surface->intel.drm.stride < 4096)
+ tiling = I915_TILING_NONE;
+#endif
+ surface->intel.drm.stride = i965_tiling_stride (tiling,
+ surface->intel.drm.stride);
+
+ height = i965_tiling_height (tiling, height);
+ assert (height <= I965_MAX_SIZE);
+
+ size = surface->intel.drm.stride * height;
+ if (tiling != I915_TILING_NONE)
+ size = (size + 4095) & -4096;
+
+ surface->intel.drm.bo = &intel_bo_create (to_intel_device (&base_dev->base),
+ size, gpu_target)->base;
+ if (surface->intel.drm.bo == NULL) {
+ status_ignored = _cairo_drm_surface_finish (&surface->intel.drm);
+ free (surface);
+ return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
+ }
+
+ intel_bo_set_tiling (to_intel_device (&base_dev->base),
+ to_intel_bo (surface->intel.drm.bo),
+ tiling, surface->intel.drm.stride);
+
+ assert (surface->intel.drm.bo->size >= (size_t) surface->intel.drm.stride*height);
+ }
+
+ return &surface->intel.drm.base;
+}
+
+static cairo_surface_t *
+i965_surface_create (cairo_drm_device_t *device,
+ cairo_content_t content, int width, int height)
+{
+ return i965_surface_create_internal (device, content, width, height,
+ I965_TILING_DEFAULT, TRUE);
+}
+
+static cairo_surface_t *
+i965_surface_create_for_name (cairo_drm_device_t *base_dev,
+ unsigned int name,
+ cairo_format_t format,
+ int width, int height, int stride)
+{
+ i965_device_t *device;
+ i965_surface_t *surface;
+ cairo_content_t content;
+ cairo_status_t status_ignored;
+ int min_stride;
+
+ min_stride = cairo_format_stride_for_width (format, (width + 3) & -4);
+ if (stride < min_stride || stride & 63)
+ return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_STRIDE));
+
+ if (format == CAIRO_FORMAT_A1)
+ return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT));
+
+ switch (format) {
+ case CAIRO_FORMAT_ARGB32:
+ content = CAIRO_CONTENT_COLOR_ALPHA;
+ break;
+ case CAIRO_FORMAT_RGB24:
+ content = CAIRO_CONTENT_COLOR;
+ break;
+ case CAIRO_FORMAT_A8:
+ content = CAIRO_CONTENT_ALPHA;
+ break;
+ default:
+ case CAIRO_FORMAT_A1:
+ return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT));
+ }
+
+ surface = malloc (sizeof (i965_surface_t));
+ if (unlikely (surface == NULL))
+ return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
+
+ i965_surface_init (surface, content, base_dev);
+
+ device = (i965_device_t *) base_dev;
+ surface->intel.drm.bo = &intel_bo_create_for_name (&device->intel, name)->base;
+ if (unlikely (surface->intel.drm.bo == NULL)) {
+ status_ignored = _cairo_drm_surface_finish (&surface->intel.drm);
+ free (surface);
+ return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
+ }
+
+ surface->intel.drm.width = width;
+ surface->intel.drm.height = height;
+ surface->intel.drm.stride = stride;
+
+ return &surface->intel.drm.base;
+}
+
+static cairo_status_t
+i965_surface_enable_scan_out (void *abstract_surface)
+{
+ i965_surface_t *surface = abstract_surface;
+ intel_bo_t *bo;
+
+ if (unlikely (surface->intel.drm.bo == NULL))
+ return _cairo_error (CAIRO_STATUS_INVALID_SIZE);
+
+ bo = to_intel_bo (surface->intel.drm.bo);
+ if (bo->tiling != I915_TILING_X) {
+ i965_device_t *device = i965_device (surface);
+ cairo_surface_pattern_t pattern;
+ cairo_surface_t *clone;
+ cairo_status_t status;
+
+ clone = i965_surface_create_internal (&device->intel.base,
+ surface->intel.drm.base.content,
+ surface->intel.drm.width,
+ surface->intel.drm.height,
+ I915_TILING_X,
+ TRUE);
+ if (unlikely (clone->status))
+ return clone->status;
+
+ /* 2D blit? */
+ _cairo_pattern_init_for_surface (&pattern, &surface->intel.drm.base);
+ pattern.base.filter = CAIRO_FILTER_NEAREST;
+
+ status = _cairo_surface_paint (clone,
+ CAIRO_OPERATOR_SOURCE,
+ &pattern.base,
+ NULL);
+
+ _cairo_pattern_fini (&pattern.base);
+
+ if (unlikely (status)) {
+ cairo_surface_destroy (clone);
+ return status;
+ }
+
+ /* swap buffer objects */
+ surface->intel.drm.bo = ((cairo_drm_surface_t *) clone)->bo;
+ ((cairo_drm_surface_t *) clone)->bo = &bo->base;
+ bo = to_intel_bo (surface->intel.drm.bo);
+
+ cairo_surface_destroy (clone);
+ }
+
+ if (unlikely (bo->tiling == I915_TILING_Y))
+ return _cairo_error (CAIRO_STATUS_INVALID_FORMAT); /* XXX */
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+_i965_device_flush (cairo_drm_device_t *device)
+{
+ cairo_status_t status;
+
+ status = cairo_device_acquire (&device->base);
+ if (likely (status == CAIRO_STATUS_SUCCESS))
+ status = i965_device_flush ((i965_device_t *) device);
+
+ cairo_device_release (&device->base);
+
+ return status;
+}
+
+static cairo_int_status_t
+_i965_device_throttle (cairo_drm_device_t *device)
+{
+ cairo_status_t status;
+
+ status = cairo_device_acquire (&device->base);
+ if (unlikely (status))
+ return status;
+
+ status = i965_device_flush ((i965_device_t *) device);
+ intel_throttle ((intel_device_t *) device);
+
+ cairo_device_release (&device->base);
+
+ return status;
+}
+
+static void
+_i965_device_destroy (void *base)
+{
+ i965_device_t *device = base;
+
+ i965_device_reset (device);
+ i965_general_state_reset (device);
+
+ _cairo_hash_table_destroy (device->sf_states);
+ _cairo_hash_table_destroy (device->samplers);
+ _cairo_hash_table_destroy (device->cc_states);
+ _cairo_hash_table_destroy (device->wm_kernels);
+ _cairo_hash_table_destroy (device->wm_states);
+ _cairo_hash_table_destroy (device->wm_bindings);
+
+ _cairo_freelist_fini (&device->sf_freelist);
+ _cairo_freelist_fini (&device->cc_freelist);
+ _cairo_freelist_fini (&device->wm_kernel_freelist);
+ _cairo_freelist_fini (&device->wm_state_freelist);
+ _cairo_freelist_fini (&device->wm_binding_freelist);
+ _cairo_freelist_fini (&device->sampler_freelist);
+
+ intel_device_fini (&device->intel);
+ free (device);
+}
+
+static cairo_bool_t
+hash_equal (const void *A, const void *B)
+{
+ const cairo_hash_entry_t *a = A, *b = B;
+ return a->hash == b->hash;
+}
+
+cairo_drm_device_t *
+_cairo_drm_i965_device_create (int fd, dev_t dev, int vendor_id, int chip_id)
+{
+ i965_device_t *device;
+ uint64_t gtt_size;
+ cairo_status_t status;
+
+ if (! intel_info (fd, >t_size))
+ return NULL;
+
+ device = malloc (sizeof (i965_device_t));
+ if (unlikely (device == NULL))
+ return (cairo_drm_device_t *) _cairo_device_create_in_error (CAIRO_STATUS_NO_MEMORY);
+
+ status = intel_device_init (&device->intel, fd);
+ if (unlikely (status))
+ goto CLEANUP;
+
+ device->is_g4x = IS_G4X (chip_id);
+ //device->is_g5x = IS_G5X (chip_id);
+
+ device->intel.base.surface.create = i965_surface_create;
+ device->intel.base.surface.create_for_name = i965_surface_create_for_name;
+ device->intel.base.surface.create_from_cacheable_image = NULL;
+ device->intel.base.surface.enable_scan_out = i965_surface_enable_scan_out;
+
+ device->intel.base.device.flush = _i965_device_flush;
+ device->intel.base.device.throttle = _i965_device_throttle;
+ device->intel.base.device.destroy = _i965_device_destroy;
+
+ device->sf_states = _cairo_hash_table_create (i965_sf_state_equal);
+ if (unlikely (device->sf_states == NULL))
+ goto CLEANUP_INTEL;
+
+ _cairo_freelist_init (&device->sf_freelist,
+ sizeof (struct i965_sf_state));
+
+
+ device->cc_states = _cairo_hash_table_create (i965_cc_state_equal);
+ if (unlikely (device->cc_states == NULL))
+ goto CLEANUP_SF;
+
+ _cairo_freelist_init (&device->cc_freelist,
+ sizeof (struct i965_cc_state));
+
+
+ device->wm_kernels = _cairo_hash_table_create (hash_equal);
+ if (unlikely (device->wm_kernels == NULL))
+ goto CLEANUP_CC;
+
+ _cairo_freelist_init (&device->wm_kernel_freelist,
+ sizeof (struct i965_wm_kernel));
+
+ device->wm_states = _cairo_hash_table_create (i965_wm_state_equal);
+ if (unlikely (device->wm_states == NULL))
+ goto CLEANUP_WM_KERNEL;
+
+ _cairo_freelist_init (&device->wm_state_freelist,
+ sizeof (struct i965_wm_state));
+
+
+ device->wm_bindings = _cairo_hash_table_create (i965_wm_binding_equal);
+ if (unlikely (device->wm_bindings == NULL))
+ goto CLEANUP_WM_STATE;
+
+ _cairo_freelist_init (&device->wm_binding_freelist,
+ sizeof (struct i965_wm_binding));
+
+ device->samplers = _cairo_hash_table_create (hash_equal);
+ if (unlikely (device->samplers == NULL))
+ goto CLEANUP_WM_BINDING;
+
+ _cairo_freelist_init (&device->sampler_freelist,
+ sizeof (struct i965_sampler));
+
+ i965_stream_init (&device->batch,
+ device->batch_base, sizeof (device->batch_base),
+ NULL, 0,
+ device->batch_relocations,
+ ARRAY_LENGTH (device->batch_relocations));
+
+ i965_stream_init (&device->surface,
+ device->surface_base, sizeof (device->surface_base),
+ device->surface_pending_relocations,
+ ARRAY_LENGTH (device->surface_pending_relocations),
+ device->surface_relocations,
+ ARRAY_LENGTH (device->surface_relocations));
+
+ i965_stream_init (&device->general,
+ device->general_base, sizeof (device->general_base),
+ device->general_pending_relocations,
+ ARRAY_LENGTH (device->general_pending_relocations),
+ NULL, 0);
+
+ i965_stream_init (&device->vertex,
+ device->vertex_base, sizeof (device->vertex_base),
+ device->vertex_pending_relocations,
+ ARRAY_LENGTH (device->vertex_pending_relocations),
+ NULL, 0);
+
+ i965_stream_init (&device->constant,
+ device->constant_base, sizeof (device->constant_base),
+ device->constant_pending_relocations,
+ ARRAY_LENGTH (device->constant_pending_relocations),
+ NULL, 0);
+
+ cairo_list_init (&device->flush);
+ i965_device_reset (device);
+ device->vs_offset = (uint32_t) -1;
+ device->border_color_offset = (uint32_t) -1;
+ device->general_state = NULL;
+
+ return _cairo_drm_device_init (&device->intel.base,
+ fd, dev, vendor_id, chip_id,
+ I965_MAX_SIZE);
+
+ CLEANUP_WM_BINDING:
+ _cairo_hash_table_destroy (device->wm_bindings);
+ CLEANUP_WM_STATE:
+ _cairo_hash_table_destroy (device->wm_states);
+ CLEANUP_WM_KERNEL:
+ _cairo_hash_table_destroy (device->wm_kernels);
+ CLEANUP_CC:
+ _cairo_hash_table_destroy (device->cc_states);
+ CLEANUP_SF:
+ _cairo_hash_table_destroy (device->sf_states);
+ CLEANUP_INTEL:
+ intel_device_fini (&device->intel);
+ CLEANUP:
+ free (device);
+ return (cairo_drm_device_t *) _cairo_device_create_in_error (status);
+}
diff --git a/src/drm/cairo-drm-intel-brw-defines.h b/src/drm/cairo-drm-intel-brw-defines.h
new file mode 100644
index 0000000..b2be36f
--- /dev/null
+++ b/src/drm/cairo-drm-intel-brw-defines.h
@@ -0,0 +1,824 @@
+/**************************************************************************
+ *
+ * Copyright 2005 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+#ifndef CAIRO_DRM_INTEL_BRW_DEFINES_H
+#define CAIRO_DRM_INTEL_BRW_DEFINES_H
+
+/* 3D state: */
+#define _3DOP_3DSTATE_PIPELINED 0x0
+#define _3DOP_3DSTATE_NONPIPELINED 0x1
+#define _3DOP_3DCONTROL 0x2
+#define _3DOP_3DPRIMITIVE 0x3
+
+#define _3DSTATE_PIPELINED_POINTERS 0x00
+#define _3DSTATE_BINDING_TABLE_POINTERS 0x01
+#define _3DSTATE_VERTEX_BUFFERS 0x08
+#define _3DSTATE_VERTEX_ELEMENTS 0x09
+#define _3DSTATE_INDEX_BUFFER 0x0A
+#define _3DSTATE_VF_STATISTICS 0x0B
+#define _3DSTATE_DRAWING_RECTANGLE 0x00
+#define _3DSTATE_CONSTANT_COLOR 0x01
+#define _3DSTATE_SAMPLER_PALETTE_LOAD 0x02
+#define _3DSTATE_CHROMA_KEY 0x04
+#define _3DSTATE_DEPTH_BUFFER 0x05
+#define _3DSTATE_POLY_STIPPLE_OFFSET 0x06
+#define _3DSTATE_POLY_STIPPLE_PATTERN 0x07
+#define _3DSTATE_LINE_STIPPLE 0x08
+#define _3DSTATE_GLOBAL_DEPTH_OFFSET_CLAMP 0x09
+#define _3DCONTROL 0x00
+#define _3DPRIMITIVE 0x00
+
+#define PIPE_CONTROL_NOWRITE 0x00
+#define PIPE_CONTROL_WRITEIMMEDIATE 0x01
+#define PIPE_CONTROL_WRITEDEPTH 0x02
+#define PIPE_CONTROL_WRITETIMESTAMP 0x03
+
+#define PIPE_CONTROL_GTTWRITE_PROCESS_LOCAL 0x00
+#define PIPE_CONTROL_GTTWRITE_GLOBAL 0x01
+
+#define BRW_3D(Pipeline,Opcode,Subopcode) ((3 << 29) | \
+ ((Pipeline) << 27) | \
+ ((Opcode) << 24) | \
+ ((Subopcode) << 16))
+
+#define BRW_PIPE_CONTROL BRW_3D(3, 2, 0)
+#define BRW_PIPE_CONTROL_NOWRITE (0 << 14)
+#define BRW_PIPE_CONTROL_WRITE_QWORD (1 << 14)
+#define BRW_PIPE_CONTROL_WRITE_DEPTH (2 << 14)
+#define BRW_PIPE_CONTROL_WRITE_TIME (3 << 14)
+#define BRW_PIPE_CONTROL_DEPTH_STALL (1 << 13)
+#define BRW_PIPE_CONTROL_WC_FLUSH (1 << 12)
+#define BRW_PIPE_CONTROL_IS_FLUSH (1 << 11)
+#define BRW_PIPE_CONTROL_NOTIFY_ENABLE (1 << 8)
+#define BRW_PIPE_CONTROL_GLOBAL_GTT (1 << 2)
+#define BRW_PIPE_CONTROL_LOCAL_PGTT (0 << 2)
+
+#define _3DPRIM_POINTLIST 0x01
+#define _3DPRIM_LINELIST 0x02
+#define _3DPRIM_LINESTRIP 0x03
+#define _3DPRIM_TRILIST 0x04
+#define _3DPRIM_TRISTRIP 0x05
+#define _3DPRIM_TRIFAN 0x06
+#define _3DPRIM_QUADLIST 0x07
+#define _3DPRIM_QUADSTRIP 0x08
+#define _3DPRIM_LINELIST_ADJ 0x09
+#define _3DPRIM_LINESTRIP_ADJ 0x0A
+#define _3DPRIM_TRILIST_ADJ 0x0B
+#define _3DPRIM_TRISTRIP_ADJ 0x0C
+#define _3DPRIM_TRISTRIP_REVERSE 0x0D
+#define _3DPRIM_POLYGON 0x0E
+#define _3DPRIM_RECTLIST 0x0F
+#define _3DPRIM_LINELOOP 0x10
+#define _3DPRIM_POINTLIST_BF 0x11
+#define _3DPRIM_LINESTRIP_CONT 0x12
+#define _3DPRIM_LINESTRIP_BF 0x13
+#define _3DPRIM_LINESTRIP_CONT_BF 0x14
+#define _3DPRIM_TRIFAN_NOSTIPPLE 0x15
+
+#define _3DPRIM_VERTEXBUFFER_ACCESS_SEQUENTIAL 0
+#define _3DPRIM_VERTEXBUFFER_ACCESS_RANDOM 1
+
+#define BRW_ANISORATIO_2 0
+#define BRW_ANISORATIO_4 1
+#define BRW_ANISORATIO_6 2
+#define BRW_ANISORATIO_8 3
+#define BRW_ANISORATIO_10 4
+#define BRW_ANISORATIO_12 5
+#define BRW_ANISORATIO_14 6
+#define BRW_ANISORATIO_16 7
+
+#define BRW_BLENDFACTOR_ONE 0x1
+#define BRW_BLENDFACTOR_SRC_COLOR 0x2
+#define BRW_BLENDFACTOR_SRC_ALPHA 0x3
+#define BRW_BLENDFACTOR_DST_ALPHA 0x4
+#define BRW_BLENDFACTOR_DST_COLOR 0x5
+#define BRW_BLENDFACTOR_SRC_ALPHA_SATURATE 0x6
+#define BRW_BLENDFACTOR_CONST_COLOR 0x7
+#define BRW_BLENDFACTOR_CONST_ALPHA 0x8
+#define BRW_BLENDFACTOR_SRC1_COLOR 0x9
+#define BRW_BLENDFACTOR_SRC1_ALPHA 0x0A
+#define BRW_BLENDFACTOR_ZERO 0x11
+#define BRW_BLENDFACTOR_INV_SRC_COLOR 0x12
+#define BRW_BLENDFACTOR_INV_SRC_ALPHA 0x13
+#define BRW_BLENDFACTOR_INV_DST_ALPHA 0x14
+#define BRW_BLENDFACTOR_INV_DST_COLOR 0x15
+#define BRW_BLENDFACTOR_INV_CONST_COLOR 0x17
+#define BRW_BLENDFACTOR_INV_CONST_ALPHA 0x18
+#define BRW_BLENDFACTOR_INV_SRC1_COLOR 0x19
+#define BRW_BLENDFACTOR_INV_SRC1_ALPHA 0x1A
+
+#define BRW_BLENDFUNCTION_ADD 0
+#define BRW_BLENDFUNCTION_SUBTRACT 1
+#define BRW_BLENDFUNCTION_REVERSE_SUBTRACT 2
+#define BRW_BLENDFUNCTION_MIN 3
+#define BRW_BLENDFUNCTION_MAX 4
+
+#define BRW_ALPHATEST_FORMAT_UNORM8 0
+#define BRW_ALPHATEST_FORMAT_FLOAT32 1
+
+#define BRW_CHROMAKEY_KILL_ON_ANY_MATCH 0
+#define BRW_CHROMAKEY_REPLACE_BLACK 1
+
+#define BRW_CLIP_API_OGL 0
+#define BRW_CLIP_API_DX 1
+
+#define BRW_CLIPMODE_NORMAL 0
+#define BRW_CLIPMODE_CLIP_ALL 1
+#define BRW_CLIPMODE_CLIP_NON_REJECTED 2
+#define BRW_CLIPMODE_REJECT_ALL 3
+#define BRW_CLIPMODE_ACCEPT_ALL 4
+
+#define BRW_CLIP_NDCSPACE 0
+#define BRW_CLIP_SCREENSPACE 1
+
+#define BRW_COMPAREFUNCTION_ALWAYS 0
+#define BRW_COMPAREFUNCTION_NEVER 1
+#define BRW_COMPAREFUNCTION_LESS 2
+#define BRW_COMPAREFUNCTION_EQUAL 3
+#define BRW_COMPAREFUNCTION_LEQUAL 4
+#define BRW_COMPAREFUNCTION_GREATER 5
+#define BRW_COMPAREFUNCTION_NOTEQUAL 6
+#define BRW_COMPAREFUNCTION_GEQUAL 7
+
+#define BRW_COVERAGE_PIXELS_HALF 0
+#define BRW_COVERAGE_PIXELS_1 1
+#define BRW_COVERAGE_PIXELS_2 2
+#define BRW_COVERAGE_PIXELS_4 3
+
+#define BRW_CULLMODE_BOTH 0
+#define BRW_CULLMODE_NONE 1
+#define BRW_CULLMODE_FRONT 2
+#define BRW_CULLMODE_BACK 3
+
+#define BRW_DEFAULTCOLOR_R8G8B8A8_UNORM 0
+#define BRW_DEFAULTCOLOR_R32G32B32A32_FLOAT 1
+
+#define BRW_DEPTHFORMAT_D32_FLOAT_S8X24_UINT 0
+#define BRW_DEPTHFORMAT_D32_FLOAT 1
+#define BRW_DEPTHFORMAT_D24_UNORM_S8_UINT 2
+#define BRW_DEPTHFORMAT_D16_UNORM 5
+
+#define BRW_FLOATING_POINT_IEEE_754 0
+#define BRW_FLOATING_POINT_NON_IEEE_754 1
+
+#define BRW_FRONTWINDING_CW 0
+#define BRW_FRONTWINDING_CCW 1
+
+#define BRW_INDEX_BYTE 0
+#define BRW_INDEX_WORD 1
+#define BRW_INDEX_DWORD 2
+
+#define BRW_LOGICOPFUNCTION_CLEAR 0
+#define BRW_LOGICOPFUNCTION_NOR 1
+#define BRW_LOGICOPFUNCTION_AND_INVERTED 2
+#define BRW_LOGICOPFUNCTION_COPY_INVERTED 3
+#define BRW_LOGICOPFUNCTION_AND_REVERSE 4
+#define BRW_LOGICOPFUNCTION_INVERT 5
+#define BRW_LOGICOPFUNCTION_XOR 6
+#define BRW_LOGICOPFUNCTION_NAND 7
+#define BRW_LOGICOPFUNCTION_AND 8
+#define BRW_LOGICOPFUNCTION_EQUIV 9
+#define BRW_LOGICOPFUNCTION_NOOP 10
+#define BRW_LOGICOPFUNCTION_OR_INVERTED 11
+#define BRW_LOGICOPFUNCTION_COPY 12
+#define BRW_LOGICOPFUNCTION_OR_REVERSE 13
+#define BRW_LOGICOPFUNCTION_OR 14
+#define BRW_LOGICOPFUNCTION_SET 15
+
+#define BRW_MAPFILTER_NEAREST 0x0
+#define BRW_MAPFILTER_LINEAR 0x1
+#define BRW_MAPFILTER_ANISOTROPIC 0x2
+
+#define BRW_MIPFILTER_NONE 0
+#define BRW_MIPFILTER_NEAREST 1
+#define BRW_MIPFILTER_LINEAR 3
+
+#define BRW_POLYGON_FRONT_FACING 0
+#define BRW_POLYGON_BACK_FACING 1
+
+#define BRW_PREFILTER_ALWAYS 0x0
+#define BRW_PREFILTER_NEVER 0x1
+#define BRW_PREFILTER_LESS 0x2
+#define BRW_PREFILTER_EQUAL 0x3
+#define BRW_PREFILTER_LEQUAL 0x4
+#define BRW_PREFILTER_GREATER 0x5
+#define BRW_PREFILTER_NOTEQUAL 0x6
+#define BRW_PREFILTER_GEQUAL 0x7
+
+#define BRW_PROVOKING_VERTEX_0 0
+#define BRW_PROVOKING_VERTEX_1 1
+#define BRW_PROVOKING_VERTEX_2 2
+
+#define BRW_RASTRULE_UPPER_LEFT 0
+#define BRW_RASTRULE_UPPER_RIGHT 1
+
+#define BRW_RENDERTARGET_CLAMPRANGE_UNORM 0
+#define BRW_RENDERTARGET_CLAMPRANGE_SNORM 1
+#define BRW_RENDERTARGET_CLAMPRANGE_FORMAT 2
+
+#define BRW_STENCILOP_KEEP 0
+#define BRW_STENCILOP_ZERO 1
+#define BRW_STENCILOP_REPLACE 2
+#define BRW_STENCILOP_INCRSAT 3
+#define BRW_STENCILOP_DECRSAT 4
+#define BRW_STENCILOP_INCR 5
+#define BRW_STENCILOP_DECR 6
+#define BRW_STENCILOP_INVERT 7
+
+#define BRW_SURFACE_MIPMAPLAYOUT_BELOW 0
+#define BRW_SURFACE_MIPMAPLAYOUT_RIGHT 1
+
+#define BRW_SURFACEFORMAT_R32G32B32A32_FLOAT 0x000
+#define BRW_SURFACEFORMAT_R32G32B32A32_SINT 0x001
+#define BRW_SURFACEFORMAT_R32G32B32A32_UINT 0x002
+#define BRW_SURFACEFORMAT_R32G32B32A32_UNORM 0x003
+#define BRW_SURFACEFORMAT_R32G32B32A32_SNORM 0x004
+#define BRW_SURFACEFORMAT_R64G64_FLOAT 0x005
+#define BRW_SURFACEFORMAT_R32G32B32X32_FLOAT 0x006
+#define BRW_SURFACEFORMAT_R32G32B32A32_SSCALED 0x007
+#define BRW_SURFACEFORMAT_R32G32B32A32_USCALED 0x008
+#define BRW_SURFACEFORMAT_R32G32B32_FLOAT 0x040
+#define BRW_SURFACEFORMAT_R32G32B32_SINT 0x041
+#define BRW_SURFACEFORMAT_R32G32B32_UINT 0x042
+#define BRW_SURFACEFORMAT_R32G32B32_UNORM 0x043
+#define BRW_SURFACEFORMAT_R32G32B32_SNORM 0x044
+#define BRW_SURFACEFORMAT_R32G32B32_SSCALED 0x045
+#define BRW_SURFACEFORMAT_R32G32B32_USCALED 0x046
+#define BRW_SURFACEFORMAT_R16G16B16A16_UNORM 0x080
+#define BRW_SURFACEFORMAT_R16G16B16A16_SNORM 0x081
+#define BRW_SURFACEFORMAT_R16G16B16A16_SINT 0x082
+#define BRW_SURFACEFORMAT_R16G16B16A16_UINT 0x083
+#define BRW_SURFACEFORMAT_R16G16B16A16_FLOAT 0x084
+#define BRW_SURFACEFORMAT_R32G32_FLOAT 0x085
+#define BRW_SURFACEFORMAT_R32G32_SINT 0x086
+#define BRW_SURFACEFORMAT_R32G32_UINT 0x087
+#define BRW_SURFACEFORMAT_R32_FLOAT_X8X24_TYPELESS 0x088
+#define BRW_SURFACEFORMAT_X32_TYPELESS_G8X24_UINT 0x089
+#define BRW_SURFACEFORMAT_L32A32_FLOAT 0x08A
+#define BRW_SURFACEFORMAT_R32G32_UNORM 0x08B
+#define BRW_SURFACEFORMAT_R32G32_SNORM 0x08C
+#define BRW_SURFACEFORMAT_R64_FLOAT 0x08D
+#define BRW_SURFACEFORMAT_R16G16B16X16_UNORM 0x08E
+#define BRW_SURFACEFORMAT_R16G16B16X16_FLOAT 0x08F
+#define BRW_SURFACEFORMAT_A32X32_FLOAT 0x090
+#define BRW_SURFACEFORMAT_L32X32_FLOAT 0x091
+#define BRW_SURFACEFORMAT_I32X32_FLOAT 0x092
+#define BRW_SURFACEFORMAT_R16G16B16A16_SSCALED 0x093
+#define BRW_SURFACEFORMAT_R16G16B16A16_USCALED 0x094
+#define BRW_SURFACEFORMAT_R32G32_SSCALED 0x095
+#define BRW_SURFACEFORMAT_R32G32_USCALED 0x096
+#define BRW_SURFACEFORMAT_B8G8R8A8_UNORM 0x0C0
+#define BRW_SURFACEFORMAT_B8G8R8A8_UNORM_SRGB 0x0C1
+#define BRW_SURFACEFORMAT_R10G10B10A2_UNORM 0x0C2
+#define BRW_SURFACEFORMAT_R10G10B10A2_UNORM_SRGB 0x0C3
+#define BRW_SURFACEFORMAT_R10G10B10A2_UINT 0x0C4
+#define BRW_SURFACEFORMAT_R10G10B10_SNORM_A2_UNORM 0x0C5
+#define BRW_SURFACEFORMAT_R8G8B8A8_UNORM 0x0C7
+#define BRW_SURFACEFORMAT_R8G8B8A8_UNORM_SRGB 0x0C8
+#define BRW_SURFACEFORMAT_R8G8B8A8_SNORM 0x0C9
+#define BRW_SURFACEFORMAT_R8G8B8A8_SINT 0x0CA
+#define BRW_SURFACEFORMAT_R8G8B8A8_UINT 0x0CB
+#define BRW_SURFACEFORMAT_R16G16_UNORM 0x0CC
+#define BRW_SURFACEFORMAT_R16G16_SNORM 0x0CD
+#define BRW_SURFACEFORMAT_R16G16_SINT 0x0CE
+#define BRW_SURFACEFORMAT_R16G16_UINT 0x0CF
+#define BRW_SURFACEFORMAT_R16G16_FLOAT 0x0D0
+#define BRW_SURFACEFORMAT_B10G10R10A2_UNORM 0x0D1
+#define BRW_SURFACEFORMAT_B10G10R10A2_UNORM_SRGB 0x0D2
+#define BRW_SURFACEFORMAT_R11G11B10_FLOAT 0x0D3
+#define BRW_SURFACEFORMAT_R32_SINT 0x0D6
+#define BRW_SURFACEFORMAT_R32_UINT 0x0D7
+#define BRW_SURFACEFORMAT_R32_FLOAT 0x0D8
+#define BRW_SURFACEFORMAT_R24_UNORM_X8_TYPELESS 0x0D9
+#define BRW_SURFACEFORMAT_X24_TYPELESS_G8_UINT 0x0DA
+#define BRW_SURFACEFORMAT_L16A16_UNORM 0x0DF
+#define BRW_SURFACEFORMAT_I24X8_UNORM 0x0E0
+#define BRW_SURFACEFORMAT_L24X8_UNORM 0x0E1
+#define BRW_SURFACEFORMAT_A24X8_UNORM 0x0E2
+#define BRW_SURFACEFORMAT_I32_FLOAT 0x0E3
+#define BRW_SURFACEFORMAT_L32_FLOAT 0x0E4
+#define BRW_SURFACEFORMAT_A32_FLOAT 0x0E5
+#define BRW_SURFACEFORMAT_B8G8R8X8_UNORM 0x0E9
+#define BRW_SURFACEFORMAT_B8G8R8X8_UNORM_SRGB 0x0EA
+#define BRW_SURFACEFORMAT_R8G8B8X8_UNORM 0x0EB
+#define BRW_SURFACEFORMAT_R8G8B8X8_UNORM_SRGB 0x0EC
+#define BRW_SURFACEFORMAT_R9G9B9E5_SHAREDEXP 0x0ED
+#define BRW_SURFACEFORMAT_B10G10R10X2_UNORM 0x0EE
+#define BRW_SURFACEFORMAT_L16A16_FLOAT 0x0F0
+#define BRW_SURFACEFORMAT_R32_UNORM 0x0F1
+#define BRW_SURFACEFORMAT_R32_SNORM 0x0F2
+#define BRW_SURFACEFORMAT_R10G10B10X2_USCALED 0x0F3
+#define BRW_SURFACEFORMAT_R8G8B8A8_SSCALED 0x0F4
+#define BRW_SURFACEFORMAT_R8G8B8A8_USCALED 0x0F5
+#define BRW_SURFACEFORMAT_R16G16_SSCALED 0x0F6
+#define BRW_SURFACEFORMAT_R16G16_USCALED 0x0F7
+#define BRW_SURFACEFORMAT_R32_SSCALED 0x0F8
+#define BRW_SURFACEFORMAT_R32_USCALED 0x0F9
+#define BRW_SURFACEFORMAT_B5G6R5_UNORM 0x100
+#define BRW_SURFACEFORMAT_B5G6R5_UNORM_SRGB 0x101
+#define BRW_SURFACEFORMAT_B5G5R5A1_UNORM 0x102
+#define BRW_SURFACEFORMAT_B5G5R5A1_UNORM_SRGB 0x103
+#define BRW_SURFACEFORMAT_B4G4R4A4_UNORM 0x104
+#define BRW_SURFACEFORMAT_B4G4R4A4_UNORM_SRGB 0x105
+#define BRW_SURFACEFORMAT_R8G8_UNORM 0x106
+#define BRW_SURFACEFORMAT_R8G8_SNORM 0x107
+#define BRW_SURFACEFORMAT_R8G8_SINT 0x108
+#define BRW_SURFACEFORMAT_R8G8_UINT 0x109
+#define BRW_SURFACEFORMAT_R16_UNORM 0x10A
+#define BRW_SURFACEFORMAT_R16_SNORM 0x10B
+#define BRW_SURFACEFORMAT_R16_SINT 0x10C
+#define BRW_SURFACEFORMAT_R16_UINT 0x10D
+#define BRW_SURFACEFORMAT_R16_FLOAT 0x10E
+#define BRW_SURFACEFORMAT_I16_UNORM 0x111
+#define BRW_SURFACEFORMAT_L16_UNORM 0x112
+#define BRW_SURFACEFORMAT_A16_UNORM 0x113
+#define BRW_SURFACEFORMAT_L8A8_UNORM 0x114
+#define BRW_SURFACEFORMAT_I16_FLOAT 0x115
+#define BRW_SURFACEFORMAT_L16_FLOAT 0x116
+#define BRW_SURFACEFORMAT_A16_FLOAT 0x117
+#define BRW_SURFACEFORMAT_R5G5_SNORM_B6_UNORM 0x119
+#define BRW_SURFACEFORMAT_B5G5R5X1_UNORM 0x11A
+#define BRW_SURFACEFORMAT_B5G5R5X1_UNORM_SRGB 0x11B
+#define BRW_SURFACEFORMAT_R8G8_SSCALED 0x11C
+#define BRW_SURFACEFORMAT_R8G8_USCALED 0x11D
+#define BRW_SURFACEFORMAT_R16_SSCALED 0x11E
+#define BRW_SURFACEFORMAT_R16_USCALED 0x11F
+#define BRW_SURFACEFORMAT_R8_UNORM 0x140
+#define BRW_SURFACEFORMAT_R8_SNORM 0x141
+#define BRW_SURFACEFORMAT_R8_SINT 0x142
+#define BRW_SURFACEFORMAT_R8_UINT 0x143
+#define BRW_SURFACEFORMAT_A8_UNORM 0x144
+#define BRW_SURFACEFORMAT_I8_UNORM 0x145
+#define BRW_SURFACEFORMAT_L8_UNORM 0x146
+#define BRW_SURFACEFORMAT_P4A4_UNORM 0x147
+#define BRW_SURFACEFORMAT_A4P4_UNORM 0x148
+#define BRW_SURFACEFORMAT_R8_SSCALED 0x149
+#define BRW_SURFACEFORMAT_R8_USCALED 0x14A
+#define BRW_SURFACEFORMAT_R1_UINT 0x181
+#define BRW_SURFACEFORMAT_YCRCB_NORMAL 0x182
+#define BRW_SURFACEFORMAT_YCRCB_SWAPUVY 0x183
+#define BRW_SURFACEFORMAT_BC1_UNORM 0x186
+#define BRW_SURFACEFORMAT_BC2_UNORM 0x187
+#define BRW_SURFACEFORMAT_BC3_UNORM 0x188
+#define BRW_SURFACEFORMAT_BC4_UNORM 0x189
+#define BRW_SURFACEFORMAT_BC5_UNORM 0x18A
+#define BRW_SURFACEFORMAT_BC1_UNORM_SRGB 0x18B
+#define BRW_SURFACEFORMAT_BC2_UNORM_SRGB 0x18C
+#define BRW_SURFACEFORMAT_BC3_UNORM_SRGB 0x18D
+#define BRW_SURFACEFORMAT_MONO8 0x18E
+#define BRW_SURFACEFORMAT_YCRCB_SWAPUV 0x18F
+#define BRW_SURFACEFORMAT_YCRCB_SWAPY 0x190
+#define BRW_SURFACEFORMAT_DXT1_RGB 0x191
+#define BRW_SURFACEFORMAT_FXT1 0x192
+#define BRW_SURFACEFORMAT_R8G8B8_UNORM 0x193
+#define BRW_SURFACEFORMAT_R8G8B8_SNORM 0x194
+#define BRW_SURFACEFORMAT_R8G8B8_SSCALED 0x195
+#define BRW_SURFACEFORMAT_R8G8B8_USCALED 0x196
+#define BRW_SURFACEFORMAT_R64G64B64A64_FLOAT 0x197
+#define BRW_SURFACEFORMAT_R64G64B64_FLOAT 0x198
+#define BRW_SURFACEFORMAT_BC4_SNORM 0x199
+#define BRW_SURFACEFORMAT_BC5_SNORM 0x19A
+#define BRW_SURFACEFORMAT_R16G16B16_UNORM 0x19C
+#define BRW_SURFACEFORMAT_R16G16B16_SNORM 0x19D
+#define BRW_SURFACEFORMAT_R16G16B16_SSCALED 0x19E
+#define BRW_SURFACEFORMAT_R16G16B16_USCALED 0x19F
+
+#define BRW_SURFACERETURNFORMAT_FLOAT32 0
+#define BRW_SURFACERETURNFORMAT_S1 1
+
+#define BRW_SURFACE_1D 0
+#define BRW_SURFACE_2D 1
+#define BRW_SURFACE_3D 2
+#define BRW_SURFACE_CUBE 3
+#define BRW_SURFACE_BUFFER 4
+#define BRW_SURFACE_NULL 7
+
+#define BRW_BORDER_COLOR_MODE_DEFAULT 0
+#define BRW_BORDER_COLOR_MODE_LEGACY 1
+
+#define BRW_TEXCOORDMODE_WRAP 0
+#define BRW_TEXCOORDMODE_MIRROR 1
+#define BRW_TEXCOORDMODE_CLAMP 2
+#define BRW_TEXCOORDMODE_CUBE 3
+#define BRW_TEXCOORDMODE_CLAMP_BORDER 4
+#define BRW_TEXCOORDMODE_MIRROR_ONCE 5
+
+#define BRW_THREAD_PRIORITY_NORMAL 0
+#define BRW_THREAD_PRIORITY_HIGH 1
+
+#define BRW_TILEWALK_XMAJOR 0
+#define BRW_TILEWALK_YMAJOR 1
+
+#define BRW_VERTEX_SUBPIXEL_PRECISION_8BITS 0
+#define BRW_VERTEX_SUBPIXEL_PRECISION_4BITS 1
+
+#define BRW_VERTEXBUFFER_ACCESS_VERTEXDATA 0
+#define BRW_VERTEXBUFFER_ACCESS_INSTANCEDATA 1
+
+#define BRW_VFCOMPONENT_NOSTORE 0
+#define BRW_VFCOMPONENT_STORE_SRC 1
+#define BRW_VFCOMPONENT_STORE_0 2
+#define BRW_VFCOMPONENT_STORE_1_FLT 3
+#define BRW_VFCOMPONENT_STORE_1_INT 4
+#define BRW_VFCOMPONENT_STORE_VID 5
+#define BRW_VFCOMPONENT_STORE_IID 6
+#define BRW_VFCOMPONENT_STORE_PID 7
+
+
+
+/* Execution Unit (EU) defines */
+
+#define BRW_ALIGN_1 0
+#define BRW_ALIGN_16 1
+
+#define BRW_ADDRESS_DIRECT 0
+#define BRW_ADDRESS_REGISTER_INDIRECT_REGISTER 1
+
+#define BRW_CHANNEL_X 0
+#define BRW_CHANNEL_Y 1
+#define BRW_CHANNEL_Z 2
+#define BRW_CHANNEL_W 3
+
+#define BRW_COMPRESSION_NONE 0
+#define BRW_COMPRESSION_2NDHALF 1
+#define BRW_COMPRESSION_COMPRESSED 2
+
+#define BRW_CONDITIONAL_NONE 0
+#define BRW_CONDITIONAL_Z 1
+#define BRW_CONDITIONAL_NZ 2
+#define BRW_CONDITIONAL_EQ 1 /* Z */
+#define BRW_CONDITIONAL_NEQ 2 /* NZ */
+#define BRW_CONDITIONAL_G 3
+#define BRW_CONDITIONAL_GE 4
+#define BRW_CONDITIONAL_L 5
+#define BRW_CONDITIONAL_LE 6
+#define BRW_CONDITIONAL_C 7
+#define BRW_CONDITIONAL_O 8
+
+#define BRW_DEBUG_NONE 0
+#define BRW_DEBUG_BREAKPOINT 1
+
+#define BRW_DEPENDENCY_NORMAL 0
+#define BRW_DEPENDENCY_NOTCLEARED 1
+#define BRW_DEPENDENCY_NOTCHECKED 2
+#define BRW_DEPENDENCY_DISABLE 3
+
+#define BRW_EXECUTE_1 0
+#define BRW_EXECUTE_2 1
+#define BRW_EXECUTE_4 2
+#define BRW_EXECUTE_8 3
+#define BRW_EXECUTE_16 4
+#define BRW_EXECUTE_32 5
+
+#define BRW_HORIZONTAL_STRIDE_0 0
+#define BRW_HORIZONTAL_STRIDE_1 1
+#define BRW_HORIZONTAL_STRIDE_2 2
+#define BRW_HORIZONTAL_STRIDE_4 3
+
+#define BRW_INSTRUCTION_NORMAL 0
+#define BRW_INSTRUCTION_SATURATE 1
+
+#define BRW_MASK_ENABLE 0
+#define BRW_MASK_DISABLE 1
+
+#define BRW_OPCODE_MOV 1
+#define BRW_OPCODE_SEL 2
+#define BRW_OPCODE_NOT 4
+#define BRW_OPCODE_AND 5
+#define BRW_OPCODE_OR 6
+#define BRW_OPCODE_XOR 7
+#define BRW_OPCODE_SHR 8
+#define BRW_OPCODE_SHL 9
+#define BRW_OPCODE_RSR 10
+#define BRW_OPCODE_RSL 11
+#define BRW_OPCODE_ASR 12
+#define BRW_OPCODE_CMP 16
+#define BRW_OPCODE_JMPI 32
+#define BRW_OPCODE_IF 34
+#define BRW_OPCODE_IFF 35
+#define BRW_OPCODE_ELSE 36
+#define BRW_OPCODE_ENDIF 37
+#define BRW_OPCODE_DO 38
+#define BRW_OPCODE_WHILE 39
+#define BRW_OPCODE_BREAK 40
+#define BRW_OPCODE_CONTINUE 41
+#define BRW_OPCODE_HALT 42
+#define BRW_OPCODE_MSAVE 44
+#define BRW_OPCODE_MRESTORE 45
+#define BRW_OPCODE_PUSH 46
+#define BRW_OPCODE_POP 47
+#define BRW_OPCODE_WAIT 48
+#define BRW_OPCODE_SEND 49
+#define BRW_OPCODE_ADD 64
+#define BRW_OPCODE_MUL 65
+#define BRW_OPCODE_AVG 66
+#define BRW_OPCODE_FRC 67
+#define BRW_OPCODE_RNDU 68
+#define BRW_OPCODE_RNDD 69
+#define BRW_OPCODE_RNDE 70
+#define BRW_OPCODE_RNDZ 71
+#define BRW_OPCODE_MAC 72
+#define BRW_OPCODE_MACH 73
+#define BRW_OPCODE_LZD 74
+#define BRW_OPCODE_SAD2 80
+#define BRW_OPCODE_SADA2 81
+#define BRW_OPCODE_DP4 84
+#define BRW_OPCODE_DPH 85
+#define BRW_OPCODE_DP3 86
+#define BRW_OPCODE_DP2 87
+#define BRW_OPCODE_DPA2 88
+#define BRW_OPCODE_LINE 89
+#define BRW_OPCODE_NOP 126
+
+#define BRW_PREDICATE_NONE 0
+#define BRW_PREDICATE_NORMAL 1
+#define BRW_PREDICATE_ALIGN1_ANYV 2
+#define BRW_PREDICATE_ALIGN1_ALLV 3
+#define BRW_PREDICATE_ALIGN1_ANY2H 4
+#define BRW_PREDICATE_ALIGN1_ALL2H 5
+#define BRW_PREDICATE_ALIGN1_ANY4H 6
+#define BRW_PREDICATE_ALIGN1_ALL4H 7
+#define BRW_PREDICATE_ALIGN1_ANY8H 8
+#define BRW_PREDICATE_ALIGN1_ALL8H 9
+#define BRW_PREDICATE_ALIGN1_ANY16H 10
+#define BRW_PREDICATE_ALIGN1_ALL16H 11
+#define BRW_PREDICATE_ALIGN16_REPLICATE_X 2
+#define BRW_PREDICATE_ALIGN16_REPLICATE_Y 3
+#define BRW_PREDICATE_ALIGN16_REPLICATE_Z 4
+#define BRW_PREDICATE_ALIGN16_REPLICATE_W 5
+#define BRW_PREDICATE_ALIGN16_ANY4H 6
+#define BRW_PREDICATE_ALIGN16_ALL4H 7
+
+#define BRW_ARCHITECTURE_REGISTER_FILE 0
+#define BRW_GENERAL_REGISTER_FILE 1
+#define BRW_MESSAGE_REGISTER_FILE 2
+#define BRW_IMMEDIATE_VALUE 3
+
+#define BRW_REGISTER_TYPE_UD 0
+#define BRW_REGISTER_TYPE_D 1
+#define BRW_REGISTER_TYPE_UW 2
+#define BRW_REGISTER_TYPE_W 3
+#define BRW_REGISTER_TYPE_UB 4
+#define BRW_REGISTER_TYPE_B 5
+#define BRW_REGISTER_TYPE_VF 5 /* packed float vector, immediates only? */
+#define BRW_REGISTER_TYPE_HF 6
+#define BRW_REGISTER_TYPE_V 6 /* packed int vector, immediates only, uword dest only */
+#define BRW_REGISTER_TYPE_F 7
+
+#define BRW_ARF_NULL 0x00
+#define BRW_ARF_ADDRESS 0x10
+#define BRW_ARF_ACCUMULATOR 0x20
+#define BRW_ARF_FLAG 0x30
+#define BRW_ARF_MASK 0x40
+#define BRW_ARF_MASK_STACK 0x50
+#define BRW_ARF_MASK_STACK_DEPTH 0x60
+#define BRW_ARF_STATE 0x70
+#define BRW_ARF_CONTROL 0x80
+#define BRW_ARF_NOTIFICATION_COUNT 0x90
+#define BRW_ARF_IP 0xA0
+
+#define BRW_AMASK 0
+#define BRW_IMASK 1
+#define BRW_LMASK 2
+#define BRW_CMASK 3
+
+
+
+#define BRW_THREAD_NORMAL 0
+#define BRW_THREAD_ATOMIC 1
+#define BRW_THREAD_SWITCH 2
+
+#define BRW_VERTICAL_STRIDE_0 0
+#define BRW_VERTICAL_STRIDE_1 1
+#define BRW_VERTICAL_STRIDE_2 2
+#define BRW_VERTICAL_STRIDE_4 3
+#define BRW_VERTICAL_STRIDE_8 4
+#define BRW_VERTICAL_STRIDE_16 5
+#define BRW_VERTICAL_STRIDE_32 6
+#define BRW_VERTICAL_STRIDE_64 7
+#define BRW_VERTICAL_STRIDE_128 8
+#define BRW_VERTICAL_STRIDE_256 9
+#define BRW_VERTICAL_STRIDE_ONE_DIMENSIONAL 0xF
+
+#define BRW_WIDTH_1 0
+#define BRW_WIDTH_2 1
+#define BRW_WIDTH_4 2
+#define BRW_WIDTH_8 3
+#define BRW_WIDTH_16 4
+
+#define BRW_STATELESS_BUFFER_BOUNDARY_1K 0
+#define BRW_STATELESS_BUFFER_BOUNDARY_2K 1
+#define BRW_STATELESS_BUFFER_BOUNDARY_4K 2
+#define BRW_STATELESS_BUFFER_BOUNDARY_8K 3
+#define BRW_STATELESS_BUFFER_BOUNDARY_16K 4
+#define BRW_STATELESS_BUFFER_BOUNDARY_32K 5
+#define BRW_STATELESS_BUFFER_BOUNDARY_64K 6
+#define BRW_STATELESS_BUFFER_BOUNDARY_128K 7
+#define BRW_STATELESS_BUFFER_BOUNDARY_256K 8
+#define BRW_STATELESS_BUFFER_BOUNDARY_512K 9
+#define BRW_STATELESS_BUFFER_BOUNDARY_1M 10
+#define BRW_STATELESS_BUFFER_BOUNDARY_2M 11
+
+#define BRW_POLYGON_FACING_FRONT 0
+#define BRW_POLYGON_FACING_BACK 1
+
+#define BRW_MESSAGE_TARGET_NULL 0
+#define BRW_MESSAGE_TARGET_MATH 1
+#define BRW_MESSAGE_TARGET_SAMPLER 2
+#define BRW_MESSAGE_TARGET_GATEWAY 3
+#define BRW_MESSAGE_TARGET_DATAPORT_READ 4
+#define BRW_MESSAGE_TARGET_DATAPORT_WRITE 5
+#define BRW_MESSAGE_TARGET_URB 6
+#define BRW_MESSAGE_TARGET_THREAD_SPAWNER 7
+
+#define BRW_SAMPLER_RETURN_FORMAT_FLOAT32 0
+#define BRW_SAMPLER_RETURN_FORMAT_UINT32 2
+#define BRW_SAMPLER_RETURN_FORMAT_SINT32 3
+
+#define BRW_SAMPLER_MESSAGE_SIMD8_SAMPLE 0
+#define BRW_SAMPLER_MESSAGE_SIMD16_SAMPLE 0
+#define BRW_SAMPLER_MESSAGE_SIMD16_SAMPLE_BIAS 0
+#define BRW_SAMPLER_MESSAGE_SIMD8_KILLPIX 1
+#define BRW_SAMPLER_MESSAGE_SIMD4X2_SAMPLE_LOD 1
+#define BRW_SAMPLER_MESSAGE_SIMD16_SAMPLE_LOD 1
+#define BRW_SAMPLER_MESSAGE_SIMD4X2_SAMPLE_GRADIENTS 2
+#define BRW_SAMPLER_MESSAGE_SIMD8_SAMPLE_GRADIENTS 2
+#define BRW_SAMPLER_MESSAGE_SIMD4X2_SAMPLE_COMPARE 0
+#define BRW_SAMPLER_MESSAGE_SIMD16_SAMPLE_COMPARE 2
+#define BRW_SAMPLER_MESSAGE_SIMD4X2_RESINFO 2
+#define BRW_SAMPLER_MESSAGE_SIMD8_RESINFO 2
+#define BRW_SAMPLER_MESSAGE_SIMD16_RESINFO 2
+#define BRW_SAMPLER_MESSAGE_SIMD4X2_LD 3
+#define BRW_SAMPLER_MESSAGE_SIMD8_LD 3
+#define BRW_SAMPLER_MESSAGE_SIMD16_LD 3
+
+#define BRW_DATAPORT_OWORD_BLOCK_1_OWORDLOW 0
+#define BRW_DATAPORT_OWORD_BLOCK_1_OWORDHIGH 1
+#define BRW_DATAPORT_OWORD_BLOCK_2_OWORDS 2
+#define BRW_DATAPORT_OWORD_BLOCK_4_OWORDS 3
+#define BRW_DATAPORT_OWORD_BLOCK_8_OWORDS 4
+
+#define BRW_DATAPORT_OWORD_DUAL_BLOCK_1OWORD 0
+#define BRW_DATAPORT_OWORD_DUAL_BLOCK_4OWORDS 2
+
+#define BRW_DATAPORT_DWORD_SCATTERED_BLOCK_8DWORDS 2
+#define BRW_DATAPORT_DWORD_SCATTERED_BLOCK_16DWORDS 3
+
+#define BRW_DATAPORT_READ_MESSAGE_OWORD_BLOCK_READ 0
+#define BRW_DATAPORT_READ_MESSAGE_OWORD_DUAL_BLOCK_READ 1
+#define BRW_DATAPORT_READ_MESSAGE_DWORD_BLOCK_READ 2
+#define BRW_DATAPORT_READ_MESSAGE_DWORD_SCATTERED_READ 3
+
+#define BRW_DATAPORT_READ_TARGET_DATA_CACHE 0
+#define BRW_DATAPORT_READ_TARGET_RENDER_CACHE 1
+#define BRW_DATAPORT_READ_TARGET_SAMPLER_CACHE 2
+
+#define BRW_DATAPORT_RENDER_TARGET_WRITE_SIMD16_SINGLE_SOURCE 0
+#define BRW_DATAPORT_RENDER_TARGET_WRITE_SIMD16_SINGLE_SOURCE_REPLICATED 1
+#define BRW_DATAPORT_RENDER_TARGET_WRITE_SIMD8_DUAL_SOURCE_SUBSPAN01 2
+#define BRW_DATAPORT_RENDER_TARGET_WRITE_SIMD8_DUAL_SOURCE_SUBSPAN23 3
+#define BRW_DATAPORT_RENDER_TARGET_WRITE_SIMD8_SINGLE_SOURCE_SUBSPAN01 4
+
+#define BRW_DATAPORT_WRITE_MESSAGE_OWORD_BLOCK_WRITE 0
+#define BRW_DATAPORT_WRITE_MESSAGE_OWORD_DUAL_BLOCK_WRITE 1
+#define BRW_DATAPORT_WRITE_MESSAGE_DWORD_BLOCK_WRITE 2
+#define BRW_DATAPORT_WRITE_MESSAGE_DWORD_SCATTERED_WRITE 3
+#define BRW_DATAPORT_WRITE_MESSAGE_RENDER_TARGET_WRITE 4
+#define BRW_DATAPORT_WRITE_MESSAGE_STREAMED_VERTEX_BUFFER_WRITE 5
+#define BRW_DATAPORT_WRITE_MESSAGE_FLUSH_RENDER_CACHE 7
+
+#define BRW_MATH_FUNCTION_INV 1
+#define BRW_MATH_FUNCTION_LOG 2
+#define BRW_MATH_FUNCTION_EXP 3
+#define BRW_MATH_FUNCTION_SQRT 4
+#define BRW_MATH_FUNCTION_RSQ 5
+#define BRW_MATH_FUNCTION_SIN 6 /* was 7 */
+#define BRW_MATH_FUNCTION_COS 7 /* was 8 */
+#define BRW_MATH_FUNCTION_SINCOS 8 /* was 6 */
+#define BRW_MATH_FUNCTION_TAN 9
+#define BRW_MATH_FUNCTION_POW 10
+#define BRW_MATH_FUNCTION_INT_DIV_QUOTIENT_AND_REMAINDER 11
+#define BRW_MATH_FUNCTION_INT_DIV_QUOTIENT 12
+#define BRW_MATH_FUNCTION_INT_DIV_REMAINDER 13
+
+#define BRW_MATH_INTEGER_UNSIGNED 0
+#define BRW_MATH_INTEGER_SIGNED 1
+
+#define BRW_MATH_PRECISION_FULL 0
+#define BRW_MATH_PRECISION_PARTIAL 1
+
+#define BRW_MATH_SATURATE_NONE 0
+#define BRW_MATH_SATURATE_SATURATE 1
+
+#define BRW_MATH_DATA_VECTOR 0
+#define BRW_MATH_DATA_SCALAR 1
+
+#define BRW_URB_OPCODE_WRITE 0
+
+#define BRW_URB_SWIZZLE_NONE 0
+#define BRW_URB_SWIZZLE_INTERLEAVE 1
+#define BRW_URB_SWIZZLE_TRANSPOSE 2
+
+#define BRW_SCRATCH_SPACE_SIZE_1K 0
+#define BRW_SCRATCH_SPACE_SIZE_2K 1
+#define BRW_SCRATCH_SPACE_SIZE_4K 2
+#define BRW_SCRATCH_SPACE_SIZE_8K 3
+#define BRW_SCRATCH_SPACE_SIZE_16K 4
+#define BRW_SCRATCH_SPACE_SIZE_32K 5
+#define BRW_SCRATCH_SPACE_SIZE_64K 6
+#define BRW_SCRATCH_SPACE_SIZE_128K 7
+#define BRW_SCRATCH_SPACE_SIZE_256K 8
+#define BRW_SCRATCH_SPACE_SIZE_512K 9
+#define BRW_SCRATCH_SPACE_SIZE_1M 10
+#define BRW_SCRATCH_SPACE_SIZE_2M 11
+
+
+
+
+#define CMD_URB_FENCE 0x6000
+#define CMD_CONST_BUFFER_STATE 0x6001
+#define CMD_CONST_BUFFER 0x6002
+
+#define CMD_STATE_BASE_ADDRESS 0x6101
+#define CMD_STATE_INSN_POINTER 0x6102
+#define CMD_PIPELINE_SELECT 0x6104
+
+#define CMD_PIPELINED_STATE_POINTERS 0x7800
+#define CMD_BINDING_TABLE_PTRS 0x7801
+#define CMD_VERTEX_BUFFER 0x7808
+#define CMD_VERTEX_ELEMENT 0x7809
+#define CMD_INDEX_BUFFER 0x780a
+#define CMD_VF_STATISTICS 0x780b
+
+#define CMD_DRAW_RECT 0x7900
+#define CMD_BLEND_CONSTANT_COLOR 0x7901
+#define CMD_CHROMA_KEY 0x7904
+#define CMD_DEPTH_BUFFER 0x7905
+#define CMD_POLY_STIPPLE_OFFSET 0x7906
+#define CMD_POLY_STIPPLE_PATTERN 0x7907
+#define CMD_LINE_STIPPLE_PATTERN 0x7908
+#define CMD_GLOBAL_DEPTH_OFFSET_CLAMP 0x7908
+
+#define CMD_PIPE_CONTROL 0x7a00
+
+#define CMD_3D_PRIM 0x7b00
+
+#define CMD_MI_FLUSH 0x0200
+
+
+/* Various values from the R0 vertex header:
+ */
+#define R02_PRIM_END 0x1
+#define R02_PRIM_START 0x2
+
+/* media pipeline */
+
+#define BRW_VFE_MODE_GENERIC 0x0
+#define BRW_VFE_MODE_VLD_MPEG2 0x1
+#define BRW_VFE_MODE_IS 0x2
+#define BRW_VFE_MODE_AVC_MC 0x4
+#define BRW_VFE_MODE_AVC_IT 0x7
+#define BRW_VFE_MODE_VC1_IT 0xB
+
+#define BRW_VFE_DEBUG_COUNTER_FREE 0
+#define BRW_VFE_DEBUG_COUNTER_FROZEN 1
+#define BRW_VFE_DEBUG_COUNTER_ONCE 2
+#define BRW_VFE_DEBUG_COUNTER_ALWAYS 3
+
+/* VLD_STATE */
+#define BRW_MPEG_TOP_FIELD 1
+#define BRW_MPEG_BOTTOM_FIELD 2
+#define BRW_MPEG_FRAME 3
+#define BRW_MPEG_QSCALE_LINEAR 0
+#define BRW_MPEG_QSCALE_NONLINEAR 1
+#define BRW_MPEG_ZIGZAG_SCAN 0
+#define BRW_MPEG_ALTER_VERTICAL_SCAN 1
+#define BRW_MPEG_I_PICTURE 1
+#define BRW_MPEG_P_PICTURE 2
+#define BRW_MPEG_B_PICTURE 3
+
+#endif
diff --git a/src/drm/cairo-drm-intel-brw-eu-emit.c b/src/drm/cairo-drm-intel-brw-eu-emit.c
new file mode 100644
index 0000000..05bac0a
--- /dev/null
+++ b/src/drm/cairo-drm-intel-brw-eu-emit.c
@@ -0,0 +1,1089 @@
+/*
+ Copyright (C) Intel Corp. 2006. All Rights Reserved.
+ Intel funded Tungsten Graphics (http://www.tungstengraphics.com) to
+ develop this 3D driver.
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice (including the
+ next paragraph) shall be included in all copies or substantial
+ portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ **********************************************************************/
+/*
+ * Authors:
+ * Keith Whitwell <keith at tungstengraphics.com>
+ */
+
+#include "cairoint.h"
+#include "cairo-drm-intel-brw-eu.h"
+
+#include <string.h>
+
+/***********************************************************************
+ * Internal helper for constructing instructions
+ */
+
+static void guess_execution_size( struct brw_instruction *insn,
+ struct brw_reg reg )
+{
+ if (reg.width == BRW_WIDTH_8 &&
+ insn->header.compression_control == BRW_COMPRESSION_COMPRESSED)
+ insn->header.execution_size = BRW_EXECUTE_16;
+ else
+ insn->header.execution_size = reg.width; /* note - definitions are compatible */
+}
+
+
+void
+brw_instruction_set_destination (struct brw_instruction *insn,
+ struct brw_reg dest)
+{
+ insn->bits1.da1.dest_reg_file = dest.file;
+ insn->bits1.da1.dest_reg_type = dest.type;
+ insn->bits1.da1.dest_address_mode = dest.address_mode;
+
+ if (dest.address_mode == BRW_ADDRESS_DIRECT) {
+ insn->bits1.da1.dest_reg_nr = dest.nr;
+
+ if (insn->header.access_mode == BRW_ALIGN_1) {
+ insn->bits1.da1.dest_subreg_nr = dest.subnr;
+ if (dest.hstride == BRW_HORIZONTAL_STRIDE_0)
+ dest.hstride = BRW_HORIZONTAL_STRIDE_1;
+ insn->bits1.da1.dest_horiz_stride = dest.hstride;
+ } else {
+ insn->bits1.da16.dest_subreg_nr = dest.subnr / 16;
+ insn->bits1.da16.dest_writemask = dest.dw1.bits.writemask;
+ }
+ } else {
+ insn->bits1.ia1.dest_subreg_nr = dest.subnr;
+
+ /* These are different sizes in align1 vs align16:
+ */
+ if (insn->header.access_mode == BRW_ALIGN_1) {
+ insn->bits1.ia1.dest_indirect_offset = dest.dw1.bits.indirect_offset;
+ if (dest.hstride == BRW_HORIZONTAL_STRIDE_0)
+ dest.hstride = BRW_HORIZONTAL_STRIDE_1;
+ insn->bits1.ia1.dest_horiz_stride = dest.hstride;
+ } else {
+ insn->bits1.ia16.dest_indirect_offset = dest.dw1.bits.indirect_offset;
+ }
+ }
+
+ /* NEW: Set the execution size based on dest.width and
+ * insn->compression_control:
+ */
+ guess_execution_size(insn, dest);
+}
+
+void
+brw_instruction_set_source0 (struct brw_instruction *insn,
+ struct brw_reg reg)
+{
+ assert(reg.file != BRW_MESSAGE_REGISTER_FILE);
+
+ insn->bits1.da1.src0_reg_file = reg.file;
+ insn->bits1.da1.src0_reg_type = reg.type;
+ insn->bits2.da1.src0_abs = reg.abs;
+ insn->bits2.da1.src0_negate = reg.negate;
+ insn->bits2.da1.src0_address_mode = reg.address_mode;
+
+ if (reg.file == BRW_IMMEDIATE_VALUE) {
+ insn->bits3.ud = reg.dw1.ud;
+
+ /* Required to set some fields in src1 as well:
+ */
+ insn->bits1.da1.src1_reg_file = 0; /* arf */
+ insn->bits1.da1.src1_reg_type = reg.type;
+ } else {
+ if (reg.address_mode == BRW_ADDRESS_DIRECT) {
+ if (insn->header.access_mode == BRW_ALIGN_1) {
+ insn->bits2.da1.src0_subreg_nr = reg.subnr;
+ insn->bits2.da1.src0_reg_nr = reg.nr;
+ } else {
+ insn->bits2.da16.src0_subreg_nr = reg.subnr / 16;
+ insn->bits2.da16.src0_reg_nr = reg.nr;
+ }
+ } else {
+ insn->bits2.ia1.src0_subreg_nr = reg.subnr;
+
+ if (insn->header.access_mode == BRW_ALIGN_1) {
+ insn->bits2.ia1.src0_indirect_offset = reg.dw1.bits.indirect_offset;
+ } else {
+ insn->bits2.ia16.src0_subreg_nr = reg.dw1.bits.indirect_offset;
+ }
+ }
+
+ if (insn->header.access_mode == BRW_ALIGN_1) {
+ if (reg.width == BRW_WIDTH_1 &&
+ insn->header.execution_size == BRW_EXECUTE_1) {
+ insn->bits2.da1.src0_horiz_stride = BRW_HORIZONTAL_STRIDE_0;
+ insn->bits2.da1.src0_width = BRW_WIDTH_1;
+ insn->bits2.da1.src0_vert_stride = BRW_VERTICAL_STRIDE_0;
+ } else {
+ insn->bits2.da1.src0_horiz_stride = reg.hstride;
+ insn->bits2.da1.src0_width = reg.width;
+ insn->bits2.da1.src0_vert_stride = reg.vstride;
+ }
+ } else {
+ insn->bits2.da16.src0_swz_x = BRW_GET_SWZ(reg.dw1.bits.swizzle, BRW_CHANNEL_X);
+ insn->bits2.da16.src0_swz_y = BRW_GET_SWZ(reg.dw1.bits.swizzle, BRW_CHANNEL_Y);
+ insn->bits2.da16.src0_swz_z = BRW_GET_SWZ(reg.dw1.bits.swizzle, BRW_CHANNEL_Z);
+ insn->bits2.da16.src0_swz_w = BRW_GET_SWZ(reg.dw1.bits.swizzle, BRW_CHANNEL_W);
+
+ /* This is an oddity of the fact we're using the same
+ * descriptions for registers in align_16 as align_1:
+ */
+ if (reg.vstride == BRW_VERTICAL_STRIDE_8)
+ insn->bits2.da16.src0_vert_stride = BRW_VERTICAL_STRIDE_4;
+ else
+ insn->bits2.da16.src0_vert_stride = reg.vstride;
+ }
+ }
+}
+
+
+void brw_set_src1( struct brw_instruction *insn,
+ struct brw_reg reg )
+{
+ assert(reg.file != BRW_MESSAGE_REGISTER_FILE);
+
+ insn->bits1.da1.src1_reg_file = reg.file;
+ insn->bits1.da1.src1_reg_type = reg.type;
+ insn->bits3.da1.src1_abs = reg.abs;
+ insn->bits3.da1.src1_negate = reg.negate;
+
+ /* Only src1 can be immediate in two-argument instructions.
+ */
+ assert(insn->bits1.da1.src0_reg_file != BRW_IMMEDIATE_VALUE);
+
+ if (reg.file == BRW_IMMEDIATE_VALUE) {
+ insn->bits3.ud = reg.dw1.ud;
+ }
+ else {
+ /* This is a hardware restriction, which may or may not be lifted
+ * in the future:
+ */
+ assert (reg.address_mode == BRW_ADDRESS_DIRECT);
+ //assert (reg.file == BRW_GENERAL_REGISTER_FILE);
+
+ if (insn->header.access_mode == BRW_ALIGN_1) {
+ insn->bits3.da1.src1_subreg_nr = reg.subnr;
+ insn->bits3.da1.src1_reg_nr = reg.nr;
+ }
+ else {
+ insn->bits3.da16.src1_subreg_nr = reg.subnr / 16;
+ insn->bits3.da16.src1_reg_nr = reg.nr;
+ }
+
+ if (insn->header.access_mode == BRW_ALIGN_1) {
+ if (reg.width == BRW_WIDTH_1 &&
+ insn->header.execution_size == BRW_EXECUTE_1) {
+ insn->bits3.da1.src1_horiz_stride = BRW_HORIZONTAL_STRIDE_0;
+ insn->bits3.da1.src1_width = BRW_WIDTH_1;
+ insn->bits3.da1.src1_vert_stride = BRW_VERTICAL_STRIDE_0;
+ }
+ else {
+ insn->bits3.da1.src1_horiz_stride = reg.hstride;
+ insn->bits3.da1.src1_width = reg.width;
+ insn->bits3.da1.src1_vert_stride = reg.vstride;
+ }
+ }
+ else {
+ insn->bits3.da16.src1_swz_x = BRW_GET_SWZ(reg.dw1.bits.swizzle, BRW_CHANNEL_X);
+ insn->bits3.da16.src1_swz_y = BRW_GET_SWZ(reg.dw1.bits.swizzle, BRW_CHANNEL_Y);
+ insn->bits3.da16.src1_swz_z = BRW_GET_SWZ(reg.dw1.bits.swizzle, BRW_CHANNEL_Z);
+ insn->bits3.da16.src1_swz_w = BRW_GET_SWZ(reg.dw1.bits.swizzle, BRW_CHANNEL_W);
+
+ /* This is an oddity of the fact we're using the same
+ * descriptions for registers in align_16 as align_1:
+ */
+ if (reg.vstride == BRW_VERTICAL_STRIDE_8)
+ insn->bits3.da16.src1_vert_stride = BRW_VERTICAL_STRIDE_4;
+ else
+ insn->bits3.da16.src1_vert_stride = reg.vstride;
+ }
+ }
+}
+
+
+
+static void brw_set_math_message( struct brw_instruction *insn,
+ uint32_t msg_length,
+ uint32_t response_length,
+ uint32_t function,
+ uint32_t integer_type,
+ int low_precision,
+ int saturate,
+ uint32_t dataType )
+{
+ brw_set_src1 (insn, brw_imm_d (0));
+
+ insn->bits3.math.function = function;
+ insn->bits3.math.int_type = integer_type;
+ insn->bits3.math.precision = low_precision;
+ insn->bits3.math.saturate = saturate;
+ insn->bits3.math.data_type = dataType;
+ insn->bits3.math.response_length = response_length;
+ insn->bits3.math.msg_length = msg_length;
+ insn->bits3.math.msg_target = BRW_MESSAGE_TARGET_MATH;
+ insn->bits3.math.end_of_thread = 0;
+}
+
+static void brw_set_urb_message( struct brw_instruction *insn,
+ int allocate,
+ int used,
+ uint32_t msg_length,
+ uint32_t response_length,
+ int end_of_thread,
+ int complete,
+ uint32_t offset,
+ uint32_t swizzle_control )
+{
+ brw_set_src1 (insn, brw_imm_d (0));
+
+ insn->bits3.urb.opcode = 0; /* ? */
+ insn->bits3.urb.offset = offset;
+ insn->bits3.urb.swizzle_control = swizzle_control;
+ insn->bits3.urb.allocate = allocate;
+ insn->bits3.urb.used = used; /* ? */
+ insn->bits3.urb.complete = complete;
+ insn->bits3.urb.response_length = response_length;
+ insn->bits3.urb.msg_length = msg_length;
+ insn->bits3.urb.msg_target = BRW_MESSAGE_TARGET_URB;
+ insn->bits3.urb.end_of_thread = end_of_thread;
+}
+
+void
+brw_instruction_set_dp_write_message (struct brw_instruction *insn,
+ uint32_t binding_table_index,
+ uint32_t msg_control,
+ uint32_t msg_type,
+ uint32_t msg_length,
+ uint32_t pixel_scoreboard_clear,
+ uint32_t response_length,
+ uint32_t end_of_thread)
+{
+ brw_set_src1 (insn, brw_imm_d (0));
+
+ insn->bits3.dp_write.binding_table_index = binding_table_index;
+ insn->bits3.dp_write.msg_control = msg_control;
+ insn->bits3.dp_write.pixel_scoreboard_clear = pixel_scoreboard_clear;
+ insn->bits3.dp_write.msg_type = msg_type;
+ insn->bits3.dp_write.send_commit_msg = 0;
+ insn->bits3.dp_write.response_length = response_length;
+ insn->bits3.dp_write.msg_length = msg_length;
+ insn->bits3.dp_write.msg_target = BRW_MESSAGE_TARGET_DATAPORT_WRITE;
+ insn->bits3.urb.end_of_thread = end_of_thread;
+}
+
+static void brw_set_dp_read_message( struct brw_instruction *insn,
+ uint32_t binding_table_index,
+ uint32_t msg_control,
+ uint32_t msg_type,
+ uint32_t target_cache,
+ uint32_t msg_length,
+ uint32_t response_length,
+ uint32_t end_of_thread )
+{
+ brw_set_src1 (insn, brw_imm_d (0));
+
+ insn->bits3.dp_read.binding_table_index = binding_table_index;
+ insn->bits3.dp_read.msg_control = msg_control;
+ insn->bits3.dp_read.msg_type = msg_type;
+ insn->bits3.dp_read.target_cache = target_cache;
+ insn->bits3.dp_read.response_length = response_length;
+ insn->bits3.dp_read.msg_length = msg_length;
+ insn->bits3.dp_read.msg_target = BRW_MESSAGE_TARGET_DATAPORT_READ;
+ insn->bits3.dp_read.end_of_thread = end_of_thread;
+}
+
+static void
+brw_set_sampler_message (struct brw_instruction *insn,
+ cairo_bool_t is_g4x,
+ uint32_t binding_table_index,
+ uint32_t sampler,
+ uint32_t msg_type,
+ uint32_t response_length,
+ uint32_t msg_length,
+ cairo_bool_t eot)
+{
+ brw_set_src1 (insn, brw_imm_d (0));
+
+ if (is_g4x) {
+ /* XXX presume the driver is sane! */
+ insn->bits3.sampler_g4x.binding_table_index = binding_table_index;
+ insn->bits3.sampler_g4x.sampler = sampler;
+ insn->bits3.sampler_g4x.msg_type = msg_type;
+ insn->bits3.sampler_g4x.response_length = response_length;
+ insn->bits3.sampler_g4x.msg_length = msg_length;
+ insn->bits3.sampler_g4x.end_of_thread = eot;
+ insn->bits3.sampler_g4x.msg_target = BRW_MESSAGE_TARGET_SAMPLER;
+ } else {
+ insn->bits3.sampler.binding_table_index = binding_table_index;
+ insn->bits3.sampler.sampler = sampler;
+ insn->bits3.sampler.msg_type = msg_type;
+ insn->bits3.sampler.return_format = BRW_SAMPLER_RETURN_FORMAT_FLOAT32;
+ insn->bits3.sampler.response_length = response_length;
+ insn->bits3.sampler.msg_length = msg_length;
+ insn->bits3.sampler.end_of_thread = eot;
+ insn->bits3.sampler.msg_target = BRW_MESSAGE_TARGET_SAMPLER;
+ }
+}
+
+struct brw_instruction *
+brw_next_instruction (struct brw_compile *p,
+ uint32_t opcode)
+{
+ struct brw_instruction *insn;
+
+ assert(p->nr_insn + 1 < BRW_EU_MAX_INSN);
+
+ insn = &p->store[p->nr_insn++];
+ memcpy(insn, p->current, sizeof(*insn));
+
+ /* Reset this one-shot flag: */
+ if (p->current->header.destreg__conditonalmod) {
+ p->current->header.destreg__conditonalmod = 0;
+ p->current->header.predicate_control = BRW_PREDICATE_NORMAL;
+ }
+
+ insn->header.opcode = opcode;
+ return insn;
+}
+
+static struct brw_instruction *brw_alu1( struct brw_compile *p,
+ uint32_t opcode,
+ struct brw_reg dest,
+ struct brw_reg src )
+{
+ struct brw_instruction *insn = brw_next_instruction(p, opcode);
+ brw_instruction_set_destination(insn, dest);
+ brw_instruction_set_source0(insn, src);
+ return insn;
+}
+
+static struct brw_instruction *brw_alu2(struct brw_compile *p,
+ uint32_t opcode,
+ struct brw_reg dest,
+ struct brw_reg src0,
+ struct brw_reg src1 )
+{
+ struct brw_instruction *insn = brw_next_instruction(p, opcode);
+ brw_instruction_set_destination(insn, dest);
+ brw_instruction_set_source0(insn, src0);
+ brw_set_src1(insn, src1);
+ return insn;
+}
+
+
+/***********************************************************************
+ * Convenience routines.
+ */
+#define ALU1(OP) \
+ struct brw_instruction *brw_##OP(struct brw_compile *p, \
+ struct brw_reg dest, \
+ struct brw_reg src0) \
+{ \
+ return brw_alu1(p, BRW_OPCODE_##OP, dest, src0); \
+}
+
+#define ALU2(OP) \
+ struct brw_instruction *brw_##OP(struct brw_compile *p, \
+ struct brw_reg dest, \
+ struct brw_reg src0, \
+ struct brw_reg src1) \
+{ \
+ return brw_alu2(p, BRW_OPCODE_##OP, dest, src0, src1); \
+}
+
+
+ ALU1(MOV)
+ ALU2(SEL)
+ ALU1(NOT)
+ ALU2(AND)
+ ALU2(OR)
+ ALU2(XOR)
+ ALU2(SHR)
+ ALU2(SHL)
+ ALU2(RSR)
+ ALU2(RSL)
+ ALU2(ASR)
+ ALU2(ADD)
+ ALU2(MUL)
+ ALU1(FRC)
+ ALU1(RNDD)
+ ALU1(RNDZ)
+ ALU2(MAC)
+ ALU2(MACH)
+ ALU1(LZD)
+ ALU2(DP4)
+ ALU2(DPH)
+ ALU2(DP3)
+ ALU2(DP2)
+ALU2(LINE)
+
+
+
+
+void brw_NOP(struct brw_compile *p)
+{
+ struct brw_instruction *insn = brw_next_instruction(p, BRW_OPCODE_NOP);
+ brw_instruction_set_destination(insn, retype(brw_vec4_grf(0,0), BRW_REGISTER_TYPE_UD));
+ brw_instruction_set_source0(insn, retype(brw_vec4_grf(0,0), BRW_REGISTER_TYPE_UD));
+ brw_set_src1(insn, brw_imm_ud(0x0));
+}
+
+
+
+
+
+/***********************************************************************
+ * Comparisons, if/else/endif
+ */
+
+struct brw_instruction *brw_JMPI(struct brw_compile *p,
+ struct brw_reg dest,
+ struct brw_reg src0,
+ struct brw_reg src1)
+{
+ struct brw_instruction *insn = brw_alu2(p, BRW_OPCODE_JMPI, dest, src0, src1);
+
+ p->current->header.predicate_control = BRW_PREDICATE_NONE;
+
+ return insn;
+}
+
+/* EU takes the value from the flag register and pushes it onto some
+ * sort of a stack (presumably merging with any flag value already on
+ * the stack). Within an if block, the flags at the top of the stack
+ * control execution on each channel of the unit, eg. on each of the
+ * 16 pixel values in our wm programs.
+ *
+ * When the matching 'else' instruction is reached (presumably by
+ * countdown of the instruction count patched in by our ELSE/ENDIF
+ * functions), the relevent flags are inverted.
+ *
+ * When the matching 'endif' instruction is reached, the flags are
+ * popped off. If the stack is now empty, normal execution resumes.
+ *
+ * No attempt is made to deal with stack overflow (14 elements?).
+ */
+struct brw_instruction *brw_IF(struct brw_compile *p, uint32_t execute_size)
+{
+ struct brw_instruction *insn;
+
+ if (p->single_program_flow) {
+ assert(execute_size == BRW_EXECUTE_1);
+
+ insn = brw_next_instruction(p, BRW_OPCODE_ADD);
+ insn->header.predicate_inverse = 1;
+ } else {
+ insn = brw_next_instruction(p, BRW_OPCODE_IF);
+ }
+
+ /* Override the defaults for this instruction:
+ */
+ brw_instruction_set_destination (insn, brw_ip_reg ());
+ brw_instruction_set_source0 (insn, brw_ip_reg ());
+ brw_set_src1 (insn, brw_imm_d (0));
+
+ insn->header.execution_size = execute_size;
+ insn->header.compression_control = BRW_COMPRESSION_NONE;
+ insn->header.predicate_control = BRW_PREDICATE_NORMAL;
+ insn->header.mask_control = BRW_MASK_ENABLE;
+ if (!p->single_program_flow)
+ insn->header.thread_control = BRW_THREAD_SWITCH;
+
+ p->current->header.predicate_control = BRW_PREDICATE_NONE;
+
+ return insn;
+}
+
+
+struct brw_instruction *brw_ELSE(struct brw_compile *p,
+ struct brw_instruction *if_insn)
+{
+ struct brw_instruction *insn;
+
+ if (p->single_program_flow) {
+ insn = brw_next_instruction(p, BRW_OPCODE_ADD);
+ } else {
+ insn = brw_next_instruction(p, BRW_OPCODE_ELSE);
+ }
+
+ brw_instruction_set_destination (insn, brw_ip_reg ());
+ brw_instruction_set_source0 (insn, brw_ip_reg ());
+ brw_set_src1 (insn, brw_imm_d (0));
+
+ insn->header.compression_control = BRW_COMPRESSION_NONE;
+ insn->header.execution_size = if_insn->header.execution_size;
+ insn->header.mask_control = BRW_MASK_ENABLE;
+ if (!p->single_program_flow)
+ insn->header.thread_control = BRW_THREAD_SWITCH;
+
+ /* Patch the if instruction to point at this instruction.
+ */
+ if (p->single_program_flow) {
+ assert(if_insn->header.opcode == BRW_OPCODE_ADD);
+
+ if_insn->bits3.ud = (insn - if_insn + 1) * 16;
+ } else {
+ assert(if_insn->header.opcode == BRW_OPCODE_IF);
+
+ if_insn->bits3.if_else.jump_count = insn - if_insn;
+ if_insn->bits3.if_else.pop_count = 1;
+ if_insn->bits3.if_else.pad0 = 0;
+ }
+
+ return insn;
+}
+
+void brw_ENDIF(struct brw_compile *p,
+ struct brw_instruction *patch_insn)
+{
+ if (p->single_program_flow) {
+ /* In single program flow mode, there's no need to execute an ENDIF,
+ * since we don't need to do any stack operations, and if we're executing
+ * currently, we want to just continue executing.
+ */
+ struct brw_instruction *next = &p->store[p->nr_insn];
+
+ assert(patch_insn->header.opcode == BRW_OPCODE_ADD);
+
+ patch_insn->bits3.ud = (next - patch_insn) * 16;
+ } else {
+ struct brw_instruction *insn = brw_next_instruction(p, BRW_OPCODE_ENDIF);
+
+ brw_instruction_set_destination(insn, retype(brw_vec4_grf(0,0), BRW_REGISTER_TYPE_UD));
+ brw_instruction_set_source0(insn, retype(brw_vec4_grf(0,0), BRW_REGISTER_TYPE_UD));
+ brw_set_src1 (insn, brw_imm_d (0));
+
+ insn->header.compression_control = BRW_COMPRESSION_NONE;
+ insn->header.execution_size = patch_insn->header.execution_size;
+ insn->header.mask_control = BRW_MASK_ENABLE;
+ insn->header.thread_control = BRW_THREAD_SWITCH;
+
+ assert(patch_insn->bits3.if_else.jump_count == 0);
+
+ /* Patch the if or else instructions to point at this or the next
+ * instruction respectively.
+ */
+ if (patch_insn->header.opcode == BRW_OPCODE_IF) {
+ /* Automagically turn it into an IFF:
+ */
+ patch_insn->header.opcode = BRW_OPCODE_IFF;
+ patch_insn->bits3.if_else.jump_count = insn - patch_insn + 1;
+ patch_insn->bits3.if_else.pop_count = 0;
+ patch_insn->bits3.if_else.pad0 = 0;
+ } else if (patch_insn->header.opcode == BRW_OPCODE_ELSE) {
+ patch_insn->bits3.if_else.jump_count = insn - patch_insn + 1;
+ patch_insn->bits3.if_else.pop_count = 1;
+ patch_insn->bits3.if_else.pad0 = 0;
+ } else {
+ assert(0);
+ }
+
+ /* Also pop item off the stack in the endif instruction:
+ */
+ insn->bits3.if_else.jump_count = 0;
+ insn->bits3.if_else.pop_count = 1;
+ insn->bits3.if_else.pad0 = 0;
+ }
+}
+
+struct brw_instruction *brw_BREAK(struct brw_compile *p)
+{
+ struct brw_instruction *insn;
+ insn = brw_next_instruction(p, BRW_OPCODE_BREAK);
+ brw_instruction_set_destination(insn, brw_ip_reg());
+ brw_instruction_set_source0(insn, brw_ip_reg());
+ brw_set_src1(insn, brw_imm_d (0));
+ insn->header.compression_control = BRW_COMPRESSION_NONE;
+ insn->header.execution_size = BRW_EXECUTE_8;
+ /* insn->header.mask_control = BRW_MASK_DISABLE; */
+ insn->bits3.if_else.pad0 = 0;
+ return insn;
+}
+
+struct brw_instruction *brw_CONT(struct brw_compile *p)
+{
+ struct brw_instruction *insn;
+ insn = brw_next_instruction(p, BRW_OPCODE_CONTINUE);
+ brw_instruction_set_destination(insn, brw_ip_reg());
+ brw_instruction_set_source0(insn, brw_ip_reg());
+ brw_set_src1 (insn, brw_imm_d (0));
+ insn->header.compression_control = BRW_COMPRESSION_NONE;
+ insn->header.execution_size = BRW_EXECUTE_8;
+ /* insn->header.mask_control = BRW_MASK_DISABLE; */
+ insn->bits3.if_else.pad0 = 0;
+ return insn;
+}
+
+/* DO/WHILE loop:
+*/
+struct brw_instruction *brw_DO(struct brw_compile *p, uint32_t execute_size)
+{
+ if (p->single_program_flow) {
+ return &p->store[p->nr_insn];
+ } else {
+ struct brw_instruction *insn = brw_next_instruction(p, BRW_OPCODE_DO);
+
+ /* Override the defaults for this instruction:
+ */
+ brw_instruction_set_destination(insn, brw_null_reg());
+ brw_instruction_set_source0(insn, brw_null_reg());
+ brw_set_src1(insn, brw_null_reg());
+
+ insn->header.compression_control = BRW_COMPRESSION_NONE;
+ insn->header.execution_size = execute_size;
+ insn->header.predicate_control = BRW_PREDICATE_NONE;
+ /* insn->header.mask_control = BRW_MASK_ENABLE; */
+ /* insn->header.mask_control = BRW_MASK_DISABLE; */
+
+ return insn;
+ }
+}
+
+
+
+struct brw_instruction *brw_WHILE(struct brw_compile *p,
+ struct brw_instruction *do_insn)
+{
+ struct brw_instruction *insn;
+
+ if (p->single_program_flow)
+ insn = brw_next_instruction(p, BRW_OPCODE_ADD);
+ else
+ insn = brw_next_instruction(p, BRW_OPCODE_WHILE);
+
+ brw_instruction_set_destination(insn, brw_ip_reg());
+ brw_instruction_set_source0(insn, brw_ip_reg());
+ brw_set_src1 (insn, brw_imm_d (0));
+
+ insn->header.compression_control = BRW_COMPRESSION_NONE;
+
+ if (p->single_program_flow) {
+ insn->header.execution_size = BRW_EXECUTE_1;
+
+ insn->bits3.d = (do_insn - insn) * 16;
+ } else {
+ insn->header.execution_size = do_insn->header.execution_size;
+
+ assert(do_insn->header.opcode == BRW_OPCODE_DO);
+ insn->bits3.if_else.jump_count = do_insn - insn + 1;
+ insn->bits3.if_else.pop_count = 0;
+ insn->bits3.if_else.pad0 = 0;
+ }
+
+ /* insn->header.mask_control = BRW_MASK_ENABLE; */
+
+ /* insn->header.mask_control = BRW_MASK_DISABLE; */
+ p->current->header.predicate_control = BRW_PREDICATE_NONE;
+ return insn;
+}
+
+
+/* FORWARD JUMPS:
+*/
+void brw_land_fwd_jump(struct brw_compile *p,
+ struct brw_instruction *jmp_insn)
+{
+ struct brw_instruction *landing = &p->store[p->nr_insn];
+
+ assert(jmp_insn->header.opcode == BRW_OPCODE_JMPI);
+ assert(jmp_insn->bits1.da1.src1_reg_file = BRW_IMMEDIATE_VALUE);
+
+ jmp_insn->bits3.ud = (landing - jmp_insn) - 1;
+}
+
+
+
+/* To integrate with the above, it makes sense that the comparison
+ * instruction should populate the flag register. It might be simpler
+ * just to use the flag reg for most WM tasks?
+ */
+void brw_CMP(struct brw_compile *p,
+ struct brw_reg dest,
+ uint32_t conditional,
+ struct brw_reg src0,
+ struct brw_reg src1)
+{
+ struct brw_instruction *insn = brw_next_instruction(p, BRW_OPCODE_CMP);
+
+ insn->header.destreg__conditonalmod = conditional;
+ brw_instruction_set_destination(insn, dest);
+ brw_instruction_set_source0(insn, src0);
+ brw_set_src1(insn, src1);
+
+ /* guess_execution_size(insn, src0); */
+
+
+ /* Make it so that future instructions will use the computed flag
+ * value until brw_set_predicate_control_flag_value() is called
+ * again.
+ */
+ if (dest.file == BRW_ARCHITECTURE_REGISTER_FILE &&
+ dest.nr == 0) {
+ p->current->header.predicate_control = BRW_PREDICATE_NORMAL;
+ p->flag_value = 0xff;
+ }
+}
+
+
+
+/***********************************************************************
+ * Helpers for the various SEND message types:
+ */
+
+/* Invert 8 values
+*/
+void brw_math( struct brw_compile *p,
+ struct brw_reg dest,
+ uint32_t function,
+ uint32_t saturate,
+ uint32_t msg_reg_nr,
+ struct brw_reg src,
+ uint32_t data_type,
+ uint32_t precision )
+{
+ struct brw_instruction *insn = brw_next_instruction(p, BRW_OPCODE_SEND);
+ uint32_t msg_length = (function == BRW_MATH_FUNCTION_POW) ? 2 : 1;
+ uint32_t response_length = (function == BRW_MATH_FUNCTION_SINCOS) ? 2 : 1;
+
+ /* Example code doesn't set predicate_control for send
+ * instructions.
+ */
+ insn->header.predicate_control = 0;
+ insn->header.destreg__conditonalmod = msg_reg_nr;
+
+ response_length = 1;
+
+ brw_instruction_set_destination(insn, dest);
+ brw_instruction_set_source0(insn, src);
+ brw_set_math_message(insn,
+ msg_length, response_length,
+ function,
+ BRW_MATH_INTEGER_UNSIGNED,
+ precision,
+ saturate,
+ data_type);
+}
+
+/* Use 2 send instructions to invert 16 elements
+*/
+void brw_math_16( struct brw_compile *p,
+ struct brw_reg dest,
+ uint32_t function,
+ uint32_t saturate,
+ uint32_t msg_reg_nr,
+ struct brw_reg src,
+ uint32_t precision )
+{
+ struct brw_instruction *insn;
+ uint32_t msg_length = (function == BRW_MATH_FUNCTION_POW) ? 2 : 1;
+ uint32_t response_length = (function == BRW_MATH_FUNCTION_SINCOS) ? 2 : 1;
+
+ /* First instruction:
+ */
+ brw_push_insn_state(p);
+ brw_set_predicate_control_flag_value(p, 0xff);
+ brw_set_compression_control(p, BRW_COMPRESSION_NONE);
+
+ insn = brw_next_instruction(p, BRW_OPCODE_SEND);
+ insn->header.destreg__conditonalmod = msg_reg_nr;
+
+ brw_instruction_set_destination(insn, dest);
+ brw_instruction_set_source0(insn, src);
+ brw_set_math_message(insn,
+ msg_length, response_length,
+ function,
+ BRW_MATH_INTEGER_UNSIGNED,
+ precision,
+ saturate,
+ BRW_MATH_DATA_VECTOR);
+
+ /* Second instruction:
+ */
+ insn = brw_next_instruction(p, BRW_OPCODE_SEND);
+ insn->header.compression_control = BRW_COMPRESSION_2NDHALF;
+ insn->header.destreg__conditonalmod = msg_reg_nr+1;
+
+ brw_instruction_set_destination(insn, offset(dest,1));
+ brw_instruction_set_source0(insn, src);
+ brw_set_math_message(insn,
+ msg_length, response_length,
+ function,
+ BRW_MATH_INTEGER_UNSIGNED,
+ precision,
+ saturate,
+ BRW_MATH_DATA_VECTOR);
+
+ brw_pop_insn_state(p);
+}
+
+
+
+
+void brw_dp_WRITE_16( struct brw_compile *p,
+ struct brw_reg src,
+ uint32_t msg_reg_nr,
+ uint32_t scratch_offset )
+{
+ {
+ brw_push_insn_state(p);
+ brw_set_mask_control(p, BRW_MASK_DISABLE);
+ brw_set_compression_control(p, BRW_COMPRESSION_NONE);
+
+ brw_MOV (p,
+ retype (brw_vec1_grf (0, 2), BRW_REGISTER_TYPE_D),
+ brw_imm_d (scratch_offset));
+
+ brw_pop_insn_state(p);
+ }
+
+ {
+ uint32_t msg_length = 3;
+ struct brw_reg dest = retype(brw_null_reg(), BRW_REGISTER_TYPE_UW);
+ struct brw_instruction *insn = brw_next_instruction(p, BRW_OPCODE_SEND);
+
+ insn->header.predicate_control = 0; /* XXX */
+ insn->header.compression_control = BRW_COMPRESSION_NONE;
+ insn->header.destreg__conditonalmod = msg_reg_nr;
+
+ brw_instruction_set_destination(insn, dest);
+ brw_instruction_set_source0(insn, src);
+
+ brw_instruction_set_dp_write_message(insn,
+ 255, /* bti */
+ BRW_DATAPORT_OWORD_BLOCK_4_OWORDS, /* msg_control */
+ BRW_DATAPORT_WRITE_MESSAGE_OWORD_BLOCK_WRITE, /* msg_type */
+ msg_length,
+ 0, /* pixel scoreboard */
+ 0, /* response_length */
+ 0); /* eot */
+ }
+
+}
+
+
+void brw_dp_READ_16( struct brw_compile *p,
+ struct brw_reg dest,
+ uint32_t msg_reg_nr,
+ uint32_t scratch_offset )
+{
+ {
+ brw_push_insn_state(p);
+ brw_set_compression_control(p, BRW_COMPRESSION_NONE);
+ brw_set_mask_control(p, BRW_MASK_DISABLE);
+
+ brw_MOV (p,
+ retype (brw_vec1_grf (0, 2), BRW_REGISTER_TYPE_D),
+ brw_imm_d (scratch_offset));
+
+ brw_pop_insn_state(p);
+ }
+
+ {
+ struct brw_instruction *insn = brw_next_instruction(p, BRW_OPCODE_SEND);
+
+ insn->header.predicate_control = 0; /* XXX */
+ insn->header.compression_control = BRW_COMPRESSION_NONE;
+ insn->header.destreg__conditonalmod = msg_reg_nr;
+
+ brw_instruction_set_destination(insn, dest); /* UW? */
+ brw_instruction_set_source0(insn, retype(brw_vec8_grf(0), BRW_REGISTER_TYPE_UW));
+
+ brw_set_dp_read_message(insn,
+ 255, /* bti */
+ 3, /* msg_control */
+ BRW_DATAPORT_READ_MESSAGE_OWORD_BLOCK_READ, /* msg_type */
+ 1, /* target cache */
+ 1, /* msg_length */
+ 2, /* response_length */
+ 0); /* eot */
+ }
+}
+
+
+void brw_fb_WRITE(struct brw_compile *p,
+ struct brw_reg dest,
+ uint32_t msg_reg_nr,
+ struct brw_reg src0,
+ uint32_t binding_table_index,
+ uint32_t msg_length,
+ uint32_t response_length,
+ int eot)
+{
+ struct brw_instruction *insn = brw_next_instruction(p, BRW_OPCODE_SEND);
+
+ insn->header.predicate_control = 0; /* XXX */
+ insn->header.compression_control = BRW_COMPRESSION_NONE;
+ insn->header.destreg__conditonalmod = msg_reg_nr;
+
+ brw_instruction_set_destination(insn, dest);
+ brw_instruction_set_source0(insn, src0);
+ brw_instruction_set_dp_write_message(insn,
+ binding_table_index,
+ BRW_DATAPORT_RENDER_TARGET_WRITE_SIMD16_SINGLE_SOURCE, /* msg_control */
+ BRW_DATAPORT_WRITE_MESSAGE_RENDER_TARGET_WRITE, /* msg_type */
+ msg_length,
+ 1, /* pixel scoreboard */
+ response_length,
+ eot);
+}
+
+
+
+void brw_SAMPLE (struct brw_compile *p,
+ struct brw_reg dest,
+ uint32_t msg_reg_nr,
+ struct brw_reg src0,
+ uint32_t binding_table_index,
+ uint32_t sampler,
+ uint32_t writemask,
+ uint32_t msg_type,
+ uint32_t response_length,
+ uint32_t msg_length,
+ cairo_bool_t eot)
+{
+ int need_stall = 0;
+
+ if(writemask == 0) {
+ /* printf("%s: zero writemask??\n", __FUNCTION__); */
+ return;
+ }
+
+ /* Hardware doesn't do destination dependency checking on send
+ * instructions properly. Add a workaround which generates the
+ * dependency by other means. In practice it seems like this bug
+ * only crops up for texture samples, and only where registers are
+ * written by the send and then written again later without being
+ * read in between. Luckily for us, we already track that
+ * information and use it to modify the writemask for the
+ * instruction, so that is a guide for whether a workaround is
+ * needed.
+ */
+ if (writemask != WRITEMASK_XYZW) {
+ uint32_t dst_offset = 0;
+ uint32_t i, newmask = 0, len = 0;
+
+ for (i = 0; i < 4; i++) {
+ if (writemask & (1<<i))
+ break;
+ dst_offset += 2;
+ }
+ for (; i < 4; i++) {
+ if (!(writemask & (1<<i)))
+ break;
+ newmask |= 1<<i;
+ len++;
+ }
+
+ if (newmask != writemask) {
+ need_stall = 1;
+ /* printf("need stall %x %x\n", newmask , writemask); */
+ }
+ else {
+ struct brw_reg m1 = brw_message_reg(msg_reg_nr);
+
+ newmask = ~newmask & WRITEMASK_XYZW;
+
+ brw_push_insn_state(p);
+
+ brw_set_compression_control(p, BRW_COMPRESSION_NONE);
+ brw_set_mask_control(p, BRW_MASK_DISABLE);
+
+ brw_MOV(p, m1, brw_vec8_grf(0));
+ brw_MOV(p, get_element_ud(m1, 2), brw_imm_ud(newmask << 12));
+
+ brw_pop_insn_state(p);
+
+ src0 = retype(brw_null_reg(), BRW_REGISTER_TYPE_UW);
+ dest = offset(dest, dst_offset);
+ response_length = len * 2;
+ }
+ }
+
+ {
+ struct brw_instruction *insn = brw_next_instruction(p, BRW_OPCODE_SEND);
+
+ insn->header.predicate_control = 0; /* XXX */
+ insn->header.compression_control = BRW_COMPRESSION_NONE;
+ insn->header.destreg__conditonalmod = msg_reg_nr;
+
+ brw_instruction_set_destination(insn, dest);
+ brw_instruction_set_source0(insn, src0);
+ brw_set_sampler_message (insn, p->is_g4x,
+ binding_table_index,
+ sampler,
+ msg_type,
+ response_length,
+ msg_length,
+ eot);
+ }
+
+ if (need_stall)
+ {
+ struct brw_reg reg = vec8(offset(dest, response_length-1));
+
+ /* mov (8) r9.0<1>:f r9.0<8;8,1>:f { Align1 }
+ */
+ brw_push_insn_state(p);
+ brw_set_compression_control(p, 0);
+ brw_MOV(p, reg, reg);
+ brw_pop_insn_state(p);
+ }
+}
+
+/* All these variables are pretty confusing - we might be better off
+ * using bitmasks and macros for this, in the old style. Or perhaps
+ * just having the caller instantiate the fields in dword3 itself.
+ */
+void brw_urb_WRITE(struct brw_compile *p,
+ struct brw_reg dest,
+ uint32_t msg_reg_nr,
+ struct brw_reg src0,
+ int allocate,
+ int used,
+ uint32_t msg_length,
+ uint32_t response_length,
+ int eot,
+ int writes_complete,
+ uint32_t offset,
+ uint32_t swizzle)
+{
+ struct brw_instruction *insn = brw_next_instruction(p, BRW_OPCODE_SEND);
+
+ assert(msg_length < 16);
+
+ brw_instruction_set_destination (insn, dest);
+ brw_instruction_set_source0 (insn, src0);
+ brw_set_src1 (insn, brw_imm_d (0));
+
+ insn->header.destreg__conditonalmod = msg_reg_nr;
+
+ brw_set_urb_message (insn,
+ allocate,
+ used,
+ msg_length,
+ response_length,
+ eot,
+ writes_complete,
+ offset,
+ swizzle);
+}
diff --git a/src/drm/cairo-drm-intel-brw-eu-util.c b/src/drm/cairo-drm-intel-brw-eu-util.c
new file mode 100644
index 0000000..592235b
--- /dev/null
+++ b/src/drm/cairo-drm-intel-brw-eu-util.c
@@ -0,0 +1,121 @@
+/*
+ Copyright (C) Intel Corp. 2006. All Rights Reserved.
+ Intel funded Tungsten Graphics (http://www.tungstengraphics.com) to
+ develop this 3D driver.
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice (including the
+ next paragraph) shall be included in all copies or substantial
+ portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ **********************************************************************/
+/*
+ * Authors:
+ * Keith Whitwell <keith at tungstengraphics.com>
+ */
+
+
+#include "cairoint.h"
+#include "cairo-drm-intel-brw-eu.h"
+
+
+void brw_math_invert( struct brw_compile *p,
+ struct brw_reg dst,
+ struct brw_reg src)
+{
+ brw_math( p,
+ dst,
+ BRW_MATH_FUNCTION_INV,
+ BRW_MATH_SATURATE_NONE,
+ 0,
+ src,
+ BRW_MATH_PRECISION_FULL,
+ BRW_MATH_DATA_VECTOR );
+}
+
+
+
+void brw_copy4(struct brw_compile *p,
+ struct brw_reg dst,
+ struct brw_reg src,
+ uint32_t count)
+{
+ uint32_t i;
+
+ dst = vec4(dst);
+ src = vec4(src);
+
+ for (i = 0; i < count; i++)
+ {
+ uint32_t delta = i*32;
+ brw_MOV(p, byte_offset(dst, delta), byte_offset(src, delta));
+ brw_MOV(p, byte_offset(dst, delta+16), byte_offset(src, delta+16));
+ }
+}
+
+
+void brw_copy8(struct brw_compile *p,
+ struct brw_reg dst,
+ struct brw_reg src,
+ uint32_t count)
+{
+ uint32_t i;
+
+ dst = vec8(dst);
+ src = vec8(src);
+
+ for (i = 0; i < count; i++)
+ {
+ uint32_t delta = i*32;
+ brw_MOV(p, byte_offset(dst, delta), byte_offset(src, delta));
+ }
+}
+
+
+void brw_copy_indirect_to_indirect(struct brw_compile *p,
+ struct brw_indirect dst_ptr,
+ struct brw_indirect src_ptr,
+ uint32_t count)
+{
+ uint32_t i;
+
+ for (i = 0; i < count; i++)
+ {
+ uint32_t delta = i*32;
+ brw_MOV(p, deref_4f(dst_ptr, delta), deref_4f(src_ptr, delta));
+ brw_MOV(p, deref_4f(dst_ptr, delta+16), deref_4f(src_ptr, delta+16));
+ }
+}
+
+
+void brw_copy_from_indirect(struct brw_compile *p,
+ struct brw_reg dst,
+ struct brw_indirect ptr,
+ uint32_t count)
+{
+ uint32_t i;
+
+ dst = vec4(dst);
+
+ for (i = 0; i < count; i++)
+ {
+ uint32_t delta = i*32;
+ brw_MOV(p, byte_offset(dst, delta), deref_4f(ptr, delta));
+ brw_MOV(p, byte_offset(dst, delta+16), deref_4f(ptr, delta+16));
+ }
+}
diff --git a/src/drm/cairo-drm-intel-brw-eu.c b/src/drm/cairo-drm-intel-brw-eu.c
new file mode 100644
index 0000000..51c3de4
--- /dev/null
+++ b/src/drm/cairo-drm-intel-brw-eu.c
@@ -0,0 +1,250 @@
+/*
+ Copyright (C) Intel Corp. 2006. All Rights Reserved.
+ Intel funded Tungsten Graphics (http://www.tungstengraphics.com) to
+ develop this 3D driver.
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice (including the
+ next paragraph) shall be included in all copies or substantial
+ portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ **********************************************************************/
+/*
+ * Authors:
+ * Keith Whitwell <keith at tungstengraphics.com>
+ */
+
+#include "cairoint.h"
+#include "cairo-drm-intel-brw-eu.h"
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+/* How does predicate control work when execution_size != 8? Do I
+ * need to test/set for 0xffff when execution_size is 16?
+ */
+void brw_set_predicate_control_flag_value( struct brw_compile *p, uint32_t value )
+{
+ p->current->header.predicate_control = BRW_PREDICATE_NONE;
+
+ if (value != 0xff) {
+ if (value != p->flag_value) {
+ brw_push_insn_state(p);
+ brw_MOV(p, brw_flag_reg(), brw_imm_uw(value));
+ p->flag_value = value;
+ brw_pop_insn_state(p);
+ }
+
+ p->current->header.predicate_control = BRW_PREDICATE_NORMAL;
+ }
+}
+
+void brw_set_predicate_control( struct brw_compile *p, uint32_t pc )
+{
+ p->current->header.predicate_control = pc;
+}
+
+void brw_set_conditionalmod( struct brw_compile *p, uint32_t conditional )
+{
+ p->current->header.destreg__conditonalmod = conditional;
+}
+
+void brw_set_access_mode( struct brw_compile *p, uint32_t access_mode )
+{
+ p->current->header.access_mode = access_mode;
+}
+
+void brw_set_compression_control( struct brw_compile *p, int compression_control )
+{
+ p->current->header.compression_control = compression_control;
+}
+
+void brw_set_mask_control( struct brw_compile *p, uint32_t value )
+{
+ p->current->header.mask_control = value;
+}
+
+void brw_set_saturate( struct brw_compile *p, uint32_t value )
+{
+ p->current->header.saturate = value;
+}
+
+void brw_push_insn_state( struct brw_compile *p )
+{
+ assert(p->current != &p->stack[BRW_EU_MAX_INSN_STACK-1]);
+ memcpy(p->current+1, p->current, sizeof(struct brw_instruction));
+ p->current++;
+}
+
+void brw_pop_insn_state( struct brw_compile *p )
+{
+ assert(p->current != p->stack);
+ p->current--;
+}
+
+/************************************************************************/
+void
+brw_compile_init (struct brw_compile *p,
+ cairo_bool_t is_g4x)
+{
+ p->nr_insn = 0;
+ p->current = p->stack;
+ memset (p->current, 0, sizeof (p->current[0]));
+
+ p->is_g4x = is_g4x;
+
+ /* Some defaults? */
+ brw_set_mask_control (p, BRW_MASK_ENABLE); /* what does this do? */
+ brw_set_saturate (p, 0);
+ brw_set_compression_control (p, BRW_COMPRESSION_NONE);
+ brw_set_predicate_control_flag_value (p, 0xff);
+}
+
+const uint32_t *
+brw_get_program (struct brw_compile *p,
+ uint32_t *sz)
+{
+ *sz = p->nr_insn * sizeof (struct brw_instruction);
+ return (const uint32_t *)p->store;
+}
+
+
+
+/**
+ * Subroutine calls require special attention.
+ * Mesa instructions may be expanded into multiple hardware instructions
+ * so the prog_instruction::BranchTarget field can't be used as an index
+ * into the hardware instructions.
+ *
+ * The BranchTarget field isn't needed, however. Mesa's GLSL compiler
+ * emits CAL and BGNSUB instructions with labels that can be used to map
+ * subroutine calls to actual subroutine code blocks.
+ *
+ * The structures and function here implement patching of CAL instructions
+ * so they jump to the right subroutine code...
+ */
+
+
+/**
+ * For each OPCODE_BGNSUB we create one of these.
+ */
+struct brw_glsl_label
+{
+ const char *name; /**< the label string */
+ uint32_t position; /**< the position of the brw instruction for this label */
+ struct brw_glsl_label *next; /**< next in linked list */
+};
+
+
+/**
+ * For each OPCODE_CAL we create one of these.
+ */
+struct brw_glsl_call
+{
+ uint32_t call_inst_pos; /**< location of the CAL instruction */
+ const char *sub_name; /**< name of subroutine to call */
+ struct brw_glsl_call *next; /**< next in linked list */
+};
+
+
+/**
+ * Called for each OPCODE_BGNSUB.
+ */
+ void
+brw_save_label(struct brw_compile *c, const char *name, uint32_t position)
+{
+ struct brw_glsl_label *label = calloc(1, sizeof *label);
+ label->name = name;
+ label->position = position;
+ label->next = c->first_label;
+ c->first_label = label;
+}
+
+
+/**
+ * Called for each OPCODE_CAL.
+ */
+ void
+brw_save_call(struct brw_compile *c, const char *name, uint32_t call_pos)
+{
+ struct brw_glsl_call *call = calloc(1, sizeof *call);
+ call->call_inst_pos = call_pos;
+ call->sub_name = name;
+ call->next = c->first_call;
+ c->first_call = call;
+}
+
+
+/**
+ * Lookup a label, return label's position/offset.
+ */
+ static uint32_t
+brw_lookup_label(struct brw_compile *c, const char *name)
+{
+ const struct brw_glsl_label *label;
+ for (label = c->first_label; label; label = label->next) {
+ if (strcmp(name, label->name) == 0) {
+ return label->position;
+ }
+ }
+ abort(); /* should never happen */
+ return ~0;
+}
+
+
+/**
+ * When we're done generating code, this function is called to resolve
+ * subroutine calls.
+ */
+ void
+brw_resolve_cals(struct brw_compile *c)
+{
+ const struct brw_glsl_call *call;
+
+ for (call = c->first_call; call; call = call->next) {
+ const uint32_t sub_loc = brw_lookup_label(c, call->sub_name);
+ struct brw_instruction *brw_call_inst = &c->store[call->call_inst_pos];
+ struct brw_instruction *brw_sub_inst = &c->store[sub_loc];
+ int32_t offset = brw_sub_inst - brw_call_inst;
+
+ /* patch brw_inst1 to point to brw_inst2 */
+ brw_set_src1(brw_call_inst, brw_imm_d(offset * 16));
+ }
+
+ /* free linked list of calls */
+ {
+ struct brw_glsl_call *call, *next;
+ for (call = c->first_call; call; call = next) {
+ next = call->next;
+ free(call);
+ }
+ c->first_call = NULL;
+ }
+
+ /* free linked list of labels */
+ {
+ struct brw_glsl_label *label, *next;
+ for (label = c->first_label; label; label = next) {
+ next = label->next;
+ free(label);
+ }
+ c->first_label = NULL;
+ }
+}
diff --git a/src/drm/cairo-drm-intel-brw-eu.h b/src/drm/cairo-drm-intel-brw-eu.h
new file mode 100644
index 0000000..7a2a65c
--- /dev/null
+++ b/src/drm/cairo-drm-intel-brw-eu.h
@@ -0,0 +1,1043 @@
+/*
+ Copyright (C) Intel Corp. 2006. All Rights Reserved.
+ Intel funded Tungsten Graphics (http://www.tungstengraphics.com) to
+ develop this 3D driver.
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice (including the
+ next paragraph) shall be included in all copies or substantial
+ portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ **********************************************************************/
+/*
+ * Authors:
+ * Keith Whitwell <keith at tungstengraphics.com>
+ */
+
+#ifndef CAIRO_DRM_INTEL_BRW_EU_H
+#define CAIRO_DRM_INTEL_BRW_EU_H
+
+#include "cairo-drm-intel-brw-structs.h"
+#include "cairo-drm-intel-brw-defines.h"
+
+#include <assert.h>
+
+
+/**
+ * Writemask values, 1 bit per component.
+ */
+#define WRITEMASK_X 0x1
+#define WRITEMASK_Y 0x2
+#define WRITEMASK_Z 0x4
+#define WRITEMASK_W 0x8
+#define WRITEMASK_XY (WRITEMASK_X | WRITEMASK_Y)
+#define WRITEMASK_XZ (WRITEMASK_X | WRITEMASK_Z)
+#define WRITEMASK_YZ (WRITEMASK_Y | WRITEMASK_Z)
+#define WRITEMASK_XYZ (WRITEMASK_X | WRITEMASK_Y | WRITEMASK_Z)
+#define WRITEMASK_XW (WRITEMASK_X | WRITEMASK_W)
+#define WRITEMASK_YW (WRITEMASK_Y | WRITEMASK_W)
+#define WRITEMASK_XYW (WRITEMASK_X | WRITEMASK_Y | WRITEMASK_W)
+#define WRITEMASK_ZW (WRITEMASK_Z | WRITEMASK_W)
+#define WRITEMASK_XZW (WRITEMASK_X | WRITEMASK_Z | WRITEMASK_W)
+#define WRITEMASK_YZW (WRITEMASK_Y | WRITEMASK_Z | WRITEMASK_W)
+#define WRITEMASK_XYZW (WRITEMASK_X | WRITEMASK_Y | WRITEMASK_Z | WRITEMASK_W)
+
+#define BRW_SWIZZLE4(a,b,c,d) (((a)<<0) | ((b)<<2) | ((c)<<4) | ((d)<<6))
+#define BRW_GET_SWZ(swz, idx) (((swz) >> ((idx)*2)) & 0x3)
+
+#define BRW_SWIZZLE_NOOP BRW_SWIZZLE4 (0,1,2,3)
+#define BRW_SWIZZLE_XYZW BRW_SWIZZLE4 (0,1,2,3)
+#define BRW_SWIZZLE_XXXX BRW_SWIZZLE4 (0,0,0,0)
+#define BRW_SWIZZLE_XYXY BRW_SWIZZLE4 (0,1,0,1)
+
+#define REG_SIZE (8*4)
+
+/* These aren't hardware structs, just something useful for us to pass around:
+ *
+ * Align1 operation has a lot of control over input ranges. Used in
+ * WM programs to implement shaders decomposed into "channel serial"
+ * or "structure of array" form:
+ */
+struct brw_reg {
+ uint32_t type:4;
+ uint32_t file:2;
+ uint32_t nr:8;
+ uint32_t subnr:5; /* :1 in align16 */
+ uint32_t negate:1; /* source only */
+ uint32_t abs:1; /* source only */
+ uint32_t vstride:4; /* source only */
+ uint32_t width:3; /* src only, align1 only */
+ uint32_t hstride:2; /* align1 only */
+ uint32_t address_mode:1; /* relative addressing, hopefully! */
+ uint32_t pad0:1;
+
+ union {
+ struct {
+ uint32_t swizzle:8; /* src only, align16 only */
+ uint32_t writemask:4; /* dest only, align16 only */
+ int32_t indirect_offset:10; /* relative addressing offset */
+ uint32_t pad1:10; /* two dwords total */
+ } bits;
+
+ float f;
+ int32_t d;
+ uint32_t ud;
+ } dw1;
+};
+
+struct brw_indirect {
+ uint32_t addr_subnr:4;
+ int32_t addr_offset:10;
+ uint32_t pad:18;
+};
+
+struct brw_glsl_label;
+struct brw_glsl_call;
+
+#define BRW_EU_MAX_INSN_STACK 5
+#define BRW_EU_MAX_INSN 200
+
+struct brw_compile {
+ struct brw_instruction store[BRW_EU_MAX_INSN];
+ uint32_t nr_insn;
+
+ cairo_bool_t is_g4x;
+
+ /* Allow clients to push/pop instruction state:
+ */
+ struct brw_instruction stack[BRW_EU_MAX_INSN_STACK];
+ struct brw_instruction *current;
+
+ uint32_t flag_value;
+ int single_program_flow;
+ struct brw_context *brw;
+
+ struct brw_glsl_label *first_label; /**< linked list of labels */
+ struct brw_glsl_call *first_call; /**< linked list of CALs */
+};
+
+cairo_private void
+brw_save_label (struct brw_compile *c,
+ const char *name,
+ uint32_t position);
+
+cairo_private void
+brw_save_call (struct brw_compile *c,
+ const char *name,
+ uint32_t call_pos);
+
+cairo_private void
+brw_resolve_cals (struct brw_compile *c);
+
+static always_inline int
+type_sz (uint32_t type)
+{
+ switch (type) {
+ case BRW_REGISTER_TYPE_UD:
+ case BRW_REGISTER_TYPE_D:
+ case BRW_REGISTER_TYPE_F:
+ return 4;
+ case BRW_REGISTER_TYPE_HF:
+ case BRW_REGISTER_TYPE_UW:
+ case BRW_REGISTER_TYPE_W:
+ return 2;
+ case BRW_REGISTER_TYPE_UB:
+ case BRW_REGISTER_TYPE_B:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+/**
+ * Construct a brw_reg.
+ * \param file one of the BRW_x_REGISTER_FILE values
+ * \param nr register number/index
+ * \param subnr register sub number
+ * \param type one of BRW_REGISTER_TYPE_x
+ * \param vstride one of BRW_VERTICAL_STRIDE_x
+ * \param width one of BRW_WIDTH_x
+ * \param hstride one of BRW_HORIZONTAL_STRIDE_x
+ * \param swizzle one of BRW_SWIZZLE_x
+ * \param writemask WRITEMASK_X/Y/Z/W bitfield
+ */
+static always_inline struct brw_reg
+brw_reg (uint32_t file,
+ uint32_t nr,
+ uint32_t subnr,
+ uint32_t type,
+ uint32_t vstride,
+ uint32_t width,
+ uint32_t hstride,
+ uint32_t swizzle,
+ uint32_t writemask)
+{
+ struct brw_reg reg;
+
+ if (type == BRW_GENERAL_REGISTER_FILE)
+ assert(nr < 128);
+ else if (type == BRW_MESSAGE_REGISTER_FILE)
+ assert(nr < 9);
+ else if (type == BRW_ARCHITECTURE_REGISTER_FILE)
+ assert(nr <= BRW_ARF_IP);
+
+ reg.type = type;
+ reg.file = file;
+ reg.nr = nr;
+ reg.subnr = subnr * type_sz(type);
+ reg.negate = 0;
+ reg.abs = 0;
+ reg.vstride = vstride;
+ reg.width = width;
+ reg.hstride = hstride;
+ reg.address_mode = BRW_ADDRESS_DIRECT;
+ reg.pad0 = 0;
+
+ /* Could do better: If the reg is r5.3<0;1,0>, we probably want to
+ * set swizzle and writemask to W, as the lower bits of subnr will
+ * be lost when converted to align16. This is probably too much to
+ * keep track of as you'd want it adjusted by suboffset(), etc.
+ * Perhaps fix up when converting to align16?
+ */
+ reg.dw1.bits.swizzle = swizzle;
+ reg.dw1.bits.writemask = writemask;
+ reg.dw1.bits.indirect_offset = 0;
+ reg.dw1.bits.pad1 = 0;
+
+ return reg;
+}
+
+/** Construct float[16] register */
+static always_inline struct brw_reg
+brw_vec16_reg (uint32_t file,
+ uint32_t nr,
+ uint32_t subnr)
+{
+ return brw_reg (file, nr, subnr,
+ BRW_REGISTER_TYPE_F,
+ BRW_VERTICAL_STRIDE_16,
+ BRW_WIDTH_16,
+ BRW_HORIZONTAL_STRIDE_1,
+ BRW_SWIZZLE_XYZW,
+ WRITEMASK_XYZW);
+}
+
+/** Construct float[8] register */
+static always_inline struct brw_reg
+brw_vec8_reg (uint32_t file,
+ uint32_t nr,
+ uint32_t subnr)
+{
+ return brw_reg (file, nr, subnr,
+ BRW_REGISTER_TYPE_F,
+ BRW_VERTICAL_STRIDE_8,
+ BRW_WIDTH_8,
+ BRW_HORIZONTAL_STRIDE_1,
+ BRW_SWIZZLE_XYZW,
+ WRITEMASK_XYZW);
+}
+
+/** Construct float[4] register */
+static always_inline struct brw_reg
+brw_vec4_reg (uint32_t file,
+ uint32_t nr,
+ uint32_t subnr)
+{
+ return brw_reg (file, nr, subnr,
+ BRW_REGISTER_TYPE_F,
+ BRW_VERTICAL_STRIDE_4,
+ BRW_WIDTH_4,
+ BRW_HORIZONTAL_STRIDE_1,
+ BRW_SWIZZLE_XYZW,
+ WRITEMASK_XYZW);
+}
+
+/** Construct float[2] register */
+static always_inline struct brw_reg
+brw_vec2_reg (uint32_t file,
+ uint32_t nr,
+ uint32_t subnr)
+{
+ return brw_reg (file, nr, subnr,
+ BRW_REGISTER_TYPE_F,
+ BRW_VERTICAL_STRIDE_2,
+ BRW_WIDTH_2,
+ BRW_HORIZONTAL_STRIDE_1,
+ BRW_SWIZZLE_XYXY,
+ WRITEMASK_XY);
+}
+
+/** Construct float[1] register */
+static always_inline struct brw_reg
+brw_vec1_reg (uint32_t file,
+ uint32_t nr,
+ uint32_t subnr)
+{
+ return brw_reg (file, nr, subnr,
+ BRW_REGISTER_TYPE_F,
+ BRW_VERTICAL_STRIDE_0,
+ BRW_WIDTH_1,
+ BRW_HORIZONTAL_STRIDE_0,
+ BRW_SWIZZLE_XXXX,
+ WRITEMASK_X);
+}
+
+static always_inline struct brw_reg
+retype (struct brw_reg reg,
+ uint32_t type)
+{
+ reg.type = type;
+ return reg;
+}
+
+static always_inline struct brw_reg
+suboffset (struct brw_reg reg,
+ uint32_t delta)
+{
+ reg.subnr += delta * type_sz (reg.type);
+ return reg;
+}
+
+static always_inline struct brw_reg
+offset (struct brw_reg reg,
+ uint32_t delta)
+{
+ reg.nr += delta;
+ return reg;
+}
+
+static always_inline struct brw_reg
+byte_offset (struct brw_reg reg,
+ uint32_t bytes)
+{
+ uint32_t newoffset = reg.nr * REG_SIZE + reg.subnr + bytes;
+ reg.nr = newoffset / REG_SIZE;
+ reg.subnr = newoffset % REG_SIZE;
+ return reg;
+}
+
+/** Construct unsigned word[16] register */
+static always_inline struct brw_reg
+brw_uw16_reg (uint32_t file,
+ uint32_t nr,
+ uint32_t subnr)
+{
+ return suboffset (retype (brw_vec16_reg (file, nr, 0), BRW_REGISTER_TYPE_UW), subnr);
+}
+
+/** Construct unsigned word[8] register */
+static always_inline struct brw_reg
+brw_uw8_reg (uint32_t file,
+ uint32_t nr,
+ uint32_t subnr)
+{
+ return suboffset (retype (brw_vec8_reg (file, nr, 0), BRW_REGISTER_TYPE_UW), subnr);
+}
+
+/** Construct unsigned word[2] register */
+static always_inline struct brw_reg
+brw_uw2_reg (uint32_t file,
+ uint32_t nr,
+ uint32_t subnr)
+{
+ return suboffset (retype (brw_vec2_reg (file, nr, 0), BRW_REGISTER_TYPE_UW), subnr);
+}
+
+/** Construct unsigned word[1] register */
+static always_inline struct brw_reg
+brw_uw1_reg (uint32_t file,
+ uint32_t nr,
+ uint32_t subnr)
+{
+ return suboffset (retype (brw_vec1_reg (file, nr, 0), BRW_REGISTER_TYPE_UW), subnr);
+}
+
+static always_inline struct brw_reg
+brw_imm_reg (uint32_t type)
+{
+ return brw_reg (BRW_IMMEDIATE_VALUE,
+ 0,
+ 0,
+ type,
+ BRW_VERTICAL_STRIDE_0,
+ BRW_WIDTH_1,
+ BRW_HORIZONTAL_STRIDE_0,
+ 0,
+ 0);
+}
+
+/** Construct float immediate register */
+static always_inline struct brw_reg brw_imm_f( float f )
+{
+ struct brw_reg imm = brw_imm_reg(BRW_REGISTER_TYPE_F);
+ imm.dw1.f = f;
+ return imm;
+}
+
+/** Construct integer immediate register */
+static always_inline struct brw_reg brw_imm_d( int32_t d )
+{
+ struct brw_reg imm = brw_imm_reg(BRW_REGISTER_TYPE_D);
+ imm.dw1.d = d;
+ return imm;
+}
+
+/** Construct uint immediate register */
+static always_inline struct brw_reg brw_imm_ud( uint32_t ud )
+{
+ struct brw_reg imm = brw_imm_reg(BRW_REGISTER_TYPE_UD);
+ imm.dw1.ud = ud;
+ return imm;
+}
+
+/** Construct ushort immediate register */
+static always_inline struct brw_reg brw_imm_uw( uint16_t uw )
+{
+ struct brw_reg imm = brw_imm_reg(BRW_REGISTER_TYPE_UW);
+ imm.dw1.ud = uw | (uw << 16);
+ return imm;
+}
+
+/** Construct short immediate register */
+static always_inline struct brw_reg brw_imm_w( int16_t w )
+{
+ struct brw_reg imm = brw_imm_reg(BRW_REGISTER_TYPE_W);
+ imm.dw1.d = w | (w << 16);
+ return imm;
+}
+
+/* brw_imm_b and brw_imm_ub aren't supported by hardware - the type
+ * numbers alias with _V and _VF below:
+ */
+
+/** Construct vector of eight signed half-byte values */
+static always_inline
+struct brw_reg brw_imm_v (uint32_t v)
+{
+ struct brw_reg imm = brw_imm_reg(BRW_REGISTER_TYPE_V);
+ imm.vstride = BRW_VERTICAL_STRIDE_0;
+ imm.width = BRW_WIDTH_8;
+ imm.hstride = BRW_HORIZONTAL_STRIDE_1;
+ imm.dw1.ud = v;
+ return imm;
+}
+
+/** Construct vector of four 8-bit float values */
+static always_inline struct brw_reg
+brw_imm_vf (uint32_t v)
+{
+ struct brw_reg imm = brw_imm_reg(BRW_REGISTER_TYPE_VF);
+ imm.vstride = BRW_VERTICAL_STRIDE_0;
+ imm.width = BRW_WIDTH_4;
+ imm.hstride = BRW_HORIZONTAL_STRIDE_1;
+ imm.dw1.ud = v;
+ return imm;
+}
+
+#define VF_ZERO 0x0
+#define VF_ONE 0x30
+#define VF_NEG (1<<7)
+
+static always_inline struct brw_reg
+brw_imm_vf4 (uint32_t v0,
+ uint32_t v1,
+ uint32_t v2,
+ uint32_t v3)
+{
+ struct brw_reg imm = brw_imm_reg(BRW_REGISTER_TYPE_VF);
+ imm.vstride = BRW_VERTICAL_STRIDE_0;
+ imm.width = BRW_WIDTH_4;
+ imm.hstride = BRW_HORIZONTAL_STRIDE_1;
+ imm.dw1.ud = ((v0 << 0) |
+ (v1 << 8) |
+ (v2 << 16) |
+ (v3 << 24));
+ return imm;
+}
+
+static always_inline struct brw_reg
+brw_address (struct brw_reg reg)
+{
+ return brw_imm_uw (reg.nr * REG_SIZE + reg.subnr);
+}
+
+/** Construct float[1] general-purpose register */
+static always_inline struct brw_reg
+brw_vec1_grf (uint32_t nr, uint32_t subnr)
+{
+ return brw_vec1_reg (BRW_GENERAL_REGISTER_FILE, nr, subnr);
+}
+
+/** Construct float[2] general-purpose register */
+static always_inline struct brw_reg
+brw_vec2_grf (uint32_t nr, uint32_t subnr)
+{
+ return brw_vec2_reg (BRW_GENERAL_REGISTER_FILE, nr, subnr);
+}
+
+/** Construct float[4] general-purpose register */
+static always_inline struct brw_reg
+brw_vec4_grf (uint32_t nr, uint32_t subnr)
+{
+ return brw_vec4_reg (BRW_GENERAL_REGISTER_FILE, nr, subnr);
+}
+
+/** Construct float[8] general-purpose register */
+static always_inline struct brw_reg
+brw_vec8_grf (uint32_t nr)
+{
+ return brw_vec8_reg (BRW_GENERAL_REGISTER_FILE, nr, 0);
+}
+
+static always_inline struct brw_reg
+brw_uw8_grf (uint32_t nr, uint32_t subnr)
+{
+ return brw_uw8_reg (BRW_GENERAL_REGISTER_FILE, nr, subnr);
+}
+
+static always_inline struct brw_reg
+brw_uw16_grf (uint32_t nr, uint32_t subnr)
+{
+ return brw_uw16_reg (BRW_GENERAL_REGISTER_FILE, nr, subnr);
+}
+
+/** Construct null register (usually used for setting condition codes) */
+static always_inline struct brw_reg
+brw_null_reg (void)
+{
+ return brw_vec8_reg (BRW_ARCHITECTURE_REGISTER_FILE,
+ BRW_ARF_NULL,
+ 0);
+}
+
+static always_inline struct brw_reg
+brw_address_reg (uint32_t subnr)
+{
+ return brw_uw1_reg (BRW_ARCHITECTURE_REGISTER_FILE,
+ BRW_ARF_ADDRESS,
+ subnr);
+}
+
+/* If/else instructions break in align16 mode if writemask & swizzle
+ * aren't xyzw. This goes against the convention for other scalar
+ * regs:
+ */
+static always_inline struct brw_reg
+brw_ip_reg (void)
+{
+ return brw_reg (BRW_ARCHITECTURE_REGISTER_FILE,
+ BRW_ARF_IP,
+ 0,
+ BRW_REGISTER_TYPE_UD,
+ BRW_VERTICAL_STRIDE_4, /* ? */
+ BRW_WIDTH_1,
+ BRW_HORIZONTAL_STRIDE_0,
+ BRW_SWIZZLE_XYZW,
+ WRITEMASK_XYZW);
+}
+
+static always_inline struct brw_reg
+brw_acc_reg (void)
+{
+ return brw_vec8_reg (BRW_ARCHITECTURE_REGISTER_FILE,
+ BRW_ARF_ACCUMULATOR,
+ 0);
+}
+
+static always_inline struct brw_reg
+brw_flag_reg (void)
+{
+ return brw_uw1_reg (BRW_ARCHITECTURE_REGISTER_FILE,
+ BRW_ARF_FLAG,
+ 0);
+}
+
+static always_inline struct brw_reg
+brw_mask_reg (uint32_t subnr)
+{
+ return brw_uw1_reg (BRW_ARCHITECTURE_REGISTER_FILE,
+ BRW_ARF_MASK,
+ subnr);
+}
+
+static always_inline struct brw_reg
+brw_message4_reg (uint32_t nr)
+{
+ return brw_vec4_reg (BRW_MESSAGE_REGISTER_FILE,
+ nr,
+ 0);
+}
+
+static always_inline struct brw_reg
+brw_message_reg (uint32_t nr)
+{
+ return brw_vec8_reg (BRW_MESSAGE_REGISTER_FILE,
+ nr,
+ 0);
+}
+
+/* This is almost always called with a numeric constant argument, so
+ * make things easy to evaluate at compile time:
+ */
+static always_inline uint32_t
+cvt (uint32_t val)
+{
+ switch (val) {
+ case 0: return 0;
+ case 1: return 1;
+ case 2: return 2;
+ case 4: return 3;
+ case 8: return 4;
+ case 16: return 5;
+ case 32: return 6;
+ }
+ return 0;
+}
+
+static always_inline struct brw_reg
+stride (struct brw_reg reg,
+ uint32_t vstride,
+ uint32_t width,
+ uint32_t hstride)
+{
+ reg.vstride = cvt (vstride);
+ reg.width = cvt (width) - 1;
+ reg.hstride = cvt (hstride);
+ return reg;
+}
+
+static always_inline struct brw_reg
+vec16 (struct brw_reg reg)
+{
+ return stride (reg, 16,16,1);
+}
+
+static always_inline struct brw_reg
+vec8 (struct brw_reg reg)
+{
+ return stride (reg, 8,8,1);
+}
+
+static always_inline struct brw_reg
+vec4 (struct brw_reg reg)
+{
+ return stride (reg, 4,4,1);
+}
+
+static always_inline struct brw_reg
+vec2 (struct brw_reg reg)
+{
+ return stride (reg, 2,2,1);
+}
+
+static always_inline struct brw_reg
+vec1 (struct brw_reg reg)
+{
+ return stride (reg, 0,1,0);
+}
+
+static always_inline struct brw_reg
+get_element (struct brw_reg reg, uint32_t elt)
+{
+ return vec1 (suboffset (reg, elt));
+}
+
+static always_inline struct brw_reg
+get_element_ud (struct brw_reg reg, uint32_t elt)
+{
+ return vec1 (suboffset (retype (reg, BRW_REGISTER_TYPE_UD), elt));
+}
+
+static always_inline struct brw_reg
+brw_swizzle (struct brw_reg reg,
+ uint32_t x,
+ uint32_t y,
+ uint32_t z,
+ uint32_t w)
+{
+ reg.dw1.bits.swizzle = BRW_SWIZZLE4 (BRW_GET_SWZ (reg.dw1.bits.swizzle, x),
+ BRW_GET_SWZ (reg.dw1.bits.swizzle, y),
+ BRW_GET_SWZ (reg.dw1.bits.swizzle, z),
+ BRW_GET_SWZ (reg.dw1.bits.swizzle, w));
+ return reg;
+}
+
+static always_inline struct brw_reg
+brw_swizzle1 (struct brw_reg reg,
+ uint32_t x)
+{
+ return brw_swizzle (reg, x, x, x, x);
+}
+
+static always_inline struct brw_reg
+brw_writemask (struct brw_reg reg,
+ uint32_t mask)
+{
+ reg.dw1.bits.writemask &= mask;
+ return reg;
+}
+
+static always_inline struct brw_reg
+brw_set_writemask (struct brw_reg reg,
+ uint32_t mask)
+{
+ reg.dw1.bits.writemask = mask;
+ return reg;
+}
+
+static always_inline struct brw_reg
+negate (struct brw_reg reg)
+{
+ reg.negate ^= 1;
+ return reg;
+}
+
+static always_inline struct brw_reg
+brw_abs (struct brw_reg reg)
+{
+ reg.abs = 1;
+ return reg;
+}
+
+static always_inline struct brw_reg
+brw_vec4_indirect (uint32_t subnr,
+ int32_t offset)
+{
+ struct brw_reg reg = brw_vec4_grf (0, 0);
+ reg.subnr = subnr;
+ reg.address_mode = BRW_ADDRESS_REGISTER_INDIRECT_REGISTER;
+ reg.dw1.bits.indirect_offset = offset;
+ return reg;
+}
+
+static always_inline struct brw_reg
+brw_vec1_indirect (uint32_t subnr,
+ int32_t offset)
+{
+ struct brw_reg reg = brw_vec1_grf (0, 0);
+ reg.subnr = subnr;
+ reg.address_mode = BRW_ADDRESS_REGISTER_INDIRECT_REGISTER;
+ reg.dw1.bits.indirect_offset = offset;
+ return reg;
+}
+
+static always_inline struct brw_reg
+deref_4f (struct brw_indirect ptr, int32_t offset)
+{
+ return brw_vec4_indirect (ptr.addr_subnr, ptr.addr_offset + offset);
+}
+
+static always_inline struct brw_reg
+deref_1f(struct brw_indirect ptr, int32_t offset)
+{
+ return brw_vec1_indirect (ptr.addr_subnr, ptr.addr_offset + offset);
+}
+
+static always_inline struct brw_reg
+deref_4b(struct brw_indirect ptr, int32_t offset)
+{
+ return retype (deref_4f (ptr, offset), BRW_REGISTER_TYPE_B);
+}
+
+static always_inline struct brw_reg
+deref_1uw(struct brw_indirect ptr, int32_t offset)
+{
+ return retype (deref_1f (ptr, offset), BRW_REGISTER_TYPE_UW);
+}
+
+static always_inline struct brw_reg
+deref_1d (struct brw_indirect ptr, int32_t offset)
+{
+ return retype (deref_1f (ptr, offset), BRW_REGISTER_TYPE_D);
+}
+
+static always_inline struct brw_reg
+deref_1ud (struct brw_indirect ptr, int32_t offset)
+{
+ return retype (deref_1f (ptr, offset), BRW_REGISTER_TYPE_UD);
+}
+
+static always_inline struct brw_reg
+get_addr_reg (struct brw_indirect ptr)
+{
+ return brw_address_reg (ptr.addr_subnr);
+}
+
+static always_inline struct brw_indirect
+brw_indirect_offset (struct brw_indirect ptr, int32_t offset)
+{
+ ptr.addr_offset += offset;
+ return ptr;
+}
+
+static always_inline struct brw_indirect
+brw_indirect (uint32_t addr_subnr, int32_t offset)
+{
+ struct brw_indirect ptr;
+ ptr.addr_subnr = addr_subnr;
+ ptr.addr_offset = offset;
+ ptr.pad = 0;
+ return ptr;
+}
+
+static always_inline struct brw_instruction *
+current_insn (struct brw_compile *p)
+{
+ return &p->store[p->nr_insn];
+}
+
+cairo_private void brw_pop_insn_state (struct brw_compile *p);
+cairo_private void brw_push_insn_state (struct brw_compile *p);
+cairo_private void brw_set_mask_control (struct brw_compile *p, uint32_t value);
+cairo_private void brw_set_saturate (struct brw_compile *p, uint32_t value);
+cairo_private void brw_set_access_mode (struct brw_compile *p, uint32_t access_mode);
+cairo_private void brw_set_compression_control (struct brw_compile *p, int control);
+cairo_private void brw_set_predicate_control_flag_value (struct brw_compile *p, uint32_t value);
+cairo_private void brw_set_predicate_control (struct brw_compile *p, uint32_t pc);
+cairo_private void brw_set_conditionalmod (struct brw_compile *p, uint32_t conditional);
+
+cairo_private void
+brw_compile_init (struct brw_compile *p,
+ cairo_bool_t is_g4x);
+cairo_private const uint32_t *brw_get_program (struct brw_compile *p, uint32_t *sz);
+
+/* Helpers for regular instructions:
+ */
+#define ALU1(OP) \
+cairo_private_no_warn struct brw_instruction * \
+brw_##OP(struct brw_compile *p, \
+ struct brw_reg dest, \
+ struct brw_reg src0);
+
+#define ALU2(OP) \
+cairo_private_no_warn struct brw_instruction * \
+brw_##OP(struct brw_compile *p, \
+ struct brw_reg dest, \
+ struct brw_reg src0, \
+ struct brw_reg src1);
+
+ALU1(MOV)
+ALU2(SEL)
+ALU1(NOT)
+ALU2(AND)
+ALU2(OR)
+ALU2(XOR)
+ALU2(SHR)
+ALU2(SHL)
+ALU2(RSR)
+ALU2(RSL)
+ALU2(ASR)
+ALU2(JMPI)
+ALU2(ADD)
+ALU2(MUL)
+ALU1(FRC)
+ALU1(RNDD)
+ALU1(RNDZ)
+ALU2(MAC)
+ALU2(MACH)
+ALU1(LZD)
+ALU2(DP4)
+ALU2(DPH)
+ALU2(DP3)
+ALU2(DP2)
+ALU2(LINE)
+
+#undef ALU1
+#undef ALU2
+
+/* Helpers for SEND instruction: */
+cairo_private void
+brw_urb_WRITE (struct brw_compile *p,
+ struct brw_reg dest,
+ uint32_t msg_reg_nr,
+ struct brw_reg src0,
+ int allocate,
+ int used,
+ uint32_t msg_length,
+ uint32_t response_length,
+ int eot,
+ int writes_complete,
+ uint32_t offset,
+ uint32_t swizzle);
+
+cairo_private void
+brw_fb_WRITE (struct brw_compile *p,
+ struct brw_reg dest,
+ uint32_t msg_reg_nr,
+ struct brw_reg src0,
+ uint32_t binding_table_index,
+ uint32_t msg_length,
+ uint32_t response_length,
+ int eot);
+
+cairo_private void
+brw_SAMPLE (struct brw_compile *p,
+ struct brw_reg dest,
+ uint32_t msg_reg_nr,
+ struct brw_reg src0,
+ uint32_t binding_table_index,
+ uint32_t sampler,
+ uint32_t writemask,
+ uint32_t msg_type,
+ uint32_t response_length,
+ uint32_t msg_length,
+ cairo_bool_t eot);
+
+cairo_private void
+brw_math_16 (struct brw_compile *p,
+ struct brw_reg dest,
+ uint32_t function,
+ uint32_t saturate,
+ uint32_t msg_reg_nr,
+ struct brw_reg src,
+ uint32_t precision);
+
+cairo_private void
+brw_math (struct brw_compile *p,
+ struct brw_reg dest,
+ uint32_t function,
+ uint32_t saturate,
+ uint32_t msg_reg_nr,
+ struct brw_reg src,
+ uint32_t data_type,
+ uint32_t precision);
+
+cairo_private void
+brw_dp_READ_16 (struct brw_compile *p,
+ struct brw_reg dest,
+ uint32_t msg_reg_nr,
+ uint32_t scratch_offset);
+
+cairo_private void
+brw_dp_WRITE_16 (struct brw_compile *p,
+ struct brw_reg src,
+ uint32_t msg_reg_nr,
+ uint32_t scratch_offset);
+
+/* If/else/endif. Works by manipulating the execution flags on each
+ * channel.
+ */
+cairo_private struct brw_instruction *
+brw_IF (struct brw_compile *p,
+ uint32_t execute_size);
+
+cairo_private struct brw_instruction *
+brw_ELSE (struct brw_compile *p,
+ struct brw_instruction *if_insn);
+
+cairo_private void
+brw_ENDIF (struct brw_compile *p,
+ struct brw_instruction *if_or_else_insn);
+
+
+/* DO/WHILE loops: */
+cairo_private struct brw_instruction *
+brw_DO (struct brw_compile *p,
+ uint32_t execute_size);
+
+cairo_private struct brw_instruction *
+brw_WHILE (struct brw_compile *p,
+ struct brw_instruction *patch_insn);
+
+cairo_private struct brw_instruction *
+brw_BREAK (struct brw_compile *p);
+
+cairo_private struct brw_instruction *
+brw_CONT (struct brw_compile *p);
+
+/* Forward jumps: */
+cairo_private void
+brw_land_fwd_jump (struct brw_compile *p,
+ struct brw_instruction *jmp_insn);
+
+cairo_private void
+brw_NOP (struct brw_compile *p);
+
+/* Special case: there is never a destination, execution size will be
+ * taken from src0:
+ */
+cairo_private void
+brw_CMP (struct brw_compile *p,
+ struct brw_reg dest,
+ uint32_t conditional,
+ struct brw_reg src0,
+ struct brw_reg src1);
+
+cairo_private void
+brw_print_reg (struct brw_reg reg);
+
+cairo_private struct brw_instruction *
+brw_next_instruction (struct brw_compile *p,
+ uint32_t opcode);
+
+cairo_private void
+brw_instruction_set_destination (struct brw_instruction *insn,
+ struct brw_reg dest);
+
+cairo_private void
+brw_instruction_set_source0 (struct brw_instruction *insn,
+ struct brw_reg reg);
+
+cairo_private void
+brw_instruction_set_dp_write_message (struct brw_instruction *insn,
+ uint32_t binding_table_index,
+ uint32_t msg_control,
+ uint32_t msg_type,
+ uint32_t msg_length,
+ uint32_t pixel_scoreboard_clear,
+ uint32_t response_length,
+ uint32_t end_of_thread);
+
+/***********************************************************************
+ * brw_eu_util.c:
+ */
+
+cairo_private void
+brw_copy_indirect_to_indirect (struct brw_compile *p,
+ struct brw_indirect dst_ptr,
+ struct brw_indirect src_ptr,
+ uint32_t count);
+
+cairo_private void
+brw_copy_from_indirect (struct brw_compile *p,
+ struct brw_reg dst,
+ struct brw_indirect ptr,
+ uint32_t count);
+
+cairo_private void
+brw_copy4 (struct brw_compile *p,
+ struct brw_reg dst,
+ struct brw_reg src,
+ uint32_t count);
+
+cairo_private void
+brw_copy8 (struct brw_compile *p,
+ struct brw_reg dst,
+ struct brw_reg src,
+ uint32_t count);
+
+cairo_private void
+brw_math_invert (struct brw_compile *p,
+ struct brw_reg dst,
+ struct brw_reg src);
+
+cairo_private void
+brw_set_src1 (struct brw_instruction *insn,
+ struct brw_reg reg);
+
+#endif
diff --git a/src/drm/cairo-drm-intel-brw-structs.h b/src/drm/cairo-drm-intel-brw-structs.h
new file mode 100644
index 0000000..f42483e
--- /dev/null
+++ b/src/drm/cairo-drm-intel-brw-structs.h
@@ -0,0 +1,1328 @@
+/**************************************************************************
+ *
+ * Copyright 2005 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+#ifndef CAIRO_DRM_INTEL_BRW_STRUCTS_H
+#define CAIRO_DRM_INTEL_BRW_STRUCTS_H
+
+#include "cairo-types-private.h"
+
+/* Command packets:
+*/
+struct header {
+ unsigned int length:16;
+ unsigned int opcode:16;
+};
+
+union header_union {
+ struct header bits;
+ unsigned int dword;
+};
+
+struct brw_3d_control {
+ struct {
+ unsigned int length:8;
+ unsigned int notify_enable:1;
+ unsigned int pad:3;
+ unsigned int wc_flush_enable:1;
+ unsigned int depth_stall_enable:1;
+ unsigned int operation:2;
+ unsigned int opcode:16;
+ } header;
+
+ struct {
+ unsigned int pad:2;
+ unsigned int dest_addr_type:1;
+ unsigned int dest_addr:29;
+ } dest;
+
+ unsigned int dword2;
+ unsigned int dword3;
+};
+
+
+struct brw_3d_primitive {
+ struct {
+ unsigned int length:8;
+ unsigned int pad:2;
+ unsigned int topology:5;
+ unsigned int indexed:1;
+ unsigned int opcode:16;
+ } header;
+
+ unsigned int verts_per_instance;
+ unsigned int start_vert_location;
+ unsigned int instance_count;
+ unsigned int start_instance_location;
+ unsigned int base_vert_location;
+};
+
+/* These seem to be passed around as function args, so it works out
+ * better to keep them as #defines:
+ */
+#define BRW_FLUSH_READ_CACHE 0x1
+#define BRW_FLUSH_STATE_CACHE 0x2
+#define BRW_INHIBIT_FLUSH_RENDER_CACHE 0x4
+#define BRW_FLUSH_SNAPSHOT_COUNTERS 0x8
+
+struct brw_mi_flush {
+ unsigned int flags:4;
+ unsigned int pad:12;
+ unsigned int opcode:16;
+};
+
+struct brw_vf_statistics {
+ unsigned int statistics_enable:1;
+ unsigned int pad:15;
+ unsigned int opcode:16;
+};
+
+
+struct brw_binding_table_pointers {
+ struct header header;
+ unsigned int vs;
+ unsigned int gs;
+ unsigned int clp;
+ unsigned int sf;
+ unsigned int wm;
+};
+
+struct brw_blend_constant_color {
+ struct header header;
+ float blend_constant_color[4];
+};
+
+struct brw_depthbuffer {
+ union header_union header;
+
+ union {
+ struct {
+ unsigned int pitch:18;
+ unsigned int format:3;
+ unsigned int pad:4;
+ unsigned int depth_offset_disable:1;
+ unsigned int tile_walk:1;
+ unsigned int tiled_surface:1;
+ unsigned int pad2:1;
+ unsigned int surface_type:3;
+ } bits;
+ unsigned int dword;
+ } dword1;
+
+ unsigned int dword2_base_addr;
+
+ union {
+ struct {
+ unsigned int pad:1;
+ unsigned int mipmap_layout:1;
+ unsigned int lod:4;
+ unsigned int width:13;
+ unsigned int height:13;
+ } bits;
+ unsigned int dword;
+ } dword3;
+
+ union {
+ struct {
+ unsigned int pad:12;
+ unsigned int min_array_element:9;
+ unsigned int depth:11;
+ } bits;
+ unsigned int dword;
+ } dword4;
+};
+
+struct brw_drawrect {
+ struct header header;
+ unsigned int xmin:16;
+ unsigned int ymin:16;
+ unsigned int xmax:16;
+ unsigned int ymax:16;
+ unsigned int xorg:16;
+ unsigned int yorg:16;
+};
+
+struct brw_global_depth_offset_clamp {
+ struct header header;
+ float depth_offset_clamp;
+};
+
+struct brw_indexbuffer {
+ union {
+ struct {
+ unsigned int length:8;
+ unsigned int index_format:2;
+ unsigned int cut_index_enable:1;
+ unsigned int pad:5;
+ unsigned int opcode:16;
+ } bits;
+ unsigned int dword;
+ } header;
+ unsigned int buffer_start;
+ unsigned int buffer_end;
+};
+
+
+struct brw_line_stipple {
+ struct header header;
+
+ struct {
+ unsigned int pattern:16;
+ unsigned int pad:16;
+ } bits0;
+
+ struct {
+ unsigned int repeat_count:9;
+ unsigned int pad:7;
+ unsigned int inverse_repeat_count:16;
+ } bits1;
+};
+
+struct brw_pipelined_state_pointers {
+ struct header header;
+
+ struct {
+ unsigned int pad:5;
+ unsigned int offset:27;
+ } vs;
+
+ struct {
+ unsigned int enable:1;
+ unsigned int pad:4;
+ unsigned int offset:27;
+ } gs;
+
+ struct {
+ unsigned int enable:1;
+ unsigned int pad:4;
+ unsigned int offset:27;
+ } clp;
+
+ struct {
+ unsigned int pad:5;
+ unsigned int offset:27;
+ } sf;
+
+ struct {
+ unsigned int pad:5;
+ unsigned int offset:27;
+ } wm;
+
+ struct {
+ unsigned int pad:6;
+ unsigned int offset:26;
+ } cc;
+};
+
+struct brw_polygon_stipple_offset {
+ struct header header;
+
+ struct {
+ unsigned int y_offset:5;
+ unsigned int pad:3;
+ unsigned int x_offset:5;
+ unsigned int pad0:19;
+ } bits0;
+};
+
+struct brw_polygon_stipple {
+ struct header header;
+ unsigned int stipple[32];
+};
+
+struct brw_pipeline_select {
+ struct {
+ unsigned int pipeline_select:1;
+ unsigned int pad:15;
+ unsigned int opcode:16;
+ } header;
+};
+
+struct brw_pipe_control {
+ struct {
+ unsigned int length:8;
+ unsigned int notify_enable:1;
+ unsigned int pad:2;
+ unsigned int instruction_state_cache_flush_enable:1;
+ unsigned int write_cache_flush_enable:1;
+ unsigned int depth_stall_enable:1;
+ unsigned int post_sync_operation:2;
+
+ unsigned int opcode:16;
+ } header;
+
+ struct {
+ unsigned int pad:2;
+ unsigned int dest_addr_type:1;
+ unsigned int dest_addr:29;
+ } bits1;
+
+ unsigned int data0;
+ unsigned int data1;
+};
+
+
+struct brw_urb_fence {
+ struct {
+ unsigned int length:8;
+ unsigned int vs_realloc:1;
+ unsigned int gs_realloc:1;
+ unsigned int clp_realloc:1;
+ unsigned int sf_realloc:1;
+ unsigned int vfe_realloc:1;
+ unsigned int cs_realloc:1;
+ unsigned int pad:2;
+ unsigned int opcode:16;
+ } header;
+
+ struct {
+ unsigned int vs_fence:10;
+ unsigned int gs_fence:10;
+ unsigned int clp_fence:10;
+ unsigned int pad:2;
+ } bits0;
+
+ struct {
+ unsigned int sf_fence:10;
+ unsigned int vf_fence:10;
+ unsigned int cs_fence:10;
+ unsigned int pad:2;
+ } bits1;
+};
+
+struct brw_constant_buffer_state {
+ struct header header;
+
+ struct {
+ unsigned int nr_urb_entries:3;
+ unsigned int pad:1;
+ unsigned int urb_entry_size:5;
+ unsigned int pad0:23;
+ } bits0;
+};
+
+struct brw_constant_buffer {
+ struct {
+ unsigned int length:8;
+ unsigned int valid:1;
+ unsigned int pad:7;
+ unsigned int opcode:16;
+ } header;
+
+ struct {
+ unsigned int buffer_length:6;
+ unsigned int buffer_address:26;
+ } bits0;
+};
+
+struct brw_state_base_address {
+ struct header header;
+
+ struct {
+ unsigned int modify_enable:1;
+ unsigned int pad:4;
+ unsigned int general_state_address:27;
+ } bits0;
+
+ struct {
+ unsigned int modify_enable:1;
+ unsigned int pad:4;
+ unsigned int surface_state_address:27;
+ } bits1;
+
+ struct {
+ unsigned int modify_enable:1;
+ unsigned int pad:4;
+ unsigned int indirect_object_state_address:27;
+ } bits2;
+
+ struct {
+ unsigned int modify_enable:1;
+ unsigned int pad:11;
+ unsigned int general_state_upper_bound:20;
+ } bits3;
+
+ struct {
+ unsigned int modify_enable:1;
+ unsigned int pad:11;
+ unsigned int indirect_object_state_upper_bound:20;
+ } bits4;
+};
+
+struct brw_state_prefetch {
+ struct header header;
+
+ struct {
+ unsigned int prefetch_count:3;
+ unsigned int pad:3;
+ unsigned int prefetch_pointer:26;
+ } bits0;
+};
+
+struct brw_system_instruction_pointer {
+ struct header header;
+
+ struct {
+ unsigned int pad:4;
+ unsigned int system_instruction_pointer:28;
+ } bits0;
+};
+
+
+/* State structs for the various fixed function units:
+*/
+
+struct thread0 {
+ unsigned int pad0:1;
+ unsigned int grf_reg_count:3;
+ unsigned int pad1:2;
+ unsigned int kernel_start_pointer:26;
+};
+
+struct thread1 {
+ unsigned int ext_halt_exception_enable:1;
+ unsigned int sw_exception_enable:1;
+ unsigned int mask_stack_exception_enable:1;
+ unsigned int timeout_exception_enable:1;
+ unsigned int illegal_op_exception_enable:1;
+ unsigned int pad0:3;
+ unsigned int depth_coef_urb_read_offset:6; /* WM only */
+ unsigned int pad1:2;
+ unsigned int floating_point_mode:1;
+ unsigned int thread_priority:1;
+ unsigned int binding_table_entry_count:8;
+ unsigned int pad3:5;
+ unsigned int single_program_flow:1;
+};
+
+struct thread2 {
+ unsigned int per_thread_scratch_space:4;
+ unsigned int pad0:6;
+ unsigned int scratch_space_base_pointer:22;
+};
+
+struct thread3 {
+ unsigned int dispatch_grf_start_reg:4;
+ unsigned int urb_entry_read_offset:6;
+ unsigned int pad0:1;
+ unsigned int urb_entry_read_length:6;
+ unsigned int pad1:1;
+ unsigned int const_urb_entry_read_offset:6;
+ unsigned int pad2:1;
+ unsigned int const_urb_entry_read_length:6;
+ unsigned int pad3:1;
+};
+
+struct brw_clip_unit_state {
+ struct thread0 thread0;
+ struct thread1 thread1;
+ struct thread2 thread2;
+ struct thread3 thread3;
+
+ struct {
+ unsigned int pad0:9;
+ unsigned int gs_output_stats:1; /* not always */
+ unsigned int stats_enable:1;
+ unsigned int nr_urb_entries:7;
+ unsigned int pad1:1;
+ unsigned int urb_entry_allocation_size:5;
+ unsigned int pad2:1;
+ unsigned int max_threads:6; /* may be less */
+ unsigned int pad3:1;
+ } thread4;
+
+ struct {
+ unsigned int pad0:13;
+ unsigned int clip_mode:3;
+ unsigned int userclip_enable_flags:8;
+ unsigned int userclip_must_clip:1;
+ unsigned int pad1:1;
+ unsigned int guard_band_enable:1;
+ unsigned int viewport_z_clip_enable:1;
+ unsigned int viewport_xy_clip_enable:1;
+ unsigned int vertex_position_space:1;
+ unsigned int api_mode:1;
+ unsigned int pad2:1;
+ } clip5;
+
+ struct {
+ unsigned int pad0:5;
+ unsigned int clipper_viewport_state_ptr:27;
+ } clip6;
+
+ float viewport_xmin;
+ float viewport_xmax;
+ float viewport_ymin;
+ float viewport_ymax;
+};
+
+struct brw_cc_unit_state {
+ struct {
+ unsigned int pad0:3;
+ unsigned int bf_stencil_pass_depth_pass_op:3;
+ unsigned int bf_stencil_pass_depth_fail_op:3;
+ unsigned int bf_stencil_fail_op:3;
+ unsigned int bf_stencil_func:3;
+ unsigned int bf_stencil_enable:1;
+ unsigned int pad1:2;
+ unsigned int stencil_write_enable:1;
+ unsigned int stencil_pass_depth_pass_op:3;
+ unsigned int stencil_pass_depth_fail_op:3;
+ unsigned int stencil_fail_op:3;
+ unsigned int stencil_func:3;
+ unsigned int stencil_enable:1;
+ } cc0;
+
+ struct {
+ unsigned int bf_stencil_ref:8;
+ unsigned int stencil_write_mask:8;
+ unsigned int stencil_test_mask:8;
+ unsigned int stencil_ref:8;
+ } cc1;
+
+ struct {
+ unsigned int logicop_enable:1;
+ unsigned int pad0:10;
+ unsigned int depth_write_enable:1;
+ unsigned int depth_test_function:3;
+ unsigned int depth_test:1;
+ unsigned int bf_stencil_write_mask:8;
+ unsigned int bf_stencil_test_mask:8;
+ } cc2;
+
+ struct {
+ unsigned int pad0:8;
+ unsigned int alpha_test_func:3;
+ unsigned int alpha_test:1;
+ unsigned int blend_enable:1;
+ unsigned int ia_blend_enable:1;
+ unsigned int pad1:1;
+ unsigned int alpha_test_format:1;
+ unsigned int pad2:16;
+ } cc3;
+
+ struct {
+ unsigned int pad0:5;
+ unsigned int cc_viewport_state_offset:27;
+ } cc4;
+
+ struct {
+ unsigned int pad0:2;
+ unsigned int ia_dest_blend_factor:5;
+ unsigned int ia_src_blend_factor:5;
+ unsigned int ia_blend_function:3;
+ unsigned int statistics_enable:1;
+ unsigned int logicop_func:4;
+ unsigned int pad1:11;
+ unsigned int dither_enable:1;
+ } cc5;
+
+ struct {
+ unsigned int clamp_post_alpha_blend:1;
+ unsigned int clamp_pre_alpha_blend:1;
+ unsigned int clamp_range:2;
+ unsigned int pad0:11;
+ unsigned int y_dither_offset:2;
+ unsigned int x_dither_offset:2;
+ unsigned int dest_blend_factor:5;
+ unsigned int src_blend_factor:5;
+ unsigned int blend_function:3;
+ } cc6;
+
+ struct {
+ union {
+ float f;
+ unsigned char ub[4];
+ } alpha_ref;
+ } cc7;
+};
+
+struct brw_sf_unit_state {
+ struct thread0 thread0;
+ struct {
+ unsigned int pad0:7;
+ unsigned int sw_exception_enable:1;
+ unsigned int pad1:3;
+ unsigned int mask_stack_exception_enable:1;
+ unsigned int pad2:1;
+ unsigned int illegal_op_exception_enable:1;
+ unsigned int pad3:2;
+ unsigned int floating_point_mode:1;
+ unsigned int thread_priority:1;
+ unsigned int binding_table_entry_count:8;
+ unsigned int pad4:5;
+ unsigned int single_program_flow:1;
+ } sf1;
+
+ struct thread2 thread2;
+ struct thread3 thread3;
+
+ struct {
+ unsigned int pad0:10;
+ unsigned int stats_enable:1;
+ unsigned int nr_urb_entries:7;
+ unsigned int pad1:1;
+ unsigned int urb_entry_allocation_size:5;
+ unsigned int pad2:1;
+ unsigned int max_threads:6;
+ unsigned int pad3:1;
+ } thread4;
+
+ struct {
+ unsigned int front_winding:1;
+ unsigned int viewport_transform:1;
+ unsigned int pad0:3;
+ unsigned int sf_viewport_state_offset:27;
+ } sf5;
+
+ struct {
+ unsigned int pad0:9;
+ unsigned int dest_org_vbias:4;
+ unsigned int dest_org_hbias:4;
+ unsigned int scissor:1;
+ unsigned int disable_2x2_trifilter:1;
+ unsigned int disable_zero_pix_trifilter:1;
+ unsigned int point_rast_rule:2;
+ unsigned int line_endcap_aa_region_width:2;
+ unsigned int line_width:4;
+ unsigned int fast_scissor_disable:1;
+ unsigned int cull_mode:2;
+ unsigned int aa_enable:1;
+ } sf6;
+
+ struct {
+ unsigned int point_size:11;
+ unsigned int use_point_size_state:1;
+ unsigned int subpixel_precision:1;
+ unsigned int sprite_point:1;
+ unsigned int pad0:11;
+ unsigned int trifan_pv:2;
+ unsigned int linestrip_pv:2;
+ unsigned int tristrip_pv:2;
+ unsigned int line_last_pixel_enable:1;
+ } sf7;
+};
+
+struct brw_gs_unit_state {
+ struct thread0 thread0;
+ struct thread1 thread1;
+ struct thread2 thread2;
+ struct thread3 thread3;
+
+ struct {
+ unsigned int pad0:10;
+ unsigned int stats_enable:1;
+ unsigned int nr_urb_entries:7;
+ unsigned int pad1:1;
+ unsigned int urb_entry_allocation_size:5;
+ unsigned int pad2:1;
+ unsigned int max_threads:1;
+ unsigned int pad3:6;
+ } thread4;
+
+ struct {
+ unsigned int sampler_count:3;
+ unsigned int pad0:2;
+ unsigned int sampler_state_pointer:27;
+ } gs5;
+
+ struct {
+ unsigned int max_vp_index:4;
+ unsigned int pad0:26;
+ unsigned int reorder_enable:1;
+ unsigned int pad1:1;
+ } gs6;
+};
+
+struct brw_vs_unit_state {
+ struct thread0 thread0;
+ struct thread1 thread1;
+ struct thread2 thread2;
+ struct thread3 thread3;
+
+ struct {
+ unsigned int pad0:10;
+ unsigned int stats_enable:1;
+ unsigned int nr_urb_entries:7;
+ unsigned int pad1:1;
+ unsigned int urb_entry_allocation_size:5;
+ unsigned int pad2:1;
+ unsigned int max_threads:4;
+ unsigned int pad3:3;
+ } thread4;
+
+ struct {
+ unsigned int sampler_count:3;
+ unsigned int pad0:2;
+ unsigned int sampler_state_pointer:27;
+ } vs5;
+
+ struct {
+ unsigned int vs_enable:1;
+ unsigned int vert_cache_disable:1;
+ unsigned int pad0:30;
+ } vs6;
+};
+
+struct brw_wm_unit_state {
+ struct thread0 thread0;
+ struct thread1 thread1;
+ struct thread2 thread2;
+ struct thread3 thread3;
+
+ struct {
+ unsigned int stats_enable:1;
+ unsigned int pad0:1;
+ unsigned int sampler_count:3;
+ unsigned int sampler_state_pointer:27;
+ } wm4;
+
+ struct {
+ unsigned int enable_8_pix:1;
+ unsigned int enable_16_pix:1;
+ unsigned int enable_32_pix:1;
+ unsigned int pad0:7;
+ unsigned int legacy_global_depth_bias:1;
+ unsigned int line_stipple:1;
+ unsigned int depth_offset:1;
+ unsigned int polygon_stipple:1;
+ unsigned int line_aa_region_width:2;
+ unsigned int line_endcap_aa_region_width:2;
+ unsigned int early_depth_test:1;
+ unsigned int thread_dispatch_enable:1;
+ unsigned int program_uses_depth:1;
+ unsigned int program_computes_depth:1;
+ unsigned int program_uses_killpixel:1;
+ unsigned int legacy_line_rast: 1;
+ unsigned int transposed_urb_read:1;
+ unsigned int max_threads:7;
+ } wm5;
+
+ float global_depth_offset_constant;
+ float global_depth_offset_scale;
+};
+
+/* The hardware supports two different modes for border color. The
+ * default (OpenGL) mode uses floating-point color channels, while the
+ * legacy mode uses 4 bytes.
+ *
+ * More significantly, the legacy mode respects the components of the
+ * border color for channels not present in the source, (whereas the
+ * default mode will ignore the border color's alpha channel and use
+ * alpha==1 for an RGB source, for example).
+ *
+ * The legacy mode matches the semantics specified by the Render
+ * extension.
+ */
+struct brw_sampler_default_border_color {
+ float color[4];
+};
+
+struct brw_sampler_legacy_border_color {
+ uint8_t color[4];
+};
+
+struct brw_sampler_state {
+ struct {
+ unsigned int shadow_function:3;
+ unsigned int lod_bias:11;
+ unsigned int min_filter:3;
+ unsigned int mag_filter:3;
+ unsigned int mip_filter:2;
+ unsigned int base_level:5;
+ unsigned int pad:1;
+ unsigned int lod_preclamp:1;
+ unsigned int border_color_mode:1;
+ unsigned int pad0:1;
+ unsigned int disable:1;
+ } ss0;
+
+ struct {
+ unsigned int r_wrap_mode:3;
+ unsigned int t_wrap_mode:3;
+ unsigned int s_wrap_mode:3;
+ unsigned int pad:3;
+ unsigned int max_lod:10;
+ unsigned int min_lod:10;
+ } ss1;
+
+ struct {
+ unsigned int pad:5;
+ unsigned int border_color_pointer:27;
+ } ss2;
+
+ struct {
+ unsigned int pad:19;
+ unsigned int max_aniso:3;
+ unsigned int chroma_key_mode:1;
+ unsigned int chroma_key_index:2;
+ unsigned int chroma_key_enable:1;
+ unsigned int monochrome_filter_width:3;
+ unsigned int monochrome_filter_height:3;
+ } ss3;
+};
+
+struct brw_clipper_viewport {
+ float xmin;
+ float xmax;
+ float ymin;
+ float ymax;
+};
+
+struct brw_cc_viewport {
+ float min_depth;
+ float max_depth;
+};
+
+struct brw_sf_viewport {
+ struct {
+ float m00;
+ float m11;
+ float m22;
+ float m30;
+ float m31;
+ float m32;
+ } viewport;
+
+ struct {
+ short xmin;
+ short ymin;
+ short xmax;
+ short ymax;
+ } scissor;
+};
+
+/* Documented in the subsystem/shared-functions/sampler chapter...
+*/
+struct brw_surface_state {
+ struct {
+ unsigned int cube_pos_z:1;
+ unsigned int cube_neg_z:1;
+ unsigned int cube_pos_y:1;
+ unsigned int cube_neg_y:1;
+ unsigned int cube_pos_x:1;
+ unsigned int cube_neg_x:1;
+ unsigned int pad:3;
+ unsigned int render_cache_read_mode:1;
+ unsigned int mipmap_layout_mode:1;
+ unsigned int vert_line_stride_ofs:1;
+ unsigned int vert_line_stride:1;
+ unsigned int color_blend:1;
+ unsigned int writedisable_blue:1;
+ unsigned int writedisable_green:1;
+ unsigned int writedisable_red:1;
+ unsigned int writedisable_alpha:1;
+ unsigned int surface_format:9;
+ unsigned int data_return_format:1;
+ unsigned int pad0:1;
+ unsigned int surface_type:3;
+ } ss0;
+
+ struct {
+ unsigned int base_addr;
+ } ss1;
+
+ struct {
+ unsigned int render_target_rotation:2;
+ unsigned int mip_count:4;
+ unsigned int width:13;
+ unsigned int height:13;
+ } ss2;
+
+ struct {
+ unsigned int tile_walk:1;
+ unsigned int tiled_surface:1;
+ unsigned int pad:1;
+ unsigned int pitch:18;
+ unsigned int depth:11;
+ } ss3;
+
+ struct {
+ unsigned int pad:19;
+ unsigned int min_array_elt:9;
+ unsigned int min_lod:4;
+ } ss4;
+
+ struct {
+ unsigned int pad:20;
+ unsigned int y_offset:4;
+ unsigned int pad2:1;
+ unsigned int x_offset:7;
+ } ss5;
+};
+
+struct brw_vertex_buffer_state {
+ struct {
+ unsigned int pitch:11;
+ unsigned int pad:15;
+ unsigned int access_type:1;
+ unsigned int vb_index:5;
+ } vb0;
+
+ unsigned int start_addr;
+ unsigned int max_index;
+#if 1
+ unsigned int instance_data_step_rate; /* not included for sequential/random vertices? */
+#endif
+};
+
+#define BRW_VBP_MAX 17
+
+struct brw_vb_array_state {
+ struct header header;
+ struct brw_vertex_buffer_state vb[BRW_VBP_MAX];
+};
+
+struct brw_vertex_element_state {
+ struct {
+ unsigned int src_offset:11;
+ unsigned int pad:5;
+ unsigned int src_format:9;
+ unsigned int pad0:1;
+ unsigned int valid:1;
+ unsigned int vertex_buffer_index:5;
+ } ve0;
+
+ struct {
+ unsigned int dst_offset:8;
+ unsigned int pad:8;
+ unsigned int vfcomponent3:4;
+ unsigned int vfcomponent2:4;
+ unsigned int vfcomponent1:4;
+ unsigned int vfcomponent0:4;
+ } ve1;
+};
+
+#define BRW_VEP_MAX 18
+
+struct brw_vertex_element_packet {
+ struct header header;
+ struct brw_vertex_element_state ve[BRW_VEP_MAX];
+};
+
+struct brw_urb_immediate {
+ unsigned int opcode:4;
+ unsigned int offset:6;
+ unsigned int swizzle_control:2;
+ unsigned int pad:1;
+ unsigned int allocate:1;
+ unsigned int used:1;
+ unsigned int complete:1;
+ unsigned int response_length:4;
+ unsigned int msg_length:4;
+ unsigned int msg_target:4;
+ unsigned int pad1:3;
+ unsigned int end_of_thread:1;
+};
+
+/* Instruction format for the execution units: */
+
+struct brw_instruction {
+ struct {
+ unsigned int opcode:7;
+ unsigned int pad:1;
+ unsigned int access_mode:1;
+ unsigned int mask_control:1;
+ unsigned int dependency_control:2;
+ unsigned int compression_control:2;
+ unsigned int thread_control:2;
+ unsigned int predicate_control:4;
+ unsigned int predicate_inverse:1;
+ unsigned int execution_size:3;
+ unsigned int destreg__conditonalmod:4; /* destreg - send, conditionalmod - others */
+ unsigned int pad0:2;
+ unsigned int debug_control:1;
+ unsigned int saturate:1;
+ } header;
+
+ union {
+ struct {
+ unsigned int dest_reg_file:2;
+ unsigned int dest_reg_type:3;
+ unsigned int src0_reg_file:2;
+ unsigned int src0_reg_type:3;
+ unsigned int src1_reg_file:2;
+ unsigned int src1_reg_type:3;
+ unsigned int pad:1;
+ unsigned int dest_subreg_nr:5;
+ unsigned int dest_reg_nr:8;
+ unsigned int dest_horiz_stride:2;
+ unsigned int dest_address_mode:1;
+ } da1;
+
+ struct {
+ unsigned int dest_reg_file:2;
+ unsigned int dest_reg_type:3;
+ unsigned int src0_reg_file:2;
+ unsigned int src0_reg_type:3;
+ unsigned int pad:6;
+ int dest_indirect_offset:10; /* offset against the deref'd address reg */
+ unsigned int dest_subreg_nr:3; /* subnr for the address reg a0.x */
+ unsigned int dest_horiz_stride:2;
+ unsigned int dest_address_mode:1;
+ } ia1;
+
+ struct {
+ unsigned int dest_reg_file:2;
+ unsigned int dest_reg_type:3;
+ unsigned int src0_reg_file:2;
+ unsigned int src0_reg_type:3;
+ unsigned int src1_reg_file:2;
+ unsigned int src1_reg_type:3;
+ unsigned int pad0:1;
+ unsigned int dest_writemask:4;
+ unsigned int dest_subreg_nr:1;
+ unsigned int dest_reg_nr:8;
+ unsigned int pad1:2;
+ unsigned int dest_address_mode:1;
+ } da16;
+
+ struct {
+ unsigned int dest_reg_file:2;
+ unsigned int dest_reg_type:3;
+ unsigned int src0_reg_file:2;
+ unsigned int src0_reg_type:3;
+ unsigned int pad0:6;
+ unsigned int dest_writemask:4;
+ int dest_indirect_offset:6;
+ unsigned int dest_subreg_nr:3;
+ unsigned int pad1:2;
+ unsigned int dest_address_mode:1;
+ } ia16;
+ } bits1;
+
+
+ union {
+ struct {
+ unsigned int src0_subreg_nr:5;
+ unsigned int src0_reg_nr:8;
+ unsigned int src0_abs:1;
+ unsigned int src0_negate:1;
+ unsigned int src0_address_mode:1;
+ unsigned int src0_horiz_stride:2;
+ unsigned int src0_width:3;
+ unsigned int src0_vert_stride:4;
+ unsigned int flag_reg_nr:1;
+ unsigned int pad:6;
+ } da1;
+
+ struct {
+ int src0_indirect_offset:10;
+ unsigned int src0_subreg_nr:3;
+ unsigned int src0_abs:1;
+ unsigned int src0_negate:1;
+ unsigned int src0_address_mode:1;
+ unsigned int src0_horiz_stride:2;
+ unsigned int src0_width:3;
+ unsigned int src0_vert_stride:4;
+ unsigned int flag_reg_nr:1;
+ unsigned int pad:6;
+ } ia1;
+
+ struct {
+ unsigned int src0_swz_x:2;
+ unsigned int src0_swz_y:2;
+ unsigned int src0_subreg_nr:1;
+ unsigned int src0_reg_nr:8;
+ unsigned int src0_abs:1;
+ unsigned int src0_negate:1;
+ unsigned int src0_address_mode:1;
+ unsigned int src0_swz_z:2;
+ unsigned int src0_swz_w:2;
+ unsigned int pad0:1;
+ unsigned int src0_vert_stride:4;
+ unsigned int flag_reg_nr:1;
+ unsigned int pad1:6;
+ } da16;
+
+ struct {
+ unsigned int src0_swz_x:2;
+ unsigned int src0_swz_y:2;
+ int src0_indirect_offset:6;
+ unsigned int src0_subreg_nr:3;
+ unsigned int src0_abs:1;
+ unsigned int src0_negate:1;
+ unsigned int src0_address_mode:1;
+ unsigned int src0_swz_z:2;
+ unsigned int src0_swz_w:2;
+ unsigned int pad0:1;
+ unsigned int src0_vert_stride:4;
+ unsigned int flag_reg_nr:1;
+ unsigned int pad1:6;
+ } ia16;
+
+ } bits2;
+
+ union {
+ struct {
+ unsigned int src1_subreg_nr:5;
+ unsigned int src1_reg_nr:8;
+ unsigned int src1_abs:1;
+ unsigned int src1_negate:1;
+ unsigned int pad:1;
+ unsigned int src1_horiz_stride:2;
+ unsigned int src1_width:3;
+ unsigned int src1_vert_stride:4;
+ unsigned int pad0:7;
+ } da1;
+
+ struct {
+ unsigned int src1_swz_x:2;
+ unsigned int src1_swz_y:2;
+ unsigned int src1_subreg_nr:1;
+ unsigned int src1_reg_nr:8;
+ unsigned int src1_abs:1;
+ unsigned int src1_negate:1;
+ unsigned int pad0:1;
+ unsigned int src1_swz_z:2;
+ unsigned int src1_swz_w:2;
+ unsigned int pad1:1;
+ unsigned int src1_vert_stride:4;
+ unsigned int pad2:7;
+ } da16;
+
+ struct {
+ int src1_indirect_offset:10;
+ unsigned int src1_subreg_nr:3;
+ unsigned int src1_abs:1;
+ unsigned int src1_negate:1;
+ unsigned int pad0:1;
+ unsigned int src1_horiz_stride:2;
+ unsigned int src1_width:3;
+ unsigned int src1_vert_stride:4;
+ unsigned int flag_reg_nr:1;
+ unsigned int pad1:6;
+ } ia1;
+
+ struct {
+ unsigned int src1_swz_x:2;
+ unsigned int src1_swz_y:2;
+ int src1_indirect_offset:6;
+ unsigned int src1_subreg_nr:3;
+ unsigned int src1_abs:1;
+ unsigned int src1_negate:1;
+ unsigned int pad0:1;
+ unsigned int src1_swz_z:2;
+ unsigned int src1_swz_w:2;
+ unsigned int pad1:1;
+ unsigned int src1_vert_stride:4;
+ unsigned int flag_reg_nr:1;
+ unsigned int pad2:6;
+ } ia16;
+
+ struct {
+ int jump_count:16; /* note: signed */
+ unsigned int pop_count:4;
+ unsigned int pad0:12;
+ } if_else;
+
+ struct {
+ unsigned int function:4;
+ unsigned int int_type:1;
+ unsigned int precision:1;
+ unsigned int saturate:1;
+ unsigned int data_type:1;
+ unsigned int pad0:8;
+ unsigned int response_length:4;
+ unsigned int msg_length:4;
+ unsigned int msg_target:4;
+ unsigned int pad1:3;
+ unsigned int end_of_thread:1;
+ } math;
+
+ struct {
+ unsigned int binding_table_index:8;
+ unsigned int sampler:4;
+ unsigned int return_format:2;
+ unsigned int msg_type:2;
+ unsigned int response_length:4;
+ unsigned int msg_length:4;
+ unsigned int msg_target:4;
+ unsigned int pad1:3;
+ unsigned int end_of_thread:1;
+ } sampler;
+
+ struct {
+ uint32_t binding_table_index:8;
+ uint32_t sampler:4;
+ uint32_t msg_type:4;
+ uint32_t response_length:4;
+ uint32_t msg_length:4;
+ uint32_t msg_target:4;
+ uint32_t pad1:3;
+ uint32_t end_of_thread:1;
+ } sampler_g4x;
+
+ struct brw_urb_immediate urb;
+
+ struct {
+ unsigned int binding_table_index:8;
+ unsigned int msg_control:4;
+ unsigned int msg_type:2;
+ unsigned int target_cache:2;
+ unsigned int response_length:4;
+ unsigned int msg_length:4;
+ unsigned int msg_target:4;
+ unsigned int pad1:3;
+ unsigned int end_of_thread:1;
+ } dp_read;
+
+ struct {
+ unsigned int binding_table_index:8;
+ unsigned int msg_control:3;
+ unsigned int pixel_scoreboard_clear:1;
+ unsigned int msg_type:3;
+ unsigned int send_commit_msg:1;
+ unsigned int response_length:4;
+ unsigned int msg_length:4;
+ unsigned int msg_target:4;
+ unsigned int pad1:3;
+ unsigned int end_of_thread:1;
+ } dp_write;
+
+ struct {
+ unsigned int pad:16;
+ unsigned int response_length:4;
+ unsigned int msg_length:4;
+ unsigned int msg_target:4;
+ unsigned int pad1:3;
+ unsigned int end_of_thread:1;
+ } generic;
+
+ uint32_t ud;
+ int32_t d;
+ } bits3;
+};
+
+/* media pipeline */
+
+struct brw_vfe_state {
+ struct {
+ unsigned int per_thread_scratch_space:4;
+ unsigned int pad3:3;
+ unsigned int extend_vfe_state_present:1;
+ unsigned int pad2:2;
+ unsigned int scratch_base:22;
+ } vfe0;
+
+ struct {
+ unsigned int debug_counter_control:2;
+ unsigned int children_present:1;
+ unsigned int vfe_mode:4;
+ unsigned int pad2:2;
+ unsigned int num_urb_entries:7;
+ unsigned int urb_entry_alloc_size:9;
+ unsigned int max_threads:7;
+ } vfe1;
+
+ struct {
+ unsigned int pad4:4;
+ unsigned int interface_descriptor_base:28;
+ } vfe2;
+};
+
+struct brw_vld_state {
+ struct {
+ unsigned int pad6:6;
+ unsigned int scan_order:1;
+ unsigned int intra_vlc_format:1;
+ unsigned int quantizer_scale_type:1;
+ unsigned int concealment_motion_vector:1;
+ unsigned int frame_predict_frame_dct:1;
+ unsigned int top_field_first:1;
+ unsigned int picture_structure:2;
+ unsigned int intra_dc_precision:2;
+ unsigned int f_code_0_0:4;
+ unsigned int f_code_0_1:4;
+ unsigned int f_code_1_0:4;
+ unsigned int f_code_1_1:4;
+ } vld0;
+
+ struct {
+ unsigned int pad2:9;
+ unsigned int picture_coding_type:2;
+ unsigned int pad:21;
+ } vld1;
+
+ struct {
+ unsigned int index_0:4;
+ unsigned int index_1:4;
+ unsigned int index_2:4;
+ unsigned int index_3:4;
+ unsigned int index_4:4;
+ unsigned int index_5:4;
+ unsigned int index_6:4;
+ unsigned int index_7:4;
+ } desc_remap_table0;
+
+ struct {
+ unsigned int index_8:4;
+ unsigned int index_9:4;
+ unsigned int index_10:4;
+ unsigned int index_11:4;
+ unsigned int index_12:4;
+ unsigned int index_13:4;
+ unsigned int index_14:4;
+ unsigned int index_15:4;
+ } desc_remap_table1;
+};
+
+struct brw_interface_descriptor {
+ struct {
+ unsigned int grf_reg_blocks:4;
+ unsigned int pad:2;
+ unsigned int kernel_start_pointer:26;
+ } desc0;
+
+ struct {
+ unsigned int pad:7;
+ unsigned int software_exception:1;
+ unsigned int pad2:3;
+ unsigned int maskstack_exception:1;
+ unsigned int pad3:1;
+ unsigned int illegal_opcode_exception:1;
+ unsigned int pad4:2;
+ unsigned int floating_point_mode:1;
+ unsigned int thread_priority:1;
+ unsigned int single_program_flow:1;
+ unsigned int pad5:1;
+ unsigned int const_urb_entry_read_offset:6;
+ unsigned int const_urb_entry_read_len:6;
+ } desc1;
+
+ struct {
+ unsigned int pad:2;
+ unsigned int sampler_count:3;
+ unsigned int sampler_state_pointer:27;
+ } desc2;
+
+ struct {
+ unsigned int binding_table_entry_count:5;
+ unsigned int binding_table_pointer:27;
+ } desc3;
+};
+
+#endif
diff --git a/src/drm/cairo-drm-intel-command-private.h b/src/drm/cairo-drm-intel-command-private.h
new file mode 100644
index 0000000..3860c3f
--- /dev/null
+++ b/src/drm/cairo-drm-intel-command-private.h
@@ -0,0 +1,909 @@
+/**************************************************************************
+ *
+ * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+#ifndef CAIRO_DRM_INTEL_COMMAND_PRIVATE_H
+#define CAIRO_DRM_INTEL_COMMAND_PRIVATE_H
+
+#include "cairo-types-private.h"
+
+#define CMD_MI (0x0 << 29)
+#define CMD_misc (0x1 << 29)
+#define CMD_2D (0x2 << 29)
+#define CMD_3D (0x3 << 29)
+/* 4-7 reserved */
+
+#define MI_NOOP (CMD_MI | 0)
+/* Batch */
+#define MI_BATCH_BUFFER (CMD_MI | (0x30 << 23) | 1)
+#define MI_BATCH_BUFFER_START (CMD_MI | (0x31 << 23))
+#define MI_BATCH_BUFFER_END (CMD_MI | (0x0a << 23))
+#define MI_BATCH_NON_SECURE (1)
+#define MI_BATCH_NON_SECURE_I965 (1 << 8)
+/* Flush */
+#define MI_FLUSH (CMD_MI | (0x04 << 23))
+#define MI_WRITE_DIRTY_STATE (1<<4)
+#define MI_END_SCENE (1<<3)
+#define MI_GLOBAL_SNAPSHOT_COUNT_RESET (1<<3)
+#define MI_INHIBIT_RENDER_CACHE_FLUSH (1<<2)
+#define MI_STATE_INSTRUCTION_CACHE_FLUSH (1<<1)
+#define MI_INVALIDATE_MAP_CACHE (1<<0)
+
+#define PRIM3D (CMD_3D | (0x1f<<24))
+#define PRIM3D_TRILIST (PRIM3D | (0x0<<18))
+#define PRIM3D_TRISTRIP (PRIM3D | (0x1<<18))
+#define PRIM3D_TRISTRIP_RVRSE (PRIM3D | (0x2<<18))
+#define PRIM3D_TRIFAN (PRIM3D | (0x3<<18))
+#define PRIM3D_POLY (PRIM3D | (0x4<<18))
+#define PRIM3D_LINELIST (PRIM3D | (0x5<<18))
+#define PRIM3D_LINESTRIP (PRIM3D | (0x6<<18))
+#define PRIM3D_RECTLIST (PRIM3D | (0x7<<18))
+#define PRIM3D_POINTLIST (PRIM3D | (0x8<<18))
+#define PRIM3D_DIB (PRIM3D | (0x9<<18))
+#define PRIM3D_CLEAR_RECT (PRIM3D | (0xa<<18))
+#define PRIM3D_ZONE_INIT (PRIM3D | (0xd<<18))
+#define PRIM3D_MASK (0x1f<<18)
+#define PRIM3D_INDIRECT_SEQUENTIAL ((1<<23) | (0<<17))
+#define PRIM3D_INDIRECT_ELTS ((1<<23) | (1<<17))
+
+/* p137 */
+#define _3DSTATE_AA_CMD (CMD_3D | (0x06<<24))
+#define AA_LINE_ECAAR_WIDTH_ENABLE (1<<16)
+#define AA_LINE_ECAAR_WIDTH_0_5 0
+#define AA_LINE_ECAAR_WIDTH_1_0 (1<<14)
+#define AA_LINE_ECAAR_WIDTH_2_0 (2<<14)
+#define AA_LINE_ECAAR_WIDTH_4_0 (3<<14)
+#define AA_LINE_REGION_WIDTH_ENABLE (1<<8)
+#define AA_LINE_REGION_WIDTH_0_5 0
+#define AA_LINE_REGION_WIDTH_1_0 (1<<6)
+#define AA_LINE_REGION_WIDTH_2_0 (2<<6)
+#define AA_LINE_REGION_WIDTH_4_0 (3<<6)
+
+/* 3DSTATE_BACKFACE_STENCIL_OPS, p138*/
+#define _3DSTATE_BACKFACE_STENCIL_OPS (CMD_3D | (0x8<<24))
+#define BFO_ENABLE_STENCIL_REF (1<<23)
+#define BFO_STENCIL_REF_SHIFT 15
+#define BFO_STENCIL_REF_MASK (0xff<<15)
+#define BFO_ENABLE_STENCIL_FUNCS (1<<14)
+#define BFO_STENCIL_TEST_SHIFT 11
+#define BFO_STENCIL_TEST_MASK (0x7<<11)
+#define BFO_STENCIL_FAIL_SHIFT 8
+#define BFO_STENCIL_FAIL_MASK (0x7<<8)
+#define BFO_STENCIL_PASS_Z_FAIL_SHIFT 5
+#define BFO_STENCIL_PASS_Z_FAIL_MASK (0x7<<5)
+#define BFO_STENCIL_PASS_Z_PASS_SHIFT 2
+#define BFO_STENCIL_PASS_Z_PASS_MASK (0x7<<2)
+#define BFO_ENABLE_STENCIL_TWO_SIDE (1<<1)
+#define BFO_STENCIL_TWO_SIDE (1<<0)
+
+/* 3DSTATE_BACKFACE_STENCIL_MASKS, p140 */
+#define _3DSTATE_BACKFACE_STENCIL_MASKS (CMD_3D | (0x9<<24))
+#define BFM_ENABLE_STENCIL_TEST_MASK (1<<17)
+#define BFM_ENABLE_STENCIL_WRITE_MASK (1<<16)
+#define BFM_STENCIL_TEST_MASK_SHIFT 8
+#define BFM_STENCIL_TEST_MASK_MASK (0xff<<8)
+#define BFM_STENCIL_WRITE_MASK_SHIFT 0
+#define BFM_STENCIL_WRITE_MASK_MASK (0xff<<0)
+
+/* 3DSTATE_BIN_CONTROL p141 */
+
+/* p143 */
+#define _3DSTATE_BUF_INFO_CMD (CMD_3D | (0x1d<<24) | (0x8e<<16) | 1)
+/* Dword 1 */
+#define BUF_3D_ID_COLOR_BACK (0x3<<24)
+#define BUF_3D_ID_DEPTH (0x7<<24)
+#define BUF_3D_USE_FENCE (1<<23)
+#define BUF_3D_TILED_SURFACE (1<<22)
+#define BUF_3D_TILE_WALK_X 0
+#define BUF_3D_TILE_WALK_Y (1<<21)
+#define BUF_3D_PITCH(x) (x)
+/* Dword 2 */
+#define BUF_3D_ADDR(x) ((x) & ~0x3)
+
+/* 3DSTATE_CHROMA_KEY */
+
+/* 3DSTATE_CLEAR_PARAMETERS, p150 */
+#define _3DSTATE_CLEAR_PARAMETERS (CMD_3D | (0x1d<<24) | (0x9c<<16) | 5)
+/* Dword 1 */
+#define CLEARPARAM_CLEAR_RECT (1 << 16)
+#define CLEARPARAM_ZONE_INIT (0 << 16)
+#define CLEARPARAM_WRITE_COLOR (1 << 2)
+#define CLEARPARAM_WRITE_DEPTH (1 << 1)
+#define CLEARPARAM_WRITE_STENCIL (1 << 0)
+
+/* 3DSTATE_CONSTANT_BLEND_COLOR, p153 */
+#define _3DSTATE_CONST_BLEND_COLOR_CMD (CMD_3D | (0x1d<<24) | (0x88<<16))
+
+/* 3DSTATE_COORD_SET_BINDINGS, p154 */
+#define _3DSTATE_COORD_SET_BINDINGS (CMD_3D | (0x16<<24))
+#define CSB_TCB(iunit, eunit) ((eunit)<<(iunit*3))
+
+/* p156 */
+#define _3DSTATE_DFLT_DIFFUSE_CMD (CMD_3D | (0x1d<<24) | (0x99<<16))
+
+/* p157 */
+#define _3DSTATE_DFLT_SPEC_CMD (CMD_3D | (0x1d<<24) | (0x9a<<16))
+
+/* p158 */
+#define _3DSTATE_DFLT_Z_CMD (CMD_3D | (0x1d<<24) | (0x98<<16))
+
+/* 3DSTATE_DEPTH_OFFSET_SCALE, p159 */
+#define _3DSTATE_DEPTH_OFFSET_SCALE (CMD_3D | (0x1d<<24) | (0x97<<16))
+/* scale in dword 1 */
+
+/* The depth subrectangle is not supported, but must be disabled. */
+/* 3DSTATE_DEPTH_SUBRECT_DISABLE, p160 */
+#define _3DSTATE_DEPTH_SUBRECT_DISABLE (CMD_3D | (0x1c<<24) | (0x11<<19) | (1 << 1) | (0 << 0))
+
+/* p161 */
+#define _3DSTATE_DST_BUF_VARS_CMD (CMD_3D | (0x1d<<24) | (0x85<<16))
+/* Dword 1 */
+#define TEX_DEFAULT_COLOR_OGL (0<<30)
+#define TEX_DEFAULT_COLOR_D3D (1<<30)
+#define ZR_EARLY_DEPTH (1<<29)
+#define LOD_PRECLAMP_OGL (1<<28)
+#define LOD_PRECLAMP_D3D (0<<28)
+#define DITHER_FULL_ALWAYS (0<<26)
+#define DITHER_FULL_ON_FB_BLEND (1<<26)
+#define DITHER_CLAMPED_ALWAYS (2<<26)
+#define LINEAR_GAMMA_BLEND_32BPP (1<<25)
+#define DEBUG_DISABLE_ENH_DITHER (1<<24)
+#define DSTORG_HORT_BIAS(x) ((x)<<20)
+#define DSTORG_VERT_BIAS(x) ((x)<<16)
+#define COLOR_4_2_2_CHNL_WRT_ALL 0
+#define COLOR_4_2_2_CHNL_WRT_Y (1<<12)
+#define COLOR_4_2_2_CHNL_WRT_CR (2<<12)
+#define COLOR_4_2_2_CHNL_WRT_CB (3<<12)
+#define COLOR_4_2_2_CHNL_WRT_CRCB (4<<12)
+#define COLR_BUF_8BIT 0
+#define COLR_BUF_RGB555 (1<<8)
+#define COLR_BUF_RGB565 (2<<8)
+#define COLR_BUF_ARGB8888 (3<<8)
+#define COLR_BUF_ARGB4444 (8<<8)
+#define COLR_BUF_ARGB1555 (9<<8)
+#define COLR_BUF_ARGB2AAA (0xa<<8)
+#define DEPTH_FRMT_16_FIXED 0
+#define DEPTH_FRMT_16_FLOAT (1<<2)
+#define DEPTH_FRMT_24_FIXED_8_OTHER (2<<2)
+#define VERT_LINE_STRIDE_1 (1<<1)
+#define VERT_LINE_STRIDE_0 (0<<1)
+#define VERT_LINE_STRIDE_OFS_1 1
+#define VERT_LINE_STRIDE_OFS_0 0
+
+/* p166 */
+#define _3DSTATE_DRAW_RECT_CMD (CMD_3D|(0x1d<<24)|(0x80<<16)|3)
+/* Dword 1 */
+#define DRAW_RECT_DIS_DEPTH_OFS (1<<30)
+#define DRAW_DITHER_OFS_X(x) ((x)<<26)
+#define DRAW_DITHER_OFS_Y(x) ((x)<<24)
+/* Dword 2 */
+#define DRAW_YMIN(x) ((x)<<16)
+#define DRAW_XMIN(x) (x)
+/* Dword 3 */
+#define DRAW_YMAX(x) ((x)<<16)
+#define DRAW_XMAX(x) (x)
+/* Dword 4 */
+#define DRAW_YORG(x) ((x)<<16)
+#define DRAW_XORG(x) (x)
+
+/* 3DSTATE_FILTER_COEFFICIENTS_4X4, p170 */
+
+/* 3DSTATE_FILTER_COEFFICIENTS_6X5, p172 */
+
+/* _3DSTATE_FOG_COLOR, p173 */
+#define _3DSTATE_FOG_COLOR_CMD (CMD_3D|(0x15<<24))
+#define FOG_COLOR_RED(x) ((x)<<16)
+#define FOG_COLOR_GREEN(x) ((x)<<8)
+#define FOG_COLOR_BLUE(x) (x)
+
+/* _3DSTATE_FOG_MODE, p174 */
+#define _3DSTATE_FOG_MODE_CMD (CMD_3D|(0x1d<<24)|(0x89<<16)|2)
+/* Dword 1 */
+#define FMC1_FOGFUNC_MODIFY_ENABLE (1<<31)
+#define FMC1_FOGFUNC_VERTEX (0<<28)
+#define FMC1_FOGFUNC_PIXEL_EXP (1<<28)
+#define FMC1_FOGFUNC_PIXEL_EXP2 (2<<28)
+#define FMC1_FOGFUNC_PIXEL_LINEAR (3<<28)
+#define FMC1_FOGFUNC_MASK (3<<28)
+#define FMC1_FOGINDEX_MODIFY_ENABLE (1<<27)
+#define FMC1_FOGINDEX_Z (0<<25)
+#define FMC1_FOGINDEX_W (1<<25)
+#define FMC1_C1_C2_MODIFY_ENABLE (1<<24)
+#define FMC1_DENSITY_MODIFY_ENABLE (1<<23)
+#define FMC1_C1_ONE (1<<13)
+#define FMC1_C1_MASK (0xffff<<4)
+/* Dword 2 */
+#define FMC2_C2_ONE (1<<16)
+/* Dword 3 */
+#define FMC3_D_ONE (1<<16)
+
+/* _3DSTATE_INDEPENDENT_ALPHA_BLEND, p177 */
+#define _3DSTATE_INDEPENDENT_ALPHA_BLEND_CMD (CMD_3D|(0x0b<<24))
+#define IAB_MODIFY_ENABLE (1<<23)
+#define IAB_ENABLE (1<<22)
+#define IAB_MODIFY_FUNC (1<<21)
+#define IAB_FUNC_SHIFT 16
+#define IAB_MODIFY_SRC_FACTOR (1<<11)
+#define IAB_SRC_FACTOR_SHIFT 6
+#define IAB_SRC_FACTOR_MASK (BLENDFACT_MASK<<6)
+#define IAB_MODIFY_DST_FACTOR (1<<5)
+#define IAB_DST_FACTOR_SHIFT 0
+#define IAB_DST_FACTOR_MASK (BLENDFACT_MASK<<0)
+
+#define BLENDFACT_ZERO 0x01
+#define BLENDFACT_ONE 0x02
+#define BLENDFACT_SRC_COLR 0x03
+#define BLENDFACT_INV_SRC_COLR 0x04
+#define BLENDFACT_SRC_ALPHA 0x05
+#define BLENDFACT_INV_SRC_ALPHA 0x06
+#define BLENDFACT_DST_ALPHA 0x07
+#define BLENDFACT_INV_DST_ALPHA 0x08
+#define BLENDFACT_DST_COLR 0x09
+#define BLENDFACT_INV_DST_COLR 0x0a
+#define BLENDFACT_SRC_ALPHA_SATURATE 0x0b
+#define BLENDFACT_CONST_COLOR 0x0c
+#define BLENDFACT_INV_CONST_COLOR 0x0d
+#define BLENDFACT_CONST_ALPHA 0x0e
+#define BLENDFACT_INV_CONST_ALPHA 0x0f
+#define BLENDFACT_MASK 0x0f
+
+#define BLENDFUNC_ADD 0x0
+#define BLENDFUNC_SUBTRACT 0x1
+#define BLENDFUNC_REVERSE_SUBTRACT 0x2
+#define BLENDFUNC_MIN 0x3
+#define BLENDFUNC_MAX 0x4
+#define BLENDFUNC_MASK 0x7
+
+/* 3DSTATE_LOAD_INDIRECT, p180 */
+
+#define _3DSTATE_LOAD_INDIRECT (CMD_3D|(0x1d<<24)|(0x7<<16))
+#define LI0_STATE_STATIC_INDIRECT (0x01<<8)
+#define LI0_STATE_DYNAMIC_INDIRECT (0x02<<8)
+#define LI0_STATE_SAMPLER (0x04<<8)
+#define LI0_STATE_MAP (0x08<<8)
+#define LI0_STATE_PROGRAM (0x10<<8)
+#define LI0_STATE_CONSTANTS (0x20<<8)
+
+#define SIS0_BUFFER_ADDRESS(x) ((x)&~0x3)
+#define SIS0_FORCE_LOAD (1<<1)
+#define SIS0_BUFFER_VALID (1<<0)
+#define SIS1_BUFFER_LENGTH(x) ((x)&0xff)
+
+#define DIS0_BUFFER_ADDRESS(x) ((x)&~0x3)
+#define DIS0_BUFFER_RESET (1<<1)
+#define DIS0_BUFFER_VALID (1<<0)
+
+#define SSB0_BUFFER_ADDRESS(x) ((x)&~0x3)
+#define SSB0_FORCE_LOAD (1<<1)
+#define SSB0_BUFFER_VALID (1<<0)
+#define SSB1_BUFFER_LENGTH(x) ((x)&0xff)
+
+#define MSB0_BUFFER_ADDRESS(x) ((x)&~0x3)
+#define MSB0_FORCE_LOAD (1<<1)
+#define MSB0_BUFFER_VALID (1<<0)
+#define MSB1_BUFFER_LENGTH(x) ((x)&0xff)
+
+#define PSP0_BUFFER_ADDRESS(x) ((x)&~0x3)
+#define PSP0_FORCE_LOAD (1<<1)
+#define PSP0_BUFFER_VALID (1<<0)
+#define PSP1_BUFFER_LENGTH(x) ((x)&0xff)
+
+#define PSC0_BUFFER_ADDRESS(x) ((x)&~0x3)
+#define PSC0_FORCE_LOAD (1<<1)
+#define PSC0_BUFFER_VALID (1<<0)
+#define PSC1_BUFFER_LENGTH(x) ((x)&0xff)
+
+/* _3DSTATE_RASTERIZATION_RULES */
+#define _3DSTATE_RASTER_RULES_CMD (CMD_3D|(0x07<<24))
+#define ENABLE_POINT_RASTER_RULE (1<<15)
+#define OGL_POINT_RASTER_RULE (1<<13)
+#define ENABLE_TEXKILL_3D_4D (1<<10)
+#define TEXKILL_3D (0<<9)
+#define TEXKILL_4D (1<<9)
+#define ENABLE_LINE_STRIP_PROVOKE_VRTX (1<<8)
+#define ENABLE_TRI_FAN_PROVOKE_VRTX (1<<5)
+#define LINE_STRIP_PROVOKE_VRTX(x) ((x)<<6)
+#define TRI_FAN_PROVOKE_VRTX(x) ((x)<<3)
+
+/* _3DSTATE_SCISSOR_ENABLE, p256 */
+#define _3DSTATE_SCISSOR_ENABLE_CMD (CMD_3D|(0x1c<<24)|(0x10<<19))
+#define ENABLE_SCISSOR_RECT ((1<<1) | 1)
+#define DISABLE_SCISSOR_RECT (1<<1)
+
+/* _3DSTATE_SCISSOR_RECTANGLE_0, p257 */
+#define _3DSTATE_SCISSOR_RECT_0_CMD (CMD_3D|(0x1d<<24)|(0x81<<16)|1)
+/* Dword 1 */
+#define SCISSOR_RECT_0_YMIN(x) ((x)<<16)
+#define SCISSOR_RECT_0_XMIN(x) (x)
+/* Dword 2 */
+#define SCISSOR_RECT_0_YMAX(x) ((x)<<16)
+#define SCISSOR_RECT_0_XMAX(x) (x)
+
+/* p189 */
+#define _3DSTATE_LOAD_STATE_IMMEDIATE_1 (CMD_3D | (0x1d<<24) | (0x04<<16))
+#define I1_LOAD_S(n) (1<<(4+n))
+
+#define S0_VB_OFFSET_MASK 0xffffffc
+#define S0_AUTO_CACHE_INV_DISABLE (1<<0)
+
+#define S1_VERTEX_WIDTH_SHIFT 24
+#define S1_VERTEX_WIDTH_MASK (0x3f<<24)
+#define S1_VERTEX_PITCH_SHIFT 16
+#define S1_VERTEX_PITCH_MASK (0x3f<<16)
+
+#define TEXCOORDFMT_2D 0x0
+#define TEXCOORDFMT_3D 0x1
+#define TEXCOORDFMT_4D 0x2
+#define TEXCOORDFMT_1D 0x3
+#define TEXCOORDFMT_2D_16 0x4
+#define TEXCOORDFMT_4D_16 0x5
+#define TEXCOORDFMT_NOT_PRESENT 0xf
+#define S2_TEXCOORD_FMT0_MASK 0xf
+#define S2_TEXCOORD_FMT1_SHIFT 4
+#define S2_TEXCOORD_FMT(unit, type) ((type)<<(unit*4))
+#define S2_TEXCOORD_NONE (~0U)
+
+#define TEXCOORD_WRAP_SHORTEST_TCX 8
+#define TEXCOORD_WRAP_SHORTEST_TCY 4
+#define TEXCOORD_WRAP_SHORTEST_TCZ 2
+#define TEXCOORD_PERSPECTIVE_DISABLE 1
+
+#define S3_WRAP_SHORTEST_TCX(unit) (TEXCOORD_WRAP_SHORTEST_TCX << ((unit) * 4))
+#define S3_WRAP_SHORTEST_TCY(unit) (TEXCOORD_WRAP_SHORTEST_TCY << ((unit) * 4))
+#define S3_WRAP_SHORTEST_TCZ(unit) (TEXCOORD_WRAP_SHORTEST_TCZ << ((unit) * 4))
+#define S3_PERSPECTIVE_DISABLE(unit) (TEXCOORD_PERSPECTIVE_DISABLE << ((unit) * 4))
+
+/* S3 not interesting */
+
+#define S4_POINT_WIDTH_SHIFT 23
+#define S4_POINT_WIDTH_MASK (0x1ff<<23)
+#define S4_LINE_WIDTH_SHIFT 19
+#define S4_LINE_WIDTH_ONE (0x2<<19)
+#define S4_LINE_WIDTH_MASK (0xf<<19)
+#define S4_FLATSHADE_ALPHA (1<<18)
+#define S4_FLATSHADE_FOG (1<<17)
+#define S4_FLATSHADE_SPECULAR (1<<16)
+#define S4_FLATSHADE_COLOR (1<<15)
+#define S4_CULLMODE_BOTH (0<<13)
+#define S4_CULLMODE_NONE (1<<13)
+#define S4_CULLMODE_CW (2<<13)
+#define S4_CULLMODE_CCW (3<<13)
+#define S4_CULLMODE_MASK (3<<13)
+#define S4_VFMT_POINT_WIDTH (1<<12)
+#define S4_VFMT_SPEC_FOG (1<<11)
+#define S4_VFMT_COLOR (1<<10)
+#define S4_VFMT_DEPTH_OFFSET (1<<9)
+#define S4_VFMT_XYZ (1<<6)
+#define S4_VFMT_XYZW (2<<6)
+#define S4_VFMT_XY (3<<6)
+#define S4_VFMT_XYW (4<<6)
+#define S4_VFMT_XYZW_MASK (7<<6)
+#define S4_FORCE_DEFAULT_DIFFUSE (1<<5)
+#define S4_FORCE_DEFAULT_SPECULAR (1<<4)
+#define S4_LOCAL_DEPTH_OFFSET_ENABLE (1<<3)
+#define S4_VFMT_FOG_PARAM (1<<2)
+#define S4_SPRITE_POINT_ENABLE (1<<1)
+#define S4_LINE_ANTIALIAS_ENABLE (1<<0)
+
+#define S4_VFMT_MASK (S4_VFMT_POINT_WIDTH | \
+ S4_VFMT_SPEC_FOG | \
+ S4_VFMT_COLOR | \
+ S4_VFMT_DEPTH_OFFSET | \
+ S4_VFMT_XYZW_MASK | \
+ S4_VFMT_FOG_PARAM)
+
+#define S5_WRITEDISABLE_ALPHA (1<<31)
+#define S5_WRITEDISABLE_RED (1<<30)
+#define S5_WRITEDISABLE_GREEN (1<<29)
+#define S5_WRITEDISABLE_BLUE (1<<28)
+#define S5_WRITEDISABLE_MASK (0xf<<28)
+#define S5_FORCE_DEFAULT_POINT_SIZE (1<<27)
+#define S5_LAST_PIXEL_ENABLE (1<<26)
+#define S5_GLOBAL_DEPTH_OFFSET_ENABLE (1<<25)
+#define S5_FOG_ENABLE (1<<24)
+#define S5_STENCIL_REF_SHIFT 16
+#define S5_STENCIL_REF_MASK (0xff<<16)
+#define S5_STENCIL_TEST_FUNC_SHIFT 13
+#define S5_STENCIL_TEST_FUNC_MASK (0x7<<13)
+#define S5_STENCIL_FAIL_SHIFT 10
+#define S5_STENCIL_FAIL_MASK (0x7<<10)
+#define S5_STENCIL_PASS_Z_FAIL_SHIFT 7
+#define S5_STENCIL_PASS_Z_FAIL_MASK (0x7<<7)
+#define S5_STENCIL_PASS_Z_PASS_SHIFT 4
+#define S5_STENCIL_PASS_Z_PASS_MASK (0x7<<4)
+#define S5_STENCIL_WRITE_ENABLE (1<<3)
+#define S5_STENCIL_TEST_ENABLE (1<<2)
+#define S5_COLOR_DITHER_ENABLE (1<<1)
+#define S5_LOGICOP_ENABLE (1<<0)
+
+#define COMPAREFUNC_ALWAYS 0
+#define COMPAREFUNC_NEVER 0x1
+#define COMPAREFUNC_LESS 0x2
+#define COMPAREFUNC_EQUAL 0x3
+#define COMPAREFUNC_LEQUAL 0x4
+#define COMPAREFUNC_GREATER 0x5
+#define COMPAREFUNC_NOTEQUAL 0x6
+#define COMPAREFUNC_GEQUAL 0x7
+
+#define STENCILOP_KEEP 0
+#define STENCILOP_ZERO 0x1
+#define STENCILOP_REPLACE 0x2
+#define STENCILOP_INCRSAT 0x3
+#define STENCILOP_DECRSAT 0x4
+#define STENCILOP_INCR 0x5
+#define STENCILOP_DECR 0x6
+#define STENCILOP_INVERT 0x7
+
+#define S6_ALPHA_TEST_ENABLE (1<<31)
+#define S6_ALPHA_TEST_FUNC_SHIFT 28
+#define S6_ALPHA_TEST_FUNC_MASK (0x7<<28)
+#define S6_ALPHA_REF_SHIFT 20
+#define S6_ALPHA_REF_MASK (0xff<<20)
+#define S6_DEPTH_TEST_ENABLE (1<<19)
+#define S6_DEPTH_TEST_FUNC_SHIFT 16
+#define S6_DEPTH_TEST_FUNC_MASK (0x7<<16)
+#define S6_CBUF_BLEND_ENABLE (1<<15)
+#define S6_CBUF_BLEND_FUNC_SHIFT 12
+#define S6_CBUF_BLEND_FUNC_MASK (0x7<<12)
+#define S6_CBUF_SRC_BLEND_FACT_SHIFT 8
+#define S6_CBUF_SRC_BLEND_FACT_MASK (0xf<<8)
+#define S6_CBUF_DST_BLEND_FACT_SHIFT 4
+#define S6_CBUF_DST_BLEND_FACT_MASK (0xf<<4)
+#define S6_DEPTH_WRITE_ENABLE (1<<3)
+#define S6_COLOR_WRITE_ENABLE (1<<2)
+#define S6_TRISTRIP_PV_SHIFT 0
+#define S6_TRISTRIP_PV_MASK (0x3<<0)
+
+#define S7_DEPTH_OFFSET_CONST_MASK ~0
+
+/* 3DSTATE_MAP_DEINTERLACER_PARAMETERS */
+/* 3DSTATE_MAP_PALETTE_LOAD_32, p206 */
+
+/* _3DSTATE_MODES_4, p218 */
+#define _3DSTATE_MODES_4_CMD (CMD_3D|(0x0d<<24))
+#define ENABLE_LOGIC_OP_FUNC (1<<23)
+#define LOGIC_OP_FUNC(x) ((x)<<18)
+#define LOGICOP_MASK (0xf<<18)
+#define LOGICOP_COPY 0xc
+#define MODE4_ENABLE_STENCIL_TEST_MASK ((1<<17)|(0xff00))
+#define ENABLE_STENCIL_TEST_MASK (1<<17)
+#define STENCIL_TEST_MASK(x) ((x)<<8)
+#define MODE4_ENABLE_STENCIL_WRITE_MASK ((1<<16)|(0x00ff))
+#define ENABLE_STENCIL_WRITE_MASK (1<<16)
+#define STENCIL_WRITE_MASK(x) ((x)&0xff)
+
+/* _3DSTATE_MODES_5, p220 */
+#define _3DSTATE_MODES_5_CMD (CMD_3D|(0x0c<<24))
+#define PIPELINE_FLUSH_RENDER_CACHE (1<<18)
+#define PIPELINE_FLUSH_TEXTURE_CACHE (1<<16)
+
+/* p221 */
+#define _3DSTATE_PIXEL_SHADER_CONSTANTS (CMD_3D|(0x1d<<24)|(0x6<<16))
+#define PS1_REG(n) (1<<(n))
+#define PS2_CONST_X(n) (n)
+#define PS3_CONST_Y(n) (n)
+#define PS4_CONST_Z(n) (n)
+#define PS5_CONST_W(n) (n)
+
+/* p222 */
+
+#define I915_MAX_TEX_INDIRECT 4
+#define I915_MAX_TEX_INSN 32
+#define I915_MAX_ALU_INSN 64
+#define I915_MAX_DECL_INSN 27
+#define I915_MAX_TEMPORARY 16
+
+/* Each instruction is 3 dwords long, though most don't require all
+ * this space. Maximum of 123 instructions. Smaller maxes per insn
+ * type.
+ */
+#define _3DSTATE_PIXEL_SHADER_PROGRAM (CMD_3D|(0x1d<<24)|(0x5<<16))
+
+#define REG_TYPE_R 0 /* temporary regs, no need to
+ * dcl, must be written before
+ * read -- Preserved between
+ * phases.
+ */
+#define REG_TYPE_T 1 /* Interpolated values, must be
+ * dcl'ed before use.
+ *
+ * 0..7: texture coord,
+ * 8: diffuse spec,
+ * 9: specular color,
+ * 10: fog parameter in w.
+ */
+#define REG_TYPE_CONST 2 /* Restriction: only one const
+ * can be referenced per
+ * instruction, though it may be
+ * selected for multiple inputs.
+ * Constants not initialized
+ * default to zero.
+ */
+#define REG_TYPE_S 3 /* sampler */
+#define REG_TYPE_OC 4 /* output color (rgba) */
+#define REG_TYPE_OD 5 /* output depth (w), xyz are
+ * temporaries. If not written,
+ * interpolated depth is used?
+ */
+#define REG_TYPE_U 6 /* unpreserved temporaries */
+#define REG_TYPE_MASK 0x7
+#define REG_NR_MASK 0xf
+
+/* REG_TYPE_T:
+ */
+#define T_TEX0 0
+#define T_TEX1 1
+#define T_TEX2 2
+#define T_TEX3 3
+#define T_TEX4 4
+#define T_TEX5 5
+#define T_TEX6 6
+#define T_TEX7 7
+#define T_DIFFUSE 8
+#define T_SPECULAR 9
+#define T_FOG_W 10 /* interpolated fog is in W coord */
+
+/* Arithmetic instructions */
+
+/* .replicate_swizzle == selection and replication of a particular
+ * scalar channel, ie., .xxxx, .yyyy, .zzzz or .wwww
+ */
+#define A0_NOP (0x0<<24) /* no operation */
+#define A0_ADD (0x1<<24) /* dst = src0 + src1 */
+#define A0_MOV (0x2<<24) /* dst = src0 */
+#define A0_MUL (0x3<<24) /* dst = src0 * src1 */
+#define A0_MAD (0x4<<24) /* dst = src0 * src1 + src2 */
+#define A0_DP2ADD (0x5<<24) /* dst.xyzw = src0.xy dot src1.xy + src2.replicate_swizzle */
+#define A0_DP3 (0x6<<24) /* dst.xyzw = src0.xyz dot src1.xyz */
+#define A0_DP4 (0x7<<24) /* dst.xyzw = src0.xyzw dot src1.xyzw */
+#define A0_FRC (0x8<<24) /* dst = src0 - floor(src0) */
+#define A0_RCP (0x9<<24) /* dst.xyzw = 1/(src0.replicate_swizzle) */
+#define A0_RSQ (0xa<<24) /* dst.xyzw = 1/(sqrt(abs(src0.replicate_swizzle))) */
+#define A0_EXP (0xb<<24) /* dst.xyzw = exp2(src0.replicate_swizzle) */
+#define A0_LOG (0xc<<24) /* dst.xyzw = log2(abs(src0.replicate_swizzle)) */
+#define A0_CMP (0xd<<24) /* dst = (src0 >= 0.0) ? src1 : src2 */
+#define A0_MIN (0xe<<24) /* dst = (src0 < src1) ? src0 : src1 */
+#define A0_MAX (0xf<<24) /* dst = (src0 >= src1) ? src0 : src1 */
+#define A0_FLR (0x10<<24) /* dst = floor(src0) */
+#define A0_MOD (0x11<<24) /* dst = src0 fmod 1.0 */
+#define A0_TRC (0x12<<24) /* dst = int(src0) */
+#define A0_SGE (0x13<<24) /* dst = src0 >= src1 ? 1.0 : 0.0 */
+#define A0_SLT (0x14<<24) /* dst = src0 < src1 ? 1.0 : 0.0 */
+#define A0_DEST_SATURATE (1<<22)
+#define A0_DEST_TYPE_SHIFT 19
+/* Allow: R, OC, OD, U */
+#define A0_DEST_NR_SHIFT 14
+/* Allow R: 0..15, OC,OD: 0..0, U: 0..2 */
+#define A0_DEST_CHANNEL_X (1<<10)
+#define A0_DEST_CHANNEL_Y (2<<10)
+#define A0_DEST_CHANNEL_Z (4<<10)
+#define A0_DEST_CHANNEL_W (8<<10)
+#define A0_DEST_CHANNEL_ALL (0xf<<10)
+#define A0_DEST_CHANNEL_SHIFT 10
+#define A0_SRC0_TYPE_SHIFT 7
+#define A0_SRC0_NR_SHIFT 2
+
+#define A0_DEST_CHANNEL_XY (A0_DEST_CHANNEL_X|A0_DEST_CHANNEL_Y)
+#define A0_DEST_CHANNEL_XYZ (A0_DEST_CHANNEL_XY|A0_DEST_CHANNEL_Z)
+
+#define SRC_X 0
+#define SRC_Y 1
+#define SRC_Z 2
+#define SRC_W 3
+#define SRC_ZERO 4
+#define SRC_ONE 5
+
+#define A1_SRC0_CHANNEL_X_NEGATE (1<<31)
+#define A1_SRC0_CHANNEL_X_SHIFT 28
+#define A1_SRC0_CHANNEL_Y_NEGATE (1<<27)
+#define A1_SRC0_CHANNEL_Y_SHIFT 24
+#define A1_SRC0_CHANNEL_Z_NEGATE (1<<23)
+#define A1_SRC0_CHANNEL_Z_SHIFT 20
+#define A1_SRC0_CHANNEL_W_NEGATE (1<<19)
+#define A1_SRC0_CHANNEL_W_SHIFT 16
+#define A1_SRC1_TYPE_SHIFT 13
+#define A1_SRC1_NR_SHIFT 8
+#define A1_SRC1_CHANNEL_X_NEGATE (1<<7)
+#define A1_SRC1_CHANNEL_X_SHIFT 4
+#define A1_SRC1_CHANNEL_Y_NEGATE (1<<3)
+#define A1_SRC1_CHANNEL_Y_SHIFT 0
+
+#define A2_SRC1_CHANNEL_Z_NEGATE (1<<31)
+#define A2_SRC1_CHANNEL_Z_SHIFT 28
+#define A2_SRC1_CHANNEL_W_NEGATE (1<<27)
+#define A2_SRC1_CHANNEL_W_SHIFT 24
+#define A2_SRC2_TYPE_SHIFT 21
+#define A2_SRC2_NR_SHIFT 16
+#define A2_SRC2_CHANNEL_X_NEGATE (1<<15)
+#define A2_SRC2_CHANNEL_X_SHIFT 12
+#define A2_SRC2_CHANNEL_Y_NEGATE (1<<11)
+#define A2_SRC2_CHANNEL_Y_SHIFT 8
+#define A2_SRC2_CHANNEL_Z_NEGATE (1<<7)
+#define A2_SRC2_CHANNEL_Z_SHIFT 4
+#define A2_SRC2_CHANNEL_W_NEGATE (1<<3)
+#define A2_SRC2_CHANNEL_W_SHIFT 0
+
+/* Texture instructions */
+#define T0_TEXLD (0x15<<24) /* Sample texture using predeclared
+ * sampler and address, and output
+ * filtered texel data to destination
+ * register */
+#define T0_TEXLDP (0x16<<24) /* Same as texld but performs a
+ * perspective divide of the texture
+ * coordinate .xyz values by .w before
+ * sampling. */
+#define T0_TEXLDB (0x17<<24) /* Same as texld but biases the
+ * computed LOD by w. Only S4.6 two's
+ * comp is used. This implies that a
+ * float to fixed conversion is
+ * done. */
+#define T0_TEXKILL (0x18<<24) /* Does not perform a sampling
+ * operation. Simply kills the pixel
+ * if any channel of the address
+ * register is < 0.0. */
+#define T0_DEST_TYPE_SHIFT 19
+/* Allow: R, OC, OD, U */
+/* Note: U (unpreserved) regs do not retain their values between
+ * phases (cannot be used for feedback)
+ *
+ * Note: oC and OD registers can only be used as the destination of a
+ * texture instruction once per phase (this is an implementation
+ * restriction).
+ */
+#define T0_DEST_NR_SHIFT 14
+/* Allow R: 0..15, OC,OD: 0..0, U: 0..2 */
+#define T0_SAMPLER_NR_SHIFT 0 /* This field ignored for TEXKILL */
+#define T0_SAMPLER_NR_MASK (0xf<<0)
+
+#define T1_ADDRESS_REG_TYPE_SHIFT 24 /* Reg to use as texture coord */
+/* Allow R, T, OC, OD -- R, OC, OD are 'dependent' reads, new program phase */
+#define T1_ADDRESS_REG_NR_SHIFT 17
+#define T2_MBZ 0
+
+/* Declaration instructions */
+#define D0_DCL (0x19<<24) /* Declare a t (interpolated attrib)
+ * register or an s (sampler)
+ * register. */
+#define D0_SAMPLE_TYPE_SHIFT 22
+#define D0_SAMPLE_TYPE_2D (0x0<<22)
+#define D0_SAMPLE_TYPE_CUBE (0x1<<22)
+#define D0_SAMPLE_TYPE_VOLUME (0x2<<22)
+#define D0_SAMPLE_TYPE_MASK (0x3<<22)
+
+#define D0_TYPE_SHIFT 19
+/* Allow: T, S */
+#define D0_NR_SHIFT 14
+/* Allow T: 0..10, S: 0..15 */
+#define D0_CHANNEL_X (1<<10)
+#define D0_CHANNEL_Y (2<<10)
+#define D0_CHANNEL_Z (4<<10)
+#define D0_CHANNEL_W (8<<10)
+#define D0_CHANNEL_ALL (0xf<<10)
+#define D0_CHANNEL_NONE (0<<10)
+
+#define D0_CHANNEL_XY (D0_CHANNEL_X|D0_CHANNEL_Y)
+#define D0_CHANNEL_XYZ (D0_CHANNEL_XY|D0_CHANNEL_Z)
+
+/* I915 Errata: Do not allow (xz), (xw), (xzw) combinations for diffuse
+ * or specular declarations.
+ *
+ * For T dcls, only allow: (x), (xy), (xyz), (w), (xyzw)
+ *
+ * Must be zero for S (sampler) dcls
+ */
+#define D1_MBZ 0
+#define D2_MBZ 0
+
+/* p207.
+ * The DWORD count is 3 times the number of bits set in MS1_MAPMASK_MASK
+ */
+#define _3DSTATE_MAP_STATE (CMD_3D|(0x1d<<24)|(0x0<<16))
+
+#define MS1_MAPMASK_SHIFT 0
+#define MS1_MAPMASK_MASK (0x8fff<<0)
+
+#define MS2_UNTRUSTED_SURFACE (1<<31)
+#define MS2_ADDRESS_MASK 0xfffffffc
+#define MS2_VERTICAL_LINE_STRIDE (1<<1)
+#define MS2_VERTICAL_OFFSET (1<<1)
+
+#define MS3_HEIGHT_SHIFT 21
+#define MS3_WIDTH_SHIFT 10
+#define MS3_PALETTE_SELECT (1<<9)
+#define MS3_MAPSURF_FORMAT_SHIFT 7
+#define MS3_MAPSURF_FORMAT_MASK (0x7<<7)
+#define MAPSURF_8BIT (1<<7)
+#define MAPSURF_16BIT (2<<7)
+#define MAPSURF_32BIT (3<<7)
+#define MAPSURF_422 (5<<7)
+#define MAPSURF_COMPRESSED (6<<7)
+#define MAPSURF_4BIT_INDEXED (7<<7)
+#define MS3_MT_FORMAT_MASK (0x7 << 3)
+#define MS3_MT_FORMAT_SHIFT 3
+#define MT_4BIT_IDX_ARGB8888 (7<<3) /* SURFACE_4BIT_INDEXED */
+#define MT_8BIT_I8 (0<<3) /* SURFACE_8BIT */
+#define MT_8BIT_L8 (1<<3)
+#define MT_8BIT_A8 (4<<3)
+#define MT_8BIT_MONO8 (5<<3)
+#define MT_16BIT_RGB565 (0<<3) /* SURFACE_16BIT */
+#define MT_16BIT_ARGB1555 (1<<3)
+#define MT_16BIT_ARGB4444 (2<<3)
+#define MT_16BIT_AY88 (3<<3)
+#define MT_16BIT_88DVDU (5<<3)
+#define MT_16BIT_BUMP_655LDVDU (6<<3)
+#define MT_16BIT_I16 (7<<3)
+#define MT_16BIT_L16 (8<<3)
+#define MT_16BIT_A16 (9<<3)
+#define MT_32BIT_ARGB8888 (0<<3) /* SURFACE_32BIT */
+#define MT_32BIT_ABGR8888 (1<<3)
+#define MT_32BIT_XRGB8888 (2<<3)
+#define MT_32BIT_XBGR8888 (3<<3)
+#define MT_32BIT_QWVU8888 (4<<3)
+#define MT_32BIT_AXVU8888 (5<<3)
+#define MT_32BIT_LXVU8888 (6<<3)
+#define MT_32BIT_XLVU8888 (7<<3)
+#define MT_32BIT_ARGB2101010 (8<<3)
+#define MT_32BIT_ABGR2101010 (9<<3)
+#define MT_32BIT_AWVU2101010 (0xA<<3)
+#define MT_32BIT_GR1616 (0xB<<3)
+#define MT_32BIT_VU1616 (0xC<<3)
+#define MT_32BIT_xI824 (0xD<<3)
+#define MT_32BIT_xA824 (0xE<<3)
+#define MT_32BIT_xL824 (0xF<<3)
+#define MT_422_YCRCB_SWAPY (0<<3) /* SURFACE_422 */
+#define MT_422_YCRCB_NORMAL (1<<3)
+#define MT_422_YCRCB_SWAPUV (2<<3)
+#define MT_422_YCRCB_SWAPUVY (3<<3)
+#define MT_COMPRESS_DXT1 (0<<3) /* SURFACE_COMPRESSED */
+#define MT_COMPRESS_DXT2_3 (1<<3)
+#define MT_COMPRESS_DXT4_5 (2<<3)
+#define MT_COMPRESS_FXT1 (3<<3)
+#define MT_COMPRESS_DXT1_RGB (4<<3)
+#define MS3_USE_FENCE_REGS (1<<2)
+#define MS3_TILED_SURFACE (1<<1)
+#define MS3_TILE_WALK (1<<0)
+
+/* The pitch is the pitch measured in DWORDS, minus 1 */
+#define MS4_PITCH_SHIFT 21
+#define MS4_CUBE_FACE_ENA_NEGX (1<<20)
+#define MS4_CUBE_FACE_ENA_POSX (1<<19)
+#define MS4_CUBE_FACE_ENA_NEGY (1<<18)
+#define MS4_CUBE_FACE_ENA_POSY (1<<17)
+#define MS4_CUBE_FACE_ENA_NEGZ (1<<16)
+#define MS4_CUBE_FACE_ENA_POSZ (1<<15)
+#define MS4_CUBE_FACE_ENA_MASK (0x3f<<15)
+#define MS4_MAX_LOD_SHIFT 9
+#define MS4_MAX_LOD_MASK (0x3f<<9)
+#define MS4_MIP_LAYOUT_LEGACY (0<<8)
+#define MS4_MIP_LAYOUT_BELOW_LPT (0<<8)
+#define MS4_MIP_LAYOUT_RIGHT_LPT (1<<8)
+#define MS4_VOLUME_DEPTH_SHIFT 0
+#define MS4_VOLUME_DEPTH_MASK (0xff<<0)
+
+/* p244.
+ * The DWORD count is 3 times the number of bits set in SS1_MAPMASK_MASK.
+ */
+#define _3DSTATE_SAMPLER_STATE (CMD_3D|(0x1d<<24)|(0x1<<16))
+
+#define SS1_MAPMASK_SHIFT 0
+#define SS1_MAPMASK_MASK (0x8fff<<0)
+
+#define SS2_REVERSE_GAMMA_ENABLE (1<<31)
+#define SS2_PACKED_TO_PLANAR_ENABLE (1<<30)
+#define SS2_COLORSPACE_CONVERSION (1<<29)
+#define SS2_CHROMAKEY_SHIFT 27
+#define SS2_BASE_MIP_LEVEL_SHIFT 22
+#define SS2_BASE_MIP_LEVEL_MASK (0x1f<<22)
+#define SS2_MIP_FILTER_SHIFT 20
+#define SS2_MIP_FILTER_MASK (0x3<<20)
+#define MIPFILTER_NONE 0
+#define MIPFILTER_NEAREST 1
+#define MIPFILTER_LINEAR 3
+#define SS2_MAG_FILTER_SHIFT 17
+#define SS2_MAG_FILTER_MASK (0x7<<17)
+#define FILTER_NEAREST 0
+#define FILTER_LINEAR 1
+#define FILTER_ANISOTROPIC 2
+#define FILTER_4X4_1 3
+#define FILTER_4X4_2 4
+#define FILTER_4X4_FLAT 5
+#define FILTER_6X5_MONO 6 /* XXX - check */
+#define SS2_MIN_FILTER_SHIFT 14
+#define SS2_MIN_FILTER_MASK (0x7<<14)
+#define SS2_LOD_BIAS_SHIFT 5
+#define SS2_LOD_BIAS_ONE (0x10<<5)
+#define SS2_LOD_BIAS_MASK (0x1ff<<5)
+/* Shadow requires:
+ * MT_X8{I,L,A}24 or MT_{I,L,A}16 texture format
+ * FILTER_4X4_x MIN and MAG filters
+ */
+#define SS2_SHADOW_ENABLE (1<<4)
+#define SS2_MAX_ANISO_MASK (1<<3)
+#define SS2_MAX_ANISO_2 (0<<3)
+#define SS2_MAX_ANISO_4 (1<<3)
+#define SS2_SHADOW_FUNC_SHIFT 0
+#define SS2_SHADOW_FUNC_MASK (0x7<<0)
+/* SS2_SHADOW_FUNC values: see COMPAREFUNC_* */
+
+#define SS3_MIN_LOD_SHIFT 24
+#define SS3_MIN_LOD_ONE (0x10<<24)
+#define SS3_MIN_LOD_MASK (0xff<<24)
+#define SS3_KILL_PIXEL_ENABLE (1<<17)
+#define SS3_TCX_ADDR_MODE_SHIFT 12
+#define SS3_TCX_ADDR_MODE_MASK (0x7<<12)
+#define TEXCOORDMODE_WRAP 0
+#define TEXCOORDMODE_MIRROR 1
+#define TEXCOORDMODE_CLAMP_EDGE 2
+#define TEXCOORDMODE_CUBE 3
+#define TEXCOORDMODE_CLAMP_BORDER 4
+#define TEXCOORDMODE_MIRROR_ONCE 5
+#define SS3_TCY_ADDR_MODE_SHIFT 9
+#define SS3_TCY_ADDR_MODE_MASK (0x7<<9)
+#define SS3_TCZ_ADDR_MODE_SHIFT 6
+#define SS3_TCZ_ADDR_MODE_MASK (0x7<<6)
+#define SS3_NORMALIZED_COORDS (1<<5)
+#define SS3_TEXTUREMAP_INDEX_SHIFT 1
+#define SS3_TEXTUREMAP_INDEX_MASK (0xf<<1)
+#define SS3_DEINTERLACER_ENABLE (1<<0)
+
+#define SS4_BORDER_COLOR_MASK (~0)
+
+/* 3DSTATE_SPAN_STIPPLE, p258
+ */
+#define _3DSTATE_STIPPLE ((0x3<<29)|(0x1d<<24)|(0x83<<16))
+#define ST1_ENABLE (1<<16)
+#define ST1_MASK (0xffff)
+
+#define FLUSH_MAP_CACHE (1<<0)
+#define FLUSH_RENDER_CACHE (1<<1)
+
+/* BLT commands */
+#define COLOR_BLT_CMD (CMD_2D | (0x40 << 22) | 3)
+#define XY_COLOR_BLT_CMD (CMD_2D | (0x50 << 22) | 4)
+#define XY_SETUP_CLIP_BLT_CMD (CMD_2D | (0x03 << 22) | 1)
+#define XY_SRC_COPY_BLT_CMD (CMD_2D | (0x53 << 22) | 6)
+#define SRC_COPY_BLT_CMD (CMD_2D | (0x43 << 22) | 4)
+
+#define XY_MONO_PAT_BLT_CMD (CMD_2D | (0x52<<22)|0x7)
+#define XY_MONO_PAT_VERT_SEED ((1<<10) | (1<<9)|(1<<8))
+#define XY_MONO_PAT_HORT_SEED ((1<<14) | (1<<13)|(1<<12))
+#define XY_MONO_SRC_BLT_CMD (CMD_2D | (0x54<<22)|(0x6))
+
+#define XY_SETUP_BLT_CMD (CMD_2D | (0x01 << 22) | 6)
+#define XY_TEXT_IMMEDIATE_BLIT_CMD (CMD_2D | (0x31 << 22))
+#define XY_TEXT_BYTE_PACKED (1 << 16)
+
+/* BR00 */
+#define XY_BLT_WRITE_ALPHA (1 << 21)
+#define XY_BLT_WRITE_RGB (1 << 20)
+#define XY_SRC_TILED (1 << 15)
+#define XY_DST_TILED (1 << 11)
+
+/* BR13 */
+#define BR13_565 (0x1 << 24)
+#define BR13_8888 (0x3 << 24)
+
+#endif /* CAIRO_DRM_INTEL_COMMAND_PRIVATE_H */
diff --git a/src/drm/cairo-drm-intel-debug.c b/src/drm/cairo-drm-intel-debug.c
new file mode 100644
index 0000000..cc2e47a
--- /dev/null
+++ b/src/drm/cairo-drm-intel-debug.c
@@ -0,0 +1,1208 @@
+/**************************************************************************
+ *
+ * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+#include "cairoint.h"
+#include "cairo-drm-intel-private.h"
+
+struct debug_stream {
+ unsigned offset; /* current gtt offset */
+ const char *ptr; /* pointer to gtt offset zero */
+ const char *end; /* pointer to gtt offset zero */
+};
+
+static cairo_bool_t
+debug (struct debug_stream *stream, const char *name, uint32_t len)
+{
+ uint32_t i;
+ const uint32_t *ptr = (uint32_t *)(stream->ptr + stream->offset);
+
+ if (len == 0) {
+ fprintf (stderr, "Error - zero length packet (0x%08x)\n", stream->ptr[0]);
+ ASSERT_NOT_REACHED;
+ return FALSE;
+ }
+
+ fprintf (stderr, "%04x: ", stream->offset);
+
+ fprintf (stderr, "%s (%d dwords):\n", name, len);
+ for (i = 0; i < len; i++)
+ fprintf (stderr, "\t0x%08x\n", ptr[i]);
+ fprintf (stderr, "\n");
+
+ stream->offset += len * sizeof(uint32_t);
+ return TRUE;
+}
+
+
+static const char *
+get_prim_name (uint32_t val)
+{
+ switch (val & PRIM3D_MASK) {
+ case PRIM3D_TRILIST: return "TRILIST";
+ case PRIM3D_TRISTRIP: return "TRISTRIP";
+ case PRIM3D_TRISTRIP_RVRSE: return "TRISTRIP_RVRSE";
+ case PRIM3D_TRIFAN: return "TRIFAN";
+ case PRIM3D_POLY: return "POLY";
+ case PRIM3D_LINELIST: return "LINELIST";
+ case PRIM3D_LINESTRIP: return "LINESTRIP";
+ case PRIM3D_RECTLIST: return "RECTLIST";
+ case PRIM3D_POINTLIST: return "POINTLIST";
+ case PRIM3D_DIB: return "DIB";
+ case PRIM3D_CLEAR_RECT: return "CLEAR_RECT";
+ case PRIM3D_ZONE_INIT: return "ZONE_INIT";
+ default: return "????";
+ }
+}
+
+static cairo_bool_t
+debug_prim (struct debug_stream *stream,
+ const char *name,
+ cairo_bool_t dump_floats,
+ uint32_t len)
+{
+ uint32_t *ptr = (uint32_t *)(stream->ptr + stream->offset);
+ const char *prim = get_prim_name( ptr[0] );
+ uint32_t i;
+
+ fprintf (stderr, "%04x: ", stream->offset);
+ fprintf (stderr, "%s %s (%d dwords):\n", name, prim, len);
+ fprintf (stderr, "\t0x%08x\n", ptr[0]);
+ for (i = 1; i < len; i++) {
+ if (dump_floats)
+ fprintf (stderr, "\t0x%08x // %f\n", ptr[i], *(float *)&ptr[i]);
+ else
+ fprintf (stderr, "\t0x%08x\n", ptr[i]);
+ }
+
+ fprintf (stderr, "\n");
+
+ stream->offset += len * sizeof(uint32_t);
+ return TRUE;
+}
+
+static const char *opcodes[] = {
+ "NOP",
+ "ADD",
+ "MOV",
+ "MUL",
+ "MAD",
+ "DP2ADD",
+ "DP3",
+ "DP4",
+ "FRC",
+ "RCP",
+ "RSQ",
+ "EXP",
+ "LOG",
+ "CMP",
+ "MIN",
+ "MAX",
+ "FLR",
+ "MOD",
+ "TRC",
+ "SGE",
+ "SLT",
+ "TEXLD",
+ "TEXLDP",
+ "TEXLDB",
+ "TEXKILL",
+ "DCL",
+ "0x1a",
+ "0x1b",
+ "0x1c",
+ "0x1d",
+ "0x1e",
+ "0x1f",
+};
+
+static const int args[] = {
+ 0, /* 0 nop */
+ 2, /* 1 add */
+ 1, /* 2 mov */
+ 2, /* 3 m ul */
+ 3, /* 4 mad */
+ 3, /* 5 dp2add */
+ 2, /* 6 dp3 */
+ 2, /* 7 dp4 */
+ 1, /* 8 frc */
+ 1, /* 9 rcp */
+ 1, /* a rsq */
+ 1, /* b exp */
+ 1, /* c log */
+ 3, /* d cmp */
+ 2, /* e min */
+ 2, /* f max */
+ 1, /* 10 flr */
+ 1, /* 11 mod */
+ 1, /* 12 trc */
+ 2, /* 13 sge */
+ 2, /* 14 slt */
+ 1,
+ 1,
+ 1,
+ 1,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+};
+
+static const char *regname[] = {
+ "R",
+ "T",
+ "CONST",
+ "S",
+ "OC",
+ "OD",
+ "U",
+ "UNKNOWN",
+};
+
+static void
+print_reg_type_nr(uint32_t type, uint32_t nr)
+{
+ switch (type) {
+ case REG_TYPE_T:
+ switch (nr) {
+ case T_DIFFUSE:
+ fprintf (stderr, "T_DIFFUSE");
+ return;
+ case T_SPECULAR:
+ fprintf (stderr, "T_SPECULAR");
+ return;
+ case T_FOG_W:
+ fprintf (stderr, "T_FOG_W");
+ return;
+ default:
+ fprintf (stderr, "T_TEX%d", nr);
+ return;
+ }
+ case REG_TYPE_OC:
+ if (nr == 0) {
+ fprintf (stderr, "oC");
+ return;
+ }
+ break;
+ case REG_TYPE_OD:
+ if (nr == 0) {
+ fprintf (stderr, "oD");
+ return;
+ }
+ break;
+ default:
+ break;
+ }
+
+ fprintf (stderr, "%s[%d]", regname[type], nr);
+}
+
+#define REG_SWIZZLE_MASK 0x7777
+#define REG_NEGATE_MASK 0x8888
+
+#define REG_SWIZZLE_XYZW ((SRC_X << A2_SRC2_CHANNEL_X_SHIFT) | \
+ (SRC_Y << A2_SRC2_CHANNEL_Y_SHIFT) | \
+ (SRC_Z << A2_SRC2_CHANNEL_Z_SHIFT) | \
+ (SRC_W << A2_SRC2_CHANNEL_W_SHIFT))
+
+static void
+print_reg_neg_swizzle(uint32_t reg)
+{
+ int i;
+
+ if ((reg & REG_SWIZZLE_MASK) == REG_SWIZZLE_XYZW &&
+ (reg & REG_NEGATE_MASK) == 0)
+ return;
+
+ fprintf (stderr, ".");
+
+ for (i = 12; i >= 0; i -= 4) {
+ if (reg & (8 << i))
+ fprintf (stderr, "-");
+
+ switch ((reg >> i) & 0x7) {
+ case 0:
+ fprintf (stderr, "x");
+ break;
+ case 1:
+ fprintf (stderr, "y");
+ break;
+ case 2:
+ fprintf (stderr, "z");
+ break;
+ case 3:
+ fprintf (stderr, "w");
+ break;
+ case 4:
+ fprintf (stderr, "0");
+ break;
+ case 5:
+ fprintf (stderr, "1");
+ break;
+ default:
+ fprintf (stderr, "?");
+ break;
+ }
+ }
+}
+
+static void
+print_src_reg(uint32_t dword)
+{
+ uint32_t nr = (dword >> A2_SRC2_NR_SHIFT) & REG_NR_MASK;
+ uint32_t type = (dword >> A2_SRC2_TYPE_SHIFT) & REG_TYPE_MASK;
+ print_reg_type_nr(type, nr);
+ print_reg_neg_swizzle(dword);
+}
+
+static void
+print_dest_reg(uint32_t dword)
+{
+ uint32_t nr = (dword >> A0_DEST_NR_SHIFT) & REG_NR_MASK;
+ uint32_t type = (dword >> A0_DEST_TYPE_SHIFT) & REG_TYPE_MASK;
+ print_reg_type_nr(type, nr);
+ if ((dword & A0_DEST_CHANNEL_ALL) == A0_DEST_CHANNEL_ALL)
+ return;
+ fprintf (stderr, ".");
+ if (dword & A0_DEST_CHANNEL_X)
+ fprintf (stderr, "x");
+ if (dword & A0_DEST_CHANNEL_Y)
+ fprintf (stderr, "y");
+ if (dword & A0_DEST_CHANNEL_Z)
+ fprintf (stderr, "z");
+ if (dword & A0_DEST_CHANNEL_W)
+ fprintf (stderr, "w");
+}
+
+#define GET_SRC0_REG(r0, r1) ((r0<<14)|(r1>>A1_SRC0_CHANNEL_W_SHIFT))
+#define GET_SRC1_REG(r0, r1) ((r0<<8)|(r1>>A2_SRC1_CHANNEL_W_SHIFT))
+#define GET_SRC2_REG(r) (r)
+
+static void
+print_arith_op(uint32_t opcode, const uint32_t * program)
+{
+ if (opcode != A0_NOP) {
+ print_dest_reg(program[0]);
+ if (program[0] & A0_DEST_SATURATE)
+ fprintf (stderr, " = SATURATE ");
+ else
+ fprintf (stderr, " = ");
+ }
+
+ fprintf (stderr, "%s ", opcodes[opcode]);
+
+ print_src_reg(GET_SRC0_REG(program[0], program[1]));
+ if (args[opcode] == 1) {
+ fprintf (stderr, "\n");
+ return;
+ }
+
+ fprintf (stderr, ", ");
+ print_src_reg(GET_SRC1_REG(program[1], program[2]));
+ if (args[opcode] == 2) {
+ fprintf (stderr, "\n");
+ return;
+ }
+
+ fprintf (stderr, ", ");
+ print_src_reg(GET_SRC2_REG(program[2]));
+ fprintf (stderr, "\n");
+ return;
+}
+
+static void
+print_tex_op(uint32_t opcode, const uint32_t * program)
+{
+ print_dest_reg(program[0] | A0_DEST_CHANNEL_ALL);
+ fprintf (stderr, " = ");
+
+ fprintf (stderr, "%s ", opcodes[opcode]);
+
+ fprintf (stderr, "S[%d],", program[0] & T0_SAMPLER_NR_MASK);
+
+ print_reg_type_nr((program[1] >> T1_ADDRESS_REG_TYPE_SHIFT) &
+ REG_TYPE_MASK,
+ (program[1] >> T1_ADDRESS_REG_NR_SHIFT) & REG_NR_MASK);
+ fprintf (stderr, "\n");
+}
+
+static void
+print_dcl_op(uint32_t opcode, const uint32_t * program)
+{
+ fprintf (stderr, "%s ", opcodes[opcode]);
+ print_dest_reg(program[0] | A0_DEST_CHANNEL_ALL);
+ fprintf (stderr, "\n");
+}
+
+static void
+i915_disassemble_program (const uint32_t * program, uint32_t sz)
+{
+ uint32_t size = program[0] & 0x1ff;
+ uint32_t i;
+
+ fprintf (stderr, "\tPROGRAM\n");
+
+ assert(size + 2 == sz);
+
+ program++;
+ for (i = 1; i < sz; i += 3, program += 3) {
+ uint32_t opcode = program[0] & (0x1f << 24);
+
+ fprintf (stderr, "\t\t");
+
+ if ((int) opcode >= A0_NOP && opcode <= A0_SLT)
+ print_arith_op(opcode >> 24, program);
+ else if (opcode >= T0_TEXLD && opcode <= T0_TEXKILL)
+ print_tex_op(opcode >> 24, program);
+ else if (opcode == D0_DCL)
+ print_dcl_op(opcode >> 24, program);
+ else
+ fprintf (stderr, "Unknown opcode 0x%x\n", opcode);
+ }
+
+ fprintf (stderr, "\tEND-PROGRAM\n\n");
+}
+
+static cairo_bool_t
+debug_program (struct debug_stream *stream, const char *name, uint32_t len)
+{
+ uint32_t *ptr = (uint32_t *)(stream->ptr + stream->offset);
+
+ if (len == 0) {
+ fprintf (stderr, "Error - zero length packet (0x%08x)\n", stream->ptr[0]);
+ ASSERT_NOT_REACHED;
+ return FALSE;
+ }
+
+ fprintf (stderr, "%04x: ", stream->offset);
+ fprintf (stderr, "%s (%d dwords):\n", name, len);
+ i915_disassemble_program (ptr, len);
+
+ stream->offset += len * sizeof(uint32_t);
+ return TRUE;
+}
+
+static cairo_bool_t
+debug_chain (struct debug_stream *stream, const char *name, uint32_t len)
+{
+ uint32_t *ptr = (uint32_t *)(stream->ptr + stream->offset);
+ uint32_t old_offset = stream->offset + len * sizeof(uint32_t);
+ uint32_t i;
+
+ fprintf (stderr, "%s (%d dwords):\n", name, len);
+ for (i = 0; i < len; i++)
+ fprintf (stderr, "\t0x%08x\n", ptr[i]);
+
+ stream->offset = ptr[1] & ~0x3;
+
+ if (stream->offset < old_offset)
+ fprintf (stderr, "\n... skipping backwards from 0x%x --> 0x%x ...\n\n",
+ old_offset, stream->offset );
+ else
+ fprintf (stderr, "\n... skipping from 0x%x --> 0x%x ...\n\n",
+ old_offset, stream->offset );
+
+ return TRUE;
+}
+
+static cairo_bool_t
+debug_variable_length_prim (struct debug_stream *stream)
+{
+ uint32_t *ptr = (uint32_t *)(stream->ptr + stream->offset);
+ const char *prim = get_prim_name( ptr[0] );
+ uint32_t i, len;
+
+ uint16_t *idx = (uint16_t *)(ptr+1);
+ for (i = 0; idx[i] != 0xffff; i++)
+ ;
+
+ len = 1+(i+2)/2;
+
+ fprintf (stderr, "%04x: ", stream->offset);
+ fprintf (stderr, "3DPRIM, %s variable length %d indicies (%d dwords):\n", prim, i, len);
+ for (i = 0; i < len; i++)
+ fprintf (stderr, "\t0x%08x\n", ptr[i]);
+ fprintf (stderr, "\n");
+
+ stream->offset += len * sizeof(uint32_t);
+ return TRUE;
+}
+
+#define BITS(dw, hi, lo, ...) \
+ do { \
+ unsigned himask = 0xffffffffU >> (31 - (hi)); \
+ fprintf (stderr, "\t\t "); \
+ fprintf (stderr, __VA_ARGS__); \
+ fprintf (stderr, ": 0x%x\n", ((dw) & himask) >> (lo)); \
+ } while (0)
+
+#define MBZ(dw, hi, lo) do { \
+ unsigned x = (dw) >> (lo); \
+ unsigned lomask = (1 << (lo)) - 1; \
+ unsigned himask; \
+ himask = (1UL << (hi)) - 1; \
+ assert ((x & himask & ~lomask) == 0); \
+} while (0)
+
+#define FLAG(dw, bit, ... ) \
+ do { \
+ if (((dw) >> (bit)) & 1) { \
+ fprintf (stderr, "\t\t "); \
+ fprintf (stderr, __VA_ARGS__); \
+ fprintf (stderr, "\n"); \
+ } \
+ } while (0)
+
+static cairo_bool_t
+debug_load_immediate (struct debug_stream *stream,
+ const char *name,
+ uint32_t len)
+{
+ uint32_t *ptr = (uint32_t *)(stream->ptr + stream->offset);
+ uint32_t bits = (ptr[0] >> 4) & 0xff;
+ uint32_t j = 0;
+
+ fprintf (stderr, "%04x: ", stream->offset);
+ fprintf (stderr, "%s (%d dwords, flags: %x):\n", name, len, bits);
+ fprintf (stderr, "\t0x%08x\n", ptr[j++]);
+
+ if (bits & (1<<0)) {
+ fprintf (stderr, "\t LIS0: 0x%08x\n", ptr[j]);
+ fprintf (stderr, "\t vb address: 0x%08x\n", (ptr[j] & ~0x3));
+ BITS (ptr[j], 0, 0, "vb invalidate disable");
+ j++;
+ }
+ if (bits & (1<<1)) {
+ fprintf (stderr, "\t LIS1: 0x%08x\n", ptr[j]);
+ BITS (ptr[j], 29, 24, "vb dword width");
+ BITS (ptr[j], 21, 16, "vb dword pitch");
+ BITS (ptr[j], 15, 0, "vb max index");
+ j++;
+ }
+ if (bits & (1<<2)) {
+ int i;
+ fprintf (stderr, "\t LIS2: 0x%08x\n", ptr[j]);
+ for (i = 0; i < 8; i++) {
+ unsigned tc = (ptr[j] >> (i * 4)) & 0xf;
+ if (tc != 0xf)
+ BITS (tc, 3, 0, "tex coord %d", i);
+ }
+ j++;
+ }
+ if (bits & (1<<3)) {
+ fprintf (stderr, "\t LIS3: 0x%08x\n", ptr[j]);
+ j++;
+ }
+ if (bits & (1<<4)) {
+ fprintf (stderr, "\t LIS4: 0x%08x\n", ptr[j]);
+ BITS (ptr[j], 31, 23, "point width");
+ BITS (ptr[j], 22, 19, "line width");
+ FLAG (ptr[j], 18, "alpha flatshade");
+ FLAG (ptr[j], 17, "fog flatshade");
+ FLAG (ptr[j], 16, "spec flatshade");
+ FLAG (ptr[j], 15, "rgb flatshade");
+ BITS (ptr[j], 14, 13, "cull mode");
+ FLAG (ptr[j], 12, "vfmt: point width");
+ FLAG (ptr[j], 11, "vfmt: specular/fog");
+ FLAG (ptr[j], 10, "vfmt: rgba");
+ FLAG (ptr[j], 9, "vfmt: depth offset");
+ BITS (ptr[j], 8, 6, "vfmt: position (2==xyzw)");
+ FLAG (ptr[j], 5, "force dflt diffuse");
+ FLAG (ptr[j], 4, "force dflt specular");
+ FLAG (ptr[j], 3, "local depth offset enable");
+ FLAG (ptr[j], 2, "vfmt: fp32 fog coord");
+ FLAG (ptr[j], 1, "sprite point");
+ FLAG (ptr[j], 0, "antialiasing");
+ j++;
+ }
+ if (bits & (1<<5)) {
+ fprintf (stderr, "\t LIS5: 0x%08x\n", ptr[j]);
+ BITS (ptr[j], 31, 28, "rgba write disables");
+ FLAG (ptr[j], 27, "force dflt point width");
+ FLAG (ptr[j], 26, "last pixel enable");
+ FLAG (ptr[j], 25, "global z offset enable");
+ FLAG (ptr[j], 24, "fog enable");
+ BITS (ptr[j], 23, 16, "stencil ref");
+ BITS (ptr[j], 15, 13, "stencil test");
+ BITS (ptr[j], 12, 10, "stencil fail op");
+ BITS (ptr[j], 9, 7, "stencil pass z fail op");
+ BITS (ptr[j], 6, 4, "stencil pass z pass op");
+ FLAG (ptr[j], 3, "stencil write enable");
+ FLAG (ptr[j], 2, "stencil test enable");
+ FLAG (ptr[j], 1, "color dither enable");
+ FLAG (ptr[j], 0, "logiop enable");
+ j++;
+ }
+ if (bits & (1<<6)) {
+ fprintf (stderr, "\t LIS6: 0x%08x\n", ptr[j]);
+ FLAG (ptr[j], 31, "alpha test enable");
+ BITS (ptr[j], 30, 28, "alpha func");
+ BITS (ptr[j], 27, 20, "alpha ref");
+ FLAG (ptr[j], 19, "depth test enable");
+ BITS (ptr[j], 18, 16, "depth func");
+ FLAG (ptr[j], 15, "blend enable");
+ BITS (ptr[j], 14, 12, "blend func");
+ BITS (ptr[j], 11, 8, "blend src factor");
+ BITS (ptr[j], 7, 4, "blend dst factor");
+ FLAG (ptr[j], 3, "depth write enable");
+ FLAG (ptr[j], 2, "color write enable");
+ BITS (ptr[j], 1, 0, "provoking vertex");
+ j++;
+ }
+
+ fprintf (stderr, "\n");
+
+ assert(j == len);
+
+ stream->offset += len * sizeof(uint32_t);
+ return TRUE;
+}
+
+static cairo_bool_t
+debug_load_indirect (struct debug_stream *stream,
+ const char *name,
+ uint32_t len)
+{
+ uint32_t *ptr = (uint32_t *)(stream->ptr + stream->offset);
+ uint32_t bits = (ptr[0] >> 8) & 0x3f;
+ uint32_t i, j = 0;
+
+ fprintf (stderr, "%04x: ", stream->offset);
+ fprintf (stderr, "%s (%d dwords):\n", name, len);
+ fprintf (stderr, "\t0x%08x\n", ptr[j++]);
+
+ for (i = 0; i < 6; i++) {
+ if (bits & (1<<i)) {
+ switch (1<<(8+i)) {
+ case LI0_STATE_STATIC_INDIRECT:
+ fprintf (stderr, " STATIC: 0x%08x | %x\n", ptr[j]&~3, ptr[j]&3); j++;
+ fprintf (stderr, " 0x%08x\n", ptr[j++]);
+ break;
+ case LI0_STATE_DYNAMIC_INDIRECT:
+ fprintf (stderr, " DYNAMIC: 0x%08x | %x\n", ptr[j]&~3, ptr[j]&3); j++;
+ break;
+ case LI0_STATE_SAMPLER:
+ fprintf (stderr, " SAMPLER: 0x%08x | %x\n", ptr[j]&~3, ptr[j]&3); j++;
+ fprintf (stderr, " 0x%08x\n", ptr[j++]);
+ break;
+ case LI0_STATE_MAP:
+ fprintf (stderr, " MAP: 0x%08x | %x\n", ptr[j]&~3, ptr[j]&3); j++;
+ fprintf (stderr, " 0x%08x\n", ptr[j++]);
+ break;
+ case LI0_STATE_PROGRAM:
+ fprintf (stderr, " PROGRAM: 0x%08x | %x\n", ptr[j]&~3, ptr[j]&3); j++;
+ fprintf (stderr, " 0x%08x\n", ptr[j++]);
+ break;
+ case LI0_STATE_CONSTANTS:
+ fprintf (stderr, " CONSTANTS: 0x%08x | %x\n", ptr[j]&~3, ptr[j]&3); j++;
+ fprintf (stderr, " 0x%08x\n", ptr[j++]);
+ break;
+ default:
+ ASSERT_NOT_REACHED;
+ break;
+ }
+ }
+ }
+
+ if (bits == 0) {
+ fprintf (stderr, "\t DUMMY: 0x%08x\n", ptr[j++]);
+ }
+
+ fprintf (stderr, "\n");
+
+ assert(j == len);
+ stream->offset += len * sizeof(uint32_t);
+ return TRUE;
+}
+
+static void
+BR13 (struct debug_stream *stream,
+ uint32_t val)
+{
+ fprintf (stderr, "\t0x%08x\n", val);
+ FLAG (val, 30, "clipping enable");
+ BITS (val, 25, 24, "color depth (3==32bpp)");
+ BITS (val, 23, 16, "raster op");
+ BITS (val, 15, 0, "dest pitch");
+}
+
+static void
+BR2223 (struct debug_stream *stream,
+ uint32_t val22, uint32_t val23)
+{
+ union { uint32_t val; short field[2]; } BR22, BR23;
+
+ BR22.val = val22;
+ BR23.val = val23;
+
+ fprintf (stderr, "\t0x%08x\n", val22);
+ BITS (val22, 31, 16, "dest y1");
+ BITS (val22, 15, 0, "dest x1");
+
+ fprintf (stderr, "\t0x%08x\n", val23);
+ BITS (val23, 31, 16, "dest y2");
+ BITS (val23, 15, 0, "dest x2");
+
+ /* The blit engine may produce unexpected results when these aren't met */
+ assert(BR22.field[0] < BR23.field[0]);
+ assert(BR22.field[1] < BR23.field[1]);
+}
+
+static void
+BR09 (struct debug_stream *stream,
+ uint32_t val)
+{
+ fprintf (stderr, "\t0x%08x -- dest address\n", val);
+}
+
+static void
+BR26 (struct debug_stream *stream,
+ uint32_t val)
+{
+ fprintf (stderr, "\t0x%08x\n", val);
+ BITS (val, 31, 16, "src y1");
+ BITS (val, 15, 0, "src x1");
+}
+
+static void
+BR11 (struct debug_stream *stream,
+ uint32_t val)
+{
+ fprintf (stderr, "\t0x%08x\n", val);
+ BITS (val, 15, 0, "src pitch");
+}
+
+static void
+BR12 (struct debug_stream *stream,
+ uint32_t val)
+{
+ fprintf (stderr, "\t0x%08x -- src address\n", val);
+}
+
+static void
+BR16 (struct debug_stream *stream,
+ uint32_t val)
+{
+ fprintf (stderr, "\t0x%08x -- color\n", val);
+}
+
+static cairo_bool_t
+debug_copy_blit (struct debug_stream *stream,
+ const char *name,
+ uint32_t len)
+{
+ uint32_t *ptr = (uint32_t *)(stream->ptr + stream->offset);
+ uint32_t j = 0;
+
+ fprintf (stderr, "%s (%d dwords):\n", name, len);
+ fprintf (stderr, "\t0x%08x\n", ptr[j++]);
+
+ BR13(stream, ptr[j++]);
+ BR2223(stream, ptr[j], ptr[j+1]);
+ j += 2;
+ BR09(stream, ptr[j++]);
+ BR26(stream, ptr[j++]);
+ BR11(stream, ptr[j++]);
+ BR12(stream, ptr[j++]);
+
+ stream->offset += len * sizeof(uint32_t);
+ assert(j == len);
+ return TRUE;
+}
+
+static cairo_bool_t
+debug_color_blit (struct debug_stream *stream,
+ const char *name,
+ uint32_t len)
+{
+ uint32_t *ptr = (uint32_t *)(stream->ptr + stream->offset);
+ uint32_t j = 0;
+
+ fprintf (stderr, "%04x: ", stream->offset);
+ fprintf (stderr, "%s (%d dwords):\n", name, len);
+ fprintf (stderr, "\t0x%08x\n", ptr[j++]);
+
+ BR13(stream, ptr[j++]);
+ BR2223(stream, ptr[j], ptr[j+1]);
+ j += 2;
+ BR09(stream, ptr[j++]);
+ BR16(stream, ptr[j++]);
+
+ stream->offset += len * sizeof(uint32_t);
+ assert(j == len);
+ return TRUE;
+}
+
+static cairo_bool_t
+debug_modes4 (struct debug_stream *stream,
+ const char *name,
+ uint32_t len)
+{
+ uint32_t *ptr = (uint32_t *)(stream->ptr + stream->offset);
+ uint32_t j = 0;
+
+ fprintf (stderr, "%04x: ", stream->offset);
+ fprintf (stderr, "%s (%d dwords):\n", name, len);
+ fprintf (stderr, "\t0x%08x\n", ptr[j]);
+ BITS (ptr[j], 21, 18, "logicop func");
+ FLAG (ptr[j], 17, "stencil test mask modify-enable");
+ FLAG (ptr[j], 16, "stencil write mask modify-enable");
+ BITS (ptr[j], 15, 8, "stencil test mask");
+ BITS (ptr[j], 7, 0, "stencil write mask");
+ fprintf (stderr, "\n");
+ j++;
+
+ stream->offset += len * sizeof(uint32_t);
+ assert(j == len);
+ return TRUE;
+}
+
+static cairo_bool_t
+debug_map_state (struct debug_stream *stream,
+ const char *name,
+ uint32_t len)
+{
+ uint32_t *ptr = (uint32_t *)(stream->ptr + stream->offset);
+ uint32_t j = 0;
+
+ fprintf (stderr, "%04x: ", stream->offset);
+ fprintf (stderr, "%s (%d dwords):\n", name, len);
+ fprintf (stderr, "\t0x%08x\n", ptr[j++]);
+
+ {
+ fprintf (stderr, "\t0x%08x\n", ptr[j]);
+ BITS (ptr[j], 15, 0, "map mask");
+ j++;
+ }
+
+ while (j < len) {
+ {
+ fprintf (stderr, "\t TMn.0: 0x%08x\n", ptr[j]);
+ fprintf (stderr, "\t map address: 0x%08x\n", (ptr[j] & ~0x3));
+ FLAG (ptr[j], 1, "vertical line stride");
+ FLAG (ptr[j], 0, "vertical line stride offset");
+ j++;
+ }
+
+ {
+ fprintf (stderr, "\t TMn.1: 0x%08x\n", ptr[j]);
+ BITS (ptr[j], 31, 21, "height");
+ BITS (ptr[j], 20, 10, "width");
+ BITS (ptr[j], 9, 7, "surface format");
+ BITS (ptr[j], 6, 3, "texel format");
+ FLAG (ptr[j], 2, "use fence regs");
+ FLAG (ptr[j], 1, "tiled surface");
+ FLAG (ptr[j], 0, "tile walk ymajor");
+ j++;
+ }
+ {
+ fprintf (stderr, "\t TMn.2: 0x%08x\n", ptr[j]);
+ BITS (ptr[j], 31, 21, "dword pitch");
+ BITS (ptr[j], 20, 15, "cube face enables");
+ BITS (ptr[j], 14, 9, "max lod");
+ FLAG (ptr[j], 8, "mip layout right");
+ BITS (ptr[j], 7, 0, "depth");
+ j++;
+ }
+ }
+
+ stream->offset += len * sizeof(uint32_t);
+ assert(j == len);
+ return TRUE;
+}
+
+static cairo_bool_t
+debug_sampler_state (struct debug_stream *stream,
+ const char *name,
+ uint32_t len)
+{
+ uint32_t *ptr = (uint32_t *)(stream->ptr + stream->offset);
+ uint32_t j = 0;
+
+ fprintf (stderr, "%04x: ", stream->offset);
+ fprintf (stderr, "%s (%d dwords):\n", name, len);
+ fprintf (stderr, "\t0x%08x\n", ptr[j++]);
+
+ {
+ fprintf (stderr, "\t0x%08x\n", ptr[j]);
+ BITS (ptr[j], 15, 0, "sampler mask");
+ j++;
+ }
+
+ while (j < len) {
+ {
+ fprintf (stderr, "\t TSn.0: 0x%08x\n", ptr[j]);
+ FLAG (ptr[j], 31, "reverse gamma");
+ FLAG (ptr[j], 30, "planar to packed");
+ FLAG (ptr[j], 29, "yuv->rgb");
+ BITS (ptr[j], 28, 27, "chromakey index");
+ BITS (ptr[j], 26, 22, "base mip level");
+ BITS (ptr[j], 21, 20, "mip mode filter");
+ BITS (ptr[j], 19, 17, "mag mode filter");
+ BITS (ptr[j], 16, 14, "min mode filter");
+ BITS (ptr[j], 13, 5, "lod bias (s4.4)");
+ FLAG (ptr[j], 4, "shadow enable");
+ FLAG (ptr[j], 3, "max-aniso-4");
+ BITS (ptr[j], 2, 0, "shadow func");
+ j++;
+ }
+
+ {
+ fprintf (stderr, "\t TSn.1: 0x%08x\n", ptr[j]);
+ BITS (ptr[j], 31, 24, "min lod");
+ MBZ( ptr[j], 23, 18 );
+ FLAG (ptr[j], 17, "kill pixel enable");
+ FLAG (ptr[j], 16, "keyed tex filter mode");
+ FLAG (ptr[j], 15, "chromakey enable");
+ BITS (ptr[j], 14, 12, "tcx wrap mode");
+ BITS (ptr[j], 11, 9, "tcy wrap mode");
+ BITS (ptr[j], 8, 6, "tcz wrap mode");
+ FLAG (ptr[j], 5, "normalized coords");
+ BITS (ptr[j], 4, 1, "map (surface) index");
+ FLAG (ptr[j], 0, "EAST deinterlacer enable");
+ j++;
+ }
+ {
+ fprintf (stderr, "\t TSn.2: 0x%08x (default color)\n", ptr[j]);
+ j++;
+ }
+ }
+
+ stream->offset += len * sizeof(uint32_t);
+ assert(j == len);
+ return TRUE;
+}
+
+static cairo_bool_t
+debug_dest_vars (struct debug_stream *stream,
+ const char *name,
+ uint32_t len)
+{
+ uint32_t *ptr = (uint32_t *)(stream->ptr + stream->offset);
+ uint32_t j = 0;
+
+ fprintf (stderr, "%04x: ", stream->offset);
+ fprintf (stderr, "%s (%d dwords):\n", name, len);
+ fprintf (stderr, "\t0x%08x\n", ptr[j++]);
+
+ {
+ fprintf (stderr, "\t0x%08x\n", ptr[j]);
+ FLAG (ptr[j], 31, "early classic ztest");
+ FLAG (ptr[j], 30, "opengl tex default color");
+ FLAG (ptr[j], 29, "bypass iz");
+ FLAG (ptr[j], 28, "lod preclamp");
+ BITS (ptr[j], 27, 26, "dither pattern");
+ FLAG (ptr[j], 25, "linear gamma blend");
+ FLAG (ptr[j], 24, "debug dither");
+ BITS (ptr[j], 23, 20, "dstorg x");
+ BITS (ptr[j], 19, 16, "dstorg y");
+ MBZ (ptr[j], 15, 15 );
+ BITS (ptr[j], 14, 12, "422 write select");
+ BITS (ptr[j], 11, 8, "cbuf format");
+ BITS (ptr[j], 3, 2, "zbuf format");
+ FLAG (ptr[j], 1, "vert line stride");
+ FLAG (ptr[j], 1, "vert line stride offset");
+ j++;
+ }
+
+ stream->offset += len * sizeof(uint32_t);
+ assert(j == len);
+ return TRUE;
+}
+
+static cairo_bool_t debug_buf_info( struct debug_stream *stream,
+ const char *name,
+ uint32_t len )
+{
+ uint32_t *ptr = (uint32_t *)(stream->ptr + stream->offset);
+ uint32_t j = 0;
+
+ fprintf (stderr, "%04x: ", stream->offset);
+ fprintf (stderr, "%s (%d dwords):\n", name, len);
+ fprintf (stderr, "\t0x%08x\n", ptr[j++]);
+
+ {
+ fprintf (stderr, "\t0x%08x\n", ptr[j]);
+ BITS (ptr[j], 28, 28, "aux buffer id");
+ BITS (ptr[j], 27, 24, "buffer id (7=depth, 3=back)");
+ FLAG (ptr[j], 23, "use fence regs");
+ FLAG (ptr[j], 22, "tiled surface");
+ FLAG (ptr[j], 21, "tile walk ymajor");
+ MBZ (ptr[j], 20, 14);
+ BITS (ptr[j], 13, 2, "dword pitch");
+ MBZ (ptr[j], 2, 0);
+ j++;
+ }
+
+ fprintf (stderr, "\t0x%08x -- buffer base address\n", ptr[j++]);
+
+ stream->offset += len * sizeof(uint32_t);
+ assert(j == len);
+ return TRUE;
+}
+
+static cairo_bool_t
+decode_3d_i915 (struct debug_stream *stream)
+{
+ uint32_t *ptr = (uint32_t *)(stream->ptr + stream->offset);
+ uint32_t cmd = *ptr;
+
+ switch ((cmd >> 24) & 0x1f) {
+ case 0x6:
+ return debug (stream, "3DSTATE_ANTI_ALIASING", 1);
+ case 0x7:
+ return debug (stream, "3DSTATE_RASTERIZATION_RULES", 1);
+ case 0x8:
+ return debug (stream, "3DSTATE_BACKFACE_STENCIL_OPS", 1);
+ case 0x9:
+ return debug (stream, "3DSTATE_BACKFACE_STENCIL_MASKS", 1);
+ case 0xb:
+ return debug (stream, "3DSTATE_INDEPENDENT_ALPHA_BLEND", 1);
+ case 0xc:
+ return debug (stream, "3DSTATE_MODES5", 1);
+ case 0xd:
+ return debug_modes4(stream, "3DSTATE_MODES4", 1);
+ case 0x15:
+ return debug (stream, "3DSTATE_FOG_COLOR", 1);
+ case 0x16:
+ return debug (stream, "3DSTATE_COORD_SET_BINDINGS", 1);
+ case 0x1c:
+ /* 3DState16NP */
+ switch((cmd >> 19) & 0x1f) {
+ case 0x10:
+ return debug (stream, "3DSTATE_SCISSOR_ENABLE", 1);
+ case 0x11:
+ return debug (stream, "3DSTATE_DEPTH_SUBRECTANGLE_DISABLE", 1);
+ default:
+ break;
+ }
+ break;
+ case 0x1d:
+ /* 3DStateMW */
+ switch ((cmd >> 16) & 0xff) {
+ case 0x0:
+ return debug_map_state(stream, "3DSTATE_MAP_STATE", (cmd & 0x1f) + 2);
+ case 0x1:
+ return debug_sampler_state(stream, "3DSTATE_SAMPLER_STATE", (cmd & 0x1f) + 2);
+ case 0x4:
+ return debug_load_immediate(stream, "3DSTATE_LOAD_STATE_IMMEDIATE", (cmd & 0xf) + 2);
+ case 0x5:
+ return debug_program(stream, "3DSTATE_PIXEL_SHADER_PROGRAM", (cmd & 0x1ff) + 2);
+ case 0x6:
+ return debug (stream, "3DSTATE_PIXEL_SHADER_CONSTANTS", (cmd & 0xff) + 2);
+ case 0x7:
+ return debug_load_indirect(stream, "3DSTATE_LOAD_INDIRECT", (cmd & 0xff) + 2);
+ case 0x80:
+ return debug (stream, "3DSTATE_DRAWING_RECTANGLE", (cmd & 0xffff) + 2);
+ case 0x81:
+ return debug (stream, "3DSTATE_SCISSOR_RECTANGLE", (cmd & 0xffff) + 2);
+ case 0x83:
+ return debug (stream, "3DSTATE_SPAN_STIPPLE", (cmd & 0xffff) + 2);
+ case 0x85:
+ return debug_dest_vars(stream, "3DSTATE_DEST_BUFFER_VARS", (cmd & 0xffff) + 2);
+ case 0x88:
+ return debug (stream, "3DSTATE_CONSTANT_BLEND_COLOR", (cmd & 0xffff) + 2);
+ case 0x89:
+ return debug (stream, "3DSTATE_FOG_MODE", (cmd & 0xffff) + 2);
+ case 0x8e:
+ return debug_buf_info(stream, "3DSTATE_BUFFER_INFO", (cmd & 0xffff) + 2);
+ case 0x97:
+ return debug (stream, "3DSTATE_DEPTH_OFFSET_SCALE", (cmd & 0xffff) + 2);
+ case 0x98:
+ return debug (stream, "3DSTATE_DEFAULT_Z", (cmd & 0xffff) + 2);
+ case 0x99:
+ return debug (stream, "3DSTATE_DEFAULT_DIFFUSE", (cmd & 0xffff) + 2);
+ case 0x9a:
+ return debug (stream, "3DSTATE_DEFAULT_SPECULAR", (cmd & 0xffff) + 2);
+ case 0x9c:
+ return debug (stream, "3DSTATE_CLEAR_PARAMETERS", (cmd & 0xffff) + 2);
+ default:
+ ASSERT_NOT_REACHED;
+ return 0;
+ }
+ break;
+ case 0x1e:
+ if (cmd & (1 << 23))
+ return debug (stream, "???", (cmd & 0xffff) + 1);
+ else
+ return debug (stream, "", 1);
+ break;
+ case 0x1f:
+ if ((cmd & (1 << 23)) == 0) {
+ return debug_prim (stream, "3DPRIM (inline)", 1, (cmd & 0x1ffff) + 2);
+ } else if (cmd & (1 << 17)) {
+ if ((cmd & 0xffff) == 0)
+ return debug_variable_length_prim (stream);
+ else
+ return debug_prim (stream, "3DPRIM (indexed)", 0, (((cmd & 0xffff) + 1) / 2) + 1);
+ } else
+ return debug_prim (stream, "3DPRIM (indirect sequential)", 0, 2);
+ break;
+ default:
+ return debug (stream, "", 0);
+ }
+
+ return FALSE;
+}
+
+static cairo_bool_t
+decode_3d_i965 (struct debug_stream *stream)
+{
+ const uint32_t *data = (uint32_t *) (stream->ptr + stream->offset);
+ const uint32_t opcode = (data[0] & 0xffff0000) >> 16;
+ unsigned int idx;
+ const struct {
+ uint32_t opcode;
+ int min_len;
+ int max_len;
+ const char *name;
+ } opcodes_3d[] = {
+ { 0x6000, 3, 3, "URB_FENCE" },
+ { 0x6001, 2, 2, "CS_URB_STATE" },
+ { 0x6002, 2, 2, "CONSTANT_BUFFER" },
+ { 0x6101, 6, 6, "STATE_BASE_ADDRESS" },
+ { 0x6102, 2, 2 , "STATE_SIP" },
+ { 0x6104, 1, 1, "3DSTATE_PIPELINE_SELECT" },
+ { 0x680b, 1, 1, "3DSTATE_VF_STATISTICS" },
+ { 0x6904, 1, 1, "3DSTATE_PIPELINE_SELECT" },
+ { 0x7800, 7, 7, "3DSTATE_PIPELINED_POINTERS" },
+ { 0x7801, 6, 6, "3DSTATE_BINDING_TABLE_POINTERS" },
+ { 0x780b, 1, 1, "3DSTATE_VF_STATISTICS" },
+ { 0x7808, 5, 257, "3DSTATE_VERTEX_BUFFERS" },
+ { 0x7809, 3, 256, "3DSTATE_VERTEX_ELEMENTS" },
+ { 0x780a, 3, 3, "3DSTATE_INDEX_BUFFER" },
+ { 0x7900, 4, 4, "3DSTATE_DRAWING_RECTANGLE" },
+ { 0x7901, 5, 5, "3DSTATE_CONSTANT_COLOR" },
+ { 0x7905, 5, 7, "3DSTATE_DEPTH_BUFFER" },
+ { 0x7906, 2, 2, "3DSTATE_POLY_STIPPLE_OFFSET" },
+ { 0x7907, 33, 33, "3DSTATE_POLY_STIPPLE_PATTERN" },
+ { 0x7908, 3, 3, "3DSTATE_LINE_STIPPLE" },
+ { 0x7909, 2, 2, "3DSTATE_GLOBAL_DEPTH_OFFSET_CLAMP" },
+ { 0x790a, 3, 3, "3DSTATE_AA_LINE_PARAMETERS" },
+ { 0x7b00, 6, 6, "3DPRIMITIVE" },
+ }, *opcode_3d;
+
+ for (idx = 0; idx < ARRAY_LENGTH (opcodes_3d); idx++) {
+ opcode_3d = &opcodes_3d[idx];
+ if (opcode == opcode_3d->opcode) {
+ unsigned int len = 1;
+ if (opcode_3d->max_len != 1)
+ len = (data[0] & 0x000000ff) + 2;
+ return debug (stream, opcode_3d->name, len);
+ }
+ }
+
+ return FALSE;
+}
+
+static cairo_bool_t
+decode_3d_i830 (struct debug_stream *stream)
+{
+ ASSERT_NOT_REACHED;
+ return FALSE;
+}
+
+static cairo_bool_t
+i915_debug_packet (struct debug_stream *stream,
+ int devid)
+{
+ uint32_t *ptr = (uint32_t *)(stream->ptr + stream->offset);
+ uint32_t cmd = *ptr;
+
+ switch (((cmd >> 29) & 0x7)) {
+ case 0x0:
+ switch ((cmd >> 23) & 0x3f) {
+ case 0x0:
+ return debug (stream, "MI_NOOP", 1);
+ case 0x3:
+ return debug (stream, "MI_WAIT_FOR_EVENT", 1);
+ case 0x4:
+ return debug (stream, "MI_FLUSH", 1);
+ case 0xA:
+ debug (stream, "MI_BATCH_BUFFER_END", 1);
+ return FALSE;
+ case 0x22:
+ return debug (stream, "MI_LOAD_REGISTER_IMM", 3);
+ case 0x31:
+ return debug_chain(stream, "MI_BATCH_BUFFER_START", 2);
+ default:
+ break;
+ }
+ break;
+ case 0x1:
+ break;
+ case 0x2:
+ switch ((cmd >> 22) & 0xff) {
+ case 0x50:
+ return debug_color_blit(stream, "XY_COLOR_BLT", (cmd & 0xff) + 2);
+ case 0x53:
+ return debug_copy_blit(stream, "XY_SRC_COPY_BLT", (cmd & 0xff) + 2);
+ default:
+ return debug (stream, "blit command", (cmd & 0xff) + 2);
+ }
+ break;
+ case 0x3:
+ if (IS_965(devid))
+ return decode_3d_i965 (stream);
+ else if (IS_9XX(devid))
+ return decode_3d_i915 (stream);
+ else
+ return decode_3d_i830 (stream);
+ default:
+ break;
+ }
+
+ fprintf (stderr, "Bogus cmd: %x [%x]\n", (cmd >> 29) & 7, cmd);
+ ASSERT_NOT_REACHED;
+ return 0;
+}
+
+void
+intel_dump_batchbuffer (const void *batch,
+ uint32_t length,
+ int devid)
+{
+ struct debug_stream stream;
+ cairo_bool_t done = FALSE;
+
+ fprintf (stderr, "\nBATCH: (%d dwords)\n", length / 4);
+
+ stream.offset = 0;
+ stream.ptr = batch;
+
+ while (! done && stream.offset < length) {
+ if (! i915_debug_packet (&stream, devid))
+ break;
+
+ assert (stream.offset <= length);
+ }
+
+ fprintf (stderr, "END-BATCH\n\n");
+ fflush (stderr);
+}
diff --git a/src/drm/cairo-drm-intel-ioctl-private.h b/src/drm/cairo-drm-intel-ioctl-private.h
new file mode 100644
index 0000000..74d76b9
--- /dev/null
+++ b/src/drm/cairo-drm-intel-ioctl-private.h
@@ -0,0 +1,417 @@
+/* Cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2009 Chris Wilson
+ *
+ * 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.
+ *
+ */
+
+#ifndef CAIRO_DRM_INTEL_IOCTL_PRIVATE_H
+#define CAIRO_DRM_INTEL_IOCTL_PRIVATE_H
+
+#include "cairo-drm-intel-command-private.h"
+
+/** @{
+ * Intel memory domains
+ *
+ * Most of these just align with the various caches in
+ * the system and are used to flush and invalidate as
+ * objects end up cached in different domains.
+ */
+/** CPU cache */
+#define I915_GEM_DOMAIN_CPU 0x00000001
+/** Render cache, used by 2D and 3D drawing */
+#define I915_GEM_DOMAIN_RENDER 0x00000002
+/** Sampler cache, used by texture engine */
+#define I915_GEM_DOMAIN_SAMPLER 0x00000004
+/** Command queue, used to load batch buffers */
+#define I915_GEM_DOMAIN_COMMAND 0x00000008
+/** Instruction cache, used by shader programs */
+#define I915_GEM_DOMAIN_INSTRUCTION 0x00000010
+/** Vertex address cache */
+#define I915_GEM_DOMAIN_VERTEX 0x00000020
+/** GTT domain - aperture and scanout */
+#define I915_GEM_DOMAIN_GTT 0x00000040
+/** @} */
+
+#define I915_TILING_NONE 0
+#define I915_TILING_X 1
+#define I915_TILING_Y 2
+
+#define I915_BIT_6_SWIZZLE_NONE 0
+#define I915_BIT_6_SWIZZLE_9 1
+#define I915_BIT_6_SWIZZLE_9_10 2
+#define I915_BIT_6_SWIZZLE_9_11 3
+#define I915_BIT_6_SWIZZLE_9_10_11 4
+
+#define DRM_I915_GEM_EXECBUFFER 0x14
+#define DRM_I915_GEM_BUSY 0x17
+#define DRM_I915_GEM_THROTTLE 0x18
+#define DRM_I915_GEM_CREATE 0x1b
+#define DRM_I915_GEM_PREAD 0x1c
+#define DRM_I915_GEM_PWRITE 0x1d
+#define DRM_I915_GEM_MMAP 0x1e
+#define DRM_I915_GEM_SET_DOMAIN 0x1f
+#define DRM_I915_GEM_SET_TILING 0x21
+#define DRM_I915_GEM_GET_TILING 0x22
+#define DRM_I915_GEM_GET_APERTURE 0x23
+#define DRM_I915_GEM_MMAP_GTT 0x24
+
+struct drm_i915_gem_create {
+ /**
+ * Requested size for the object.
+ *
+ * The (page-aligned) allocated size for the object will be returned.
+ */
+ uint64_t size;
+ /**
+ * Returned handle for the object.
+ *
+ * Object handles are nonzero.
+ */
+ uint32_t handle;
+ uint32_t pad;
+};
+
+struct drm_i915_gem_pread {
+ /** Handle for the object being read. */
+ uint32_t handle;
+ uint32_t pad;
+ /** Offset into the object to read from */
+ uint64_t offset;
+ /** Length of data to read */
+ uint64_t size;
+ /**
+ * Pointer to write the data into.
+ *
+ * This is a fixed-size type for 32/64 compatibility.
+ */
+ uint64_t data_ptr;
+};
+
+struct drm_i915_gem_pwrite {
+ /** Handle for the object being written to. */
+ uint32_t handle;
+ uint32_t pad;
+ /** Offset into the object to write to */
+ uint64_t offset;
+ /** Length of data to write */
+ uint64_t size;
+ /**
+ * Pointer to read the data from.
+ *
+ * This is a fixed-size type for 32/64 compatibility.
+ */
+ uint64_t data_ptr;
+};
+
+struct drm_i915_gem_mmap {
+ /** Handle for the object being mapped. */
+ uint32_t handle;
+ uint32_t pad;
+ /** Offset in the object to map. */
+ uint64_t offset;
+ /**
+ * Length of data to map.
+ *
+ * The value will be page-aligned.
+ */
+ uint64_t size;
+ /**
+ * Returned pointer the data was mapped at.
+ *
+ * This is a fixed-size type for 32/64 compatibility.
+ */
+ uint64_t addr_ptr;
+};
+
+struct drm_i915_gem_mmap_gtt {
+ /** Handle for the object being mapped. */
+ uint32_t handle;
+ uint32_t pad;
+ /**
+ * Fake offset to use for subsequent mmap call
+ *
+ * This is a fixed-size type for 32/64 compatibility.
+ */
+ uint64_t offset;
+};
+
+struct drm_i915_gem_set_domain {
+ /** Handle for the object */
+ uint32_t handle;
+
+ /** New read domains */
+ uint32_t read_domains;
+
+ /** New write domain */
+ uint32_t write_domain;
+};
+
+struct drm_i915_gem_relocation_entry {
+ /**
+ * Handle of the buffer being pointed to by this relocation entry.
+ *
+ * It's appealing to make this be an index into the mm_validate_entry
+ * list to refer to the buffer, but this allows the driver to create
+ * a relocation list for state buffers and not re-write it per
+ * exec using the buffer.
+ */
+ uint32_t target_handle;
+
+ /**
+ * Value to be added to the offset of the target buffer to make up
+ * the relocation entry.
+ */
+ uint32_t delta;
+
+ /** Offset in the buffer the relocation entry will be written into */
+ uint64_t offset;
+
+ /**
+ * Offset value of the target buffer that the relocation entry was last
+ * written as.
+ *
+ * If the buffer has the same offset as last time, we can skip syncing
+ * and writing the relocation. This value is written back out by
+ * the execbuffer ioctl when the relocation is written.
+ */
+ uint64_t presumed_offset;
+
+ /**
+ * Target memory domains read by this operation.
+ */
+ uint32_t read_domains;
+
+ /**
+ * Target memory domains written by this operation.
+ *
+ * Note that only one domain may be written by the whole
+ * execbuffer operation, so that where there are conflicts,
+ * the application will get -EINVAL back.
+ */
+ uint32_t write_domain;
+};
+
+struct drm_i915_gem_exec_object {
+ /**
+ * User's handle for a buffer to be bound into the GTT for this
+ * operation.
+ */
+ uint32_t handle;
+
+ /** Number of relocations to be performed on this buffer */
+ uint32_t relocation_count;
+ /**
+ * Pointer to array of struct drm_i915_gem_relocation_entry containing
+ * the relocations to be performed in this buffer.
+ */
+ uint64_t relocs_ptr;
+
+ /** Required alignment in graphics aperture */
+ uint64_t alignment;
+
+ /**
+ * Returned value of the updated offset of the object, for future
+ * presumed_offset writes.
+ */
+ uint64_t offset;
+};
+
+struct drm_i915_gem_execbuffer {
+ /**
+ * List of buffers to be validated with their relocations to be
+ * performend on them.
+ *
+ * This is a pointer to an array of struct drm_i915_gem_validate_entry.
+ *
+ * These buffers must be listed in an order such that all relocations
+ * a buffer is performing refer to buffers that have already appeared
+ * in the validate list.
+ */
+ uint64_t buffers_ptr;
+ uint32_t buffer_count;
+
+ /** Offset in the batchbuffer to start execution from. */
+ uint32_t batch_start_offset;
+ /** Bytes used in batchbuffer from batch_start_offset */
+ uint32_t batch_len;
+ uint32_t DR1;
+ uint32_t DR4;
+ uint32_t num_cliprects;
+ /** This is a struct drm_clip_rect *cliprects */
+ uint64_t cliprects_ptr;
+};
+
+struct drm_i915_gem_busy {
+ /** Handle of the buffer to check for busy */
+ uint32_t handle;
+
+ /** Return busy status (1 if busy, 0 if idle) */
+ uint32_t busy;
+};
+
+struct drm_i915_gem_set_tiling {
+ /** Handle of the buffer to have its tiling state updated */
+ uint32_t handle;
+
+ /**
+ * Tiling mode for the object (I915_TILING_NONE, I915_TILING_X,
+ * I915_TILING_Y).
+ *
+ * This value is to be set on request, and will be updated by the
+ * kernel on successful return with the actual chosen tiling layout.
+ *
+ * The tiling mode may be demoted to I915_TILING_NONE when the system
+ * has bit 6 swizzling that can't be managed correctly by GEM.
+ *
+ * Buffer contents become undefined when changing tiling_mode.
+ */
+ uint32_t tiling_mode;
+
+ /**
+ * Stride in bytes for the object when in I915_TILING_X or
+ * I915_TILING_Y.
+ */
+ uint32_t stride;
+
+ /**
+ * Returned address bit 6 swizzling required for CPU access through
+ * mmap mapping.
+ */
+ uint32_t swizzle_mode;
+};
+
+struct drm_i915_gem_get_tiling {
+ /** Handle of the buffer to get tiling state for. */
+ uint32_t handle;
+
+ /**
+ * Current tiling mode for the object (I915_TILING_NONE, I915_TILING_X,
+ * I915_TILING_Y).
+ */
+ uint32_t tiling_mode;
+
+ /**
+ * Returned address bit 6 swizzling required for CPU access through
+ * mmap mapping.
+ */
+ uint32_t swizzle_mode;
+};
+
+struct drm_i915_gem_get_aperture {
+ /** Total size of the aperture used by i915_gem_execbuffer, in bytes */
+ uint64_t aper_size;
+
+ /**
+ * Available space in the aperture used by i915_gem_execbuffer, in
+ * bytes
+ */
+ uint64_t aper_available_size;
+};
+
+
+#define DRM_IOCTL_I915_GEM_EXECBUFFER DRM_IOW(DRM_COMMAND_BASE + DRM_I915_GEM_EXECBUFFER, struct drm_i915_gem_execbuffer)
+#define DRM_IOCTL_I915_GEM_BUSY DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_BUSY, struct drm_i915_gem_busy)
+#define DRM_IOCTL_I915_GEM_THROTTLE DRM_IO ( DRM_COMMAND_BASE + DRM_I915_GEM_THROTTLE)
+#define DRM_IOCTL_I915_GEM_CREATE DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_CREATE, struct drm_i915_gem_create)
+#define DRM_IOCTL_I915_GEM_PREAD DRM_IOW (DRM_COMMAND_BASE + DRM_I915_GEM_PREAD, struct drm_i915_gem_pread)
+#define DRM_IOCTL_I915_GEM_PWRITE DRM_IOW (DRM_COMMAND_BASE + DRM_I915_GEM_PWRITE, struct drm_i915_gem_pwrite)
+#define DRM_IOCTL_I915_GEM_MMAP DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_MMAP, struct drm_i915_gem_mmap)
+#define DRM_IOCTL_I915_GEM_MMAP_GTT DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_MMAP_GTT, struct drm_i915_gem_mmap_gtt)
+#define DRM_IOCTL_I915_GEM_SET_DOMAIN DRM_IOW (DRM_COMMAND_BASE + DRM_I915_GEM_SET_DOMAIN, struct drm_i915_gem_set_domain)
+#define DRM_IOCTL_I915_GEM_SET_TILING DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_GEM_SET_TILING, struct drm_i915_gem_set_tiling)
+#define DRM_IOCTL_I915_GEM_GET_TILING DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_GEM_GET_TILING, struct drm_i915_gem_get_tiling)
+#define DRM_IOCTL_I915_GEM_GET_APERTURE DRM_IOR (DRM_COMMAND_BASE + DRM_I915_GEM_GET_APERTURE, struct drm_i915_gem_get_aperture)
+
+#define I915_MADV_WILLNEED 0
+#define I915_MADV_DONTNEED 1
+
+struct drm_i915_gem_madvise {
+ uint32_t handle;
+ uint32_t madv;
+ uint32_t retained;
+};
+#define DRM_I915_GEM_MADVISE 0x26
+#define DRM_IOCTL_I915_GEM_MADVISE DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_GEM_MADVISE, struct drm_i915_gem_madvise)
+
+
+/* XXX execbuffer2 */
+struct drm_i915_gem_exec_object2 {
+ /**
+ * User's handle for a buffer to be bound into the GTT for this
+ * operation.
+ */
+ uint32_t handle;
+
+ /** Number of relocations to be performed on this buffer */
+ uint32_t relocation_count;
+ /**
+ * Pointer to array of struct drm_i915_gem_relocation_entry containing
+ * the relocations to be performed in this buffer.
+ */
+ uint64_t relocs_ptr;
+
+ /** Required alignment in graphics aperture */
+ uint64_t alignment;
+
+ /**
+ * Returned value of the updated offset of the object, for future
+ * presumed_offset writes.
+ */
+ uint64_t offset;
+
+#define EXEC_OBJECT_NEEDS_FENCE (1<<0)
+ uint64_t flags;
+ uint64_t rsvd1;
+ uint64_t rsvd2;
+};
+
+struct drm_i915_gem_execbuffer2 {
+ /**
+ * List of gem_exec_object2 structs
+ */
+ uint64_t buffers_ptr;
+ uint32_t buffer_count;
+
+ /** Offset in the batchbuffer to start execution from. */
+ uint32_t batch_start_offset;
+ /** Bytes used in batchbuffer from batch_start_offset */
+ uint32_t batch_len;
+ uint32_t DR1;
+ uint32_t DR4;
+ uint32_t num_cliprects;
+ /** This is a struct drm_clip_rect *cliprects */
+ uint64_t cliprects_ptr;
+ uint64_t flags;
+ uint64_t rsvd1;
+ uint64_t rsvd2;
+};
+
+#define I915_GEM_3D_PIPELINE 0x1
+#define I915_GEM_MEDIA_PIPELINE 0x2
+#define DRM_I915_GEM_EXECBUFFER2 0x29
+#define DRM_IOCTL_I915_GEM_EXECBUFFER2 DRM_IOW(DRM_COMMAND_BASE + DRM_I915_GEM_EXECBUFFER2, struct drm_i915_gem_execbuffer2)
+
+#endif /* CAIRO_DRM_INTEL_IOCTL_PRIVATE_H */
diff --git a/src/drm/cairo-drm-intel-private.h b/src/drm/cairo-drm-intel-private.h
index f5791f3..eedb700 100644
--- a/src/drm/cairo-drm-intel-private.h
+++ b/src/drm/cairo-drm-intel-private.h
@@ -30,51 +30,30 @@
#ifndef CAIRO_DRM_INTEL_PRIVATE_H
#define CAIRO_DRM_INTEL_PRIVATE_H
+#include "cairoint.h"
+#include "cairo-cache-private.h"
#include "cairo-compiler-private.h"
-#include "cairo-types-private.h"
#include "cairo-drm-private.h"
-#include "cairo-list-private.h"
#include "cairo-freelist-private.h"
+#include "cairo-list-private.h"
#include "cairo-mutex-private.h"
+#include "cairo-rtree-private.h"
+#include "cairo-types-private.h"
-/** @{
- * Intel memory domains
- *
- * Most of these just align with the various caches in
- * the system and are used to flush and invalidate as
- * objects end up cached in different domains.
- */
-/** CPU cache */
-#define I915_GEM_DOMAIN_CPU 0x00000001
-/** Render cache, used by 2D and 3D drawing */
-#define I915_GEM_DOMAIN_RENDER 0x00000002
-/** Sampler cache, used by texture engine */
-#define I915_GEM_DOMAIN_SAMPLER 0x00000004
-/** Command queue, used to load batch buffers */
-#define I915_GEM_DOMAIN_COMMAND 0x00000008
-/** Instruction cache, used by shader programs */
-#define I915_GEM_DOMAIN_INSTRUCTION 0x00000010
-/** Vertex address cache */
-#define I915_GEM_DOMAIN_VERTEX 0x00000020
-/** GTT domain - aperture and scanout */
-#define I915_GEM_DOMAIN_GTT 0x00000040
-/** @} */
-
-#define I915_TILING_NONE 0
-#define I915_TILING_X 1
-#define I915_TILING_Y 2
-
-#define I915_BIT_6_SWIZZLE_NONE 0
-#define I915_BIT_6_SWIZZLE_9 1
-#define I915_BIT_6_SWIZZLE_9_10 2
-#define I915_BIT_6_SWIZZLE_9_11 3
-#define I915_BIT_6_SWIZZLE_9_10_11 4
+#include "cairo-drm-intel-ioctl-private.h"
+
+#define NEAREST_BIAS (-.375)
#define INTEL_TILING_DEFAULT I915_TILING_Y
#define INTEL_BO_CACHE_BUCKETS 12 /* cache surfaces up to 16 MiB */
+#define INTEL_GLYPH_CACHE_WIDTH 1024
+#define INTEL_GLYPH_CACHE_HEIGHT 1024
+#define INTEL_GLYPH_CACHE_MIN_SIZE 1
+#define INTEL_GLYPH_CACHE_MAX_SIZE 128
+
typedef struct _intel_bo {
cairo_drm_bo_t base;
@@ -86,12 +65,125 @@ typedef struct _intel_bo {
uint32_t tiling;
uint32_t swizzle;
uint32_t stride;
+ cairo_bool_t purgeable;
+
+ uint32_t opaque0;
+ uint32_t opaque1;
- cairo_bool_t in_batch;
- uint32_t read_domains;
- uint32_t write_domain;
+ struct drm_i915_gem_exec_object2 *exec;
+ uint32_t batch_read_domains;
+ uint32_t batch_write_domain;
+
+ cairo_list_t link;
} intel_bo_t;
+#define INTEL_BATCH_SIZE (64*1024)
+#define INTEL_VERTEX_BUFFER_SIZE (512*1024)
+#define INTEL_MAX_RELOCS 2048
+
+static inline void
+intel_bo_mark_purgeable (intel_bo_t *bo,
+ cairo_bool_t purgeable)
+{
+ if (bo->base.name == 0)
+ bo->purgeable = purgeable;
+}
+
+typedef struct _intel_vertex_buffer intel_vertex_buffer_t;
+
+typedef void (*intel_vertex_buffer_new_func_t) (intel_vertex_buffer_t *vertex_buffer);
+typedef void (*intel_vertex_buffer_start_rectangles_func_t) (intel_vertex_buffer_t *vertex_buffer,
+ uint32_t floats_per_vertex);
+typedef void (*intel_vertex_buffer_flush_func_t) (intel_vertex_buffer_t *vertex_buffer);
+typedef void (*intel_vertex_buffer_finish_func_t) (intel_vertex_buffer_t *vertex_buffer);
+
+struct _intel_vertex_buffer {
+ uint32_t vbo_batch; /* reloc position in batch, 0 -> not yet allocated */
+ uint32_t vbo_offset;
+ uint32_t vbo_used;
+
+ uint32_t vertex_index;
+ uint32_t vertex_count;
+
+ uint32_t floats_per_vertex;
+ uint32_t rectangle_size;
+
+ intel_bo_t *last_vbo;
+ uint32_t last_vbo_offset;
+ uint32_t last_vbo_space;
+
+ intel_vertex_buffer_new_func_t new;
+ intel_vertex_buffer_start_rectangles_func_t start_rectangles;
+ intel_vertex_buffer_flush_func_t flush;
+ intel_vertex_buffer_finish_func_t finish;
+
+ uint32_t base[INTEL_VERTEX_BUFFER_SIZE / sizeof (uint32_t)];
+};
+
+typedef struct _intel_batch intel_batch_t;
+
+typedef void (*intel_batch_commit_func_t) (intel_batch_t *batch);
+typedef void (*intel_batch_reset_func_t) (intel_batch_t *batch);
+
+struct _intel_batch {
+ size_t gtt_size;
+ size_t gtt_avail_size;
+
+ intel_batch_commit_func_t commit;
+ intel_batch_reset_func_t reset;
+
+ uint16_t exec_count;
+ uint16_t reloc_count;
+ uint16_t used;
+ uint16_t header;
+
+ intel_bo_t *target_bo[INTEL_MAX_RELOCS];
+ struct drm_i915_gem_exec_object2 exec[INTEL_MAX_RELOCS];
+ struct drm_i915_gem_relocation_entry reloc[INTEL_MAX_RELOCS];
+
+ uint32_t base[INTEL_BATCH_SIZE / sizeof (uint32_t)];
+
+ intel_vertex_buffer_t vertex_buffer;
+};
+
+typedef struct _intel_buffer {
+ intel_bo_t *bo;
+ uint32_t offset;
+ cairo_format_t format;
+ uint32_t map0, map1;
+ uint32_t width;
+ uint32_t height;
+ uint32_t stride;
+} intel_buffer_t;
+
+typedef struct _intel_buffer_cache {
+ int ref_count;
+ intel_buffer_t buffer;
+ cairo_rtree_t rtree;
+ cairo_list_t link;
+} intel_buffer_cache_t;
+
+typedef struct _intel_glyph {
+ cairo_rtree_node_t node;
+ intel_buffer_cache_t *cache;
+ void **owner;
+ float texcoord[3];
+} intel_glyph_t;
+
+typedef struct _intel_gradient_cache {
+ cairo_pattern_union_t pattern;
+ intel_buffer_t buffer;
+} intel_gradient_cache_t;
+#define GRADIENT_CACHE_SIZE 16
+
+typedef struct _intel_surface {
+ cairo_drm_surface_t drm;
+
+ cairo_cache_entry_t snapshot_cache_entry;
+} intel_surface_t;
+
+typedef void (*intel_reset_context_func_t) (void *device);
+
typedef struct _intel_device {
cairo_drm_device_t base;
@@ -108,8 +200,54 @@ typedef struct _intel_device {
size_t bo_cache_size;
size_t bo_max_cache_size_high;
size_t bo_max_cache_size_low;
+
+ cairo_mutex_t mutex;
+ intel_batch_t batch;
+
+ cairo_bool_t glyph_cache_mapped;
+ intel_buffer_cache_t glyph_cache[2];
+
+ struct {
+ intel_gradient_cache_t cache[GRADIENT_CACHE_SIZE];
+ unsigned int size;
+ } gradient_cache;
+
+ cairo_cache_t snapshot_cache;
+ size_t snapshot_cache_max_size;
+
+ intel_reset_context_func_t reset_context;
+
+ cairo_status_t (*flush) (struct _intel_device *);
} intel_device_t;
+static inline intel_device_t *
+to_intel_device (cairo_device_t *base)
+{
+ return (intel_device_t *) base;
+}
+
+static inline intel_bo_t *
+to_intel_bo (cairo_drm_bo_t *base)
+{
+ return (intel_bo_t *) base;
+}
+
+static inline intel_bo_t *
+intel_bo_reference (intel_bo_t *bo)
+{
+ return to_intel_bo (cairo_drm_bo_reference (&bo->base));
+}
+
+cairo_private cairo_bool_t
+intel_bo_madvise (intel_device_t *device, intel_bo_t *bo, int madv);
+
+
+static always_inline void
+intel_bo_destroy (intel_device_t *device, intel_bo_t *bo)
+{
+ cairo_drm_bo_destroy (&device->base.base, &bo->base);
+}
+
cairo_private cairo_bool_t
intel_info (int fd, uint64_t *gtt_size);
@@ -119,23 +257,27 @@ intel_device_init (intel_device_t *device, int fd);
cairo_private void
intel_device_fini (intel_device_t *dev);
-cairo_private cairo_drm_bo_t *
+cairo_private intel_bo_t *
intel_bo_create (intel_device_t *dev,
uint32_t size,
cairo_bool_t gpu_target);
-cairo_private void
-intel_bo_release (void *_dev, void *_bo);
-
-cairo_private cairo_drm_bo_t *
+cairo_private intel_bo_t *
intel_bo_create_for_name (intel_device_t *dev, uint32_t name);
cairo_private void
-intel_bo_set_tiling (intel_device_t *dev,
+intel_bo_set_tiling (const intel_device_t *dev,
intel_bo_t *bo,
uint32_t tiling,
uint32_t stride);
+cairo_private cairo_bool_t
+intel_bo_is_inactive (const intel_device_t *device,
+ const intel_bo_t *bo);
+
+cairo_private void
+intel_bo_wait (const intel_device_t *device, const intel_bo_t *bo);
+
cairo_private void
intel_bo_write (const intel_device_t *dev,
intel_bo_t *bo,
@@ -150,9 +292,6 @@ intel_bo_read (const intel_device_t *dev,
unsigned long size,
void *data);
-cairo_private void
-intel_bo_wait (const intel_device_t *dev, intel_bo_t *bo);
-
cairo_private void *
intel_bo_map (const intel_device_t *dev, intel_bo_t *bo);
@@ -176,7 +315,203 @@ intel_bo_get_image (const intel_device_t *device,
intel_bo_t *bo,
const cairo_drm_surface_t *surface);
+cairo_private cairo_status_t
+intel_bo_put_image (intel_device_t *dev,
+ intel_bo_t *bo, int stride,
+ cairo_image_surface_t *src,
+ int src_x, int src_y,
+ int width, int height,
+ int dst_x, int dst_y);
+
+cairo_private void
+intel_surface_init (intel_surface_t *surface,
+ const cairo_surface_backend_t *backend,
+ cairo_drm_device_t *device,
+ cairo_content_t content);
+
+cairo_private cairo_status_t
+intel_buffer_cache_init (intel_buffer_cache_t *cache,
+ intel_device_t *device,
+ cairo_format_t format,
+ int width, int height);
+
+cairo_private cairo_status_t
+intel_gradient_render (intel_device_t *device,
+ const cairo_gradient_pattern_t *pattern,
+ intel_buffer_t *buffer);
+
+cairo_private cairo_int_status_t
+intel_get_glyph (intel_device_t *device,
+ cairo_scaled_font_t *scaled_font,
+ cairo_scaled_glyph_t *scaled_glyph);
+
+cairo_private void
+intel_scaled_glyph_fini (cairo_scaled_glyph_t *scaled_glyph,
+ cairo_scaled_font_t *scaled_font);
+
+cairo_private void
+intel_scaled_font_fini (cairo_scaled_font_t *scaled_font);
+
+cairo_private void
+intel_glyph_cache_unmap (intel_device_t *device);
+
+cairo_private void
+intel_glyph_cache_unpin (intel_device_t *device);
+
+static inline intel_glyph_t *
+intel_glyph_pin (intel_glyph_t *glyph)
+{
+ cairo_rtree_node_t *node = &glyph->node;
+ if (unlikely (node->pinned == 0))
+ return _cairo_rtree_pin (&glyph->cache->rtree, node);
+ return glyph;
+}
+
+cairo_private cairo_status_t
+intel_snapshot_cache_insert (intel_device_t *device,
+ intel_surface_t *surface);
+
+cairo_private void
+intel_surface_detach_snapshot (cairo_surface_t *abstract_surface);
+
+cairo_private void
+intel_snapshot_cache_thaw (intel_device_t *device);
+
cairo_private void
intel_throttle (intel_device_t *device);
+cairo_private cairo_status_t
+intel_surface_acquire_source_image (void *abstract_surface,
+ cairo_image_surface_t **image_out,
+ void **image_extra);
+
+cairo_private void
+intel_surface_release_source_image (void *abstract_surface,
+ cairo_image_surface_t *image,
+ void *image_extra);
+cairo_private cairo_surface_t *
+intel_surface_map_to_image (void *abstract_surface);
+
+cairo_private cairo_status_t
+intel_surface_flush (void *abstract_surface);
+
+cairo_private cairo_status_t
+intel_surface_finish (void *abstract_surface);
+
+cairo_private void
+intel_dump_batchbuffer (const void *batch,
+ uint32_t length,
+ int devid);
+
+static inline float cairo_const
+texcoord_2d_16 (double x, double y)
+{
+ union {
+ uint32_t ui;
+ float f;
+ } u;
+ u.ui = (_cairo_half_from_float (y) << 16) | _cairo_half_from_float (x);
+ return u.f;
+}
+
+static inline uint32_t cairo_const
+MS3_tiling (uint32_t tiling)
+{
+ switch (tiling) {
+ default:
+ case I915_TILING_NONE: return 0;
+ case I915_TILING_X: return MS3_TILED_SURFACE;
+ case I915_TILING_Y: return MS3_TILED_SURFACE | MS3_TILE_WALK;
+ }
+}
+
+#define PCI_CHIP_I810 0x7121
+#define PCI_CHIP_I810_DC100 0x7123
+#define PCI_CHIP_I810_E 0x7125
+#define PCI_CHIP_I815 0x1132
+
+#define PCI_CHIP_I830_M 0x3577
+#define PCI_CHIP_845_G 0x2562
+#define PCI_CHIP_I855_GM 0x3582
+#define PCI_CHIP_I865_G 0x2572
+
+#define PCI_CHIP_I915_G 0x2582
+#define PCI_CHIP_E7221_G 0x258A
+#define PCI_CHIP_I915_GM 0x2592
+#define PCI_CHIP_I945_G 0x2772
+#define PCI_CHIP_I945_GM 0x27A2
+#define PCI_CHIP_I945_GME 0x27AE
+
+#define PCI_CHIP_Q35_G 0x29B2
+#define PCI_CHIP_G33_G 0x29C2
+#define PCI_CHIP_Q33_G 0x29D2
+
+#define PCI_CHIP_IGD_GM 0xA011
+#define PCI_CHIP_IGD_G 0xA001
+
+#define IS_IGDGM(devid) (devid == PCI_CHIP_IGD_GM)
+#define IS_IGDG(devid) (devid == PCI_CHIP_IGD_G)
+#define IS_IGD(devid) (IS_IGDG(devid) || IS_IGDGM(devid))
+
+#define PCI_CHIP_I965_G 0x29A2
+#define PCI_CHIP_I965_Q 0x2992
+#define PCI_CHIP_I965_G_1 0x2982
+#define PCI_CHIP_I946_GZ 0x2972
+#define PCI_CHIP_I965_GM 0x2A02
+#define PCI_CHIP_I965_GME 0x2A12
+
+#define PCI_CHIP_GM45_GM 0x2A42
+
+#define PCI_CHIP_IGD_E_G 0x2E02
+#define PCI_CHIP_Q45_G 0x2E12
+#define PCI_CHIP_G45_G 0x2E22
+#define PCI_CHIP_G41_G 0x2E32
+
+#define PCI_CHIP_ILD_G 0x0042
+#define PCI_CHIP_ILM_G 0x0046
+
+#define IS_MOBILE(devid) (devid == PCI_CHIP_I855_GM || \
+ devid == PCI_CHIP_I915_GM || \
+ devid == PCI_CHIP_I945_GM || \
+ devid == PCI_CHIP_I945_GME || \
+ devid == PCI_CHIP_I965_GM || \
+ devid == PCI_CHIP_I965_GME || \
+ devid == PCI_CHIP_GM45_GM || IS_IGD(devid))
+
+#define IS_G45(devid) (devid == PCI_CHIP_IGD_E_G || \
+ devid == PCI_CHIP_Q45_G || \
+ devid == PCI_CHIP_G45_G || \
+ devid == PCI_CHIP_G41_G)
+#define IS_GM45(devid) (devid == PCI_CHIP_GM45_GM)
+#define IS_G4X(devid) (IS_G45(devid) || IS_GM45(devid))
+
+#define IS_ILD(devid) (devid == PCI_CHIP_ILD_G)
+#define IS_ILM(devid) (devid == PCI_CHIP_ILM_G)
+#define IS_IRONLAKE(devid) (IS_ILD(devid) || IS_ILM(devid))
+
+#define IS_915(devid) (devid == PCI_CHIP_I915_G || \
+ devid == PCI_CHIP_E7221_G || \
+ devid == PCI_CHIP_I915_GM)
+
+#define IS_945(devid) (devid == PCI_CHIP_I945_G || \
+ devid == PCI_CHIP_I945_GM || \
+ devid == PCI_CHIP_I945_GME || \
+ devid == PCI_CHIP_G33_G || \
+ devid == PCI_CHIP_Q33_G || \
+ devid == PCI_CHIP_Q35_G || IS_IGD(devid))
+
+#define IS_965(devid) (devid == PCI_CHIP_I965_G || \
+ devid == PCI_CHIP_I965_Q || \
+ devid == PCI_CHIP_I965_G_1 || \
+ devid == PCI_CHIP_I965_GM || \
+ devid == PCI_CHIP_I965_GME || \
+ devid == PCI_CHIP_I946_GZ || \
+ IS_G4X(devid) || \
+ IS_IRONLAKE(devid))
+
+#define IS_9XX(devid) (IS_915(devid) || \
+ IS_945(devid) || \
+ IS_965(devid))
+
+
#endif /* CAIRO_DRM_INTEL_PRIVATE_H */
diff --git a/src/drm/cairo-drm-intel-surface.c b/src/drm/cairo-drm-intel-surface.c
index e9e1cac..5b7c60b 100644
--- a/src/drm/cairo-drm-intel-surface.c
+++ b/src/drm/cairo-drm-intel-surface.c
@@ -31,84 +31,66 @@
#include "cairo-drm-private.h"
#include "cairo-drm-intel-private.h"
+
#include "cairo-error-private.h"
/* Basic generic/stub surface for intel chipsets */
#define MAX_SIZE 2048
-typedef struct _intel_surface intel_surface_t;
-
-struct _intel_surface {
- cairo_drm_surface_t base;
-};
-
-static inline intel_device_t *
-to_intel_device (cairo_drm_device_t *device)
-{
- return (intel_device_t *) device;
-}
-
-static inline intel_bo_t *
-to_intel_bo (cairo_drm_bo_t *bo)
-{
- return (intel_bo_t *) bo;
-}
-
-static cairo_status_t
-intel_batch_flush (intel_device_t *device)
-{
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-intel_surface_batch_flush (intel_surface_t *surface)
+static cairo_surface_t *
+intel_surface_create_similar (void *abstract_surface,
+ cairo_content_t content,
+ int width,
+ int height)
{
- if (to_intel_bo (surface->base.bo)->write_domain)
- return intel_batch_flush (to_intel_device (surface->base.device));
-
- return CAIRO_STATUS_SUCCESS;
+ return cairo_image_surface_create (_cairo_format_from_content (content),
+ width, height);
}
-static cairo_status_t
+cairo_status_t
intel_surface_finish (void *abstract_surface)
{
intel_surface_t *surface = abstract_surface;
- return _cairo_drm_surface_finish (&surface->base);
+ return _cairo_drm_surface_finish (&surface->drm);
}
-static cairo_status_t
+cairo_status_t
intel_surface_acquire_source_image (void *abstract_surface,
- cairo_image_surface_t **image_out,
- void **image_extra)
+ cairo_image_surface_t **image_out,
+ void **image_extra)
{
intel_surface_t *surface = abstract_surface;
cairo_surface_t *image;
cairo_status_t status;
- if (surface->base.fallback != NULL) {
- image = surface->base.fallback;
+ /* XXX batch flush */
+
+ if (surface->drm.fallback != NULL) {
+ image = surface->drm.fallback;
goto DONE;
}
- image = _cairo_surface_has_snapshot (&surface->base.base,
+ image = _cairo_surface_has_snapshot (&surface->drm.base,
&_cairo_image_surface_backend);
if (image != NULL)
goto DONE;
- status = intel_surface_batch_flush (surface);
- if (unlikely (status))
- return status;
+ if (surface->drm.base.backend->flush != NULL) {
+ status = surface->drm.base.backend->flush (surface);
+ if (unlikely (status))
+ return status;
+ }
- image = intel_bo_get_image (to_intel_device (surface->base.device),
- to_intel_bo (surface->base.bo),
- &surface->base);
+ image = intel_bo_get_image (to_intel_device (surface->drm.base.device),
+ to_intel_bo (surface->drm.bo),
+ &surface->drm);
status = image->status;
if (unlikely (status))
return status;
- status = _cairo_surface_attach_snapshot (&surface->base.base,
+ status = _cairo_surface_attach_snapshot (&surface->drm.base,
image,
cairo_surface_destroy);
if (unlikely (status)) {
@@ -122,7 +104,7 @@ DONE:
return CAIRO_STATUS_SUCCESS;
}
-static void
+void
intel_surface_release_source_image (void *abstract_surface,
cairo_image_surface_t *image,
void *image_extra)
@@ -130,180 +112,200 @@ intel_surface_release_source_image (void *abstract_surface,
cairo_surface_destroy (&image->base);
}
-static cairo_surface_t *
-intel_surface_snapshot (void *abstract_surface)
+cairo_surface_t *
+intel_surface_map_to_image (void *abstract_surface)
{
intel_surface_t *surface = abstract_surface;
- cairo_status_t status;
- if (surface->base.fallback != NULL)
- return NULL;
+ if (surface->drm.fallback == NULL) {
+ cairo_surface_t *image;
+ cairo_status_t status;
+ void *ptr;
- status = intel_surface_batch_flush (surface);
- if (unlikely (status))
- return _cairo_surface_create_in_error (status);
+ if (surface->drm.base.backend->flush != NULL) {
+ status = surface->drm.base.backend->flush (surface);
+ if (unlikely (status))
+ return _cairo_surface_create_in_error (status);
+ }
+
+ ptr = intel_bo_map (to_intel_device (surface->drm.base.device),
+ to_intel_bo (surface->drm.bo));
+ if (unlikely (ptr == NULL))
+ return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
+
+ image = cairo_image_surface_create_for_data (ptr,
+ surface->drm.format,
+ surface->drm.width,
+ surface->drm.height,
+ surface->drm.stride);
+ if (unlikely (image->status)) {
+ intel_bo_unmap (to_intel_bo (surface->drm.bo));
+ return image;
+ }
+
+ surface->drm.fallback = image;
+ }
- return intel_bo_get_image (to_intel_device (surface->base.device),
- to_intel_bo (surface->base.bo),
- &surface->base);
+ return surface->drm.fallback;
}
-static cairo_status_t
-intel_surface_acquire_dest_image (void *abstract_surface,
- cairo_rectangle_int_t *interest_rect,
- cairo_image_surface_t **image_out,
- cairo_rectangle_int_t *image_rect_out,
- void **image_extra)
+cairo_status_t
+intel_surface_flush (void *abstract_surface)
{
intel_surface_t *surface = abstract_surface;
- cairo_surface_t *image;
cairo_status_t status;
- void *ptr;
- assert (surface->base.fallback == NULL);
+ if (surface->drm.fallback == NULL)
+ return CAIRO_STATUS_SUCCESS;
- status = intel_surface_batch_flush (surface);
- if (unlikely (status))
- return status;
-
- /* Force a read barrier, as well as flushing writes above */
- if (to_intel_bo (surface->base.bo)->in_batch) {
- status = intel_batch_flush (to_intel_device (surface->base.device));
- if (unlikely (status))
- return status;
- }
-
- ptr = intel_bo_map (to_intel_device (surface->base.device),
- to_intel_bo (surface->base.bo));
- if (unlikely (ptr == NULL))
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
- image = cairo_image_surface_create_for_data (ptr,
- surface->base.format,
- surface->base.width,
- surface->base.height,
- surface->base.stride);
- status = image->status;
- if (unlikely (status)) {
- intel_bo_unmap (to_intel_bo (surface->base.bo));
- return status;
- }
-
- surface->base.fallback = cairo_surface_reference (image);
+ /* kill any outstanding maps */
+ cairo_surface_finish (surface->drm.fallback);
- *image_out = (cairo_image_surface_t *) image;
- *image_extra = NULL;
+ status = cairo_surface_status (surface->drm.fallback);
+ cairo_surface_destroy (surface->drm.fallback);
+ surface->drm.fallback = NULL;
- image_rect_out->x = 0;
- image_rect_out->y = 0;
- image_rect_out->width = surface->base.width;
- image_rect_out->height = surface->base.height;
+ intel_bo_unmap (to_intel_bo (surface->drm.bo));
- return CAIRO_STATUS_SUCCESS;
+ return status;
}
-static void
-intel_surface_release_dest_image (void *abstract_surface,
- cairo_rectangle_int_t *interest_rect,
- cairo_image_surface_t *image,
- cairo_rectangle_int_t *image_rect,
- void *image_extra)
+static cairo_int_status_t
+intel_surface_paint (void *abstract_surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_clip_t *clip)
{
- /* Keep the fallback until we flush, either explicitly or at the
- * end of this context. The idea is to avoid excess migration of
- * the buffer between GPU and CPU domains.
- */
- cairo_surface_destroy (&image->base);
+ return _cairo_surface_paint (intel_surface_map_to_image (abstract_surface),
+ op, source, clip);
}
-static cairo_status_t
-intel_surface_flush (void *abstract_surface)
+static cairo_int_status_t
+intel_surface_mask (void *abstract_surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ const cairo_pattern_t *mask,
+ cairo_clip_t *clip)
{
- intel_surface_t *surface = abstract_surface;
- cairo_status_t status;
-
- if (surface->base.fallback == NULL)
- return intel_surface_batch_flush (surface);
-
- /* kill any outstanding maps */
- cairo_surface_finish (surface->base.fallback);
+ return _cairo_surface_mask (intel_surface_map_to_image (abstract_surface),
+ op, source, mask, clip);
+}
- status = cairo_surface_status (surface->base.fallback);
- cairo_surface_destroy (surface->base.fallback);
- surface->base.fallback = NULL;
+static cairo_int_status_t
+intel_surface_stroke (void *abstract_surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_path_fixed_t *path,
+ const cairo_stroke_style_t *stroke_style,
+ const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm_inverse,
+ double tolerance,
+ cairo_antialias_t antialias,
+ cairo_clip_t *clip)
+{
+ return _cairo_surface_stroke (intel_surface_map_to_image (abstract_surface),
+ op, source, path, stroke_style, ctm, ctm_inverse,
+ tolerance, antialias, clip);
+}
- intel_bo_unmap (to_intel_bo (surface->base.bo));
+static cairo_int_status_t
+intel_surface_fill (void *abstract_surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_path_fixed_t *path,
+ cairo_fill_rule_t fill_rule,
+ double tolerance,
+ cairo_antialias_t antialias,
+ cairo_clip_t *clip)
+{
+ return _cairo_surface_fill (intel_surface_map_to_image (abstract_surface),
+ op, source, path, fill_rule,
+ tolerance, antialias, clip);
+}
- return status;
+static cairo_int_status_t
+intel_surface_glyphs (void *abstract_surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_scaled_font_t *scaled_font,
+ cairo_clip_t *clip,
+ int *num_remaining)
+{
+ *num_remaining = 0;
+ return _cairo_surface_show_text_glyphs (intel_surface_map_to_image (abstract_surface),
+ op, source,
+ NULL, 0,
+ glyphs, num_glyphs,
+ NULL, 0, 0,
+ scaled_font, clip);
}
static const cairo_surface_backend_t intel_surface_backend = {
CAIRO_SURFACE_TYPE_DRM,
- _cairo_drm_surface_create_similar,
- intel_surface_finish,
+ intel_surface_create_similar,
+ intel_surface_finish,
intel_surface_acquire_source_image,
intel_surface_release_source_image,
- intel_surface_acquire_dest_image,
- intel_surface_release_dest_image,
-
- NULL, //intel_surface_clone_similar,
- NULL, //intel_surface_composite,
- NULL, //intel_surface_fill_rectangles,
- NULL, //intel_surface_composite_trapezoids,
- NULL, //intel_surface_create_span_renderer,
- NULL, //intel_surface_check_span_renderer,
+ NULL, NULL, NULL,
+ NULL, /* composite */
+ NULL, /* fill */
+ NULL, /* trapezoids */
+ NULL, /* span */
+ NULL, /* check-span */
+
NULL, /* copy_page */
NULL, /* show_page */
_cairo_drm_surface_get_extents,
- NULL, /* old_show_glyphs */
+ NULL, /* old-glyphs */
_cairo_drm_surface_get_font_options,
- intel_surface_flush,
- NULL, /* mark_dirty_rectangle */
- NULL, //intel_surface_scaled_font_fini,
- NULL, //intel_surface_scaled_glyph_fini,
-
- _cairo_drm_surface_paint,
- _cairo_drm_surface_mask,
- _cairo_drm_surface_stroke,
- _cairo_drm_surface_fill,
- _cairo_drm_surface_show_glyphs,
- intel_surface_snapshot,
-
- NULL, /* is_similar */
+ intel_surface_flush,
+ NULL, /* mark dirty */
+ NULL, NULL, /* font/glyph fini */
+
+ intel_surface_paint,
+ intel_surface_mask,
+ intel_surface_stroke,
+ intel_surface_fill,
+ intel_surface_glyphs,
};
-static void
+void
intel_surface_init (intel_surface_t *surface,
- cairo_content_t content,
- cairo_drm_device_t *device)
+ const cairo_surface_backend_t *backend,
+ cairo_drm_device_t *device,
+ cairo_content_t content)
{
- _cairo_surface_init (&surface->base.base,
- &intel_surface_backend,
- NULL, /* device */
+ _cairo_surface_init (&surface->drm.base,
+ backend,
+ &device->base,
content);
- _cairo_drm_surface_init (&surface->base, device);
+ _cairo_drm_surface_init (&surface->drm, device);
switch (content) {
case CAIRO_CONTENT_ALPHA:
- surface->base.format = CAIRO_FORMAT_A8;
+ surface->drm.format = CAIRO_FORMAT_A8;
break;
case CAIRO_CONTENT_COLOR:
- surface->base.format = CAIRO_FORMAT_RGB24;
+ surface->drm.format = CAIRO_FORMAT_RGB24;
break;
default:
ASSERT_NOT_REACHED;
case CAIRO_CONTENT_COLOR_ALPHA:
- surface->base.format = CAIRO_FORMAT_ARGB32;
+ surface->drm.format = CAIRO_FORMAT_ARGB32;
break;
}
+
+ surface->snapshot_cache_entry.hash = 0;
}
static cairo_surface_t *
-intel_surface_create_internal (cairo_drm_device_t *device,
- cairo_content_t content,
- int width, int height)
+intel_surface_create (cairo_drm_device_t *device,
+ cairo_content_t content,
+ int width, int height)
{
intel_surface_t *surface;
cairo_status_t status;
@@ -312,36 +314,28 @@ intel_surface_create_internal (cairo_drm_device_t *device,
if (unlikely (surface == NULL))
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
- intel_surface_init (surface, content, device);
+ intel_surface_init (surface, &intel_surface_backend, device, content);
if (width && height) {
- surface->base.width = width;
- surface->base.height = height;
+ surface->drm.width = width;
+ surface->drm.height = height;
/* Vol I, p134: size restrictions for textures */
width = (width + 3) & -4;
height = (height + 1) & -2;
- surface->base.stride =
- cairo_format_stride_for_width (surface->base.format, width);
- surface->base.bo = intel_bo_create (to_intel_device (device),
- surface->base.stride * height,
- TRUE);
- if (surface->base.bo == NULL) {
- status = _cairo_drm_surface_finish (&surface->base);
+ surface->drm.stride =
+ cairo_format_stride_for_width (surface->drm.format, width);
+ surface->drm.bo = &intel_bo_create (to_intel_device (&device->base),
+ surface->drm.stride * height,
+ TRUE)->base;
+ if (surface->drm.bo == NULL) {
+ status = _cairo_drm_surface_finish (&surface->drm);
free (surface);
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
}
}
- return &surface->base.base;
-}
-
-static cairo_surface_t *
-intel_surface_create (cairo_drm_device_t *device,
- cairo_content_t content,
- int width, int height)
-{
- return intel_surface_create_internal (device, content, width, height);
+ return &surface->drm.base;
}
static cairo_surface_t *
@@ -376,46 +370,41 @@ intel_surface_create_for_name (cairo_drm_device_t *device,
if (unlikely (surface == NULL))
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
- intel_surface_init (surface, content, device);
+ intel_surface_init (surface, &intel_surface_backend, device, content);
if (width && height) {
- surface->base.width = width;
- surface->base.height = height;
- surface->base.stride = stride;
-
- surface->base.bo = intel_bo_create_for_name (to_intel_device (device),
- name);
- if (unlikely (surface->base.bo == NULL)) {
- status = _cairo_drm_surface_finish (&surface->base);
+ surface->drm.width = width;
+ surface->drm.height = height;
+ surface->drm.stride = stride;
+
+ surface->drm.bo = &intel_bo_create_for_name (to_intel_device (&device->base),
+ name)->base;
+ if (unlikely (surface->drm.bo == NULL)) {
+ status = _cairo_drm_surface_finish (&surface->drm);
free (surface);
return _cairo_surface_create_in_error (_cairo_error
(CAIRO_STATUS_NO_MEMORY));
}
}
- return &surface->base.base;
+ return &surface->drm.base;
}
static cairo_status_t
intel_surface_enable_scan_out (void *abstract_surface)
{
intel_surface_t *surface = abstract_surface;
- cairo_status_t status;
- if (unlikely (surface->base.bo == NULL))
+ if (unlikely (surface->drm.bo == NULL))
return _cairo_error (CAIRO_STATUS_INVALID_SIZE);
- status = intel_surface_batch_flush (surface);
- if (unlikely (status))
- return status;
-
- if (to_intel_bo (surface->base.bo)->tiling == I915_TILING_Y) {
- intel_bo_set_tiling (to_intel_device (surface->base.device),
- to_intel_bo (surface->base.bo),
- I915_TILING_X, surface->base.stride);
+ if (to_intel_bo (surface->drm.bo)->tiling == I915_TILING_Y) {
+ intel_bo_set_tiling (to_intel_device (surface->drm.base.device),
+ to_intel_bo (surface->drm.bo),
+ I915_TILING_X, surface->drm.stride);
}
- if (unlikely (to_intel_bo (surface->base.bo)->tiling == I915_TILING_Y))
+ if (unlikely (to_intel_bo (surface->drm.bo)->tiling == I915_TILING_Y))
return _cairo_error (CAIRO_STATUS_INVALID_FORMAT); /* XXX */
return CAIRO_STATUS_SUCCESS;
@@ -424,13 +413,7 @@ intel_surface_enable_scan_out (void *abstract_surface)
static cairo_int_status_t
intel_device_throttle (cairo_drm_device_t *device)
{
- cairo_status_t status;
-
- status = intel_batch_flush (to_intel_device (device));
- if (unlikely (status))
- return status;
-
- intel_throttle (to_intel_device (device));
+ intel_throttle (to_intel_device (&device->base));
return CAIRO_STATUS_SUCCESS;
}
@@ -455,24 +438,28 @@ _cairo_drm_intel_device_create (int fd, dev_t dev, int vendor_id, int chip_id)
device = malloc (sizeof (intel_device_t));
if (unlikely (device == NULL))
- return _cairo_drm_device_create_in_error (CAIRO_STATUS_NO_MEMORY);
+ return (cairo_drm_device_t *) _cairo_device_create_in_error (CAIRO_STATUS_NO_MEMORY);
status = intel_device_init (device, fd);
if (unlikely (status)) {
free (device);
- return _cairo_drm_device_create_in_error (status);
+ return (cairo_drm_device_t *) _cairo_device_create_in_error (status);
}
- device->base.bo.release = intel_bo_release;
-
device->base.surface.create = intel_surface_create;
device->base.surface.create_for_name = intel_surface_create_for_name;
device->base.surface.create_from_cacheable_image = NULL;
device->base.surface.flink = _cairo_drm_surface_flink;
device->base.surface.enable_scan_out = intel_surface_enable_scan_out;
+ device->base.surface.map_to_image = intel_surface_map_to_image;
+
+ device->base.device.flush = NULL;
device->base.device.throttle = intel_device_throttle;
device->base.device.destroy = intel_device_destroy;
- return _cairo_drm_device_init (&device->base, fd, dev, MAX_SIZE);
+ return _cairo_drm_device_init (&device->base,
+ fd, dev,
+ vendor_id, chip_id,
+ MAX_SIZE);
}
diff --git a/src/drm/cairo-drm-intel.c b/src/drm/cairo-drm-intel.c
index 6c8a8fd..7cbbb16 100644
--- a/src/drm/cairo-drm-intel.c
+++ b/src/drm/cairo-drm-intel.c
@@ -32,6 +32,8 @@
#include "cairo-drm-private.h"
#include "cairo-drm-ioctl-private.h"
#include "cairo-drm-intel-private.h"
+#include "cairo-drm-intel-ioctl-private.h"
+
#include "cairo-error-private.h"
#include "cairo-freelist-private.h"
@@ -39,300 +41,13 @@
#include <sys/mman.h>
#include <errno.h>
-#define DRM_I915_GEM_EXECBUFFER 0x14
-#define DRM_I915_GEM_BUSY 0x17
-#define DRM_I915_GEM_THROTTLE 0x18
-#define DRM_I915_GEM_CREATE 0x1b
-#define DRM_I915_GEM_PREAD 0x1c
-#define DRM_I915_GEM_PWRITE 0x1d
-#define DRM_I915_GEM_MMAP 0x1e
-#define DRM_I915_GEM_SET_DOMAIN 0x1f
-#define DRM_I915_GEM_SET_TILING 0x21
-#define DRM_I915_GEM_GET_TILING 0x22
-#define DRM_I915_GEM_GET_APERTURE 0x23
-#define DRM_I915_GEM_MMAP_GTT 0x24
-
-struct drm_i915_gem_create {
- /**
- * Requested size for the object.
- *
- * The (page-aligned) allocated size for the object will be returned.
- */
- uint64_t size;
- /**
- * Returned handle for the object.
- *
- * Object handles are nonzero.
- */
- uint32_t handle;
- uint32_t pad;
-};
-
-struct drm_i915_gem_pread {
- /** Handle for the object being read. */
- uint32_t handle;
- uint32_t pad;
- /** Offset into the object to read from */
- uint64_t offset;
- /** Length of data to read */
- uint64_t size;
- /**
- * Pointer to write the data into.
- *
- * This is a fixed-size type for 32/64 compatibility.
- */
- uint64_t data_ptr;
-};
-
-struct drm_i915_gem_pwrite {
- /** Handle for the object being written to. */
- uint32_t handle;
- uint32_t pad;
- /** Offset into the object to write to */
- uint64_t offset;
- /** Length of data to write */
- uint64_t size;
- /**
- * Pointer to read the data from.
- *
- * This is a fixed-size type for 32/64 compatibility.
- */
- uint64_t data_ptr;
-};
-
-struct drm_i915_gem_mmap {
- /** Handle for the object being mapped. */
- uint32_t handle;
- uint32_t pad;
- /** Offset in the object to map. */
- uint64_t offset;
- /**
- * Length of data to map.
- *
- * The value will be page-aligned.
- */
- uint64_t size;
- /**
- * Returned pointer the data was mapped at.
- *
- * This is a fixed-size type for 32/64 compatibility.
- */
- uint64_t addr_ptr;
-};
-
-struct drm_i915_gem_mmap_gtt {
- /** Handle for the object being mapped. */
- uint32_t handle;
- uint32_t pad;
- /**
- * Fake offset to use for subsequent mmap call
- *
- * This is a fixed-size type for 32/64 compatibility.
- */
- uint64_t offset;
-};
-
-struct drm_i915_gem_set_domain {
- /** Handle for the object */
- uint32_t handle;
-
- /** New read domains */
- uint32_t read_domains;
-
- /** New write domain */
- uint32_t write_domain;
-};
-
-struct drm_i915_gem_relocation_entry {
- /**
- * Handle of the buffer being pointed to by this relocation entry.
- *
- * It's appealing to make this be an index into the mm_validate_entry
- * list to refer to the buffer, but this allows the driver to create
- * a relocation list for state buffers and not re-write it per
- * exec using the buffer.
- */
- uint32_t target_handle;
-
- /**
- * Value to be added to the offset of the target buffer to make up
- * the relocation entry.
- */
- uint32_t delta;
-
- /** Offset in the buffer the relocation entry will be written into */
- uint64_t offset;
-
- /**
- * Offset value of the target buffer that the relocation entry was last
- * written as.
- *
- * If the buffer has the same offset as last time, we can skip syncing
- * and writing the relocation. This value is written back out by
- * the execbuffer ioctl when the relocation is written.
- */
- uint64_t presumed_offset;
-
- /**
- * Target memory domains read by this operation.
- */
- uint32_t read_domains;
-
- /**
- * Target memory domains written by this operation.
- *
- * Note that only one domain may be written by the whole
- * execbuffer operation, so that where there are conflicts,
- * the application will get -EINVAL back.
- */
- uint32_t write_domain;
-};
-
-struct drm_i915_gem_exec_object {
- /**
- * User's handle for a buffer to be bound into the GTT for this
- * operation.
- */
- uint32_t handle;
-
- /** Number of relocations to be performed on this buffer */
- uint32_t relocation_count;
- /**
- * Pointer to array of struct drm_i915_gem_relocation_entry containing
- * the relocations to be performed in this buffer.
- */
- uint64_t relocs_ptr;
-
- /** Required alignment in graphics aperture */
- uint64_t alignment;
-
- /**
- * Returned value of the updated offset of the object, for future
- * presumed_offset writes.
- */
- uint64_t offset;
-};
-
-struct drm_i915_gem_execbuffer {
- /**
- * List of buffers to be validated with their relocations to be
- * performend on them.
- *
- * This is a pointer to an array of struct drm_i915_gem_validate_entry.
- *
- * These buffers must be listed in an order such that all relocations
- * a buffer is performing refer to buffers that have already appeared
- * in the validate list.
- */
- uint64_t buffers_ptr;
- uint32_t buffer_count;
-
- /** Offset in the batchbuffer to start execution from. */
- uint32_t batch_start_offset;
- /** Bytes used in batchbuffer from batch_start_offset */
- uint32_t batch_len;
- uint32_t DR1;
- uint32_t DR4;
- uint32_t num_cliprects;
- /** This is a struct drm_clip_rect *cliprects */
- uint64_t cliprects_ptr;
-};
-
-struct drm_i915_gem_busy {
- /** Handle of the buffer to check for busy */
- uint32_t handle;
-
- /** Return busy status (1 if busy, 0 if idle) */
- uint32_t busy;
-};
-
-struct drm_i915_gem_set_tiling {
- /** Handle of the buffer to have its tiling state updated */
- uint32_t handle;
-
- /**
- * Tiling mode for the object (I915_TILING_NONE, I915_TILING_X,
- * I915_TILING_Y).
- *
- * This value is to be set on request, and will be updated by the
- * kernel on successful return with the actual chosen tiling layout.
- *
- * The tiling mode may be demoted to I915_TILING_NONE when the system
- * has bit 6 swizzling that can't be managed correctly by GEM.
- *
- * Buffer contents become undefined when changing tiling_mode.
- */
- uint32_t tiling_mode;
-
- /**
- * Stride in bytes for the object when in I915_TILING_X or
- * I915_TILING_Y.
- */
- uint32_t stride;
-
- /**
- * Returned address bit 6 swizzling required for CPU access through
- * mmap mapping.
- */
- uint32_t swizzle_mode;
-};
-
-struct drm_i915_gem_get_tiling {
- /** Handle of the buffer to get tiling state for. */
- uint32_t handle;
-
- /**
- * Current tiling mode for the object (I915_TILING_NONE, I915_TILING_X,
- * I915_TILING_Y).
- */
- uint32_t tiling_mode;
-
- /**
- * Returned address bit 6 swizzling required for CPU access through
- * mmap mapping.
- */
- uint32_t swizzle_mode;
-};
-
-struct drm_i915_gem_get_aperture {
- /** Total size of the aperture used by i915_gem_execbuffer, in bytes */
- uint64_t aper_size;
-
- /**
- * Available space in the aperture used by i915_gem_execbuffer, in
- * bytes
- */
- uint64_t aper_available_size;
-};
-
-
-#define DRM_IOCTL_I915_GEM_EXECBUFFER DRM_IOW(DRM_COMMAND_BASE + DRM_I915_GEM_EXECBUFFER, struct drm_i915_gem_execbuffer)
-#define DRM_IOCTL_I915_GEM_BUSY DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_BUSY, struct drm_i915_gem_busy)
-#define DRM_IOCTL_I915_GEM_THROTTLE DRM_IO ( DRM_COMMAND_BASE + DRM_I915_GEM_THROTTLE)
-#define DRM_IOCTL_I915_GEM_CREATE DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_CREATE, struct drm_i915_gem_create)
-#define DRM_IOCTL_I915_GEM_PREAD DRM_IOW (DRM_COMMAND_BASE + DRM_I915_GEM_PREAD, struct drm_i915_gem_pread)
-#define DRM_IOCTL_I915_GEM_PWRITE DRM_IOW (DRM_COMMAND_BASE + DRM_I915_GEM_PWRITE, struct drm_i915_gem_pwrite)
-#define DRM_IOCTL_I915_GEM_MMAP DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_MMAP, struct drm_i915_gem_mmap)
-#define DRM_IOCTL_I915_GEM_MMAP_GTT DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_MMAP_GTT, struct drm_i915_gem_mmap_gtt)
-#define DRM_IOCTL_I915_GEM_SET_DOMAIN DRM_IOW (DRM_COMMAND_BASE + DRM_I915_GEM_SET_DOMAIN, struct drm_i915_gem_set_domain)
-#define DRM_IOCTL_I915_GEM_SET_TILING DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_GEM_SET_TILING, struct drm_i915_gem_set_tiling)
-#define DRM_IOCTL_I915_GEM_GET_TILING DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_GEM_GET_TILING, struct drm_i915_gem_get_tiling)
-#define DRM_IOCTL_I915_GEM_GET_APERTURE DRM_IOR (DRM_COMMAND_BASE + DRM_I915_GEM_GET_APERTURE, struct drm_i915_gem_get_aperture)
-
-/* XXX madvise */
-#ifndef DRM_I915_GEM_MADVISE
-#define I915_MADV_WILLNEED 0
-#define I915_MADV_DONTNEED 1
-
-struct drm_i915_gem_madvise {
- uint32_t handle;
- uint32_t madv;
- uint32_t retained;
-};
-#define DRM_I915_GEM_MADVISE 0x26
-#define DRM_IOCTL_I915_GEM_MADVISE DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_GEM_MADVISE, struct drm_i915_gem_madvise)
-#endif
+#define GLYPH_CACHE_WIDTH 1024
+#define GLYPH_CACHE_HEIGHT 1024
+#define GLYPH_CACHE_MIN_SIZE 1
+#define GLYPH_CACHE_MAX_SIZE 128
+#define IMAGE_CACHE_WIDTH 1024
+#define IMAGE_CACHE_HEIGHT 1024
cairo_bool_t
intel_info (int fd, uint64_t *gtt_size)
@@ -453,12 +168,14 @@ intel_bo_map (const intel_device_t *device, intel_bo_t *bo)
do {
ret = ioctl (device->base.fd,
- DRM_IOCTL_I915_GEM_SET_DOMAIN, &set_domain);
+ DRM_IOCTL_I915_GEM_SET_DOMAIN,
+ &set_domain);
} while (ret == -1 && errno == EINTR);
if (ret != 0) {
- _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
- return NULL;
+ intel_bo_unmap (bo);
+ _cairo_error_throw (CAIRO_STATUS_DEVICE_ERROR);
+ return NULL;
}
return bo->virtual;
@@ -471,7 +188,7 @@ intel_bo_unmap (intel_bo_t *bo)
bo->virtual = NULL;
}
-static cairo_bool_t
+cairo_bool_t
intel_bo_is_inactive (const intel_device_t *device, const intel_bo_t *bo)
{
struct drm_i915_gem_busy busy;
@@ -484,6 +201,21 @@ intel_bo_is_inactive (const intel_device_t *device, const intel_bo_t *bo)
return ! busy.busy;
}
+void
+intel_bo_wait (const intel_device_t *device, const intel_bo_t *bo)
+{
+ struct drm_i915_gem_set_domain set_domain;
+ int ret;
+
+ set_domain.handle = bo->base.handle;
+ set_domain.read_domains = I915_GEM_DOMAIN_GTT;
+ set_domain.write_domain = 0;
+
+ do {
+ ret = ioctl (device->base.fd, DRM_IOCTL_I915_GEM_SET_DOMAIN, &set_domain);
+ } while (ret == -1 && errno == EINTR);
+}
+
static inline int
pot (int v)
{
@@ -515,7 +247,7 @@ intel_bo_cache_remove (intel_device_t *device,
_cairo_freepool_free (&device->bo_pool, bo);
}
-static cairo_bool_t
+cairo_bool_t
intel_bo_madvise (intel_device_t *device,
intel_bo_t *bo,
int advice)
@@ -548,7 +280,7 @@ intel_bo_cache_purge (intel_device_t *device)
}
}
-cairo_drm_bo_t *
+intel_bo_t *
intel_bo_create (intel_device_t *device,
uint32_t size,
cairo_bool_t gpu_target)
@@ -584,18 +316,19 @@ intel_bo_create (intel_device_t *device,
* cause serialisation...
*/
- if (! intel_bo_madvise (device, bo, I915_MADV_WILLNEED)) {
- intel_bo_cache_remove (device, bo, bucket);
- goto retry;
- }
-
if (device->bo_cache[bucket].num_entries-- >
- device->bo_cache[bucket].min_entries)
+ device->bo_cache[bucket].min_entries)
{
device->bo_cache_size -= bo->base.size;
}
cairo_list_del (&bo->cache_list);
- CAIRO_MUTEX_UNLOCK (device->bo_mutex);
+
+ if (! intel_bo_madvise (device, bo, I915_MADV_WILLNEED)) {
+ _cairo_drm_bo_close (&device->base, &bo->base);
+ _cairo_freepool_free (&device->bo_pool, bo);
+ goto retry;
+ }
+
goto DONE;
}
@@ -608,18 +341,19 @@ intel_bo_create (intel_device_t *device,
bo = cairo_list_first_entry (&device->bo_cache[bucket].list,
intel_bo_t, cache_list);
if (intel_bo_is_inactive (device, bo)) {
- if (! intel_bo_madvise (device, bo, I915_MADV_WILLNEED)) {
- intel_bo_cache_remove (device, bo, bucket);
- goto retry;
- }
-
if (device->bo_cache[bucket].num_entries-- >
device->bo_cache[bucket].min_entries)
{
device->bo_cache_size -= bo->base.size;
}
cairo_list_del (&bo->cache_list);
- CAIRO_MUTEX_UNLOCK (device->bo_mutex);
+
+ if (! intel_bo_madvise (device, bo, I915_MADV_WILLNEED)) {
+ _cairo_drm_bo_close (&device->base, &bo->base);
+ _cairo_freepool_free (&device->bo_pool, bo);
+ goto retry;
+ }
+
goto DONE;
}
}
@@ -646,10 +380,9 @@ intel_bo_create (intel_device_t *device,
/* no cached buffer available, allocate fresh */
bo = _cairo_freepool_alloc (&device->bo_pool);
- CAIRO_MUTEX_UNLOCK (device->bo_mutex);
if (unlikely (bo == NULL)) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
- return NULL;
+ goto UNLOCK;
}
cairo_list_init (&bo->cache_list);
@@ -663,29 +396,37 @@ intel_bo_create (intel_device_t *device,
bo->tiling = I915_TILING_NONE;
bo->stride = 0;
bo->swizzle = I915_BIT_6_SWIZZLE_NONE;
+ bo->purgeable = 0;
+
+ bo->opaque0 = 0;
+ bo->opaque1 = 0;
- bo->in_batch = FALSE;
- bo->read_domains = 0;
- bo->write_domain = 0;
+ bo->exec = NULL;
+ bo->batch_read_domains = 0;
+ bo->batch_write_domain = 0;
+ cairo_list_init (&bo->link);
create.size = size;
create.handle = 0;
ret = ioctl (device->base.fd, DRM_IOCTL_I915_GEM_CREATE, &create);
if (unlikely (ret != 0)) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
- free (bo);
- return NULL;
+ _cairo_freepool_free (&device->bo_pool, bo);
+ bo = NULL;
+ goto UNLOCK;
}
bo->base.handle = create.handle;
DONE:
CAIRO_REFERENCE_COUNT_INIT (&bo->base.ref_count, 1);
+UNLOCK:
+ CAIRO_MUTEX_UNLOCK (device->bo_mutex);
- return &bo->base;
+ return bo;
}
-cairo_drm_bo_t *
+intel_bo_t *
intel_bo_create_for_name (intel_device_t *device, uint32_t name)
{
struct drm_i915_gem_get_tiling get_tiling;
@@ -702,40 +443,48 @@ intel_bo_create_for_name (intel_device_t *device, uint32_t name)
}
status = _cairo_drm_bo_open_for_name (&device->base, &bo->base, name);
- if (unlikely (status)) {
- _cairo_freepool_free (&device->bo_pool, bo);
- return NULL;
- }
+ if (unlikely (status))
+ goto FAIL;
CAIRO_REFERENCE_COUNT_INIT (&bo->base.ref_count, 1);
cairo_list_init (&bo->cache_list);
bo->offset = 0;
bo->virtual = NULL;
+ bo->purgeable = 0;
+
+ bo->opaque0 = 0;
+ bo->opaque1 = 0;
- bo->in_batch = FALSE;
- bo->read_domains = 0;
- bo->write_domain = 0;
+ bo->exec = NULL;
+ bo->batch_read_domains = 0;
+ bo->batch_write_domain = 0;
+ cairo_list_init (&bo->link);
memset (&get_tiling, 0, sizeof (get_tiling));
get_tiling.handle = bo->base.handle;
ret = ioctl (device->base.fd, DRM_IOCTL_I915_GEM_GET_TILING, &get_tiling);
if (unlikely (ret != 0)) {
- _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
+ _cairo_error_throw (CAIRO_STATUS_DEVICE_ERROR);
_cairo_drm_bo_close (&device->base, &bo->base);
- _cairo_freepool_free (&device->bo_pool, bo);
- return NULL;
+ goto FAIL;
}
bo->tiling = get_tiling.tiling_mode;
bo->swizzle = get_tiling.swizzle_mode;
// bo->stride = get_tiling.stride; /* XXX not available from get_tiling */
- return &bo->base;
+ return bo;
+
+FAIL:
+ CAIRO_MUTEX_LOCK (device->bo_mutex);
+ _cairo_freepool_free (&device->bo_pool, bo);
+ CAIRO_MUTEX_UNLOCK (device->bo_mutex);
+ return NULL;
}
-void
+static void
intel_bo_release (void *_dev, void *_bo)
{
intel_device_t *device = _dev;
@@ -747,7 +496,10 @@ intel_bo_release (void *_dev, void *_bo)
bucket = ffs (bo->base.size / 4096) - 1;
CAIRO_MUTEX_LOCK (device->bo_mutex);
- if (bo->base.name == 0 && bucket < INTEL_BO_CACHE_BUCKETS) {
+ if (bo->base.name == 0 &&
+ bucket < INTEL_BO_CACHE_BUCKETS &&
+ intel_bo_madvise (device, bo, I915_MADV_DONTNEED))
+ {
if (++device->bo_cache[bucket].num_entries >
device->bo_cache[bucket].min_entries)
{
@@ -755,8 +507,6 @@ intel_bo_release (void *_dev, void *_bo)
}
cairo_list_add_tail (&bo->cache_list, &device->bo_cache[bucket].list);
-
- intel_bo_madvise (device, bo, I915_MADV_DONTNEED);
}
else
{
@@ -767,7 +517,7 @@ intel_bo_release (void *_dev, void *_bo)
}
void
-intel_bo_set_tiling (intel_device_t *device,
+intel_bo_set_tiling (const intel_device_t *device,
intel_bo_t *bo,
uint32_t tiling,
uint32_t stride)
@@ -781,7 +531,7 @@ intel_bo_set_tiling (intel_device_t *device,
return;
}
- assert (! bo->in_batch);
+ assert (bo->exec == NULL);
if (bo->virtual)
intel_bo_unmap (bo);
@@ -790,7 +540,9 @@ intel_bo_set_tiling (intel_device_t *device,
set_tiling.tiling_mode = tiling;
set_tiling.stride = stride;
- ret = ioctl (device->base.fd, DRM_IOCTL_I915_GEM_SET_TILING, &set_tiling);
+ do {
+ ret = ioctl (device->base.fd, DRM_IOCTL_I915_GEM_SET_TILING, &set_tiling);
+ } while (ret == -1 && errno == EINTR);
if (ret == 0) {
bo->tiling = set_tiling.tiling_mode;
bo->swizzle = set_tiling.swizzle_mode;
@@ -859,6 +611,148 @@ intel_bo_get_image (const intel_device_t *device,
return &image->base;
}
+static cairo_status_t
+_intel_bo_put_a1_image (intel_device_t *dev,
+ intel_bo_t *bo, int stride,
+ cairo_image_surface_t *src,
+ int src_x, int src_y,
+ int width, int height,
+ int dst_x, int dst_y)
+{
+ uint8_t buf[CAIRO_STACK_BUFFER_SIZE];
+ uint8_t *a8 = buf;
+ uint8_t *data;
+ int x;
+
+ data = src->data + src_y * src->stride;
+
+ if (bo->tiling == I915_TILING_NONE && width == stride) {
+ uint8_t *p;
+ int size;
+
+ size = stride * height;
+ if (size > (int) sizeof (buf)) {
+ a8 = _cairo_malloc_ab (stride, height);
+ if (a8 == NULL)
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ }
+
+ p = a8;
+ while (height--) {
+ for (x = 0; x < width; x++) {
+ int i = src_x + x;
+ int byte = i / 8;
+ int bit = i % 8;
+ p[x] = data[byte] & (1 << bit) ? 0xff : 0x00;
+ }
+
+ data += src->stride;
+ p += stride;
+ }
+
+ intel_bo_write (dev, bo,
+ dst_y * stride + dst_x, /* XXX bo_offset */
+ size, a8);
+ } else {
+ uint8_t *dst;
+
+ if (width > (int) sizeof (buf)) {
+ a8 = malloc (width);
+ if (a8 == NULL)
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ }
+
+ dst = intel_bo_map (dev, bo);
+ if (dst == NULL) {
+ if (a8 != buf)
+ free (a8);
+ return _cairo_error (CAIRO_STATUS_DEVICE_ERROR);
+ }
+
+ dst += dst_y * stride + dst_x; /* XXX bo_offset */
+ while (height--) {
+ for (x = 0; x < width; x++) {
+ int i = src_x + x;
+ int byte = i / 8;
+ int bit = i % 8;
+ a8[x] = data[byte] & (1 << bit) ? 0xff : 0x00;
+ }
+
+ memcpy (dst, a8, width);
+ dst += stride;
+ data += src->stride;
+ }
+ intel_bo_unmap (bo);
+ }
+
+ if (a8 != buf)
+ free (a8);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+cairo_status_t
+intel_bo_put_image (intel_device_t *dev,
+ intel_bo_t *bo, int stride,
+ cairo_image_surface_t *src,
+ int src_x, int src_y,
+ int width, int height,
+ int dst_x, int dst_y)
+{
+ uint8_t *data;
+ int size;
+ int offset;
+
+ offset = dst_y * stride;
+ data = src->data + src_y * src->stride;
+ switch (src->format) {
+ default:
+ case CAIRO_FORMAT_ARGB32:
+ case CAIRO_FORMAT_RGB24:
+ offset += 4 * dst_x;
+ data += 4 * src_x;
+ size = 4 * width;
+ break;
+ case CAIRO_FORMAT_A8:
+ offset += dst_x;
+ data += src_x;
+ size = width;
+ break;
+ case CAIRO_FORMAT_A1:
+ return _intel_bo_put_a1_image (dev,
+ bo, stride, src,
+ src_x, src_y,
+ width, height,
+ dst_x, dst_y);
+ }
+
+ if (bo->tiling == I915_TILING_NONE) {
+ if (src->stride == stride) {
+ intel_bo_write (dev, bo, offset, stride * height, data);
+ } else while (height--) {
+ intel_bo_write (dev, bo, offset, size, data);
+ offset += stride;
+ data += src->stride;
+ }
+ } else {
+ uint8_t *dst;
+
+ dst = intel_bo_map (dev, bo);
+ if (unlikely (dst == NULL))
+ return _cairo_error (CAIRO_STATUS_DEVICE_ERROR);
+
+ dst += offset;
+ while (height--) {
+ memcpy (dst, data, size);
+ dst += stride;
+ data += src->stride;
+ }
+ intel_bo_unmap (bo);
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
static void
_intel_device_init_bo_cache (intel_device_t *device)
{
@@ -883,23 +777,69 @@ _intel_device_init_bo_cache (intel_device_t *device)
}
_cairo_freepool_init (&device->bo_pool, sizeof (intel_bo_t));
+
+ device->base.surface.flink = _cairo_drm_surface_flink;
+ device->base.surface.map_to_image = intel_surface_map_to_image;
+}
+
+static cairo_bool_t
+_intel_snapshot_cache_entry_can_remove (const void *closure)
+{
+ return TRUE;
+}
+
+static void
+_intel_snapshot_cache_entry_destroy (void *closure)
+{
+ intel_surface_t *surface = cairo_container_of (closure,
+ intel_surface_t,
+ snapshot_cache_entry);
+
+ surface->snapshot_cache_entry.hash = 0;
+ cairo_surface_destroy (&surface->drm.base);
}
cairo_status_t
intel_device_init (intel_device_t *device, int fd)
{
struct drm_i915_gem_get_aperture aperture;
+ cairo_status_t status;
+ size_t size;
int ret;
+ int n;
ret = ioctl (fd, DRM_IOCTL_I915_GEM_GET_APERTURE, &aperture);
if (ret != 0)
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ return _cairo_error (CAIRO_STATUS_DEVICE_ERROR);
+
+ CAIRO_MUTEX_INIT (device->mutex);
device->gtt_max_size = aperture.aper_size;
device->gtt_avail_size = aperture.aper_available_size;
+ device->gtt_avail_size -= device->gtt_avail_size >> 5;
_intel_device_init_bo_cache (device);
+ size = aperture.aper_size / 8;
+ device->snapshot_cache_max_size = size / 4;
+ status = _cairo_cache_init (&device->snapshot_cache,
+ NULL,
+ _intel_snapshot_cache_entry_can_remove,
+ _intel_snapshot_cache_entry_destroy,
+ size);
+ if (unlikely (status))
+ return status;
+
+ device->glyph_cache_mapped = FALSE;
+ for (n = 0; n < ARRAY_LENGTH (device->glyph_cache); n++) {
+ device->glyph_cache[n].buffer.bo = NULL;
+ cairo_list_init (&device->glyph_cache[n].rtree.pinned);
+ }
+
+ device->gradient_cache.size = 0;
+
+ device->base.bo.release = intel_bo_release;
+
return CAIRO_STATUS_SUCCESS;
}
@@ -920,10 +860,42 @@ _intel_bo_cache_fini (intel_device_t *device)
CAIRO_MUTEX_FINI (device->bo_mutex);
}
+static void
+_intel_gradient_cache_fini (intel_device_t *device)
+{
+ unsigned int n;
+
+ for (n = 0; n < device->gradient_cache.size; n++) {
+ _cairo_pattern_fini (&device->gradient_cache.cache[n].pattern.base);
+ if (device->gradient_cache.cache[n].buffer.bo != NULL)
+ cairo_drm_bo_destroy (&device->base.base,
+ &device->gradient_cache.cache[n].buffer.bo->base);
+ }
+}
+
+static void
+_intel_glyph_cache_fini (intel_device_t *device, intel_buffer_cache_t *cache)
+{
+ if (cache->buffer.bo == NULL)
+ return;
+
+ intel_bo_destroy (device, cache->buffer.bo);
+ _cairo_rtree_fini (&cache->rtree);
+}
+
void
intel_device_fini (intel_device_t *device)
{
+ int n;
+
+ for (n = 0; n < ARRAY_LENGTH (device->glyph_cache); n++)
+ _intel_glyph_cache_fini (device, &device->glyph_cache[n]);
+
+ _cairo_cache_fini (&device->snapshot_cache);
+
+ _intel_gradient_cache_fini (device);
_intel_bo_cache_fini (device);
+
_cairo_drm_device_fini (&device->base);
}
@@ -932,3 +904,591 @@ intel_throttle (intel_device_t *device)
{
ioctl (device->base.fd, DRM_IOCTL_I915_GEM_THROTTLE);
}
+
+void
+intel_glyph_cache_unmap (intel_device_t *device)
+{
+ int n;
+
+ if (likely (! device->glyph_cache_mapped))
+ return;
+
+ for (n = 0; n < ARRAY_LENGTH (device->glyph_cache); n++) {
+ if (device->glyph_cache[n].buffer.bo != NULL &&
+ device->glyph_cache[n].buffer.bo->virtual != NULL)
+ {
+ intel_bo_unmap (device->glyph_cache[n].buffer.bo);
+ }
+ }
+
+ device->glyph_cache_mapped = FALSE;
+}
+
+void
+intel_glyph_cache_unpin (intel_device_t *device)
+{
+ int n;
+
+ for (n = 0; n < ARRAY_LENGTH (device->glyph_cache); n++)
+ _cairo_rtree_unpin (&device->glyph_cache[n].rtree);
+}
+
+static cairo_status_t
+intel_glyph_cache_add_glyph (intel_device_t *device,
+ intel_buffer_cache_t *cache,
+ cairo_scaled_glyph_t *scaled_glyph)
+{
+ cairo_image_surface_t *glyph_surface = scaled_glyph->surface;
+ intel_glyph_t *glyph;
+ cairo_rtree_node_t *node = NULL;
+ double sf_x, sf_y;
+ cairo_status_t status;
+ uint8_t *dst, *src;
+ int width, height;
+
+ width = glyph_surface->width;
+ if (width < GLYPH_CACHE_MIN_SIZE)
+ width = GLYPH_CACHE_MIN_SIZE;
+ height = glyph_surface->height;
+ if (height < GLYPH_CACHE_MIN_SIZE)
+ height = GLYPH_CACHE_MIN_SIZE;
+
+ /* search for an available slot */
+ status = _cairo_rtree_insert (&cache->rtree, width, height, &node);
+ /* search for an unpinned slot */
+ if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
+ status = _cairo_rtree_evict_random (&cache->rtree, width, height, &node);
+ if (status == CAIRO_STATUS_SUCCESS)
+ status = _cairo_rtree_node_insert (&cache->rtree, node, width, height, &node);
+ }
+ if (unlikely (status))
+ return status;
+
+ height = glyph_surface->height;
+ src = glyph_surface->data;
+ dst = cache->buffer.bo->virtual;
+ if (dst == NULL) {
+ dst = intel_bo_map (device, cache->buffer.bo);
+ if (unlikely (dst == NULL))
+ return _cairo_error (CAIRO_STATUS_DEVICE_ERROR);
+ }
+
+ dst += node->y * cache->buffer.stride;
+ switch (glyph_surface->format) {
+ case CAIRO_FORMAT_A1: {
+ uint8_t buf[CAIRO_STACK_BUFFER_SIZE];
+ uint8_t *a8 = buf;
+ int x;
+
+ if (width > (int) sizeof (buf)) {
+ a8 = malloc (width);
+ if (unlikely (a8 == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ }
+
+ dst += node->x;
+ width = glyph_surface->width;
+ while (height--) {
+ for (x = 0; x < width; x++)
+ a8[x] = src[x>>3] & (1 << (x&7)) ? 0xff : 0x00;
+
+ memcpy (dst, a8, width);
+ dst += cache->buffer.stride;
+ src += glyph_surface->stride;
+ }
+
+ if (a8 != buf)
+ free (a8);
+ break;
+ }
+
+ case CAIRO_FORMAT_A8:
+ dst += node->x;
+ width = glyph_surface->width;
+ while (height--) {
+ memcpy (dst, src, width);
+ dst += cache->buffer.stride;
+ src += glyph_surface->stride;
+ }
+ break;
+
+ default:
+ ASSERT_NOT_REACHED;
+ case CAIRO_FORMAT_RGB24:
+ case CAIRO_FORMAT_ARGB32:
+ dst += 4*node->x;
+ width = 4*glyph_surface->width;
+ while (height--) {
+ memcpy (dst, src, width);
+ dst += cache->buffer.stride;
+ src += glyph_surface->stride;
+ }
+ break;
+ }
+
+ /* leave mapped! */
+ device->glyph_cache_mapped = TRUE;
+
+ scaled_glyph->surface_private = node;
+
+ glyph= (intel_glyph_t *) node;
+ glyph->node.owner = &scaled_glyph->surface_private;
+ glyph->cache = cache;
+
+ /* compute tex coords: bottom-right, bottom-left, top-left */
+ sf_x = 1. / cache->buffer.width;
+ sf_y = 1. / cache->buffer.height;
+ glyph->texcoord[0] =
+ texcoord_2d_16 (sf_x * (node->x + glyph_surface->width + NEAREST_BIAS),
+ sf_y * (node->y + glyph_surface->height + NEAREST_BIAS));
+ glyph->texcoord[1] =
+ texcoord_2d_16 (sf_x * (node->x + NEAREST_BIAS),
+ sf_y * (node->y + glyph_surface->height + NEAREST_BIAS));
+ glyph->texcoord[2] =
+ texcoord_2d_16 (sf_x * (node->x + NEAREST_BIAS),
+ sf_y * (node->y + NEAREST_BIAS));
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+void
+intel_scaled_glyph_fini (cairo_scaled_glyph_t *scaled_glyph,
+ cairo_scaled_font_t *scaled_font)
+{
+ intel_glyph_t *glyph;
+
+ glyph = scaled_glyph->surface_private;
+ if (glyph != NULL) {
+ glyph->node.owner = NULL;
+ if (! glyph->node.pinned) {
+ intel_buffer_cache_t *cache;
+
+ /* XXX thread-safety? Probably ok due to the frozen scaled-font. */
+ cache = glyph->cache;
+ assert (cache != NULL);
+
+ glyph->node.state = CAIRO_RTREE_NODE_AVAILABLE;
+ cairo_list_move (&glyph->node.link,
+ &cache->rtree.available);
+
+ if (! glyph->node.parent->pinned)
+ _cairo_rtree_node_collapse (&cache->rtree, glyph->node.parent);
+ }
+ }
+}
+
+void
+intel_scaled_font_fini (cairo_scaled_font_t *scaled_font)
+{
+ intel_device_t *device;
+
+ device = scaled_font->surface_private;
+ if (device != NULL) {
+ /* XXX decouple? */
+ }
+}
+
+static cairo_status_t
+intel_get_glyph_cache (intel_device_t *device,
+ cairo_format_t format,
+ intel_buffer_cache_t **out)
+{
+ intel_buffer_cache_t *cache;
+ cairo_status_t status;
+
+ switch (format) {
+ case CAIRO_FORMAT_ARGB32:
+ case CAIRO_FORMAT_RGB24:
+ cache = &device->glyph_cache[0];
+ format = CAIRO_FORMAT_ARGB32;
+ break;
+ case CAIRO_FORMAT_A8:
+ case CAIRO_FORMAT_A1:
+ cache = &device->glyph_cache[1];
+ format = CAIRO_FORMAT_A8;
+ break;
+ default:
+ ASSERT_NOT_REACHED;
+ }
+
+ if (unlikely (cache->buffer.bo == NULL)) {
+ status = intel_buffer_cache_init (cache, device, format,
+ INTEL_GLYPH_CACHE_WIDTH,
+ INTEL_GLYPH_CACHE_HEIGHT);
+ if (unlikely (status))
+ return status;
+
+ _cairo_rtree_init (&cache->rtree,
+ INTEL_GLYPH_CACHE_WIDTH,
+ INTEL_GLYPH_CACHE_HEIGHT,
+ 0, sizeof (intel_glyph_t), NULL);
+ }
+
+ *out = cache;
+ return CAIRO_STATUS_SUCCESS;
+}
+
+cairo_int_status_t
+intel_get_glyph (intel_device_t *device,
+ cairo_scaled_font_t *scaled_font,
+ cairo_scaled_glyph_t *scaled_glyph)
+{
+ cairo_bool_t own_surface = FALSE;
+ intel_buffer_cache_t *cache;
+ cairo_status_t status;
+
+ if (scaled_glyph->surface == NULL) {
+ status =
+ scaled_font->backend->scaled_glyph_init (scaled_font,
+ scaled_glyph,
+ CAIRO_SCALED_GLYPH_INFO_SURFACE);
+ if (unlikely (status))
+ return status;
+
+ if (unlikely (scaled_glyph->surface == NULL))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ own_surface = TRUE;
+ }
+
+ if (unlikely (scaled_glyph->surface->width == 0 ||
+ scaled_glyph->surface->height == 0))
+ {
+ return CAIRO_INT_STATUS_NOTHING_TO_DO;
+ }
+
+ if (unlikely (scaled_glyph->surface->width > GLYPH_CACHE_MAX_SIZE ||
+ scaled_glyph->surface->height > GLYPH_CACHE_MAX_SIZE))
+ {
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ }
+
+ status = intel_get_glyph_cache (device,
+ scaled_glyph->surface->format,
+ &cache);
+ if (unlikely (status))
+ return status;
+
+ status = intel_glyph_cache_add_glyph (device, cache, scaled_glyph);
+ if (unlikely (_cairo_status_is_error (status)))
+ return status;
+
+ if (unlikely (status == CAIRO_INT_STATUS_UNSUPPORTED)) {
+ /* no room, replace entire cache */
+
+ assert (cache->buffer.bo->exec != NULL);
+
+ _cairo_rtree_reset (&cache->rtree);
+ intel_bo_destroy (device, cache->buffer.bo);
+ cache->buffer.bo = NULL;
+
+ status = intel_buffer_cache_init (cache, device,
+ scaled_glyph->surface->format,
+ GLYPH_CACHE_WIDTH,
+ GLYPH_CACHE_HEIGHT);
+ if (unlikely (status))
+ return status;
+
+ status = intel_glyph_cache_add_glyph (device, cache, scaled_glyph);
+ if (unlikely (status))
+ return status;
+ }
+
+ if (own_surface) {
+ /* and release the copy of the image from system memory */
+ cairo_surface_destroy (&scaled_glyph->surface->base);
+ scaled_glyph->surface = NULL;
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+cairo_status_t
+intel_buffer_cache_init (intel_buffer_cache_t *cache,
+ intel_device_t *device,
+ cairo_format_t format,
+ int width, int height)
+{
+ const uint32_t tiling = I915_TILING_Y;
+
+ assert ((width & 3) == 0);
+ assert ((height & 1) == 0);
+ cache->buffer.format = format;
+ cache->buffer.width = width;
+ cache->buffer.height = height;
+
+ switch (format) {
+ case CAIRO_FORMAT_A1:
+ case CAIRO_FORMAT_RGB24:
+ ASSERT_NOT_REACHED;
+ case CAIRO_FORMAT_ARGB32:
+ cache->buffer.map0 = MAPSURF_32BIT | MT_32BIT_ARGB8888;
+ cache->buffer.stride = width * 4;
+ break;
+ case CAIRO_FORMAT_A8:
+ cache->buffer.map0 = MAPSURF_8BIT | MT_8BIT_I8;
+ cache->buffer.stride = width;
+ break;
+ }
+ cache->buffer.map0 |= ((height - 1) << MS3_HEIGHT_SHIFT) |
+ ((width - 1) << MS3_WIDTH_SHIFT);
+ cache->buffer.map1 = ((cache->buffer.stride / 4) - 1) << MS4_PITCH_SHIFT;
+
+ cache->buffer.bo = intel_bo_create (device,
+ height * cache->buffer.stride, FALSE);
+ if (unlikely (cache->buffer.bo == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+ intel_bo_set_tiling (device, cache->buffer.bo, tiling, cache->buffer.stride);
+
+ cache->buffer.map0 |= MS3_tiling (cache->buffer.bo->tiling);
+
+ cache->ref_count = 0;
+ cairo_list_init (&cache->link);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+cairo_status_t
+intel_snapshot_cache_insert (intel_device_t *device,
+ intel_surface_t *surface)
+{
+ cairo_status_t status;
+ int bpp;
+
+ bpp = 1;
+ if (surface->drm.format != CAIRO_FORMAT_A8)
+ bpp = 4;
+
+ surface->snapshot_cache_entry.hash = (unsigned long) surface;
+ surface->snapshot_cache_entry.size =
+ surface->drm.width * surface->drm.height * bpp;
+
+ if (surface->snapshot_cache_entry.size >
+ device->snapshot_cache_max_size)
+ {
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+ if (device->snapshot_cache.freeze_count == 0)
+ _cairo_cache_freeze (&device->snapshot_cache);
+
+ status = _cairo_cache_insert (&device->snapshot_cache,
+ &surface->snapshot_cache_entry);
+ if (unlikely (status)) {
+ surface->snapshot_cache_entry.hash = 0;
+ return status;
+ }
+
+ cairo_surface_reference (&surface->drm.base);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+void
+intel_surface_detach_snapshot (cairo_surface_t *abstract_surface)
+{
+ intel_surface_t *surface = (intel_surface_t *) abstract_surface;
+
+ if (surface->snapshot_cache_entry.hash) {
+ intel_device_t *device;
+
+ device = (intel_device_t *) surface->drm.base.device;
+ _cairo_cache_remove (&device->snapshot_cache,
+ &surface->snapshot_cache_entry);
+ surface->snapshot_cache_entry.hash = 0;
+ }
+}
+
+void
+intel_snapshot_cache_thaw (intel_device_t *device)
+{
+ if (device->snapshot_cache.freeze_count)
+ _cairo_cache_thaw (&device->snapshot_cache);
+}
+
+static cairo_bool_t
+_gradient_color_stops_equal (const cairo_gradient_pattern_t *a,
+ const cairo_gradient_pattern_t *b)
+{
+ unsigned int n;
+
+ if (a->n_stops != b->n_stops)
+ return FALSE;
+
+ for (n = 0; n < a->n_stops; n++) {
+ if (_cairo_fixed_from_double (a->stops[n].offset) !=
+ _cairo_fixed_from_double (b->stops[n].offset))
+ {
+ return FALSE;
+ }
+
+ if (! _cairo_color_equal (&a->stops[n].color, &b->stops[n].color))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static uint32_t
+hars_petruska_f54_1_random (void)
+{
+#define rol(x,k) ((x << k) | (x >> (32-k)))
+ static uint32_t x;
+ return x = (x ^ rol (x, 5) ^ rol (x, 24)) + 0x37798849;
+#undef rol
+}
+
+static int
+intel_gradient_sample_width (const cairo_gradient_pattern_t *gradient)
+{
+ unsigned int n;
+ int width;
+
+ width = 8;
+ for (n = 1; n < gradient->n_stops; n++) {
+ double dx = gradient->stops[n].offset - gradient->stops[n-1].offset;
+ double delta, max;
+ int ramp;
+
+ if (dx == 0)
+ continue;
+
+ max = gradient->stops[n].color.red -
+ gradient->stops[n-1].color.red;
+
+ delta = gradient->stops[n].color.green -
+ gradient->stops[n-1].color.green;
+ if (delta > max)
+ max = delta;
+
+ delta = gradient->stops[n].color.blue -
+ gradient->stops[n-1].color.blue;
+ if (delta > max)
+ max = delta;
+
+ delta = gradient->stops[n].color.alpha -
+ gradient->stops[n-1].color.alpha;
+ if (delta > max)
+ max = delta;
+
+ ramp = 128 * max / dx;
+ if (ramp > width)
+ width = ramp;
+ }
+
+ width = (width + 7) & -8;
+ return MIN (width, 1024);
+}
+
+cairo_status_t
+intel_gradient_render (intel_device_t *device,
+ const cairo_gradient_pattern_t *pattern,
+ intel_buffer_t *buffer)
+{
+ pixman_image_t *gradient, *image;
+ pixman_gradient_stop_t pixman_stops_stack[32];
+ pixman_gradient_stop_t *pixman_stops;
+ pixman_point_fixed_t p1, p2;
+ int width;
+ unsigned int i;
+ cairo_status_t status;
+
+ for (i = 0; i < device->gradient_cache.size; i++) {
+ if (_gradient_color_stops_equal (pattern,
+ &device->gradient_cache.cache[i].pattern.gradient.base)) {
+ *buffer = device->gradient_cache.cache[i].buffer;
+ return CAIRO_STATUS_SUCCESS;
+ }
+ }
+
+ pixman_stops = pixman_stops_stack;
+ if (unlikely (pattern->n_stops > ARRAY_LENGTH (pixman_stops_stack))) {
+ pixman_stops = _cairo_malloc_ab (pattern->n_stops,
+ sizeof (pixman_gradient_stop_t));
+ if (unlikely (pixman_stops == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ }
+
+ for (i = 0; i < pattern->n_stops; i++) {
+ pixman_stops[i].x = _cairo_fixed_16_16_from_double (pattern->stops[i].offset);
+ pixman_stops[i].color.red = pattern->stops[i].color.red_short;
+ pixman_stops[i].color.green = pattern->stops[i].color.green_short;
+ pixman_stops[i].color.blue = pattern->stops[i].color.blue_short;
+ pixman_stops[i].color.alpha = pattern->stops[i].color.alpha_short;
+ }
+
+ width = intel_gradient_sample_width (pattern);
+
+ p1.x = 0;
+ p1.y = 0;
+ p2.x = width << 16;
+ p2.y = 0;
+
+ gradient = pixman_image_create_linear_gradient (&p1, &p2,
+ pixman_stops,
+ pattern->n_stops);
+ if (pixman_stops != pixman_stops_stack)
+ free (pixman_stops);
+
+ if (unlikely (gradient == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+ pixman_image_set_filter (gradient, PIXMAN_FILTER_BILINEAR, NULL, 0);
+
+ image = pixman_image_create_bits (PIXMAN_a8r8g8b8, width, 1, NULL, 0);
+ if (unlikely (image == NULL)) {
+ pixman_image_unref (gradient);
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ }
+
+ pixman_image_composite (PIXMAN_OP_SRC,
+ gradient, NULL, image,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ width, 1);
+
+ pixman_image_unref (gradient);
+
+ buffer->bo = intel_bo_create (device, 4*width, FALSE);
+ if (unlikely (buffer->bo == NULL)) {
+ pixman_image_unref (image);
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ }
+
+ intel_bo_write (device, buffer->bo, 0, 4*width, pixman_image_get_data (image));
+ pixman_image_unref (image);
+
+ buffer->offset = 0;
+ buffer->width = width;
+ buffer->height = 1;
+ buffer->stride = 4*width;
+ buffer->format = CAIRO_FORMAT_ARGB32;
+ buffer->map0 = MAPSURF_32BIT | MT_32BIT_ARGB8888;
+ buffer->map0 |= MS3_tiling (buffer->bo->tiling);
+ buffer->map0 |= ((width - 1) << MS3_WIDTH_SHIFT);
+ buffer->map1 = (width - 1) << MS4_PITCH_SHIFT;
+
+ if (device->gradient_cache.size < GRADIENT_CACHE_SIZE) {
+ i = device->gradient_cache.size++;
+ } else {
+ i = hars_petruska_f54_1_random () % GRADIENT_CACHE_SIZE;
+ _cairo_pattern_fini (&device->gradient_cache.cache[i].pattern.base);
+ intel_bo_destroy (device, device->gradient_cache.cache[i].buffer.bo);
+ }
+
+ status = _cairo_pattern_init_copy (&device->gradient_cache.cache[i].pattern.base,
+ &pattern->base);
+ if (unlikely (status)) {
+ intel_bo_destroy (device, buffer->bo);
+ /* Ensure the cache is correctly initialised for i965_device_destroy */
+ _cairo_pattern_init_solid (&device->gradient_cache.cache[i].pattern.solid,
+ CAIRO_COLOR_TRANSPARENT,
+ CAIRO_CONTENT_ALPHA);
+ return status;
+ }
+
+ device->gradient_cache.cache[i].buffer = *buffer;
+ return CAIRO_STATUS_SUCCESS;
+}
diff --git a/src/drm/cairo-drm-private.h b/src/drm/cairo-drm-private.h
index 0f1b735..549832d 100644
--- a/src/drm/cairo-drm-private.h
+++ b/src/drm/cairo-drm-private.h
@@ -38,11 +38,14 @@
#include "cairo-drm.h"
-#include "cairo-surface-private.h"
+#include "cairo-device-private.h"
#include "cairo-reference-count-private.h"
+#include "cairo-surface-private.h"
#include <sys/types.h> /* dev_t */
+typedef struct _cairo_drm_device cairo_drm_device_t;
+
typedef cairo_drm_device_t *
(*cairo_drm_device_create_func_t) (int fd,
dev_t dev,
@@ -50,6 +53,9 @@ typedef cairo_drm_device_t *
int chip_id);
typedef cairo_int_status_t
+(*cairo_drm_device_flush_func_t) (cairo_drm_device_t *device);
+
+typedef cairo_int_status_t
(*cairo_drm_device_throttle_func_t) (cairo_drm_device_t *device);
typedef void
@@ -76,11 +82,15 @@ typedef cairo_int_status_t
typedef cairo_status_t
(*cairo_drm_surface_enable_scan_out_func_t) (void *surface);
+typedef cairo_surface_t *
+(*cairo_drm_surface_map_to_image_func_t) (void *surface);
+
typedef struct _cairo_drm_bo_backend {
void (*release) (void *device, void *bo);
} cairo_drm_bo_backend_t;
typedef struct _cairo_drm_device_backend {
+ cairo_drm_device_flush_func_t flush;
cairo_drm_device_throttle_func_t throttle;
cairo_drm_device_destroy_func_t destroy;
} cairo_drm_device_backend_t;
@@ -91,6 +101,7 @@ typedef struct _cairo_drm_surface_backend {
cairo_drm_surface_create_from_cacheable_image_func_t create_from_cacheable_image;
cairo_drm_surface_flink_func_t flink;
cairo_drm_surface_enable_scan_out_func_t enable_scan_out;
+ cairo_drm_surface_map_to_image_func_t map_to_image;
} cairo_drm_surface_backend_t;
typedef struct _cairo_drm_bo {
@@ -101,9 +112,10 @@ typedef struct _cairo_drm_bo {
} cairo_drm_bo_t;
struct _cairo_drm_device {
- cairo_reference_count_t ref_count;
- cairo_status_t status;
+ cairo_device_t base;
+ int vendor_id;
+ int chip_id;
dev_t id;
int fd;
@@ -119,7 +131,6 @@ struct _cairo_drm_device {
typedef struct _cairo_drm_surface {
cairo_surface_t base;
- cairo_drm_device_t *device;
cairo_drm_bo_t *bo;
cairo_format_t format;
@@ -136,17 +147,16 @@ cairo_drm_bo_reference (cairo_drm_bo_t *bo)
return bo;
}
-static inline void
-cairo_drm_bo_destroy (cairo_drm_device_t *device,
+static always_inline void
+cairo_drm_bo_destroy (cairo_device_t *abstract_device,
cairo_drm_bo_t *bo)
{
- if (_cairo_reference_count_dec_and_test (&bo->ref_count))
+ if (_cairo_reference_count_dec_and_test (&bo->ref_count)) {
+ cairo_drm_device_t *device = (cairo_drm_device_t *) abstract_device;
device->bo.release (device, bo);
+ }
}
-cairo_private cairo_drm_device_t *
-_cairo_drm_device_create_in_error (cairo_status_t status);
-
cairo_private cairo_status_t
_cairo_drm_bo_open_for_name (const cairo_drm_device_t *dev,
cairo_drm_bo_t *bo,
@@ -181,56 +191,20 @@ _cairo_drm_surface_get_extents (void *abstract_surface,
cairo_rectangle_int_t *rectangle);
cairo_private cairo_int_status_t
-_cairo_drm_surface_paint (void *abstract_surface,
- cairo_operator_t op,
- const cairo_pattern_t *source,
- cairo_clip_t *clip);
-
-cairo_private cairo_int_status_t
-_cairo_drm_surface_mask (void *abstract_surface,
- cairo_operator_t op,
- const cairo_pattern_t *source,
- const cairo_pattern_t *mask,
- cairo_clip_t *clip);
-
-cairo_private cairo_int_status_t
-_cairo_drm_surface_stroke (void *abstract_surface,
- cairo_operator_t op,
- const cairo_pattern_t *source,
- cairo_path_fixed_t *path,
- const cairo_stroke_style_t *style,
- const cairo_matrix_t *ctm,
- const cairo_matrix_t *ctm_inverse,
- double tolerance,
- cairo_antialias_t antialias,
- cairo_clip_t *clip);
-
-cairo_private cairo_int_status_t
-_cairo_drm_surface_fill (void *abstract_surface,
- cairo_operator_t op,
- const cairo_pattern_t *source,
- cairo_path_fixed_t *path,
- cairo_fill_rule_t fill_rule,
- double tolerance,
- cairo_antialias_t antialias,
- cairo_clip_t *clip);
-
-cairo_private cairo_int_status_t
-_cairo_drm_surface_show_glyphs (void *abstract_surface,
- cairo_operator_t op,
- const cairo_pattern_t *source,
- cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_scaled_font_t *scaled_font,
- cairo_clip_t *clip,
- int *remaining_glyphs);
-
-cairo_private cairo_int_status_t
_cairo_drm_surface_flink (void *abstract_surface);
+static inline cairo_drm_device_t *
+_cairo_drm_device_create_in_error (cairo_status_t status)
+{
+ return (cairo_drm_device_t *) _cairo_device_create_in_error (CAIRO_STATUS_NO_MEMORY);
+}
+
cairo_private cairo_drm_device_t *
_cairo_drm_device_init (cairo_drm_device_t *device,
- int fd, dev_t id,
+ int fd,
+ dev_t devid,
+ int vendor_id,
+ int chip_id,
int max_surface_size);
cairo_private void
@@ -242,6 +216,12 @@ cairo_private cairo_drm_device_t *
_cairo_drm_intel_device_create (int fd, dev_t dev, int vendor_id, int chip_id);
cairo_private cairo_drm_device_t *
+_cairo_drm_i915_device_create (int fd, dev_t dev, int vendor_id, int chip_id);
+
+cairo_private cairo_drm_device_t *
+_cairo_drm_i965_device_create (int fd, dev_t dev, int vendor_id, int chip_id);
+
+cairo_private cairo_drm_device_t *
_cairo_drm_radeon_device_create (int fd, dev_t dev, int vendor_id, int chip_id);
#if CAIRO_HAS_GALLIUM_SURFACE
@@ -250,8 +230,13 @@ _cairo_drm_gallium_device_create (int fd, dev_t dev, int vendor_id, int chip_id)
#endif
slim_hidden_proto (cairo_drm_device_default);
-slim_hidden_proto (cairo_drm_device_destroy);
slim_hidden_proto (cairo_drm_device_get);
-slim_hidden_proto_no_warn (cairo_drm_device_reference);
+slim_hidden_proto (cairo_drm_device_get_for_fd);
+
+slim_hidden_proto (cairo_drm_surface_create_for_name);
+
+cairo_private cairo_bool_t
+_cairo_drm_size_is_valid (cairo_device_t *abstract_device,
+ int width, int height);
#endif /* CAIRO_DRM_PRIVATE_H */
diff --git a/src/drm/cairo-drm-radeon-private.h b/src/drm/cairo-drm-radeon-private.h
index 9c0c3b4..e63bb04 100644
--- a/src/drm/cairo-drm-radeon-private.h
+++ b/src/drm/cairo-drm-radeon-private.h
@@ -99,9 +99,6 @@ radeon_bo_create (radeon_device_t *dev,
cairo_private cairo_drm_bo_t *
radeon_bo_create_for_name (radeon_device_t *dev, uint32_t name);
-cairo_private void
-radeon_bo_release (void *_dev, void *_bo);
-
cairo_private cairo_surface_t *
radeon_bo_get_image (const radeon_device_t *device,
radeon_bo_t *bo,
diff --git a/src/drm/cairo-drm-radeon-surface.c b/src/drm/cairo-drm-radeon-surface.c
index 858f353..7521199 100644
--- a/src/drm/cairo-drm-radeon-surface.c
+++ b/src/drm/cairo-drm-radeon-surface.c
@@ -31,6 +31,7 @@
#include "cairo-drm-private.h"
#include "cairo-drm-radeon-private.h"
+
#include "cairo-error-private.h"
/* Basic stub surface for radeon chipsets */
@@ -42,7 +43,7 @@ typedef struct _radeon_surface {
} radeon_surface_t;
static inline radeon_device_t *
-to_radeon_device (cairo_drm_device_t *device)
+to_radeon_device (cairo_device_t *device)
{
return (radeon_device_t *) device;
}
@@ -53,19 +54,14 @@ to_radeon_bo (cairo_drm_bo_t *bo)
return (radeon_bo_t *) bo;
}
-static cairo_status_t
-radeon_batch_flush (radeon_device_t *device)
-{
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-radeon_surface_batch_flush (radeon_surface_t *surface)
+static cairo_surface_t *
+radeon_surface_create_similar (void *abstract_surface,
+ cairo_content_t content,
+ int width,
+ int height)
{
- if (to_radeon_bo (surface->base.bo)->write_domain)
- return radeon_batch_flush (to_radeon_device (surface->base.device));
-
- return CAIRO_STATUS_SUCCESS;
+ return cairo_image_surface_create (_cairo_format_from_content (content),
+ width, height);
}
static cairo_status_t
@@ -85,6 +81,8 @@ radeon_surface_acquire_source_image (void *abstract_surface,
cairo_surface_t *image;
cairo_status_t status;
+ /* XXX batch flush */
+
if (surface->base.fallback != NULL) {
image = surface->base.fallback;
goto DONE;
@@ -95,13 +93,15 @@ radeon_surface_acquire_source_image (void *abstract_surface,
if (image != NULL)
goto DONE;
- status = radeon_surface_batch_flush (surface);
- if (unlikely (status))
- return status;
+ if (surface->base.base.backend->flush != NULL) {
+ status = surface->base.base.backend->flush (surface);
+ if (unlikely (status))
+ return status;
+ }
- image = radeon_bo_get_image (to_radeon_device (surface->base.device),
- to_radeon_bo (surface->base.bo),
- &surface->base);
+ image = radeon_bo_get_image (to_radeon_device (surface->base.base.device),
+ to_radeon_bo (surface->base.bo),
+ &surface->base);
status = image->status;
if (unlikely (status))
return status;
@@ -121,94 +121,46 @@ DONE:
}
static void
-radeon_surface_release_source_image (void *abstract_surface,
- cairo_image_surface_t *image,
- void *image_extra)
+radeon_surface_release_source_image (void *abstract_surface,
+ cairo_image_surface_t *image,
+ void *image_extra)
{
cairo_surface_destroy (&image->base);
}
static cairo_surface_t *
-radeon_surface_snapshot (void *abstract_surface)
-{
- radeon_surface_t *surface = abstract_surface;
- cairo_status_t status;
-
- if (surface->base.fallback != NULL)
- return NULL;
-
- status = radeon_surface_batch_flush (surface);
- if (unlikely (status))
- return _cairo_surface_create_in_error (status);
-
- return radeon_bo_get_image (to_radeon_device (surface->base.device),
- to_radeon_bo (surface->base.bo),
- &surface->base);
-}
-
-static cairo_status_t
-radeon_surface_acquire_dest_image (void *abstract_surface,
- cairo_rectangle_int_t *interest_rect,
- cairo_image_surface_t **image_out,
- cairo_rectangle_int_t *image_rect_out,
- void **image_extra)
+radeon_surface_map_to_image (radeon_surface_t *surface)
{
- radeon_surface_t *surface = abstract_surface;
- cairo_surface_t *image;
- cairo_status_t status;
- void *ptr;
-
- assert (surface->base.fallback == NULL);
-
- status = radeon_surface_batch_flush (surface);
- if (unlikely (status))
- return status;
-
- /* Force a read barrier, as well as flushing writes above */
- radeon_bo_wait (to_radeon_device (surface->base.device),
- to_radeon_bo (surface->base.bo));
+ if (surface->base.fallback == NULL) {
+ cairo_surface_t *image;
+ cairo_status_t status;
+ void *ptr;
+
+ if (surface->base.base.backend->flush != NULL) {
+ status = surface->base.base.backend->flush (surface);
+ if (unlikely (status))
+ return _cairo_surface_create_in_error (status);
+ }
- ptr = radeon_bo_map (to_radeon_device (surface->base.device),
- to_radeon_bo (surface->base.bo));
- if (unlikely (ptr == NULL))
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ ptr = radeon_bo_map (to_radeon_device (surface->base.base.device),
+ to_radeon_bo (surface->base.bo));
+ if (unlikely (ptr == NULL))
+ return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
+
+ image = cairo_image_surface_create_for_data (ptr,
+ surface->base.format,
+ surface->base.width,
+ surface->base.height,
+ surface->base.stride);
+ if (unlikely (image->status)) {
+ radeon_bo_unmap (to_radeon_bo (surface->base.bo));
+ return image;
+ }
- image = cairo_image_surface_create_for_data (ptr,
- surface->base.format,
- surface->base.width,
- surface->base.height,
- surface->base.stride);
- status = image->status;
- if (unlikely (status)) {
- radeon_bo_unmap (to_radeon_bo (surface->base.bo));
- return status;
+ surface->base.fallback = image;
}
- surface->base.fallback = cairo_surface_reference (image);
-
- *image_out = (cairo_image_surface_t *) image;
- *image_extra = NULL;
-
- image_rect_out->x = 0;
- image_rect_out->y = 0;
- image_rect_out->width = surface->base.width;
- image_rect_out->height = surface->base.height;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static void
-radeon_surface_release_dest_image (void *abstract_surface,
- cairo_rectangle_int_t *interest_rect,
- cairo_image_surface_t *image,
- cairo_rectangle_int_t *image_rect,
- void *image_extra)
-{
- /* Keep the fallback until we flush, either explicitly or at the
- * end of this context. The idea is to avoid excess migration of
- * the buffer between GPU and CPU domains.
- */
- cairo_surface_destroy (&image->base);
+ return surface->base.fallback;
}
static cairo_status_t
@@ -218,7 +170,7 @@ radeon_surface_flush (void *abstract_surface)
cairo_status_t status;
if (surface->base.fallback == NULL)
- return radeon_surface_batch_flush (surface);
+ return CAIRO_STATUS_SUCCESS;
/* kill any outstanding maps */
cairo_surface_finish (surface->base.fallback);
@@ -232,53 +184,117 @@ radeon_surface_flush (void *abstract_surface)
return status;
}
+static cairo_int_status_t
+radeon_surface_paint (void *abstract_surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_clip_t *clip)
+{
+ return _cairo_surface_paint (radeon_surface_map_to_image (abstract_surface),
+ op, source, clip);
+}
+
+static cairo_int_status_t
+radeon_surface_mask (void *abstract_surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ const cairo_pattern_t *mask,
+ cairo_clip_t *clip)
+{
+ return _cairo_surface_mask (radeon_surface_map_to_image (abstract_surface),
+ op, source, mask, clip);
+}
+
+static cairo_int_status_t
+radeon_surface_stroke (void *abstract_surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_path_fixed_t *path,
+ const cairo_stroke_style_t *stroke_style,
+ const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm_inverse,
+ double tolerance,
+ cairo_antialias_t antialias,
+ cairo_clip_t *clip)
+{
+ return _cairo_surface_stroke (radeon_surface_map_to_image (abstract_surface),
+ op, source, path, stroke_style, ctm, ctm_inverse,
+ tolerance, antialias, clip);
+}
+
+static cairo_int_status_t
+radeon_surface_fill (void *abstract_surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_path_fixed_t *path,
+ cairo_fill_rule_t fill_rule,
+ double tolerance,
+ cairo_antialias_t antialias,
+ cairo_clip_t *clip)
+{
+ return _cairo_surface_fill (radeon_surface_map_to_image (abstract_surface),
+ op, source, path, fill_rule,
+ tolerance, antialias, clip);
+}
+
+static cairo_int_status_t
+radeon_surface_glyphs (void *abstract_surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_scaled_font_t *scaled_font,
+ cairo_clip_t *clip,
+ int *num_remaining)
+{
+ *num_remaining = 0;
+ return _cairo_surface_show_text_glyphs (radeon_surface_map_to_image (abstract_surface),
+ op, source,
+ NULL, 0,
+ glyphs, num_glyphs,
+ NULL, 0, 0,
+ scaled_font, clip);
+}
+
static const cairo_surface_backend_t radeon_surface_backend = {
CAIRO_SURFACE_TYPE_DRM,
- _cairo_drm_surface_create_similar,
- radeon_surface_finish,
+ radeon_surface_create_similar,
+ radeon_surface_finish,
radeon_surface_acquire_source_image,
radeon_surface_release_source_image,
- radeon_surface_acquire_dest_image,
- radeon_surface_release_dest_image,
-
- NULL, //radeon_surface_clone_similar,
- NULL, //radeon_surface_composite,
- NULL, //radeon_surface_fill_rectangles,
- NULL, //radeon_surface_composite_trapezoids,
- NULL, //radeon_surface_create_span_renderer,
- NULL, //radeon_surface_check_span_renderer,
+ NULL, NULL, NULL,
+ NULL, /* composite */
+ NULL, /* fill */
+ NULL, /* trapezoids */
+ NULL, /* span */
+ NULL, /* check-span */
+
NULL, /* copy_page */
NULL, /* show_page */
_cairo_drm_surface_get_extents,
- NULL, /* old_show_glyphs */
+ NULL, /* old-glyphs */
_cairo_drm_surface_get_font_options,
- radeon_surface_flush,
- NULL, /* mark_dirty_rectangle */
- NULL, //radeon_surface_scaled_font_fini,
- NULL, //radeon_surface_scaled_glyph_fini,
-
- _cairo_drm_surface_paint,
- _cairo_drm_surface_mask,
- _cairo_drm_surface_stroke,
- _cairo_drm_surface_fill,
- _cairo_drm_surface_show_glyphs,
-
- radeon_surface_snapshot,
- NULL, /* is_similar */
-
- NULL, /* reset */
+ radeon_surface_flush,
+ NULL, /* mark dirty */
+ NULL, NULL, /* font/glyph fini */
+
+ radeon_surface_paint,
+ radeon_surface_mask,
+ radeon_surface_stroke,
+ radeon_surface_fill,
+ radeon_surface_glyphs,
};
static void
radeon_surface_init (radeon_surface_t *surface,
- cairo_content_t content,
- cairo_drm_device_t *device)
+ cairo_content_t content,
+ cairo_drm_device_t *device)
{
_cairo_surface_init (&surface->base.base,
&radeon_surface_backend,
- NULL, /* device */
+ &device->base,
content);
_cairo_drm_surface_init (&surface->base, device);
@@ -318,7 +334,7 @@ radeon_surface_create_internal (cairo_drm_device_t *device,
surface->base.stride =
cairo_format_stride_for_width (surface->base.format, width);
- surface->base.bo = radeon_bo_create (to_radeon_device (device),
+ surface->base.bo = radeon_bo_create (to_radeon_device (&device->base),
surface->base.stride * height,
RADEON_GEM_DOMAIN_GTT);
@@ -379,7 +395,7 @@ radeon_surface_create_for_name (cairo_drm_device_t *device,
surface->base.height = height;
surface->base.stride = stride;
- surface->base.bo = radeon_bo_create_for_name (to_radeon_device (device),
+ surface->base.bo = radeon_bo_create_for_name (to_radeon_device (&device->base),
name);
if (unlikely (surface->base.bo == NULL)) {
@@ -428,13 +444,12 @@ _cairo_drm_radeon_device_create (int fd, dev_t dev, int vendor_id, int chip_id)
device->base.surface.flink = _cairo_drm_surface_flink;
device->base.surface.enable_scan_out = NULL;
+ device->base.device.flush = NULL;
device->base.device.throttle = NULL;
device->base.device.destroy = radeon_device_destroy;
- device->base.bo.release = radeon_bo_release;
-
device->vram_limit = vram_size;
device->gart_limit = gart_size;
- return _cairo_drm_device_init (&device->base, dev, fd, MAX_SIZE);
+ return _cairo_drm_device_init (&device->base, fd, dev, vendor_id, chip_id, MAX_SIZE);
}
diff --git a/src/drm/cairo-drm-radeon.c b/src/drm/cairo-drm-radeon.c
index e435d70..a968308 100644
--- a/src/drm/cairo-drm-radeon.c
+++ b/src/drm/cairo-drm-radeon.c
@@ -32,6 +32,7 @@
#include "cairo-drm-private.h"
#include "cairo-drm-radeon-private.h"
#include "cairo-drm-ioctl-private.h"
+
#include "cairo-error-private.h"
#include <sys/ioctl.h>
@@ -371,7 +372,7 @@ radeon_bo_create_for_name (radeon_device_t *device,
return &bo->base;
}
-void
+static void
radeon_bo_release (void *_dev, void *_bo)
{
radeon_device_t *device = _dev;
@@ -431,6 +432,8 @@ radeon_device_init (radeon_device_t *device, int fd)
{
_radeon_device_init_bo_cache (device);
+ device->base.bo.release = radeon_bo_release;
+
return CAIRO_STATUS_SUCCESS;
}
diff --git a/src/drm/cairo-drm-surface.c b/src/drm/cairo-drm-surface.c
index 429b528..e37d3e2 100644
--- a/src/drm/cairo-drm-surface.c
+++ b/src/drm/cairo-drm-surface.c
@@ -33,8 +33,8 @@
#include "cairoint.h"
#include "cairo-drm-private.h"
+
#include "cairo-error-private.h"
-#include "cairo-surface-fallback-private.h"
cairo_surface_t *
_cairo_drm_surface_create_similar (void *abstract_surface,
@@ -43,13 +43,8 @@ _cairo_drm_surface_create_similar (void *abstract_surface,
int height)
{
cairo_drm_surface_t *surface = abstract_surface;
- cairo_drm_device_t *device;
-
- if (surface->fallback != NULL)
- return _cairo_image_surface_create_with_content (content,
- width, height);
+ cairo_drm_device_t *device = (cairo_drm_device_t *) surface->base.device;
- device = surface->device;
if (width > device->max_surface_size || height > device->max_surface_size)
return NULL;
@@ -60,8 +55,6 @@ void
_cairo_drm_surface_init (cairo_drm_surface_t *surface,
cairo_drm_device_t *device)
{
- surface->device = cairo_drm_device_reference (device);
-
surface->bo = NULL;
surface->width = 0;
surface->height = 0;
@@ -75,9 +68,7 @@ cairo_status_t
_cairo_drm_surface_finish (cairo_drm_surface_t *surface)
{
if (surface->bo != NULL)
- cairo_drm_bo_destroy (surface->device, surface->bo);
-
- cairo_drm_device_destroy (surface->device);
+ cairo_drm_bo_destroy (surface->base.device, surface->bo);
return CAIRO_STATUS_SUCCESS;
}
@@ -105,147 +96,32 @@ _cairo_drm_surface_get_extents (void *abstract_surface,
return TRUE;
}
-cairo_int_status_t
-_cairo_drm_surface_paint (void *abstract_surface,
- cairo_operator_t op,
- const cairo_pattern_t *source,
- cairo_clip_t *clip)
-{
- cairo_drm_surface_t *surface = abstract_surface;
-
- if (surface->fallback != NULL)
- return _cairo_surface_paint (surface->fallback, op, source, clip);
-
- return _cairo_surface_fallback_paint (&surface->base, op, source, clip);
-}
-
-cairo_int_status_t
-_cairo_drm_surface_mask (void *abstract_surface,
- cairo_operator_t op,
- const cairo_pattern_t *source,
- const cairo_pattern_t *mask,
- cairo_clip_t *clip)
-{
- cairo_drm_surface_t *surface = abstract_surface;
-
- if (surface->fallback != NULL) {
- return _cairo_surface_mask (surface->fallback,
- op, source, mask,
- clip);
- }
-
- return _cairo_surface_fallback_mask (&surface->base,
- op, source, mask, clip);
-}
-
-cairo_int_status_t
-_cairo_drm_surface_stroke (void *abstract_surface,
- cairo_operator_t op,
- const cairo_pattern_t *source,
- cairo_path_fixed_t *path,
- const cairo_stroke_style_t *style,
- const cairo_matrix_t *ctm,
- const cairo_matrix_t *ctm_inverse,
- double tolerance,
- cairo_antialias_t antialias,
- cairo_clip_t *clip)
-{
- cairo_drm_surface_t *surface = abstract_surface;
-
- if (surface->fallback != NULL) {
- return _cairo_surface_stroke (surface->fallback,
- op, source,
- path, style,
- ctm, ctm_inverse,
- tolerance, antialias,
- clip);
- }
-
- return _cairo_surface_fallback_stroke (&surface->base, op, source,
- path, style,
- ctm, ctm_inverse,
- tolerance, antialias,
- clip);
-}
-
-cairo_int_status_t
-_cairo_drm_surface_fill (void *abstract_surface,
- cairo_operator_t op,
- const cairo_pattern_t *source,
- cairo_path_fixed_t *path,
- cairo_fill_rule_t fill_rule,
- double tolerance,
- cairo_antialias_t antialias,
- cairo_clip_t *clip)
-{
- cairo_drm_surface_t *surface = abstract_surface;
-
- if (surface->fallback != NULL) {
- return _cairo_surface_fill (surface->fallback,
- op, source,
- path, fill_rule,
- tolerance, antialias,
- clip);
- }
-
- return _cairo_surface_fallback_fill (&surface->base, op, source,
- path, fill_rule,
- tolerance, antialias,
- clip);
-}
-
-cairo_int_status_t
-_cairo_drm_surface_show_glyphs (void *abstract_surface,
- cairo_operator_t op,
- const cairo_pattern_t *source,
- cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_scaled_font_t *scaled_font,
- cairo_clip_t *clip,
- int *remaining_glyphs)
-{
- cairo_drm_surface_t *surface = abstract_surface;
-
- if (surface->fallback != NULL) {
- *remaining_glyphs = 0;
- return _cairo_surface_show_text_glyphs (surface->fallback,
- op, source,
- NULL, 0,
- glyphs, num_glyphs,
- NULL, 0, 0,
- scaled_font,
- clip);
- }
-
- return _cairo_surface_fallback_show_glyphs (&surface->base,
- op, source,
- glyphs, num_glyphs,
- scaled_font,
- clip);
-}
-
-
cairo_surface_t *
-cairo_drm_surface_create (cairo_drm_device_t *device,
+cairo_drm_surface_create (cairo_device_t *abstract_device,
cairo_content_t content,
int width, int height)
{
+ cairo_drm_device_t *device = (cairo_drm_device_t *) abstract_device;
cairo_surface_t *surface;
if (! CAIRO_CONTENT_VALID (content))
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_CONTENT));
- if (device != NULL && device->status)
+ if (device != NULL && device->base.status)
{
- surface = _cairo_surface_create_in_error (device->status);
+ surface = _cairo_surface_create_in_error (device->base.status);
}
else if (device == NULL ||
device->surface.create == NULL ||
width == 0 || width > device->max_surface_size ||
height == 0 || height > device->max_surface_size)
{
- surface = _cairo_image_surface_create_with_content (content,
- width, height);
+ surface = cairo_image_surface_create (_cairo_format_from_content (content),
+ width, height);
+ }
+ else if (device->base.finished)
+ {
+ surface = _cairo_surface_create_in_error (CAIRO_STATUS_SURFACE_FINISHED);
}
else
{
@@ -256,19 +132,20 @@ cairo_drm_surface_create (cairo_drm_device_t *device,
}
cairo_surface_t *
-cairo_drm_surface_create_for_name (cairo_drm_device_t *device,
+cairo_drm_surface_create_for_name (cairo_device_t *abstract_device,
unsigned int name,
cairo_format_t format,
int width, int height, int stride)
{
+ cairo_drm_device_t *device = (cairo_drm_device_t *) abstract_device;
cairo_surface_t *surface;
if (! CAIRO_FORMAT_VALID (format))
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT));
- if (device != NULL && device->status)
+ if (device != NULL && device->base.status)
{
- surface = _cairo_surface_create_in_error (device->status);
+ surface = _cairo_surface_create_in_error (device->base.status);
}
else if (device == NULL || device->surface.create_for_name == NULL)
{
@@ -280,6 +157,10 @@ cairo_drm_surface_create_for_name (cairo_drm_device_t *device,
{
surface = _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE));
}
+ else if (device->base.finished)
+ {
+ surface = _cairo_surface_create_in_error (CAIRO_STATUS_SURFACE_FINISHED);
+ }
else
{
surface = device->surface.create_for_name (device,
@@ -289,20 +170,25 @@ cairo_drm_surface_create_for_name (cairo_drm_device_t *device,
return surface;
}
+slim_hidden_def (cairo_drm_surface_create_for_name);
cairo_surface_t *
-cairo_drm_surface_create_from_cacheable_image (cairo_drm_device_t *dev,
+cairo_drm_surface_create_from_cacheable_image (cairo_device_t *abstract_device,
cairo_surface_t *surface)
{
+ cairo_drm_device_t *device = (cairo_drm_device_t *) abstract_device;
+
if (surface->status) {
surface = _cairo_surface_create_in_error (surface->status);
- } else if (dev != NULL && dev->status) {
- surface = _cairo_surface_create_in_error (dev->status);
- } else if (dev == NULL || dev->surface.create_from_cacheable_image == NULL) {
+ } else if (device != NULL && device->base.status) {
+ surface = _cairo_surface_create_in_error (device->base.status);
+ } else if (device == NULL || device->surface.create_from_cacheable_image == NULL) {
/* XXX invalid device! */
surface = _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT));
+ } else if (device->base.finished) {
+ surface = _cairo_surface_create_in_error (CAIRO_STATUS_SURFACE_FINISHED);
} else {
- surface = dev->surface.create_from_cacheable_image (dev, surface);
+ surface = device->surface.create_from_cacheable_image (device, surface);
}
return surface;
@@ -324,32 +210,22 @@ cairo_status_t
cairo_drm_surface_enable_scan_out (cairo_surface_t *abstract_surface)
{
cairo_drm_surface_t *surface;
+ cairo_drm_device_t *device;
surface = _cairo_surface_as_drm (abstract_surface);
- if (surface == NULL)
+ if (unlikely (surface == NULL))
return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
+ if (unlikely (surface->base.finished))
+ return _cairo_error (CAIRO_STATUS_SURFACE_FINISHED);
- if (surface->device->surface.enable_scan_out == NULL)
+ device = (cairo_drm_device_t *) surface->base.device;
+ if (device->surface.enable_scan_out == NULL)
return CAIRO_STATUS_SUCCESS;
- return surface->device->surface.enable_scan_out (abstract_surface);
-}
+ if (unlikely (device->base.finished))
+ return _cairo_error (CAIRO_STATUS_SURFACE_FINISHED);
-cairo_drm_device_t *
-cairo_drm_surface_get_device (cairo_surface_t *abstract_surface)
-{
- cairo_drm_surface_t *surface;
-
- if (unlikely (abstract_surface->status))
- return _cairo_drm_device_create_in_error (abstract_surface->status);
-
- surface = _cairo_surface_as_drm (abstract_surface);
- if (surface == NULL) {
- _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
- return NULL;
- }
-
- return surface->device;
+ return device->surface.enable_scan_out (abstract_surface);
}
unsigned int
@@ -371,13 +247,15 @@ _cairo_drm_surface_flink (void *abstract_surface)
{
cairo_drm_surface_t *surface = abstract_surface;
- return _cairo_drm_bo_flink (surface->device, surface->bo);
+ return _cairo_drm_bo_flink ((cairo_drm_device_t *) surface->base.device,
+ surface->bo);
}
unsigned int
cairo_drm_surface_get_name (cairo_surface_t *abstract_surface)
{
cairo_drm_surface_t *surface;
+ cairo_drm_device_t *device;
cairo_status_t status;
surface = _cairo_surface_as_drm (abstract_surface);
@@ -389,10 +267,11 @@ cairo_drm_surface_get_name (cairo_surface_t *abstract_surface)
if (surface->bo->name)
return surface->bo->name;
- if (surface->device->surface.flink == NULL)
+ device = (cairo_drm_device_t *) surface->base.device;
+ if (device->surface.flink == NULL)
return 0;
- status = surface->device->surface.flink (abstract_surface);
+ status = device->surface.flink (abstract_surface);
if (status) {
if (_cairo_status_is_error (status))
status = _cairo_surface_set_error (abstract_surface, status);
@@ -456,10 +335,8 @@ cairo_surface_t *
cairo_drm_surface_map (cairo_surface_t *abstract_surface)
{
cairo_drm_surface_t *surface;
- cairo_rectangle_int_t roi;
- cairo_image_surface_t *image;
+ cairo_drm_device_t *device;
cairo_status_t status;
- void *image_extra;
if (unlikely (abstract_surface->status))
return _cairo_surface_create_in_error (abstract_surface->status);
@@ -474,23 +351,9 @@ cairo_drm_surface_map (cairo_surface_t *abstract_surface)
return _cairo_surface_create_in_error (status);
}
- roi.x = roi.y = 0;
- roi.width = surface->width;
- roi.height = surface->height;
-
- status = _cairo_surface_acquire_dest_image (abstract_surface,
- &roi,
- &image,
- &roi,
- &image_extra);
- if (unlikely (status))
- return _cairo_surface_create_in_error (status);
-
- assert (image_extra == NULL);
-
surface->map_count++;
-
- return &image->base;
+ device = (cairo_drm_device_t *) surface->base.device;
+ return cairo_surface_reference (device->surface.map_to_image (surface));
}
void
diff --git a/src/drm/cairo-drm.c b/src/drm/cairo-drm.c
index a218fa5..9ccb10d 100644
--- a/src/drm/cairo-drm.c
+++ b/src/drm/cairo-drm.c
@@ -33,6 +33,8 @@
#include "cairoint.h"
#include "cairo-drm-private.h"
+
+#include "cairo-device-private.h"
#include "cairo-error-private.h"
#define LIBUDEV_I_KNOW_THE_API_IS_SUBJECT_TO_CHANGE
@@ -43,29 +45,6 @@
static cairo_drm_device_t *_cairo_drm_known_devices;
static cairo_drm_device_t *_cairo_drm_default_device;
-static const cairo_drm_device_t _nil_device = {
- CAIRO_REFERENCE_COUNT_INVALID,
- CAIRO_STATUS_NO_MEMORY
-};
-
-static const cairo_drm_device_t _invalid_device = {
- CAIRO_REFERENCE_COUNT_INVALID,
- CAIRO_STATUS_INVALID_CONTENT
-};
-
-cairo_drm_device_t *
-_cairo_drm_device_create_in_error (cairo_status_t status)
-{
- switch ((int) status) {
- default:
- ASSERT_NOT_REACHED;
- case CAIRO_STATUS_NO_MEMORY:
- return (cairo_drm_device_t *) &_nil_device;
- case CAIRO_STATUS_INVALID_CONTENT:
- return (cairo_drm_device_t *) &_invalid_device;
- }
-}
-
static const char *
get_udev_property(struct udev_device *device, const char *name)
{
@@ -81,16 +60,69 @@ get_udev_property(struct udev_device *device, const char *name)
return NULL;
}
+static void
+_device_flush (void *abstract_device)
+{
+ cairo_drm_device_t *device = abstract_device;
+
+ device->device.flush (device);
+}
+
+static void
+_device_finish (void *abstract_device)
+{
+ cairo_drm_device_t *device = abstract_device;
+
+ CAIRO_MUTEX_LOCK (_cairo_drm_device_mutex);
+ if (device->prev != NULL)
+ device->prev->next = device->next;
+ else
+ _cairo_drm_known_devices = device->next;
+ if (device->next != NULL)
+ device->next->prev = device->prev;
+
+ CAIRO_MUTEX_UNLOCK (_cairo_drm_device_mutex);
+
+ if (_cairo_atomic_ptr_cmpxchg (&_cairo_drm_default_device,
+ device, NULL) == device)
+ {
+ cairo_device_destroy (&device->base);
+ }
+}
+
+static void
+_device_destroy (void *abstract_device)
+{
+ cairo_drm_device_t *device = abstract_device;
+
+ device->device.destroy (device);
+}
+
+static const cairo_device_backend_t _cairo_drm_device_backend = {
+ CAIRO_DEVICE_TYPE_DRM,
+
+ NULL, NULL, /* lock, unlock */
+
+ _device_flush,
+ _device_finish,
+ _device_destroy,
+};
+
cairo_drm_device_t *
_cairo_drm_device_init (cairo_drm_device_t *dev,
int fd,
dev_t devid,
+ int vendor_id,
+ int chip_id,
int max_surface_size)
{
- CAIRO_REFERENCE_COUNT_INIT (&dev->ref_count, 1);
- dev->status = CAIRO_STATUS_SUCCESS;
+ assert (CAIRO_MUTEX_IS_LOCKED (_cairo_drm_device_mutex));
+
+ _cairo_device_init (&dev->base, &_cairo_drm_device_backend);
dev->id = devid;
+ dev->vendor_id = vendor_id;
+ dev->chip_id = chip_id;
dev->fd = fd;
dev->max_surface_size = max_surface_size;
@@ -102,12 +134,12 @@ _cairo_drm_device_init (cairo_drm_device_t *dev,
_cairo_drm_known_devices = dev;
if (_cairo_drm_default_device == NULL)
- _cairo_drm_default_device = cairo_drm_device_reference (dev);
+ _cairo_drm_default_device = (cairo_drm_device_t *) cairo_device_reference (&dev->base);
return dev;
}
-cairo_drm_device_t *
+cairo_device_t *
cairo_drm_device_get (struct udev_device *device)
{
static const struct dri_driver_entry {
@@ -115,7 +147,34 @@ cairo_drm_device_get (struct udev_device *device)
uint32_t chip_id;
cairo_drm_device_create_func_t create_func;
} driver_map[] = {
+ { 0x8086, 0x29a2, _cairo_drm_i965_device_create }, /* I965_G */
+ { 0x8086, 0x2982, _cairo_drm_i965_device_create }, /* G35_G */
+ { 0x8086, 0x2992, _cairo_drm_i965_device_create }, /* I965_Q */
+ { 0x8086, 0x2972, _cairo_drm_i965_device_create }, /* I946_GZ */
+ { 0x8086, 0x2a02, _cairo_drm_i965_device_create }, /* I965_GM */
+ { 0x8086, 0x2a12, _cairo_drm_i965_device_create }, /* I965_GME */
+ { 0x8086, 0x2e02, _cairo_drm_i965_device_create }, /* IGD_E_G */
+ { 0x8086, 0x2e22, _cairo_drm_i965_device_create }, /* G45_G */
+ { 0x8086, 0x2e12, _cairo_drm_i965_device_create }, /* Q45_G */
+ { 0x8086, 0x2e32, _cairo_drm_i965_device_create }, /* G41_G */
+ { 0x8086, 0x2a42, _cairo_drm_i965_device_create }, /* GM45_GM */
+
+ { 0x8086, 0x2582, _cairo_drm_i915_device_create }, /* I915_G */
+ { 0x8086, 0x2592, _cairo_drm_i915_device_create }, /* I915_GM */
+ { 0x8086, 0x258a, _cairo_drm_i915_device_create }, /* E7221_G */
+ { 0x8086, 0x2772, _cairo_drm_i915_device_create }, /* I945_G */
+ { 0x8086, 0x27a2, _cairo_drm_i915_device_create }, /* I945_GM */
+ { 0x8086, 0x27ae, _cairo_drm_i915_device_create }, /* I945_GME */
+ { 0x8086, 0x29c2, _cairo_drm_i915_device_create }, /* G33_G */
+ { 0x8086, 0x29b2, _cairo_drm_i915_device_create }, /* Q35_G */
+ { 0x8086, 0x29d2, _cairo_drm_i915_device_create }, /* Q33_G */
+ { 0x8086, 0xa011, _cairo_drm_i915_device_create }, /* IGD_GM */
+ { 0x8086, 0xa001, _cairo_drm_i915_device_create }, /* IGD_G */
+
+ /* XXX i830 */
+
{ 0x8086, ~0, _cairo_drm_intel_device_create },
+
{ 0x1002, ~0, _cairo_drm_radeon_device_create },
#if CAIRO_HAS_GALLIUM_SURFACE
{ ~0, ~0, _cairo_drm_gallium_device_create },
@@ -135,16 +194,16 @@ cairo_drm_device_get (struct udev_device *device)
CAIRO_MUTEX_LOCK (_cairo_drm_device_mutex);
for (dev = _cairo_drm_known_devices; dev != NULL; dev = dev->next) {
if (dev->id == devid) {
- dev = cairo_drm_device_reference (dev);
+ dev = (cairo_drm_device_t *) cairo_device_reference (&dev->base);
goto DONE;
}
}
- dev = (cairo_drm_device_t *) &_nil_device;
parent = udev_device_get_parent (device);
pci_id = get_udev_property (parent, "PCI_ID");
if (sscanf (pci_id, "%x:%x", &vendor_id, &chip_id) != 2) {
- _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
+ dev = (cairo_drm_device_t *)
+ _cairo_device_create_in_error (CAIRO_STATUS_DEVICE_ERROR);
goto DONE;
}
@@ -166,8 +225,8 @@ cairo_drm_device_get (struct udev_device *device)
}
if (i == ARRAY_LENGTH (driver_map)) {
- /* XXX should be no driver or something*/
- _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
+ dev = (cairo_drm_device_t *)
+ _cairo_device_create_in_error (CAIRO_STATUS_DEVICE_ERROR);
goto DONE;
}
}
@@ -190,22 +249,21 @@ cairo_drm_device_get (struct udev_device *device)
DONE:
CAIRO_MUTEX_UNLOCK (_cairo_drm_device_mutex);
- return dev;
+ return &dev->base;
}
slim_hidden_def (cairo_drm_device_get);
-cairo_drm_device_t *
+cairo_device_t *
cairo_drm_device_get_for_fd (int fd)
{
struct stat st;
struct udev *udev;
struct udev_device *device;
- cairo_drm_device_t *dev = NULL;
+ cairo_device_t *dev = NULL;
if (fstat (fd, &st) < 0 || ! S_ISCHR (st.st_mode)) {
//_cairo_error_throw (CAIRO_STATUS_INVALID_DEVICE);
- _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
- return (cairo_drm_device_t *) &_nil_device;
+ return _cairo_device_create_in_error (CAIRO_STATUS_NO_MEMORY);
}
udev = udev_new ();
@@ -220,25 +278,24 @@ cairo_drm_device_get_for_fd (int fd)
return dev;
}
+slim_hidden_def (cairo_drm_device_get_for_fd);
-cairo_drm_device_t *
+cairo_device_t *
cairo_drm_device_default (void)
{
struct udev *udev;
struct udev_enumerate *e;
struct udev_list_entry *entry;
- cairo_drm_device_t *dev;
+ cairo_device_t *dev;
/* optimistic atomic pointer read */
- dev = _cairo_drm_default_device;
+ dev = &_cairo_drm_default_device->base;
if (dev != NULL)
return dev;
udev = udev_new();
- if (udev == NULL) {
- _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
- return (cairo_drm_device_t *) &_nil_device;
- }
+ if (udev == NULL)
+ return _cairo_device_create_in_error (CAIRO_STATUS_NO_MEMORY);
e = udev_enumerate_new (udev);
udev_enumerate_add_match_subsystem (e, "drm");
@@ -255,8 +312,9 @@ cairo_drm_device_default (void)
udev_device_unref (device);
if (dev != NULL) {
- if (dev->fd == -1) { /* try again, we may find a usable card */
- cairo_drm_device_destroy (dev);
+ if (((cairo_drm_device_t *) dev)->fd == -1) {
+ /* try again, we may find a usable card */
+ cairo_device_destroy (dev);
dev = NULL;
} else
break;
@@ -265,7 +323,7 @@ cairo_drm_device_default (void)
udev_enumerate_unref (e);
udev_unref (udev);
- cairo_drm_device_destroy (dev); /* owned by _cairo_drm_default_device */
+ cairo_device_destroy (dev); /* owned by _cairo_drm_default_device */
return dev;
}
slim_hidden_def (cairo_drm_device_default);
@@ -274,90 +332,56 @@ void
_cairo_drm_device_reset_static_data (void)
{
if (_cairo_drm_default_device != NULL) {
- cairo_drm_device_destroy (_cairo_drm_default_device);
+ cairo_device_t *device = &_cairo_drm_default_device->base;
_cairo_drm_default_device = NULL;
+ cairo_device_destroy (device);
}
}
-cairo_drm_device_t *
-cairo_drm_device_reference (cairo_drm_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_drm_device_reference);
-
int
-cairo_drm_device_get_fd (cairo_drm_device_t *device)
+cairo_drm_device_get_fd (cairo_device_t *abstract_device)
{
- if (device->status)
+ cairo_drm_device_t *device = (cairo_drm_device_t *) abstract_device;
+
+ if (device->base.status)
return -1;
return device->fd;
}
-cairo_status_t
-cairo_drm_device_status (cairo_drm_device_t *device)
-{
- if (device == NULL)
- return CAIRO_STATUS_NULL_POINTER;
-
- return device->status;
-}
-
void
_cairo_drm_device_fini (cairo_drm_device_t *device)
{
- CAIRO_MUTEX_LOCK (_cairo_drm_device_mutex);
- if (device->prev != NULL)
- device->prev->next = device->next;
- else
- _cairo_drm_known_devices = device->next;
- if (device->next != NULL)
- device->next->prev = device->prev;
- CAIRO_MUTEX_UNLOCK (_cairo_drm_device_mutex);
-
if (device->fd != -1)
close (device->fd);
}
void
-cairo_drm_device_destroy (cairo_drm_device_t *device)
+cairo_drm_device_throttle (cairo_device_t *abstract_device)
{
- if (device == NULL ||
- CAIRO_REFERENCE_COUNT_IS_INVALID (&device->ref_count))
- {
+ cairo_drm_device_t *device = (cairo_drm_device_t *) abstract_device;
+ cairo_status_t status;
+
+ if (unlikely (device->base.status))
return;
- }
- assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&device->ref_count));
- if (! _cairo_reference_count_dec_and_test (&device->ref_count))
+ if (device->device.throttle == NULL)
return;
- device->device.destroy (device);
+ status = device->device.throttle (device);
+ if (unlikely (status))
+ _cairo_status_set_error (&device->base.status, status);
}
-slim_hidden_def (cairo_drm_device_destroy);
-void
-cairo_drm_device_throttle (cairo_drm_device_t *dev)
+cairo_bool_t
+_cairo_drm_size_is_valid (cairo_device_t *abstract_device,
+ int width, int height)
{
- cairo_status_t status;
+ cairo_drm_device_t *device = (cairo_drm_device_t *) abstract_device;
- if (unlikely (dev->status))
- return;
+ if (unlikely (device->base.status))
+ return FALSE;
- if (dev->device.throttle == NULL)
- return;
-
- status = dev->device.throttle (dev);
- if (unlikely (status))
- _cairo_status_set_error (&dev->status, status);
+ return width <= device->max_surface_size &&
+ height <= device->max_surface_size;
}
commit b9407af6a4bc792c1bcb52c90aa8a618627bb618
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Fri Jan 22 17:57:41 2010 +0000
image: Implement high level interface.
Write a dedicated compositor for pixman so that we avoid the
middle-layer syndrome of surface-fallback. The major upshot of this
rewrite is that the image surface is now several times quicker for glyph
compositing, which dramatically improves performance for text rendering
by firefox and friends. It also uses a couple of the new scan
convertors, such as the rectangular scan converter for rectilinear
paths.
Speedups
========
image-rgba firefox-talos-gfx-0 342050.17 (342155.88 0.02%) -> 69412.44 (69702.90 0.21%): 4.93x speedup
ââââ
image-rgba vim-0 97518.13 (97696.23 1.21%) -> 30712.63 (31238.65 0.85%): 3.18x speedup
âââ
image-rgba evolution-0 69927.77 (110261.08 19.84%) -> 24430.05 (25368.85 1.89%): 2.86x speedup
ââ
image-rgba poppler-0 41452.61 (41547.03 2.51%) -> 21195.52 (21656.85 1.08%): 1.96x speedup
â
image-rgba firefox-planet-gnome-0 217512.61 (217636.80 0.06%) -> 123341.02 (123641.94 0.12%): 1.76x speedup
â
image-rgba swfdec-youtube-0 41302.71 (41373.60 0.11%) -> 31343.93 (31488.87 0.23%): 1.32x speedup
â
image-rgba swfdec-giant-steps-0 20699.54 (20739.52 0.10%) -> 17360.19 (17375.51 0.04%): 1.19x speedup
â
image-rgba gvim-0 167837.47 (168027.68 0.51%) -> 151105.94 (151635.85 0.18%): 1.11x speedup
â
image-rgba firefox-talos-svg-0 375273.43 (388250.94 1.60%) -> 356846.09 (370370.08 1.86%): 1.05x speedup
diff --git a/src/cairo-image-surface.c b/src/cairo-image-surface.c
index b50a994..f3886c0 100644
--- a/src/cairo-image-surface.c
+++ b/src/cairo-image-surface.c
@@ -2,6 +2,7 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2003 University of Southern California
+ * Copyright © 2009,2010 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
@@ -33,19 +34,35 @@
*
* Contributor(s):
* Carl D. Worth <cworth at cworth.org>
+ * Chris Wilson <chris at chris-wilson.co.uk>
*/
#include "cairoint.h"
+#include "cairo-boxes-private.h"
#include "cairo-clip-private.h"
#include "cairo-composite-rectangles-private.h"
#include "cairo-error-private.h"
#include "cairo-region-private.h"
+#include "cairo-scaled-font-private.h"
+#include "cairo-surface-snapshot-private.h"
+#include "cairo-surface-subsurface-private.h"
/* Limit on the width / height of an image surface in pixels. This is
* mainly determined by coordinates of things sent to pixman at the
* moment being in 16.16 format. */
#define MAX_IMAGE_SIZE 32767
+#define PIXMAN_MAX_INT ((pixman_fixed_1 >> 1) - pixman_fixed_e) /* need to ensure deltas also fit */
+
+static cairo_int_status_t
+_cairo_image_surface_fill (void *dst,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_path_fixed_t *path,
+ cairo_fill_rule_t fill_rule,
+ double tolerance,
+ cairo_antialias_t antialias,
+ cairo_clip_t *clip);
static cairo_bool_t
_cairo_image_surface_is_size_valid (int width, int height)
@@ -54,7 +71,7 @@ _cairo_image_surface_is_size_valid (int width, int height)
0 <= height && height <= MAX_IMAGE_SIZE;
}
-static cairo_format_t
+cairo_format_t
_cairo_format_from_pixman_format (pixman_format_code_t pixman_format)
{
switch (pixman_format) {
@@ -96,69 +113,18 @@ _cairo_format_from_pixman_format (pixman_format_code_t pixman_format)
return CAIRO_FORMAT_INVALID;
}
-static cairo_content_t
+cairo_content_t
_cairo_content_from_pixman_format (pixman_format_code_t pixman_format)
{
- switch (pixman_format) {
- case PIXMAN_a8r8g8b8:
- case PIXMAN_a8b8g8r8:
- case PIXMAN_a1r5g5b5:
- case PIXMAN_a1b5g5r5:
- case PIXMAN_a4r4g4b4:
- case PIXMAN_a4b4g4r4:
- case PIXMAN_a2r2g2b2:
- case PIXMAN_a2b2g2r2:
- case PIXMAN_a1r1g1b1:
- case PIXMAN_a1b1g1r1:
-#if PIXMAN_VERSION >= PIXMAN_VERSION_ENCODE(0,11,9)
- case PIXMAN_a2b10g10r10:
-#endif
-#if PIXMAN_VERSION >= PIXMAN_VERSION_ENCODE(0,14,1)
- case PIXMAN_b8g8r8a8:
-#endif
-#if PIXMAN_VERSION >= PIXMAN_VERSION_ENCODE(0,15,16)
- case PIXMAN_a2r10g10b10:
-#endif
- return CAIRO_CONTENT_COLOR_ALPHA;
- case PIXMAN_x8r8g8b8:
- case PIXMAN_x8b8g8r8:
- case PIXMAN_r8g8b8:
- case PIXMAN_b8g8r8:
- case PIXMAN_r5g6b5:
- case PIXMAN_b5g6r5:
- case PIXMAN_x1r5g5b5:
- case PIXMAN_x1b5g5r5:
- case PIXMAN_x4r4g4b4:
- case PIXMAN_x4b4g4r4:
- case PIXMAN_r3g3b2:
- case PIXMAN_b2g3r3:
- case PIXMAN_c8:
- case PIXMAN_g8:
- case PIXMAN_r1g2b1:
- case PIXMAN_b1g2r1:
- case PIXMAN_c4:
- case PIXMAN_g4:
- case PIXMAN_g1:
- case PIXMAN_yuy2:
- case PIXMAN_yv12:
-#if PIXMAN_VERSION >= PIXMAN_VERSION_ENCODE(0,11,9)
- case PIXMAN_x2b10g10r10:
-#endif
-#if PIXMAN_VERSION >= PIXMAN_VERSION_ENCODE(0,14,1)
- case PIXMAN_b8g8r8x8:
-#endif
-#if PIXMAN_VERSION >= PIXMAN_VERSION_ENCODE(0,15,16)
- case PIXMAN_x2r10g10b10:
-#endif
- return CAIRO_CONTENT_COLOR;
- case PIXMAN_a8:
- case PIXMAN_a1:
- case PIXMAN_x4a4:
- case PIXMAN_a4:
- return CAIRO_CONTENT_ALPHA;
- }
+ cairo_content_t content;
- return CAIRO_CONTENT_COLOR_ALPHA;
+ content = 0;
+ if (PIXMAN_FORMAT_RGB (pixman_format))
+ content |= CAIRO_CONTENT_COLOR;
+ if (PIXMAN_FORMAT_A (pixman_format))
+ content |= CAIRO_CONTENT_ALPHA;
+
+ return content;
}
cairo_surface_t *
@@ -169,10 +135,6 @@ _cairo_image_surface_create_for_pixman_image (pixman_image_t *pixman_image,
int width = pixman_image_get_width (pixman_image);
int height = pixman_image_get_height (pixman_image);
- if (! _cairo_image_surface_is_size_valid (width, height)) {
- return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE));
- }
-
surface = malloc (sizeof (cairo_image_surface_t));
if (unlikely (surface == NULL))
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
@@ -186,7 +148,7 @@ _cairo_image_surface_create_for_pixman_image (pixman_image_t *pixman_image,
surface->pixman_format = pixman_format;
surface->format = _cairo_format_from_pixman_format (pixman_format);
- surface->data = (unsigned char *) pixman_image_get_data (pixman_image);
+ surface->data = (uint8_t *) pixman_image_get_data (pixman_image);
surface->owns_data = FALSE;
surface->transparency = CAIRO_IMAGE_UNKNOWN;
@@ -195,8 +157,6 @@ _cairo_image_surface_create_for_pixman_image (pixman_image_t *pixman_image,
surface->stride = pixman_image_get_stride (pixman_image);
surface->depth = pixman_image_get_depth (pixman_image);
- surface->clip_region = NULL;
-
return &surface->base;
}
@@ -305,46 +265,6 @@ _pixman_format_to_masks (pixman_format_code_t format,
}
}
-/* XXX: This function really should be eliminated. We don't really
- * want to advertise a cairo image surface that supports any possible
- * format. A minimal step would be to replace this function with one
- * that accepts a #cairo_internal_format_t rather than mask values. */
-cairo_surface_t *
-_cairo_image_surface_create_with_masks (unsigned char *data,
- cairo_format_masks_t *masks,
- int width,
- int height,
- int stride)
-{
- pixman_format_code_t pixman_format;
-
- if (! _pixman_format_from_masks (masks, &pixman_format)) {
- fprintf (stderr,
- "Error: Cairo %s does not yet support the requested image format:\n"
- "\tDepth: %d\n"
- "\tAlpha mask: 0x%08lx\n"
- "\tRed mask: 0x%08lx\n"
- "\tGreen mask: 0x%08lx\n"
- "\tBlue mask: 0x%08lx\n"
-#ifdef PACKAGE_BUGGREPORT
- "Please file an enhancement request (quoting the above) at:\n"
- PACKAGE_BUGREPORT"\n"
-#endif
- ,
- cairo_version_string (),
- masks->bpp, masks->alpha_mask,
- masks->red_mask, masks->green_mask, masks->blue_mask);
-
- ASSERT_NOT_REACHED;
- }
-
- return _cairo_image_surface_create_with_pixman_format (data,
- pixman_format,
- width,
- height,
- stride);
-}
-
static pixman_format_code_t
_cairo_format_to_pixman_format_code (cairo_format_t format)
{
@@ -442,9 +362,6 @@ _cairo_image_surface_create_with_content (cairo_content_t content,
int width,
int height)
{
- if (! CAIRO_CONTENT_VALID (content))
- return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_CONTENT));
-
return cairo_image_surface_create (_cairo_format_from_content (content),
width, height);
}
@@ -554,6 +471,9 @@ cairo_image_surface_create_for_data (unsigned char *data,
if ((stride & (CAIRO_STRIDE_ALIGNMENT-1)) != 0)
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_STRIDE));
+ if (! _cairo_image_surface_is_size_valid (width, height))
+ return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE));
+
minstride = cairo_format_stride_for_width (format, width);
if (stride < 0) {
if (stride > -minstride) {
@@ -573,21 +493,6 @@ cairo_image_surface_create_for_data (unsigned char *data,
}
slim_hidden_def (cairo_image_surface_create_for_data);
-cairo_surface_t *
-_cairo_image_surface_create_for_data_with_content (unsigned char *data,
- cairo_content_t content,
- int width,
- int height,
- int stride)
-{
- if (! CAIRO_CONTENT_VALID (content))
- return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_CONTENT));
-
- return cairo_image_surface_create_for_data (data,
- _cairo_format_from_content (content),
- width, height, stride);
-}
-
/**
* cairo_image_surface_get_data:
* @surface: a #cairo_image_surface_t
@@ -770,6 +675,9 @@ _cairo_image_surface_create_similar (void *abstract_other,
{
cairo_image_surface_t *other = abstract_other;
+ if (! _cairo_image_surface_is_size_valid (width, height))
+ return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE));
+
if (content == other->base.content) {
return _cairo_image_surface_create_with_pixman_format (NULL,
other->pixman_format,
@@ -796,8 +704,6 @@ _cairo_image_surface_finish (void *abstract_surface)
surface->data = NULL;
}
- cairo_region_destroy (surface->clip_region);
-
return CAIRO_STATUS_SUCCESS;
}
@@ -825,176 +731,6 @@ _cairo_image_surface_release_source_image (void *abstract_surf
{
}
-static cairo_status_t
-_cairo_image_surface_acquire_dest_image (void *abstract_surface,
- cairo_rectangle_int_t *interest_rect,
- cairo_image_surface_t **image_out,
- cairo_rectangle_int_t *image_rect_out,
- void **image_extra)
-{
- cairo_image_surface_t *surface = abstract_surface;
-
- image_rect_out->x = 0;
- image_rect_out->y = 0;
- image_rect_out->width = surface->width;
- image_rect_out->height = surface->height;
-
- *image_out = surface;
- *image_extra = NULL;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static void
-_cairo_image_surface_release_dest_image (void *abstract_surface,
- cairo_rectangle_int_t *interest_rect,
- cairo_image_surface_t *image,
- cairo_rectangle_int_t *image_rect,
- void *image_extra)
-{
-}
-
-static cairo_status_t
-_cairo_image_surface_clone_similar (void *abstract_surface,
- cairo_surface_t *src,
- int src_x,
- int src_y,
- int width,
- int height,
- int *clone_offset_x,
- int *clone_offset_y,
- cairo_surface_t **clone_out)
-{
- cairo_image_surface_t *surface = abstract_surface;
-
- if (src->backend == surface->base.backend) {
- *clone_offset_x = *clone_offset_y = 0;
- *clone_out = cairo_surface_reference (src);
-
- return CAIRO_STATUS_SUCCESS;
- }
-
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-
-static cairo_status_t
-_cairo_image_surface_set_matrix (cairo_image_surface_t *surface,
- const cairo_matrix_t *matrix,
- double xc, double yc)
-{
- pixman_transform_t pixman_transform;
-
- _cairo_matrix_to_pixman_matrix (matrix, &pixman_transform, xc, yc);
-
- if (! pixman_image_set_transform (surface->pixman_image, &pixman_transform))
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_image_surface_set_filter (cairo_image_surface_t *surface,
- cairo_filter_t filter)
-{
- pixman_filter_t pixman_filter;
-
- switch (filter) {
- case CAIRO_FILTER_FAST:
- pixman_filter = PIXMAN_FILTER_FAST;
- break;
- case CAIRO_FILTER_GOOD:
- pixman_filter = PIXMAN_FILTER_GOOD;
- break;
- case CAIRO_FILTER_BEST:
- pixman_filter = PIXMAN_FILTER_BEST;
- break;
- case CAIRO_FILTER_NEAREST:
- pixman_filter = PIXMAN_FILTER_NEAREST;
- break;
- case CAIRO_FILTER_BILINEAR:
- pixman_filter = PIXMAN_FILTER_BILINEAR;
- break;
- case CAIRO_FILTER_GAUSSIAN:
- /* XXX: The GAUSSIAN value has no implementation in cairo
- * whatsoever, so it was really a mistake to have it in the
- * API. We could fix this by officially deprecating it, or
- * else inventing semantics and providing an actual
- * implementation for it. */
- default:
- pixman_filter = PIXMAN_FILTER_BEST;
- }
-
- if (! pixman_image_set_filter (surface->pixman_image,
- pixman_filter,
- NULL, 0))
- {
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
- }
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_image_surface_set_extend (cairo_image_surface_t *surface,
- cairo_extend_t extend)
-{
- pixman_repeat_t pixman_repeat;
-
- switch (extend) {
- case CAIRO_EXTEND_NONE:
- pixman_repeat = PIXMAN_REPEAT_NONE;
- break;
- case CAIRO_EXTEND_REPEAT:
- pixman_repeat = PIXMAN_REPEAT_NORMAL;
- break;
- case CAIRO_EXTEND_REFLECT:
- pixman_repeat = PIXMAN_REPEAT_REFLECT;
- break;
- case CAIRO_EXTEND_PAD:
- pixman_repeat = PIXMAN_REPEAT_PAD;
- break;
- }
-
- pixman_image_set_repeat (surface->pixman_image, pixman_repeat);
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_image_surface_set_component_alpha (cairo_image_surface_t *surface,
- cairo_bool_t ca)
-{
- pixman_image_set_component_alpha (surface->pixman_image, ca);
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_image_surface_set_attributes (cairo_image_surface_t *surface,
- cairo_surface_attributes_t *attributes,
- double xc, double yc)
-{
- cairo_int_status_t status;
-
- status = _cairo_image_surface_set_matrix (surface, &attributes->matrix,
- xc, yc);
- if (unlikely (status))
- return status;
-
- status = _cairo_image_surface_set_filter (surface, attributes->filter);
- if (unlikely (status))
- return status;
-
- status = _cairo_image_surface_set_extend (surface, attributes->extend);
- if (unlikely (status))
- return status;
-
- status = _cairo_image_surface_set_component_alpha (surface,
- attributes->has_component_alpha);
- if (unlikely (status))
- return status;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
/* XXX: I think we should fix pixman to match the names/order of the
* cairo operators, but that will likely be better done at the same
* time the X server is ported to pixman, (which will change a lot of
@@ -1077,25 +813,3100 @@ static cairo_status_t
_cairo_image_surface_set_clip_region (cairo_image_surface_t *surface,
cairo_region_t *region)
{
- if (region == surface->clip_region)
+ if (! pixman_image_set_clip_region32 (surface->pixman_image, ®ion->rgn))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static void
+_cairo_image_surface_unset_clip_region (cairo_image_surface_t *surface)
+{
+ pixman_image_set_clip_region32 (surface->pixman_image, NULL);
+}
+
+static double
+_pixman_nearest_sample (double d)
+{
+ return ceil (d - .5);
+}
+
+static cairo_bool_t
+_nearest_sample (cairo_filter_t filter, double *tx, double *ty)
+{
+ if (filter == CAIRO_FILTER_FAST || filter == CAIRO_FILTER_NEAREST) {
+ *tx = _pixman_nearest_sample (*tx);
+ *ty = _pixman_nearest_sample (*ty);
+ } else {
+ if (*tx != floor (*tx) || *ty != floor (*ty))
+ return FALSE;
+ }
+ return fabs (*tx) < PIXMAN_MAX_INT && fabs (*ty) < PIXMAN_MAX_INT;
+}
+
+#if HAS_ATOMIC_OPS
+static pixman_image_t *
+_pixman_transparent_image (void)
+{
+ static pixman_image_t *__pixman_transparent_image;
+ pixman_image_t *image;
+
+ image = __pixman_transparent_image;
+ if (unlikely (image == NULL)) {
+ pixman_color_t color;
+
+ color.red = 0x00;
+ color.green = 0x00;
+ color.blue = 0x00;
+ color.alpha = 0x00;
+
+ image = pixman_image_create_solid_fill (&color);
+
+ if (_cairo_atomic_ptr_cmpxchg (&__pixman_transparent_image,
+ NULL, image) == NULL)
+ {
+ pixman_image_ref (image);
+ }
+ } else {
+ pixman_image_ref (image);
+ }
+
+ return image;
+}
+
+static pixman_image_t *
+_pixman_black_image (void)
+{
+ static pixman_image_t *__pixman_black_image;
+ pixman_image_t *image;
+
+ image = __pixman_black_image;
+ if (unlikely (image == NULL)) {
+ pixman_color_t color;
+
+ color.red = 0x00;
+ color.green = 0x00;
+ color.blue = 0x00;
+ color.alpha = 0xffff;
+
+ image = pixman_image_create_solid_fill (&color);
+
+ if (_cairo_atomic_ptr_cmpxchg (&__pixman_black_image,
+ NULL, image) == NULL)
+ {
+ pixman_image_ref (image);
+ }
+ } else {
+ pixman_image_ref (image);
+ }
+
+ return image;
+}
+
+static pixman_image_t *
+_pixman_white_image (void)
+{
+ static pixman_image_t *__pixman_white_image;
+ pixman_image_t *image;
+
+ image = __pixman_white_image;
+ if (unlikely (image == NULL)) {
+ pixman_color_t color;
+
+ color.red = 0xffff;
+ color.green = 0xffff;
+ color.blue = 0xffff;
+ color.alpha = 0xffff;
+
+ image = pixman_image_create_solid_fill (&color);
+
+ if (_cairo_atomic_ptr_cmpxchg (&__pixman_white_image,
+ NULL, image) == NULL)
+ {
+ pixman_image_ref (image);
+ }
+ } else {
+ pixman_image_ref (image);
+ }
+
+ return image;
+}
+#else
+static pixman_image_t *
+_pixman_white_image (void)
+{
+ return _pixman_image_for_solid (&_cairo_pattern_white);
+}
+#endif
+
+static uint32_t
+hars_petruska_f54_1_random (void)
+{
+#define rol(x,k) ((x << k) | (x >> (32-k)))
+ static uint32_t x;
+ return x = (x ^ rol (x, 5) ^ rol (x, 24)) + 0x37798849;
+#undef rol
+}
+
+static pixman_image_t *
+_pixman_image_for_solid (const cairo_solid_pattern_t *pattern)
+{
+ static struct {
+ cairo_color_t color;
+ pixman_image_t *image;
+ } cache[16];
+ static int n_cached;
+ pixman_color_t color;
+ pixman_image_t *image;
+ int i;
+
+#if HAS_ATOMIC_OPS
+ if (pattern->color.alpha_short <= 0x00ff)
+ return _pixman_transparent_image ();
+
+ if (pattern->color.alpha_short >= 0xff00) {
+ if (pattern->color.red_short <= 0x00ff &&
+ pattern->color.green_short <= 0x00ff &&
+ pattern->color.blue_short <= 0x00ff)
+ {
+ return _pixman_black_image ();
+ }
+
+ if (pattern->color.red_short >= 0xff00 &&
+ pattern->color.green_short >= 0xff00 &&
+ pattern->color.blue_short >= 0xff00)
+ {
+ return _pixman_white_image ();
+ }
+ }
+#endif
+
+ CAIRO_MUTEX_LOCK (_cairo_image_solid_cache_mutex);
+ for (i = 0; i < n_cached; i++) {
+ if (_cairo_color_equal (&cache[i].color, &pattern->color)) {
+ image = pixman_image_ref (cache[i].image);
+ goto UNLOCK;
+ }
+ }
+
+ color.red = pattern->color.red_short;
+ color.green = pattern->color.green_short;
+ color.blue = pattern->color.blue_short;
+ color.alpha = pattern->color.alpha_short;
+
+ image = pixman_image_create_solid_fill (&color);
+ if (image == NULL)
+ goto UNLOCK;
+
+ if (n_cached < ARRAY_LENGTH (cache)) {
+ i = n_cached++;
+ } else {
+ i = hars_petruska_f54_1_random () % ARRAY_LENGTH (cache);
+ pixman_image_unref (cache[i].image);
+ }
+ cache[i].image = pixman_image_ref (image);
+ cache[i].color = pattern->color;
+
+UNLOCK:
+ CAIRO_MUTEX_UNLOCK (_cairo_image_solid_cache_mutex);
+ return image;
+}
+
+static pixman_image_t *
+_pixman_image_for_gradient (const cairo_gradient_pattern_t *pattern,
+ const cairo_rectangle_int_t *extents,
+ int *ix, int *iy)
+{
+ pixman_image_t *pixman_image;
+ pixman_gradient_stop_t pixman_stops_static[2];
+ pixman_gradient_stop_t *pixman_stops = pixman_stops_static;
+ cairo_matrix_t matrix = pattern->base.matrix;
+ double tx, ty;
+ unsigned int i;
+
+ if (pattern->n_stops > ARRAY_LENGTH(pixman_stops_static)) {
+ pixman_stops = _cairo_malloc_ab (pattern->n_stops,
+ sizeof(pixman_gradient_stop_t));
+ if (unlikely (pixman_stops == NULL))
+ return NULL;
+ }
+
+ for (i = 0; i < pattern->n_stops; i++) {
+ pixman_stops[i].x = _cairo_fixed_16_16_from_double (pattern->stops[i].offset);
+ pixman_stops[i].color.red = pattern->stops[i].color.red_short;
+ pixman_stops[i].color.green = pattern->stops[i].color.green_short;
+ pixman_stops[i].color.blue = pattern->stops[i].color.blue_short;
+ pixman_stops[i].color.alpha = pattern->stops[i].color.alpha_short;
+ }
+
+ if (pattern->base.type == CAIRO_PATTERN_TYPE_LINEAR) {
+ cairo_linear_pattern_t *linear = (cairo_linear_pattern_t *) pattern;
+ pixman_point_fixed_t p1, p2;
+ cairo_fixed_t xdim, ydim;
+
+ xdim = fabs (linear->p2.x - linear->p1.x);
+ ydim = fabs (linear->p2.y - linear->p1.y);
+
+ /*
+ * Transform the matrix to avoid overflow when converting between
+ * cairo_fixed_t and pixman_fixed_t (without incurring performance
+ * loss when the transformation is unnecessary).
+ *
+ * XXX: Consider converting out-of-range co-ordinates and transforms.
+ * Having a function to compute the required transformation to
+ * "normalize" a given bounding box would be generally useful -
+ * cf linear patterns, gradient patterns, surface patterns...
+ */
+ if (_cairo_fixed_integer_ceil (xdim) > PIXMAN_MAX_INT ||
+ _cairo_fixed_integer_ceil (ydim) > PIXMAN_MAX_INT)
+ {
+ double sf;
+
+ if (xdim > ydim)
+ sf = PIXMAN_MAX_INT / _cairo_fixed_to_double (xdim);
+ else
+ sf = PIXMAN_MAX_INT / _cairo_fixed_to_double (ydim);
+
+ p1.x = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (linear->p1.x) * sf);
+ p1.y = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (linear->p1.y) * sf);
+ p2.x = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (linear->p2.x) * sf);
+ p2.y = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (linear->p2.y) * sf);
+
+ cairo_matrix_scale (&matrix, sf, sf);
+ }
+ else
+ {
+ p1.x = _cairo_fixed_to_16_16 (linear->p1.x);
+ p1.y = _cairo_fixed_to_16_16 (linear->p1.y);
+ p2.x = _cairo_fixed_to_16_16 (linear->p2.x);
+ p2.y = _cairo_fixed_to_16_16 (linear->p2.y);
+ }
+
+ pixman_image = pixman_image_create_linear_gradient (&p1, &p2,
+ pixman_stops,
+ pattern->n_stops);
+ } else {
+ cairo_radial_pattern_t *radial = (cairo_radial_pattern_t *) pattern;
+ pixman_point_fixed_t c1, c2;
+ pixman_fixed_t r1, r2;
+
+ c1.x = _cairo_fixed_to_16_16 (radial->c1.x);
+ c1.y = _cairo_fixed_to_16_16 (radial->c1.y);
+ r1 = _cairo_fixed_to_16_16 (radial->r1);
+
+ c2.x = _cairo_fixed_to_16_16 (radial->c2.x);
+ c2.y = _cairo_fixed_to_16_16 (radial->c2.y);
+ r2 = _cairo_fixed_to_16_16 (radial->r2);
+
+ pixman_image = pixman_image_create_radial_gradient (&c1, &c2, r1, r2,
+ pixman_stops,
+ pattern->n_stops);
+ }
+
+ if (pixman_stops != pixman_stops_static)
+ free (pixman_stops);
+
+ tx = pattern->base.matrix.x0;
+ ty = pattern->base.matrix.y0;
+ if (! _cairo_matrix_is_translation (&pattern->base.matrix) ||
+ ! _nearest_sample (pattern->base.filter, &tx, &ty))
+ {
+ pixman_transform_t pixman_transform;
+
+ if (tx != 0. || ty != 0.) {
+ cairo_matrix_t m, inv;
+ cairo_status_t status;
+ double x, y;
+
+ /* pixman also limits the [xy]_offset to 16 bits so evenly
+ * spread the bits between the two.
+ */
+ inv = pattern->base.matrix;
+ status = cairo_matrix_invert (&inv);
+ assert (status == CAIRO_STATUS_SUCCESS);
+
+ x = floor (inv.x0 / 2);
+ y = floor (inv.y0 / 2);
+ tx = -x;
+ ty = -y;
+ cairo_matrix_init_translate (&inv, x, y);
+ cairo_matrix_multiply (&m, &inv, &pattern->base.matrix);
+ _cairo_matrix_to_pixman_matrix (&m, &pixman_transform,
+ extents->x + extents->width/2.,
+ extents->y + extents->height/2.);
+ } else {
+ tx = ty = 0;
+ _cairo_matrix_to_pixman_matrix (&pattern->base.matrix,
+ &pixman_transform,
+ extents->x + extents->width/2.,
+ extents->y + extents->height/2.);
+ }
+
+ if (! pixman_image_set_transform (pixman_image, &pixman_transform)) {
+ pixman_image_unref (pixman_image);
+ return NULL;
+ }
+ }
+ *ix = tx;
+ *iy = ty;
+
+ {
+ pixman_repeat_t pixman_repeat;
+
+ switch (pattern->base.extend) {
+ default:
+ case CAIRO_EXTEND_NONE:
+ pixman_repeat = PIXMAN_REPEAT_NONE;
+ break;
+ case CAIRO_EXTEND_REPEAT:
+ pixman_repeat = PIXMAN_REPEAT_NORMAL;
+ break;
+ case CAIRO_EXTEND_REFLECT:
+ pixman_repeat = PIXMAN_REPEAT_REFLECT;
+ break;
+ case CAIRO_EXTEND_PAD:
+ pixman_repeat = PIXMAN_REPEAT_PAD;
+ break;
+ }
+
+ pixman_image_set_repeat (pixman_image, pixman_repeat);
+ }
+
+ return pixman_image;
+}
+
+struct acquire_source_cleanup {
+ cairo_surface_t *surface;
+ cairo_image_surface_t *image;
+ void *image_extra;
+};
+
+static void
+_acquire_source_cleanup (pixman_image_t *pixman_image,
+ void *closure)
+{
+ struct acquire_source_cleanup *data = closure;
+
+ _cairo_surface_release_source_image (data->surface,
+ data->image,
+ data->image_extra);
+ free (data);
+}
+
+static pixman_image_t *
+_pixman_image_for_surface (const cairo_surface_pattern_t *pattern,
+ const cairo_rectangle_int_t *extents,
+ int *ix, int *iy)
+{
+ pixman_image_t *pixman_image;
+ cairo_extend_t extend;
+ double tx, ty;
+
+ tx = pattern->base.matrix.x0;
+ ty = pattern->base.matrix.y0;
+
+ extend = pattern->base.extend;
+
+ pixman_image = NULL;
+ if (pattern->surface->type == CAIRO_SURFACE_TYPE_IMAGE) {
+ cairo_image_surface_t *source = (cairo_image_surface_t *) pattern->surface;
+ cairo_surface_type_t type;
+
+ if (source->base.backend->type == CAIRO_INTERNAL_SURFACE_TYPE_SNAPSHOT)
+ source = (cairo_image_surface_t *) ((cairo_surface_snapshot_t *) pattern->surface)->target;
+
+ type = source->base.backend->type;
+ if (type == CAIRO_SURFACE_TYPE_IMAGE) {
+ if (extend != CAIRO_EXTEND_NONE &&
+ extents->x >= 0 && extents->y >= 0 &&
+ extents->x + extents->width <= source->width &&
+ extents->y + extents->height <= source->height)
+ {
+ extend = CAIRO_EXTEND_NONE;
+ }
+
+ /* avoid allocating a 'pattern' image if we can reuse the original */
+ if (extend == CAIRO_EXTEND_NONE &&
+ _cairo_matrix_is_translation (&pattern->base.matrix) &&
+ _nearest_sample (pattern->base.filter, &tx, &ty))
+ {
+ *ix = tx;
+ *iy = ty;
+ return pixman_image_ref (source->pixman_image);
+ }
+
+ pixman_image = pixman_image_create_bits (source->pixman_format,
+ source->width,
+ source->height,
+ (uint32_t *) source->data,
+ source->stride);
+ if (unlikely (pixman_image == NULL))
+ return NULL;
+ } else if (type == CAIRO_INTERNAL_SURFACE_TYPE_SUBSURFACE) {
+ cairo_surface_subsurface_t *sub;
+ cairo_bool_t is_contained = FALSE;
+
+ sub = (cairo_surface_subsurface_t *) source;
+ source = (cairo_image_surface_t *) sub->target;
+
+ if (extend != CAIRO_EXTEND_NONE &&
+ extents->x >= 0 && extents->y >= 0 &&
+ extents->x + extents->width <= sub->extents.width &&
+ extents->y + extents->height <= sub->extents.height)
+ {
+ extend = CAIRO_EXTEND_NONE;
+ is_contained = TRUE;
+ }
+
+ if (is_contained &&
+ _cairo_matrix_is_translation (&pattern->base.matrix) &&
+ _nearest_sample (pattern->base.filter, &tx, &ty))
+ {
+ *ix = tx + sub->extents.x;
+ *iy = ty + sub->extents.y;
+ return pixman_image_ref (source->pixman_image);
+ }
+
+ /* Avoid sub-byte offsets, force a copy in that case. */
+ if (PIXMAN_FORMAT_BPP (source->pixman_format) >= 8) {
+ pixman_image = pixman_image_create_bits (source->pixman_format,
+ sub->extents.width,
+ sub->extents.height,
+ (uint32_t *) (source->data + sub->extents.x * PIXMAN_FORMAT_BPP(source->pixman_format)/8 + sub->extents.y * source->stride),
+ source->stride);
+ if (unlikely (pixman_image == NULL))
+ return NULL;
+ }
+ }
+ }
+
+ if (pixman_image == NULL) {
+ struct acquire_source_cleanup *cleanup;
+ cairo_image_surface_t *source = (cairo_image_surface_t *) pattern->surface;
+ cairo_status_t status;
+
+ cleanup = malloc (sizeof (*cleanup));
+ if (unlikely (cleanup == NULL))
+ return NULL;
+
+ cleanup->surface = pattern->surface;
+ status = _cairo_surface_acquire_source_image (pattern->surface,
+ &cleanup->image,
+ &cleanup->image_extra);
+ if (unlikely (status)) {
+ free (cleanup);
+ return NULL;
+ }
+
+ source = cleanup->image;
+ if (extend != CAIRO_EXTEND_NONE &&
+ extents->x >= 0 && extents->y >= 0 &&
+ extents->x + extents->width <= source->width &&
+ extents->y + extents->height <= source->height)
+ {
+ extend = CAIRO_EXTEND_NONE;
+ }
+
+ pixman_image = pixman_image_create_bits (source->pixman_format,
+ source->width,
+ source->height,
+ (uint32_t *) source->data,
+ source->stride);
+ if (unlikely (pixman_image == NULL)) {
+ _cairo_surface_release_source_image (pattern->surface,
+ cleanup->image,
+ cleanup->image_extra);
+ free (cleanup);
+ return NULL;
+ }
+
+ pixman_image_set_destroy_function (pixman_image,
+ _acquire_source_cleanup, cleanup);
+ }
+
+ if (! _cairo_matrix_is_translation (&pattern->base.matrix) ||
+ ! _nearest_sample (pattern->base.filter, &tx, &ty))
+ {
+ pixman_transform_t pixman_transform;
+ cairo_matrix_t m;
+
+ m = pattern->base.matrix;
+ if (m.x0 != 0. || m.y0 != 0.) {
+ cairo_matrix_t inv;
+ cairo_status_t status;
+ double x, y;
+
+ /* pixman also limits the [xy]_offset to 16 bits so evenly
+ * spread the bits between the two.
+ */
+ inv = m;
+ status = cairo_matrix_invert (&inv);
+ assert (status == CAIRO_STATUS_SUCCESS);
+
+ x = floor (inv.x0 / 2);
+ y = floor (inv.y0 / 2);
+ tx = -x;
+ ty = -y;
+ cairo_matrix_init_translate (&inv, x, y);
+ cairo_matrix_multiply (&m, &inv, &m);
+ } else {
+ tx = ty = 0;
+ }
+
+ _cairo_matrix_to_pixman_matrix (&m, &pixman_transform,
+ extents->x + extents->width/2.,
+ extents->y + extents->height/2.);
+ if (! pixman_image_set_transform (pixman_image, &pixman_transform)) {
+ pixman_image_unref (pixman_image);
+ return NULL;
+ }
+ }
+ *ix = tx;
+ *iy = ty;
+
+ if (_cairo_matrix_has_unity_scale (&pattern->base.matrix) &&
+ tx == pattern->base.matrix.x0 &&
+ ty == pattern->base.matrix.y0)
+ {
+ pixman_image_set_filter (pixman_image, PIXMAN_FILTER_NEAREST, NULL, 0);
+ }
+ else
+ {
+ pixman_filter_t pixman_filter;
+
+ switch (pattern->base.filter) {
+ case CAIRO_FILTER_FAST:
+ pixman_filter = PIXMAN_FILTER_FAST;
+ break;
+ case CAIRO_FILTER_GOOD:
+ pixman_filter = PIXMAN_FILTER_GOOD;
+ break;
+ case CAIRO_FILTER_BEST:
+ pixman_filter = PIXMAN_FILTER_BEST;
+ break;
+ case CAIRO_FILTER_NEAREST:
+ pixman_filter = PIXMAN_FILTER_NEAREST;
+ break;
+ case CAIRO_FILTER_BILINEAR:
+ pixman_filter = PIXMAN_FILTER_BILINEAR;
+ break;
+ case CAIRO_FILTER_GAUSSIAN:
+ /* XXX: The GAUSSIAN value has no implementation in cairo
+ * whatsoever, so it was really a mistake to have it in the
+ * API. We could fix this by officially deprecating it, or
+ * else inventing semantics and providing an actual
+ * implementation for it. */
+ default:
+ pixman_filter = PIXMAN_FILTER_BEST;
+ }
+
+ pixman_image_set_filter (pixman_image, pixman_filter, NULL, 0);
+ }
+
+ {
+ pixman_repeat_t pixman_repeat;
+
+ switch (extend) {
+ default:
+ case CAIRO_EXTEND_NONE:
+ pixman_repeat = PIXMAN_REPEAT_NONE;
+ break;
+ case CAIRO_EXTEND_REPEAT:
+ pixman_repeat = PIXMAN_REPEAT_NORMAL;
+ break;
+ case CAIRO_EXTEND_REFLECT:
+ pixman_repeat = PIXMAN_REPEAT_REFLECT;
+ break;
+ case CAIRO_EXTEND_PAD:
+ pixman_repeat = PIXMAN_REPEAT_PAD;
+ break;
+ }
+
+ pixman_image_set_repeat (pixman_image, pixman_repeat);
+ }
+
+ return pixman_image;
+}
+
+static pixman_image_t *
+_pixman_image_for_pattern (const cairo_pattern_t *pattern,
+ const cairo_rectangle_int_t *extents,
+ int *tx, int *ty)
+{
+ *tx = *ty = 0;
+
+ if (pattern == NULL)
+ return _pixman_white_image ();
+
+ switch (pattern->type) {
+ default:
+ ASSERT_NOT_REACHED;
+ case CAIRO_PATTERN_TYPE_SOLID:
+ return _pixman_image_for_solid ((const cairo_solid_pattern_t *) pattern);
+
+ case CAIRO_PATTERN_TYPE_RADIAL:
+ case CAIRO_PATTERN_TYPE_LINEAR:
+ return _pixman_image_for_gradient ((const cairo_gradient_pattern_t *) pattern,
+ extents, tx, ty);
+
+ case CAIRO_PATTERN_TYPE_SURFACE:
+ return _pixman_image_for_surface ((const cairo_surface_pattern_t *) pattern,
+ extents, tx, ty);
+ }
+}
+
+static void
+_cairo_image_surface_fixup_unbounded (cairo_image_surface_t *dst,
+ const cairo_composite_rectangles_t *rects,
+ cairo_clip_t *clip)
+{
+ pixman_image_t *mask = NULL;
+ int mask_x = 0, mask_y = 0;
+
+ if (clip != NULL) {
+ cairo_surface_t *clip_surface;
+
+ clip_surface = _cairo_clip_get_surface (clip, &dst->base);
+ assert (clip_surface->status == CAIRO_STATUS_SUCCESS);
+
+ mask = ((cairo_image_surface_t *) clip_surface)->pixman_image;
+ mask_x = -clip->path->extents.x;
+ mask_y = -clip->path->extents.y;
+ } else {
+ if (rects->bounded.width == rects->unbounded.width &&
+ rects->bounded.height == rects->unbounded.height)
+ {
+ return;
+ }
+ }
+
+ /* top */
+ if (rects->bounded.y != rects->unbounded.y) {
+ int x = rects->unbounded.x;
+ int y = rects->unbounded.y;
+ int width = rects->unbounded.width;
+ int height = rects->bounded.y - y;
+
+ if (mask != NULL) {
+ pixman_image_composite (PIXMAN_OP_OUT_REVERSE,
+ mask, NULL, dst->pixman_image,
+ x + mask_x, y + mask_y,
+ 0, 0,
+ x, y,
+ width, height);
+ } else {
+ pixman_fill ((uint32_t *) dst->data, dst->stride / sizeof (uint32_t),
+ PIXMAN_FORMAT_BPP (dst->pixman_format),
+ x, y, width, height,
+ 0);
+ }
+ }
+
+ /* left */
+ if (rects->bounded.x != rects->unbounded.x) {
+ int x = rects->unbounded.x;
+ int y = rects->bounded.y;
+ int width = rects->bounded.x - rects->unbounded.x;
+ int height = rects->bounded.height;
+
+ if (mask != NULL) {
+ pixman_image_composite (PIXMAN_OP_OUT_REVERSE,
+ mask, NULL, dst->pixman_image,
+ x + mask_x, y + mask_y,
+ 0, 0,
+ x, y,
+ width, height);
+ } else {
+ pixman_fill ((uint32_t *) dst->data, dst->stride / sizeof (uint32_t),
+ PIXMAN_FORMAT_BPP (dst->pixman_format),
+ x, y, width, height,
+ 0);
+ }
+ }
+
+ /* right */
+ if (rects->bounded.x + rects->bounded.width != rects->unbounded.x + rects->unbounded.width) {
+ int x = rects->bounded.x + rects->bounded.width;
+ int y = rects->bounded.y;
+ int width = rects->unbounded.x + rects->unbounded.width - x;
+ int height = rects->bounded.height;
+
+ if (mask != NULL) {
+ pixman_image_composite (PIXMAN_OP_OUT_REVERSE,
+ mask, NULL, dst->pixman_image,
+ x + mask_x, y + mask_y,
+ 0, 0,
+ x, y,
+ width, height);
+ } else {
+ pixman_fill ((uint32_t *) dst->data, dst->stride / sizeof (uint32_t),
+ PIXMAN_FORMAT_BPP (dst->pixman_format),
+ x, y, width, height,
+ 0);
+ }
+ }
+
+ /* bottom */
+ if (rects->bounded.y + rects->bounded.height != rects->unbounded.y + rects->unbounded.height) {
+ int x = rects->unbounded.x;
+ int y = rects->bounded.y + rects->bounded.height;
+ int width = rects->unbounded.width;
+ int height = rects->unbounded.y + rects->unbounded.height - y;
+
+ if (mask != NULL) {
+ pixman_image_composite (PIXMAN_OP_OUT_REVERSE,
+ mask, NULL, dst->pixman_image,
+ x + mask_x, y + mask_y,
+ 0, 0,
+ x, y,
+ width, height);
+ } else {
+ pixman_fill ((uint32_t *) dst->data, dst->stride / sizeof (uint32_t),
+ PIXMAN_FORMAT_BPP (dst->pixman_format),
+ x, y, width, height,
+ 0);
+ }
+ }
+}
+
+static cairo_status_t
+_cairo_image_surface_fixup_unbounded_boxes (cairo_image_surface_t *dst,
+ const cairo_composite_rectangles_t *extents,
+ cairo_region_t *clip_region,
+ cairo_boxes_t *boxes)
+{
+ cairo_boxes_t clear;
+ cairo_box_t box;
+ cairo_status_t status;
+ struct _cairo_boxes_chunk *chunk;
+ int i;
+
+ if (boxes->num_boxes <= 1 && clip_region == NULL) {
+ _cairo_image_surface_fixup_unbounded (dst, extents, NULL);
return CAIRO_STATUS_SUCCESS;
+ }
+
+ _cairo_boxes_init (&clear);
+
+ box.p1.x = _cairo_fixed_from_int (extents->unbounded.x + extents->unbounded.width);
+ box.p1.y = _cairo_fixed_from_int (extents->unbounded.y);
+ box.p2.x = _cairo_fixed_from_int (extents->unbounded.x);
+ box.p2.y = _cairo_fixed_from_int (extents->unbounded.y + extents->unbounded.height);
+
+ if (clip_region == NULL) {
+ cairo_boxes_t tmp;
+
+ _cairo_boxes_init (&tmp);
+
+ status = _cairo_boxes_add (&tmp, &box);
+ assert (status == CAIRO_STATUS_SUCCESS);
+
+ tmp.chunks.next = &boxes->chunks;
+ tmp.num_boxes += boxes->num_boxes;
+
+ status = _cairo_bentley_ottmann_tessellate_boxes (&tmp,
+ CAIRO_FILL_RULE_WINDING,
+ &clear);
+
+ tmp.chunks.next = NULL;
+ } else {
+ pixman_box32_t *pbox;
+
+ pbox = pixman_region32_rectangles (&clip_region->rgn, &i);
+ _cairo_boxes_limit (&clear, (cairo_box_t *) pbox, i);
+
+ status = _cairo_boxes_add (&clear, &box);
+ assert (status == CAIRO_STATUS_SUCCESS);
+
+ for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
+ for (i = 0; i < chunk->count; i++) {
+ status = _cairo_boxes_add (&clear, &chunk->base[i]);
+ if (unlikely (status)) {
+ _cairo_boxes_fini (&clear);
+ return status;
+ }
+ }
+ }
+
+ status = _cairo_bentley_ottmann_tessellate_boxes (&clear,
+ CAIRO_FILL_RULE_WINDING,
+ &clear);
+ }
+
+ if (likely (status == CAIRO_STATUS_SUCCESS)) {
+ for (chunk = &clear.chunks; chunk != NULL; chunk = chunk->next) {
+ for (i = 0; i < chunk->count; i++) {
+ int x1 = _cairo_fixed_integer_part (chunk->base[i].p1.x);
+ int y1 = _cairo_fixed_integer_part (chunk->base[i].p1.y);
+ int x2 = _cairo_fixed_integer_part (chunk->base[i].p2.x);
+ int y2 = _cairo_fixed_integer_part (chunk->base[i].p2.y);
+
+ pixman_fill ((uint32_t *) dst->data, dst->stride / sizeof (uint32_t),
+ PIXMAN_FORMAT_BPP (dst->pixman_format),
+ x1, y1, x2 - x1, y2 - y1,
+ 0);
+ }
+ }
+ }
+
+ _cairo_boxes_fini (&clear);
+
+ return status;
+}
+
+static cairo_bool_t
+can_reduce_alpha_op (cairo_operator_t op)
+{
+ int iop = op;
+ switch (iop) {
+ case CAIRO_OPERATOR_OVER:
+ case CAIRO_OPERATOR_SOURCE:
+ case CAIRO_OPERATOR_ADD:
+ return TRUE;
+ default:
+ return FALSE;
+ }
+}
+
+static cairo_bool_t
+reduce_alpha_op (cairo_image_surface_t *dst,
+ cairo_operator_t op,
+ const cairo_pattern_t *pattern)
+{
+ return dst->base.is_clear &&
+ dst->base.content == CAIRO_CONTENT_ALPHA &&
+ _cairo_pattern_is_opaque_solid (pattern) &&
+ can_reduce_alpha_op (op);
+}
+
+/* low level compositor */
+typedef cairo_status_t
+(*image_draw_func_t) (void *closure,
+ pixman_image_t *dst,
+ pixman_format_code_t dst_format,
+ cairo_operator_t op,
+ const cairo_pattern_t *src,
+ int dst_x,
+ int dst_y,
+ const cairo_rectangle_int_t *extents,
+ cairo_region_t *clip_region);
+
+static pixman_image_t *
+_create_composite_mask_pattern (cairo_clip_t *clip,
+ image_draw_func_t draw_func,
+ void *draw_closure,
+ cairo_image_surface_t *dst,
+ const cairo_rectangle_int_t *extents)
+{
+ cairo_region_t *clip_region = NULL;
+ pixman_image_t *mask;
+ cairo_status_t status;
+ cairo_bool_t need_clip_surface = FALSE;
+
+ if (clip != NULL) {
+ status = _cairo_clip_get_region (clip, &clip_region);
+ assert (! _cairo_status_is_error (status));
+
+ /* The all-clipped state should never propagate this far. */
+ assert (status != CAIRO_INT_STATUS_NOTHING_TO_DO);
- if (cairo_region_equal (surface->clip_region, region))
+ need_clip_surface = status == CAIRO_INT_STATUS_UNSUPPORTED;
+
+ if (clip_region != NULL && cairo_region_num_rectangles (clip_region) == 1)
+ clip_region = NULL;
+ }
+
+ mask = pixman_image_create_bits (PIXMAN_a8, extents->width, extents->height,
+ NULL, 0);
+ if (unlikely (mask == NULL))
+ return NULL;
+
+ /* Is it worth setting the clip region here? */
+ if (clip_region != NULL) {
+ pixman_region32_translate (&clip_region->rgn, -extents->x, -extents->y);
+ pixman_image_set_clip_region32 (mask, &clip_region->rgn);
+ pixman_region32_translate (&clip_region->rgn, extents->x, extents->y);
+ }
+
+ status = draw_func (draw_closure,
+ mask, PIXMAN_a8,
+ CAIRO_OPERATOR_ADD, NULL,
+ extents->x, extents->y,
+ extents, NULL);
+ if (unlikely (status)) {
+ pixman_image_unref (mask);
+ return NULL;
+ }
+
+ if (need_clip_surface) {
+ cairo_surface_t *tmp;
+
+ tmp = _cairo_image_surface_create_for_pixman_image (mask, PIXMAN_a8);
+ if (unlikely (tmp->status)) {
+ pixman_image_unref (mask);
+ return NULL;
+ }
+
+ pixman_image_ref (mask);
+
+ status = _cairo_clip_combine_with_surface (clip, tmp, extents->x, extents->y);
+ cairo_surface_destroy (tmp);
+ if (unlikely (status)) {
+ pixman_image_unref (mask);
+ return NULL;
+ }
+ }
+
+ if (clip_region != NULL)
+ pixman_image_set_clip_region (mask, NULL);
+
+ return mask;
+}
+
+/* Handles compositing with a clip surface when the operator allows
+ * us to combine the clip with the mask
+ */
+static cairo_status_t
+_clip_and_composite_with_mask (cairo_clip_t *clip,
+ cairo_operator_t op,
+ const cairo_pattern_t *pattern,
+ image_draw_func_t draw_func,
+ void *draw_closure,
+ cairo_image_surface_t *dst,
+ const cairo_rectangle_int_t *extents)
+{
+ pixman_image_t *mask;
+
+ mask = _create_composite_mask_pattern (clip, draw_func, draw_closure, dst, extents);
+ if (unlikely (mask == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+ if (pattern == NULL) {
+ if (dst->pixman_format == PIXMAN_a8) {
+ pixman_image_composite (_pixman_operator (op),
+ mask, NULL, dst->pixman_image,
+ 0, 0, 0, 0,
+ extents->x, extents->y,
+ extents->width, extents->height);
+ } else {
+ pixman_image_t *src;
+
+ src = _pixman_white_image ();
+ if (unlikely (src == NULL)) {
+ pixman_image_unref (mask);
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ }
+
+ pixman_image_composite (_pixman_operator (op),
+ src, mask, dst->pixman_image,
+ 0, 0, 0, 0,
+ extents->x, extents->y,
+ extents->width, extents->height);
+ pixman_image_unref (src);
+ }
+ } else {
+ pixman_image_t *src;
+ int src_x, src_y;
+
+ src = _pixman_image_for_pattern (pattern, extents, &src_x, &src_y);
+ if (unlikely (src == NULL)) {
+ pixman_image_unref (mask);
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ }
+
+ pixman_image_composite (_pixman_operator (op),
+ src, mask, dst->pixman_image,
+ extents->x + src_x, extents->y + src_y,
+ 0, 0,
+ extents->x, extents->y,
+ extents->width, extents->height);
+ pixman_image_unref (src);
+ }
+
+ pixman_image_unref (mask);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+/* Handles compositing with a clip surface when we have to do the operation
+ * in two pieces and combine them together.
+ */
+static cairo_status_t
+_clip_and_composite_combine (cairo_clip_t *clip,
+ cairo_operator_t op,
+ const cairo_pattern_t *src,
+ image_draw_func_t draw_func,
+ void *draw_closure,
+ cairo_image_surface_t *dst,
+ const cairo_rectangle_int_t *extents)
+{
+ pixman_image_t *tmp;
+ cairo_surface_t *clip_surface;
+ cairo_status_t status;
+
+ tmp = pixman_image_create_bits (dst->pixman_format,
+ extents->width, extents->height,
+ NULL, 0);
+ if (unlikely (tmp == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+ if (src == NULL) {
+ status = (*draw_func) (draw_closure,
+ tmp, dst->pixman_format,
+ CAIRO_OPERATOR_ADD, NULL,
+ extents->x, extents->y,
+ extents, NULL);
+ } else {
+ /* Initialize the temporary surface from the destination surface */
+ if (! dst->base.is_clear) {
+ pixman_image_composite (PIXMAN_OP_SRC,
+ dst->pixman_image, NULL, tmp,
+ extents->x, extents->y,
+ 0, 0,
+ 0, 0,
+ extents->width, extents->height);
+ }
+
+ status = (*draw_func) (draw_closure,
+ tmp, dst->pixman_format,
+ op, src,
+ extents->x, extents->y,
+ extents, NULL);
+ }
+ if (unlikely (status))
+ goto CLEANUP_SURFACE;
+
+ assert (clip->path != NULL);
+ clip_surface = _cairo_clip_get_surface (clip, &dst->base);
+ if (unlikely (clip_surface->status))
+ goto CLEANUP_SURFACE;
+
+ if (! dst->base.is_clear) {
+#if PIXMAN_HAS_OP_LERP
+ pixman_image_composite (PIXMAN_OP_LERP,
+ tmp,
+ ((cairo_image_surface_t *) clip_surface)->pixman_image,
+ dst->pixman_image,
+ 0, 0,
+ extents->x - clip->path->extents.x,
+ extents->y - clip->path->extents.y,
+ extents->x, extents->y,
+ extents->width, extents->height);
+#else
+ /* Punch the clip out of the destination */
+ pixman_image_composite (PIXMAN_OP_OUT_REVERSE,
+ ((cairo_image_surface_t *) clip_surface)->pixman_image,
+ NULL, dst->pixman_image,
+ extents->x - clip->path->extents.x,
+ extents->y - clip->path->extents.y,
+ 0, 0,
+ extents->x, extents->y,
+ extents->width, extents->height);
+
+ /* Now add the two results together */
+ pixman_image_composite (PIXMAN_OP_ADD,
+ tmp,
+ ((cairo_image_surface_t *) clip_surface)->pixman_image,
+ dst->pixman_image,
+ 0, 0,
+ extents->x - clip->path->extents.x,
+ extents->y - clip->path->extents.y,
+ extents->x, extents->y,
+ extents->width, extents->height);
+#endif
+ } else {
+ pixman_image_composite (PIXMAN_OP_SRC,
+ tmp,
+ ((cairo_image_surface_t *) clip_surface)->pixman_image,
+ dst->pixman_image,
+ 0, 0,
+ extents->x - clip->path->extents.x,
+ extents->y - clip->path->extents.y,
+ extents->x, extents->y,
+ extents->width, extents->height);
+ }
+
+ CLEANUP_SURFACE:
+ pixman_image_unref (tmp);
+
+ return status;
+}
+
+/* Handles compositing for %CAIRO_OPERATOR_SOURCE, which is special; it's
+ * defined as (src IN mask IN clip) ADD (dst OUT (mask IN clip))
+ */
+static cairo_status_t
+_clip_and_composite_source (cairo_clip_t *clip,
+ const cairo_pattern_t *pattern,
+ image_draw_func_t draw_func,
+ void *draw_closure,
+ cairo_image_surface_t *dst,
+ const cairo_rectangle_int_t *extents)
+{
+ pixman_image_t *mask, *src;
+ int src_x, src_y;
+
+ if (pattern == NULL) {
+ cairo_region_t *clip_region;
+ cairo_status_t status;
+
+ status = draw_func (draw_closure,
+ dst->pixman_image, dst->pixman_format,
+ CAIRO_OPERATOR_SOURCE, NULL,
+ extents->x, extents->y,
+ extents, NULL);
+ if (unlikely (status))
+ return status;
+
+ if (_cairo_clip_get_region (clip, &clip_region) == CAIRO_INT_STATUS_UNSUPPORTED)
+ status = _cairo_clip_combine_with_surface (clip, &dst->base, 0, 0);
+
+ return status;
+ }
+
+ /* Create a surface that is mask IN clip */
+ mask = _create_composite_mask_pattern (clip, draw_func, draw_closure, dst, extents);
+ if (unlikely (mask == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+ src = _pixman_image_for_pattern (pattern, extents, &src_x, &src_y);
+ if (unlikely (src == NULL)) {
+ pixman_image_unref (mask);
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ }
+
+ if (! dst->base.is_clear) {
+#if PIXMAN_HAS_OP_LERP
+ pixman_image_composite (PIXMAN_OP_LERP,
+ src, mask, dst->pixman_image,
+ extents->x + src_x, extents->y + src_y,
+ 0, 0,
+ extents->x, extents->y,
+ extents->width, extents->height);
+#else
+ /* Compute dest' = dest OUT (mask IN clip) */
+ pixman_image_composite (PIXMAN_OP_OUT_REVERSE,
+ mask, NULL, dst->pixman_image,
+ 0, 0, 0, 0,
+ extents->x, extents->y,
+ extents->width, extents->height);
+
+ /* Now compute (src IN (mask IN clip)) ADD dest' */
+ pixman_image_composite (PIXMAN_OP_ADD,
+ src, mask, dst->pixman_image,
+ extents->x + src_x, extents->y + src_y,
+ 0, 0,
+ extents->x, extents->y,
+ extents->width, extents->height);
+#endif
+ } else {
+ pixman_image_composite (PIXMAN_OP_SRC,
+ src, mask, dst->pixman_image,
+ extents->x + src_x, extents->y + src_y,
+ 0, 0,
+ extents->x, extents->y,
+ extents->width, extents->height);
+ }
+
+ pixman_image_unref (src);
+ pixman_image_unref (mask);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_clip_and_composite (cairo_image_surface_t *dst,
+ cairo_operator_t op,
+ const cairo_pattern_t *src,
+ image_draw_func_t draw_func,
+ void *draw_closure,
+ const cairo_composite_rectangles_t*extents,
+ cairo_clip_t *clip)
+{
+ cairo_status_t status;
+ cairo_region_t *clip_region = NULL;
+ cairo_bool_t need_clip_surface = FALSE;
+
+ if (clip != NULL) {
+ status = _cairo_clip_get_region (clip, &clip_region);
+ if (unlikely (status == CAIRO_INT_STATUS_NOTHING_TO_DO))
+ return CAIRO_STATUS_SUCCESS;
+
+ assert (! _cairo_status_is_error (status));
+ need_clip_surface = status == CAIRO_INT_STATUS_UNSUPPORTED;
+
+ if (clip_region != NULL && cairo_region_num_rectangles (clip_region) == 1)
+ clip_region = NULL;
+ }
+
+ if (clip_region != NULL) {
+ status = _cairo_image_surface_set_clip_region (dst, clip_region);
+ if (unlikely (status))
+ return status;
+ }
+
+ if (reduce_alpha_op (dst, op, src)) {
+ op = CAIRO_OPERATOR_ADD;
+ src = NULL;
+ }
+
+ if (op == CAIRO_OPERATOR_SOURCE) {
+ status = _clip_and_composite_source (clip, src,
+ draw_func, draw_closure,
+ dst, &extents->bounded);
+ } else {
+ if (op == CAIRO_OPERATOR_CLEAR) {
+ src = NULL;
+ op = CAIRO_OPERATOR_DEST_OUT;
+ }
+
+ if (need_clip_surface) {
+ if (extents->is_bounded) {
+ status = _clip_and_composite_with_mask (clip, op, src,
+ draw_func, draw_closure,
+ dst, &extents->bounded);
+ } else {
+ status = _clip_and_composite_combine (clip, op, src,
+ draw_func, draw_closure,
+ dst, &extents->bounded);
+ }
+ } else {
+ status = draw_func (draw_closure,
+ dst->pixman_image, dst->pixman_format,
+ op, src,
+ 0, 0,
+ &extents->bounded,
+ clip_region);
+ }
+ }
+
+ if (status == CAIRO_STATUS_SUCCESS && ! extents->is_bounded) {
+ _cairo_image_surface_fixup_unbounded (dst, extents,
+ need_clip_surface ? clip : NULL);
+ }
+
+ if (clip_region != NULL)
+ _cairo_image_surface_unset_clip_region (dst);
+
+ return status;
+}
+
+#define CAIRO_FIXED_16_16_MIN _cairo_fixed_from_int (-32768)
+#define CAIRO_FIXED_16_16_MAX _cairo_fixed_from_int (32767)
+
+static cairo_bool_t
+_line_exceeds_16_16 (const cairo_line_t *line)
+{
+ return
+ line->p1.x <= CAIRO_FIXED_16_16_MIN ||
+ line->p1.x >= CAIRO_FIXED_16_16_MAX ||
+
+ line->p2.x <= CAIRO_FIXED_16_16_MIN ||
+ line->p2.x >= CAIRO_FIXED_16_16_MAX ||
+
+ line->p1.y <= CAIRO_FIXED_16_16_MIN ||
+ line->p1.y >= CAIRO_FIXED_16_16_MAX ||
+
+ line->p2.y <= CAIRO_FIXED_16_16_MIN ||
+ line->p2.y >= CAIRO_FIXED_16_16_MAX;
+}
+
+static void
+_project_line_x_onto_16_16 (const cairo_line_t *line,
+ cairo_fixed_t top,
+ cairo_fixed_t bottom,
+ pixman_line_fixed_t *out)
+{
+ cairo_point_double_t p1, p2;
+ double m;
+
+ p1.x = _cairo_fixed_to_double (line->p1.x);
+ p1.y = _cairo_fixed_to_double (line->p1.y);
+
+ p2.x = _cairo_fixed_to_double (line->p2.x);
+ p2.y = _cairo_fixed_to_double (line->p2.y);
+
+ m = (p2.x - p1.x) / (p2.y - p1.y);
+ out->p1.x = _cairo_fixed_16_16_from_double (p1.x + m * _cairo_fixed_to_double (top - line->p1.y));
+ out->p2.x = _cairo_fixed_16_16_from_double (p1.x + m * _cairo_fixed_to_double (bottom - line->p1.y));
+}
+
+
+typedef struct {
+ cairo_trapezoid_t *traps;
+ int num_traps;
+ cairo_antialias_t antialias;
+} composite_traps_info_t;
+
+static void
+_pixman_image_add_traps (pixman_image_t *image,
+ int dst_x, int dst_y,
+ composite_traps_info_t *info)
+{
+ cairo_trapezoid_t *t = info->traps;
+ int num_traps = info->num_traps;
+ while (num_traps--) {
+ pixman_trapezoid_t trap;
+
+ /* top/bottom will be clamped to surface bounds */
+ trap.top = _cairo_fixed_to_16_16 (t->top);
+ trap.bottom = _cairo_fixed_to_16_16 (t->bottom);
+
+ /* However, all the other coordinates will have been left untouched so
+ * as not to introduce numerical error. Recompute them if they
+ * exceed the 16.16 limits.
+ */
+ if (unlikely (_line_exceeds_16_16 (&t->left))) {
+ _project_line_x_onto_16_16 (&t->left, t->top, t->bottom, &trap.left);
+ trap.left.p1.y = trap.top;
+ trap.left.p2.y = trap.bottom;
+ } else {
+ trap.left.p1.x = _cairo_fixed_to_16_16 (t->left.p1.x);
+ trap.left.p1.y = _cairo_fixed_to_16_16 (t->left.p1.y);
+ trap.left.p2.x = _cairo_fixed_to_16_16 (t->left.p2.x);
+ trap.left.p2.y = _cairo_fixed_to_16_16 (t->left.p2.y);
+ }
+
+ if (unlikely (_line_exceeds_16_16 (&t->right))) {
+ _project_line_x_onto_16_16 (&t->right, t->top, t->bottom, &trap.right);
+ trap.right.p1.y = trap.top;
+ trap.right.p2.y = trap.bottom;
+ } else {
+ trap.right.p1.x = _cairo_fixed_to_16_16 (t->right.p1.x);
+ trap.right.p1.y = _cairo_fixed_to_16_16 (t->right.p1.y);
+ trap.right.p2.x = _cairo_fixed_to_16_16 (t->right.p2.x);
+ trap.right.p2.y = _cairo_fixed_to_16_16 (t->right.p2.y);
+ }
+
+ pixman_rasterize_trapezoid (image, &trap, -dst_x, -dst_y);
+
+ t++;
+ }
+}
+
+static cairo_status_t
+_composite_traps (void *closure,
+ pixman_image_t *dst,
+ pixman_format_code_t dst_format,
+ cairo_operator_t op,
+ const cairo_pattern_t *pattern,
+ int dst_x,
+ int dst_y,
+ const cairo_rectangle_int_t *extents,
+ cairo_region_t *clip_region)
+{
+ composite_traps_info_t *info = closure;
+ pixman_image_t *src, *mask;
+ pixman_format_code_t format;
+ int src_x = 0, src_y = 0;
+ cairo_status_t status;
+
+ /* Special case adding trapezoids onto a mask surface; we want to avoid
+ * creating an intermediate temporary mask unnecessarily.
+ *
+ * We make the assumption here that the portion of the trapezoids
+ * contained within the surface is bounded by [dst_x,dst_y,width,height];
+ * the Cairo core code passes bounds based on the trapezoid extents.
+ */
+ format = info->antialias == CAIRO_ANTIALIAS_NONE ? PIXMAN_a1 : PIXMAN_a8;
+ if (dst_format == format &&
+ (pattern == NULL ||
+ (op == CAIRO_OPERATOR_ADD && _cairo_pattern_is_opaque_solid (pattern))))
+ {
+ _pixman_image_add_traps (dst, dst_x, dst_y, info);
return CAIRO_STATUS_SUCCESS;
+ }
+
+ src = _pixman_image_for_pattern (pattern, extents, &src_x, &src_y);
+ if (unlikely (src == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+ mask = pixman_image_create_bits (format, extents->width, extents->height,
+ NULL, 0);
+ if (unlikely (mask == NULL)) {
+ status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ goto CLEANUP_SOURCE;
+ }
+
+ _pixman_image_add_traps (mask, extents->x, extents->y, info);
+ pixman_image_composite (_pixman_operator (op),
+ src, mask, dst,
+ extents->x + src_x, extents->y + src_y,
+ 0, 0,
+ extents->x - dst_x, extents->y - dst_y,
+ extents->width, extents->height);
+
+ pixman_image_unref (mask);
+
+ status = CAIRO_STATUS_SUCCESS;
+ CLEANUP_SOURCE:
+ pixman_image_unref (src);
- cairo_region_destroy (surface->clip_region);
- surface->clip_region = cairo_region_reference (region);
+ return status;
+}
- if (! pixman_image_set_clip_region32 (surface->pixman_image,
- region ? ®ion->rgn : NULL))
+static inline uint32_t
+color_to_uint32 (const cairo_color_t *color)
+{
+ return
+ (color->alpha_short >> 8 << 24) |
+ (color->red_short >> 8 << 16) |
+ (color->green_short & 0xff00) |
+ (color->blue_short >> 8);
+}
+
+static inline cairo_bool_t
+color_to_pixel (const cairo_color_t *color,
+ pixman_format_code_t format,
+ uint32_t *pixel)
+{
+ uint32_t c;
+
+ if (!(format == PIXMAN_a8r8g8b8 ||
+ format == PIXMAN_x8r8g8b8 ||
+ format == PIXMAN_a8b8g8r8 ||
+ format == PIXMAN_x8b8g8r8 ||
+ format == PIXMAN_b8g8r8a8 ||
+ format == PIXMAN_b8g8r8x8 ||
+ format == PIXMAN_r5g6b5 ||
+ format == PIXMAN_b5g6r5 ||
+ format == PIXMAN_a8))
{
+ return FALSE;
+ }
+
+ c = color_to_uint32 (color);
+
+ if (PIXMAN_FORMAT_TYPE (format) == PIXMAN_TYPE_ABGR) {
+ c = ((c & 0xff000000) >> 0) |
+ ((c & 0x00ff0000) >> 16) |
+ ((c & 0x0000ff00) >> 0) |
+ ((c & 0x000000ff) << 16);
+ }
+
+ if (PIXMAN_FORMAT_TYPE (format) == PIXMAN_TYPE_BGRA) {
+ c = ((c & 0xff000000) >> 24) |
+ ((c & 0x00ff0000) >> 8) |
+ ((c & 0x0000ff00) << 8) |
+ ((c & 0x000000ff) << 24);
+ }
+
+ if (format == PIXMAN_a8) {
+ c = c >> 24;
+ } else if (format == PIXMAN_r5g6b5 || format == PIXMAN_b5g6r5) {
+ c = ((((c) >> 3) & 0x001f) |
+ (((c) >> 5) & 0x07e0) |
+ (((c) >> 8) & 0xf800));
+ }
+
+ *pixel = c;
+ return TRUE;
+}
+
+static inline cairo_bool_t
+pattern_to_pixel (const cairo_solid_pattern_t *solid,
+ cairo_operator_t op,
+ pixman_format_code_t format,
+ uint32_t *pixel)
+{
+ if (op == CAIRO_OPERATOR_CLEAR) {
+ *pixel = 0;
+ return TRUE;
+ }
+
+ if (solid->base.type != CAIRO_PATTERN_TYPE_SOLID)
+ return FALSE;
+
+ if (op == CAIRO_OPERATOR_OVER) {
+ if (solid->color.alpha_short >= 0xff00)
+ op = CAIRO_OPERATOR_SOURCE;
+ }
+
+ if (op != CAIRO_OPERATOR_SOURCE)
+ return FALSE;
+
+ return color_to_pixel (&solid->color, format, pixel);
+}
+
+typedef struct _fill_span {
+ cairo_span_renderer_t base;
+
+ uint8_t *mask_data;
+ pixman_image_t *src, *dst, *mask;
+} fill_span_renderer_t;
+
+static cairo_status_t
+_fill_span (void *abstract_renderer,
+ int y, int height,
+ const cairo_half_open_span_t *spans,
+ unsigned num_spans)
+{
+ fill_span_renderer_t *renderer = abstract_renderer;
+ uint8_t *row;
+ unsigned i;
+
+ if (num_spans == 0)
+ return CAIRO_STATUS_SUCCESS;
+
+ row = renderer->mask_data - spans[0].x;
+ for (i = 0; i < num_spans - 1; i++) {
+ /* We implement setting the most common single pixel wide
+ * span case to avoid the overhead of a memset call.
+ * Open coding setting longer spans didn't show a
+ * noticeable improvement over memset.
+ */
+ if (spans[i+1].x == spans[i].x + 1) {
+ row[spans[i].x] = spans[i].coverage;
+ } else {
+ memset (row + spans[i].x,
+ spans[i].coverage,
+ spans[i+1].x - spans[i].x);
+ }
+ }
+
+ do {
+ pixman_image_composite (PIXMAN_OP_OVER,
+ renderer->src, renderer->mask, renderer->dst,
+ 0, 0, 0, 0,
+ spans[0].x, y++,
+ spans[i].x - spans[0].x, 1);
+ } while (--height);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+/* avoid using region code to re-validate boxes */
+static cairo_status_t
+_fill_unaligned_boxes (cairo_image_surface_t *dst,
+ const cairo_pattern_t *pattern,
+ uint32_t pixel,
+ const cairo_boxes_t *boxes,
+ const cairo_composite_rectangles_t *extents)
+{
+ uint8_t buf[CAIRO_STACK_BUFFER_SIZE];
+ fill_span_renderer_t renderer;
+ cairo_rectangular_scan_converter_t converter;
+ const struct _cairo_boxes_chunk *chunk;
+ cairo_status_t status;
+ int i;
+
+ /* XXX
+ * using composite for fill:
+ * spiral-box-nonalign-evenodd-fill.512 2201957 2.202
+ * spiral-box-nonalign-nonzero-fill.512 336726 0.337
+ * spiral-box-pixalign-evenodd-fill.512 352256 0.352
+ * spiral-box-pixalign-nonzero-fill.512 147056 0.147
+ * using fill:
+ * spiral-box-nonalign-evenodd-fill.512 3174565 3.175
+ * spiral-box-nonalign-nonzero-fill.512 182710 0.183
+ * spiral-box-pixalign-evenodd-fill.512 353863 0.354
+ * spiral-box-pixalign-nonzero-fill.512 147402 0.147
+ *
+ * cairo-perf-trace seems to favour using fill.
+ */
+
+ renderer.base.render_rows = _fill_span;
+ renderer.dst = dst->pixman_image;
+
+ if ((unsigned) extents->bounded.width <= sizeof (buf)) {
+ renderer.mask = pixman_image_create_bits (PIXMAN_a8,
+ extents->bounded.width, 1,
+ (uint32_t *) buf,
+ sizeof (buf));
+ } else {
+ renderer.mask = pixman_image_create_bits (PIXMAN_a8,
+ extents->bounded.width, 1,
+ NULL, 0);
+ }
+ if (unlikely (renderer.mask == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+ renderer.mask_data = (uint8_t *) pixman_image_get_data (renderer.mask);
+
+ renderer.src = _pixman_image_for_solid ((const cairo_solid_pattern_t *) pattern);
+ if (unlikely (renderer.src == NULL)) {
+ status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ goto CLEANUP_MASK;
}
+ _cairo_rectangular_scan_converter_init (&converter, &extents->bounded);
+
+ /* first blit any aligned part of the boxes */
+ for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
+ const cairo_box_t *box = chunk->base;
+
+ for (i = 0; i < chunk->count; i++) {
+ int x1 = _cairo_fixed_integer_ceil (box[i].p1.x);
+ int y1 = _cairo_fixed_integer_ceil (box[i].p1.y);
+ int x2 = _cairo_fixed_integer_floor (box[i].p2.x);
+ int y2 = _cairo_fixed_integer_floor (box[i].p2.y);
+
+ if (x2 > x1 && y2 > y1) {
+ cairo_box_t b;
+
+ pixman_fill ((uint32_t *) dst->data,
+ dst->stride / sizeof (uint32_t),
+ PIXMAN_FORMAT_BPP (dst->pixman_format),
+ x1, y1, x2 - x1, y2 - y1,
+ pixel);
+
+ /* top */
+ if (! _cairo_fixed_is_integer (box[i].p1.y)) {
+ b.p1.x = box[i].p1.x;
+ b.p1.y = box[i].p1.y;
+ b.p2.x = box[i].p2.x;
+ b.p2.y = _cairo_fixed_from_int (y1);
+
+ status = _cairo_rectangular_scan_converter_add_box (&converter, &b, 1);
+ if (unlikely (status))
+ goto CLEANUP_CONVERTER;
+ }
+
+ /* left */
+ if (! _cairo_fixed_is_integer (box[i].p1.x)) {
+ b.p1.x = box[i].p1.x;
+ b.p1.y = box[i].p1.y;
+ b.p2.x = _cairo_fixed_from_int (x1);
+ b.p2.y = box[i].p2.y;
+
+ status = _cairo_rectangular_scan_converter_add_box (&converter, &b, 1);
+ if (unlikely (status))
+ goto CLEANUP_CONVERTER;
+ }
+
+ /* right */
+ if (! _cairo_fixed_is_integer (box[i].p2.x)) {
+ b.p1.x = _cairo_fixed_from_int (x2);
+ b.p1.y = box[i].p1.y;
+ b.p2.x = box[i].p2.x;
+ b.p2.y = box[i].p2.y;
+
+ status = _cairo_rectangular_scan_converter_add_box (&converter, &b, 1);
+ if (unlikely (status))
+ goto CLEANUP_CONVERTER;
+ }
+
+ /* bottom */
+ if (! _cairo_fixed_is_integer (box[i].p2.y)) {
+ b.p1.x = box[i].p1.x;
+ b.p1.y = _cairo_fixed_from_int (y2);
+ b.p2.x = box[i].p2.x;
+ b.p2.y = box[i].p2.y;
+
+ status = _cairo_rectangular_scan_converter_add_box (&converter, &b, 1);
+ if (unlikely (status))
+ goto CLEANUP_CONVERTER;
+ }
+ } else {
+ status = _cairo_rectangular_scan_converter_add_box (&converter, &box[i], 1);
+ if (unlikely (status))
+ goto CLEANUP_CONVERTER;
+ }
+ }
+ }
+
+ status = converter.base.generate (&converter.base, &renderer.base);
+
+ CLEANUP_CONVERTER:
+ converter.base.destroy (&converter.base);
+ pixman_image_unref (renderer.src);
+ CLEANUP_MASK:
+ pixman_image_unref (renderer.mask);
+
+ return status;
+}
+
+typedef struct _cairo_image_surface_span_renderer {
+ cairo_span_renderer_t base;
+
+ uint8_t *mask_data;
+ uint32_t mask_stride;
+} cairo_image_surface_span_renderer_t;
+
+static cairo_status_t
+_cairo_image_surface_span (void *abstract_renderer,
+ int y, int height,
+ const cairo_half_open_span_t *spans,
+ unsigned num_spans)
+{
+ cairo_image_surface_span_renderer_t *renderer = abstract_renderer;
+ uint8_t *row;
+ unsigned i;
+
+ if (num_spans == 0)
+ return CAIRO_STATUS_SUCCESS;
+
+ /* XXX will it be quicker to repeat the sparse memset,
+ * or perform a simpler memcpy?
+ * The fairly dense spiral benchmarks suggests that the sparse
+ * memset is a win there as well.
+ */
+ row = renderer->mask_data + y * renderer->mask_stride;
+ do {
+ for (i = 0; i < num_spans - 1; i++) {
+ if (! spans[i].coverage)
+ continue;
+
+ /* We implement setting rendering the most common single
+ * pixel wide span case to avoid the overhead of a memset
+ * call. Open coding setting longer spans didn't show a
+ * noticeable improvement over memset. */
+ if (spans[i+1].x == spans[i].x + 1) {
+ row[spans[i].x] = spans[i].coverage;
+ } else {
+ memset (row + spans[i].x,
+ spans[i].coverage,
+ spans[i+1].x - spans[i].x);
+ }
+ }
+ row += renderer->mask_stride;
+ } while (--height);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_composite_unaligned_boxes (cairo_image_surface_t *dst,
+ cairo_operator_t op,
+ const cairo_pattern_t *pattern,
+ const cairo_boxes_t *boxes,
+ const cairo_composite_rectangles_t *extents)
+{
+ uint8_t buf[CAIRO_STACK_BUFFER_SIZE];
+ cairo_image_surface_span_renderer_t renderer;
+ cairo_rectangular_scan_converter_t converter;
+ pixman_image_t *mask, *src;
+ cairo_status_t status;
+ const struct _cairo_boxes_chunk *chunk;
+ int i, src_x, src_y;
+
+ i = CAIRO_STRIDE_FOR_WIDTH_BPP (extents->bounded.width, 8) * extents->bounded.height;
+ if ((unsigned) i <= sizeof (buf)) {
+ mask = pixman_image_create_bits (PIXMAN_a8,
+ extents->bounded.width,
+ extents->bounded.height,
+ (uint32_t *) buf,
+ CAIRO_STRIDE_FOR_WIDTH_BPP (extents->bounded.width, 8));
+ memset (buf, 0, i);
+ } else {
+ mask = pixman_image_create_bits (PIXMAN_a8,
+ extents->bounded.width,
+ extents->bounded.height,
+ NULL, 0);
+ }
+ if (unlikely (mask == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+ renderer.base.render_rows = _cairo_image_surface_span;
+ renderer.mask_stride = pixman_image_get_stride (mask);
+ renderer.mask_data = (uint8_t *) pixman_image_get_data (mask);
+ renderer.mask_data -= extents->bounded.y * renderer.mask_stride + extents->bounded.x;
+
+ _cairo_rectangular_scan_converter_init (&converter, &extents->bounded);
+
+ for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
+ const cairo_box_t *box = chunk->base;
+
+ for (i = 0; i < chunk->count; i++) {
+ status = _cairo_rectangular_scan_converter_add_box (&converter, &box[i], 1);
+ if (unlikely (status))
+ goto CLEANUP;
+ }
+ }
+
+ status = converter.base.generate (&converter.base, &renderer.base);
+ if (unlikely (status))
+ goto CLEANUP;
+
+ src = _pixman_image_for_pattern (pattern, &extents->bounded, &src_x, &src_y);
+ if (unlikely (src == NULL)) {
+ status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ goto CLEANUP;
+ }
+
+ pixman_image_composite (_pixman_operator (op),
+ src, mask, dst->pixman_image,
+ extents->bounded.x + src_x, extents->bounded.y + src_y,
+ 0, 0,
+ extents->bounded.x, extents->bounded.y,
+ extents->bounded.width, extents->bounded.height);
+ pixman_image_unref (src);
+
+ CLEANUP:
+ converter.base.destroy (&converter.base);
+ pixman_image_unref (mask);
+
+ return status;
+}
+
+static cairo_status_t
+_composite_boxes (cairo_image_surface_t *dst,
+ cairo_operator_t op,
+ const cairo_pattern_t *pattern,
+ cairo_boxes_t *boxes,
+ cairo_antialias_t antialias,
+ cairo_clip_t *clip,
+ const cairo_composite_rectangles_t *extents)
+{
+ cairo_region_t *clip_region = NULL;
+ cairo_bool_t need_clip_mask = FALSE;
+ cairo_status_t status;
+ struct _cairo_boxes_chunk *chunk;
+ uint32_t pixel;
+ int i;
+
+ if (clip != NULL) {
+ status = _cairo_clip_get_region (clip, &clip_region);
+ need_clip_mask = status == CAIRO_INT_STATUS_UNSUPPORTED;
+ if (need_clip_mask &&
+ (op == CAIRO_OPERATOR_SOURCE || ! extents->is_bounded))
+ {
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ }
+
+ if (clip_region != NULL && cairo_region_num_rectangles (clip_region) == 1)
+ clip_region = NULL;
+ }
+
+ if (antialias != CAIRO_ANTIALIAS_NONE) {
+ if (! boxes->is_pixel_aligned) {
+ if (need_clip_mask)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ if (pattern_to_pixel ((cairo_solid_pattern_t *) pattern, op,
+ dst->pixman_format, &pixel))
+ {
+ return _fill_unaligned_boxes (dst, pattern, pixel, boxes, extents);
+ }
+ else
+ {
+ return _composite_unaligned_boxes (dst, op, pattern, boxes, extents);
+ }
+ }
+ }
+
+ status = CAIRO_STATUS_SUCCESS;
+ if (! need_clip_mask &&
+ pattern_to_pixel ((cairo_solid_pattern_t *) pattern, op, dst->pixman_format,
+ &pixel))
+ {
+ for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
+ cairo_box_t *box = chunk->base;
+
+ for (i = 0; i < chunk->count; i++) {
+ int x1 = _cairo_fixed_integer_round (box[i].p1.x);
+ int y1 = _cairo_fixed_integer_round (box[i].p1.y);
+ int x2 = _cairo_fixed_integer_round (box[i].p2.x);
+ int y2 = _cairo_fixed_integer_round (box[i].p2.y);
+
+ if (x2 == x1 || y2 == y1)
+ continue;
+
+ pixman_fill ((uint32_t *) dst->data, dst->stride / sizeof (uint32_t),
+ PIXMAN_FORMAT_BPP (dst->pixman_format),
+ x1, y1, x2 - x1, y2 - y1,
+ pixel);
+ }
+ }
+ }
+ else
+ {
+ pixman_image_t *src = NULL, *mask = NULL;
+ int src_x, src_y, mask_x = 0, mask_y = 0;
+ pixman_op_t pixman_op = _pixman_operator (op);
+
+ if (need_clip_mask) {
+ cairo_surface_t *clip_surface;
+
+ clip_surface = _cairo_clip_get_surface (clip, &dst->base);
+ if (unlikely (clip_surface->status))
+ return clip_surface->status;
+
+ mask_x = -clip->path->extents.x;
+ mask_y = -clip->path->extents.y;
+
+ if (op == CAIRO_OPERATOR_CLEAR) {
+ pattern = NULL;
+ pixman_op = PIXMAN_OP_OUT_REVERSE;
+ }
+
+ mask = ((cairo_image_surface_t *) clip_surface)->pixman_image;
+ }
+
+ if (pattern != NULL) {
+ src = _pixman_image_for_pattern (pattern, &extents->bounded, &src_x, &src_y);
+ if (unlikely (src == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ } else {
+ src = mask;
+ src_x = mask_x;
+ src_y = mask_y;
+ mask = NULL;
+ }
+
+ for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
+ const cairo_box_t *box = chunk->base;
+
+ for (i = 0; i < chunk->count; i++) {
+ int x1 = _cairo_fixed_integer_round (box[i].p1.x);
+ int y1 = _cairo_fixed_integer_round (box[i].p1.y);
+ int x2 = _cairo_fixed_integer_round (box[i].p2.x);
+ int y2 = _cairo_fixed_integer_round (box[i].p2.y);
+
+ if (x2 == x1 || y2 == y1)
+ continue;
+
+ pixman_image_composite (pixman_op,
+ src, mask, dst->pixman_image,
+ x1 + src_x, y1 + src_y,
+ x1 + mask_x, y1 + mask_y,
+ x1, y1,
+ x2 - x1, y2 - y1);
+ }
+ }
+
+ if (pattern != NULL)
+ pixman_image_unref (src);
+
+ if (! extents->is_bounded) {
+ status =
+ _cairo_image_surface_fixup_unbounded_boxes (dst, extents,
+ clip_region, boxes);
+ }
+ }
+
+ return status;
+}
+
+static cairo_status_t
+_clip_and_composite_boxes (cairo_image_surface_t *dst,
+ cairo_operator_t op,
+ const cairo_pattern_t *src,
+ cairo_boxes_t *boxes,
+ cairo_antialias_t antialias,
+ const cairo_composite_rectangles_t *extents,
+ cairo_clip_t *clip)
+{
+ cairo_traps_t traps;
+ cairo_status_t status;
+ composite_traps_info_t info;
+
+ if (boxes->num_boxes == 0 && extents->is_bounded)
+ return CAIRO_STATUS_SUCCESS;
+
+ /* Use a fast path if the boxes are pixel aligned */
+ status = _composite_boxes (dst, op, src, boxes, antialias, clip, extents);
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+ return status;
+
+ /* Otherwise render via a mask and composite in the usual fashion. */
+ status = _cairo_traps_init_boxes (&traps, boxes);
+ if (unlikely (status))
+ return status;
+
+ info.num_traps = traps.num_traps;
+ info.traps = traps.traps;
+ info.antialias = antialias;
+ return _clip_and_composite (dst, op, src,
+ _composite_traps, &info,
+ extents, clip);
+}
+
+static cairo_bool_t
+_mono_edge_is_vertical (const cairo_line_t *line)
+{
+ return _cairo_fixed_integer_round (line->p1.x) == _cairo_fixed_integer_round (line->p2.x);
+}
+
+static cairo_bool_t
+_traps_are_pixel_aligned (cairo_traps_t *traps,
+ cairo_antialias_t antialias)
+{
+ int i;
+
+ if (antialias == CAIRO_ANTIALIAS_NONE) {
+ for (i = 0; i < traps->num_traps; i++) {
+ if (! _mono_edge_is_vertical (&traps->traps[i].left) ||
+ ! _mono_edge_is_vertical (&traps->traps[i].right))
+ {
+ traps->maybe_region = FALSE;
+ return FALSE;
+ }
+ }
+ } else {
+ for (i = 0; i < traps->num_traps; i++) {
+ if (traps->traps[i].left.p1.x != traps->traps[i].left.p2.x ||
+ traps->traps[i].right.p1.x != traps->traps[i].right.p2.x ||
+ ! _cairo_fixed_is_integer (traps->traps[i].top) ||
+ ! _cairo_fixed_is_integer (traps->traps[i].bottom) ||
+ ! _cairo_fixed_is_integer (traps->traps[i].left.p1.x) ||
+ ! _cairo_fixed_is_integer (traps->traps[i].right.p1.x))
+ {
+ traps->maybe_region = FALSE;
+ return FALSE;
+ }
+ }
+ }
+
+ return TRUE;
+}
+
+static void
+_boxes_for_traps (cairo_boxes_t *boxes,
+ cairo_traps_t *traps)
+{
+ int i;
+
+ _cairo_boxes_init (boxes);
+
+ boxes->num_boxes = traps->num_traps;
+ boxes->chunks.base = (cairo_box_t *) traps->traps;
+ boxes->chunks.count = traps->num_traps;
+ boxes->chunks.size = traps->num_traps;
+
+ for (i = 0; i < traps->num_traps; i++) {
+ cairo_fixed_t x1 = traps->traps[i].left.p1.x;
+ cairo_fixed_t x2 = traps->traps[i].right.p1.x;
+ cairo_fixed_t y1 = traps->traps[i].top;
+ cairo_fixed_t y2 = traps->traps[i].bottom;
+
+ boxes->chunks.base[i].p1.x = x1;
+ boxes->chunks.base[i].p1.y = y1;
+ boxes->chunks.base[i].p2.x = x2;
+ boxes->chunks.base[i].p2.y = y2;
+
+ if (boxes->is_pixel_aligned) {
+ boxes->is_pixel_aligned =
+ _cairo_fixed_is_integer (x1) && _cairo_fixed_is_integer (y1) &&
+ _cairo_fixed_is_integer (x2) && _cairo_fixed_is_integer (y2);
+ }
+ }
+}
+
+static cairo_status_t
+_clip_and_composite_trapezoids (cairo_image_surface_t *dst,
+ cairo_operator_t op,
+ const cairo_pattern_t *src,
+ cairo_traps_t *traps,
+ cairo_antialias_t antialias,
+ const cairo_composite_rectangles_t *extents,
+ cairo_clip_t *clip)
+{
+ composite_traps_info_t info;
+ cairo_bool_t need_clip_surface = FALSE;
+ cairo_status_t status;
+
+ if (traps->num_traps == 0 && extents->is_bounded)
+ return CAIRO_STATUS_SUCCESS;
+
+ if (clip != NULL) {
+ cairo_region_t *clip_region;
+
+ status = _cairo_clip_get_region (clip, &clip_region);
+ need_clip_surface = status == CAIRO_INT_STATUS_UNSUPPORTED;
+ }
+
+ if (traps->has_intersections) {
+ if (traps->is_rectangular)
+ status = _cairo_bentley_ottmann_tessellate_rectangular_traps (traps, CAIRO_FILL_RULE_WINDING);
+ else if (traps->is_rectilinear)
+ status = _cairo_bentley_ottmann_tessellate_rectilinear_traps (traps, CAIRO_FILL_RULE_WINDING);
+ else
+ status = _cairo_bentley_ottmann_tessellate_traps (traps, CAIRO_FILL_RULE_WINDING);
+ if (unlikely (status))
+ return status;
+ }
+
+ /* Use a fast path if the trapezoids consist of a simple region,
+ * but we can only do this if we do not have a clip surface, or can
+ * substitute the mask with the clip.
+ */
+ if (traps->maybe_region && _traps_are_pixel_aligned (traps, antialias) &&
+ (! need_clip_surface ||
+ (extents->is_bounded && op != CAIRO_OPERATOR_SOURCE)))
+ {
+ cairo_boxes_t boxes;
+
+ _boxes_for_traps (&boxes, traps);
+ return _clip_and_composite_boxes (dst, op, src,
+ &boxes, antialias,
+ extents, clip);
+ }
+
+ /* No fast path, exclude self-intersections and clip trapezoids. */
+ /* Otherwise render the trapezoids to a mask and composite in the usual
+ * fashion.
+ */
+ info.traps = traps->traps;;
+ info.num_traps = traps->num_traps;
+ info.antialias = antialias;
+ return _clip_and_composite (dst, op, src,
+ _composite_traps, &info,
+ extents, clip);
+}
+
+static cairo_bool_t
+box_is_aligned (const cairo_box_t *box)
+{
+ return
+ _cairo_fixed_is_integer (box->p1.x) &&
+ _cairo_fixed_is_integer (box->p1.y) &&
+ _cairo_fixed_is_integer (box->p2.x) &&
+ _cairo_fixed_is_integer (box->p2.y);
+}
+
+static inline cairo_status_t
+_clip_to_boxes (cairo_clip_t **clip,
+ const cairo_composite_rectangles_t *extents,
+ cairo_box_t **boxes,
+ int *num_boxes)
+{
+ cairo_status_t status;
+ const cairo_rectangle_int_t *rect;
+
+ rect = extents->is_bounded ? &extents->bounded : &extents->unbounded;
+
+ if (*clip == NULL)
+ goto EXTENTS;
+
+ status = _cairo_clip_rectangle (*clip, rect);
+ if (unlikely (status))
+ return status;
+
+ status = _cairo_clip_get_boxes (*clip, boxes, num_boxes);
+ switch ((int) status) {
+ case CAIRO_STATUS_SUCCESS:
+ if (extents->is_bounded || (*num_boxes == 1 && box_is_aligned (*boxes)))
+ *clip = NULL;
+ goto DONE;
+
+ case CAIRO_INT_STATUS_UNSUPPORTED:
+ goto EXTENTS;
+
+ default:
+ return status;
+ }
+
+ EXTENTS:
+ status = CAIRO_STATUS_SUCCESS;
+ _cairo_box_from_rectangle (&(*boxes)[0], rect);
+ *num_boxes = 1;
+ DONE:
+ return status;
+}
+
+static cairo_clip_path_t *
+_clip_get_single_path (cairo_clip_t *clip)
+{
+ cairo_clip_path_t *iter = clip->path;
+ cairo_clip_path_t *path = NULL;
+
+ do {
+ if ((iter->flags & CAIRO_CLIP_PATH_IS_BOX) == 0) {
+ if (path != NULL)
+ return FALSE;
+
+ path = iter;
+ }
+ iter = iter->prev;
+ } while (iter != NULL);
+
+ return path;
+}
+
+/* high level image interface */
+
+static cairo_int_status_t
+_cairo_image_surface_paint (void *abstract_surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_clip_t *clip)
+{
+ cairo_image_surface_t *surface = abstract_surface;
+ cairo_composite_rectangles_t extents;
+ cairo_clip_path_t *clip_path;
+ cairo_clip_t local_clip;
+ cairo_bool_t have_clip = FALSE;
+ cairo_box_t boxes_stack[32], *clip_boxes = boxes_stack;
+ int num_boxes = ARRAY_LENGTH (boxes_stack);
+ cairo_status_t status;
+
+ status = _cairo_composite_rectangles_init_for_paint (&extents,
+ surface->width,
+ surface->height,
+ op, source,
+ clip);
+ if (unlikely (status))
+ return status;
+
+ if (_cairo_clip_contains_rectangle (clip, &extents))
+ clip = NULL;
+
+ if (clip != NULL) {
+ clip = _cairo_clip_init_copy (&local_clip, clip);
+ have_clip = TRUE;
+ }
+
+ status = _clip_to_boxes (&clip, &extents, &clip_boxes, &num_boxes);
+ if (unlikely (status)) {
+ if (have_clip)
+ _cairo_clip_fini (&local_clip);
+
+ return status;
+ }
+
+ /* If the clip cannot be reduced to a set of boxes, we will need to
+ * use a clipmask. Paint is special as it is the only operation that
+ * does not implicitly use a mask, so we may be able to reduce this
+ * operation to a fill...
+ */
+ if (clip != NULL &&
+ extents.is_bounded &&
+ (clip_path = _clip_get_single_path (clip)) != NULL)
+ {
+ status = _cairo_image_surface_fill (surface, op, source,
+ &clip_path->path,
+ clip_path->fill_rule,
+ clip_path->tolerance,
+ clip_path->antialias,
+ NULL);
+ }
+ else
+ {
+ cairo_boxes_t boxes;
+
+ _cairo_boxes_init_for_array (&boxes, clip_boxes, num_boxes);
+ status = _clip_and_composite_boxes (surface, op, source,
+ &boxes, CAIRO_ANTIALIAS_DEFAULT,
+ &extents, clip);
+ }
+
+ if (clip_boxes != boxes_stack)
+ free (clip_boxes);
+
+ if (have_clip)
+ _cairo_clip_fini (&local_clip);
+
+ return status;
+}
+
+static cairo_status_t
+_composite_mask (void *closure,
+ pixman_image_t *dst,
+ pixman_format_code_t dst_format,
+ cairo_operator_t op,
+ const cairo_pattern_t *src_pattern,
+ int dst_x,
+ int dst_y,
+ const cairo_rectangle_int_t *extents,
+ cairo_region_t *clip_region)
+{
+ const cairo_pattern_t *mask_pattern = closure;
+ pixman_image_t *src, *mask = NULL;
+ int src_x = 0, src_y = 0;
+ int mask_x = 0, mask_y = 0;
+
+ if (src_pattern != NULL) {
+ src = _pixman_image_for_pattern (src_pattern, extents, &src_x, &src_y);
+ if (unlikely (src == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+ mask = _pixman_image_for_pattern (mask_pattern, extents, &mask_x, &mask_y);
+ if (unlikely (mask == NULL)) {
+ pixman_image_unref (src);
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ }
+
+ if (mask_pattern->has_component_alpha)
+ pixman_image_set_component_alpha (mask, TRUE);
+ } else {
+ src = _pixman_image_for_pattern (mask_pattern, extents, &src_x, &src_y);
+ if (unlikely (src == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ }
+
+ pixman_image_composite (_pixman_operator (op), src, mask, dst,
+ extents->x + src_x, extents->y + src_y,
+ extents->x + mask_x, extents->y + mask_y,
+ extents->x - dst_x, extents->y - dst_y,
+ extents->width, extents->height);
+
+ if (mask != NULL)
+ pixman_image_unref (mask);
+ pixman_image_unref (src);
+
return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
+_cairo_image_surface_mask (void *abstract_surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ const cairo_pattern_t *mask,
+ cairo_clip_t *clip)
+{
+ cairo_image_surface_t *surface = abstract_surface;
+ cairo_composite_rectangles_t extents;
+ cairo_clip_t local_clip;
+ cairo_bool_t have_clip = FALSE;
+ cairo_status_t status;
+
+ status = _cairo_composite_rectangles_init_for_mask (&extents,
+ surface->width, surface->height,
+ op, source, mask, clip);
+ if (unlikely (status))
+ return status;
+
+ if (_cairo_clip_contains_rectangle (clip, &extents))
+ clip = NULL;
+
+ if (clip != NULL && extents.is_bounded) {
+ clip = _cairo_clip_init_copy (&local_clip, clip);
+ status = _cairo_clip_rectangle (clip, &extents.bounded);
+ if (unlikely (status)) {
+ _cairo_clip_fini (&local_clip);
+ return status;
+ }
+
+ have_clip = TRUE;
+ }
+
+ status = _clip_and_composite (surface, op, source,
+ _composite_mask, (void *) mask,
+ &extents, clip);
+
+ if (have_clip)
+ _cairo_clip_fini (&local_clip);
+
+ return status;
+}
+
+typedef struct {
+ cairo_polygon_t *polygon;
+ cairo_fill_rule_t fill_rule;
+ cairo_antialias_t antialias;
+} composite_spans_info_t;
+
+//#define USE_BOTOR_SCAN_CONVERTER
+static cairo_status_t
+_composite_spans (void *closure,
+ pixman_image_t *dst,
+ pixman_format_code_t dst_format,
+ cairo_operator_t op,
+ const cairo_pattern_t *pattern,
+ int dst_x,
+ int dst_y,
+ const cairo_rectangle_int_t *extents,
+ cairo_region_t *clip_region)
+{
+ uint8_t mask_buf[CAIRO_STACK_BUFFER_SIZE];
+ composite_spans_info_t *info = closure;
+ cairo_image_surface_span_renderer_t renderer;
+#if USE_BOTOR_SCAN_CONVERTER
+ cairo_box_t box;
+ cairo_botor_scan_converter_t converter;
+#else
+ cairo_scan_converter_t *converter;
+#endif
+ pixman_image_t *mask;
+ cairo_status_t status;
+
+#if USE_BOTOR_SCAN_CONVERTER
+ box.p1.x = _cairo_fixed_from_int (extents->x);
+ box.p1.y = _cairo_fixed_from_int (extents->y);
+ box.p2.x = _cairo_fixed_from_int (extents->x + extents->width);
+ box.p2.y = _cairo_fixed_from_int (extents->y + extents->height);
+ _cairo_botor_scan_converter_init (&converter, &box, info->fill_rule);
+ status = converter.base.add_polygon (&converter.base, info->polygon);
+#else
+ converter = _cairo_tor_scan_converter_create (extents->x, extents->y,
+ extents->x + extents->width,
+ extents->y + extents->height,
+ info->fill_rule);
+ status = converter->add_polygon (converter, info->polygon);
+#endif
+ if (unlikely (status))
+ goto CLEANUP_CONVERTER;
+
+ /* TODO: support rendering to A1 surfaces (or: go add span
+ * compositing to pixman.) */
+
+ if (pattern == NULL && dst_format == PIXMAN_a8) {
+ mask = dst;
+ dst = NULL;
+ } else {
+ int stride = CAIRO_STRIDE_FOR_WIDTH_BPP (extents->width, 8);
+ uint8_t *data = mask_buf;
+
+ if (extents->height * stride <= (int) sizeof (mask_buf))
+ memset (data, 0, extents->height * stride);
+ else
+ data = NULL, stride = 0;
+
+ mask = pixman_image_create_bits (PIXMAN_a8,
+ extents->width,
+ extents->height,
+ (uint32_t *) data,
+ stride);
+ if (unlikely (mask == NULL)) {
+ status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ goto CLEANUP_CONVERTER;
+ }
+ }
+
+ renderer.base.render_rows = _cairo_image_surface_span;
+ renderer.mask_stride = pixman_image_get_stride (mask);
+ renderer.mask_data = (uint8_t *) pixman_image_get_data (mask);
+ if (dst != NULL)
+ renderer.mask_data -= extents->y * renderer.mask_stride + extents->x;
+ else
+ renderer.mask_data -= dst_y * renderer.mask_stride + dst_x;
+
+#if USE_BOTOR_SCAN_CONVERTER
+ status = converter.base.generate (&converter.base, &renderer.base);
+#else
+ status = converter->generate (converter, &renderer.base);
+#endif
+ if (unlikely (status))
+ goto CLEANUP_RENDERER;
+
+ if (dst != NULL) {
+ pixman_image_t *src;
+ int src_x, src_y;
+
+ src = _pixman_image_for_pattern (pattern, extents, &src_x, &src_y);
+ if (unlikely (src == NULL)) {
+ status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ goto CLEANUP_RENDERER;
+ }
+
+ pixman_image_composite (_pixman_operator (op), src, mask, dst,
+ extents->x + src_x, extents->y + src_y,
+ 0, 0, /* mask.x, mask.y */
+ extents->x - dst_x, extents->y - dst_y,
+ extents->width, extents->height);
+ pixman_image_unref (src);
+ }
+
+ CLEANUP_RENDERER:
+ if (dst != NULL)
+ pixman_image_unref (mask);
+ CLEANUP_CONVERTER:
+#if USE_BOTOR_SCAN_CONVERTER
+ converter.base.destroy (&converter.base);
+#else
+ converter->destroy (converter);
+#endif
+ return status;
+}
+
+static cairo_status_t
+_clip_and_composite_polygon (cairo_image_surface_t *dst,
+ cairo_operator_t op,
+ const cairo_pattern_t *src,
+ cairo_polygon_t *polygon,
+ cairo_fill_rule_t fill_rule,
+ cairo_antialias_t antialias,
+ cairo_composite_rectangles_t *extents,
+ cairo_clip_t *clip)
+{
+ cairo_status_t status;
+
+ if (polygon->num_edges == 0) {
+ cairo_traps_t traps;
+
+ if (extents->is_bounded)
+ return CAIRO_STATUS_SUCCESS;
+
+ _cairo_traps_init (&traps);
+ status = _clip_and_composite_trapezoids (dst, op, src,
+ &traps, antialias,
+ extents, clip);
+ _cairo_traps_fini (&traps);
+
+ return status;
+ }
+
+ _cairo_box_round_to_rectangle (&polygon->extents, &extents->mask);
+ if (! _cairo_rectangle_intersect (&extents->bounded, &extents->mask))
+ return CAIRO_STATUS_SUCCESS;
+
+ if (antialias != CAIRO_ANTIALIAS_NONE) {
+ composite_spans_info_t info;
+
+ info.polygon = polygon;
+ info.fill_rule = fill_rule;
+ info.antialias = antialias;
+
+ status = _clip_and_composite (dst, op, src,
+ _composite_spans, &info,
+ extents, clip);
+ } else {
+ cairo_traps_t traps;
+
+ _cairo_traps_init (&traps);
+
+ /* Fall back to trapezoid fills. */
+ status = _cairo_bentley_ottmann_tessellate_polygon (&traps,
+ polygon,
+ fill_rule);
+ if (likely (status == CAIRO_STATUS_SUCCESS)) {
+ status = _clip_and_composite_trapezoids (dst, op, src,
+ &traps, antialias,
+ extents, clip);
+ }
+
+ _cairo_traps_fini (&traps);
+ }
+
+ return status;
+}
+
+static cairo_int_status_t
+_cairo_image_surface_stroke (void *abstract_surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_path_fixed_t *path,
+ const cairo_stroke_style_t *style,
+ const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm_inverse,
+ double tolerance,
+ cairo_antialias_t antialias,
+ cairo_clip_t *clip)
+{
+ cairo_image_surface_t *surface = abstract_surface;
+ cairo_composite_rectangles_t extents;
+ cairo_box_t boxes_stack[32], *clip_boxes = boxes_stack;
+ int num_boxes = ARRAY_LENGTH (boxes_stack);
+ cairo_clip_t local_clip;
+ cairo_bool_t have_clip = FALSE;
+ cairo_status_t status;
+
+ status = _cairo_composite_rectangles_init_for_stroke (&extents,
+ surface->width,
+ surface->height,
+ op, source,
+ path, style, ctm,
+ clip);
+ if (unlikely (status))
+ return status;
+
+ if (_cairo_clip_contains_rectangle (clip, &extents))
+ clip = NULL;
+
+ if (clip != NULL) {
+ clip = _cairo_clip_init_copy (&local_clip, clip);
+ have_clip = TRUE;
+ }
+
+ status = _clip_to_boxes (&clip, &extents, &clip_boxes, &num_boxes);
+ if (unlikely (status)) {
+ if (have_clip)
+ _cairo_clip_fini (&local_clip);
+
+ return status;
+ }
+
+ status = CAIRO_INT_STATUS_UNSUPPORTED;
+ if (path->is_rectilinear) {
+ cairo_boxes_t boxes;
+
+ _cairo_boxes_init (&boxes);
+ _cairo_boxes_limit (&boxes, clip_boxes, num_boxes);
+
+ status = _cairo_path_fixed_stroke_rectilinear_to_boxes (path,
+ style,
+ ctm,
+ &boxes);
+ if (likely (status == CAIRO_STATUS_SUCCESS)) {
+ status = _clip_and_composite_boxes (surface, op, source,
+ &boxes, antialias,
+ &extents, clip);
+ }
+
+ _cairo_boxes_fini (&boxes);
+ }
+
+ if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
+ cairo_polygon_t polygon;
+
+ _cairo_polygon_init (&polygon);
+ _cairo_polygon_limit (&polygon, clip_boxes, num_boxes);
+
+ status = _cairo_path_fixed_stroke_to_polygon (path,
+ style,
+ ctm, ctm_inverse,
+ tolerance,
+ &polygon);
+ if (likely (status == CAIRO_STATUS_SUCCESS)) {
+ status = _clip_and_composite_polygon (surface, op, source, &polygon,
+ CAIRO_FILL_RULE_WINDING, antialias,
+ &extents, clip);
+ }
+
+ _cairo_polygon_fini (&polygon);
+ }
+
+ if (clip_boxes != boxes_stack)
+ free (clip_boxes);
+
+ if (have_clip)
+ _cairo_clip_fini (&local_clip);
+
+ return status;
+}
+
+static cairo_int_status_t
+_cairo_image_surface_fill (void *abstract_surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_path_fixed_t *path,
+ cairo_fill_rule_t fill_rule,
+ double tolerance,
+ cairo_antialias_t antialias,
+ cairo_clip_t *clip)
+{
+ cairo_image_surface_t *surface = abstract_surface;
+ cairo_composite_rectangles_t extents;
+ cairo_box_t boxes_stack[32], *clip_boxes = boxes_stack;
+ cairo_clip_t local_clip;
+ cairo_bool_t have_clip = FALSE;
+ int num_boxes = ARRAY_LENGTH (boxes_stack);
+ cairo_status_t status;
+
+ status = _cairo_composite_rectangles_init_for_fill (&extents,
+ surface->width,
+ surface->height,
+ op, source, path,
+ clip);
+ if (unlikely (status))
+ return status;
+
+ if (_cairo_clip_contains_rectangle (clip, &extents))
+ clip = NULL;
+
+ if (extents.is_bounded && clip != NULL) {
+ cairo_clip_path_t *clip_path;
+
+ if (((clip_path = _clip_get_single_path (clip)) != NULL) &&
+ _cairo_path_fixed_equal (&clip_path->path, path))
+ {
+ clip = NULL;
+ }
+ }
+
+ if (clip != NULL) {
+ clip = _cairo_clip_init_copy (&local_clip, clip);
+ have_clip = TRUE;
+ }
+
+ status = _clip_to_boxes (&clip, &extents, &clip_boxes, &num_boxes);
+ if (unlikely (status)) {
+ if (have_clip)
+ _cairo_clip_fini (&local_clip);
+
+ return status;
+ }
+
+ if (_cairo_path_fixed_is_rectilinear_fill (path)) {
+ cairo_boxes_t boxes;
+
+ _cairo_boxes_init (&boxes);
+ _cairo_boxes_limit (&boxes, clip_boxes, num_boxes);
+
+ status = _cairo_path_fixed_fill_rectilinear_to_boxes (path,
+ fill_rule,
+ &boxes);
+ if (likely (status == CAIRO_STATUS_SUCCESS)) {
+ status = _clip_and_composite_boxes (surface, op, source,
+ &boxes, antialias,
+ &extents, clip);
+ }
+
+ _cairo_boxes_fini (&boxes);
+ } else {
+ cairo_polygon_t polygon;
+
+ assert (! path->is_empty_fill);
+
+ _cairo_polygon_init (&polygon);
+ _cairo_polygon_limit (&polygon, clip_boxes, num_boxes);
+
+ status = _cairo_path_fixed_fill_to_polygon (path, tolerance, &polygon);
+ if (likely (status == CAIRO_STATUS_SUCCESS)) {
+ status = _clip_and_composite_polygon (surface, op, source, &polygon,
+ fill_rule, antialias,
+ &extents, clip);
+ }
+
+ _cairo_polygon_fini (&polygon);
+ }
+
+ if (clip_boxes != boxes_stack)
+ free (clip_boxes);
+
+ if (have_clip)
+ _cairo_clip_fini (&local_clip);
+
+ return status;
+}
+
+typedef struct {
+ cairo_scaled_font_t *font;
+ cairo_glyph_t *glyphs;
+ int num_glyphs;
+} composite_glyphs_info_t;
+
+static cairo_status_t
+_composite_glyphs_via_mask (void *closure,
+ pixman_image_t *dst,
+ pixman_format_code_t dst_format,
+ cairo_operator_t op,
+ const cairo_pattern_t *pattern,
+ int dst_x,
+ int dst_y,
+ const cairo_rectangle_int_t *extents,
+ cairo_region_t *clip_region)
+{
+ composite_glyphs_info_t *info = closure;
+ cairo_scaled_font_t *font = info->font;
+ cairo_glyph_t *glyphs = info->glyphs;
+ int num_glyphs = info->num_glyphs;
+ pixman_image_t *mask = NULL;
+ pixman_image_t *src;
+ pixman_image_t *white;
+ pixman_format_code_t mask_format = 0; /* silence gcc */
+ cairo_status_t status;
+ int src_x, src_y;
+ int i;
+
+ src = _pixman_image_for_pattern (pattern, extents, &src_x, &src_y);
+ if (unlikely (src == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+ white = _pixman_white_image ();
+ if (unlikely (white == NULL)) {
+ pixman_image_unref (src);
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ }
+
+ _cairo_scaled_font_freeze_cache (font);
+
+ for (i = 0; i < num_glyphs; i++) {
+ int x, y;
+ cairo_image_surface_t *glyph_surface;
+ cairo_scaled_glyph_t *scaled_glyph;
+
+ status = _cairo_scaled_glyph_lookup (font, glyphs[i].index,
+ CAIRO_SCALED_GLYPH_INFO_SURFACE,
+ &scaled_glyph);
+
+ if (unlikely (status))
+ goto CLEANUP;
+
+ glyph_surface = scaled_glyph->surface;
+
+ if (glyph_surface->width == 0 || glyph_surface->height == 0)
+ continue;
+
+ /* To start, create the mask using the format from the first
+ * glyph. Later we'll deal with different formats. */
+ if (mask == NULL) {
+ mask_format = glyph_surface->pixman_format;
+ mask = pixman_image_create_bits (mask_format,
+ extents->width, extents->height,
+ NULL, 0);
+ if (unlikely (mask == NULL)) {
+ status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ goto CLEANUP;
+ }
+
+ if (PIXMAN_FORMAT_RGB (mask_format))
+ pixman_image_set_component_alpha (mask, TRUE);
+ }
+
+ /* If we have glyphs of different formats, we "upgrade" the mask
+ * to the wider of the formats. */
+ if (glyph_surface->pixman_format != mask_format &&
+ PIXMAN_FORMAT_BPP (mask_format) <
+ PIXMAN_FORMAT_BPP (glyph_surface->pixman_format))
+ {
+ pixman_image_t *new_mask;
+
+ mask_format = glyph_surface->pixman_format;
+ new_mask = pixman_image_create_bits (mask_format,
+ extents->width, extents->height,
+ NULL, 0);
+ if (unlikely (new_mask == NULL)) {
+ status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ goto CLEANUP;
+ }
+
+ pixman_image_composite (PIXMAN_OP_SRC,
+ white, mask, new_mask,
+ 0, 0, 0, 0, 0, 0,
+ extents->width, extents->height);
+
+ pixman_image_unref (mask);
+ mask = new_mask;
+ if (PIXMAN_FORMAT_RGB (mask_format))
+ pixman_image_set_component_alpha (mask, TRUE);
+ }
+
+ /* round glyph locations to the nearest pixel */
+ /* XXX: FRAGILE: We're ignoring device_transform scaling here. A bug? */
+ x = _cairo_lround (glyphs[i].x -
+ glyph_surface->base.device_transform.x0);
+ y = _cairo_lround (glyphs[i].y -
+ glyph_surface->base.device_transform.y0);
+ if (glyph_surface->pixman_format == mask_format) {
+ pixman_image_composite (PIXMAN_OP_ADD,
+ glyph_surface->pixman_image, NULL, mask,
+ 0, 0, 0, 0,
+ x - extents->x, y - extents->y,
+ glyph_surface->width,
+ glyph_surface->height);
+ } else {
+ pixman_image_composite (PIXMAN_OP_ADD,
+ white, glyph_surface->pixman_image, mask,
+ 0, 0, 0, 0,
+ x - extents->x, y - extents->y,
+ glyph_surface->width,
+ glyph_surface->height);
+ }
+ }
+
+ pixman_image_composite (_pixman_operator (op),
+ src, mask, dst,
+ extents->x + src_x, extents->y + src_y,
+ 0, 0,
+ extents->x - dst_x, extents->y - dst_y,
+ extents->width, extents->height);
+
+CLEANUP:
+ _cairo_scaled_font_thaw_cache (font);
+ pixman_image_unref (mask);
+ pixman_image_unref (src);
+ pixman_image_unref (white);
+
+ return status;
+}
+
+static cairo_status_t
+_composite_glyphs (void *closure,
+ pixman_image_t *dst,
+ pixman_format_code_t dst_format,
+ cairo_operator_t op,
+ const cairo_pattern_t *pattern,
+ int dst_x,
+ int dst_y,
+ const cairo_rectangle_int_t *extents,
+ cairo_region_t *clip_region)
+{
+ composite_glyphs_info_t *info = closure;
+ cairo_scaled_glyph_t *glyph_cache[64];
+ pixman_op_t pixman_op = _pixman_operator (op);
+ pixman_image_t *src = NULL;
+ int src_x, src_y;
+ cairo_status_t status;
+ int i;
+
+ if (pattern != NULL) {
+ src = _pixman_image_for_pattern (pattern, extents, &src_x, &src_y);
+ if (unlikely (src == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+ src_x -= dst_x;
+ src_y -= dst_y;
+ } else {
+ src = _pixman_white_image ();
+ src_x = src_y = 0;
+ }
+
+ memset (glyph_cache, 0, sizeof (glyph_cache));
+ status = CAIRO_STATUS_SUCCESS;
+
+ _cairo_scaled_font_freeze_cache (info->font);
+ for (i = 0; i < info->num_glyphs; i++) {
+ int x, y;
+ cairo_image_surface_t *glyph_surface;
+ cairo_scaled_glyph_t *scaled_glyph;
+ unsigned long glyph_index = info->glyphs[i].index;
+ int cache_index = glyph_index % ARRAY_LENGTH (glyph_cache);
+
+ scaled_glyph = glyph_cache[cache_index];
+ if (scaled_glyph == NULL ||
+ _cairo_scaled_glyph_index (scaled_glyph) != glyph_index)
+ {
+ status = _cairo_scaled_glyph_lookup (info->font, glyph_index,
+ CAIRO_SCALED_GLYPH_INFO_SURFACE,
+ &scaled_glyph);
+
+ if (unlikely (status))
+ break;
+
+ glyph_cache[cache_index] = scaled_glyph;
+ }
+
+ glyph_surface = scaled_glyph->surface;
+ if (glyph_surface->width && glyph_surface->height) {
+ /* round glyph locations to the nearest pixel */
+ /* XXX: FRAGILE: We're ignoring device_transform scaling here. A bug? */
+ x = _cairo_lround (info->glyphs[i].x -
+ glyph_surface->base.device_transform.x0);
+ y = _cairo_lround (info->glyphs[i].y -
+ glyph_surface->base.device_transform.y0);
+
+ pixman_image_composite (pixman_op,
+ src, glyph_surface->pixman_image, dst,
+ x + src_x, y + src_y,
+ 0, 0,
+ x - dst_x, y - dst_y,
+ glyph_surface->width,
+ glyph_surface->height);
+ }
+ }
+ _cairo_scaled_font_thaw_cache (info->font);
+
+ pixman_image_unref (src);
+
+ return status;
+}
+
+static cairo_int_status_t
+_cairo_image_surface_glyphs (void *abstract_surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_scaled_font_t *scaled_font,
+ cairo_clip_t *clip,
+ int *num_remaining)
+{
+ cairo_image_surface_t *surface = abstract_surface;
+ cairo_composite_rectangles_t extents;
+ composite_glyphs_info_t glyph_info;
+ cairo_clip_t local_clip;
+ cairo_bool_t have_clip = FALSE;
+ cairo_bool_t overlap;
+ cairo_status_t status;
+
+ status = _cairo_composite_rectangles_init_for_glyphs (&extents,
+ surface->width,
+ surface->height,
+ op, source,
+ scaled_font,
+ glyphs, num_glyphs,
+ clip,
+ &overlap);
+ if (unlikely (status))
+ return status;
+
+ if (_cairo_clip_contains_rectangle (clip, &extents))
+ clip = NULL;
+
+ if (clip != NULL && extents.is_bounded) {
+ clip = _cairo_clip_init_copy (&local_clip, clip);
+ status = _cairo_clip_rectangle (clip, &extents.bounded);
+ if (unlikely (status))
+ return status;
+
+ have_clip = TRUE;
+ }
+
+ glyph_info.font = scaled_font;
+ glyph_info.glyphs = glyphs;
+ glyph_info.num_glyphs = num_glyphs;
+
+ status = _clip_and_composite (surface, op, source,
+ overlap || extents.is_bounded == 0 ? _composite_glyphs_via_mask : _composite_glyphs,
+ &glyph_info,
+ &extents, clip);
+
+ if (have_clip)
+ _cairo_clip_fini (&local_clip);
+
+ *num_remaining = 0;
+ return status;
+}
+
+static cairo_bool_t
+_cairo_image_surface_get_extents (void *abstract_surface,
+ cairo_rectangle_int_t *rectangle)
+{
+ cairo_image_surface_t *surface = abstract_surface;
+
+ rectangle->x = 0;
+ rectangle->y = 0;
+ rectangle->width = surface->width;
+ rectangle->height = surface->height;
+
+ return TRUE;
+}
+
+static void
+_cairo_image_surface_get_font_options (void *abstract_surface,
+ cairo_font_options_t *options)
+{
+ _cairo_font_options_init_default (options);
+
+ cairo_font_options_set_hint_metrics (options, CAIRO_HINT_METRICS_ON);
+}
+
+/* legacy interface kept for compatibility until surface-fallback is removed */
+static cairo_status_t
+_cairo_image_surface_acquire_dest_image (void *abstract_surface,
+ cairo_rectangle_int_t *interest_rect,
+ cairo_image_surface_t **image_out,
+ cairo_rectangle_int_t *image_rect_out,
+ void **image_extra)
+{
+ cairo_image_surface_t *surface = abstract_surface;
+
+ image_rect_out->x = 0;
+ image_rect_out->y = 0;
+ image_rect_out->width = surface->width;
+ image_rect_out->height = surface->height;
+
+ *image_out = surface;
+ *image_extra = NULL;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static void
+_cairo_image_surface_release_dest_image (void *abstract_surface,
+ cairo_rectangle_int_t *interest_rect,
+ cairo_image_surface_t *image,
+ cairo_rectangle_int_t *image_rect,
+ void *image_extra)
+{
+}
+
+static cairo_status_t
+_cairo_image_surface_clone_similar (void *abstract_surface,
+ cairo_surface_t *src,
+ int src_x,
+ int src_y,
+ int width,
+ int height,
+ int *clone_offset_x,
+ int *clone_offset_y,
+ cairo_surface_t **clone_out)
+{
+ cairo_image_surface_t *surface = abstract_surface;
+
+ if (src->backend == surface->base.backend) {
+ *clone_offset_x = *clone_offset_y = 0;
+ *clone_out = cairo_surface_reference (src);
+
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+}
+
+static cairo_int_status_t
_cairo_image_surface_composite (cairo_operator_t op,
const cairo_pattern_t *src_pattern,
const cairo_pattern_t *mask_pattern,
@@ -1110,82 +3921,85 @@ _cairo_image_surface_composite (cairo_operator_t op,
unsigned int height,
cairo_region_t *clip_region)
{
- cairo_surface_attributes_t src_attr, mask_attr;
- cairo_image_surface_t *dst = abstract_dst;
- cairo_image_surface_t *src;
- cairo_image_surface_t *mask;
- cairo_int_status_t status;
+ cairo_image_surface_t *dst = abstract_dst;
+ cairo_composite_rectangles_t extents;
+ pixman_image_t *src;
+ int src_offset_x, src_offset_y;
+ cairo_status_t status;
- status = _cairo_image_surface_set_clip_region (dst, clip_region);
- if (unlikely (status))
- return status;
+ if (clip_region != NULL) {
+ status = _cairo_image_surface_set_clip_region (dst, clip_region);
+ if (unlikely (status))
+ return status;
+ }
- status = _cairo_pattern_acquire_surfaces (src_pattern, mask_pattern,
- &dst->base,
- src_x, src_y,
- mask_x, mask_y,
- width, height,
- CAIRO_PATTERN_ACQUIRE_NONE,
- (cairo_surface_t **) &src,
- (cairo_surface_t **) &mask,
- &src_attr, &mask_attr);
- if (unlikely (status))
- return status;
+ extents.source.x = src_x;
+ extents.source.y = src_y;
+ extents.source.width = width;
+ extents.source.height = height;
- status = _cairo_image_surface_set_attributes (src, &src_attr,
- dst_x + width / 2.,
- dst_y + height / 2.);
- if (unlikely (status))
- goto CLEANUP_SURFACES;
+ extents.mask.x = dst_x;
+ extents.mask.y = dst_y;
+ extents.mask.width = width;
+ extents.mask.height = height;
- if (mask) {
- status = _cairo_image_surface_set_attributes (mask, &mask_attr,
- dst_x + width / 2.,
- dst_y + height / 2.);
- if (unlikely (status))
- goto CLEANUP_SURFACES;
+ extents.bounded.x = dst_x;
+ extents.bounded.y = dst_y;
+ extents.bounded.width = width;
+ extents.bounded.height = height;
+
+ if (clip_region != NULL) {
+ cairo_region_get_extents (clip_region, &extents.unbounded);
+ } else {
+ extents.unbounded.x = 0;
+ extents.unbounded.y = 0;
+ extents.unbounded.width = dst->width;
+ extents.unbounded.height = dst->height;
+ }
+
+ extents.is_bounded = _cairo_operator_bounded_by_either (op);
+
+ src = _pixman_image_for_pattern (src_pattern, &extents.bounded, &src_offset_x, &src_offset_y);
+ if (unlikely (src == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+ if (mask_pattern != NULL) {
+ pixman_image_t *mask;
+ int mask_offset_x, mask_offset_y;
+
+ mask = _pixman_image_for_pattern (mask_pattern, &extents.bounded, &mask_offset_x, &mask_offset_y);
+ if (unlikely (mask == NULL)) {
+ pixman_image_unref (src);
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ }
pixman_image_composite (_pixman_operator (op),
- src->pixman_image,
- mask->pixman_image,
- dst->pixman_image,
- src_x + src_attr.x_offset,
- src_y + src_attr.y_offset,
- mask_x + mask_attr.x_offset,
- mask_y + mask_attr.y_offset,
- dst_x, dst_y,
- width, height);
+ src, mask, dst->pixman_image,
+ src_x + src_offset_x,
+ src_y + src_offset_y,
+ mask_x + mask_offset_x,
+ mask_y + mask_offset_y,
+ dst_x, dst_y, width, height);
+
+ pixman_image_unref (mask);
} else {
pixman_image_composite (_pixman_operator (op),
- src->pixman_image,
- NULL,
- dst->pixman_image,
- src_x + src_attr.x_offset,
- src_y + src_attr.y_offset,
+ src, NULL, dst->pixman_image,
+ src_x + src_offset_x,
+ src_y + src_offset_y,
0, 0,
- dst_x, dst_y,
- width, height);
+ dst_x, dst_y, width, height);
}
- if (! _cairo_operator_bounded_by_source (op)) {
- status = _cairo_surface_composite_fixup_unbounded (&dst->base,
- &src_attr, src->width, src->height,
- mask ? &mask_attr : NULL,
- mask ? mask->width : 0,
- mask ? mask->height : 0,
- src_x, src_y,
- mask_x, mask_y,
- dst_x, dst_y, width, height,
- clip_region);
- }
+ pixman_image_unref (src);
- CLEANUP_SURFACES:
- if (mask)
- _cairo_pattern_release_surface (mask_pattern, &mask->base, &mask_attr);
+ if (! extents.is_bounded)
+ _cairo_image_surface_fixup_unbounded (dst, &extents, NULL);
- _cairo_pattern_release_surface (src_pattern, &src->base, &src_attr);
+ if (clip_region != NULL)
+ _cairo_image_surface_unset_clip_region (dst);
- return status;
+ return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
@@ -1212,9 +4026,6 @@ _cairo_image_surface_fill_rectangles (void *abstract_surface,
pixman_color.blue = color->blue_short;
pixman_color.alpha = color->alpha_short;
- status = _cairo_image_surface_set_clip_region (surface, NULL);
- assert (status == CAIRO_STATUS_SUCCESS);
-
if (num_rects > ARRAY_LENGTH (stack_rects)) {
pixman_rects = _cairo_malloc_ab (num_rects, sizeof (pixman_rectangle16_t));
if (unlikely (pixman_rects == NULL))
@@ -1228,7 +4039,6 @@ _cairo_image_surface_fill_rectangles (void *abstract_surface,
pixman_rects[i].height = rects[i].height;
}
- /* XXX: pixman_fill_region() should be implemented */
status = CAIRO_STATUS_SUCCESS;
if (! pixman_image_fill_rectangles (_pixman_operator (op),
surface->pixman_image,
@@ -1245,42 +4055,6 @@ _cairo_image_surface_fill_rectangles (void *abstract_surface,
return status;
}
-static pixman_format_code_t
-_pixman_mask_format_from_antialias (cairo_antialias_t antialias)
-{
- if (antialias == CAIRO_ANTIALIAS_NONE)
- return PIXMAN_a1;
- return PIXMAN_a8;
-}
-
-static void
-_pixman_add_trapezoids (pixman_image_t *image,
- int dst_x, int dst_y,
- const cairo_trapezoid_t *traps,
- int num_traps)
-{
- while (num_traps--) {
- pixman_trapezoid_t trap;
-
- trap.top = _cairo_fixed_to_16_16 (traps->top);
- trap.bottom = _cairo_fixed_to_16_16 (traps->bottom);
-
- trap.left.p1.x = _cairo_fixed_to_16_16 (traps->left.p1.x);
- trap.left.p1.y = _cairo_fixed_to_16_16 (traps->left.p1.y);
- trap.left.p2.x = _cairo_fixed_to_16_16 (traps->left.p2.x);
- trap.left.p2.y = _cairo_fixed_to_16_16 (traps->left.p2.y);
-
- trap.right.p1.x = _cairo_fixed_to_16_16 (traps->right.p1.x);
- trap.right.p1.y = _cairo_fixed_to_16_16 (traps->right.p1.y);
- trap.right.p2.x = _cairo_fixed_to_16_16 (traps->right.p2.x);
- trap.right.p2.y = _cairo_fixed_to_16_16 (traps->right.p2.y);
-
- pixman_rasterize_trapezoid (image, &trap, -dst_x, -dst_y);
-
- traps++;
- }
-}
-
static cairo_int_status_t
_cairo_image_surface_composite_trapezoids (cairo_operator_t op,
const cairo_pattern_t *pattern,
@@ -1296,11 +4070,10 @@ _cairo_image_surface_composite_trapezoids (cairo_operator_t op,
int num_traps,
cairo_region_t *clip_region)
{
- cairo_surface_attributes_t attributes;
cairo_image_surface_t *dst = abstract_dst;
- cairo_image_surface_t *src;
- cairo_int_status_t status;
- pixman_image_t *mask;
+ cairo_composite_rectangles_t extents;
+ composite_traps_info_t info;
+ cairo_status_t status;
if (height == 0 || width == 0)
return CAIRO_STATUS_SUCCESS;
@@ -1308,101 +4081,66 @@ _cairo_image_surface_composite_trapezoids (cairo_operator_t op,
if (CAIRO_INJECT_FAULT ())
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
- /* Special case adding trapezoids onto a mask surface; we want to avoid
- * creating an intermediate temporary mask unnecessarily.
- *
- * We make the assumption here that the portion of the trapezoids
- * contained within the surface is bounded by [dst_x,dst_y,width,height];
- * the Cairo core code passes bounds based on the trapezoid extents.
- *
- * Currently the check clip_region == NULL is needed for correct
- * functioning, since pixman_add_trapezoids() doesn't obey the
- * surface clip, which is a libpixman bug , but there's no harm in
- * falling through to the general case when the surface is clipped
- * since libpixman would have to generate an intermediate mask anyways.
- */
- if (op == CAIRO_OPERATOR_ADD &&
- clip_region == NULL &&
- _cairo_pattern_is_opaque_solid (pattern) &&
- dst->base.content == CAIRO_CONTENT_ALPHA &&
- antialias != CAIRO_ANTIALIAS_NONE)
- {
- _pixman_add_trapezoids (dst->pixman_image, 0, 0, traps, num_traps);
- return CAIRO_STATUS_SUCCESS;
- }
+ extents.source.x = src_x;
+ extents.source.y = src_y;
+ extents.source.width = width;
+ extents.source.height = height;
- status = _cairo_image_surface_set_clip_region (dst, clip_region);
- if (unlikely (status))
- return status;
+ extents.mask.x = dst_x;
+ extents.mask.y = dst_y;
+ extents.mask.width = width;
+ extents.mask.height = height;
- status = _cairo_pattern_acquire_surface (pattern, &dst->base,
- src_x, src_y, width, height,
- CAIRO_PATTERN_ACQUIRE_NONE,
- (cairo_surface_t **) &src,
- &attributes);
- if (unlikely (status))
- return status;
+ extents.bounded.x = dst_x;
+ extents.bounded.y = dst_y;
+ extents.bounded.width = width;
+ extents.bounded.height = height;
- status = _cairo_image_surface_set_attributes (src, &attributes,
- dst_x + width / 2.,
- dst_y + height / 2.);
- if (unlikely (status))
- goto CLEANUP_SOURCE;
+ cairo_region_get_extents (clip_region, &extents.unbounded);
+ extents.is_bounded = _cairo_operator_bounded_by_either (op);
- mask = pixman_image_create_bits (_pixman_mask_format_from_antialias (antialias),
- width, height, NULL, 0);
- if (unlikely (mask == NULL)) {
- status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
- goto CLEANUP_SOURCE;
+ if (clip_region != NULL) {
+ status = _cairo_image_surface_set_clip_region (dst, clip_region);
+ if (unlikely (status))
+ return status;
}
- _pixman_add_trapezoids (mask, dst_x, dst_y, traps, num_traps);
-
- pixman_image_composite (_pixman_operator (op),
- src->pixman_image,
- mask,
- dst->pixman_image,
- src_x + attributes.x_offset,
- src_y + attributes.y_offset,
- 0, 0,
- dst_x, dst_y,
- width, height);
-
- pixman_image_unref (mask);
+ info.traps = traps;
+ info.num_traps = num_traps;
+ info.antialias = antialias;
+ status = _composite_traps (&info,
+ dst->pixman_image,
+ dst->pixman_format,
+ op,
+ pattern,
+ 0, 0,
+ &extents.bounded,
+ clip_region);
- if (! _cairo_operator_bounded_by_mask (op)) {
- status = _cairo_surface_composite_shape_fixup_unbounded (&dst->base,
- &attributes,
- src->width, src->height,
- width, height,
- src_x, src_y,
- 0, 0,
- dst_x, dst_y, width, height,
- clip_region);
- }
+ if (status == CAIRO_STATUS_SUCCESS && ! extents.is_bounded)
+ _cairo_image_surface_fixup_unbounded (dst, &extents, NULL);
- CLEANUP_SOURCE:
- _cairo_pattern_release_surface (pattern, &src->base, &attributes);
+ if (clip_region != NULL)
+ _cairo_image_surface_unset_clip_region (dst);
return status;
}
-typedef struct _cairo_image_surface_span_renderer {
+typedef struct _legacy_image_surface_span_renderer {
cairo_span_renderer_t base;
cairo_operator_t op;
const cairo_pattern_t *pattern;
cairo_antialias_t antialias;
+ cairo_region_t *clip_region;
+ pixman_image_t *mask;
uint8_t *mask_data;
uint32_t mask_stride;
- cairo_image_surface_t *src;
- cairo_surface_attributes_t src_attributes;
- cairo_image_surface_t *mask;
cairo_image_surface_t *dst;
cairo_composite_rectangles_t composite_rectangles;
-} cairo_image_surface_span_renderer_t;
+} legacy_image_surface_span_renderer_t;
void
_cairo_image_surface_span_render_row (
@@ -1446,7 +4184,7 @@ _cairo_image_surface_span_renderer_render_rows (
const cairo_half_open_span_t *spans,
unsigned num_spans)
{
- cairo_image_surface_span_renderer_t *renderer = abstract_renderer;
+ legacy_image_surface_span_renderer_t *renderer = abstract_renderer;
while (height--)
_cairo_image_surface_span_render_row (y++, spans, num_spans, renderer->mask_data, renderer->mask_stride);
return CAIRO_STATUS_SUCCESS;
@@ -1455,17 +4193,11 @@ _cairo_image_surface_span_renderer_render_rows (
static void
_cairo_image_surface_span_renderer_destroy (void *abstract_renderer)
{
- cairo_image_surface_span_renderer_t *renderer = abstract_renderer;
- if (!renderer) return;
-
- if (renderer->src != NULL) {
- _cairo_pattern_release_surface (renderer->pattern,
- &renderer->src->base,
- &renderer->src_attributes);
- }
+ legacy_image_surface_span_renderer_t *renderer = abstract_renderer;
+ if (renderer == NULL)
+ return;
- if (renderer->mask != NULL)
- cairo_surface_destroy (&renderer->mask->base);
+ pixman_image_unref (renderer->mask);
free (renderer);
}
@@ -1473,47 +4205,41 @@ _cairo_image_surface_span_renderer_destroy (void *abstract_renderer)
static cairo_status_t
_cairo_image_surface_span_renderer_finish (void *abstract_renderer)
{
- cairo_image_surface_span_renderer_t *renderer = abstract_renderer;
- cairo_status_t status = CAIRO_STATUS_SUCCESS;
+ legacy_image_surface_span_renderer_t *renderer = abstract_renderer;
+ cairo_composite_rectangles_t *rects = &renderer->composite_rectangles;
+ cairo_image_surface_t *dst = renderer->dst;
+ pixman_image_t *src;
+ int src_x, src_y;
- if (renderer->src == NULL || renderer->mask == NULL)
- return CAIRO_STATUS_SUCCESS;
+ if (renderer->clip_region != NULL) {
+ cairo_status_t status;
- status = cairo_surface_status (&renderer->mask->base);
- if (status == CAIRO_STATUS_SUCCESS) {
- cairo_composite_rectangles_t *rects = &renderer->composite_rectangles;
- cairo_image_surface_t *src = renderer->src;
- cairo_image_surface_t *dst = renderer->dst;
- cairo_surface_attributes_t *src_attributes = &renderer->src_attributes;
- int width = rects->bounded.width;
- int height = rects->bounded.height;
+ status = _cairo_image_surface_set_clip_region (dst, renderer->clip_region);
+ if (unlikely (status))
+ return status;
+ }
+
+ src = _pixman_image_for_pattern (renderer->pattern, &rects->bounded, &src_x, &src_y);
+ if (src == NULL)
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+
+ pixman_image_composite (_pixman_operator (renderer->op),
+ src,
+ renderer->mask,
+ dst->pixman_image,
+ rects->bounded.x + src_x,
+ rects->bounded.y + src_y,
+ 0, 0,
+ rects->bounded.x, rects->bounded.y,
+ rects->bounded.width, rects->bounded.height);
+
+ if (! rects->is_bounded)
+ _cairo_image_surface_fixup_unbounded (dst, rects, NULL);
+
+ if (renderer->clip_region != NULL)
+ _cairo_image_surface_unset_clip_region (dst);
- pixman_image_composite (_pixman_operator (renderer->op),
- src->pixman_image,
- renderer->mask->pixman_image,
- dst->pixman_image,
- rects->bounded.x + src_attributes->x_offset,
- rects->bounded.y + src_attributes->y_offset,
- 0, 0, /* mask.x, mask.y */
- rects->bounded.x, rects->bounded.y,
- width, height);
-
- if (! rects->is_bounded) {
- status = _cairo_surface_composite_shape_fixup_unbounded (
- &dst->base,
- src_attributes,
- src->width, src->height,
- width, height,
- rects->bounded.x, rects->bounded.y,
- 0, 0, /* mask.x, mask.y */
- rects->bounded.x, rects->bounded.y,
- width, height,
- dst->clip_region);
- }
- }
- if (status != CAIRO_STATUS_SUCCESS)
- return _cairo_span_renderer_set_error (abstract_renderer,
- status);
return CAIRO_STATUS_SUCCESS;
}
@@ -1539,14 +4265,10 @@ _cairo_image_surface_create_span_renderer (cairo_operator_t op,
cairo_region_t *clip_region)
{
cairo_image_surface_t *dst = abstract_dst;
- cairo_image_surface_span_renderer_t *renderer = calloc(1, sizeof(*renderer));
- cairo_status_t status;
+ legacy_image_surface_span_renderer_t *renderer;
- status = _cairo_image_surface_set_clip_region (dst, clip_region);
- if (unlikely (status))
- return _cairo_span_renderer_create_in_error (status);
-
- if (renderer == NULL)
+ renderer = calloc(1, sizeof(*renderer));
+ if (unlikely (renderer == NULL))
return _cairo_span_renderer_create_in_error (CAIRO_STATUS_NO_MEMORY);
renderer->base.destroy = _cairo_image_surface_span_renderer_destroy;
@@ -1556,67 +4278,25 @@ _cairo_image_surface_create_span_renderer (cairo_operator_t op,
renderer->pattern = pattern;
renderer->antialias = antialias;
renderer->dst = dst;
+ renderer->clip_region = clip_region;
renderer->composite_rectangles = *rects;
- status = _cairo_pattern_acquire_surface (
- renderer->pattern, &renderer->dst->base,
- rects->bounded.x, rects->bounded.y,
- rects->bounded.width, rects->bounded.height,
- CAIRO_PATTERN_ACQUIRE_NONE,
- (cairo_surface_t **) &renderer->src,
- &renderer->src_attributes);
- if (status)
- goto unwind;
-
- status = _cairo_image_surface_set_attributes (
- renderer->src, &renderer->src_attributes,
- rects->bounded.x + rects->bounded.width/2,
- rects->bounded.y + rects->bounded.height/2);
- if (status)
- goto unwind;
-
/* TODO: support rendering to A1 surfaces (or: go add span
* compositing to pixman.) */
- renderer->mask = (cairo_image_surface_t *)
- cairo_image_surface_create (CAIRO_FORMAT_A8,
- rects->bounded.width,
- rects->bounded.height);
-
- status = cairo_surface_status (&renderer->mask->base);
-
- unwind:
- if (status != CAIRO_STATUS_SUCCESS) {
- _cairo_image_surface_span_renderer_destroy (renderer);
- return _cairo_span_renderer_create_in_error (status);
+ renderer->mask = pixman_image_create_bits (PIXMAN_a8,
+ rects->bounded.width,
+ rects->bounded.height,
+ NULL, 0);
+ if (renderer->mask == NULL) {
+ free (renderer);
+ return _cairo_span_renderer_create_in_error (CAIRO_STATUS_NO_MEMORY);
}
- renderer->mask_data = renderer->mask->data - rects->bounded.x - rects->bounded.y * renderer->mask->stride;
- renderer->mask_stride = renderer->mask->stride;
- return &renderer->base;
-}
-
-static cairo_bool_t
-_cairo_image_surface_get_extents (void *abstract_surface,
- cairo_rectangle_int_t *rectangle)
-{
- cairo_image_surface_t *surface = abstract_surface;
-
- rectangle->x = 0;
- rectangle->y = 0;
- rectangle->width = surface->width;
- rectangle->height = surface->height;
-
- return TRUE;
-}
-
-static void
-_cairo_image_surface_get_font_options (void *abstract_surface,
- cairo_font_options_t *options)
-{
- _cairo_font_options_init_default (options);
+ renderer->mask_stride = pixman_image_get_stride (renderer->mask);
+ renderer->mask_data = (uint8_t *) pixman_image_get_data (renderer->mask) - rects->bounded.x - rects->bounded.y * renderer->mask_stride;
- cairo_font_options_set_hint_metrics (options, CAIRO_HINT_METRICS_ON);
+ return &renderer->base;
}
/**
@@ -1647,6 +4327,7 @@ const cairo_surface_backend_t _cairo_image_surface_backend = {
_cairo_image_surface_composite_trapezoids,
_cairo_image_surface_create_span_renderer,
_cairo_image_surface_check_span_renderer,
+
NULL, /* copy_page */
NULL, /* show_page */
_cairo_image_surface_get_extents,
@@ -1657,11 +4338,12 @@ const cairo_surface_backend_t _cairo_image_surface_backend = {
NULL, /* font_fini */
NULL, /* glyph_fini */
- NULL, /* paint */
- NULL, /* mask */
- NULL, /* stroke */
- NULL, /* fill */
- NULL, /* show_glyphs */
+ _cairo_image_surface_paint,
+ _cairo_image_surface_mask,
+ _cairo_image_surface_stroke,
+ _cairo_image_surface_fill,
+ _cairo_image_surface_glyphs,
+ NULL, /* show_text_glyphs */
NULL, /* snapshot */
NULL, /* is_similar */
};
@@ -1673,7 +4355,6 @@ _cairo_image_surface_coerce (cairo_image_surface_t *surface,
cairo_format_t format)
{
cairo_image_surface_t *clone;
- cairo_surface_pattern_t pattern;
cairo_status_t status;
status = surface->base.status;
@@ -1688,17 +4369,13 @@ _cairo_image_surface_coerce (cairo_image_surface_t *surface,
if (unlikely (clone->base.status))
return clone;
- _cairo_pattern_init_for_surface (&pattern, &surface->base);
- status = _cairo_surface_paint (&clone->base,
- CAIRO_OPERATOR_SOURCE,
- &pattern.base,
- NULL);
- _cairo_pattern_fini (&pattern.base);
-
- if (unlikely (status)) {
- cairo_surface_destroy (&clone->base);
- return (cairo_image_surface_t *)_cairo_surface_create_in_error (status);
- }
+ pixman_image_composite (PIXMAN_OP_SRC,
+ surface->pixman_image, NULL, clone->pixman_image,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ surface->width, surface->height);
+ clone->base.is_clear = FALSE;
clone->base.device_transform =
surface->base.device_transform;
diff --git a/src/cairo-mutex-list-private.h b/src/cairo-mutex-list-private.h
index 2f48316..c84cebf 100644
--- a/src/cairo-mutex-list-private.h
+++ b/src/cairo-mutex-list-private.h
@@ -38,6 +38,8 @@
CAIRO_MUTEX_DECLARE (_cairo_pattern_solid_surface_cache_lock)
+CAIRO_MUTEX_DECLARE (_cairo_image_solid_cache_mutex)
+
CAIRO_MUTEX_DECLARE (_cairo_toy_font_face_mutex)
CAIRO_MUTEX_DECLARE (_cairo_intern_string_mutex)
CAIRO_MUTEX_DECLARE (_cairo_scaled_font_map_mutex)
diff --git a/src/cairo-xcb-surface.c b/src/cairo-xcb-surface.c
index faa5665..666abc9 100644
--- a/src/cairo-xcb-surface.c
+++ b/src/cairo-xcb-surface.c
@@ -600,14 +600,8 @@ _get_image_surface (cairo_xcb_surface_t *surface,
* which takes data in an arbitrary format and converts it
* to something supported by that library.
*/
- image = (cairo_image_surface_t *)
- _cairo_image_surface_create_with_masks (data,
- &masks,
- extents.width,
- extents.height,
- bytes_per_line);
- if (image->base.status)
- goto FAIL;
+ ASSERT_NOT_REACHED;
+ goto FAIL;
}
/* Let the surface take ownership of the data */
diff --git a/src/cairoint.h b/src/cairoint.h
index c2d36e0..6e059c4 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -833,7 +833,6 @@ struct _cairo_image_surface {
int depth;
pixman_image_t *pixman_image;
- cairo_region_t *clip_region;
unsigned owns_data : 1;
unsigned transparency : 2;
@@ -2162,9 +2161,15 @@ _cairo_format_bits_per_pixel (cairo_format_t format) cairo_const;
cairo_private cairo_format_t
_cairo_format_from_content (cairo_content_t content) cairo_const;
+cairo_private cairo_format_t
+_cairo_format_from_pixman_format (pixman_format_code_t pixman_format);
+
cairo_private cairo_content_t
_cairo_content_from_format (cairo_format_t format) cairo_const;
+cairo_private cairo_content_t
+_cairo_content_from_pixman_format (pixman_format_code_t pixman_format);
+
cairo_private cairo_surface_t *
_cairo_image_surface_create_for_pixman_image (pixman_image_t *pixman_image,
pixman_format_code_t pixman_format);
@@ -2185,24 +2190,10 @@ _cairo_image_surface_create_with_pixman_format (unsigned char *data,
int stride);
cairo_private cairo_surface_t *
-_cairo_image_surface_create_with_masks (unsigned char *data,
- cairo_format_masks_t *format,
- int width,
- int height,
- int stride);
-
-cairo_private cairo_surface_t *
_cairo_image_surface_create_with_content (cairo_content_t content,
int width,
int height);
-cairo_private cairo_surface_t *
-_cairo_image_surface_create_for_data_with_content (unsigned char *data,
- cairo_content_t content,
- int width,
- int height,
- int stride);
-
cairo_private void
_cairo_image_surface_assume_ownership_of_data (cairo_image_surface_t *surface);
diff --git a/test/clip-fill-unbounded.argb32.ref.png b/test/clip-fill-unbounded.argb32.ref.png
index 9adf992..b87efd4 100644
Binary files a/test/clip-fill-unbounded.argb32.ref.png and b/test/clip-fill-unbounded.argb32.ref.png differ
diff --git a/test/clip-fill-unbounded.rgb24.ref.png b/test/clip-fill-unbounded.rgb24.ref.png
index e57e296..915ebe1 100644
Binary files a/test/clip-fill-unbounded.rgb24.ref.png and b/test/clip-fill-unbounded.rgb24.ref.png differ
diff --git a/test/clip-stroke-unbounded.argb32.ref.png b/test/clip-stroke-unbounded.argb32.ref.png
index 39b9a30..e48537f 100644
Binary files a/test/clip-stroke-unbounded.argb32.ref.png and b/test/clip-stroke-unbounded.argb32.ref.png differ
diff --git a/test/clip-stroke-unbounded.rgb24.ref.png b/test/clip-stroke-unbounded.rgb24.ref.png
index a30352e..d2880f1 100644
Binary files a/test/clip-stroke-unbounded.rgb24.ref.png and b/test/clip-stroke-unbounded.rgb24.ref.png differ
diff --git a/test/clip-stroke.ref.png b/test/clip-stroke.ref.png
index 7af2e9b..dd5ae9a 100644
Binary files a/test/clip-stroke.ref.png and b/test/clip-stroke.ref.png differ
diff --git a/test/clipped-group.ref.png b/test/clipped-group.ref.png
index b25c9f4..c3fcbf8 100644
Binary files a/test/clipped-group.ref.png and b/test/clipped-group.ref.png differ
diff --git a/test/leaky-dashed-rectangle.ref.png b/test/leaky-dashed-rectangle.ref.png
index c0ba7b2..05f4584 100644
Binary files a/test/leaky-dashed-rectangle.ref.png and b/test/leaky-dashed-rectangle.ref.png differ
diff --git a/test/scale-offset-image.xfail.png b/test/scale-offset-image.xfail.png
index fef3a39..f0db601 100644
Binary files a/test/scale-offset-image.xfail.png and b/test/scale-offset-image.xfail.png differ
diff --git a/test/scale-offset-similar.xfail.png b/test/scale-offset-similar.xfail.png
index fef3a39..f0db601 100644
Binary files a/test/scale-offset-similar.xfail.png and b/test/scale-offset-similar.xfail.png differ
diff --git a/test/self-intersecting.ref.png b/test/self-intersecting.ref.png
index 32d1439..d554d83 100644
Binary files a/test/self-intersecting.ref.png and b/test/self-intersecting.ref.png differ
commit ec7cc9dea16f94e1e56720be548cf5520ec4708b
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Fri Jan 22 19:27:45 2010 +0000
ft: Tidy computation of transformed bitmap, and mark if CA
Discard a redundant clear as the image surface is guaranteed to return
a cleared surface that meets pixman/xlib requirements for alignment, and
more importantly add the ComponentAlpha flag on the pixman image
generated as appropriate.
diff --git a/src/cairo-ft-font.c b/src/cairo-ft-font.c
index 1c56031..56f0d10 100644
--- a/src/cairo-ft-font.c
+++ b/src/cairo-ft-font.c
@@ -992,6 +992,9 @@ _get_bitmap_surface (FT_Bitmap *bitmap,
return (*surface)->base.status;
}
+ if (format == CAIRO_FORMAT_ARGB32)
+ pixman_image_set_component_alpha ((*surface)->pixman_image, TRUE);
+
_cairo_image_surface_assume_ownership_of_data ((*surface));
_cairo_debug_check_image_surface_is_defined (&(*surface)->base);
@@ -1202,8 +1205,8 @@ _transform_glyph_bitmap (cairo_matrix_t * shape,
original_to_transformed = *shape;
cairo_surface_get_device_offset (&(*surface)->base, &origin_x, &origin_y);
- orig_width = cairo_image_surface_get_width (&(*surface)->base);
- orig_height = cairo_image_surface_get_height (&(*surface)->base);
+ orig_width = (*surface)->width;
+ orig_height = (*surface)->height;
cairo_matrix_translate (&original_to_transformed,
-origin_x, -origin_y);
@@ -1241,9 +1244,8 @@ _transform_glyph_bitmap (cairo_matrix_t * shape,
original_to_transformed.x0 -= x_min;
original_to_transformed.y0 -= y_min;
- /* Create the transformed bitmap
- */
- width = x_max - x_min;
+ /* Create the transformed bitmap */
+ width = x_max - x_min;
height = y_max - y_min;
transformed_to_original = original_to_transformed;
@@ -1251,30 +1253,19 @@ _transform_glyph_bitmap (cairo_matrix_t * shape,
if (unlikely (status))
return status;
- /* We need to pad out the width to 32-bit intervals for cairo-xlib-surface.c */
- width = (width + 3) & ~3;
image = cairo_image_surface_create (CAIRO_FORMAT_A8, width, height);
if (unlikely (image->status))
return image->status;
- /* Initialize it to empty
- */
- status = _cairo_surface_fill_rectangle (image, CAIRO_OPERATOR_CLEAR,
- CAIRO_COLOR_TRANSPARENT,
- 0, 0,
- width, height);
- if (unlikely (status)) {
- cairo_surface_destroy (image);
- return status;
- }
-
/* Draw the original bitmap transformed into the new bitmap
*/
_cairo_pattern_init_for_surface (&pattern, &(*surface)->base);
cairo_pattern_set_matrix (&pattern.base, &transformed_to_original);
- status = _cairo_surface_paint (image, CAIRO_OPERATOR_OVER,
- &pattern.base, NULL);
+ status = _cairo_surface_paint (image,
+ CAIRO_OPERATOR_SOURCE,
+ &pattern.base,
+ NULL);
_cairo_pattern_fini (&pattern.base);
commit b713510f213d0a83cb0575d6870416a0f13786c9
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Fri Jan 22 17:56:26 2010 +0000
surface-fallback: Convert to composite rectangles
diff --git a/src/cairo-surface-fallback.c b/src/cairo-surface-fallback.c
index d9528ce..7cd8dee 100644
--- a/src/cairo-surface-fallback.c
+++ b/src/cairo-surface-fallback.c
@@ -40,12 +40,13 @@
#include "cairoint.h"
-#include "cairo-surface-fallback-private.h"
+#include "cairo-boxes-private.h"
#include "cairo-clip-private.h"
#include "cairo-composite-rectangles-private.h"
#include "cairo-error-private.h"
#include "cairo-region-private.h"
#include "cairo-spans-private.h"
+#include "cairo-surface-fallback-private.h"
typedef struct {
cairo_surface_t *dst;
@@ -894,85 +895,51 @@ _composite_spans_draw_func (void *closure,
clip_region);
}
-static cairo_status_t
-_rectangle_intersect_clip (cairo_rectangle_int_t *extents, cairo_clip_t *clip)
-{
- if (clip != NULL) {
- if (! _cairo_rectangle_intersect (extents,
- _cairo_clip_get_extents (clip)))
- {
- return CAIRO_INT_STATUS_NOTHING_TO_DO;
- }
-
- return _cairo_clip_rectangle (clip, extents);
- } else if (_cairo_rectangle_empty (extents))
- return CAIRO_INT_STATUS_NOTHING_TO_DO;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
static cairo_bool_t
-_clip_contains_rectangle (cairo_clip_t *clip,
- const cairo_rectangle_int_t *rect)
+box_is_aligned (const cairo_box_t *box)
{
- cairo_clip_path_t *clip_path;
-
- clip_path = clip->path;
-
- if (clip_path->extents.x > rect->x ||
- clip_path->extents.y > rect->y ||
- clip_path->extents.x + clip_path->extents.width < rect->x + rect->width ||
- clip_path->extents.y + clip_path->extents.height < rect->y + rect->height)
- {
- return FALSE;
- }
-
- do {
- cairo_box_t box;
-
- if (! _cairo_path_fixed_is_box (&clip_path->path, &box))
- return FALSE;
-
- if (box.p1.x > _cairo_fixed_from_int (rect->x) ||
- box.p1.y > _cairo_fixed_from_int (rect->y) ||
- box.p2.x < _cairo_fixed_from_int (rect->x + rect->width) ||
- box.p2.y < _cairo_fixed_from_int (rect->y + rect->height))
- {
- return FALSE;
- }
- } while ((clip_path = clip_path->prev) != NULL);
-
- return TRUE;
+ return
+ _cairo_fixed_is_integer (box->p1.x) &&
+ _cairo_fixed_is_integer (box->p1.y) &&
+ _cairo_fixed_is_integer (box->p2.x) &&
+ _cairo_fixed_is_integer (box->p2.y);
}
static inline cairo_status_t
_clip_to_boxes (cairo_clip_t **clip,
- const cairo_rectangle_int_t *extents,
- cairo_bool_t is_bounded,
+ const cairo_composite_rectangles_t *extents,
cairo_box_t **boxes,
int *num_boxes)
{
cairo_status_t status;
+ const cairo_rectangle_int_t *rect;
- if (*clip == NULL) {
- status = CAIRO_STATUS_SUCCESS;
+ rect = extents->is_bounded ? &extents->bounded : &extents->unbounded;
+
+ if (*clip == NULL)
goto EXTENTS;
- }
+
+ status = _cairo_clip_rectangle (*clip, rect);
+ if (unlikely (status))
+ return status;
status = _cairo_clip_get_boxes (*clip, boxes, num_boxes);
switch ((int) status) {
case CAIRO_STATUS_SUCCESS:
- if (is_bounded)
+ if (extents->is_bounded || (*num_boxes == 1 && box_is_aligned (*boxes)))
*clip = NULL;
goto DONE;
- case CAIRO_INT_STATUS_UNSUPPORTED:
- status = CAIRO_STATUS_SUCCESS;
+ case CAIRO_INT_STATUS_UNSUPPORTED:
goto EXTENTS;
+
+ default:
+ return status;
}
EXTENTS:
- _cairo_box_from_rectangle (&(*boxes)[0], extents);
+ status = CAIRO_STATUS_SUCCESS;
+ _cairo_box_from_rectangle (&(*boxes)[0], rect);
*num_boxes = 1;
DONE:
return status;
@@ -984,44 +951,32 @@ _cairo_surface_fallback_paint (cairo_surface_t *surface,
const cairo_pattern_t *source,
cairo_clip_t *clip)
{
- cairo_status_t status;
- cairo_rectangle_int_t extents;
- cairo_bool_t is_bounded;
+ cairo_composite_rectangles_t extents;
+ cairo_rectangle_int_t rect;
cairo_clip_path_t *clip_path = clip ? clip->path : NULL;
- cairo_box_t boxes_stack[32], *boxes = boxes_stack;
+ cairo_box_t boxes_stack[32], *clip_boxes = boxes_stack;
+ cairo_boxes_t boxes;
int num_boxes = ARRAY_LENGTH (boxes_stack);
+ cairo_status_t status;
cairo_traps_t traps;
- is_bounded = _cairo_surface_get_extents (surface, &extents);
- assert (is_bounded || clip);
-
- is_bounded = FALSE;
- if (_cairo_operator_bounded_by_source (op)) {
- cairo_rectangle_int_t source_extents;
+ extents.is_bounded = _cairo_surface_get_extents (surface, &rect);
+ assert (extents.is_bounded || clip);
- _cairo_pattern_get_extents (source, &source_extents);
- if (! _cairo_rectangle_intersect (&extents, &source_extents))
- return CAIRO_STATUS_SUCCESS;
-
- is_bounded = TRUE;
- }
+ status = _cairo_composite_rectangles_init_for_paint (&extents,
+ rect.width,
+ rect.height,
+ op, source,
+ clip);
+ if (unlikely (status))
+ return status;
- if (is_bounded && clip != NULL && _clip_contains_rectangle (clip, &extents))
+ if (_cairo_clip_contains_rectangle (clip, &extents))
clip = NULL;
- status = _rectangle_intersect_clip (&extents, clip);
- if (unlikely (status)) {
- if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
- status = CAIRO_STATUS_SUCCESS;
- return status;
- }
-
- status = _clip_to_boxes (&clip, &extents, is_bounded, &boxes, &num_boxes);
- if (unlikely (status)) {
- if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
- status = CAIRO_STATUS_SUCCESS;
+ status = _clip_to_boxes (&clip, &extents, &clip_boxes, &num_boxes);
+ if (unlikely (status))
return status;
- }
/* If the clip cannot be reduced to a set of boxes, we will need to
* use a clipmask. Paint is special as it is the only operation that
@@ -1039,18 +994,20 @@ _cairo_surface_fallback_paint (cairo_surface_t *surface,
NULL);
}
- status = _cairo_traps_init_boxes (&traps, boxes, num_boxes);
+ /* meh, surface-fallback is dying anyway... */
+ _cairo_boxes_init_for_array (&boxes, clip_boxes, num_boxes);
+ status = _cairo_traps_init_boxes (&traps, &boxes);
if (unlikely (status))
goto CLEANUP_BOXES;
status = _clip_and_composite_trapezoids (source, op, surface,
&traps, CAIRO_ANTIALIAS_DEFAULT,
- clip, &extents);
+ clip, &extents.bounded);
_cairo_traps_fini (&traps);
CLEANUP_BOXES:
- if (boxes != boxes_stack)
- free (boxes);
+ if (clip_boxes != boxes_stack)
+ free (clip_boxes);
return status;
}
@@ -1093,48 +1050,32 @@ _cairo_surface_fallback_mask (cairo_surface_t *surface,
const cairo_pattern_t *mask,
cairo_clip_t *clip)
{
- cairo_rectangle_int_t extents;
- cairo_bool_t is_bounded;
+ cairo_composite_rectangles_t extents;
+ cairo_rectangle_int_t rect;
cairo_status_t status;
- is_bounded = _cairo_surface_get_extents (surface, &extents);
- assert (is_bounded || clip);
-
- is_bounded = FALSE;
- if (_cairo_operator_bounded_by_source (op)) {
- cairo_rectangle_int_t source_extents;
-
- _cairo_pattern_get_extents (source, &source_extents);
- if (! _cairo_rectangle_intersect (&extents, &source_extents))
- return CAIRO_STATUS_SUCCESS;
-
- is_bounded = TRUE;
- }
+ extents.is_bounded = _cairo_surface_get_extents (surface, &rect);
+ assert (extents.is_bounded || clip);
- if (_cairo_operator_bounded_by_mask (op)) {
- cairo_rectangle_int_t mask_extents;
-
- _cairo_pattern_get_extents (mask, &mask_extents);
- if (! _cairo_rectangle_intersect (&extents, &mask_extents))
- return CAIRO_STATUS_SUCCESS;
-
- is_bounded = TRUE;
- }
+ status = _cairo_composite_rectangles_init_for_mask (&extents,
+ rect.width, rect.height,
+ op, source, mask, clip);
+ if (unlikely (status))
+ return status;
- if (is_bounded && clip != NULL && _clip_contains_rectangle (clip, &extents))
+ if (_cairo_clip_contains_rectangle (clip, &extents))
clip = NULL;
- status = _rectangle_intersect_clip (&extents, clip);
- if (status) {
- if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
- status = CAIRO_STATUS_SUCCESS;
- return status;
+ if (clip != NULL && extents.is_bounded) {
+ status = _cairo_clip_rectangle (clip, &extents.bounded);
+ if (unlikely (status))
+ return status;
}
return _clip_and_composite (clip, op, source,
_cairo_surface_mask_draw_func,
(void *) mask,
- surface, &extents);
+ surface, &extents.bounded);
}
cairo_status_t
@@ -1151,60 +1092,36 @@ _cairo_surface_fallback_stroke (cairo_surface_t *surface,
{
cairo_polygon_t polygon;
cairo_traps_t traps;
- cairo_box_t boxes_stack[32], *boxes = boxes_stack;
+ cairo_box_t boxes_stack[32], *clip_boxes = boxes_stack;
int num_boxes = ARRAY_LENGTH (boxes_stack);
- cairo_rectangle_int_t extents;
- cairo_bool_t is_bounded;
+ cairo_composite_rectangles_t extents;
+ cairo_rectangle_int_t rect;
cairo_status_t status;
- is_bounded = _cairo_surface_get_extents (surface, &extents);
- assert (is_bounded || clip);
-
- is_bounded = FALSE;
- if (_cairo_operator_bounded_by_source (op)) {
- cairo_rectangle_int_t source_extents;
-
- _cairo_pattern_get_extents (source, &source_extents);
- if (! _cairo_rectangle_intersect (&extents, &source_extents))
- return CAIRO_STATUS_SUCCESS;
-
- is_bounded = TRUE;
- }
-
- if (_cairo_operator_bounded_by_mask (op)) {
- cairo_rectangle_int_t path_extents;
-
- _cairo_path_fixed_approximate_stroke_extents (path,
- stroke_style, ctm,
- &path_extents);
- if (! _cairo_rectangle_intersect (&extents, &path_extents))
- return CAIRO_STATUS_SUCCESS;
+ extents.is_bounded = _cairo_surface_get_extents (surface, &rect);
+ assert (extents.is_bounded || clip);
- is_bounded = TRUE;
- }
+ status = _cairo_composite_rectangles_init_for_stroke (&extents,
+ rect.width,
+ rect.height,
+ op, source,
+ path, stroke_style, ctm,
+ clip);
+ if (unlikely (status))
+ return status;
- if (is_bounded && clip != NULL && _clip_contains_rectangle (clip, &extents))
+ if (_cairo_clip_contains_rectangle (clip, &extents))
clip = NULL;
- status = _rectangle_intersect_clip (&extents, clip);
- if (unlikely (status)) {
- if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
- status = CAIRO_STATUS_SUCCESS;
- return status;
- }
-
- status = _clip_to_boxes (&clip, &extents, is_bounded, &boxes, &num_boxes);
- if (unlikely (status)) {
- if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
- status = CAIRO_STATUS_SUCCESS;
+ status = _clip_to_boxes (&clip, &extents, &clip_boxes, &num_boxes);
+ if (unlikely (status))
return status;
- }
_cairo_polygon_init (&polygon);
- _cairo_polygon_limit (&polygon, boxes, num_boxes);
+ _cairo_polygon_limit (&polygon, clip_boxes, num_boxes);
_cairo_traps_init (&traps);
- _cairo_traps_limit (&traps, boxes, num_boxes);
+ _cairo_traps_limit (&traps, clip_boxes, num_boxes);
if (path->is_rectilinear) {
status = _cairo_path_fixed_stroke_rectilinear_to_traps (path,
@@ -1230,10 +1147,8 @@ _cairo_surface_fallback_stroke (cairo_surface_t *surface,
goto DO_TRAPS;
if (_cairo_operator_bounded_by_mask (op)) {
- cairo_rectangle_int_t polygon_extents;
-
- _cairo_box_round_to_rectangle (&polygon.extents, &polygon_extents);
- if (! _cairo_rectangle_intersect (&extents, &polygon_extents))
+ _cairo_box_round_to_rectangle (&polygon.extents, &extents.mask);
+ if (! _cairo_rectangle_intersect (&extents.bounded, &extents.mask))
goto CLEANUP;
}
@@ -1246,7 +1161,7 @@ _cairo_surface_fallback_stroke (cairo_surface_t *surface,
status = _clip_and_composite (clip, op, source,
_composite_spans_draw_func,
- &info, surface, &extents);
+ &info, surface, &extents.bounded);
goto CLEANUP;
}
@@ -1260,12 +1175,12 @@ _cairo_surface_fallback_stroke (cairo_surface_t *surface,
DO_TRAPS:
status = _clip_and_composite_trapezoids (source, op, surface,
&traps, antialias,
- clip, &extents);
+ clip, &extents.bounded);
CLEANUP:
_cairo_traps_fini (&traps);
_cairo_polygon_fini (&polygon);
- if (boxes != boxes_stack)
- free (boxes);
+ if (clip_boxes != boxes_stack)
+ free (clip_boxes);
return status;
}
@@ -1282,67 +1197,36 @@ _cairo_surface_fallback_fill (cairo_surface_t *surface,
{
cairo_polygon_t polygon;
cairo_traps_t traps;
- cairo_box_t boxes_stack[32], *boxes = boxes_stack;
+ cairo_box_t boxes_stack[32], *clip_boxes = boxes_stack;
int num_boxes = ARRAY_LENGTH (boxes_stack);
- cairo_rectangle_int_t extents;
- cairo_bool_t is_bounded;
cairo_bool_t is_rectilinear;
+ cairo_composite_rectangles_t extents;
+ cairo_rectangle_int_t rect;
cairo_status_t status;
- is_bounded = _cairo_surface_get_extents (surface, &extents);
- assert (is_bounded || clip);
-
- is_bounded = FALSE;
- if (_cairo_operator_bounded_by_source (op)) {
- cairo_rectangle_int_t source_extents;
-
- _cairo_pattern_get_extents (source, &source_extents);
- if (! _cairo_rectangle_intersect (&extents, &source_extents))
- return CAIRO_STATUS_SUCCESS;
-
- is_bounded = TRUE;
- }
-
- if (_cairo_operator_bounded_by_mask (op)) {
- cairo_rectangle_int_t path_extents;
-
- _cairo_path_fixed_approximate_fill_extents (path, &path_extents);
- if (! _cairo_rectangle_intersect (&extents, &path_extents))
- return CAIRO_STATUS_SUCCESS;
-
- is_bounded = TRUE;
- }
-
- if (is_bounded) {
- if (clip != NULL && _clip_contains_rectangle (clip, &extents))
- clip = NULL;
-
- if (clip != NULL && clip->path->prev == NULL &&
- _cairo_path_fixed_equal (&clip->path->path, path))
- {
- clip = NULL;
- }
- }
+ extents.is_bounded = _cairo_surface_get_extents (surface, &rect);
+ assert (extents.is_bounded || clip);
- status = _rectangle_intersect_clip (&extents, clip);
- if (unlikely (status)) {
- if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
- status = CAIRO_STATUS_SUCCESS;
+ status = _cairo_composite_rectangles_init_for_fill (&extents,
+ rect.width,
+ rect.height,
+ op, source, path,
+ clip);
+ if (unlikely (status))
return status;
- }
- status = _clip_to_boxes (&clip, &extents, is_bounded, &boxes, &num_boxes);
- if (unlikely (status)) {
- if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
- status = CAIRO_STATUS_SUCCESS;
+ if (_cairo_clip_contains_rectangle (clip, &extents))
+ clip = NULL;
+
+ status = _clip_to_boxes (&clip, &extents, &clip_boxes, &num_boxes);
+ if (unlikely (status))
return status;
- }
_cairo_traps_init (&traps);
- _cairo_traps_limit (&traps, boxes, num_boxes);
+ _cairo_traps_limit (&traps, clip_boxes, num_boxes);
_cairo_polygon_init (&polygon);
- _cairo_polygon_limit (&polygon, boxes, num_boxes);
+ _cairo_polygon_limit (&polygon, clip_boxes, num_boxes);
if (path->is_empty_fill)
goto DO_TRAPS;
@@ -1367,10 +1251,8 @@ _cairo_surface_fallback_fill (cairo_surface_t *surface,
goto DO_TRAPS;
if (_cairo_operator_bounded_by_mask (op)) {
- cairo_rectangle_int_t polygon_extents;
-
- _cairo_box_round_to_rectangle (&polygon.extents, &polygon_extents);
- if (! _cairo_rectangle_intersect (&extents, &polygon_extents))
+ _cairo_box_round_to_rectangle (&polygon.extents, &extents.mask);
+ if (! _cairo_rectangle_intersect (&extents.bounded, &extents.mask))
goto CLEANUP;
}
@@ -1395,7 +1277,7 @@ _cairo_surface_fallback_fill (cairo_surface_t *surface,
status = _clip_and_composite (clip, op, source,
_composite_spans_draw_func,
- &info, surface, &extents);
+ &info, surface, &extents.bounded);
goto CLEANUP;
}
@@ -1409,12 +1291,12 @@ _cairo_surface_fallback_fill (cairo_surface_t *surface,
DO_TRAPS:
status = _clip_and_composite_trapezoids (source, op, surface,
&traps, antialias,
- clip, &extents);
+ clip, &extents.bounded);
CLEANUP:
_cairo_traps_fini (&traps);
_cairo_polygon_fini (&polygon);
- if (boxes != boxes_stack)
- free (boxes);
+ if (clip_boxes != boxes_stack)
+ free (clip_boxes);
return status;
}
@@ -1485,50 +1367,32 @@ _cairo_surface_fallback_show_glyphs (cairo_surface_t *surface,
cairo_scaled_font_t *scaled_font,
cairo_clip_t *clip)
{
- cairo_status_t status;
- cairo_rectangle_int_t extents;
cairo_show_glyphs_info_t glyph_info;
- cairo_bool_t is_bounded;
-
- is_bounded = _cairo_surface_get_extents (surface, &extents);
- assert (is_bounded || clip);
-
- is_bounded = FALSE;
- if (_cairo_operator_bounded_by_source (op)) {
- cairo_rectangle_int_t source_extents;
-
- _cairo_pattern_get_extents (source, &source_extents);
- if (! _cairo_rectangle_intersect (&extents, &source_extents))
- return CAIRO_STATUS_SUCCESS;
-
- is_bounded = TRUE;
- }
+ cairo_composite_rectangles_t extents;
+ cairo_rectangle_int_t rect;
+ cairo_status_t status;
- if (_cairo_operator_bounded_by_mask (op)) {
- cairo_rectangle_int_t glyph_extents;
+ extents.is_bounded = _cairo_surface_get_extents (surface, &rect);
+ assert (extents.is_bounded || clip);
- status = _cairo_scaled_font_glyph_device_extents (scaled_font,
- glyphs,
- num_glyphs,
- &glyph_extents,
+ status = _cairo_composite_rectangles_init_for_glyphs (&extents,
+ rect.width,
+ rect.height,
+ op, source,
+ scaled_font,
+ glyphs, num_glyphs,
+ clip,
NULL);
- if (unlikely (status))
- return status;
-
- if (! _cairo_rectangle_intersect (&extents, &glyph_extents))
- return CAIRO_STATUS_SUCCESS;
-
- is_bounded = TRUE;
- }
+ if (unlikely (status))
+ return status;
- if (is_bounded && clip != NULL && _clip_contains_rectangle (clip, &extents))
+ if (_cairo_clip_contains_rectangle (clip, &extents))
clip = NULL;
- status = _rectangle_intersect_clip (&extents, clip);
- if (status) {
- if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
- status = CAIRO_STATUS_SUCCESS;
- return status;
+ if (clip != NULL && extents.is_bounded) {
+ status = _cairo_clip_rectangle (clip, &extents.bounded);
+ if (unlikely (status))
+ return status;
}
glyph_info.font = scaled_font;
@@ -1539,7 +1403,7 @@ _cairo_surface_fallback_show_glyphs (cairo_surface_t *surface,
_cairo_surface_old_show_glyphs_draw_func,
&glyph_info,
surface,
- &extents);
+ &extents.bounded);
}
cairo_surface_t *
diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index bab13cc..1f438e8 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -121,6 +121,9 @@ cairo_status_t
_cairo_surface_set_error (cairo_surface_t *surface,
cairo_status_t status)
{
+ if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
+ status = CAIRO_STATUS_SUCCESS;
+
if (status == CAIRO_STATUS_SUCCESS || status >= CAIRO_INT_STATUS_UNSUPPORTED)
return status;
diff --git a/src/cairo-traps.c b/src/cairo-traps.c
index 8c7e7a8..3080d86 100644
--- a/src/cairo-traps.c
+++ b/src/cairo-traps.c
@@ -39,6 +39,7 @@
#include "cairoint.h"
+#include "cairo-boxes-private.h"
#include "cairo-error-private.h"
#include "cairo-region-private.h"
#include "cairo-slope-private.h"
@@ -157,45 +158,45 @@ _cairo_traps_add_trap (cairo_traps_t *traps,
**/
cairo_status_t
_cairo_traps_init_boxes (cairo_traps_t *traps,
- const cairo_box_t *boxes,
- int num_boxes)
+ const cairo_boxes_t *boxes)
{
cairo_trapezoid_t *trap;
+ const struct _cairo_boxes_chunk *chunk;
_cairo_traps_init (traps);
- while (traps->traps_size < num_boxes) {
+ while (traps->traps_size < boxes->num_boxes) {
if (unlikely (! _cairo_traps_grow (traps))) {
_cairo_traps_fini (traps);
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
}
- traps->num_traps = num_boxes;
+ traps->num_traps = boxes->num_boxes;
traps->is_rectilinear = TRUE;
traps->is_rectangular = TRUE;
+ traps->maybe_region = boxes->is_pixel_aligned;
trap = &traps->traps[0];
- while (num_boxes--) {
- trap->top = boxes->p1.y;
- trap->bottom = boxes->p2.y;
-
- trap->left.p1 = boxes->p1;
- trap->left.p2.x = boxes->p1.x;
- trap->left.p2.y = boxes->p2.y;
-
- trap->right.p1.x = boxes->p2.x;
- trap->right.p1.y = boxes->p1.y;
- trap->right.p2 = boxes->p2;
-
- if (traps->maybe_region) {
- traps->maybe_region = _cairo_fixed_is_integer (boxes->p1.x) &&
- _cairo_fixed_is_integer (boxes->p1.y) &&
- _cairo_fixed_is_integer (boxes->p2.x) &&
- _cairo_fixed_is_integer (boxes->p2.y);
- }
+ for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
+ const cairo_box_t *box;
+ int i;
+
+ box = chunk->base;
+ for (i = 0; i < chunk->count; i++) {
+ trap->top = box->p1.y;
+ trap->bottom = box->p2.y;
+
+ trap->left.p1 = box->p1;
+ trap->left.p2.x = box->p1.x;
+ trap->left.p2.y = box->p2.y;
- trap++, boxes++;
+ trap->right.p1.x = box->p2.x;
+ trap->right.p1.y = box->p1.y;
+ trap->right.p2 = box->p2;
+
+ box++, trap++;
+ }
}
return CAIRO_STATUS_SUCCESS;
diff --git a/src/cairoint.h b/src/cairoint.h
index 8e7ac58..c2d36e0 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -2377,8 +2377,7 @@ _cairo_traps_limit (cairo_traps_t *traps,
cairo_private cairo_status_t
_cairo_traps_init_boxes (cairo_traps_t *traps,
- const cairo_box_t *boxes,
- int num_boxes);
+ const cairo_boxes_t *boxes);
cairo_private void
_cairo_traps_clear (cairo_traps_t *traps);
commit 498c10032ea3f8631a928cd7df96766f2c8ddca4
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Fri Jan 22 16:39:29 2010 +0000
clip: Implement clipping using only the high-level operators.
Revamp clipping in preparation for the removal of the low-level interface
and promote backend to use the higher levels. The principle here is that
the higher level interface gives the backend more scope for choosing
better performing primitives.
diff --git a/src/cairo-clip-private.h b/src/cairo-clip-private.h
index 6128243..a3303fe 100644
--- a/src/cairo-clip-private.h
+++ b/src/cairo-clip-private.h
@@ -117,7 +117,7 @@ _cairo_clip_get_surface (cairo_clip_t *clip, cairo_surface_t *dst);
cairo_private cairo_status_t
_cairo_clip_combine_with_surface (cairo_clip_t *clip,
cairo_surface_t *dst,
- const cairo_rectangle_int_t *extents);
+ int dst_x, int dst_y);
cairo_private cairo_int_status_t
_cairo_clip_get_region (cairo_clip_t *clip,
@@ -128,6 +128,10 @@ _cairo_clip_get_boxes (cairo_clip_t *clip,
cairo_box_t **boxes,
int *count);
+cairo_private cairo_bool_t
+_cairo_clip_contains_rectangle (cairo_clip_t *clip,
+ const cairo_composite_rectangles_t *extents);
+
cairo_private void
_cairo_clip_drop_cache (cairo_clip_t *clip);
diff --git a/src/cairo-clip.c b/src/cairo-clip.c
index aa9433b..f18bff2 100644
--- a/src/cairo-clip.c
+++ b/src/cairo-clip.c
@@ -44,6 +44,7 @@
#include "cairo-error-private.h"
#include "cairo-freed-pool-private.h"
#include "cairo-path-fixed-private.h"
+#include "cairo-composite-rectangles-private.h"
#include "cairo-region-private.h"
#if HAS_FREED_POOL
@@ -169,7 +170,7 @@ _cairo_clip_intersect_rectangle (cairo_clip_t *clip,
clip_path->extents = *rect;
clip_path->fill_rule = CAIRO_FILL_RULE_WINDING;
clip_path->tolerance = 1;
- clip_path->antialias = CAIRO_ANTIALIAS_NONE;
+ clip_path->antialias = CAIRO_ANTIALIAS_DEFAULT;
clip_path->flags |= CAIRO_CLIP_PATH_IS_BOX;
/* could preallocate the region if it proves worthwhile */
@@ -328,8 +329,8 @@ _cairo_clip_rectangle (cairo_clip_t *clip,
/* if a smaller clip has already been set, ignore the new path */
if (clip->path != NULL) {
if (rectangle->x <= clip->path->extents.x &&
- rectangle->y <= clip->path->extents.x &&
- rectangle->x + rectangle->width >= clip->path->extents.x + clip->path->extents.width &&
+ rectangle->y <= clip->path->extents.y &&
+ rectangle->x + rectangle->width >= clip->path->extents.x + clip->path->extents.width &&
rectangle->y + rectangle->height >= clip->path->extents.y + clip->path->extents.height)
{
return CAIRO_STATUS_SUCCESS;
@@ -917,98 +918,56 @@ _cairo_clip_path_to_boxes (cairo_clip_path_t *clip_path,
return CAIRO_STATUS_SUCCESS;
}
-static cairo_status_t
-_combine_region (cairo_surface_t *surface,
- const cairo_region_t *region,
- const cairo_rectangle_int_t *extents)
-{
- cairo_region_t clear_region;
- cairo_status_t status;
-
- _cairo_region_init_rectangle (&clear_region, extents);
- status = cairo_region_subtract (&clear_region, region);
- if (unlikely (status))
- return status;
-
- if (! cairo_region_is_empty (&clear_region)) {
- cairo_region_translate (&clear_region, -extents->x, -extents->y);
- status = _cairo_surface_fill_region (surface,
- CAIRO_OPERATOR_CLEAR,
- CAIRO_COLOR_TRANSPARENT,
- &clear_region);
- }
- _cairo_region_fini (&clear_region);
-
- return status;
-}
-
static cairo_surface_t *
_cairo_clip_path_get_surface (cairo_clip_path_t *clip_path,
cairo_surface_t *target)
{
- cairo_surface_t *surface;
- cairo_status_t status;
const cairo_rectangle_int_t *clip_extents = &clip_path->extents;
- cairo_clip_path_t *prev;
cairo_bool_t need_translate;
+ cairo_surface_t *surface;
+ cairo_clip_path_t *prev;
+ cairo_status_t status;
if (clip_path->surface != NULL &&
clip_path->surface->backend == target->backend)
{
- return cairo_surface_reference (clip_path->surface);
+ return clip_path->surface;
}
- surface = _cairo_surface_create_similar_solid (target,
- CAIRO_CONTENT_ALPHA,
- clip_extents->width,
- clip_extents->height,
- CAIRO_COLOR_TRANSPARENT,
- FALSE);
- if (surface == NULL) {
- if (clip_path->surface != NULL &&
- clip_path->surface->backend == &_cairo_image_surface_backend)
- {
- return cairo_surface_reference (clip_path->surface);
- }
-
- surface =
- _cairo_image_surface_create_with_content (CAIRO_CONTENT_ALPHA,
- clip_extents->width,
- clip_extents->height);
- }
+ surface = _cairo_surface_create_similar_scratch (target,
+ CAIRO_CONTENT_ALPHA,
+ clip_extents->width,
+ clip_extents->height);
if (unlikely (surface->status))
return surface;
- status = _cairo_clip_path_to_region (clip_path);
- if (unlikely (_cairo_status_is_error (status)))
- goto BAIL;
-
need_translate = clip_extents->x | clip_extents->y;
- if (status == CAIRO_STATUS_SUCCESS) {
- if (need_translate) {
- cairo_region_translate (clip_path->region,
- -clip_extents->x, -clip_extents->y);
- }
- status = _cairo_surface_fill_region (surface,
- CAIRO_OPERATOR_SOURCE,
- CAIRO_COLOR_WHITE,
- clip_path->region);
- if (need_translate) {
- cairo_region_translate (clip_path->region,
- clip_extents->x, clip_extents->y);
- }
+ if (clip_path->flags & CAIRO_CLIP_PATH_IS_BOX &&
+ clip_path->path.maybe_fill_region)
+ {
+ status = _cairo_surface_paint (surface,
+ CAIRO_OPERATOR_SOURCE,
+ &_cairo_pattern_white.base,
+ NULL);
+ if (unlikely (status))
+ goto BAIL;
+ }
+ else
+ {
+ status = _cairo_surface_paint (surface,
+ CAIRO_OPERATOR_CLEAR,
+ &_cairo_pattern_clear.base,
+ NULL);
if (unlikely (status))
goto BAIL;
- goto DONE;
- } else {
if (need_translate) {
_cairo_path_fixed_translate (&clip_path->path,
_cairo_fixed_from_int (-clip_extents->x),
_cairo_fixed_from_int (-clip_extents->y));
}
status = _cairo_surface_fill (surface,
- CAIRO_OPERATOR_OVER,
+ CAIRO_OPERATOR_ADD,
&_cairo_pattern_white.base,
&clip_path->path,
clip_path->fill_rule,
@@ -1026,19 +985,14 @@ _cairo_clip_path_get_surface (cairo_clip_path_t *clip_path,
}
prev = clip_path->prev;
- NEXT_PATH:
- if (prev != NULL) {
- status = _cairo_clip_path_to_region (prev);
- if (unlikely (_cairo_status_is_error (status)))
- goto BAIL;
-
- if (status == CAIRO_STATUS_SUCCESS) {
- status = _combine_region (surface, prev->region, clip_extents);
- if (unlikely (status))
- goto BAIL;
- } else if (prev->flags & CAIRO_CLIP_PATH_IS_BOX) {
+ while (prev != NULL) {
+ if (prev->flags & CAIRO_CLIP_PATH_IS_BOX &&
+ prev->path.maybe_fill_region)
+ {
/* a simple box only affects the extents */
- } else if (prev->path.is_rectilinear) {
+ }
+ else if (prev->path.is_rectilinear)
+ {
if (need_translate) {
_cairo_path_fixed_translate (&prev->path,
_cairo_fixed_from_int (-clip_extents->x),
@@ -1060,20 +1014,21 @@ _cairo_clip_path_get_surface (cairo_clip_path_t *clip_path,
if (unlikely (status))
goto BAIL;
-
- prev = prev->prev;
- goto NEXT_PATH;
- } else {
- cairo_surface_t *prev_surface;
+ }
+ else
+ {
cairo_surface_pattern_t pattern;
+ cairo_surface_t *prev_surface;
prev_surface = _cairo_clip_path_get_surface (prev, target);
- _cairo_pattern_init_for_surface (&pattern, prev_surface);
- cairo_surface_destroy (prev_surface);
+ if (unlikely (prev_surface->status))
+ goto BAIL;
+ _cairo_pattern_init_for_surface (&pattern, prev_surface);
+ pattern.base.filter = CAIRO_FILTER_NEAREST;
cairo_matrix_init_translate (&pattern.base.matrix,
- -prev->extents.x + clip_extents->x,
- -prev->extents.y + clip_extents->y);
+ clip_extents->x - prev->extents.x,
+ clip_extents->y - prev->extents.y);
status = _cairo_surface_paint (surface,
CAIRO_OPERATOR_IN,
&pattern.base,
@@ -1082,18 +1037,64 @@ _cairo_clip_path_get_surface (cairo_clip_path_t *clip_path,
if (unlikely (status))
goto BAIL;
+
+ break;
}
+
+ prev = prev->prev;
}
- DONE:
cairo_surface_destroy (clip_path->surface);
- return clip_path->surface = cairo_surface_reference (surface);
+ return clip_path->surface = surface;
BAIL:
cairo_surface_destroy (surface);
return _cairo_surface_create_in_error (status);
}
+cairo_bool_t
+_cairo_clip_contains_rectangle (cairo_clip_t *clip,
+ const cairo_composite_rectangles_t *extents)
+{
+ cairo_clip_path_t *clip_path;
+ const cairo_rectangle_int_t *rect;
+
+ if (clip == NULL)
+ return FALSE;
+
+ rect = extents->is_bounded ? &extents->bounded : &extents->unbounded;
+
+ clip_path = clip->path;
+
+ if (clip_path->extents.x > rect->x ||
+ clip_path->extents.y > rect->y ||
+ clip_path->extents.x + clip_path->extents.width < rect->x + rect->width ||
+ clip_path->extents.y + clip_path->extents.height < rect->y + rect->height)
+ {
+ return FALSE;
+ }
+
+ do {
+ cairo_box_t box;
+
+ if ((clip_path->flags & CAIRO_CLIP_PATH_IS_BOX) == 0)
+ return FALSE;
+
+ if (! _cairo_path_fixed_is_box (&clip_path->path, &box))
+ return FALSE;
+
+ if (box.p1.x > _cairo_fixed_from_int (rect->x) ||
+ box.p1.y > _cairo_fixed_from_int (rect->y) ||
+ box.p2.x < _cairo_fixed_from_int (rect->x + rect->width) ||
+ box.p2.y < _cairo_fixed_from_int (rect->y + rect->height))
+ {
+ return FALSE;
+ }
+ } while ((clip_path = clip_path->prev) != NULL);
+
+ return TRUE;
+}
+
void
_cairo_debug_print_clip (FILE *stream, cairo_clip_t *clip)
{
@@ -1118,9 +1119,12 @@ _cairo_debug_print_clip (FILE *stream, cairo_clip_t *clip)
clip_path = clip->path;
do {
- fprintf (stream, "path: has region? %s, has surface? %s: ",
+ fprintf (stream, "path: has region? %s, has surface? %s, aa=%d, tolerance=%f, rule=%d: ",
clip_path->region == NULL ? "no" : "yes",
- clip_path->surface == NULL ? "no" : "yes");
+ clip_path->surface == NULL ? "no" : "yes",
+ clip_path->antialias,
+ clip_path->tolerance,
+ clip_path->fill_rule);
_cairo_debug_print_path (stream, &clip_path->path);
fprintf (stream, "\n");
} while ((clip_path = clip_path->prev) != NULL);
@@ -1129,6 +1133,7 @@ _cairo_debug_print_clip (FILE *stream, cairo_clip_t *clip)
cairo_surface_t *
_cairo_clip_get_surface (cairo_clip_t *clip, cairo_surface_t *target)
{
+ /* XXX is_clear -> all_clipped */
assert (clip->path != NULL);
return _cairo_clip_path_get_surface (clip->path, target);
}
@@ -1136,7 +1141,7 @@ _cairo_clip_get_surface (cairo_clip_t *clip, cairo_surface_t *target)
cairo_status_t
_cairo_clip_combine_with_surface (cairo_clip_t *clip,
cairo_surface_t *dst,
- const cairo_rectangle_int_t *extents)
+ int dst_x, int dst_y)
{
cairo_clip_path_t *clip_path = clip->path;
cairo_bool_t need_translate;
@@ -1150,9 +1155,10 @@ _cairo_clip_combine_with_surface (cairo_clip_t *clip,
cairo_surface_pattern_t pattern;
_cairo_pattern_init_for_surface (&pattern, clip_path->surface);
+ pattern.base.filter = CAIRO_FILTER_NEAREST;
cairo_matrix_init_translate (&pattern.base.matrix,
- extents->x - clip_path->extents.x,
- extents->y - clip_path->extents.y);
+ -dst_x + clip_path->extents.x,
+ -dst_y + clip_path->extents.y);
status = _cairo_surface_paint (dst,
CAIRO_OPERATOR_IN,
&pattern.base,
@@ -1163,15 +1169,8 @@ _cairo_clip_combine_with_surface (cairo_clip_t *clip,
return status;
}
- need_translate = extents->x | extents->y;
+ need_translate = dst_x | dst_y;
do {
- status = _cairo_clip_path_to_region (clip_path);
- if (unlikely (_cairo_status_is_error (status)))
- return status;
-
- if (status == CAIRO_STATUS_SUCCESS)
- return _combine_region (dst, clip_path->region, extents);
-
if (clip_path->surface != NULL &&
clip_path->surface->backend == dst->backend)
{
@@ -1179,8 +1178,9 @@ _cairo_clip_combine_with_surface (cairo_clip_t *clip,
_cairo_pattern_init_for_surface (&pattern, clip_path->surface);
cairo_matrix_init_translate (&pattern.base.matrix,
- extents->x - clip_path->extents.x,
- extents->y - clip_path->extents.y);
+ -dst_x + clip_path->extents.x,
+ -dst_y + clip_path->extents.y);
+ pattern.base.filter = CAIRO_FILTER_NEAREST;
status = _cairo_surface_paint (dst,
CAIRO_OPERATOR_IN,
&pattern.base,
@@ -1191,30 +1191,23 @@ _cairo_clip_combine_with_surface (cairo_clip_t *clip,
return status;
}
- if (clip_path->flags & CAIRO_CLIP_PATH_IS_BOX) {
- cairo_region_t clip_region;
-
- _cairo_region_init_rectangle (&clip_region, &clip_path->extents);
- status = _combine_region (dst, &clip_region, extents);
- } else {
- if (need_translate) {
- _cairo_path_fixed_translate (&clip_path->path,
- _cairo_fixed_from_int (-extents->x),
- _cairo_fixed_from_int (-extents->y));
- }
- status = _cairo_surface_fill (dst,
- CAIRO_OPERATOR_IN,
- &_cairo_pattern_white.base,
- &clip_path->path,
- clip_path->fill_rule,
- clip_path->tolerance,
- clip_path->antialias,
- NULL);
- if (need_translate) {
- _cairo_path_fixed_translate (&clip_path->path,
- _cairo_fixed_from_int (extents->x),
- _cairo_fixed_from_int (extents->y));
- }
+ if (need_translate) {
+ _cairo_path_fixed_translate (&clip_path->path,
+ _cairo_fixed_from_int (-dst_x),
+ _cairo_fixed_from_int (-dst_y));
+ }
+ status = _cairo_surface_fill (dst,
+ CAIRO_OPERATOR_IN,
+ &_cairo_pattern_white.base,
+ &clip_path->path,
+ clip_path->fill_rule,
+ clip_path->tolerance,
+ clip_path->antialias,
+ NULL);
+ if (need_translate) {
+ _cairo_path_fixed_translate (&clip_path->path,
+ _cairo_fixed_from_int (dst_x),
+ _cairo_fixed_from_int (dst_y));
}
if (unlikely (status))
diff --git a/src/cairo-surface-fallback.c b/src/cairo-surface-fallback.c
index 51e3d7e..d9528ce 100644
--- a/src/cairo-surface-fallback.c
+++ b/src/cairo-surface-fallback.c
@@ -164,7 +164,7 @@ _create_composite_mask_pattern (cairo_surface_pattern_t *mask_pattern,
goto CLEANUP_SURFACE;
if (clip_surface)
- status = _cairo_clip_combine_with_surface (clip, mask, extents);
+ status = _cairo_clip_combine_with_surface (clip, mask, extents->x, extents->y);
_cairo_pattern_init_for_surface (mask_pattern, mask);
commit 05bb43a00770f17566c80f28faf684597d1b6afb
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Fri Jan 22 16:14:53 2010 +0000
types: Move cairo_scaled_glyph_t to cairo-types-private.h
Another step in bringing some sanity to our headers.
diff --git a/src/cairo-types-private.h b/src/cairo-types-private.h
index ca41c1a..f3d14b3 100644
--- a/src/cairo-types-private.h
+++ b/src/cairo-types-private.h
@@ -396,4 +396,29 @@ typedef union {
cairo_gradient_pattern_union_t gradient;
} cairo_pattern_union_t;
+/*
+ * A #cairo_unscaled_font_t is just an opaque handle we use in the
+ * glyph cache.
+ */
+typedef struct _cairo_unscaled_font {
+ cairo_hash_entry_t hash_entry;
+ cairo_reference_count_t ref_count;
+ const cairo_unscaled_font_backend_t *backend;
+} cairo_unscaled_font_t;
+
+typedef struct _cairo_scaled_glyph {
+ cairo_hash_entry_t hash_entry;
+
+ cairo_text_extents_t metrics; /* user-space metrics */
+ cairo_text_extents_t fs_metrics; /* font-space metrics */
+ cairo_box_t bbox; /* device-space bounds */
+ int16_t x_advance; /* device-space rounded X advance */
+ int16_t y_advance; /* device-space rounded Y advance */
+
+ cairo_image_surface_t *surface; /* device-space image */
+ cairo_path_fixed_t *path; /* device-space outline */
+ cairo_surface_t *recording_surface; /* device-space recording-surface */
+
+ void *surface_private; /* for the surface backend */
+} cairo_scaled_glyph_t;
#endif /* CAIRO_TYPES_PRIVATE_H */
diff --git a/src/cairoint.h b/src/cairoint.h
index 99de262..8e7ac58 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -371,32 +371,6 @@ _cairo_hash_bytes (unsigned long hash,
const void *bytes,
unsigned int length);
-/*
- * A #cairo_unscaled_font_t is just an opaque handle we use in the
- * glyph cache.
- */
-typedef struct _cairo_unscaled_font {
- cairo_hash_entry_t hash_entry;
- cairo_reference_count_t ref_count;
- const cairo_unscaled_font_backend_t *backend;
-} cairo_unscaled_font_t;
-
-typedef struct _cairo_scaled_glyph {
- cairo_hash_entry_t hash_entry;
-
- cairo_text_extents_t metrics; /* user-space metrics */
- cairo_text_extents_t fs_metrics; /* font-space metrics */
- cairo_box_t bbox; /* device-space bounds */
- int16_t x_advance; /* device-space rounded X advance */
- int16_t y_advance; /* device-space rounded Y advance */
-
- cairo_image_surface_t *surface; /* device-space image */
- cairo_path_fixed_t *path; /* device-space outline */
- cairo_surface_t *recording_surface; /* device-space recording-surface */
-
- void *surface_private; /* for the surface backend */
-} cairo_scaled_glyph_t;
-
#define _cairo_scaled_glyph_index(g) ((g)->hash_entry.hash)
#define _cairo_scaled_glyph_set_index(g, i) ((g)->hash_entry.hash = (i))
commit 9c98656fb1ac10a6085c5db5731b6b986af26165
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Fri Jan 22 16:11:48 2010 +0000
color: Add enum value for the largest stock color.
Useful if we wish to keep a cache of patterns for the very common stock
colors...
diff --git a/src/cairo-color.c b/src/cairo-color.c
index 7640bf4..255bd36 100644
--- a/src/cairo-color.c
+++ b/src/cairo-color.c
@@ -67,13 +67,14 @@ _cairo_stock_color (cairo_stock_t stock)
return &cairo_color_black;
case CAIRO_STOCK_TRANSPARENT:
return &cairo_color_transparent;
- }
-
- ASSERT_NOT_REACHED;
- /* If the user can get here somehow, give a color that indicates a
- * problem. */
- return &cairo_color_magenta;
+ case CAIRO_STOCK_NUM_COLORS:
+ default:
+ ASSERT_NOT_REACHED;
+ /* If the user can get here somehow, give a color that indicates a
+ * problem. */
+ return &cairo_color_magenta;
+ }
}
void
diff --git a/src/cairo-types-private.h b/src/cairo-types-private.h
index 66370e3..ca41c1a 100644
--- a/src/cairo-types-private.h
+++ b/src/cairo-types-private.h
@@ -306,7 +306,8 @@ typedef struct _cairo_format_masks {
typedef enum {
CAIRO_STOCK_WHITE,
CAIRO_STOCK_BLACK,
- CAIRO_STOCK_TRANSPARENT
+ CAIRO_STOCK_TRANSPARENT,
+ CAIRO_STOCK_NUM_COLORS,
} cairo_stock_t;
typedef enum _cairo_image_transparency {
commit b7b65b5315836297f86c54121ea45e469f514312
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Fri Jan 22 16:07:25 2010 +0000
stroke: Convert rectilinear paths to boxes.
A quick and efficient method for extracting the set of boxes that
represent the path when stroked.
diff --git a/src/cairo-path-stroke.c b/src/cairo-path-stroke.c
index 264157f..f9d7de1 100644
--- a/src/cairo-path-stroke.c
+++ b/src/cairo-path-stroke.c
@@ -39,6 +39,7 @@
#define _BSD_SOURCE /* for hypot() */
#include "cairoint.h"
+#include "cairo-boxes-private.h"
#include "cairo-error-private.h"
#include "cairo-path-fixed-private.h"
#include "cairo-slope-private.h"
@@ -1419,7 +1420,8 @@ _cairo_path_fixed_stroke_to_traps (const cairo_path_fixed_t *path,
}
_cairo_polygon_init (&polygon);
- _cairo_polygon_limit (&polygon, traps->limits, traps->num_limits);
+ if (traps->num_limits)
+ _cairo_polygon_limit (&polygon, traps->limits, traps->num_limits);
status = _cairo_path_fixed_stroke_to_polygon (path,
stroke_style,
@@ -1454,7 +1456,8 @@ typedef struct _cairo_rectilinear_stroker {
const cairo_matrix_t *ctm;
cairo_fixed_t half_line_width;
- cairo_traps_t *traps;
+ cairo_bool_t do_traps;
+ void *container;
cairo_point_t current_point;
cairo_point_t first_point;
cairo_bool_t open_sub_path;
@@ -1485,18 +1488,47 @@ _cairo_rectilinear_stroker_limit (cairo_rectilinear_stroker_t *stroker,
stroker->bounds.p2.y += stroker->half_line_width;
}
-static void
+static cairo_bool_t
_cairo_rectilinear_stroker_init (cairo_rectilinear_stroker_t *stroker,
const cairo_stroke_style_t *stroke_style,
const cairo_matrix_t *ctm,
- cairo_traps_t *traps)
+ cairo_bool_t do_traps,
+ void *container)
{
+ /* This special-case rectilinear stroker only supports
+ * miter-joined lines (not curves) and a translation-only matrix
+ * (though it could probably be extended to support a matrix with
+ * uniform, integer scaling).
+ *
+ * It also only supports horizontal and vertical line_to
+ * elements. But we don't catch that here, but instead return
+ * UNSUPPORTED from _cairo_rectilinear_stroker_line_to if any
+ * non-rectilinear line_to is encountered.
+ */
+ if (stroke_style->line_join != CAIRO_LINE_JOIN_MITER)
+ return FALSE;
+
+ /* If the miter limit turns right angles into bevels, then we
+ * can't use this optimization. Remember, the ratio is
+ * 1/sin(ɸ/2). So the cutoff is 1/sin(Ï/4.0) or â·2,
+ * which we round for safety. */
+ if (stroke_style->miter_limit < M_SQRT2)
+ return FALSE;
+
+ if (! (stroke_style->line_cap == CAIRO_LINE_CAP_BUTT ||
+ stroke_style->line_cap == CAIRO_LINE_CAP_SQUARE))
+ {
+ return FALSE;
+ }
+
+ if (! _cairo_matrix_has_unity_scale (ctm))
+ return FALSE;
+
stroker->stroke_style = stroke_style;
stroker->ctm = ctm;
stroker->half_line_width =
_cairo_fixed_from_double (stroke_style->line_width / 2.0);
- stroker->traps = traps;
stroker->open_sub_path = FALSE;
stroker->segments = stroker->segments_embedded;
stroker->segments_size = ARRAY_LENGTH (stroker->segments_embedded);
@@ -1506,6 +1538,11 @@ _cairo_rectilinear_stroker_init (cairo_rectilinear_stroker_t *stroker,
_cairo_stroker_dash_init (&stroker->dash, stroke_style, ctm, _cairo_fixed_to_double (2 * CAIRO_FIXED_EPSILON));
stroker->has_bounds = FALSE;
+
+ stroker->do_traps = do_traps;
+ stroker->container = container;
+
+ return TRUE;
}
static void
@@ -1664,7 +1701,16 @@ _cairo_rectilinear_stroker_emit_segments (cairo_rectilinear_stroker_t *stroker)
b->x += half_line_width;
}
- status = _cairo_traps_tessellate_rectangle (stroker->traps, a, b);
+ if (stroker->do_traps) {
+ status = _cairo_traps_tessellate_rectangle (stroker->container, a, b);
+ } else {
+ cairo_box_t box;
+
+ box.p1 = *a;
+ box.p2 = *b;
+
+ status = _cairo_boxes_add (stroker->container, &box);
+ }
if (unlikely (status))
return status;
}
@@ -1730,8 +1776,16 @@ _cairo_rectilinear_stroker_emit_segments_dashed (cairo_rectilinear_stroker_t *st
p2.x += half_line_width;
}
- status = _cairo_traps_tessellate_rectangle (stroker->traps,
- &p1, &p2);
+ if (stroker->do_traps) {
+ status = _cairo_traps_tessellate_rectangle (stroker->container, &p1, &p2);
+ } else {
+ cairo_box_t box;
+
+ box.p1 = p1;
+ box.p2 = p2;
+
+ status = _cairo_boxes_add (stroker->container, &box);
+ }
if (unlikely (status))
return status;
}
@@ -1784,7 +1838,16 @@ _cairo_rectilinear_stroker_emit_segments_dashed (cairo_rectilinear_stroker_t *st
if (a->x == b->x && a->y == b->y)
continue;
- status = _cairo_traps_tessellate_rectangle (stroker->traps, a, b);
+ if (stroker->do_traps) {
+ status = _cairo_traps_tessellate_rectangle (stroker->container, a, b);
+ } else {
+ cairo_box_t box;
+
+ box.p1 = *a;
+ box.p2 = *b;
+
+ status = _cairo_boxes_add (stroker->container, &box);
+ }
if (unlikely (status))
return status;
}
@@ -1986,38 +2049,15 @@ _cairo_path_fixed_stroke_rectilinear_to_traps (const cairo_path_fixed_t *path,
cairo_rectilinear_stroker_t rectilinear_stroker;
cairo_int_status_t status;
- /* This special-case rectilinear stroker only supports
- * miter-joined lines (not curves) and a translation-only matrix
- * (though it could probably be extended to support a matrix with
- * uniform, integer scaling).
- *
- * It also only supports horizontal and vertical line_to
- * elements. But we don't catch that here, but instead return
- * UNSUPPORTED from _cairo_rectilinear_stroker_line_to if any
- * non-rectilinear line_to is encountered.
- */
assert (path->is_rectilinear);
- if (stroke_style->line_join != CAIRO_LINE_JOIN_MITER)
- return CAIRO_INT_STATUS_UNSUPPORTED;
- /* If the miter limit turns right angles into bevels, then we
- * can't use this optimization. Remember, the ratio is
- * 1/sin(ɸ/2). So the cutoff is 1/sin(Ï/4.0) or â·2,
- * which we round for safety. */
- if (stroke_style->miter_limit < M_SQRT2)
- return CAIRO_INT_STATUS_UNSUPPORTED;
- if (! (stroke_style->line_cap == CAIRO_LINE_CAP_BUTT ||
- stroke_style->line_cap == CAIRO_LINE_CAP_SQUARE))
+ if (! _cairo_rectilinear_stroker_init (&rectilinear_stroker,
+ stroke_style, ctm,
+ TRUE, traps))
{
return CAIRO_INT_STATUS_UNSUPPORTED;
}
- if (! _cairo_matrix_has_unity_scale (ctm))
- return CAIRO_INT_STATUS_UNSUPPORTED;
- _cairo_rectilinear_stroker_init (&rectilinear_stroker,
- stroke_style,
- ctm,
- traps);
if (traps->num_limits) {
_cairo_rectilinear_stroker_limit (&rectilinear_stroker,
traps->limits,
@@ -2053,3 +2093,63 @@ BAIL:
return status;
}
+
+cairo_int_status_t
+_cairo_path_fixed_stroke_rectilinear_to_boxes (const cairo_path_fixed_t *path,
+ const cairo_stroke_style_t *stroke_style,
+ const cairo_matrix_t *ctm,
+ cairo_boxes_t *boxes)
+{
+ cairo_rectilinear_stroker_t rectilinear_stroker;
+ cairo_int_status_t status;
+
+ assert (path->is_rectilinear);
+
+ if (! _cairo_rectilinear_stroker_init (&rectilinear_stroker,
+ stroke_style, ctm,
+ FALSE, boxes))
+ {
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ }
+
+ if (boxes->num_limits) {
+ _cairo_rectilinear_stroker_limit (&rectilinear_stroker,
+ boxes->limits,
+ boxes->num_limits);
+ }
+
+ status = _cairo_path_fixed_interpret (path,
+ CAIRO_DIRECTION_FORWARD,
+ _cairo_rectilinear_stroker_move_to,
+ rectilinear_stroker.dash.dashed ?
+ _cairo_rectilinear_stroker_line_to_dashed :
+ _cairo_rectilinear_stroker_line_to,
+ NULL,
+ _cairo_rectilinear_stroker_close_path,
+ &rectilinear_stroker);
+ if (unlikely (status))
+ goto BAIL;
+
+ if (rectilinear_stroker.dash.dashed)
+ status = _cairo_rectilinear_stroker_emit_segments_dashed (&rectilinear_stroker);
+ else
+ status = _cairo_rectilinear_stroker_emit_segments (&rectilinear_stroker);
+ if (unlikely (status))
+ goto BAIL;
+
+ /* As we incrementally tessellate, we do not eliminate self-intersections */
+ status = _cairo_bentley_ottmann_tessellate_boxes (boxes,
+ CAIRO_FILL_RULE_WINDING,
+ boxes);
+ if (unlikely (status))
+ goto BAIL;
+
+ _cairo_rectilinear_stroker_fini (&rectilinear_stroker);
+
+ return CAIRO_STATUS_SUCCESS;
+
+BAIL:
+ _cairo_rectilinear_stroker_fini (&rectilinear_stroker);
+ _cairo_boxes_clear (boxes);
+ return status;
+}
diff --git a/src/cairoint.h b/src/cairoint.h
index 4a8fe14..99de262 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -1591,6 +1591,13 @@ _cairo_path_fixed_stroke_rectilinear_to_traps (const cairo_path_fixed_t *path,
const cairo_stroke_style_t *stroke_style,
const cairo_matrix_t *ctm,
cairo_traps_t *traps);
+
+cairo_private cairo_int_status_t
+_cairo_path_fixed_stroke_rectilinear_to_boxes (const cairo_path_fixed_t *path,
+ const cairo_stroke_style_t *stroke_style,
+ const cairo_matrix_t *ctm,
+ cairo_boxes_t *boxes);
+
cairo_private cairo_status_t
_cairo_path_fixed_stroke_to_traps (const cairo_path_fixed_t *path,
const cairo_stroke_style_t *stroke_style,
commit fe6a7f4c9e69c86588eca4925a9d65f3086f98bf
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Fri Jan 22 16:02:07 2010 +0000
fill: Convert rectilinear paths to boxes.
A quick and efficient method for extracting the set of boxes that
represent the path when filled.
diff --git a/src/cairo-path-fill.c b/src/cairo-path-fill.c
index e3c9129..1218cc2 100644
--- a/src/cairo-path-fill.c
+++ b/src/cairo-path-fill.c
@@ -35,6 +35,7 @@
*/
#include "cairoint.h"
+#include "cairo-boxes-private.h"
#include "cairo-error-private.h"
#include "cairo-path-fixed-private.h"
#include "cairo-region-private.h"
@@ -142,7 +143,8 @@ _cairo_path_fixed_fill_to_traps (const cairo_path_fixed_t *path,
return CAIRO_STATUS_SUCCESS;
_cairo_polygon_init (&polygon);
- _cairo_polygon_limit (&polygon, traps->limits, traps->num_limits);
+ if (traps->num_limits)
+ _cairo_polygon_limit (&polygon, traps->limits, traps->num_limits);
status = _cairo_path_fixed_fill_to_polygon (path,
tolerance,
@@ -392,3 +394,75 @@ _cairo_path_fixed_fill_rectilinear_to_traps (const cairo_path_fixed_t *path,
return CAIRO_INT_STATUS_UNSUPPORTED;
}
}
+
+static cairo_status_t
+_cairo_path_fixed_fill_rectilinear_tessellate_to_boxes (const cairo_path_fixed_t *path,
+ cairo_fill_rule_t fill_rule,
+ cairo_boxes_t *boxes)
+{
+ cairo_polygon_t polygon;
+ cairo_status_t status;
+
+ _cairo_polygon_init (&polygon);
+ if (boxes->num_limits) {
+ _cairo_polygon_limit (&polygon, boxes->limits, boxes->num_limits);
+ boxes->num_limits = 0;
+ }
+
+ /* tolerance will be ignored as the path is rectilinear */
+ status = _cairo_path_fixed_fill_to_polygon (path, 0., &polygon);
+ if (likely (status == CAIRO_STATUS_SUCCESS)) {
+ status =
+ _cairo_bentley_ottmann_tessellate_rectilinear_polygon_to_boxes (&polygon,
+ fill_rule,
+ boxes);
+ }
+
+ _cairo_polygon_fini (&polygon);
+
+ return status;
+}
+
+cairo_status_t
+_cairo_path_fixed_fill_rectilinear_to_boxes (const cairo_path_fixed_t *path,
+ cairo_fill_rule_t fill_rule,
+ cairo_boxes_t *boxes)
+{
+ cairo_path_fixed_iter_t iter;
+ cairo_status_t status;
+ cairo_box_t box;
+
+ if (_cairo_path_fixed_is_box (path, &box))
+ return _cairo_boxes_add (boxes, &box);
+
+ _cairo_path_fixed_iter_init (&iter, path);
+ while (_cairo_path_fixed_iter_is_fill_box (&iter, &box)) {
+ if (box.p1.y == box.p2.y || box.p1.x == box.p2.x)
+ continue;
+
+ if (box.p1.y > box.p2.y) {
+ cairo_fixed_t t;
+
+ t = box.p1.y;
+ box.p1.y = box.p2.y;
+ box.p2.y = t;
+
+ t = box.p1.x;
+ box.p1.x = box.p2.x;
+ box.p2.x = t;
+ }
+
+ status = _cairo_boxes_add (boxes, &box);
+ if (unlikely (status))
+ return status;
+ }
+
+ if (_cairo_path_fixed_iter_at_end (&iter))
+ return _cairo_bentley_ottmann_tessellate_boxes (boxes, fill_rule, boxes);
+
+ /* path is not rectangular, try extracting clipped rectilinear edges */
+ _cairo_boxes_clear (boxes);
+ return _cairo_path_fixed_fill_rectilinear_tessellate_to_boxes (path,
+ fill_rule,
+ boxes);
+}
diff --git a/src/cairoint.h b/src/cairoint.h
index f4be2f5..4a8fe14 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -1561,6 +1561,11 @@ _cairo_path_fixed_fill_rectilinear_to_traps (const cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
cairo_traps_t *traps);
+cairo_private cairo_status_t
+_cairo_path_fixed_fill_rectilinear_to_boxes (const cairo_path_fixed_t *path,
+ cairo_fill_rule_t fill_rule,
+ cairo_boxes_t *boxes);
+
cairo_private cairo_region_t *
_cairo_path_fixed_fill_rectilinear_to_region (const cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
commit 6b77567b6ef28710c7707ab82c7fa95c810152d1
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Fri Jan 22 15:54:45 2010 +0000
path: Compute coarse bounds upon construction.
Frequently we only need the coarse path bounds, so avoid walking over
the list of points once more as we can cheaply track the extents during
construction.
diff --git a/src/cairo-debug.c b/src/cairo-debug.c
index 9160728..e364069 100644
--- a/src/cairo-debug.c
+++ b/src/cairo-debug.c
@@ -221,6 +221,12 @@ _cairo_debug_print_path (FILE *stream, cairo_path_fixed_t *path)
{
cairo_status_t status;
+ printf ("path: extents=(%f, %f), (%f, %f)\n",
+ _cairo_fixed_to_double (path->extents.p1.x),
+ _cairo_fixed_to_double (path->extents.p1.y),
+ _cairo_fixed_to_double (path->extents.p2.x),
+ _cairo_fixed_to_double (path->extents.p2.y));
+
status = _cairo_path_fixed_interpret (path,
CAIRO_DIRECTION_FORWARD,
_print_move_to,
diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c
index a834447..8bb7e71 100644
--- a/src/cairo-gstate.c
+++ b/src/cairo-gstate.c
@@ -806,14 +806,25 @@ _cairo_gstate_path_extents (cairo_gstate_t *gstate,
double *x1, double *y1,
double *x2, double *y2)
{
+ cairo_box_t box;
double px1, py1, px2, py2;
- _cairo_path_fixed_bounds (path,
- &px1, &py1, &px2, &py2);
+ if (_cairo_path_fixed_extents (path, &box)) {
+ px1 = _cairo_fixed_to_double (box.p1.x);
+ py1 = _cairo_fixed_to_double (box.p1.y);
+ px2 = _cairo_fixed_to_double (box.p2.x);
+ py2 = _cairo_fixed_to_double (box.p2.y);
+
+ _cairo_gstate_backend_to_user_rectangle (gstate,
+ &px1, &py1, &px2, &py2,
+ NULL);
+ } else {
+ px1 = 0.0;
+ py1 = 0.0;
+ px2 = 0.0;
+ py2 = 0.0;
+ }
- _cairo_gstate_backend_to_user_rectangle (gstate,
- &px1, &py1, &px2, &py2,
- NULL);
if (x1)
*x1 = px1;
if (y1)
diff --git a/src/cairo-path-bounds.c b/src/cairo-path-bounds.c
index 7b7ae68..8f9bdc3 100644
--- a/src/cairo-path-bounds.c
+++ b/src/cairo-path-bounds.c
@@ -35,6 +35,7 @@
*/
#include "cairoint.h"
+#include "cairo-path-fixed-private.h"
typedef struct cairo_path_bounder {
cairo_point_t current_point;
@@ -135,26 +136,6 @@ _cairo_path_bounder_curve_to (void *closure,
}
static cairo_status_t
-_cairo_path_bounder_curve_to_cp (void *closure,
- const cairo_point_t *b,
- const cairo_point_t *c,
- const cairo_point_t *d)
-{
- cairo_path_bounder_t *bounder = closure;
-
- if (bounder->has_initial_point) {
- _cairo_path_bounder_add_point (bounder, &bounder->current_point);
- bounder->has_initial_point = FALSE;
- }
-
- _cairo_path_bounder_add_point (bounder, b);
- _cairo_path_bounder_add_point (bounder, c);
- _cairo_path_bounder_add_point (bounder, d);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
_cairo_path_bounder_close_path (void *closure)
{
return CAIRO_STATUS_SUCCESS;
@@ -168,21 +149,8 @@ void
_cairo_path_fixed_approximate_clip_extents (const cairo_path_fixed_t *path,
cairo_rectangle_int_t *extents)
{
- cairo_path_bounder_t bounder;
- cairo_status_t status;
-
- _cairo_path_bounder_init (&bounder);
-
- status = _cairo_path_fixed_interpret (path, CAIRO_DIRECTION_FORWARD,
- _cairo_path_bounder_move_to,
- _cairo_path_bounder_line_to,
- _cairo_path_bounder_curve_to_cp,
- _cairo_path_bounder_close_path,
- &bounder);
- assert (status == CAIRO_STATUS_SUCCESS);
-
- if (bounder.has_point) {
- _cairo_box_round_to_rectangle (&bounder.extents, extents);
+ if (path->extents.p1.x < path->extents.p2.x) {
+ _cairo_box_round_to_rectangle (&path->extents, extents);
} else {
extents->x = extents->y = 0;
extents->width = extents->height = 0;
@@ -199,15 +167,20 @@ _cairo_path_fixed_approximate_fill_extents (const cairo_path_fixed_t *path,
cairo_path_bounder_t bounder;
cairo_status_t status;
- _cairo_path_bounder_init (&bounder);
-
- status = _cairo_path_fixed_interpret (path, CAIRO_DIRECTION_FORWARD,
- _cairo_path_bounder_move_to,
- _cairo_path_bounder_line_to,
- _cairo_path_bounder_curve_to,
- _cairo_path_bounder_close_path,
- &bounder);
- assert (status == CAIRO_STATUS_SUCCESS);
+ if (! path->has_curve_to) {
+ bounder.extents = path->extents;
+ bounder.has_point = path->extents.p1.x < path->extents.p2.x;
+ } else {
+ _cairo_path_bounder_init (&bounder);
+
+ status = _cairo_path_fixed_interpret (path, CAIRO_DIRECTION_FORWARD,
+ _cairo_path_bounder_move_to,
+ _cairo_path_bounder_line_to,
+ _cairo_path_bounder_curve_to,
+ _cairo_path_bounder_close_path,
+ &bounder);
+ assert (status == CAIRO_STATUS_SUCCESS);
+ }
if (bounder.has_point) {
_cairo_box_round_to_rectangle (&bounder.extents, extents);
@@ -226,14 +199,19 @@ _cairo_path_fixed_fill_extents (const cairo_path_fixed_t *path,
cairo_path_bounder_t bounder;
cairo_status_t status;
- _cairo_path_bounder_init (&bounder);
-
- status = _cairo_path_fixed_interpret_flat (path, CAIRO_DIRECTION_FORWARD,
- _cairo_path_bounder_move_to,
- _cairo_path_bounder_line_to,
- _cairo_path_bounder_close_path,
- &bounder, tolerance);
- assert (status == CAIRO_STATUS_SUCCESS);
+ if (! path->has_curve_to) {
+ bounder.extents = path->extents;
+ bounder.has_point = path->extents.p1.x < path->extents.p2.x;
+ } else {
+ _cairo_path_bounder_init (&bounder);
+
+ status = _cairo_path_fixed_interpret_flat (path, CAIRO_DIRECTION_FORWARD,
+ _cairo_path_bounder_move_to,
+ _cairo_path_bounder_line_to,
+ _cairo_path_bounder_close_path,
+ &bounder, tolerance);
+ assert (status == CAIRO_STATUS_SUCCESS);
+ }
if (bounder.has_point) {
_cairo_box_round_to_rectangle (&bounder.extents, extents);
@@ -247,21 +225,43 @@ _cairo_path_fixed_fill_extents (const cairo_path_fixed_t *path,
void
_cairo_path_fixed_approximate_stroke_extents (const cairo_path_fixed_t *path,
const cairo_stroke_style_t *style,
- const const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm,
cairo_rectangle_int_t *extents)
{
cairo_path_bounder_t bounder;
cairo_status_t status;
- _cairo_path_bounder_init (&bounder);
+ if (! path->has_curve_to) {
+ bounder.extents = path->extents;
- status = _cairo_path_fixed_interpret (path, CAIRO_DIRECTION_FORWARD,
- _cairo_path_bounder_move_to,
- _cairo_path_bounder_line_to,
- _cairo_path_bounder_curve_to,
- _cairo_path_bounder_close_path,
- &bounder);
- assert (status == CAIRO_STATUS_SUCCESS);
+ /* include trailing move-to for degenerate segments */
+ if (path->has_last_move_point) {
+ const cairo_point_t *point = &path->last_move_point;
+
+ if (point->x < bounder.extents.p1.x)
+ bounder.extents.p1.x = point->x;
+ if (point->y < bounder.extents.p1.y)
+ bounder.extents.p1.y = point->y;
+
+ if (point->x > bounder.extents.p2.x)
+ bounder.extents.p2.x = point->x;
+ if (point->y > bounder.extents.p2.y)
+ bounder.extents.p2.y = point->y;
+ }
+
+ bounder.has_point = bounder.extents.p1.x <= bounder.extents.p2.x;
+ bounder.has_initial_point = FALSE;
+ } else {
+ _cairo_path_bounder_init (&bounder);
+
+ status = _cairo_path_fixed_interpret (path, CAIRO_DIRECTION_FORWARD,
+ _cairo_path_bounder_move_to,
+ _cairo_path_bounder_line_to,
+ _cairo_path_bounder_curve_to,
+ _cairo_path_bounder_close_path,
+ &bounder);
+ assert (status == CAIRO_STATUS_SUCCESS);
+ }
if (bounder.has_point) {
double dx, dy;
@@ -294,12 +294,12 @@ _cairo_path_fixed_approximate_stroke_extents (const cairo_path_fixed_t *path,
}
cairo_status_t
-_cairo_path_fixed_stroke_extents (const cairo_path_fixed_t *path,
- const cairo_stroke_style_t *stroke_style,
- const cairo_matrix_t *ctm,
- const cairo_matrix_t *ctm_inverse,
- double tolerance,
- cairo_rectangle_int_t *extents)
+_cairo_path_fixed_stroke_extents (const cairo_path_fixed_t *path,
+ const cairo_stroke_style_t *stroke_style,
+ const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm_inverse,
+ double tolerance,
+ cairo_rectangle_int_t *extents)
{
cairo_traps_t traps;
cairo_box_t bbox;
@@ -322,14 +322,18 @@ _cairo_path_fixed_stroke_extents (const cairo_path_fixed_t *path,
return status;
}
-void
-_cairo_path_fixed_bounds (const cairo_path_fixed_t *path,
- double *x1, double *y1,
- double *x2, double *y2)
+cairo_bool_t
+_cairo_path_fixed_extents (const cairo_path_fixed_t *path,
+ cairo_box_t *box)
{
cairo_path_bounder_t bounder;
cairo_status_t status;
+ if (! path->has_curve_to) {
+ *box = path->extents;
+ return path->extents.p1.x < path->extents.p2.x;
+ }
+
_cairo_path_bounder_init (&bounder);
status = _cairo_path_fixed_interpret (path, CAIRO_DIRECTION_FORWARD,
@@ -340,15 +344,6 @@ _cairo_path_fixed_bounds (const cairo_path_fixed_t *path,
&bounder);
assert (status == CAIRO_STATUS_SUCCESS);
- if (bounder.has_point) {
- *x1 = _cairo_fixed_to_double (bounder.extents.p1.x);
- *y1 = _cairo_fixed_to_double (bounder.extents.p1.y);
- *x2 = _cairo_fixed_to_double (bounder.extents.p2.x);
- *y2 = _cairo_fixed_to_double (bounder.extents.p2.y);
- } else {
- *x1 = 0.0;
- *y1 = 0.0;
- *x2 = 0.0;
- *y2 = 0.0;
- }
+ *box = bounder.extents;
+ return bounder.has_point;
}
diff --git a/src/cairo-path-fixed-private.h b/src/cairo-path-fixed-private.h
index 08b7a06..601d214 100644
--- a/src/cairo-path-fixed-private.h
+++ b/src/cairo-path-fixed-private.h
@@ -80,15 +80,17 @@ struct _cairo_path_fixed {
cairo_point_t last_move_point;
cairo_point_t current_point;
unsigned int has_current_point : 1;
+ unsigned int has_last_move_point : 1;
unsigned int has_curve_to : 1;
unsigned int is_rectilinear : 1;
unsigned int maybe_fill_region : 1;
unsigned int is_empty_fill : 1;
+ cairo_box_t extents;
+
cairo_path_buf_fixed_t buf;
};
-
cairo_private void
_cairo_path_fixed_translate (cairo_path_fixed_t *path,
cairo_fixed_t offx,
diff --git a/src/cairo-path-fixed.c b/src/cairo-path-fixed.c
index 958c85c..be071d1 100644
--- a/src/cairo-path-fixed.c
+++ b/src/cairo-path-fixed.c
@@ -96,11 +96,15 @@ _cairo_path_fixed_init (cairo_path_fixed_t *path)
path->current_point.x = 0;
path->current_point.y = 0;
path->last_move_point = path->current_point;
+ path->has_last_move_point = FALSE;
path->has_current_point = FALSE;
path->has_curve_to = FALSE;
path->is_rectilinear = TRUE;
path->maybe_fill_region = TRUE;
path->is_empty_fill = TRUE;
+
+ path->extents.p1.x = path->extents.p1.y = INT_MAX;
+ path->extents.p2.x = path->extents.p2.y = INT_MIN;
}
cairo_status_t
@@ -119,12 +123,15 @@ _cairo_path_fixed_init_copy (cairo_path_fixed_t *path,
path->current_point = other->current_point;
path->last_move_point = other->last_move_point;
+ path->has_last_move_point = other->has_last_move_point;
path->has_current_point = other->has_current_point;
path->has_curve_to = other->has_curve_to;
path->is_rectilinear = other->is_rectilinear;
path->maybe_fill_region = other->maybe_fill_region;
path->is_empty_fill = other->is_empty_fill;
+ path->extents = other->extents;
+
path->buf.base.num_ops = other->buf.base.num_ops;
path->buf.base.num_points = other->buf.base.num_points;
path->buf.base.buf_size = other->buf.base.buf_size;
@@ -176,6 +183,8 @@ _cairo_path_fixed_hash (const cairo_path_fixed_t *path)
const cairo_path_buf_t *buf;
int num_points, num_ops;
+ hash = _cairo_hash_bytes (hash, &path->extents, sizeof (path->extents));
+
num_ops = num_points = 0;
cairo_path_foreach_buf_start (buf, path) {
hash = _cairo_hash_bytes (hash, buf->op,
@@ -231,6 +240,14 @@ _cairo_path_fixed_equal (const cairo_path_fixed_t *a,
return FALSE;
}
+ if (a->extents.p1.x != b->extents.p1.x ||
+ a->extents.p1.y != b->extents.p1.y ||
+ a->extents.p2.x != b->extents.p2.x ||
+ a->extents.p2.y != b->extents.p2.y)
+ {
+ return FALSE;
+ }
+
num_ops_a = num_points_a = 0;
if (a != NULL) {
cairo_path_foreach_buf_start (buf_a, a) {
@@ -365,6 +382,21 @@ _cairo_path_last_op (cairo_path_fixed_t *path)
return buf->op[buf->num_ops - 1];
}
+static inline void
+_cairo_path_fixed_extents_add (cairo_path_fixed_t *path,
+ const cairo_point_t *point)
+{
+ if (point->x < path->extents.p1.x)
+ path->extents.p1.x = point->x;
+ if (point->y < path->extents.p1.y)
+ path->extents.p1.y = point->y;
+
+ if (point->x > path->extents.p2.x)
+ path->extents.p2.x = point->x;
+ if (point->y > path->extents.p2.y)
+ path->extents.p2.y = point->y;
+}
+
cairo_status_t
_cairo_path_fixed_move_to (cairo_path_fixed_t *path,
cairo_fixed_t x,
@@ -403,6 +435,7 @@ _cairo_path_fixed_move_to (cairo_path_fixed_t *path,
path->current_point = point;
path->last_move_point = point;
+ path->has_last_move_point = TRUE;
path->has_current_point = TRUE;
return CAIRO_STATUS_SUCCESS;
@@ -511,6 +544,11 @@ _cairo_path_fixed_line_to (cairo_path_fixed_t *path,
}
path->current_point = point;
+ if (path->has_last_move_point) {
+ _cairo_path_fixed_extents_add (path, &path->last_move_point);
+ path->has_last_move_point = FALSE;
+ }
+ _cairo_path_fixed_extents_add (path, &point);
return CAIRO_STATUS_SUCCESS;
}
@@ -557,6 +595,15 @@ _cairo_path_fixed_curve_to (cairo_path_fixed_t *path,
path->is_rectilinear = FALSE;
path->maybe_fill_region = FALSE;
+ /* coarse bounds */
+ if (path->has_last_move_point) {
+ _cairo_path_fixed_extents_add (path, &path->last_move_point);
+ path->has_last_move_point = FALSE;
+ }
+ _cairo_path_fixed_extents_add (path, &point[0]);
+ _cairo_path_fixed_extents_add (path, &point[1]);
+ _cairo_path_fixed_extents_add (path, &point[2]);
+
return CAIRO_STATUS_SUCCESS;
}
@@ -907,6 +954,12 @@ _cairo_path_fixed_offset_and_scale (cairo_path_fixed_t *path,
buf->points[i].y += offy;
}
} cairo_path_foreach_buf_end (buf, path);
+
+ path->extents.p1.x = _cairo_fixed_mul (scalex, path->extents.p1.x) + offx;
+ path->extents.p2.x = _cairo_fixed_mul (scalex, path->extents.p2.x) + offx;
+
+ path->extents.p1.y = _cairo_fixed_mul (scaley, path->extents.p1.y) + offy;
+ path->extents.p2.y = _cairo_fixed_mul (scaley, path->extents.p2.y) + offy;
}
void
@@ -927,9 +980,9 @@ _cairo_path_fixed_translate (cairo_path_fixed_t *path,
}
path->last_move_point.x += offx;
- path->last_move_point.y += offx;
+ path->last_move_point.y += offy;
path->current_point.x += offx;
- path->current_point.y += offx;
+ path->current_point.y += offy;
cairo_path_foreach_buf_start (buf, path) {
for (i = 0; i < buf->num_points; i++) {
@@ -937,6 +990,11 @@ _cairo_path_fixed_translate (cairo_path_fixed_t *path,
buf->points[i].y += offy;
}
} cairo_path_foreach_buf_end (buf, path);
+
+ path->extents.p1.x += offx;
+ path->extents.p1.y += offy;
+ path->extents.p2.x += offx;
+ path->extents.p2.y += offy;
}
/**
@@ -960,14 +1018,22 @@ _cairo_path_fixed_transform (cairo_path_fixed_t *path,
if (matrix->yx == 0.0 && matrix->xy == 0.0) {
/* Fast path for the common case of scale+transform */
- _cairo_path_fixed_offset_and_scale (path,
- _cairo_fixed_from_double (matrix->x0),
- _cairo_fixed_from_double (matrix->y0),
- _cairo_fixed_from_double (matrix->xx),
- _cairo_fixed_from_double (matrix->yy));
+ if (matrix->xx == 1. && matrix->yy == 1.) {
+ _cairo_path_fixed_translate (path,
+ _cairo_fixed_from_double (matrix->x0),
+ _cairo_fixed_from_double (matrix->y0));
+ } else {
+ _cairo_path_fixed_offset_and_scale (path,
+ _cairo_fixed_from_double (matrix->x0),
+ _cairo_fixed_from_double (matrix->y0),
+ _cairo_fixed_from_double (matrix->xx),
+ _cairo_fixed_from_double (matrix->yy));
+ }
return;
}
+ path->extents.p1.x = path->extents.p1.y = INT_MAX;
+ path->extents.p2.x = path->extents.p2.y = INT_MIN;
path->maybe_fill_region = FALSE;
cairo_path_foreach_buf_start (buf, path) {
for (i = 0; i < buf->num_points; i++) {
@@ -978,6 +1044,9 @@ _cairo_path_fixed_transform (cairo_path_fixed_t *path,
buf->points[i].x = _cairo_fixed_from_double (dx);
buf->points[i].y = _cairo_fixed_from_double (dy);
+
+ /* XXX need to eliminate surplus move-to's? */
+ _cairo_path_fixed_extents_add (path, &buf->points[i]);
}
} cairo_path_foreach_buf_end (buf, path);
}
diff --git a/src/cairo.c b/src/cairo.c
index 4be3e44..3cb9b36 100644
--- a/src/cairo.c
+++ b/src/cairo.c
@@ -60,10 +60,12 @@ static const cairo_t _cairo_nil = {
{ 0, 0 }, /* last_move_point */
{ 0, 0 }, /* current point */
FALSE, /* has_current_point */
+ FALSE, /* has_last_move_point */
FALSE, /* has_curve_to */
FALSE, /* is_box */
FALSE, /* maybe_fill_region */
TRUE, /* is_empty_fill */
+ { {0, 0}, {0, 0}}, /* extents */
{{{NULL,NULL}}} /* link */
}}
};
diff --git a/src/cairoint.h b/src/cairoint.h
index 364edf5..f4be2f5 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -1498,6 +1498,10 @@ _cairo_path_fixed_interpret_flat (const cairo_path_fixed_t *path,
void *closure,
double tolerance);
+cairo_private cairo_bool_t
+_cairo_path_fixed_extents (const cairo_path_fixed_t *path,
+ cairo_box_t *box);
+
cairo_private void
_cairo_path_fixed_approximate_clip_extents (const cairo_path_fixed_t *path,
cairo_rectangle_int_t *extents);
@@ -1527,11 +1531,6 @@ _cairo_path_fixed_stroke_extents (const cairo_path_fixed_t *path,
cairo_rectangle_int_t *extents);
cairo_private void
-_cairo_path_fixed_bounds (const cairo_path_fixed_t *path,
- double *x1, double *y1,
- double *x2, double *y2);
-
-cairo_private void
_cairo_path_fixed_transform (cairo_path_fixed_t *path,
const cairo_matrix_t *matrix);
commit 6bfcf3ea55964fee1c9b73818c3bb7cdacbc4f82
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Fri Jan 22 15:37:25 2010 +0000
matrix: Do not need to iteratively refine conversion for unity matrices.
If the scale factors on the matrix are unity, then the conversion from a
cairo_matrix_t to a pixman_matrix_t is exact (within numerical
restrictions).
diff --git a/src/cairo-matrix.c b/src/cairo-matrix.c
index 75f091b..c107554 100644
--- a/src/cairo-matrix.c
+++ b/src/cairo-matrix.c
@@ -915,7 +915,7 @@ _cairo_matrix_to_pixman_matrix (const cairo_matrix_t *matrix,
* that point.
*/
- if (_cairo_matrix_is_translation (matrix))
+ if (_cairo_matrix_has_unity_scale (matrix))
return;
/* Note: If we can't invert the transformation, skip the adjustment. */
commit 13c56800ca6c32a6d8251edec5d3976399b70ea4
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Fri Jan 22 16:33:34 2010 +0000
gstate: Reduce operators
Some operators may be equivalent to simpler operations, so make the
transformation in the gstate, before calling down into the surface
backends.
diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c
index 52bf271..a834447 100644
--- a/src/cairo-gstate.c
+++ b/src/cairo-gstate.c
@@ -975,6 +975,31 @@ _clipped (cairo_gstate_t *gstate)
return _cairo_clip_get_region (&gstate->clip, NULL) == CAIRO_INT_STATUS_NOTHING_TO_DO;
}
+static cairo_operator_t
+_reduce_op (cairo_gstate_t *gstate,
+ const cairo_pattern_union_t *pattern)
+{
+ cairo_operator_t op;
+
+ op = gstate->op;
+ if (op == CAIRO_OPERATOR_SOURCE &&
+ pattern->type == CAIRO_PATTERN_TYPE_SOLID)
+ {
+ if (pattern->solid.color.alpha_short <= 0x00ff) {
+ op = CAIRO_OPERATOR_CLEAR;
+ } else if ((gstate->target->content & CAIRO_CONTENT_ALPHA) == 0) {
+ if ((pattern->solid.color.red_short |
+ pattern->solid.color.green_short |
+ pattern->solid.color.blue_short) <= 0x00ff)
+ {
+ op = CAIRO_OPERATOR_CLEAR;
+ }
+ }
+ }
+
+ return op;
+}
+
cairo_status_t
_cairo_gstate_paint (cairo_gstate_t *gstate)
{
@@ -985,13 +1010,16 @@ _cairo_gstate_paint (cairo_gstate_t *gstate)
if (unlikely (gstate->source->status))
return gstate->source->status;
+ if (gstate->op == CAIRO_OPERATOR_DEST)
+ return CAIRO_STATUS_SUCCESS;
+
if (_clipped (gstate))
return CAIRO_STATUS_SUCCESS;
_cairo_gstate_copy_transformed_source (gstate, &pattern.base);
status = _cairo_surface_paint (gstate->target,
- gstate->op,
+ _reduce_op (gstate, &pattern),
&pattern.base,
_gstate_get_clip (gstate, &clip));
_cairo_clip_fini (&clip);
@@ -1013,6 +1041,9 @@ _cairo_gstate_mask (cairo_gstate_t *gstate,
if (unlikely (gstate->source->status))
return gstate->source->status;
+ if (gstate->op == CAIRO_OPERATOR_DEST)
+ return CAIRO_STATUS_SUCCESS;
+
if (_clipped (gstate))
return CAIRO_STATUS_SUCCESS;
@@ -1050,14 +1081,14 @@ _cairo_gstate_mask (cairo_gstate_t *gstate,
mask_pattern.solid.content);
status = _cairo_surface_paint (gstate->target,
- gstate->op,
+ _reduce_op (gstate, &source_pattern),
&source_pattern.base,
_gstate_get_clip (gstate, &clip));
}
else
{
status = _cairo_surface_mask (gstate->target,
- gstate->op,
+ _reduce_op (gstate, &source_pattern),
&source_pattern.base,
&mask_pattern.base,
_gstate_get_clip (gstate, &clip));
@@ -1077,6 +1108,9 @@ _cairo_gstate_stroke (cairo_gstate_t *gstate, cairo_path_fixed_t *path)
if (unlikely (gstate->source->status))
return gstate->source->status;
+ if (gstate->op == CAIRO_OPERATOR_DEST)
+ return CAIRO_STATUS_SUCCESS;
+
if (gstate->stroke_style.line_width <= 0.0)
return CAIRO_STATUS_SUCCESS;
@@ -1086,7 +1120,7 @@ _cairo_gstate_stroke (cairo_gstate_t *gstate, cairo_path_fixed_t *path)
_cairo_gstate_copy_transformed_source (gstate, &source_pattern.base);
status = _cairo_surface_stroke (gstate->target,
- gstate->op,
+ _reduce_op (gstate, &source_pattern),
&source_pattern.base,
path,
&gstate->stroke_style,
@@ -1167,6 +1201,9 @@ _cairo_gstate_fill (cairo_gstate_t *gstate, cairo_path_fixed_t *path)
if (unlikely (gstate->source->status))
return gstate->source->status;
+ if (gstate->op == CAIRO_OPERATOR_DEST)
+ return CAIRO_STATUS_SUCCESS;
+
if (_clipped (gstate))
return CAIRO_STATUS_SUCCESS;
@@ -1180,16 +1217,34 @@ _cairo_gstate_fill (cairo_gstate_t *gstate, cairo_path_fixed_t *path)
_gstate_get_clip (gstate, &clip));
} else {
cairo_pattern_union_t pattern;
+ cairo_operator_t op;
+ cairo_rectangle_int_t extents;
+ cairo_box_t box;
_cairo_gstate_copy_transformed_source (gstate, &pattern.base);
- status = _cairo_surface_fill (gstate->target,
- gstate->op,
- &pattern.base,
- path,
- gstate->fill_rule,
- gstate->tolerance,
- gstate->antialias,
- _gstate_get_clip (gstate, &clip));
+
+ op = _reduce_op (gstate, &pattern);
+
+ /* Toolkits often paint the entire background with a fill */
+ if (_cairo_surface_get_extents (gstate->target, &extents) &&
+ _cairo_path_fixed_is_box (path, &box) &&
+ box.p1.x <= _cairo_fixed_from_int (extents.x) &&
+ box.p1.y <= _cairo_fixed_from_int (extents.y) &&
+ box.p2.x >= _cairo_fixed_from_int (extents.x + extents.width) &&
+ box.p2.y >= _cairo_fixed_from_int (extents.y + extents.height))
+ {
+ status = _cairo_surface_paint (gstate->target, op, &pattern.base,
+ _gstate_get_clip (gstate, &clip));
+ }
+ else
+ {
+ status = _cairo_surface_fill (gstate->target, op, &pattern.base,
+ path,
+ gstate->fill_rule,
+ gstate->tolerance,
+ gstate->antialias,
+ _gstate_get_clip (gstate, &clip));
+ }
}
_cairo_clip_fini (&clip);
@@ -1794,6 +1849,9 @@ _cairo_gstate_show_text_glyphs (cairo_gstate_t *gstate,
if (unlikely (gstate->source->status))
return gstate->source->status;
+ if (gstate->op == CAIRO_OPERATOR_DEST)
+ return CAIRO_STATUS_SUCCESS;
+
if (_clipped (gstate))
return CAIRO_STATUS_SUCCESS;
@@ -1852,7 +1910,7 @@ _cairo_gstate_show_text_glyphs (cairo_gstate_t *gstate,
_cairo_scaled_font_get_max_scale (gstate->scaled_font) <= 10240)
{
status = _cairo_surface_show_text_glyphs (gstate->target,
- gstate->op,
+ _reduce_op (gstate, &source_pattern),
&source_pattern.base,
utf8, utf8_len,
transformed_glyphs, num_glyphs,
@@ -1873,7 +1931,7 @@ _cairo_gstate_show_text_glyphs (cairo_gstate_t *gstate,
if (status == CAIRO_STATUS_SUCCESS) {
status = _cairo_surface_fill (gstate->target,
- gstate->op,
+ _reduce_op (gstate, &source_pattern),
&source_pattern.base,
&path,
CAIRO_FILL_RULE_WINDING,
commit 4d52be39bf36a3557f4e7c61dba764b1c6542c8f
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Fri Jan 22 16:09:11 2010 +0000
gstate: Skip ops with a clear mask.
As pointed out by Benjamin Otte, these are expensive no-ops that we can
trivially detect, just so long as we remember the semantics of extend
modes.
diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c
index 9f0e603..52bf271 100644
--- a/src/cairo-gstate.c
+++ b/src/cairo-gstate.c
@@ -1019,6 +1019,12 @@ _cairo_gstate_mask (cairo_gstate_t *gstate,
if (_cairo_pattern_is_opaque (mask, NULL))
return _cairo_gstate_paint (gstate);
+ if (_cairo_pattern_is_clear (mask) &&
+ _cairo_operator_bounded_by_mask (gstate->op))
+ {
+ return CAIRO_STATUS_SUCCESS;
+ }
+
_cairo_gstate_copy_transformed_source (gstate, &source_pattern.base);
_cairo_gstate_copy_transformed_mask (gstate, &mask_pattern.base, mask);
diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c
index 5d4ceb7..e77f153 100644
--- a/src/cairo-pattern.c
+++ b/src/cairo-pattern.c
@@ -1835,6 +1835,29 @@ _cairo_pattern_is_opaque (const cairo_pattern_t *abstract_pattern,
return FALSE;
}
+cairo_bool_t
+_cairo_pattern_is_clear (const cairo_pattern_t *abstract_pattern)
+{
+ const cairo_pattern_union_t *pattern;
+
+ if (abstract_pattern->has_component_alpha)
+ return FALSE;
+
+ pattern = (cairo_pattern_union_t *) abstract_pattern;
+ switch (pattern->type) {
+ case CAIRO_PATTERN_TYPE_SOLID:
+ return pattern->solid.color.alpha_short == 0x0000;
+ case CAIRO_PATTERN_TYPE_SURFACE:
+ return pattern->surface.surface->is_clear &&
+ pattern->surface.surface->content & CAIRO_CONTENT_ALPHA;
+ default:
+ ASSERT_NOT_REACHED;
+ case CAIRO_PATTERN_TYPE_LINEAR:
+ case CAIRO_PATTERN_TYPE_RADIAL:
+ return FALSE;
+ }
+}
+
/**
* _cairo_pattern_analyze_filter:
* @pattern: surface pattern
diff --git a/src/cairoint.h b/src/cairoint.h
index 401fac6..364edf5 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -2531,6 +2531,9 @@ cairo_private cairo_bool_t
_cairo_pattern_is_opaque (const cairo_pattern_t *pattern,
const cairo_rectangle_int_t *extents);
+cairo_private cairo_bool_t
+_cairo_pattern_is_clear (const cairo_pattern_t *pattern);
+
enum {
CAIRO_PATTERN_ACQUIRE_NONE = 0x0,
CAIRO_PATTERN_ACQUIRE_NO_REFLECT = 0x1,
commit c2ef45226d6801acb15854de55a5f5bc728ed65d
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Fri Jan 22 14:33:53 2010 +0000
gstate: Check for an invalid matrix before cairo_transform()
Similar to the other checks that will generate an invalid matrix prior
to performing the operation.
diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c
index 7b31807..9f0e603 100644
--- a/src/cairo-gstate.c
+++ b/src/cairo-gstate.c
@@ -677,6 +677,9 @@ _cairo_gstate_transform (cairo_gstate_t *gstate,
cairo_matrix_t tmp;
cairo_status_t status;
+ if (! _cairo_matrix_is_invertible (matrix))
+ return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
+
if (_cairo_matrix_is_identity (matrix))
return CAIRO_STATUS_SUCCESS;
commit 22316a0c17cd3b49ec625814f4e737b3fdc6ca63
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Fri Jan 22 14:33:16 2010 +0000
gstate: White space.
A couple of minor coding style violations.
diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c
index 0d5bedb..7b31807 100644
--- a/src/cairo-gstate.c
+++ b/src/cairo-gstate.c
@@ -532,6 +532,7 @@ _cairo_gstate_set_dash (cairo_gstate_t *gstate, const double *dash, int num_dash
for (i = 0; i < gstate->stroke_style.num_dashes; i++) {
if (gstate->stroke_style.dash[i] < 0)
return _cairo_error (CAIRO_STATUS_INVALID_DASH);
+
dash_total += gstate->stroke_style.dash[i];
}
@@ -562,10 +563,11 @@ _cairo_gstate_get_dash (cairo_gstate_t *gstate,
int *num_dashes,
double *offset)
{
- if (dashes)
+ if (dashes) {
memcpy (dashes,
gstate->stroke_style.dash,
sizeof (double) * gstate->stroke_style.num_dashes);
+ }
if (num_dashes)
*num_dashes = gstate->stroke_style.num_dashes;
@@ -912,9 +914,10 @@ _cairo_gstate_copy_transformed_pattern (cairo_gstate_t *gstate,
if (! _cairo_matrix_is_identity (ctm_inverse))
_cairo_pattern_transform (pattern, ctm_inverse);
- if (_cairo_surface_has_device_transform (gstate->target))
+ if (_cairo_surface_has_device_transform (gstate->target)) {
_cairo_pattern_transform (pattern,
&gstate->target->device_transform_inverse);
+ }
}
static void
commit 29bedde904824098f73b978d73d36b3b5420ac32
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Fri Jan 22 16:19:31 2010 +0000
pattern: Add convenience patterns for stock colours
By preallocating in our data segment a couple of solid patterns for the
stock colours, it becomes more convenient when using those in surface
operations, such as when clearing.
diff --git a/src/cairo-clip.c b/src/cairo-clip.c
index b3d3034..aa9433b 100644
--- a/src/cairo-clip.c
+++ b/src/cairo-clip.c
@@ -947,7 +947,6 @@ _cairo_clip_path_get_surface (cairo_clip_path_t *clip_path,
cairo_surface_t *target)
{
cairo_surface_t *surface;
- cairo_pattern_union_t pattern;
cairo_status_t status;
const cairo_rectangle_int_t *clip_extents = &clip_path->extents;
cairo_clip_path_t *prev;
@@ -980,10 +979,6 @@ _cairo_clip_path_get_surface (cairo_clip_path_t *clip_path,
if (unlikely (surface->status))
return surface;
- _cairo_pattern_init_solid (&pattern.solid,
- CAIRO_COLOR_WHITE,
- CAIRO_CONTENT_COLOR);
-
status = _cairo_clip_path_to_region (clip_path);
if (unlikely (_cairo_status_is_error (status)))
goto BAIL;
@@ -1014,7 +1009,7 @@ _cairo_clip_path_get_surface (cairo_clip_path_t *clip_path,
}
status = _cairo_surface_fill (surface,
CAIRO_OPERATOR_OVER,
- &pattern.base,
+ &_cairo_pattern_white.base,
&clip_path->path,
clip_path->fill_rule,
clip_path->tolerance,
@@ -1051,7 +1046,7 @@ _cairo_clip_path_get_surface (cairo_clip_path_t *clip_path,
}
status = _cairo_surface_fill (surface,
CAIRO_OPERATOR_IN,
- &pattern.base,
+ &_cairo_pattern_white.base,
&prev->path,
prev->fill_rule,
prev->tolerance,
@@ -1070,9 +1065,10 @@ _cairo_clip_path_get_surface (cairo_clip_path_t *clip_path,
goto NEXT_PATH;
} else {
cairo_surface_t *prev_surface;
+ cairo_surface_pattern_t pattern;
prev_surface = _cairo_clip_path_get_surface (prev, target);
- _cairo_pattern_init_for_surface (&pattern.surface, prev_surface);
+ _cairo_pattern_init_for_surface (&pattern, prev_surface);
cairo_surface_destroy (prev_surface);
cairo_matrix_init_translate (&pattern.base.matrix,
@@ -1142,7 +1138,6 @@ _cairo_clip_combine_with_surface (cairo_clip_t *clip,
cairo_surface_t *dst,
const cairo_rectangle_int_t *extents)
{
- cairo_pattern_union_t pattern;
cairo_clip_path_t *clip_path = clip->path;
cairo_bool_t need_translate;
cairo_status_t status;
@@ -1152,8 +1147,9 @@ _cairo_clip_combine_with_surface (cairo_clip_t *clip,
if (clip_path->surface != NULL &&
clip_path->surface->backend == dst->backend)
{
- _cairo_pattern_init_for_surface (&pattern.surface,
- clip_path->surface);
+ cairo_surface_pattern_t pattern;
+
+ _cairo_pattern_init_for_surface (&pattern, clip_path->surface);
cairo_matrix_init_translate (&pattern.base.matrix,
extents->x - clip_path->extents.x,
extents->y - clip_path->extents.y);
@@ -1167,10 +1163,6 @@ _cairo_clip_combine_with_surface (cairo_clip_t *clip,
return status;
}
- _cairo_pattern_init_solid (&pattern.solid,
- CAIRO_COLOR_WHITE,
- CAIRO_CONTENT_COLOR);
-
need_translate = extents->x | extents->y;
do {
status = _cairo_clip_path_to_region (clip_path);
@@ -1183,8 +1175,9 @@ _cairo_clip_combine_with_surface (cairo_clip_t *clip,
if (clip_path->surface != NULL &&
clip_path->surface->backend == dst->backend)
{
- _cairo_pattern_init_for_surface (&pattern.surface,
- clip_path->surface);
+ cairo_surface_pattern_t pattern;
+
+ _cairo_pattern_init_for_surface (&pattern, clip_path->surface);
cairo_matrix_init_translate (&pattern.base.matrix,
extents->x - clip_path->extents.x,
extents->y - clip_path->extents.y);
@@ -1211,7 +1204,7 @@ _cairo_clip_combine_with_surface (cairo_clip_t *clip,
}
status = _cairo_surface_fill (dst,
CAIRO_OPERATOR_IN,
- &pattern.base,
+ &_cairo_pattern_white.base,
&clip_path->path,
clip_path->fill_rule,
clip_path->tolerance,
diff --git a/src/cairo-gl-glyphs.c b/src/cairo-gl-glyphs.c
index dd6e3f2..e3e2a99 100644
--- a/src/cairo-gl-glyphs.c
+++ b/src/cairo-gl-glyphs.c
@@ -624,7 +624,6 @@ _cairo_gl_surface_show_glyphs_via_mask (cairo_gl_surface_t *dst,
cairo_gl_context_t *ctx;
cairo_surface_t *mask;
cairo_status_t status;
- cairo_solid_pattern_t solid;
cairo_bool_t has_component_alpha;
int i;
@@ -665,9 +664,9 @@ _cairo_gl_surface_show_glyphs_via_mask (cairo_gl_surface_t *dst,
glyphs[i].y -= glyph_extents->y;
}
- _cairo_pattern_init_solid (&solid, CAIRO_COLOR_WHITE, CAIRO_CONTENT_COLOR_ALPHA);
status = _render_glyphs ((cairo_gl_surface_t *) mask, 0, 0,
- CAIRO_OPERATOR_ADD, &solid.base,
+ CAIRO_OPERATOR_ADD,
+ &_cairo_pattern_white.base,
glyphs, num_glyphs, glyph_extents,
scaled_font, &has_component_alpha,
NULL, remaining_glyphs);
@@ -712,7 +711,6 @@ _cairo_gl_surface_show_glyphs (void *abstract_dst,
cairo_rectangle_int_t surface_extents;
cairo_rectangle_int_t extents;
cairo_region_t *clip_region = NULL;
- cairo_solid_pattern_t solid_pattern;
cairo_bool_t overlap, use_mask = FALSE;
cairo_bool_t has_component_alpha;
cairo_status_t status;
@@ -769,9 +767,7 @@ _cairo_gl_surface_show_glyphs (void *abstract_dst,
* mask IN clip ? 0 : dest
*/
if (op == CAIRO_OPERATOR_CLEAR) {
- _cairo_pattern_init_solid (&solid_pattern, CAIRO_COLOR_WHITE,
- CAIRO_CONTENT_COLOR);
- source = &solid_pattern.base;
+ source = &_cairo_pattern_white.base;
op = CAIRO_OPERATOR_DEST_OUT;
}
diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c
index 0c6f341..0d5bedb 100644
--- a/src/cairo-gstate.c
+++ b/src/cairo-gstate.c
@@ -1149,7 +1149,6 @@ BAIL:
cairo_status_t
_cairo_gstate_fill (cairo_gstate_t *gstate, cairo_path_fixed_t *path)
{
- cairo_pattern_union_t pattern;
cairo_clip_t clip;
cairo_status_t status;
@@ -1163,16 +1162,14 @@ _cairo_gstate_fill (cairo_gstate_t *gstate, cairo_path_fixed_t *path)
if (_cairo_operator_bounded_by_mask (gstate->op))
return CAIRO_STATUS_SUCCESS;
- _cairo_pattern_init_solid (&pattern.solid,
- CAIRO_COLOR_TRANSPARENT,
- CAIRO_CONTENT_COLOR_ALPHA);
status = _cairo_surface_paint (gstate->target,
CAIRO_OPERATOR_CLEAR,
- &pattern.base,
+ &_cairo_pattern_clear.base,
_gstate_get_clip (gstate, &clip));
} else {
- _cairo_gstate_copy_transformed_source (gstate, &pattern.base);
+ cairo_pattern_union_t pattern;
+ _cairo_gstate_copy_transformed_source (gstate, &pattern.base);
status = _cairo_surface_fill (gstate->target,
gstate->op,
&pattern.base,
diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c
index 356aa9e..5d4ceb7 100644
--- a/src/cairo-pattern.c
+++ b/src/cairo-pattern.c
@@ -68,6 +68,30 @@ const cairo_solid_pattern_t _cairo_pattern_black = {
CAIRO_CONTENT_COLOR, /* content */
};
+const cairo_solid_pattern_t _cairo_pattern_clear = {
+ { CAIRO_PATTERN_TYPE_SOLID, /* type */
+ CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */
+ CAIRO_STATUS_SUCCESS, /* status */
+ { 0, 0, 0, NULL }, /* user_data */
+ { 1., 0., 0., 1., 0., 0., }, /* matrix */
+ CAIRO_FILTER_DEFAULT, /* filter */
+ CAIRO_EXTEND_GRADIENT_DEFAULT}, /* extend */
+ { 0., 0., 0., 0., 0, 0, 0, 0 },/* color (double rgba, short rgba) */
+ CAIRO_CONTENT_ALPHA, /* content */
+};
+
+const cairo_solid_pattern_t _cairo_pattern_white = {
+ { CAIRO_PATTERN_TYPE_SOLID, /* type */
+ CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */
+ CAIRO_STATUS_SUCCESS, /* status */
+ { 0, 0, 0, NULL }, /* user_data */
+ { 1., 0., 0., 1., 0., 0., }, /* matrix */
+ CAIRO_FILTER_DEFAULT, /* filter */
+ CAIRO_EXTEND_GRADIENT_DEFAULT}, /* extend */
+ { 1., 1., 1., 1., 0xffff, 0xffff, 0xffff, 0xffff },/* color (double rgba, short rgba) */
+ CAIRO_CONTENT_COLOR_ALPHA, /* content */
+};
+
/**
* _cairo_pattern_set_error:
* @pattern: a pattern
diff --git a/src/cairo-scaled-font.c b/src/cairo-scaled-font.c
index b7b2829..7a556a7 100644
--- a/src/cairo-scaled-font.c
+++ b/src/cairo-scaled-font.c
@@ -2070,7 +2070,6 @@ _cairo_scaled_font_show_glyphs (cairo_scaled_font_t *scaled_font,
cairo_surface_t *mask = NULL;
cairo_format_t mask_format = CAIRO_FORMAT_A1; /* shut gcc up */
cairo_surface_pattern_t mask_pattern;
- cairo_solid_pattern_t white_pattern;
int i;
/* These operators aren't interpreted the same way by the backends;
@@ -2105,8 +2104,6 @@ _cairo_scaled_font_show_glyphs (cairo_scaled_font_t *scaled_font,
/* Font display routine either does not exist or failed. */
- _cairo_pattern_init_solid (&white_pattern, CAIRO_COLOR_WHITE, CAIRO_CONTENT_COLOR);
-
_cairo_scaled_font_freeze_cache (scaled_font);
for (i = 0; i < num_glyphs; i++) {
@@ -2167,7 +2164,7 @@ _cairo_scaled_font_show_glyphs (cairo_scaled_font_t *scaled_font,
* never any component alpha here.
*/
status = _cairo_surface_composite (CAIRO_OPERATOR_SOURCE,
- &white_pattern.base,
+ &_cairo_pattern_white.base,
&mask_pattern.base,
new_mask,
0, 0,
@@ -2203,7 +2200,7 @@ _cairo_scaled_font_show_glyphs (cairo_scaled_font_t *scaled_font,
glyph_pattern.base.has_component_alpha = TRUE;
status = _cairo_surface_composite (CAIRO_OPERATOR_ADD,
- &white_pattern.base,
+ &_cairo_pattern_white.base,
&glyph_pattern.base,
mask,
0, 0,
@@ -2237,8 +2234,6 @@ _cairo_scaled_font_show_glyphs (cairo_scaled_font_t *scaled_font,
CLEANUP_MASK:
_cairo_scaled_font_thaw_cache (scaled_font);
- _cairo_pattern_fini (&white_pattern.base);
-
if (mask != NULL)
cairo_surface_destroy (mask);
return _cairo_scaled_font_set_error (scaled_font, status);
diff --git a/src/cairo-surface-fallback.c b/src/cairo-surface-fallback.c
index a20bd68..51e3d7e 100644
--- a/src/cairo-surface-fallback.c
+++ b/src/cairo-surface-fallback.c
@@ -127,7 +127,6 @@ _create_composite_mask_pattern (cairo_surface_pattern_t *mask_pattern,
{
cairo_surface_t *mask;
cairo_region_t *clip_region = NULL;
- cairo_solid_pattern_t solid;
cairo_status_t status;
cairo_bool_t clip_surface = FALSE;
@@ -156,9 +155,8 @@ _create_composite_mask_pattern (cairo_surface_pattern_t *mask_pattern,
if (unlikely (mask->status))
return mask->status;
- _cairo_pattern_init_solid (&solid, CAIRO_COLOR_WHITE, CAIRO_CONTENT_ALPHA);
status = draw_func (draw_closure, CAIRO_OPERATOR_ADD,
- &solid.base, mask,
+ &_cairo_pattern_white.base, mask,
extents->x, extents->y,
extents,
clip_region);
@@ -416,7 +414,6 @@ _clip_and_composite (cairo_clip_t *clip,
cairo_surface_t *dst,
const cairo_rectangle_int_t *extents)
{
- cairo_solid_pattern_t solid_pattern;
cairo_status_t status;
if (_cairo_rectangle_empty (extents))
@@ -424,9 +421,7 @@ _clip_and_composite (cairo_clip_t *clip,
return CAIRO_STATUS_SUCCESS;
if (op == CAIRO_OPERATOR_CLEAR) {
- _cairo_pattern_init_solid (&solid_pattern, CAIRO_COLOR_WHITE,
- CAIRO_CONTENT_COLOR);
- src = &solid_pattern.base;
+ src = &_cairo_pattern_white.base;
op = CAIRO_OPERATOR_DEST_OUT;
}
@@ -487,7 +482,6 @@ _composite_trap_region (cairo_clip_t *clip,
const cairo_rectangle_int_t *extents)
{
cairo_status_t status;
- cairo_solid_pattern_t solid_pattern;
cairo_surface_pattern_t mask_pattern;
cairo_pattern_t *mask = NULL;
int mask_x = 0, mask_y =0;
@@ -501,9 +495,7 @@ _composite_trap_region (cairo_clip_t *clip,
return clip_surface->status;
if (op == CAIRO_OPERATOR_CLEAR) {
- _cairo_pattern_init_solid (&solid_pattern, CAIRO_COLOR_WHITE,
- CAIRO_CONTENT_COLOR);
- src = &solid_pattern.base;
+ src = &_cairo_pattern_white.base;
op = CAIRO_OPERATOR_DEST_OUT;
}
diff --git a/src/cairo-vg-surface.c b/src/cairo-vg-surface.c
index b3eef52..e2c5279 100644
--- a/src/cairo-vg-surface.c
+++ b/src/cairo-vg-surface.c
@@ -410,7 +410,6 @@ _vg_surface_clipper_intersect_clip_path (cairo_surface_clipper_t *clipper,
cairo_vg_surface_t,
clipper);
cairo_vg_surface_t *mask;
- cairo_solid_pattern_t white;
cairo_status_t status;
if (path == NULL) {
@@ -429,9 +428,9 @@ _vg_surface_clipper_intersect_clip_path (cairo_surface_clipper_t *clipper,
if (unlikely (mask->base.status))
return mask->base.status;
- _cairo_pattern_init_solid (&white, CAIRO_COLOR_WHITE, CAIRO_CONTENT_ALPHA);
status = _cairo_surface_fill (&mask->base,
- CAIRO_OPERATOR_SOURCE, &white.base,
+ CAIRO_OPERATOR_SOURCE,
+ _cairo_pattern_white.base,
path, fill_rule, tolerance, antialias,
NULL);
if (status) {
diff --git a/src/cairo-win32-printing-surface.c b/src/cairo-win32-printing-surface.c
index ac4bc43..4b6a208 100644
--- a/src/cairo-win32-printing-surface.c
+++ b/src/cairo-win32-printing-surface.c
@@ -439,13 +439,9 @@ _cairo_win32_printing_surface_paint_recording_pattern (cairo_win32_surface_t *
old_content = surface->content;
if (recording_surface->base.content == CAIRO_CONTENT_COLOR) {
- cairo_pattern_t *source;
- cairo_solid_pattern_t black;
-
surface->content = CAIRO_CONTENT_COLOR;
- _cairo_pattern_init_solid (&black, CAIRO_COLOR_BLACK, CAIRO_CONTENT_COLOR);
- source = (cairo_pattern_t*) &black;
- status = _cairo_win32_printing_surface_paint_solid_pattern (surface, source);
+ status = _cairo_win32_printing_surface_paint_solid_pattern (surface,
+ &_cairo_pattern_black.base);
if (status)
return status;
}
diff --git a/src/cairo-xcb-surface.c b/src/cairo-xcb-surface.c
index c9d5c92..faa5665 100644
--- a/src/cairo-xcb-surface.c
+++ b/src/cairo-xcb-surface.c
@@ -2706,7 +2706,6 @@ _cairo_xcb_surface_show_glyphs (void *abstract_dst,
cairo_surface_attributes_t attributes;
cairo_xcb_surface_t *src = NULL;
- cairo_solid_pattern_t solid_pattern;
cairo_region_t *clip_region = NULL;
if (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE_TEXT (dst) || dst->xrender_format.id == XCB_NONE)
@@ -2759,9 +2758,7 @@ _cairo_xcb_surface_show_glyphs (void *abstract_dst,
* so PictOpClear was never used with CompositeText before.
*/
if (op == CAIRO_OPERATOR_CLEAR) {
- _cairo_pattern_init_solid (&solid_pattern, CAIRO_COLOR_WHITE,
- CAIRO_CONTENT_COLOR);
- src_pattern = &solid_pattern.base;
+ src_pattern = &_cairo_pattern_white.base;
op = CAIRO_OPERATOR_DEST_OUT;
}
@@ -2826,8 +2823,6 @@ _cairo_xcb_surface_show_glyphs (void *abstract_dst,
BAIL:
if (src)
_cairo_pattern_release_surface (src_pattern, &src->base, &attributes);
- if (src_pattern == &solid_pattern.base)
- _cairo_pattern_fini (&solid_pattern.base);
return status;
}
diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c
index 6d42719..8545948 100644
--- a/src/cairo-xlib-surface.c
+++ b/src/cairo-xlib-surface.c
@@ -4397,8 +4397,6 @@ _cairo_xlib_surface_show_glyphs (void *abstract_dst,
cairo_xlib_surface_t *src = NULL;
cairo_region_t *clip_region = NULL;
- cairo_solid_pattern_t solid_pattern;
-
if (! CAIRO_SURFACE_RENDER_HAS_COMPOSITE_TEXT (dst))
return UNSUPPORTED ("XRender does not support CompositeText");
@@ -4478,9 +4476,7 @@ _cairo_xlib_surface_show_glyphs (void *abstract_dst,
* so PictOpClear was never used with CompositeText before.
*/
if (op == CAIRO_OPERATOR_CLEAR) {
- _cairo_pattern_init_solid (&solid_pattern, CAIRO_COLOR_WHITE,
- CAIRO_CONTENT_COLOR);
- src_pattern = &solid_pattern.base;
+ src_pattern = &_cairo_pattern_white.base;
op = CAIRO_OPERATOR_DEST_OUT;
}
diff --git a/src/cairoint.h b/src/cairoint.h
index d791c8c..401fac6 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -871,8 +871,9 @@ extern const cairo_private cairo_surface_backend_t _cairo_image_surface_backend;
#define CAIRO_EXTEND_GRADIENT_DEFAULT CAIRO_EXTEND_PAD
#define CAIRO_FILTER_DEFAULT CAIRO_FILTER_GOOD
+extern const cairo_private cairo_solid_pattern_t _cairo_pattern_clear;
extern const cairo_private cairo_solid_pattern_t _cairo_pattern_black;
-
+extern const cairo_private cairo_solid_pattern_t _cairo_pattern_white;
typedef struct _cairo_surface_attributes {
cairo_matrix_t matrix;
commit 9eb98e1dc5af7eac896bf469e491063777e678be
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Fri Jan 22 14:14:51 2010 +0000
scaled-font: Use tight glyph bounds when determining overlap.
An issue that we currently have is that we have a pessimistic
false-positive rate when determining whether glyphs within a string
overlap. By using the tight bounds, the overlap detection is arguably
less accurate presuming pixel-aligned opacity masks but we make the
trade-off for performance.
diff --git a/src/cairo-scaled-font.c b/src/cairo-scaled-font.c
index 0e24bbd..b7b2829 100644
--- a/src/cairo-scaled-font.c
+++ b/src/cairo-scaled-font.c
@@ -1927,12 +1927,16 @@ cairo_scaled_font_text_to_glyphs (cairo_scaled_font_t *scaled_font,
slim_hidden_def (cairo_scaled_font_text_to_glyphs);
static inline cairo_bool_t
-_range_contains_glyph (const cairo_point_int_t *min,
- const cairo_point_int_t *max,
- int left, int top,
- int right, int bottom)
+_range_contains_glyph (const cairo_box_t *extents,
+ cairo_fixed_t left,
+ cairo_fixed_t top,
+ cairo_fixed_t right,
+ cairo_fixed_t bottom)
{
- return right > min->x && left < max->x && bottom > min->y && top < max->y;
+ return right > extents->p1.x &&
+ left < extents->p2.x &&
+ bottom > extents->p1.y &&
+ top < extents->p2.y;
}
/*
@@ -1946,8 +1950,7 @@ _cairo_scaled_font_glyph_device_extents (cairo_scaled_font_t *scaled_font,
cairo_bool_t *overlap_out)
{
cairo_status_t status = CAIRO_STATUS_SUCCESS;
- cairo_point_int_t min = { CAIRO_RECT_INT_MAX, CAIRO_RECT_INT_MAX };
- cairo_point_int_t max = { CAIRO_RECT_INT_MIN, CAIRO_RECT_INT_MIN };
+ cairo_box_t box = { { INT_MAX, INT_MAX }, { INT_MIN, INT_MIN }};
cairo_scaled_glyph_t *glyph_cache[64];
cairo_bool_t overlap = overlap_out ? FALSE : TRUE;
int i;
@@ -1961,9 +1964,7 @@ _cairo_scaled_font_glyph_device_extents (cairo_scaled_font_t *scaled_font,
for (i = 0; i < num_glyphs; i++) {
cairo_scaled_glyph_t *scaled_glyph;
- int left, top;
- int right, bottom;
- int x, y;
+ cairo_fixed_t x, y, x1, y1, x2, y2;
int cache_index = glyphs[i].index % ARRAY_LENGTH (glyph_cache);
scaled_glyph = glyph_cache[cache_index];
@@ -1980,35 +1981,29 @@ _cairo_scaled_font_glyph_device_extents (cairo_scaled_font_t *scaled_font,
glyph_cache[cache_index] = scaled_glyph;
}
- /* XXX glyph images are snapped to pixel locations */
- x = _cairo_lround (glyphs[i].x);
- y = _cairo_lround (glyphs[i].y);
+ x = _cairo_fixed_from_double (glyphs[i].x);
+ x1 = x + scaled_glyph->bbox.p1.x;
+ x2 = x + scaled_glyph->bbox.p2.x;
- left = x + _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.x);
- top = y + _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.y);
- right = x + _cairo_fixed_integer_ceil (scaled_glyph->bbox.p2.x);
- bottom = y + _cairo_fixed_integer_ceil (scaled_glyph->bbox.p2.y);
+ y = _cairo_fixed_from_double (glyphs[i].y);
+ y1 = y + scaled_glyph->bbox.p1.y;
+ y2 = y + scaled_glyph->bbox.p2.y;
- if (overlap == FALSE) {
- overlap = _range_contains_glyph (&min, &max,
- left, top, right, bottom);
- }
+ if (overlap == FALSE)
+ overlap = _range_contains_glyph (&box, x1, y1, x2, y2);
- if (left < min.x) min.x = left;
- if (right > max.x) max.x = right;
- if (top < min.y) min.y = top;
- if (bottom > max.y) max.y = bottom;
+ if (x1 < box.p1.x) box.p1.x = x1;
+ if (x2 > box.p2.x) box.p2.x = x2;
+ if (y1 < box.p1.y) box.p1.y = y1;
+ if (y2 > box.p2.y) box.p2.y = y2;
}
_cairo_scaled_font_thaw_cache (scaled_font);
if (unlikely (status))
return _cairo_scaled_font_set_error (scaled_font, status);
- if (min.x < max.x && min.y < max.y) {
- extents->x = min.x;
- extents->width = max.x - min.x;
- extents->y = min.y;
- extents->height = max.y - min.y;
+ if (box.p1.x < box.p2.x) {
+ _cairo_box_round_to_rectangle (&box, extents);
} else {
extents->x = extents->y = 0;
extents->width = extents->height = 0;
commit 005b0c4eb2a1fe2c4de31ebe2a3244bea8bd2625
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Fri Jan 22 19:47:58 2010 +0000
test: Add explicit device management to xlib-surface-source
Mostly pedagogical example.
diff --git a/test/xlib-surface-source.c b/test/xlib-surface-source.c
index b99f088..65a9fdf 100644
--- a/test/xlib-surface-source.c
+++ b/test/xlib-surface-source.c
@@ -34,6 +34,7 @@
static cairo_user_data_key_t closure_key;
struct closure {
+ cairo_device_t *device;
Display *dpy;
Pixmap pix;
};
@@ -43,6 +44,9 @@ cleanup (void *data)
{
struct closure *arg = data;
+ cairo_device_finish (arg->device);
+ cairo_device_destroy (arg->device);
+
XFreePixmap (arg->dpy, arg->pix);
XCloseDisplay (arg->dpy);
@@ -74,6 +78,7 @@ create_source_surface (int size)
DefaultScreenOfDisplay (data->dpy),
xrender_format,
size, size);
+ data->device = cairo_device_reference (cairo_surface_get_device (surface));
cairo_surface_set_user_data (surface, &closure_key, data, cleanup);
return surface;
commit ca02b51ef6d058b6fb492258177f0396a5819e26
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Fri Jan 22 21:57:58 2010 +0000
test: Add an xcb surface source test
diff --git a/test/Makefile.am b/test/Makefile.am
index 6074028..ac515eb 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -41,6 +41,10 @@ if CAIRO_HAS_TEST_SURFACES
test_sources += $(test_fallback16_surface_test_sources)
endif
+if CAIRO_HAS_XCB_SURFACE
+test_sources += $(xcb_surface_test_sources)
+endif
+
if CAIRO_HAS_XLIB_SURFACE
test_sources += $(xlib_surface_test_sources)
endif
@@ -1057,6 +1061,8 @@ REFERENCE_IMAGES = \
user-font.ref.png \
user-font.svg.ref.png \
user-font.xlib.ref.png \
+ xcb-surface-source.rgb24.ref.png \
+ xcb-surface-source.argb32.ref.png \
xlib-expose-event.ref.png \
xlib-surface-source.rgb24.ref.png \
xlib-surface-source.argb32.ref.png \
diff --git a/test/Makefile.sources b/test/Makefile.sources
index 69628b0..824379e 100644
--- a/test/Makefile.sources
+++ b/test/Makefile.sources
@@ -286,6 +286,9 @@ svg_surface_test_sources = \
test_fallback16_surface_test_sources = \
test-fallback16-surface-source.c
+xcb_surface_test_sources = \
+ xcb-surface-source.c
+
xlib_surface_test_sources = \
xlib-expose-event.c \
xlib-surface.c \
diff --git a/test/xcb-surface-source.argb32.ref.png b/test/xcb-surface-source.argb32.ref.png
new file mode 100644
index 0000000..0182972
Binary files /dev/null and b/test/xcb-surface-source.argb32.ref.png differ
diff --git a/test/xcb-surface-source.c b/test/xcb-surface-source.c
new file mode 100644
index 0000000..debe93e
--- /dev/null
+++ b/test/xcb-surface-source.c
@@ -0,0 +1,145 @@
+/*
+ * Copyright © 2009 Chris Wilson
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of
+ * Chris Wilson not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior
+ * permission. Chris Wilson makes no representations about the
+ * suitability of this software for any purpose. It is provided "as
+ * is" without express or implied warranty.
+ *
+ * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Chris Wilson <chris at chris-wilson.co.uk>
+ */
+
+#include "cairo-test.h"
+#if CAIRO_HAS_XCB_SURFACE
+#include <cairo-xcb.h>
+#include <cairo-xcb-xrender.h>
+#endif
+
+#include "surface-source.c"
+
+#if CAIRO_HAS_XCB_SURFACE
+static cairo_user_data_key_t closure_key;
+
+struct closure {
+ cairo_device_t *device;
+ xcb_connection_t *connection;
+ xcb_pixmap_t pixmap;
+};
+
+static void
+cleanup (void *data)
+{
+ struct closure *arg = data;
+
+ cairo_device_finish (arg->device);
+ cairo_device_destroy (arg->device);
+
+ xcb_free_pixmap (arg->connection, arg->pixmap);
+ xcb_disconnect (arg->connection);
+
+ free (arg);
+}
+
+static xcb_render_pictforminfo_t *
+find_depth (xcb_connection_t *connection, int depth, void **formats_out)
+{
+ xcb_render_query_pict_formats_reply_t *formats;
+ xcb_render_query_pict_formats_cookie_t cookie;
+ xcb_render_pictforminfo_iterator_t i;
+
+ cookie = xcb_render_query_pict_formats (connection);
+ xcb_flush (connection);
+
+ formats = xcb_render_query_pict_formats_reply (connection, cookie, 0);
+ if (formats == NULL)
+ return NULL;
+
+ for (i = xcb_render_query_pict_formats_formats_iterator (formats);
+ i.rem;
+ xcb_render_pictforminfo_next (&i))
+ {
+ if (XCB_RENDER_PICT_TYPE_DIRECT != i.data->type)
+ continue;
+
+ if (depth != i.data->depth)
+ continue;
+
+ *formats_out = formats;
+ return i.data;
+ }
+
+ free (formats);
+ return NULL;
+}
+#endif
+
+static cairo_surface_t *
+create_source_surface (int size)
+{
+#if CAIRO_HAS_XCB_SURFACE
+ xcb_render_pictforminfo_t *render_format;
+ struct closure *data;
+ cairo_surface_t *surface;
+ xcb_screen_t *root;
+ xcb_void_cookie_t cookie;
+ void *formats;
+
+ data = xmalloc (sizeof (struct closure));
+
+ data->connection = xcb_connect (NULL, NULL);
+ render_format = find_depth (data->connection, 32, &formats);
+ if (render_format == NULL) {
+ xcb_disconnect (data->connection);
+ free (data);
+ return NULL;
+ }
+
+ root = xcb_setup_roots_iterator (xcb_get_setup (data->connection)).data;
+
+ data->pixmap = xcb_generate_id (data->connection);
+ cookie = xcb_create_pixmap_checked (data->connection, 32,
+ data->pixmap, root->root, size, size);
+ /* slow, but sure */
+ if (xcb_request_check (data->connection, cookie) != NULL) {
+ free (formats);
+ xcb_disconnect (data->connection);
+ free (data);
+ return NULL;
+ }
+
+ surface = cairo_xcb_surface_create_with_xrender_format (data->connection,
+ root,
+ data->pixmap,
+ render_format,
+ size, size);
+ free (formats);
+
+ data->device = cairo_device_reference (cairo_surface_get_device (surface));
+ cairo_surface_set_user_data (surface, &closure_key, data, cleanup);
+
+ return surface;
+#else
+ return NULL;
+#endif
+}
+
+CAIRO_TEST (xcb_surface_source,
+ "Test using a XCB surface as the source",
+ "source", /* keywords */
+ NULL, /* requirements */
+ SIZE, SIZE,
+ preamble, draw)
diff --git a/test/xcb-surface-source.rgb24.ref.png b/test/xcb-surface-source.rgb24.ref.png
new file mode 100644
index 0000000..0d68a82
Binary files /dev/null and b/test/xcb-surface-source.rgb24.ref.png differ
commit f0678fb70ceec5db1b7c3f0eb1c5603039daf307
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Fri Jan 22 19:02:39 2010 +0000
test: Tweak aligned of text-rotate
Reset the rotation for every quadrant so that the starting rectangles
are pixel-aligned.
diff --git a/test/text-rotate.c b/test/text-rotate.c
index 2613c88..cbc756c 100644
--- a/test/text-rotate.c
+++ b/test/text-rotate.c
@@ -90,14 +90,47 @@
#define NUM_TEXT 20
#define TEXT_SIZE 12
-/* Draw the word cairo at NUM_TEXT different angles */
+/* Draw the word cairo at NUM_TEXT different angles.
+ * We separate the circle into quadrants to reduce
+ * numerical errors i.e. so each quarter is pixel-aligned.
+ */
+static void
+draw_quadrant (cairo_t *cr,
+ const char *text,
+ const cairo_text_extents_t *extents,
+ const cairo_matrix_t *transform,
+ int x_off, int y_off)
+{
+ int i;
+
+ for (i = 0; i < NUM_TEXT/4; i++) {
+ cairo_save (cr);
+ cairo_rotate (cr, 2*M_PI*i/NUM_TEXT);
+ cairo_transform (cr, transform);
+ cairo_set_line_width (cr, 1.0);
+ cairo_rectangle (cr, x_off - 0.5, y_off - 0.5, extents->width + 1, extents->height + 1);
+ cairo_set_source_rgb (cr, 1, 0, 0);
+ cairo_stroke (cr);
+ cairo_move_to (cr, x_off - extents->x_bearing, y_off - extents->y_bearing);
+ cairo_set_source_rgb (cr, 0, 0, 0);
+#if CAIRO_TEST_GENERATE_REFERENCE_IMAGE
+ cairo_text_path (cr, text);
+ cairo_fill (cr);
+#else
+ cairo_show_text (cr, text);
+#endif
+ cairo_restore (cr);
+ }
+}
+
static cairo_test_status_t
draw (cairo_t *cr, int width, int height)
{
- int i, x_off, y_off;
cairo_text_extents_t extents;
cairo_font_options_t *font_options;
const char text[] = "cairo";
+ int x_off, y_off;
+ cairo_matrix_t m;
/* paint white so we don't need separate ref images for
* RGB24 and ARGB32 */
@@ -130,23 +163,20 @@ draw (cairo_t *cr, int width, int height)
x_off = floor (0.5 + (extents.height+1) / (2 * tan (M_PI/NUM_TEXT)));
}
- for (i=0; i < NUM_TEXT; i++) {
- cairo_save (cr);
- cairo_rotate (cr, 2*M_PI*i/NUM_TEXT);
- cairo_set_line_width (cr, 1.0);
- cairo_rectangle (cr, x_off - 0.5, y_off - 0.5, extents.width + 1, extents.height + 1);
- cairo_set_source_rgb (cr, 1, 0, 0);
- cairo_stroke (cr);
- cairo_move_to (cr, x_off - extents.x_bearing, y_off - extents.y_bearing);
- cairo_set_source_rgb (cr, 0, 0, 0);
-#if CAIRO_TEST_GENERATE_REFERENCE_IMAGE
- cairo_text_path (cr, text);
- cairo_fill (cr);
-#else
- cairo_show_text (cr, text);
-#endif
- cairo_restore (cr);
- }
+ cairo_save (cr);
+ cairo_matrix_init_identity (&m);
+ draw_quadrant (cr, text, &extents, &m, x_off, y_off);
+ cairo_matrix_init (&m, 0, 1, -1, 0, 0, 0);
+ draw_quadrant (cr, text, &extents, &m, x_off, y_off);
+ cairo_restore (cr);
+
+ cairo_save (cr);
+ cairo_scale (cr, -1, -1);
+ cairo_matrix_init_identity (&m);
+ draw_quadrant (cr, text, &extents, &m, x_off, y_off);
+ cairo_matrix_init (&m, 0, 1, -1, 0, 0, 0);
+ draw_quadrant (cr, text, &extents, &m, x_off, y_off);
+ cairo_restore (cr);
return CAIRO_TEST_SUCCESS;
}
diff --git a/test/text-rotate.ref.png b/test/text-rotate.ref.png
index 291c6c7..3777a9c 100644
Binary files a/test/text-rotate.ref.png and b/test/text-rotate.ref.png differ
commit 2edd2adafc471f4aa9c417d4bc76cc38466a9ed0
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Tue Jan 19 22:45:59 2010 +0000
test: Exercise scan converters with large rounded rectangles.
Having added a specialised scan converter on the premise that it should
be better at handling rounded rectangles, ensure that they are indeed
rendered correctly.
diff --git a/test/Makefile.am b/test/Makefile.am
index 5f3f429..6074028 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -836,6 +836,8 @@ REFERENCE_IMAGES = \
rotated-clip.ref.png \
rotated-clip.ps.ref.png \
rotated-clip.xlib.ref.png \
+ rounded-rectangle-fill.xlib.ref.png \
+ rounded-rectangle-stroke.xlib.ref.png \
scale-down-source-surface-paint.ref.png \
scale-offset-image.gl.ref.png \
scale-offset-image.pdf.argb32.ref.png \
diff --git a/test/Makefile.sources b/test/Makefile.sources
index d90f04a..69628b0 100644
--- a/test/Makefile.sources
+++ b/test/Makefile.sources
@@ -182,6 +182,8 @@ test_sources = \
rgb24-ignore-alpha.c \
rotate-image-surface-paint.c \
rotated-clip.c \
+ rounded-rectangle-fill.c \
+ rounded-rectangle-stroke.c \
scale-down-source-surface-paint.c \
scale-offset-image.c \
scale-offset-similar.c \
diff --git a/test/rounded-rectangle-fill.c b/test/rounded-rectangle-fill.c
new file mode 100644
index 0000000..d211cf6
--- /dev/null
+++ b/test/rounded-rectangle-fill.c
@@ -0,0 +1,65 @@
+/*
+ * Copyright © 2009 Chris Wilson
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Author: Chris Wilson <chris at chris-wilson.co.uk>
+ */
+
+#include "cairo-test.h"
+
+#define SIZE 80
+
+/* A very simple test to exercise the scan rasterisers with constant regions. */
+
+static void
+rounded_rectangle (cairo_t *cr, int x, int y, int w, int h, int r)
+{
+ cairo_new_sub_path (cr);
+ cairo_arc (cr, x + r, y + r, r, M_PI, 3 * M_PI / 2);
+ cairo_arc (cr, x + w - r, y + r, r, 3 *M_PI / 2, 2 * M_PI);
+ cairo_arc (cr, x + w - r, y + h - r, r, 0, M_PI / 2);
+ cairo_arc (cr, x + r, y + h - r, r, M_PI / 2, M_PI);
+ cairo_close_path (cr);
+}
+
+static cairo_test_status_t
+draw (cairo_t *cr, int width, int height)
+{
+ /* Paint background white, then draw in black. */
+ cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* white */
+ cairo_paint (cr);
+ cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); /* black */
+
+ cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD);
+ rounded_rectangle (cr, 5, 5, width-10, height-10, 15);
+ rounded_rectangle (cr, 15, 15, width-30, height-30, 5);
+ cairo_fill (cr);
+
+ return CAIRO_TEST_SUCCESS;
+}
+
+CAIRO_TEST (rounded_rectangle_fill,
+ "Tests handling of rounded rectangles, the UI designers favourite",
+ "fill, rounded-rectangle", /* keywords */
+ NULL, /* requirements */
+ SIZE, SIZE,
+ NULL, draw)
diff --git a/test/rounded-rectangle-fill.xlib.ref.png b/test/rounded-rectangle-fill.xlib.ref.png
new file mode 100644
index 0000000..52a355d
Binary files /dev/null and b/test/rounded-rectangle-fill.xlib.ref.png differ
diff --git a/test/rounded-rectangle-stroke.c b/test/rounded-rectangle-stroke.c
new file mode 100644
index 0000000..22bc515
--- /dev/null
+++ b/test/rounded-rectangle-stroke.c
@@ -0,0 +1,64 @@
+/*
+ * Copyright © 2009 Chris Wilson
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Author: Chris Wilson <chris at chris-wilson.co.uk>
+ */
+
+#include "cairo-test.h"
+
+#define SIZE 80
+
+/* A very simple test to exercise the scan rasterisers with constant regions. */
+
+static void
+rounded_rectangle (cairo_t *cr, int x, int y, int w, int h, int r)
+{
+ cairo_new_sub_path (cr);
+ cairo_arc (cr, x + r, y + r, r, M_PI, 3 * M_PI / 2);
+ cairo_arc (cr, x + w - r, y + r, r, 3 *M_PI / 2, 2 * M_PI);
+ cairo_arc (cr, x + w - r, y + h - r, r, 0, M_PI / 2);
+ cairo_arc (cr, x + r, y + h - r, r, M_PI / 2, M_PI);
+ cairo_close_path (cr);
+}
+
+static cairo_test_status_t
+draw (cairo_t *cr, int width, int height)
+{
+ /* Paint background white, then draw in black. */
+ cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* white */
+ cairo_paint (cr);
+ cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); /* black */
+
+ cairo_set_line_width (cr, 10);
+ rounded_rectangle (cr, 10, 10, width-20, height-20, 10);
+ cairo_stroke (cr);
+
+ return CAIRO_TEST_SUCCESS;
+}
+
+CAIRO_TEST (rounded_rectangle_stroke,
+ "Tests handling of rounded rectangles, the UI designers favourite",
+ "stroke, rounded-rectangle", /* keywords */
+ NULL, /* requirements */
+ SIZE, SIZE,
+ NULL, draw)
diff --git a/test/rounded-rectangle-stroke.xlib.ref.png b/test/rounded-rectangle-stroke.xlib.ref.png
new file mode 100644
index 0000000..c7a6554
Binary files /dev/null and b/test/rounded-rectangle-stroke.xlib.ref.png differ
commit 5187501e997d6b8c0d135542d21accde9e311281
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Tue Jan 19 22:41:45 2010 +0000
test: Add --track-origins=yes to valgrind flags.
Enable origin tracking by default for make check-valgrind. This is
slower and consumes more memory than regular valgrind, but the
additional information provided about the source of the uninitialised
data is often invaluable.
diff --git a/test/Makefile.am b/test/Makefile.am
index b820dd5..5f3f429 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -1302,7 +1302,9 @@ TESTS_ENVIRONMENT = CAIRO_TEST_MODE="$(MODE)" CAIRO_TEST_TARGET="$(TARGETS)" CAI
EXTRA_VALGRIND_FLAGS = $(CAIRO_EXTRA_VALGRIND_FLAGS)
VALGRIND_FLAGS = \
--tool=memcheck --suppressions=$(srcdir)/.valgrind-suppressions \
- --leak-check=yes --show-reachable=yes $(EXTRA_VALGRIND_FLAGS)
+ --track-origins=yes \
+ --leak-check=yes --show-reachable=yes \
+ $(EXTRA_VALGRIND_FLAGS)
CLEANFILES += \
valgrind-log \
commit 3a5d71c431dfb251308c3e4e02d2ea4acec90a91
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Tue Jan 19 19:18:54 2010 +0000
pattern: An EXTEND_NONE surface is not opaque if we sample outside
Fixes test/clear-source as proposed by Benjamin Otte.
diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c
index 03e408d..0c6f341 100644
--- a/src/cairo-gstate.c
+++ b/src/cairo-gstate.c
@@ -1010,7 +1010,7 @@ _cairo_gstate_mask (cairo_gstate_t *gstate,
if (_clipped (gstate))
return CAIRO_STATUS_SUCCESS;
- if (_cairo_pattern_is_opaque (mask))
+ if (_cairo_pattern_is_opaque (mask, NULL))
return _cairo_gstate_paint (gstate);
_cairo_gstate_copy_transformed_source (gstate, &source_pattern.base);
diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c
index 00d6c07..356aa9e 100644
--- a/src/cairo-pattern.c
+++ b/src/cairo-pattern.c
@@ -1739,6 +1739,34 @@ _cairo_pattern_is_opaque_solid (const cairo_pattern_t *pattern)
}
static cairo_bool_t
+_surface_is_opaque (const cairo_surface_pattern_t *pattern,
+ const cairo_rectangle_int_t *r)
+{
+ if (pattern->surface->content & CAIRO_CONTENT_ALPHA)
+ return FALSE;
+
+ if (pattern->base.extend != CAIRO_EXTEND_NONE)
+ return TRUE;
+
+ if (r != NULL) {
+ cairo_rectangle_int_t extents;
+
+ if (! _cairo_surface_get_extents (pattern->surface, &extents))
+ return TRUE;
+
+ if (r->x >= extents.x &&
+ r->y >= extents.y &&
+ r->x + r->width <= extents.x + extents.width &&
+ r->y + r->height <= extents.y + extents.height)
+ {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+static cairo_bool_t
_gradient_is_opaque (const cairo_gradient_pattern_t *gradient)
{
unsigned int i;
@@ -1760,7 +1788,8 @@ _gradient_is_opaque (const cairo_gradient_pattern_t *gradient)
* Return value: %TRUE if the pattern is a opaque.
**/
cairo_bool_t
-_cairo_pattern_is_opaque (const cairo_pattern_t *abstract_pattern)
+_cairo_pattern_is_opaque (const cairo_pattern_t *abstract_pattern,
+ const cairo_rectangle_int_t *extents)
{
const cairo_pattern_union_t *pattern;
@@ -1772,7 +1801,7 @@ _cairo_pattern_is_opaque (const cairo_pattern_t *abstract_pattern)
case CAIRO_PATTERN_TYPE_SOLID:
return _cairo_pattern_is_opaque_solid (abstract_pattern);
case CAIRO_PATTERN_TYPE_SURFACE:
- return cairo_surface_get_content (pattern->surface.surface) == CAIRO_CONTENT_COLOR;
+ return _surface_is_opaque (&pattern->surface, extents);
case CAIRO_PATTERN_TYPE_LINEAR:
case CAIRO_PATTERN_TYPE_RADIAL:
return _gradient_is_opaque (&pattern->gradient.base);
diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c
index b32b8ec..2b6ebc3 100644
--- a/src/cairo-pdf-surface.c
+++ b/src/cairo-pdf-surface.c
@@ -45,6 +45,7 @@
#include "cairo-pdf-surface-private.h"
#include "cairo-pdf-operators-private.h"
#include "cairo-analysis-surface-private.h"
+#include "cairo-composite-rectangles-private.h"
#include "cairo-error-private.h"
#include "cairo-image-info-private.h"
#include "cairo-recording-surface-private.h"
@@ -1179,25 +1180,6 @@ _cairo_pdf_surface_add_pdf_pattern (cairo_pdf_surface_t *surface,
return CAIRO_STATUS_SUCCESS;
}
- if (pattern->type == CAIRO_PATTERN_TYPE_LINEAR ||
- pattern->type == CAIRO_PATTERN_TYPE_RADIAL)
- {
- cairo_gradient_pattern_t *gradient;
-
- gradient = (cairo_gradient_pattern_t *) pattern;
-
- /* Gradients with zero stops do not produce any output */
- if (gradient->n_stops == 0)
- return CAIRO_INT_STATUS_NOTHING_TO_DO;
-
- /* Gradients with one stop are the same as solid colors */
- if (gradient->n_stops == 1) {
- pattern_res->id = 0;
- gstate_res->id = 0;
- return CAIRO_STATUS_SUCCESS;
- }
- }
-
status = _cairo_pattern_create_copy (&pdf_pattern.pattern, pattern);
if (unlikely (status))
return status;
@@ -1212,8 +1194,9 @@ _cairo_pdf_surface_add_pdf_pattern (cairo_pdf_surface_t *surface,
/* gradient patterns require an smask object to implement transparency */
if (pattern->type == CAIRO_PATTERN_TYPE_LINEAR ||
- pattern->type == CAIRO_PATTERN_TYPE_RADIAL) {
- if (_cairo_pattern_is_opaque (pattern) == FALSE) {
+ pattern->type == CAIRO_PATTERN_TYPE_RADIAL)
+ {
+ if (_cairo_pattern_is_opaque (pattern, extents) == FALSE) {
pdf_pattern.gstate_res = _cairo_pdf_surface_new_object (surface);
if (pdf_pattern.gstate_res.id == 0) {
cairo_pattern_destroy (pdf_pattern.pattern);
@@ -1222,14 +1205,14 @@ _cairo_pdf_surface_add_pdf_pattern (cairo_pdf_surface_t *surface,
}
}
- pdf_pattern.width = surface->width;
+ pdf_pattern.width = surface->width;
pdf_pattern.height = surface->height;
if (extents != NULL) {
pdf_pattern.extents = *extents;
} else {
pdf_pattern.extents.x = 0;
pdf_pattern.extents.y = 0;
- pdf_pattern.extents.width = surface->width;
+ pdf_pattern.extents.width = surface->width;
pdf_pattern.extents.height = surface->height;
}
@@ -5214,7 +5197,8 @@ _pdf_operator_supported (cairo_operator_t op)
static cairo_int_status_t
_cairo_pdf_surface_analyze_operation (cairo_pdf_surface_t *surface,
cairo_operator_t op,
- const cairo_pattern_t *pattern)
+ const cairo_pattern_t *pattern,
+ const cairo_rectangle_int_t *extents)
{
if (surface->force_fallbacks &&
surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
@@ -5248,7 +5232,7 @@ _cairo_pdf_surface_analyze_operation (cairo_pdf_surface_t *surface,
cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) pattern;
if (_cairo_surface_is_recording (surface_pattern->surface)) {
- if (_cairo_pattern_is_opaque (pattern)) {
+ if (_cairo_pattern_is_opaque (pattern, extents)) {
return CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN;
} else {
/* FIXME: The analysis surface does not yet have
@@ -5267,7 +5251,7 @@ _cairo_pdf_surface_analyze_operation (cairo_pdf_surface_t *surface,
}
}
- if (_cairo_pattern_is_opaque (pattern))
+ if (_cairo_pattern_is_opaque (pattern, extents))
return CAIRO_STATUS_SUCCESS;
else
return CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY;
@@ -5279,12 +5263,10 @@ _cairo_pdf_surface_analyze_operation (cairo_pdf_surface_t *surface,
static cairo_bool_t
_cairo_pdf_surface_operation_supported (cairo_pdf_surface_t *surface,
cairo_operator_t op,
- const cairo_pattern_t *pattern)
+ const cairo_pattern_t *pattern,
+ const cairo_rectangle_int_t *extents)
{
- if (_cairo_pdf_surface_analyze_operation (surface, op, pattern) != CAIRO_INT_STATUS_UNSUPPORTED)
- return TRUE;
- else
- return FALSE;
+ return _cairo_pdf_surface_analyze_operation (surface, op, pattern, extents) != CAIRO_INT_STATUS_UNSUPPORTED;
}
static cairo_int_status_t
@@ -5314,17 +5296,27 @@ _cairo_pdf_surface_paint (void *abstract_surface,
cairo_status_t status;
cairo_pdf_smask_group_t *group;
cairo_pdf_resource_t pattern_res, gstate_res;
- cairo_rectangle_int_t extents;
+ cairo_composite_rectangles_t extents;
+
+ status = _cairo_composite_rectangles_init_for_paint (&extents,
+ surface->width, surface->height,
+ op, source, clip);
+ if (unlikely (status)) {
+ if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
+ return CAIRO_STATUS_SUCCESS;
+
+ return status;
+ }
if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
- return _cairo_pdf_surface_analyze_operation (surface, op, source);
+ return _cairo_pdf_surface_analyze_operation (surface, op, source, &extents.bounded);
} else if (surface->paginated_mode == CAIRO_PAGINATED_MODE_FALLBACK) {
status = _cairo_pdf_surface_start_fallback (surface);
if (unlikely (status))
return status;
}
- assert (_cairo_pdf_surface_operation_supported (surface, op, source));
+ assert (_cairo_pdf_surface_operation_supported (surface, op, source, &extents.bounded));
status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
if (unlikely (status))
@@ -5339,8 +5331,8 @@ _cairo_pdf_surface_paint (void *abstract_surface,
return status;
if (source->type == CAIRO_PATTERN_TYPE_SURFACE &&
- source->extend == CAIRO_EXTEND_NONE) {
-
+ source->extend == CAIRO_EXTEND_NONE)
+ {
_cairo_output_stream_printf (surface->output, "q\n");
status = _cairo_pdf_surface_paint_surface_pattern (surface,
(cairo_surface_pattern_t *) source);
@@ -5351,15 +5343,10 @@ _cairo_pdf_surface_paint (void *abstract_surface,
return _cairo_output_stream_get_status (surface->output);
}
- status = _cairo_surface_paint_extents (&surface->base,
- op, source, clip,
- &extents);
- if (unlikely (status))
- return status;
-
pattern_res.id = 0;
gstate_res.id = 0;
- status = _cairo_pdf_surface_add_pdf_pattern (surface, source, &extents,
+ status = _cairo_pdf_surface_add_pdf_pattern (surface, source,
+ &extents.bounded,
&pattern_res, &gstate_res);
if (unlikely (status == CAIRO_INT_STATUS_NOTHING_TO_DO))
return CAIRO_STATUS_SUCCESS;
@@ -5424,18 +5411,29 @@ _cairo_pdf_surface_mask (void *abstract_surface,
cairo_pdf_surface_t *surface = abstract_surface;
cairo_pdf_smask_group_t *group;
cairo_status_t status;
+ cairo_composite_rectangles_t extents;
+
+ status = _cairo_composite_rectangles_init_for_mask (&extents,
+ surface->width, surface->height,
+ op, source, mask, clip);
+ if (unlikely (status)) {
+ if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
+ return CAIRO_STATUS_SUCCESS;
+
+ return status;
+ }
if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
cairo_status_t source_status, mask_status;
- source_status = _cairo_pdf_surface_analyze_operation (surface, op, source);
+ source_status = _cairo_pdf_surface_analyze_operation (surface, op, source, &extents.bounded);
if (_cairo_status_is_error (source_status))
return source_status;
if (mask->has_component_alpha) {
mask_status = CAIRO_INT_STATUS_UNSUPPORTED;
} else {
- mask_status = _cairo_pdf_surface_analyze_operation (surface, op, mask);
+ mask_status = _cairo_pdf_surface_analyze_operation (surface, op, mask, &extents.bounded);
if (_cairo_status_is_error (mask_status))
return mask_status;
}
@@ -5448,8 +5446,8 @@ _cairo_pdf_surface_mask (void *abstract_surface,
return status;
}
- assert (_cairo_pdf_surface_operation_supported (surface, op, source));
- assert (_cairo_pdf_surface_operation_supported (surface, op, mask));
+ assert (_cairo_pdf_surface_operation_supported (surface, op, source, &extents.bounded));
+ assert (_cairo_pdf_surface_operation_supported (surface, op, mask, &extents.bounded));
status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
if (unlikely (status))
@@ -5519,31 +5517,50 @@ _cairo_pdf_surface_stroke (void *abstract_surface,
cairo_clip_t *clip)
{
cairo_pdf_surface_t *surface = abstract_surface;
- cairo_status_t status;
cairo_pdf_smask_group_t *group;
cairo_pdf_resource_t pattern_res, gstate_res;
- cairo_rectangle_int_t extents;
+ cairo_composite_rectangles_t extents;
+ cairo_status_t status;
+
+ status = _cairo_composite_rectangles_init_for_stroke (&extents,
+ surface->width,
+ surface->height,
+ op, source,
+ path, style, ctm,
+ clip);
+ if (unlikely (status)) {
+ if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
+ return CAIRO_STATUS_SUCCESS;
+
+ return status;
+ }
+
+ /* use the more accurate extents */
+ if (extents.is_bounded) {
+ status = _cairo_path_fixed_stroke_extents (path, style,
+ ctm, ctm_inverse,
+ tolerance,
+ &extents.mask);
+ if (unlikely (status))
+ return status;
+
+ if (! _cairo_rectangle_intersect (&extents.bounded, &extents.mask))
+ return CAIRO_STATUS_SUCCESS;
+ }
if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
- return _cairo_pdf_surface_analyze_operation (surface, op, source);
+ return _cairo_pdf_surface_analyze_operation (surface, op, source, &extents.bounded);
- assert (_cairo_pdf_surface_operation_supported (surface, op, source));
+ assert (_cairo_pdf_surface_operation_supported (surface, op, source, &extents.bounded));
status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
if (unlikely (status))
return status;
- status = _cairo_surface_stroke_extents (&surface->base,
- op, source, path,
- style, ctm, ctm_inverse,
- tolerance, antialias,
- clip, &extents);
- if (unlikely (status))
- return status;
-
pattern_res.id = 0;
gstate_res.id = 0;
- status = _cairo_pdf_surface_add_pdf_pattern (surface, source, &extents,
+ status = _cairo_pdf_surface_add_pdf_pattern (surface, source,
+ &extents.bounded,
&pattern_res, &gstate_res);
if (unlikely (status == CAIRO_INT_STATUS_NOTHING_TO_DO))
return CAIRO_STATUS_SUCCESS;
@@ -5632,17 +5649,39 @@ _cairo_pdf_surface_fill (void *abstract_surface,
cairo_status_t status;
cairo_pdf_smask_group_t *group;
cairo_pdf_resource_t pattern_res, gstate_res;
- cairo_rectangle_int_t extents;
+ cairo_composite_rectangles_t extents;
+
+ status = _cairo_composite_rectangles_init_for_fill (&extents,
+ surface->width,
+ surface->height,
+ op, source, path,
+ clip);
+ if (unlikely (status)) {
+ if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
+ return CAIRO_STATUS_SUCCESS;
+
+ return status;
+ }
+
+ /* use the more accurate extents */
+ if (extents.is_bounded) {
+ _cairo_path_fixed_fill_extents (path,
+ tolerance, fill_rule,
+ &extents.mask);
+
+ if (! _cairo_rectangle_intersect (&extents.bounded, &extents.mask))
+ return CAIRO_STATUS_SUCCESS;
+ }
if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
- return _cairo_pdf_surface_analyze_operation (surface, op, source);
+ return _cairo_pdf_surface_analyze_operation (surface, op, source, &extents.bounded);
} else if (surface->paginated_mode == CAIRO_PAGINATED_MODE_FALLBACK) {
status = _cairo_pdf_surface_start_fallback (surface);
if (unlikely (status))
return status;
}
- assert (_cairo_pdf_surface_operation_supported (surface, op, source));
+ assert (_cairo_pdf_surface_operation_supported (surface, op, source, &extents.bounded));
status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
if (unlikely (status))
@@ -5653,8 +5692,8 @@ _cairo_pdf_surface_fill (void *abstract_surface,
return status;
if (source->type == CAIRO_PATTERN_TYPE_SURFACE &&
- source->extend == CAIRO_EXTEND_NONE) {
-
+ source->extend == CAIRO_EXTEND_NONE)
+ {
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
if (unlikely (status))
return status;
@@ -5675,16 +5714,10 @@ _cairo_pdf_surface_fill (void *abstract_surface,
return _cairo_output_stream_get_status (surface->output);
}
- status = _cairo_surface_fill_extents (&surface->base,
- op, source, path, fill_rule,
- tolerance, antialias,
- clip, &extents);
- if (unlikely (status))
- return status;
-
pattern_res.id = 0;
gstate_res.id = 0;
- status = _cairo_pdf_surface_add_pdf_pattern (surface, source, &extents,
+ status = _cairo_pdf_surface_add_pdf_pattern (surface, source,
+ &extents.bounded,
&pattern_res, &gstate_res);
if (unlikely (status == CAIRO_INT_STATUS_NOTHING_TO_DO))
return CAIRO_STATUS_SUCCESS;
@@ -5786,8 +5819,8 @@ _cairo_pdf_surface_fill_stroke (void *abstract_surface,
/* PDF rendering of fill-stroke is not the same as cairo when
* either the fill or stroke is not opaque.
*/
- if ( !_cairo_pattern_is_opaque (fill_source) ||
- !_cairo_pattern_is_opaque (stroke_source))
+ if ( !_cairo_pattern_is_opaque (fill_source, NULL) ||
+ !_cairo_pattern_is_opaque (stroke_source, NULL))
{
return CAIRO_INT_STATUS_UNSUPPORTED;
}
@@ -5891,30 +5924,40 @@ _cairo_pdf_surface_show_text_glyphs (void *abstract_surface,
cairo_clip_t *clip)
{
cairo_pdf_surface_t *surface = abstract_surface;
- cairo_status_t status;
cairo_pdf_smask_group_t *group;
cairo_pdf_resource_t pattern_res, gstate_res;
- cairo_rectangle_int_t extents;
+ cairo_composite_rectangles_t extents;
+ cairo_bool_t overlap;
+ cairo_status_t status;
+
+ status = _cairo_composite_rectangles_init_for_glyphs (&extents,
+ surface->width,
+ surface->height,
+ op, source,
+ scaled_font,
+ glyphs, num_glyphs,
+ clip,
+ &overlap);
+ if (unlikely (status)) {
+ if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
+ return CAIRO_STATUS_SUCCESS;
+
+ return status;
+ }
if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
- return _cairo_pdf_surface_analyze_operation (surface, op, source);
+ return _cairo_pdf_surface_analyze_operation (surface, op, source, &extents.bounded);
- assert (_cairo_pdf_surface_operation_supported (surface, op, source));
+ assert (_cairo_pdf_surface_operation_supported (surface, op, source, &extents.bounded));
status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
if (unlikely (status))
return status;
- status = _cairo_surface_glyphs_extents (&surface->base, op, source,
- glyphs, num_glyphs,
- scaled_font,
- clip, &extents);
- if (unlikely (status))
- return status;
-
pattern_res.id = 0;
gstate_res.id = 0;
- status = _cairo_pdf_surface_add_pdf_pattern (surface, source, &extents,
+ status = _cairo_pdf_surface_add_pdf_pattern (surface, source,
+ &extents.bounded,
&pattern_res, &gstate_res);
if (unlikely (status == CAIRO_INT_STATUS_NOTHING_TO_DO))
return CAIRO_STATUS_SUCCESS;
@@ -6000,7 +6043,7 @@ _cairo_pdf_surface_show_text_glyphs (void *abstract_surface,
* be in a separate text object otherwise overlapping text
* from separate calls to show_glyphs will not composite with
* each other. */
- if (! _cairo_pattern_is_opaque (source)) {
+ if (! _cairo_pattern_is_opaque (source, &extents.bounded)) {
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
if (unlikely (status))
return status;
diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c
index a50250f..3e48ebb 100644
--- a/src/cairo-ps-surface.c
+++ b/src/cairo-ps-surface.c
@@ -58,6 +58,7 @@
#include "cairo-ps.h"
#include "cairo-ps-surface-private.h"
#include "cairo-pdf-operators-private.h"
+#include "cairo-composite-rectangles-private.h"
#include "cairo-error-private.h"
#include "cairo-scaled-font-subsets-private.h"
#include "cairo-paginated-private.h"
@@ -1742,7 +1743,8 @@ pattern_supported (cairo_ps_surface_t *surface, const cairo_pattern_t *pattern)
static cairo_int_status_t
_cairo_ps_surface_analyze_operation (cairo_ps_surface_t *surface,
cairo_operator_t op,
- const cairo_pattern_t *pattern)
+ const cairo_pattern_t *pattern,
+ const cairo_rectangle_int_t *extents)
{
if (surface->force_fallbacks &&
surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
@@ -1788,7 +1790,7 @@ _cairo_ps_surface_analyze_operation (cairo_ps_surface_t *surface,
surface_pattern);
}
- if (_cairo_pattern_is_opaque (pattern))
+ if (_cairo_pattern_is_opaque (pattern, extents))
return CAIRO_STATUS_SUCCESS;
return CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY;
@@ -1797,12 +1799,10 @@ _cairo_ps_surface_analyze_operation (cairo_ps_surface_t *surface,
static cairo_bool_t
_cairo_ps_surface_operation_supported (cairo_ps_surface_t *surface,
cairo_operator_t op,
- const cairo_pattern_t *pattern)
+ const cairo_pattern_t *pattern,
+ const cairo_rectangle_int_t *extents)
{
- if (_cairo_ps_surface_analyze_operation (surface, op, pattern) != CAIRO_INT_STATUS_UNSUPPORTED)
- return TRUE;
- else
- return FALSE;
+ return _cairo_ps_surface_analyze_operation (surface, op, pattern, extents) != CAIRO_INT_STATUS_UNSUPPORTED;
}
/* The "standard" implementation limit for PostScript string sizes is
@@ -3437,28 +3437,32 @@ _cairo_ps_surface_paint (void *abstract_surface,
{
cairo_ps_surface_t *surface = abstract_surface;
cairo_output_stream_t *stream = surface->stream;
- cairo_rectangle_int_t extents;
+ cairo_composite_rectangles_t extents;
cairo_status_t status;
+ status = _cairo_composite_rectangles_init_for_paint (&extents,
+ surface->width, surface->height,
+ op, source, clip);
+ if (unlikely (status)) {
+ if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
+ return CAIRO_STATUS_SUCCESS;
+
+ return status;
+ }
+
+ if (! _cairo_rectangle_intersect (&extents.bounded, &surface->page_bbox))
+ return CAIRO_STATUS_SUCCESS;
+
if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
- return _cairo_ps_surface_analyze_operation (surface, op, source);
+ return _cairo_ps_surface_analyze_operation (surface, op, source, &extents.bounded);
- assert (_cairo_ps_surface_operation_supported (surface, op, source));
+ assert (_cairo_ps_surface_operation_supported (surface, op, source, &extents.bounded));
#if DEBUG_PS
_cairo_output_stream_printf (stream,
"%% _cairo_ps_surface_paint\n");
#endif
- status = _cairo_surface_paint_extents (&surface->base,
- op, source, clip,
- &extents);
- if (unlikely (status))
- return status;
-
- if (! _cairo_rectangle_intersect (&extents, &surface->page_bbox))
- return CAIRO_STATUS_SUCCESS;
-
status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
if (unlikely (status))
return status;
@@ -3474,13 +3478,13 @@ _cairo_ps_surface_paint (void *abstract_surface,
_cairo_output_stream_printf (stream, "q\n");
status = _cairo_ps_surface_paint_surface (surface,
(cairo_surface_pattern_t *) source,
- &extents, op);
+ &extents.bounded, op);
if (unlikely (status))
return status;
_cairo_output_stream_printf (stream, "Q\n");
} else {
- status = _cairo_ps_surface_emit_pattern (surface, source, &extents, op);
+ status = _cairo_ps_surface_emit_pattern (surface, source, &extents.bounded, op);
if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
return CAIRO_STATUS_SUCCESS;
@@ -3488,8 +3492,8 @@ _cairo_ps_surface_paint (void *abstract_surface,
return status;
_cairo_output_stream_printf (stream, "%d %d %d %d rectfill\n",
- extents.x, extents.y,
- extents.width, extents.height);
+ extents.bounded.x, extents.bounded.y,
+ extents.bounded.width, extents.bounded.height);
}
return CAIRO_STATUS_SUCCESS;
@@ -3508,36 +3512,54 @@ _cairo_ps_surface_stroke (void *abstract_surface,
cairo_clip_t *clip)
{
cairo_ps_surface_t *surface = abstract_surface;
+ cairo_composite_rectangles_t extents;
cairo_int_status_t status;
- cairo_rectangle_int_t extents;
+
+ status = _cairo_composite_rectangles_init_for_stroke (&extents,
+ surface->width,
+ surface->height,
+ op, source,
+ path, style, ctm,
+ clip);
+ if (unlikely (status)) {
+ if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
+ return CAIRO_STATUS_SUCCESS;
+
+ return status;
+ }
+
+ if (! _cairo_rectangle_intersect (&extents.bounded, &surface->page_bbox))
+ return CAIRO_STATUS_SUCCESS;
+
+ /* use the more accurate extents */
+ if (extents.is_bounded) {
+ status = _cairo_path_fixed_stroke_extents (path, style,
+ ctm, ctm_inverse,
+ tolerance,
+ &extents.mask);
+ if (unlikely (status))
+ return status;
+
+ if (! _cairo_rectangle_intersect (&extents.bounded, &extents.mask))
+ return CAIRO_STATUS_SUCCESS;
+ }
+
if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
- return _cairo_ps_surface_analyze_operation (surface, op, source);
+ return _cairo_ps_surface_analyze_operation (surface, op, source, &extents.bounded);
- assert (_cairo_ps_surface_operation_supported (surface, op, source));
+ assert (_cairo_ps_surface_operation_supported (surface, op, source, &extents.bounded));
#if DEBUG_PS
_cairo_output_stream_printf (surface->stream,
"%% _cairo_ps_surface_stroke\n");
#endif
- status = _cairo_surface_stroke_extents (&surface->base,
- op, source,
- path, style,
- ctm, ctm_inverse,
- tolerance, antialias,
- clip, &extents);
- if (unlikely (status))
- return status;
-
- if (! _cairo_rectangle_intersect (&extents, &surface->page_bbox))
- return CAIRO_STATUS_SUCCESS;
-
status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
if (unlikely (status))
return status;
- status = _cairo_ps_surface_emit_pattern (surface, source, &extents, op);
+ status = _cairo_ps_surface_emit_pattern (surface, source, &extents.bounded, op);
if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
return CAIRO_STATUS_SUCCESS;
@@ -3562,13 +3584,38 @@ _cairo_ps_surface_fill (void *abstract_surface,
cairo_clip_t *clip)
{
cairo_ps_surface_t *surface = abstract_surface;
+ cairo_composite_rectangles_t extents;
cairo_int_status_t status;
- cairo_rectangle_int_t extents;
+
+ status = _cairo_composite_rectangles_init_for_fill (&extents,
+ surface->width,
+ surface->height,
+ op, source, path,
+ clip);
+ if (unlikely (status)) {
+ if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
+ return CAIRO_STATUS_SUCCESS;
+
+ return status;
+ }
+
+ if (! _cairo_rectangle_intersect (&extents.bounded, &surface->page_bbox))
+ return CAIRO_STATUS_SUCCESS;
+
+ /* use the more accurate extents */
+ if (extents.is_bounded) {
+ _cairo_path_fixed_fill_extents (path,
+ tolerance, fill_rule,
+ &extents.mask);
+
+ if (! _cairo_rectangle_intersect (&extents.bounded, &extents.mask))
+ return CAIRO_STATUS_SUCCESS;
+ }
if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
- return _cairo_ps_surface_analyze_operation (surface, op, source);
+ return _cairo_ps_surface_analyze_operation (surface, op, source, &extents.bounded);
- assert (_cairo_ps_surface_operation_supported (surface, op, source));
+ assert (_cairo_ps_surface_operation_supported (surface, op, source, &extents.bounded));
#if DEBUG_PS
_cairo_output_stream_printf (surface->stream,
@@ -3579,17 +3626,6 @@ _cairo_ps_surface_fill (void *abstract_surface,
if (unlikely (status))
return status;
- status = _cairo_surface_fill_extents (&surface->base,
- op, source,
- path, fill_rule,
- tolerance, antialias,
- clip, &extents);
- if (unlikely (status))
- return status;
-
- if (! _cairo_rectangle_intersect (&extents, &surface->page_bbox))
- return CAIRO_STATUS_SUCCESS;
-
status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
if (unlikely (status))
return status;
@@ -3608,14 +3644,14 @@ _cairo_ps_surface_fill (void *abstract_surface,
status = _cairo_ps_surface_paint_surface (surface,
(cairo_surface_pattern_t *) source,
- &extents, op);
+ &extents.bounded, op);
if (unlikely (status))
return status;
_cairo_output_stream_printf (surface->stream, "Q\n");
_cairo_pdf_operators_reset (&surface->pdf_operators);
} else {
- status = _cairo_ps_surface_emit_pattern (surface, source, &extents, op);
+ status = _cairo_ps_surface_emit_pattern (surface, source, &extents.bounded, op);
if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
return CAIRO_STATUS_SUCCESS;
@@ -3641,38 +3677,40 @@ _cairo_ps_surface_show_glyphs (void *abstract_surface,
int *remaining_glyphs)
{
cairo_ps_surface_t *surface = abstract_surface;
+ cairo_composite_rectangles_t extents;
+ cairo_bool_t overlap;
cairo_status_t status;
- cairo_rectangle_int_t extents;
+
+ status = _cairo_composite_rectangles_init_for_glyphs (&extents,
+ surface->width,
+ surface->height,
+ op, source,
+ scaled_font,
+ glyphs, num_glyphs,
+ clip,
+ &overlap);
+ if (unlikely (status)) {
+ if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
+ return CAIRO_STATUS_SUCCESS;
+
+ return status;
+ }
if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
- return _cairo_ps_surface_analyze_operation (surface, op, source);
+ return _cairo_ps_surface_analyze_operation (surface, op, source, &extents.bounded);
- assert (_cairo_ps_surface_operation_supported (surface, op, source));
+ assert (_cairo_ps_surface_operation_supported (surface, op, source, &extents.bounded));
#if DEBUG_PS
_cairo_output_stream_printf (surface->stream,
"%% _cairo_ps_surface_show_glyphs\n");
#endif
- if (num_glyphs <= 0)
- return CAIRO_STATUS_SUCCESS;
-
- status = _cairo_surface_glyphs_extents (&surface->base,
- op, source,
- glyphs, num_glyphs,
- scaled_font,
- clip, &extents);
- if (unlikely (status))
- return status;
-
- if (! _cairo_rectangle_intersect (&extents, &surface->page_bbox))
- return CAIRO_STATUS_SUCCESS;
-
status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
if (unlikely (status))
return status;
- status = _cairo_ps_surface_emit_pattern (surface, source, &extents, op);
+ status = _cairo_ps_surface_emit_pattern (surface, source, &extents.bounded, op);
if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
return CAIRO_STATUS_SUCCESS;
@@ -3729,7 +3767,7 @@ _cairo_ps_surface_set_bounding_box (void *abstract_surface,
surface->page_bbox.x = x1;
surface->page_bbox.y = y1;
- surface->page_bbox.width = x2 - x1;
+ surface->page_bbox.width = x2 - x1;
surface->page_bbox.height = y2 - y1;
_cairo_output_stream_printf (surface->stream,
diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c
index 918e4ad..6d42719 100644
--- a/src/cairo-xlib-surface.c
+++ b/src/cairo-xlib-surface.c
@@ -2165,6 +2165,7 @@ _cairo_xlib_surface_composite (cairo_operator_t op,
cairo_xlib_surface_t *src;
cairo_xlib_surface_t *mask;
cairo_int_status_t status;
+ cairo_rectangle_int_t src_extents;
composite_operation_t operation;
int itx, ity;
cairo_bool_t is_integer_translation;
@@ -2181,10 +2182,15 @@ _cairo_xlib_surface_composite (cairo_operator_t op,
X_DEBUG ((dst->dpy, "composite (dst=%x)", (unsigned int) dst->drawable));
+ src_extents.x = src_x;
+ src_extents.y = src_y;
+ src_extents.width = width;
+ src_extents.height = height;
needs_alpha_composite =
_operator_needs_alpha_composite (op,
_surface_has_alpha (dst),
- ! _cairo_pattern_is_opaque (src_pattern));
+ ! _cairo_pattern_is_opaque (src_pattern,
+ &src_extents));
_cairo_xlib_display_notify (dst->display);
diff --git a/src/cairoint.h b/src/cairoint.h
index aea2b92..d791c8c 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -2527,7 +2527,8 @@ cairo_private cairo_bool_t
_cairo_pattern_is_opaque_solid (const cairo_pattern_t *pattern);
cairo_private cairo_bool_t
-_cairo_pattern_is_opaque (const cairo_pattern_t *abstract_pattern);
+_cairo_pattern_is_opaque (const cairo_pattern_t *pattern,
+ const cairo_rectangle_int_t *extents);
enum {
CAIRO_PATTERN_ACQUIRE_NONE = 0x0,
commit b07de014eba1a482747ac235670011972a82d19d
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Tue Jan 19 18:44:34 2010 +0000
spans: Add a rectangular scan converter
This is a highly specialised scan converter for the relatively common
case of where the input geometry is known to be a series of rectangles.
Generally not device aligned (or else we would most likely have chosen
an even higher performance path that does not require a coverage mask),
this optimised converter can simply compute the analytical coverage by
utilising a special case Bentley-Ottmann intersection finder.
diff --git a/src/Makefile.sources b/src/Makefile.sources
index 0f01234..8d68860 100644
--- a/src/Makefile.sources
+++ b/src/Makefile.sources
@@ -150,6 +150,7 @@ cairo_sources = \
cairo-pen.c \
cairo-polygon.c \
cairo-rectangle.c \
+ cairo-rectangular-scan-converter.c \
cairo-region.c \
cairo-rtree.c \
cairo-scaled-font.c \
diff --git a/src/cairo-rectangular-scan-converter.c b/src/cairo-rectangular-scan-converter.c
new file mode 100644
index 0000000..20717df
--- /dev/null
+++ b/src/cairo-rectangular-scan-converter.c
@@ -0,0 +1,723 @@
+/* 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.
+ *
+ * Contributor(s):
+ * Chris Wilson <chris at chris-wilson.co.uk>
+ */
+
+#include "cairoint.h"
+
+#include "cairo-combsort-private.h"
+#include "cairo-error-private.h"
+#include "cairo-freelist-private.h"
+#include "cairo-list-private.h"
+#include "cairo-spans-private.h"
+
+#include <setjmp.h>
+
+typedef struct _rectangle {
+ struct _rectangle *next, *prev;
+ cairo_fixed_t left, right;
+ cairo_fixed_t top, bottom;
+ int32_t top_y, bottom_y;
+ int dir;
+} rectangle_t;
+
+#define UNROLL3(x) x x x
+
+/* the parent is always given by index/2 */
+#define PQ_PARENT_INDEX(i) ((i) >> 1)
+#define PQ_FIRST_ENTRY 1
+
+/* left and right children are index * 2 and (index * 2) +1 respectively */
+#define PQ_LEFT_CHILD_INDEX(i) ((i) << 1)
+
+typedef struct _pqueue {
+ int size, max_size;
+
+ rectangle_t **elements;
+ rectangle_t *elements_embedded[1024];
+} pqueue_t;
+
+typedef struct {
+ rectangle_t **start;
+ pqueue_t stop;
+ rectangle_t head, tail;
+ rectangle_t *insert_cursor;
+ int32_t current_y;
+ int32_t xmin, xmax;
+
+ struct coverage {
+ struct cell {
+ struct cell *prev, *next;
+ int x, covered, uncovered;
+ } head, tail, *cursor;
+ unsigned int count;
+ cairo_freepool_t pool;
+ } coverage;
+
+ cairo_half_open_span_t spans_stack[CAIRO_STACK_ARRAY_LENGTH (cairo_half_open_span_t)];
+ cairo_half_open_span_t *spans;
+ unsigned int num_spans;
+ unsigned int size_spans;
+
+ jmp_buf jmpbuf;
+} sweep_line_t;
+
+static inline int
+rectangle_compare_start (const rectangle_t *a,
+ const rectangle_t *b)
+{
+ int cmp;
+
+ cmp = a->top_y - b->top_y;
+ if (cmp)
+ return cmp;
+
+ return a->left - b->left;
+}
+
+static inline int
+rectangle_compare_stop (const rectangle_t *a,
+ const rectangle_t *b)
+{
+ return a->bottom_y - b->bottom_y;
+}
+
+static inline void
+pqueue_init (pqueue_t *pq)
+{
+ pq->max_size = ARRAY_LENGTH (pq->elements_embedded);
+ pq->size = 0;
+
+ pq->elements = pq->elements_embedded;
+ pq->elements[PQ_FIRST_ENTRY] = NULL;
+}
+
+static inline void
+pqueue_fini (pqueue_t *pq)
+{
+ if (pq->elements != pq->elements_embedded)
+ free (pq->elements);
+}
+
+static cairo_bool_t
+pqueue_grow (pqueue_t *pq)
+{
+ rectangle_t **new_elements;
+ pq->max_size *= 2;
+
+ if (pq->elements == pq->elements_embedded) {
+ new_elements = _cairo_malloc_ab (pq->max_size,
+ sizeof (rectangle_t *));
+ if (unlikely (new_elements == NULL))
+ return FALSE;
+
+ memcpy (new_elements, pq->elements_embedded,
+ sizeof (pq->elements_embedded));
+ } else {
+ new_elements = _cairo_realloc_ab (pq->elements,
+ pq->max_size,
+ sizeof (rectangle_t *));
+ if (unlikely (new_elements == NULL))
+ return FALSE;
+ }
+
+ pq->elements = new_elements;
+ return TRUE;
+}
+
+static inline void
+pqueue_push (sweep_line_t *sweep, rectangle_t *rectangle)
+{
+ rectangle_t **elements;
+ int i, parent;
+
+ if (unlikely (sweep->stop.size + 1 == sweep->stop.max_size)) {
+ if (unlikely (! pqueue_grow (&sweep->stop)))
+ longjmp (sweep->jmpbuf,
+ _cairo_error (CAIRO_STATUS_NO_MEMORY));
+ }
+
+ elements = sweep->stop.elements;
+ for (i = ++sweep->stop.size;
+ i != PQ_FIRST_ENTRY &&
+ rectangle_compare_stop (rectangle,
+ elements[parent = PQ_PARENT_INDEX (i)]) < 0;
+ i = parent)
+ {
+ elements[i] = elements[parent];
+ }
+
+ elements[i] = rectangle;
+}
+
+static inline void
+pqueue_pop (pqueue_t *pq)
+{
+ rectangle_t **elements = pq->elements;
+ rectangle_t *tail;
+ int child, i;
+
+ tail = elements[pq->size--];
+ if (pq->size == 0) {
+ elements[PQ_FIRST_ENTRY] = NULL;
+ return;
+ }
+
+ for (i = PQ_FIRST_ENTRY;
+ (child = PQ_LEFT_CHILD_INDEX (i)) <= pq->size;
+ i = child)
+ {
+ if (child != pq->size &&
+ rectangle_compare_stop (elements[child+1],
+ elements[child]) < 0)
+ {
+ child++;
+ }
+
+ if (rectangle_compare_stop (elements[child], tail) >= 0)
+ break;
+
+ elements[i] = elements[child];
+ }
+ elements[i] = tail;
+}
+
+static inline rectangle_t *
+peek_stop (sweep_line_t *sweep)
+{
+ return sweep->stop.elements[PQ_FIRST_ENTRY];
+}
+
+CAIRO_COMBSORT_DECLARE (rectangle_sort, rectangle_t *, rectangle_compare_start)
+
+static void
+sweep_line_init (sweep_line_t *sweep)
+{
+ sweep->head.left = INT_MIN;
+ sweep->head.next = &sweep->tail;
+ sweep->tail.left = INT_MAX;
+ sweep->tail.prev = &sweep->head;
+ sweep->insert_cursor = &sweep->tail;
+
+ _cairo_freepool_init (&sweep->coverage.pool, sizeof (struct cell));
+
+ sweep->spans = sweep->spans_stack;
+ sweep->size_spans = ARRAY_LENGTH (sweep->spans_stack);
+
+ sweep->coverage.head.prev = NULL;
+ sweep->coverage.head.x = INT_MIN;
+ sweep->coverage.tail.next = NULL;
+ sweep->coverage.tail.x = INT_MAX;
+
+ pqueue_init (&sweep->stop);
+}
+
+static void
+sweep_line_fini (sweep_line_t *sweep)
+{
+ _cairo_freepool_fini (&sweep->coverage.pool);
+ pqueue_fini (&sweep->stop);
+
+ if (sweep->spans != sweep->spans_stack)
+ free (sweep->spans);
+}
+
+static inline void
+add_cell (sweep_line_t *sweep, int x, int covered, int uncovered)
+{
+ struct cell *cell;
+
+ cell = sweep->coverage.cursor;
+ if (cell->x > x) {
+ do {
+ UNROLL3({
+ if (cell->prev->x < x)
+ break;
+ cell = cell->prev;
+ })
+ } while (TRUE);
+ } else {
+ if (cell->x == x)
+ goto found;
+
+ do {
+ UNROLL3({
+ cell = cell->next;
+ if (cell->x >= x)
+ break;
+ })
+ } while (TRUE);
+ }
+
+ if (x != cell->x) {
+ struct cell *c;
+
+ sweep->coverage.count++;
+
+ c = _cairo_freepool_alloc (&sweep->coverage.pool);
+ if (unlikely (c == NULL)) {
+ longjmp (sweep->jmpbuf,
+ _cairo_error (CAIRO_STATUS_NO_MEMORY));
+ }
+
+ cell->prev->next = c;
+ c->prev = cell->prev;
+ c->next = cell;
+ cell->prev = c;
+
+ c->x = x;
+ c->covered = 0;
+ c->uncovered = 0;
+
+ cell = c;
+ }
+
+found:
+ cell->covered += covered;
+ cell->uncovered += uncovered;
+ sweep->coverage.cursor = cell;
+}
+
+static inline void
+_active_edges_to_spans (sweep_line_t *sweep)
+{
+ int32_t y = sweep->current_y;
+ rectangle_t *rectangle;
+ int coverage, prev_coverage;
+ int prev_x;
+ struct cell *cell;
+
+ sweep->num_spans = 0;
+ if (sweep->head.next == &sweep->tail)
+ return;
+
+ sweep->coverage.head.next = &sweep->coverage.tail;
+ sweep->coverage.tail.prev = &sweep->coverage.head;
+ sweep->coverage.cursor = &sweep->coverage.tail;
+ sweep->coverage.count = 0;
+
+ /* XXX cell coverage only changes when a rectangle appears or
+ * disappears. Try only modifying coverage at such times.
+ */
+ for (rectangle = sweep->head.next;
+ rectangle != &sweep->tail;
+ rectangle = rectangle->next)
+ {
+ int height;
+ int frac, i;
+
+ if (y == rectangle->bottom_y) {
+ height = rectangle->bottom & CAIRO_FIXED_FRAC_MASK;
+ if (height == 0)
+ continue;
+ } else
+ height = CAIRO_FIXED_ONE;
+ if (y == rectangle->top_y)
+ height -= rectangle->top & CAIRO_FIXED_FRAC_MASK;
+ height *= rectangle->dir;
+
+ i = _cairo_fixed_integer_part (rectangle->left),
+ frac = _cairo_fixed_fractional_part (rectangle->left);
+ add_cell (sweep, i,
+ (CAIRO_FIXED_ONE-frac) * height,
+ frac * height);
+
+ i = _cairo_fixed_integer_part (rectangle->right),
+ frac = _cairo_fixed_fractional_part (rectangle->right);
+ add_cell (sweep, i,
+ -(CAIRO_FIXED_ONE-frac) * height,
+ -frac * height);
+ }
+
+ if (2*sweep->coverage.count >= sweep->size_spans) {
+ unsigned size;
+
+ size = sweep->size_spans;
+ while (size <= 2*sweep->coverage.count)
+ size <<= 1;
+
+ if (sweep->spans != sweep->spans_stack)
+ free (sweep->spans);
+
+ sweep->spans = _cairo_malloc_ab (size, sizeof (cairo_half_open_span_t));
+ if (unlikely (sweep->spans == NULL))
+ longjmp (sweep->jmpbuf, _cairo_error (CAIRO_STATUS_NO_MEMORY));
+
+ sweep->size_spans = size;
+ }
+
+ prev_coverage = coverage = 0;
+ prev_x = INT_MIN;
+ for (cell = sweep->coverage.head.next; cell != &sweep->coverage.tail; cell = cell->next) {
+ if (cell->x != prev_x && coverage != prev_coverage) {
+ int n = sweep->num_spans++;
+ sweep->spans[n].x = prev_x;
+ sweep->spans[n].coverage = coverage >> (CAIRO_FIXED_FRAC_BITS * 2 - 8);
+ sweep->spans[n].coverage -= sweep->spans[n].coverage >> 8;
+ prev_coverage = coverage;
+ }
+
+ coverage += cell->covered;
+ if (coverage != prev_coverage) {
+ int n = sweep->num_spans++;
+ sweep->spans[n].x = cell->x;
+ sweep->spans[n].coverage = coverage >> (CAIRO_FIXED_FRAC_BITS * 2 - 8);
+ sweep->spans[n].coverage -= sweep->spans[n].coverage >> 8;
+ prev_coverage = coverage;
+ }
+ coverage += cell->uncovered;
+ prev_x = cell->x + 1;
+ }
+ _cairo_freepool_reset (&sweep->coverage.pool);
+
+ if (sweep->num_spans) {
+ if (prev_x <= sweep->xmax) {
+ int n = sweep->num_spans++;
+ sweep->spans[n].x = prev_x;
+ sweep->spans[n].coverage = coverage;
+ }
+
+ if (coverage && prev_x < sweep->xmax) {
+ int n = sweep->num_spans++;
+ sweep->spans[n].x = sweep->xmax;
+ sweep->spans[n].coverage = 0;
+ }
+ }
+}
+
+static inline void
+sweep_line_delete (sweep_line_t *sweep,
+ rectangle_t *rectangle)
+{
+ if (sweep->insert_cursor == rectangle)
+ sweep->insert_cursor = rectangle->next;
+
+ rectangle->prev->next = rectangle->next;
+ rectangle->next->prev = rectangle->prev;
+
+ pqueue_pop (&sweep->stop);
+}
+
+static inline void
+sweep_line_insert (sweep_line_t *sweep,
+ rectangle_t *rectangle)
+{
+ rectangle_t *pos;
+
+ pos = sweep->insert_cursor;
+ if (pos->left != rectangle->left) {
+ if (pos->left > rectangle->left) {
+ do {
+ UNROLL3({
+ if (pos->prev->left < rectangle->left)
+ break;
+ pos = pos->prev;
+ })
+ } while (TRUE);
+ } else {
+ do {
+ UNROLL3({
+ pos = pos->next;
+ if (pos->left >= rectangle->left)
+ break;
+ });
+ } while (TRUE);
+ }
+ }
+
+ pos->prev->next = rectangle;
+ rectangle->prev = pos->prev;
+ rectangle->next = pos;
+ pos->prev = rectangle;
+ sweep->insert_cursor = rectangle;
+
+ pqueue_push (sweep, rectangle);
+}
+
+static void
+render_rows (sweep_line_t *sweep_line,
+ cairo_span_renderer_t *renderer,
+ int height)
+{
+ cairo_status_t status;
+
+ _active_edges_to_spans (sweep_line);
+
+ status = renderer->render_rows (renderer,
+ sweep_line->current_y, height,
+ sweep_line->spans,
+ sweep_line->num_spans);
+ if (unlikely (status))
+ longjmp (sweep_line->jmpbuf, status);
+}
+
+static cairo_status_t
+generate (cairo_rectangular_scan_converter_t *self,
+ cairo_span_renderer_t *renderer,
+ rectangle_t **rectangles)
+{
+ sweep_line_t sweep_line;
+ rectangle_t *start, *stop;
+ cairo_status_t status;
+
+ sweep_line_init (&sweep_line);
+ sweep_line.xmin = self->xmin;
+ sweep_line.xmax = self->xmax;
+ sweep_line.start = rectangles;
+ if ((status = setjmp (sweep_line.jmpbuf)))
+ goto BAIL;
+
+ sweep_line.current_y = self->ymin;
+ start = *sweep_line.start++;
+ do {
+ if (start->top_y != sweep_line.current_y) {
+ render_rows (&sweep_line, renderer,
+ start->top_y - sweep_line.current_y);
+ sweep_line.current_y = start->top_y;
+ }
+
+ do {
+ sweep_line_insert (&sweep_line, start);
+ start = *sweep_line.start++;
+ if (start == NULL)
+ goto end;
+ if (start->top_y != sweep_line.current_y)
+ break;
+ } while (TRUE);
+
+ render_rows (&sweep_line, renderer, 1);
+
+ stop = peek_stop (&sweep_line);
+ while (stop->bottom_y == sweep_line.current_y) {
+ sweep_line_delete (&sweep_line, stop);
+ stop = peek_stop (&sweep_line);
+ if (stop == NULL)
+ break;
+ }
+
+ sweep_line.current_y++;
+
+ while (stop != NULL && stop->bottom_y < start->top_y) {
+ if (stop->bottom_y != sweep_line.current_y) {
+ render_rows (&sweep_line, renderer,
+ stop->bottom_y - sweep_line.current_y);
+ sweep_line.current_y = stop->bottom_y;
+ }
+
+ render_rows (&sweep_line, renderer, 1);
+
+ do {
+ sweep_line_delete (&sweep_line, stop);
+ stop = peek_stop (&sweep_line);
+ } while (stop != NULL && stop->bottom_y == sweep_line.current_y);
+
+ sweep_line.current_y++;
+ }
+ } while (TRUE);
+
+ end:
+ render_rows (&sweep_line, renderer, 1);
+
+ stop = peek_stop (&sweep_line);
+ while (stop->bottom_y == sweep_line.current_y) {
+ sweep_line_delete (&sweep_line, stop);
+ stop = peek_stop (&sweep_line);
+ if (stop == NULL)
+ goto out;
+ }
+
+ sweep_line.current_y++;
+
+ do {
+ if (stop->bottom_y != sweep_line.current_y) {
+ render_rows (&sweep_line, renderer,
+ stop->bottom_y - sweep_line.current_y);
+ sweep_line.current_y = stop->bottom_y;
+ }
+
+ render_rows (&sweep_line, renderer, 1);
+
+ do {
+ sweep_line_delete (&sweep_line, stop);
+ stop = peek_stop (&sweep_line);
+ if (stop == NULL)
+ goto out;
+ } while (stop->bottom_y == sweep_line.current_y);
+
+ sweep_line.current_y++;
+ } while (TRUE);
+
+ out:
+ status = renderer->render_rows (renderer,
+ sweep_line.current_y,
+ self->ymax - sweep_line.current_y,
+ NULL, 0);
+
+ BAIL:
+ sweep_line_fini (&sweep_line);
+
+ return status;
+}
+
+static cairo_status_t
+_cairo_rectangular_scan_converter_generate (void *converter,
+ cairo_span_renderer_t *renderer)
+{
+ cairo_rectangular_scan_converter_t *self = converter;
+ rectangle_t *rectangles_stack[CAIRO_STACK_ARRAY_LENGTH (rectangle_t *)];
+ rectangle_t **rectangles;
+ struct _cairo_rectangular_scan_converter_chunk *chunk;
+ cairo_status_t status;
+ int i, j;
+
+ if (unlikely (self->num_rectangles == 0)) {
+ return renderer->render_rows (renderer,
+ self->ymin, self->ymax - self->ymin,
+ NULL, 0);
+ }
+
+ rectangles = rectangles_stack;
+ if (unlikely (self->num_rectangles >= ARRAY_LENGTH (rectangles_stack))) {
+ rectangles = _cairo_malloc_ab (self->num_rectangles + 1,
+ sizeof (rectangle_t *));
+ if (unlikely (rectangles == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ }
+
+ j = 0;
+ for (chunk = &self->chunks; chunk != NULL; chunk = chunk->next) {
+ rectangle_t *rectangle;
+
+ rectangle = chunk->base;
+ for (i = 0; i < chunk->count; i++)
+ rectangles[j++] = &rectangle[i];
+ }
+ rectangle_sort (rectangles, j);
+ rectangles[j] = NULL;
+
+ status = generate (self, renderer, rectangles);
+
+ if (rectangles != rectangles_stack)
+ free (rectangles);
+
+ return status;
+}
+
+static rectangle_t *
+_allocate_rectangle (cairo_rectangular_scan_converter_t *self)
+{
+ rectangle_t *rectangle;
+ struct _cairo_rectangular_scan_converter_chunk *chunk;
+
+ chunk = self->tail;
+ if (chunk->count == chunk->size) {
+ int size;
+
+ size = chunk->size * 2;
+ chunk->next = _cairo_malloc_ab_plus_c (size,
+ sizeof (rectangle_t),
+ sizeof (struct _cairo_rectangular_scan_converter_chunk));
+
+ if (unlikely (chunk->next == NULL))
+ return NULL;
+
+ chunk = chunk->next;
+ chunk->next = NULL;
+ chunk->count = 0;
+ chunk->size = size;
+ chunk->base = chunk + 1;
+ self->tail = chunk;
+ }
+
+ rectangle = chunk->base;
+ return rectangle + chunk->count++;
+}
+
+cairo_status_t
+_cairo_rectangular_scan_converter_add_box (cairo_rectangular_scan_converter_t *self,
+ const cairo_box_t *box,
+ int dir)
+{
+ rectangle_t *rectangle;
+
+ rectangle = _allocate_rectangle (self);
+ if (unlikely (rectangle == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+ rectangle->left = box->p1.x;
+ rectangle->right = box->p2.x;
+ rectangle->dir = dir;
+
+ rectangle->top = box->p1.y;
+ rectangle->top_y = _cairo_fixed_integer_floor (box->p1.y);
+ rectangle->bottom = box->p2.y;
+ rectangle->bottom_y = _cairo_fixed_integer_floor (box->p2.y);
+ assert (rectangle->bottom_y >= rectangle->top_y);
+
+ self->num_rectangles++;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static void
+_cairo_rectangular_scan_converter_destroy (void *converter)
+{
+ cairo_rectangular_scan_converter_t *self = converter;
+ struct _cairo_rectangular_scan_converter_chunk *chunk, *next;
+
+ for (chunk = self->chunks.next; chunk != NULL; chunk = next) {
+ next = chunk->next;
+ free (chunk);
+ }
+}
+
+void
+_cairo_rectangular_scan_converter_init (cairo_rectangular_scan_converter_t *self,
+ const cairo_rectangle_int_t *extents)
+{
+ self->base.destroy = _cairo_rectangular_scan_converter_destroy;
+ self->base.add_edge = NULL;
+ self->base.add_polygon = NULL;
+ self->base.generate = _cairo_rectangular_scan_converter_generate;
+
+ self->xmin = extents->x;
+ self->xmax = extents->x + extents->width;
+ self->ymin = extents->y;
+ self->ymax = extents->y + extents->height;
+
+ self->chunks.base = self->buf;
+ self->chunks.next = NULL;
+ self->chunks.count = 0;
+ self->chunks.size = sizeof (self->buf) / sizeof (rectangle_t);
+ self->tail = &self->chunks;
+
+ self->num_rectangles = 0;
+}
diff --git a/src/cairo-spans-private.h b/src/cairo-spans-private.h
index c2be867..e7e9656 100644
--- a/src/cairo-spans-private.h
+++ b/src/cairo-spans-private.h
@@ -103,6 +103,31 @@ _cairo_tor_scan_converter_create (int xmin,
int ymax,
cairo_fill_rule_t fill_rule);
+typedef struct _cairo_rectangular_scan_converter {
+ cairo_scan_converter_t base;
+
+ int xmin, xmax;
+ int ymin, ymax;
+
+ struct _cairo_rectangular_scan_converter_chunk {
+ struct _cairo_rectangular_scan_converter_chunk *next;
+ void *base;
+ int count;
+ int size;
+ } chunks, *tail;
+ char buf[CAIRO_STACK_BUFFER_SIZE];
+ int num_rectangles;
+} cairo_rectangular_scan_converter_t;
+
+cairo_private void
+_cairo_rectangular_scan_converter_init (cairo_rectangular_scan_converter_t *self,
+ const cairo_rectangle_int_t *extents);
+
+cairo_private cairo_status_t
+_cairo_rectangular_scan_converter_add_box (cairo_rectangular_scan_converter_t *self,
+ const cairo_box_t *box,
+ int dir);
+
typedef struct _cairo_botor_scan_converter {
cairo_scan_converter_t base;
commit e49855497e7214c21c85b03d7ab94e9e008f821b
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Tue Jan 19 18:36:20 2010 +0000
spans: Add a Bentley-Ottmann variant on the Tor scan converter
This variant uses the Bentley-Ottmann algorithm to only maintain the
active edge list upon edge events and so can efficiently skip areas
where no change occurs. This means that it can be much quicker than the
Tor algorithm (which is still used to compute the coverages from the
active edges) for geometries consisting of long straight lines with few
intersections. However due to the computational overhead of the
Bentley-Ottmann event processing, for dense curvy paths, simply updating
the active edge list in sync with computing the coverages is a win. Due
to advantageous adaptive step size, the scan converter can be run at a
much higher subsampling with little extra overhead compared with Tor,
currently it uses a 256x256 subsampling grid to avoid any impedance
mismatch with path precision.
Given the current status of implementations, this scan converter [botor]
is likely to be advantage where detecting large regions of unchanged
span data will result in improved performance, for instance the drm
backends which convert the scan data into rectangles.
diff --git a/src/Makefile.sources b/src/Makefile.sources
index ad7428a..0f01234 100644
--- a/src/Makefile.sources
+++ b/src/Makefile.sources
@@ -112,6 +112,7 @@ cairo_sources = \
cairo-bentley-ottmann.c \
cairo-bentley-ottmann-rectangular.c \
cairo-bentley-ottmann-rectilinear.c \
+ cairo-botor-scan-converter.c \
cairo-boxes.c \
cairo.c \
cairo-cache.c \
diff --git a/src/cairo-botor-scan-converter.c b/src/cairo-botor-scan-converter.c
new file mode 100644
index 0000000..e6113fb
--- /dev/null
+++ b/src/cairo-botor-scan-converter.c
@@ -0,0 +1,2199 @@
+/*
+ * Copyright © 2004 Carl Worth
+ * Copyright © 2006 Red Hat, Inc.
+ * Copyright © 2007 David Turner
+ * Copyright © 2008 M Joonas Pihlaja
+ * Copyright © 2008 Chris Wilson
+ * 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 Carl Worth
+ *
+ * Contributor(s):
+ * Carl D. Worth <cworth at cworth.org>
+ * M Joonas Pihlaja <jpihlaja at cc.helsinki.fi>
+ * Chris Wilson <chris at chris-wilson.co.uk>
+ */
+
+/* Provide definitions for standalone compilation */
+#include "cairoint.h"
+
+#include "cairo-error-private.h"
+#include "cairo-list-private.h"
+#include "cairo-freelist-private.h"
+#include "cairo-combsort-private.h"
+
+#include <setjmp.h>
+
+#define STEP_X CAIRO_FIXED_ONE
+#define STEP_Y CAIRO_FIXED_ONE
+#define UNROLL3(x) x x x
+
+#define STEP_XY (2*STEP_X*STEP_Y) /* Unit area in the step. */
+#define AREA_TO_ALPHA(c) (((c)*255 + STEP_XY/2) / STEP_XY)
+
+typedef struct _cairo_bo_intersect_ordinate {
+ int32_t ordinate;
+ enum { EXACT, INEXACT } exactness;
+} cairo_bo_intersect_ordinate_t;
+
+typedef struct _cairo_bo_intersect_point {
+ cairo_bo_intersect_ordinate_t x;
+ cairo_bo_intersect_ordinate_t y;
+} cairo_bo_intersect_point_t;
+
+struct quorem {
+ cairo_fixed_t quo;
+ cairo_fixed_t rem;
+};
+
+struct run {
+ struct run *next;
+ int sign;
+ cairo_fixed_t y;
+};
+
+typedef struct edge {
+ cairo_list_t link;
+
+ cairo_edge_t edge;
+
+ /* Current x coordinate and advancement.
+ * Initialised to the x coordinate of the top of the
+ * edge. The quotient is in cairo_fixed_t units and the
+ * remainder is mod dy in cairo_fixed_t units.
+ */
+ cairo_fixed_t dy;
+ struct quorem x;
+ struct quorem dxdy;
+ struct quorem dxdy_full;
+
+ cairo_bool_t vertical;
+ unsigned int flags;
+
+ int current_sign;
+ struct run *runs;
+} edge_t;
+
+enum {
+ START = 0x1,
+ STOP = 0x2,
+};
+
+/* the parent is always given by index/2 */
+#define PQ_PARENT_INDEX(i) ((i) >> 1)
+#define PQ_FIRST_ENTRY 1
+
+/* left and right children are index * 2 and (index * 2) +1 respectively */
+#define PQ_LEFT_CHILD_INDEX(i) ((i) << 1)
+
+typedef enum {
+ EVENT_TYPE_STOP,
+ EVENT_TYPE_INTERSECTION,
+ EVENT_TYPE_START
+} event_type_t;
+
+typedef struct _event {
+ cairo_fixed_t y;
+ event_type_t type;
+} event_t;
+
+typedef struct _start_event {
+ cairo_fixed_t y;
+ event_type_t type;
+ edge_t *edge;
+} start_event_t;
+
+typedef struct _queue_event {
+ cairo_fixed_t y;
+ event_type_t type;
+ edge_t *e1;
+ edge_t *e2;
+} queue_event_t;
+
+typedef struct _pqueue {
+ int size, max_size;
+
+ event_t **elements;
+ event_t *elements_embedded[1024];
+} pqueue_t;
+
+struct cell {
+ struct cell *prev;
+ struct cell *next;
+ int x;
+ int uncovered_area;
+ int covered_height;
+};
+
+typedef struct _sweep_line {
+ cairo_list_t active;
+ cairo_list_t stopped;
+ cairo_list_t *insert_cursor;
+ cairo_bool_t is_vertical;
+
+ cairo_fixed_t current_row;
+ cairo_fixed_t current_subrow;
+
+ struct coverage {
+ struct cell head;
+ struct cell tail;
+
+ struct cell *cursor;
+ int count;
+
+ cairo_freepool_t pool;
+ } coverage;
+
+ struct event_queue {
+ pqueue_t pq;
+ event_t **start_events;
+
+ cairo_freepool_t pool;
+ } queue;
+
+ cairo_freepool_t runs;
+
+ jmp_buf unwind;
+} sweep_line_t;
+
+always_inline static struct quorem
+floored_divrem (int a, int b)
+{
+ struct quorem qr;
+ qr.quo = a/b;
+ qr.rem = a%b;
+ if ((a^b)<0 && qr.rem) {
+ qr.quo--;
+ qr.rem += b;
+ }
+ return qr;
+}
+
+static struct quorem
+floored_muldivrem(int x, int a, int b)
+{
+ struct quorem qr;
+ long long xa = (long long)x*a;
+ qr.quo = xa/b;
+ qr.rem = xa%b;
+ if ((xa>=0) != (b>=0) && qr.rem) {
+ qr.quo--;
+ qr.rem += b;
+ }
+ return qr;
+}
+
+static cairo_fixed_t
+line_compute_intersection_x_for_y (const cairo_line_t *line,
+ cairo_fixed_t y)
+{
+ cairo_fixed_t x, dy;
+
+ if (y == line->p1.y)
+ return line->p1.x;
+ if (y == line->p2.y)
+ return line->p2.x;
+
+ x = line->p1.x;
+ dy = line->p2.y - line->p1.y;
+ if (dy != 0) {
+ x += _cairo_fixed_mul_div_floor (y - line->p1.y,
+ line->p2.x - line->p1.x,
+ dy);
+ }
+
+ return x;
+}
+
+/*
+ * We need to compare the x-coordinates of a pair of lines for a particular y,
+ * without loss of precision.
+ *
+ * The x-coordinate along an edge for a given y is:
+ * X = A_x + (Y - A_y) * A_dx / A_dy
+ *
+ * So the inequality we wish to test is:
+ * A_x + (Y - A_y) * A_dx / A_dy â B_x + (Y - B_y) * B_dx / B_dy,
+ * where â is our inequality operator.
+ *
+ * By construction, we know that A_dy and B_dy (and (Y - A_y), (Y - B_y)) are
+ * all positive, so we can rearrange it thus without causing a sign change:
+ * A_dy * B_dy * (A_x - B_x) â (Y - B_y) * B_dx * A_dy
+ * - (Y - A_y) * A_dx * B_dy
+ *
+ * Given the assumption that all the deltas fit within 32 bits, we can compute
+ * this comparison directly using 128 bit arithmetic. For certain, but common,
+ * input we can reduce this down to a single 32 bit compare by inspecting the
+ * deltas.
+ *
+ * (And put the burden of the work on developing fast 128 bit ops, which are
+ * required throughout the tessellator.)
+ *
+ * See the similar discussion for _slope_compare().
+ */
+static int
+edges_compare_x_for_y_general (const cairo_edge_t *a,
+ const cairo_edge_t *b,
+ int32_t y)
+{
+ /* XXX: We're assuming here that dx and dy will still fit in 32
+ * bits. That's not true in general as there could be overflow. We
+ * should prevent that before the tessellation algorithm
+ * begins.
+ */
+ int32_t dx;
+ int32_t adx, ady;
+ int32_t bdx, bdy;
+ enum {
+ HAVE_NONE = 0x0,
+ HAVE_DX = 0x1,
+ HAVE_ADX = 0x2,
+ HAVE_DX_ADX = HAVE_DX | HAVE_ADX,
+ HAVE_BDX = 0x4,
+ HAVE_DX_BDX = HAVE_DX | HAVE_BDX,
+ HAVE_ADX_BDX = HAVE_ADX | HAVE_BDX,
+ HAVE_ALL = HAVE_DX | HAVE_ADX | HAVE_BDX
+ } have_dx_adx_bdx = HAVE_ALL;
+
+ /* don't bother solving for abscissa if the edges' bounding boxes
+ * can be used to order them. */
+ {
+ int32_t amin, amax;
+ int32_t bmin, bmax;
+ if (a->line.p1.x < a->line.p2.x) {
+ amin = a->line.p1.x;
+ amax = a->line.p2.x;
+ } else {
+ amin = a->line.p2.x;
+ amax = a->line.p1.x;
+ }
+ if (b->line.p1.x < b->line.p2.x) {
+ bmin = b->line.p1.x;
+ bmax = b->line.p2.x;
+ } else {
+ bmin = b->line.p2.x;
+ bmax = b->line.p1.x;
+ }
+ if (amax < bmin) return -1;
+ if (amin > bmax) return +1;
+ }
+
+ ady = a->line.p2.y - a->line.p1.y;
+ adx = a->line.p2.x - a->line.p1.x;
+ if (adx == 0)
+ have_dx_adx_bdx &= ~HAVE_ADX;
+
+ bdy = b->line.p2.y - b->line.p1.y;
+ bdx = b->line.p2.x - b->line.p1.x;
+ if (bdx == 0)
+ have_dx_adx_bdx &= ~HAVE_BDX;
+
+ dx = a->line.p1.x - b->line.p1.x;
+ if (dx == 0)
+ have_dx_adx_bdx &= ~HAVE_DX;
+
+#define L _cairo_int64x32_128_mul (_cairo_int32x32_64_mul (ady, bdy), dx)
+#define A _cairo_int64x32_128_mul (_cairo_int32x32_64_mul (adx, bdy), y - a->line.p1.y)
+#define B _cairo_int64x32_128_mul (_cairo_int32x32_64_mul (bdx, ady), y - b->line.p1.y)
+ switch (have_dx_adx_bdx) {
+ default:
+ case HAVE_NONE:
+ return 0;
+ case HAVE_DX:
+ /* A_dy * B_dy * (A_x - B_x) â 0 */
+ return dx; /* ady * bdy is positive definite */
+ case HAVE_ADX:
+ /* 0 â - (Y - A_y) * A_dx * B_dy */
+ return adx; /* bdy * (y - a->top.y) is positive definite */
+ case HAVE_BDX:
+ /* 0 â (Y - B_y) * B_dx * A_dy */
+ return -bdx; /* ady * (y - b->top.y) is positive definite */
+ case HAVE_ADX_BDX:
+ /* 0 â (Y - B_y) * B_dx * A_dy - (Y - A_y) * A_dx * B_dy */
+ if ((adx ^ bdx) < 0) {
+ return adx;
+ } else if (a->line.p1.y == b->line.p1.y) { /* common origin */
+ cairo_int64_t adx_bdy, bdx_ady;
+
+ /* â´ A_dx * B_dy â B_dx * A_dy */
+
+ adx_bdy = _cairo_int32x32_64_mul (adx, bdy);
+ bdx_ady = _cairo_int32x32_64_mul (bdx, ady);
+
+ return _cairo_int64_cmp (adx_bdy, bdx_ady);
+ } else
+ return _cairo_int128_cmp (A, B);
+ case HAVE_DX_ADX:
+ /* A_dy * (A_x - B_x) â - (Y - A_y) * A_dx */
+ if ((-adx ^ dx) < 0) {
+ return dx;
+ } else {
+ cairo_int64_t ady_dx, dy_adx;
+
+ ady_dx = _cairo_int32x32_64_mul (ady, dx);
+ dy_adx = _cairo_int32x32_64_mul (a->line.p1.y - y, adx);
+
+ return _cairo_int64_cmp (ady_dx, dy_adx);
+ }
+ case HAVE_DX_BDX:
+ /* B_dy * (A_x - B_x) â (Y - B_y) * B_dx */
+ if ((bdx ^ dx) < 0) {
+ return dx;
+ } else {
+ cairo_int64_t bdy_dx, dy_bdx;
+
+ bdy_dx = _cairo_int32x32_64_mul (bdy, dx);
+ dy_bdx = _cairo_int32x32_64_mul (y - b->line.p1.y, bdx);
+
+ return _cairo_int64_cmp (bdy_dx, dy_bdx);
+ }
+ case HAVE_ALL:
+ /* XXX try comparing (a->line.p2.x - b->line.p2.x) et al */
+ return _cairo_int128_cmp (L, _cairo_int128_sub (B, A));
+ }
+#undef B
+#undef A
+#undef L
+}
+
+/*
+ * We need to compare the x-coordinate of a line for a particular y wrt to a
+ * given x, without loss of precision.
+ *
+ * The x-coordinate along an edge for a given y is:
+ * X = A_x + (Y - A_y) * A_dx / A_dy
+ *
+ * So the inequality we wish to test is:
+ * A_x + (Y - A_y) * A_dx / A_dy â X
+ * where â is our inequality operator.
+ *
+ * By construction, we know that A_dy (and (Y - A_y)) are
+ * all positive, so we can rearrange it thus without causing a sign change:
+ * (Y - A_y) * A_dx â (X - A_x) * A_dy
+ *
+ * Given the assumption that all the deltas fit within 32 bits, we can compute
+ * this comparison directly using 64 bit arithmetic.
+ *
+ * See the similar discussion for _slope_compare() and
+ * edges_compare_x_for_y_general().
+ */
+static int
+edge_compare_for_y_against_x (const cairo_edge_t *a,
+ int32_t y,
+ int32_t x)
+{
+ int32_t adx, ady;
+ int32_t dx, dy;
+ cairo_int64_t L, R;
+
+ if (a->line.p1.x <= a->line.p2.x) {
+ if (x < a->line.p1.x)
+ return 1;
+ if (x > a->line.p2.x)
+ return -1;
+ } else {
+ if (x < a->line.p2.x)
+ return 1;
+ if (x > a->line.p1.x)
+ return -1;
+ }
+
+ adx = a->line.p2.x - a->line.p1.x;
+ dx = x - a->line.p1.x;
+
+ if (adx == 0)
+ return -dx;
+ if (dx == 0 || (adx ^ dx) < 0)
+ return adx;
+
+ dy = y - a->line.p1.y;
+ ady = a->line.p2.y - a->line.p1.y;
+
+ L = _cairo_int32x32_64_mul (dy, adx);
+ R = _cairo_int32x32_64_mul (dx, ady);
+
+ return _cairo_int64_cmp (L, R);
+}
+
+static int
+edges_compare_x_for_y (const cairo_edge_t *a,
+ const cairo_edge_t *b,
+ int32_t y)
+{
+ /* If the sweep-line is currently on an end-point of a line,
+ * then we know its precise x value (and considering that we often need to
+ * compare events at end-points, this happens frequently enough to warrant
+ * special casing).
+ */
+ enum {
+ HAVE_NEITHER = 0x0,
+ HAVE_AX = 0x1,
+ HAVE_BX = 0x2,
+ HAVE_BOTH = HAVE_AX | HAVE_BX
+ } have_ax_bx = HAVE_BOTH;
+ int32_t ax, bx;
+
+ /* XXX given we have x and dx? */
+
+ if (y == a->line.p1.y)
+ ax = a->line.p1.x;
+ else if (y == a->line.p2.y)
+ ax = a->line.p2.x;
+ else
+ have_ax_bx &= ~HAVE_AX;
+
+ if (y == b->line.p1.y)
+ bx = b->line.p1.x;
+ else if (y == b->line.p2.y)
+ bx = b->line.p2.x;
+ else
+ have_ax_bx &= ~HAVE_BX;
+
+ switch (have_ax_bx) {
+ default:
+ case HAVE_NEITHER:
+ return edges_compare_x_for_y_general (a, b, y);
+ case HAVE_AX:
+ return -edge_compare_for_y_against_x (b, y, ax);
+ case HAVE_BX:
+ return edge_compare_for_y_against_x (a, y, bx);
+ case HAVE_BOTH:
+ return ax - bx;
+ }
+}
+
+static inline int
+slope_compare (const edge_t *a,
+ const edge_t *b)
+{
+ cairo_int64_t L, R;
+ int cmp;
+
+ cmp = a->dxdy.quo - b->dxdy.quo;
+ if (cmp)
+ return cmp;
+
+ if (a->dxdy.rem == 0)
+ return -b->dxdy.rem;
+ if (b->dxdy.rem == 0)
+ return a->dxdy.rem;
+
+ L = _cairo_int32x32_64_mul (b->dy, a->dxdy.rem);
+ R = _cairo_int32x32_64_mul (a->dy, b->dxdy.rem);
+ return _cairo_int64_cmp (L, R);
+}
+
+static inline int
+line_equal (const cairo_line_t *a, const cairo_line_t *b)
+{
+ return a->p1.x == b->p1.x && a->p1.y == b->p1.y &&
+ a->p2.x == b->p2.x && a->p2.y == b->p2.y;
+}
+
+static inline int
+sweep_line_compare_edges (const edge_t *a,
+ const edge_t *b,
+ cairo_fixed_t y)
+{
+ int cmp;
+
+ if (line_equal (&a->edge.line, &b->edge.line))
+ return 0;
+
+ cmp = edges_compare_x_for_y (&a->edge, &b->edge, y);
+ if (cmp)
+ return cmp;
+
+ return slope_compare (a, b);
+}
+
+static inline cairo_int64_t
+det32_64 (int32_t a, int32_t b,
+ int32_t c, int32_t d)
+{
+ /* det = a * d - b * c */
+ return _cairo_int64_sub (_cairo_int32x32_64_mul (a, d),
+ _cairo_int32x32_64_mul (b, c));
+}
+
+static inline cairo_int128_t
+det64x32_128 (cairo_int64_t a, int32_t b,
+ cairo_int64_t c, int32_t d)
+{
+ /* det = a * d - b * c */
+ return _cairo_int128_sub (_cairo_int64x32_128_mul (a, d),
+ _cairo_int64x32_128_mul (c, b));
+}
+
+/* Compute the intersection of two lines as defined by two edges. The
+ * result is provided as a coordinate pair of 128-bit integers.
+ *
+ * Returns %CAIRO_BO_STATUS_INTERSECTION if there is an intersection or
+ * %CAIRO_BO_STATUS_PARALLEL if the two lines are exactly parallel.
+ */
+static cairo_bool_t
+intersect_lines (const edge_t *a, const edge_t *b,
+ cairo_bo_intersect_point_t *intersection)
+{
+ cairo_int64_t a_det, b_det;
+
+ /* XXX: We're assuming here that dx and dy will still fit in 32
+ * bits. That's not true in general as there could be overflow. We
+ * should prevent that before the tessellation algorithm begins.
+ * What we're doing to mitigate this is to perform clamping in
+ * cairo_bo_tessellate_polygon().
+ */
+ int32_t dx1 = a->edge.line.p1.x - a->edge.line.p2.x;
+ int32_t dy1 = a->edge.line.p1.y - a->edge.line.p2.y;
+
+ int32_t dx2 = b->edge.line.p1.x - b->edge.line.p2.x;
+ int32_t dy2 = b->edge.line.p1.y - b->edge.line.p2.y;
+
+ cairo_int64_t den_det;
+ cairo_int64_t R;
+ cairo_quorem64_t qr;
+
+ den_det = det32_64 (dx1, dy1, dx2, dy2);
+
+ /* Q: Can we determine that the lines do not intersect (within range)
+ * much more cheaply than computing the intersection point i.e. by
+ * avoiding the division?
+ *
+ * X = ax + t * adx = bx + s * bdx;
+ * Y = ay + t * ady = by + s * bdy;
+ * â´ t * (ady*bdx - bdy*adx) = bdx * (by - ay) + bdy * (ax - bx)
+ * => t * L = R
+ *
+ * Therefore we can reject any intersection (under the criteria for
+ * valid intersection events) if:
+ * L^R < 0 => t < 0, or
+ * L<R => t > 1
+ *
+ * (where top/bottom must at least extend to the line endpoints).
+ *
+ * A similar substitution can be performed for s, yielding:
+ * s * (ady*bdx - bdy*adx) = ady * (ax - bx) - adx * (ay - by)
+ */
+ R = det32_64 (dx2, dy2,
+ b->edge.line.p1.x - a->edge.line.p1.x,
+ b->edge.line.p1.y - a->edge.line.p1.y);
+ if (_cairo_int64_negative (den_det)) {
+ if (_cairo_int64_ge (den_det, R))
+ return FALSE;
+ } else {
+ if (_cairo_int64_le (den_det, R))
+ return FALSE;
+ }
+
+ R = det32_64 (dy1, dx1,
+ a->edge.line.p1.y - b->edge.line.p1.y,
+ a->edge.line.p1.x - b->edge.line.p1.x);
+ if (_cairo_int64_negative (den_det)) {
+ if (_cairo_int64_ge (den_det, R))
+ return FALSE;
+ } else {
+ if (_cairo_int64_le (den_det, R))
+ return FALSE;
+ }
+
+ /* We now know that the two lines should intersect within range. */
+
+ a_det = det32_64 (a->edge.line.p1.x, a->edge.line.p1.y,
+ a->edge.line.p2.x, a->edge.line.p2.y);
+ b_det = det32_64 (b->edge.line.p1.x, b->edge.line.p1.y,
+ b->edge.line.p2.x, b->edge.line.p2.y);
+
+ /* x = det (a_det, dx1, b_det, dx2) / den_det */
+ qr = _cairo_int_96by64_32x64_divrem (det64x32_128 (a_det, dx1,
+ b_det, dx2),
+ den_det);
+ if (_cairo_int64_eq (qr.rem, den_det))
+ return FALSE;
+#if 0
+ intersection->x.exactness = _cairo_int64_is_zero (qr.rem) ? EXACT : INEXACT;
+#else
+ intersection->x.exactness = EXACT;
+ if (! _cairo_int64_is_zero (qr.rem)) {
+ if (_cairo_int64_negative (den_det) ^ _cairo_int64_negative (qr.rem))
+ qr.rem = _cairo_int64_negate (qr.rem);
+ qr.rem = _cairo_int64_mul (qr.rem, _cairo_int32_to_int64 (2));
+ if (_cairo_int64_ge (qr.rem, den_det)) {
+ qr.quo = _cairo_int64_add (qr.quo,
+ _cairo_int32_to_int64 (_cairo_int64_negative (qr.quo) ? -1 : 1));
+ } else
+ intersection->x.exactness = INEXACT;
+ }
+#endif
+ intersection->x.ordinate = _cairo_int64_to_int32 (qr.quo);
+
+ /* y = det (a_det, dy1, b_det, dy2) / den_det */
+ qr = _cairo_int_96by64_32x64_divrem (det64x32_128 (a_det, dy1,
+ b_det, dy2),
+ den_det);
+ if (_cairo_int64_eq (qr.rem, den_det))
+ return FALSE;
+#if 0
+ intersection->y.exactness = _cairo_int64_is_zero (qr.rem) ? EXACT : INEXACT;
+#else
+ intersection->y.exactness = EXACT;
+ if (! _cairo_int64_is_zero (qr.rem)) {
+ /* compute ceiling away from zero */
+ qr.quo = _cairo_int64_add (qr.quo,
+ _cairo_int32_to_int64 (_cairo_int64_negative (qr.quo) ? -1 : 1));
+ intersection->y.exactness = INEXACT;
+ }
+#endif
+ intersection->y.ordinate = _cairo_int64_to_int32 (qr.quo);
+
+ return TRUE;
+}
+
+static int
+bo_intersect_ordinate_32_compare (int32_t a, int32_t b, int exactness)
+{
+ int cmp;
+
+ /* First compare the quotient */
+ cmp = a - b;
+ if (cmp)
+ return cmp;
+
+ /* With quotient identical, if remainder is 0 then compare equal */
+ /* Otherwise, the non-zero remainder makes a > b */
+ return -(INEXACT == exactness);
+}
+
+/* Does the given edge contain the given point. The point must already
+ * be known to be contained within the line determined by the edge,
+ * (most likely the point results from an intersection of this edge
+ * with another).
+ *
+ * If we had exact arithmetic, then this function would simply be a
+ * matter of examining whether the y value of the point lies within
+ * the range of y values of the edge. But since intersection points
+ * are not exact due to being rounded to the nearest integer within
+ * the available precision, we must also examine the x value of the
+ * point.
+ *
+ * The definition of "contains" here is that the given intersection
+ * point will be seen by the sweep line after the start event for the
+ * given edge and before the stop event for the edge. See the comments
+ * in the implementation for more details.
+ */
+static cairo_bool_t
+bo_edge_contains_intersect_point (const edge_t *edge,
+ cairo_bo_intersect_point_t *point)
+{
+ int cmp_top, cmp_bottom;
+
+ /* XXX: When running the actual algorithm, we don't actually need to
+ * compare against edge->top at all here, since any intersection above
+ * top is eliminated early via a slope comparison. We're leaving these
+ * here for now only for the sake of the quadratic-time intersection
+ * finder which needs them.
+ */
+
+ cmp_top = bo_intersect_ordinate_32_compare (point->y.ordinate,
+ edge->edge.top,
+ point->y.exactness);
+ if (cmp_top < 0)
+ return FALSE;
+
+ cmp_bottom = bo_intersect_ordinate_32_compare (point->y.ordinate,
+ edge->edge.bottom,
+ point->y.exactness);
+ if (cmp_bottom > 0)
+ return FALSE;
+
+ if (cmp_top > 0 && cmp_bottom < 0)
+ return TRUE;
+
+ /* At this stage, the point lies on the same y value as either
+ * edge->top or edge->bottom, so we have to examine the x value in
+ * order to properly determine containment. */
+
+ /* If the y value of the point is the same as the y value of the
+ * top of the edge, then the x value of the point must be greater
+ * to be considered as inside the edge. Similarly, if the y value
+ * of the point is the same as the y value of the bottom of the
+ * edge, then the x value of the point must be less to be
+ * considered as inside. */
+
+ if (cmp_top == 0) {
+ cairo_fixed_t top_x;
+
+ top_x = line_compute_intersection_x_for_y (&edge->edge.line,
+ edge->edge.top);
+ return bo_intersect_ordinate_32_compare (top_x, point->x.ordinate, point->x.exactness) < 0;
+ } else { /* cmp_bottom == 0 */
+ cairo_fixed_t bot_x;
+
+ bot_x = line_compute_intersection_x_for_y (&edge->edge.line,
+ edge->edge.bottom);
+ return bo_intersect_ordinate_32_compare (point->x.ordinate, bot_x, point->x.exactness) < 0;
+ }
+}
+
+static cairo_bool_t
+edge_intersect (const edge_t *a,
+ const edge_t *b,
+ cairo_point_t *intersection)
+{
+ cairo_bo_intersect_point_t quorem;
+
+ if (! intersect_lines (a, b, &quorem))
+ return FALSE;
+
+ if (a->edge.top != a->edge.line.p1.y || a->edge.bottom != a->edge.line.p2.y) {
+ if (! bo_edge_contains_intersect_point (a, &quorem))
+ return FALSE;
+ }
+
+ if (b->edge.top != b->edge.line.p1.y || b->edge.bottom != b->edge.line.p2.y) {
+ if (! bo_edge_contains_intersect_point (b, &quorem))
+ return FALSE;
+ }
+
+ /* Now that we've correctly compared the intersection point and
+ * determined that it lies within the edge, then we know that we
+ * no longer need any more bits of storage for the intersection
+ * than we do for our edge coordinates. We also no longer need the
+ * remainder from the division. */
+ intersection->x = quorem.x.ordinate;
+ intersection->y = quorem.y.ordinate;
+
+ return TRUE;
+}
+
+static inline int
+event_compare (const event_t *a, const event_t *b)
+{
+ return a->y - b->y;
+}
+
+static void
+pqueue_init (pqueue_t *pq)
+{
+ pq->max_size = ARRAY_LENGTH (pq->elements_embedded);
+ pq->size = 0;
+
+ pq->elements = pq->elements_embedded;
+}
+
+static void
+pqueue_fini (pqueue_t *pq)
+{
+ if (pq->elements != pq->elements_embedded)
+ free (pq->elements);
+}
+
+static cairo_bool_t
+pqueue_grow (pqueue_t *pq)
+{
+ event_t **new_elements;
+ pq->max_size *= 2;
+
+ if (pq->elements == pq->elements_embedded) {
+ new_elements = _cairo_malloc_ab (pq->max_size,
+ sizeof (event_t *));
+ if (unlikely (new_elements == NULL))
+ return FALSE;
+
+ memcpy (new_elements, pq->elements_embedded,
+ sizeof (pq->elements_embedded));
+ } else {
+ new_elements = _cairo_realloc_ab (pq->elements,
+ pq->max_size,
+ sizeof (event_t *));
+ if (unlikely (new_elements == NULL))
+ return FALSE;
+ }
+
+ pq->elements = new_elements;
+ return TRUE;
+}
+
+static inline void
+pqueue_push (sweep_line_t *sweep_line, event_t *event)
+{
+ event_t **elements;
+ int i, parent;
+
+ if (unlikely (sweep_line->queue.pq.size + 1 == sweep_line->queue.pq.max_size)) {
+ if (unlikely (! pqueue_grow (&sweep_line->queue.pq))) {
+ longjmp (sweep_line->unwind,
+ _cairo_error (CAIRO_STATUS_NO_MEMORY));
+ }
+ }
+
+ elements = sweep_line->queue.pq.elements;
+ for (i = ++sweep_line->queue.pq.size;
+ i != PQ_FIRST_ENTRY &&
+ event_compare (event,
+ elements[parent = PQ_PARENT_INDEX (i)]) < 0;
+ i = parent)
+ {
+ elements[i] = elements[parent];
+ }
+
+ elements[i] = event;
+}
+
+static inline void
+pqueue_pop (pqueue_t *pq)
+{
+ event_t **elements = pq->elements;
+ event_t *tail;
+ int child, i;
+
+ tail = elements[pq->size--];
+ if (pq->size == 0) {
+ elements[PQ_FIRST_ENTRY] = NULL;
+ return;
+ }
+
+ for (i = PQ_FIRST_ENTRY;
+ (child = PQ_LEFT_CHILD_INDEX (i)) <= pq->size;
+ i = child)
+ {
+ if (child != pq->size &&
+ event_compare (elements[child+1],
+ elements[child]) < 0)
+ {
+ child++;
+ }
+
+ if (event_compare (elements[child], tail) >= 0)
+ break;
+
+ elements[i] = elements[child];
+ }
+ elements[i] = tail;
+}
+
+static inline void
+event_insert (sweep_line_t *sweep_line,
+ event_type_t type,
+ edge_t *e1,
+ edge_t *e2,
+ cairo_fixed_t y)
+{
+ queue_event_t *event;
+
+ event = _cairo_freepool_alloc (&sweep_line->queue.pool);
+ if (unlikely (event == NULL)) {
+ longjmp (sweep_line->unwind,
+ _cairo_error (CAIRO_STATUS_NO_MEMORY));
+ }
+
+ event->y = y;
+ event->type = type;
+ event->e1 = e1;
+ event->e2 = e2;
+
+ pqueue_push (sweep_line, (event_t *) event);
+}
+
+static void
+event_delete (sweep_line_t *sweep_line,
+ event_t *event)
+{
+ _cairo_freepool_free (&sweep_line->queue.pool, event);
+}
+
+static inline event_t *
+event_next (sweep_line_t *sweep_line)
+{
+ event_t *event, *cmp;
+
+ event = sweep_line->queue.pq.elements[PQ_FIRST_ENTRY];
+ cmp = *sweep_line->queue.start_events;
+ if (event == NULL ||
+ (cmp != NULL && event_compare (cmp, event) < 0))
+ {
+ event = cmp;
+ sweep_line->queue.start_events++;
+ }
+ else
+ {
+ pqueue_pop (&sweep_line->queue.pq);
+ }
+
+ return event;
+}
+
+CAIRO_COMBSORT_DECLARE (start_event_sort, event_t *, event_compare)
+
+static inline void
+event_insert_stop (sweep_line_t *sweep_line,
+ edge_t *edge)
+{
+ event_insert (sweep_line,
+ EVENT_TYPE_STOP,
+ edge, NULL,
+ edge->edge.bottom);
+}
+
+static inline void
+event_insert_if_intersect_below_current_y (sweep_line_t *sweep_line,
+ edge_t *left,
+ edge_t *right)
+{
+ cairo_point_t intersection;
+
+ /* start points intersect */
+ if (left->edge.line.p1.x == right->edge.line.p1.x &&
+ left->edge.line.p1.y == right->edge.line.p1.y)
+ {
+ return;
+ }
+
+ /* end points intersect, process DELETE events first */
+ if (left->edge.line.p2.x == right->edge.line.p2.x &&
+ left->edge.line.p2.y == right->edge.line.p2.y)
+ {
+ return;
+ }
+
+ if (slope_compare (left, right) <= 0)
+ return;
+
+ if (! edge_intersect (left, right, &intersection))
+ return;
+
+ event_insert (sweep_line,
+ EVENT_TYPE_INTERSECTION,
+ left, right,
+ intersection.y);
+}
+
+static inline edge_t *
+link_to_edge (cairo_list_t *link)
+{
+ return (edge_t *) link;
+}
+
+static void
+sweep_line_insert (sweep_line_t *sweep_line,
+ edge_t *edge)
+{
+ cairo_list_t *pos;
+ cairo_fixed_t y = sweep_line->current_subrow;
+
+ pos = sweep_line->insert_cursor;
+ if (pos == &sweep_line->active)
+ pos = sweep_line->active.next;
+ if (pos != &sweep_line->active) {
+ int cmp;
+
+ cmp = sweep_line_compare_edges (link_to_edge (pos),
+ edge,
+ y);
+ if (cmp < 0) {
+ while (pos->next != &sweep_line->active &&
+ sweep_line_compare_edges (link_to_edge (pos->next),
+ edge,
+ y) < 0)
+ {
+ pos = pos->next;
+ }
+ } else if (cmp > 0) {
+ do {
+ pos = pos->prev;
+ } while (pos != &sweep_line->active &&
+ sweep_line_compare_edges (link_to_edge (pos),
+ edge,
+ y) > 0);
+ }
+ }
+ cairo_list_add (&edge->link, pos);
+ sweep_line->insert_cursor = &edge->link;
+}
+
+inline static void
+coverage_rewind (struct coverage *cells)
+{
+ cells->cursor = &cells->head;
+}
+
+static void
+coverage_init (struct coverage *cells)
+{
+ _cairo_freepool_init (&cells->pool,
+ sizeof (struct cell));
+ cells->head.prev = NULL;
+ cells->head.next = &cells->tail;
+ cells->head.x = INT_MIN;
+ cells->tail.prev = &cells->head;
+ cells->tail.next = NULL;
+ cells->tail.x = INT_MAX;
+ cells->count = 0;
+ coverage_rewind (cells);
+}
+
+static void
+coverage_fini (struct coverage *cells)
+{
+ _cairo_freepool_fini (&cells->pool);
+}
+
+inline static void
+coverage_reset (struct coverage *cells)
+{
+ cells->head.next = &cells->tail;
+ cells->tail.prev = &cells->head;
+ cells->count = 0;
+ _cairo_freepool_reset (&cells->pool);
+ coverage_rewind (cells);
+}
+
+inline static struct cell *
+coverage_alloc (sweep_line_t *sweep_line,
+ struct cell *tail,
+ int x)
+{
+ struct cell *cell;
+
+ cell = _cairo_freepool_alloc (&sweep_line->coverage.pool);
+ if (unlikely (NULL == cell)) {
+ longjmp (sweep_line->unwind,
+ _cairo_error (CAIRO_STATUS_NO_MEMORY));
+ }
+
+ tail->prev->next = cell;
+ cell->prev = tail->prev;
+ cell->next = tail;
+ tail->prev = cell;
+ cell->x = x;
+ cell->uncovered_area = 0;
+ cell->covered_height = 0;
+ sweep_line->coverage.count++;
+ return cell;
+}
+
+inline static struct cell *
+coverage_find (sweep_line_t *sweep_line, int x)
+{
+ struct cell *cell;
+
+ cell = sweep_line->coverage.cursor;
+ if (unlikely (cell->x > x)) {
+ do {
+ if (cell->prev->x < x)
+ break;
+ cell = cell->prev;
+ } while (TRUE);
+ } else {
+ if (cell->x == x)
+ return cell;
+
+ do {
+ UNROLL3({
+ cell = cell->next;
+ if (cell->x >= x)
+ break;
+ });
+ } while (TRUE);
+ }
+
+ if (cell->x != x)
+ cell = coverage_alloc (sweep_line, cell, x);
+
+ return sweep_line->coverage.cursor = cell;
+}
+
+static void
+coverage_render_cells (sweep_line_t *sweep_line,
+ cairo_fixed_t left, cairo_fixed_t right,
+ cairo_fixed_t y1, cairo_fixed_t y2,
+ int sign)
+{
+ int fx1, fx2;
+ int ix1, ix2;
+ int dx, dy;
+
+ /* Orient the edge left-to-right. */
+ dx = right - left;
+ if (dx >= 0) {
+ ix1 = _cairo_fixed_integer_part (left);
+ fx1 = _cairo_fixed_fractional_part (left);
+
+ ix2 = _cairo_fixed_integer_part (right);
+ fx2 = _cairo_fixed_fractional_part (right);
+
+ dy = y2 - y1;
+ } else {
+ ix1 = _cairo_fixed_integer_part (right);
+ fx1 = _cairo_fixed_fractional_part (right);
+
+ ix2 = _cairo_fixed_integer_part (left);
+ fx2 = _cairo_fixed_fractional_part (left);
+
+ dx = -dx;
+ sign = -sign;
+ dy = y1 - y2;
+ y1 = y2 - dy;
+ y2 = y1 + dy;
+ }
+
+ /* Add coverage for all pixels [ix1,ix2] on this row crossed
+ * by the edge. */
+ {
+ struct quorem y = floored_divrem ((STEP_X - fx1)*dy, dx);
+ struct cell *cell;
+
+ cell = sweep_line->coverage.cursor;
+ if (cell->x != ix1) {
+ if (unlikely (cell->x > ix1)) {
+ do {
+ if (cell->prev->x < ix1)
+ break;
+ cell = cell->prev;
+ } while (TRUE);
+ } else do {
+ UNROLL3({
+ if (cell->x >= ix1)
+ break;
+ cell = cell->next;
+ });
+ } while (TRUE);
+
+ if (cell->x != ix1)
+ cell = coverage_alloc (sweep_line, cell, ix1);
+ }
+
+ cell->uncovered_area += sign * y.quo * (STEP_X + fx1);
+ cell->covered_height += sign * y.quo;
+ y.quo += y1;
+
+ cell = cell->next;
+ if (cell->x != ++ix1)
+ cell = coverage_alloc (sweep_line, cell, ix1);
+ if (ix1 < ix2) {
+ struct quorem dydx_full = floored_divrem (STEP_X*dy, dx);
+
+ do {
+ cairo_fixed_t y_skip = dydx_full.quo;
+ y.rem += dydx_full.rem;
+ if (y.rem >= dx) {
+ ++y_skip;
+ y.rem -= dx;
+ }
+
+ y.quo += y_skip;
+
+ y_skip *= sign;
+ cell->covered_height += y_skip;
+ cell->uncovered_area += y_skip*STEP_X;
+
+ cell = cell->next;
+ if (cell->x != ++ix1)
+ cell = coverage_alloc (sweep_line, cell, ix1);
+ } while (ix1 != ix2);
+ }
+ cell->uncovered_area += sign*(y2 - y.quo)*fx2;
+ cell->covered_height += sign*(y2 - y.quo);
+ sweep_line->coverage.cursor = cell;
+ }
+}
+
+inline static void
+full_inc_edge (edge_t *edge)
+{
+ edge->x.quo += edge->dxdy_full.quo;
+ edge->x.rem += edge->dxdy_full.rem;
+ if (edge->x.rem >= 0) {
+ ++edge->x.quo;
+ edge->x.rem -= edge->dy;
+ }
+}
+
+static void
+full_add_edge (sweep_line_t *sweep_line, edge_t *edge, int sign)
+{
+ struct cell *cell;
+ cairo_fixed_t x1, x2;
+ int ix1, ix2;
+ int frac;
+
+ edge->current_sign = sign;
+
+ ix1 = _cairo_fixed_integer_part (edge->x.quo);
+
+ if (edge->vertical) {
+ frac = _cairo_fixed_fractional_part (edge->x.quo);
+ cell = coverage_find (sweep_line, ix1);
+ cell->covered_height += sign * STEP_Y;
+ cell->uncovered_area += sign * 2 * frac * STEP_Y;
+ return;
+ }
+
+ x1 = edge->x.quo;
+ full_inc_edge (edge);
+ x2 = edge->x.quo;
+
+ ix2 = _cairo_fixed_integer_part (edge->x.quo);
+
+ /* Edge is entirely within a column? */
+ if (likely (ix1 == ix2)) {
+ frac = _cairo_fixed_fractional_part (x1) +
+ _cairo_fixed_fractional_part (x2);
+ cell = coverage_find (sweep_line, ix1);
+ cell->covered_height += sign * STEP_Y;
+ cell->uncovered_area += sign * frac * STEP_Y;
+ return;
+ }
+
+ coverage_render_cells (sweep_line, x1, x2, 0, STEP_Y, sign);
+}
+
+static void
+full_nonzero (sweep_line_t *sweep_line)
+{
+ cairo_list_t *pos;
+
+ sweep_line->is_vertical = TRUE;
+ pos = sweep_line->active.next;
+ do {
+ edge_t *left = link_to_edge (pos), *right;
+ int winding = left->edge.dir;
+
+ sweep_line->is_vertical &= left->vertical;
+
+ pos = left->link.next;
+ do {
+ if (unlikely (pos == &sweep_line->active)) {
+ full_add_edge (sweep_line, left, +1);
+ return;
+ }
+
+ right = link_to_edge (pos);
+ pos = pos->next;
+ sweep_line->is_vertical &= right->vertical;
+
+ winding += right->edge.dir;
+ if (0 == winding) {
+ if (pos == &sweep_line->active ||
+ link_to_edge (pos)->x.quo != right->x.quo)
+ {
+ break;
+ }
+ }
+
+ if (! right->vertical)
+ full_inc_edge (right);
+ } while (TRUE);
+
+ full_add_edge (sweep_line, left, +1);
+ full_add_edge (sweep_line, right, -1);
+ } while (pos != &sweep_line->active);
+}
+
+static void
+full_evenodd (sweep_line_t *sweep_line)
+{
+ cairo_list_t *pos;
+
+ sweep_line->is_vertical = TRUE;
+ pos = sweep_line->active.next;
+ do {
+ edge_t *left = link_to_edge (pos), *right;
+ int winding = 0;
+
+ sweep_line->is_vertical &= left->vertical;
+
+ pos = left->link.next;
+ do {
+ if (pos == &sweep_line->active) {
+ full_add_edge (sweep_line, left, +1);
+ return;
+ }
+
+ right = link_to_edge (pos);
+ pos = pos->next;
+ sweep_line->is_vertical &= right->vertical;
+
+ if (++winding & 1) {
+ if (pos == &sweep_line->active ||
+ link_to_edge (pos)->x.quo != right->x.quo)
+ {
+ break;
+ }
+ }
+
+ if (! right->vertical)
+ full_inc_edge (right);
+ } while (TRUE);
+
+ full_add_edge (sweep_line, left, +1);
+ full_add_edge (sweep_line, right, -1);
+ } while (pos != &sweep_line->active);
+}
+
+static void
+render_rows (cairo_botor_scan_converter_t *self,
+ sweep_line_t *sweep_line,
+ int y, int height,
+ cairo_span_renderer_t *renderer)
+{
+ cairo_half_open_span_t spans_stack[CAIRO_STACK_ARRAY_LENGTH (cairo_half_open_span_t)];
+ cairo_half_open_span_t *spans = spans_stack;
+ struct cell *cell;
+ int prev_x, cover;
+ int num_spans;
+ cairo_status_t status;
+
+ if (unlikely (sweep_line->coverage.count == 0)) {
+ status = renderer->render_rows (renderer, y, height, NULL, 0);
+ if (unlikely (status))
+ longjmp (sweep_line->unwind, status);
+ return;
+ }
+
+ /* Allocate enough spans for the row. */
+
+ num_spans = 2*sweep_line->coverage.count+2;
+ if (unlikely (num_spans > ARRAY_LENGTH (spans_stack))) {
+ spans = _cairo_malloc_ab (num_spans, sizeof (cairo_half_open_span_t));
+ if (unlikely (spans == NULL)) {
+ longjmp (sweep_line->unwind,
+ _cairo_error (CAIRO_STATUS_NO_MEMORY));
+ }
+ }
+
+ /* Form the spans from the coverage and areas. */
+ num_spans = 0;
+ prev_x = self->xmin;
+ cover = 0;
+ cell = sweep_line->coverage.head.next;
+ do {
+ int x = cell->x;
+ int area;
+
+ if (x > prev_x) {
+ spans[num_spans].x = prev_x;
+ spans[num_spans].coverage = AREA_TO_ALPHA (cover);
+ ++num_spans;
+ }
+
+ cover += cell->covered_height*STEP_X*2;
+ area = cover - cell->uncovered_area;
+
+ spans[num_spans].x = x;
+ spans[num_spans].coverage = AREA_TO_ALPHA (area);
+ ++num_spans;
+
+ prev_x = x + 1;
+ } while ((cell = cell->next) != &sweep_line->coverage.tail);
+
+ if (prev_x <= self->xmax) {
+ spans[num_spans].x = prev_x;
+ spans[num_spans].coverage = AREA_TO_ALPHA (cover);
+ ++num_spans;
+ }
+
+ if (cover && prev_x < self->xmax) {
+ spans[num_spans].x = self->xmax;
+ spans[num_spans].coverage = 0;
+ ++num_spans;
+ }
+
+ status = renderer->render_rows (renderer, y, height, spans, num_spans);
+
+ if (unlikely (spans != spans_stack))
+ free (spans);
+
+ coverage_reset (&sweep_line->coverage);
+
+ if (unlikely (status))
+ longjmp (sweep_line->unwind, status);
+}
+
+static void
+full_repeat (sweep_line_t *sweep)
+{
+ edge_t *edge;
+
+ cairo_list_foreach_entry (edge, edge_t, &sweep->active, link) {
+ if (edge->current_sign)
+ full_add_edge (sweep, edge, edge->current_sign);
+ else if (! edge->vertical)
+ full_inc_edge (edge);
+ }
+}
+
+static void
+full_reset (sweep_line_t *sweep)
+{
+ edge_t *edge;
+
+ cairo_list_foreach_entry (edge, edge_t, &sweep->active, link)
+ edge->current_sign = 0;
+}
+
+static void
+full_step (cairo_botor_scan_converter_t *self,
+ sweep_line_t *sweep_line,
+ cairo_fixed_t row,
+ cairo_span_renderer_t *renderer)
+{
+ int top, bottom;
+
+ top = _cairo_fixed_integer_part (sweep_line->current_row);
+ bottom = _cairo_fixed_integer_part (row);
+ if (cairo_list_is_empty (&sweep_line->active)) {
+ cairo_status_t status;
+
+ status = renderer->render_rows (renderer, top, bottom - top, NULL, 0);
+ if (unlikely (status))
+ longjmp (sweep_line->unwind, status);
+
+ return;
+ }
+
+ if (self->fill_rule == CAIRO_FILL_RULE_WINDING)
+ full_nonzero (sweep_line);
+ else
+ full_evenodd (sweep_line);
+
+ if (sweep_line->is_vertical || bottom == top + 1) {
+ render_rows (self, sweep_line, top, bottom - top, renderer);
+ full_reset (sweep_line);
+ return;
+ }
+
+ render_rows (self, sweep_line, top++, 1, renderer);
+ do {
+ full_repeat (sweep_line);
+ render_rows (self, sweep_line, top, 1, renderer);
+ } while (++top != bottom);
+
+ full_reset (sweep_line);
+}
+
+always_inline static void
+sub_inc_edge (edge_t *edge,
+ cairo_fixed_t height)
+{
+ if (height == 1) {
+ edge->x.quo += edge->dxdy.quo;
+ edge->x.rem += edge->dxdy.rem;
+ if (edge->x.rem >= 0) {
+ ++edge->x.quo;
+ edge->x.rem -= edge->dy;
+ }
+ } else {
+ edge->x.quo += height * edge->dxdy.quo;
+ edge->x.rem += height * edge->dxdy.rem;
+ if (edge->x.rem >= 0) {
+ int carry = edge->x.rem / edge->dy + 1;
+ edge->x.quo += carry;
+ edge->x.rem -= carry * edge->dy;
+ }
+ }
+}
+
+static void
+sub_add_run (sweep_line_t *sweep_line, edge_t *edge, int y, int sign)
+{
+ struct run *run;
+
+ run = _cairo_freepool_alloc (&sweep_line->runs);
+ if (unlikely (run == NULL))
+ longjmp (sweep_line->unwind, _cairo_error (CAIRO_STATUS_NO_MEMORY));
+
+ run->y = y;
+ run->sign = sign;
+ run->next = edge->runs;
+ edge->runs = run;
+
+ edge->current_sign = sign;
+}
+
+inline static cairo_bool_t
+edges_coincident (edge_t *left, edge_t *right, cairo_fixed_t y)
+{
+ /* XXX is compare_x_for_y() worth executing during sub steps? */
+ return line_equal (&left->edge.line, &right->edge.line);
+ //edges_compare_x_for_y (&left->edge, &right->edge, y) >= 0;
+}
+
+static void
+sub_nonzero (sweep_line_t *sweep_line)
+{
+ cairo_fixed_t y = sweep_line->current_subrow;
+ cairo_fixed_t fy = _cairo_fixed_fractional_part (y);
+ cairo_list_t *pos;
+
+ pos = sweep_line->active.next;
+ do {
+ edge_t *left = link_to_edge (pos), *right;
+ int winding = left->edge.dir;
+
+ pos = left->link.next;
+ do {
+ if (unlikely (pos == &sweep_line->active)) {
+ if (left->current_sign != +1)
+ sub_add_run (sweep_line, left, fy, +1);
+ return;
+ }
+
+ right = link_to_edge (pos);
+ pos = pos->next;
+
+ winding += right->edge.dir;
+ if (0 == winding) {
+ if (pos == &sweep_line->active ||
+ ! edges_coincident (right, link_to_edge (pos), y))
+ {
+ break;
+ }
+ }
+
+ if (right->current_sign)
+ sub_add_run (sweep_line, right, fy, 0);
+ } while (TRUE);
+
+ if (left->current_sign != +1)
+ sub_add_run (sweep_line, left, fy, +1);
+ if (right->current_sign != -1)
+ sub_add_run (sweep_line, right, fy, -1);
+ } while (pos != &sweep_line->active);
+}
+
+static void
+sub_evenodd (sweep_line_t *sweep_line)
+{
+ cairo_fixed_t y = sweep_line->current_subrow;
+ cairo_fixed_t fy = _cairo_fixed_fractional_part (y);
+ cairo_list_t *pos;
+
+ pos = sweep_line->active.next;
+ do {
+ edge_t *left = link_to_edge (pos), *right;
+ int winding = 0;
+
+ pos = left->link.next;
+ do {
+ if (unlikely (pos == &sweep_line->active)) {
+ if (left->current_sign != +1)
+ sub_add_run (sweep_line, left, fy, +1);
+ return;
+ }
+
+ right = link_to_edge (pos);
+ pos = pos->next;
+
+ if (++winding & 1) {
+ if (pos == &sweep_line->active ||
+ ! edges_coincident (right, link_to_edge (pos), y))
+ {
+ break;
+ }
+ }
+
+ if (right->current_sign)
+ sub_add_run (sweep_line, right, fy, 0);
+ } while (TRUE);
+
+ if (left->current_sign != +1)
+ sub_add_run (sweep_line, left, fy, +1);
+ if (right->current_sign != -1)
+ sub_add_run (sweep_line, right, fy, -1);
+ } while (pos != &sweep_line->active);
+}
+
+always_inline static void
+sub_step (cairo_botor_scan_converter_t *self,
+ sweep_line_t *sweep_line)
+{
+ if (cairo_list_is_empty (&sweep_line->active))
+ return;
+
+ if (self->fill_rule == CAIRO_FILL_RULE_WINDING)
+ sub_nonzero (sweep_line);
+ else
+ sub_evenodd (sweep_line);
+}
+
+static void
+coverage_render_runs (sweep_line_t *sweep, edge_t *edge,
+ cairo_fixed_t y1, cairo_fixed_t y2)
+{
+ struct run tail;
+ struct run *run = &tail;
+
+ tail.next = NULL;
+ tail.y = y2;
+
+ /* Order the runs top->bottom */
+ while (edge->runs) {
+ struct run *r;
+
+ r = edge->runs;
+ edge->runs = r->next;
+ r->next = run;
+ run = r;
+ }
+
+ if (run->y > y1)
+ sub_inc_edge (edge, run->y - y1);
+
+ do {
+ cairo_fixed_t x1, x2;
+
+ y1 = run->y;
+ y2 = run->next->y;
+
+ x1 = edge->x.quo;
+ if (y2 - y1 == STEP_Y)
+ full_inc_edge (edge);
+ else
+ sub_inc_edge (edge, y2 - y1);
+ x2 = edge->x.quo;
+
+ if (run->sign) {
+ int ix1, ix2;
+
+ ix1 = _cairo_fixed_integer_part (x1);
+ ix2 = _cairo_fixed_integer_part (x2);
+
+ /* Edge is entirely within a column? */
+ if (likely (ix1 == ix2)) {
+ struct cell *cell;
+ int frac;
+
+ frac = _cairo_fixed_fractional_part (x1) +
+ _cairo_fixed_fractional_part (x2);
+ cell = coverage_find (sweep, ix1);
+ cell->covered_height += run->sign * (y2 - y1);
+ cell->uncovered_area += run->sign * (y2 - y1) * frac;
+ } else {
+ coverage_render_cells (sweep, x1, x2, y1, y2, run->sign);
+ }
+ }
+
+ run = run->next;
+ } while (run->next != NULL);
+}
+
+static void
+coverage_render_vertical_runs (sweep_line_t *sweep, edge_t *edge, cairo_fixed_t y2)
+{
+ struct cell *cell;
+ struct run *run;
+ int height = 0;
+
+ for (run = edge->runs; run != NULL; run = run->next) {
+ if (run->sign)
+ height += run->sign * (y2 - run->y);
+ y2 = run->y;
+ }
+
+ cell = coverage_find (sweep, _cairo_fixed_integer_part (edge->x.quo));
+ cell->covered_height += height;
+ cell->uncovered_area += 2 * _cairo_fixed_fractional_part (edge->x.quo) * height;
+}
+
+always_inline static void
+sub_emit (cairo_botor_scan_converter_t *self,
+ sweep_line_t *sweep,
+ cairo_span_renderer_t *renderer)
+{
+ edge_t *edge;
+
+ sub_step (self, sweep);
+
+ /* convert the runs into coverages */
+
+ cairo_list_foreach_entry (edge, edge_t, &sweep->active, link) {
+ if (edge->runs == NULL) {
+ if (! edge->vertical) {
+ if (edge->flags & START) {
+ sub_inc_edge (edge,
+ STEP_Y - _cairo_fixed_fractional_part (edge->edge.top));
+ edge->flags &= ~START;
+ } else
+ full_inc_edge (edge);
+ }
+ } else {
+ if (edge->vertical) {
+ coverage_render_vertical_runs (sweep, edge, STEP_Y);
+ } else {
+ int y1 = 0;
+ if (edge->flags & START) {
+ y1 = _cairo_fixed_fractional_part (edge->edge.top);
+ edge->flags &= ~START;
+ }
+ coverage_render_runs (sweep, edge, y1, STEP_Y);
+ }
+ }
+ edge->current_sign = 0;
+ edge->runs = NULL;
+ }
+
+ cairo_list_foreach_entry (edge, edge_t, &sweep->stopped, link) {
+ int y2 = _cairo_fixed_fractional_part (edge->edge.bottom);
+ if (edge->vertical) {
+ coverage_render_vertical_runs (sweep, edge, y2);
+ } else {
+ int y1 = 0;
+ if (edge->flags & START)
+ y1 = _cairo_fixed_fractional_part (edge->edge.top);
+ coverage_render_runs (sweep, edge, y1, y2);
+ }
+ }
+ cairo_list_init (&sweep->stopped);
+
+ _cairo_freepool_reset (&sweep->runs);
+
+ render_rows (self, sweep,
+ _cairo_fixed_integer_part (sweep->current_row), 1,
+ renderer);
+}
+
+static void
+sweep_line_init (sweep_line_t *sweep_line,
+ event_t **start_events,
+ int num_events)
+{
+ cairo_list_init (&sweep_line->active);
+ cairo_list_init (&sweep_line->stopped);
+ sweep_line->insert_cursor = &sweep_line->active;
+
+ sweep_line->current_row = INT32_MIN;
+ sweep_line->current_subrow = INT32_MIN;
+
+ coverage_init (&sweep_line->coverage);
+ _cairo_freepool_init (&sweep_line->runs, sizeof (struct run));
+
+ start_event_sort (start_events, num_events);
+ start_events[num_events] = NULL;
+
+ sweep_line->queue.start_events = start_events;
+
+ _cairo_freepool_init (&sweep_line->queue.pool,
+ sizeof (queue_event_t));
+ pqueue_init (&sweep_line->queue.pq);
+ sweep_line->queue.pq.elements[PQ_FIRST_ENTRY] = NULL;
+}
+
+static void
+sweep_line_delete (sweep_line_t *sweep_line,
+ edge_t *edge)
+{
+ if (sweep_line->insert_cursor == &edge->link)
+ sweep_line->insert_cursor = edge->link.prev;
+
+ cairo_list_del (&edge->link);
+ if (edge->runs)
+ cairo_list_add_tail (&edge->link, &sweep_line->stopped);
+ edge->flags |= STOP;
+}
+
+static void
+sweep_line_swap (sweep_line_t *sweep_line,
+ edge_t *left,
+ edge_t *right)
+{
+ right->link.prev = left->link.prev;
+ left->link.next = right->link.next;
+ right->link.next = &left->link;
+ left->link.prev = &right->link;
+ left->link.next->prev = &left->link;
+ right->link.prev->next = &right->link;
+}
+
+static void
+sweep_line_fini (sweep_line_t *sweep_line)
+{
+ pqueue_fini (&sweep_line->queue.pq);
+ _cairo_freepool_fini (&sweep_line->queue.pool);
+ coverage_fini (&sweep_line->coverage);
+ _cairo_freepool_fini (&sweep_line->runs);
+}
+
+static cairo_status_t
+botor_generate (cairo_botor_scan_converter_t *self,
+ event_t **start_events,
+ cairo_span_renderer_t *renderer)
+{
+ cairo_status_t status;
+ sweep_line_t sweep_line;
+ cairo_fixed_t ybot;
+ event_t *event;
+ cairo_list_t *left, *right;
+ edge_t *e1, *e2;
+ int bottom;
+
+ sweep_line_init (&sweep_line, start_events, self->num_edges);
+ if ((status = setjmp (sweep_line.unwind)))
+ goto unwind;
+
+ ybot = self->extents.p2.y;
+ sweep_line.current_subrow = self->extents.p1.y;
+ sweep_line.current_row = _cairo_fixed_floor (self->extents.p1.y);
+ event = *sweep_line.queue.start_events++;
+ do {
+ /* Can we process a full step in one go? */
+ if (event->y >= sweep_line.current_row + STEP_Y) {
+ bottom = _cairo_fixed_floor (event->y);
+ full_step (self, &sweep_line, bottom, renderer);
+ sweep_line.current_row = bottom;
+ sweep_line.current_subrow = bottom;
+ }
+
+ do {
+ if (event->y > sweep_line.current_subrow) {
+ sub_step (self, &sweep_line);
+ sweep_line.current_subrow = event->y;
+ }
+
+ do {
+ /* Update the active list using Bentley-Ottmann */
+ switch (event->type) {
+ case EVENT_TYPE_START:
+ e1 = ((start_event_t *) event)->edge;
+
+ sweep_line_insert (&sweep_line, e1);
+ event_insert_stop (&sweep_line, e1);
+
+ left = e1->link.prev;
+ right = e1->link.next;
+
+ if (left != &sweep_line.active) {
+ event_insert_if_intersect_below_current_y (&sweep_line,
+ link_to_edge (left), e1);
+ }
+
+ if (right != &sweep_line.active) {
+ event_insert_if_intersect_below_current_y (&sweep_line,
+ e1, link_to_edge (right));
+ }
+
+ break;
+
+ case EVENT_TYPE_STOP:
+ e1 = ((queue_event_t *) event)->e1;
+ event_delete (&sweep_line, event);
+
+ left = e1->link.prev;
+ right = e1->link.next;
+
+ sweep_line_delete (&sweep_line, e1);
+
+ if (left != &sweep_line.active &&
+ right != &sweep_line.active)
+ {
+ event_insert_if_intersect_below_current_y (&sweep_line,
+ link_to_edge (left),
+ link_to_edge (right));
+ }
+
+ break;
+
+ case EVENT_TYPE_INTERSECTION:
+ e1 = ((queue_event_t *) event)->e1;
+ e2 = ((queue_event_t *) event)->e2;
+
+ event_delete (&sweep_line, event);
+ if (e1->flags & STOP)
+ break;
+ if (e2->flags & STOP)
+ break;
+
+ /* skip this intersection if its edges are not adjacent */
+ if (&e2->link != e1->link.next)
+ break;
+
+ left = e1->link.prev;
+ right = e2->link.next;
+
+ sweep_line_swap (&sweep_line, e1, e2);
+
+ /* after the swap e2 is left of e1 */
+ if (left != &sweep_line.active) {
+ event_insert_if_intersect_below_current_y (&sweep_line,
+ link_to_edge (left), e2);
+ }
+
+ if (right != &sweep_line.active) {
+ event_insert_if_intersect_below_current_y (&sweep_line,
+ e1, link_to_edge (right));
+ }
+
+ break;
+ }
+
+ event = event_next (&sweep_line);
+ if (event == NULL)
+ goto end;
+ } while (event->y == sweep_line.current_subrow);
+ } while (event->y < sweep_line.current_row + STEP_Y);
+
+ bottom = sweep_line.current_row + STEP_Y;
+ sub_emit (self, &sweep_line, renderer);
+ sweep_line.current_subrow = bottom;
+ sweep_line.current_row = sweep_line.current_subrow;
+ } while (TRUE);
+
+ end:
+ /* flush any partial spans */
+ if (sweep_line.current_subrow != sweep_line.current_row) {
+ sub_emit (self, &sweep_line, renderer);
+ sweep_line.current_row += STEP_Y;
+ sweep_line.current_subrow = sweep_line.current_row;
+ }
+ /* clear the rest */
+ if (sweep_line.current_subrow < ybot) {
+ bottom = _cairo_fixed_integer_part (sweep_line.current_row);
+ status = renderer->render_rows (renderer,
+ bottom, _cairo_fixed_integer_ceil (ybot) - bottom,
+ NULL, 0);
+ }
+
+ unwind:
+ sweep_line_fini (&sweep_line);
+
+ return status;
+}
+
+static cairo_status_t
+_cairo_botor_scan_converter_generate (void *converter,
+ cairo_span_renderer_t *renderer)
+{
+ cairo_botor_scan_converter_t *self = converter;
+ start_event_t stack_events[CAIRO_STACK_ARRAY_LENGTH (start_event_t)];
+ start_event_t *events;
+ event_t *stack_event_ptrs[ARRAY_LENGTH (stack_events) + 1];
+ event_t **event_ptrs;
+ struct _cairo_botor_scan_converter_chunk *chunk;
+ cairo_status_t status;
+ int num_events;
+ int i, j;
+
+ num_events = self->num_edges;
+ if (unlikely (0 == num_events)) {
+ return renderer->render_rows (renderer,
+ _cairo_fixed_integer_floor (self->extents.p1.y),
+ _cairo_fixed_integer_ceil (self->extents.p2.y) -
+ _cairo_fixed_integer_floor (self->extents.p1.y),
+ NULL, 0);
+ }
+
+ events = stack_events;
+ event_ptrs = stack_event_ptrs;
+ if (unlikely (num_events >= ARRAY_LENGTH (stack_events))) {
+ events = _cairo_malloc_ab_plus_c (num_events,
+ sizeof (start_event_t) + sizeof (event_t *),
+ sizeof (event_t *));
+ if (unlikely (events == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+ event_ptrs = (event_t **) (events + num_events);
+ }
+
+ j = 0;
+ for (chunk = &self->chunks; chunk != NULL; chunk = chunk->next) {
+ edge_t *edge;
+
+ edge = chunk->base;
+ for (i = 0; i < chunk->count; i++) {
+ event_ptrs[j] = (event_t *) &events[j];
+
+ events[j].y = edge->edge.top;
+ events[j].type = EVENT_TYPE_START;
+ events[j].edge = edge;
+
+ edge++, j++;
+ }
+ }
+
+ status = botor_generate (self, event_ptrs, renderer);
+
+ if (events != stack_events)
+ free (events);
+
+ return status;
+}
+
+static edge_t *
+botor_allocate_edge (cairo_botor_scan_converter_t *self)
+{
+ struct _cairo_botor_scan_converter_chunk *chunk;
+
+ chunk = self->tail;
+ if (chunk->count == chunk->size) {
+ int size;
+
+ size = chunk->size * 2;
+ chunk->next = _cairo_malloc_ab_plus_c (size,
+ sizeof (edge_t),
+ sizeof (struct _cairo_botor_scan_converter_chunk));
+ if (unlikely (chunk->next == NULL))
+ return NULL;
+
+ chunk = chunk->next;
+ chunk->next = NULL;
+ chunk->count = 0;
+ chunk->size = size;
+ chunk->base = chunk + 1;
+ self->tail = chunk;
+ }
+
+ return (edge_t *) chunk->base + chunk->count++;
+}
+
+static cairo_status_t
+botor_add_edge (cairo_botor_scan_converter_t *self,
+ const cairo_edge_t *edge)
+{
+ edge_t *e;
+ cairo_fixed_t dx, dy;
+
+ e = botor_allocate_edge (self);
+ if (unlikely (e == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+ cairo_list_init (&e->link);
+ e->edge = *edge;
+
+ dx = edge->line.p2.x - edge->line.p1.x;
+ dy = edge->line.p2.y - edge->line.p1.y;
+ e->dy = dy;
+
+ if (dx == 0) {
+ e->vertical = TRUE;
+ e->x.quo = edge->line.p1.x;
+ e->x.rem = 0;
+ e->dxdy.quo = 0;
+ e->dxdy.rem = 0;
+ e->dxdy_full.quo = 0;
+ e->dxdy_full.rem = 0;
+ } else {
+ e->vertical = FALSE;
+ e->dxdy = floored_divrem (dx, dy);
+ if (edge->top == edge->line.p1.y) {
+ e->x.quo = edge->line.p1.x;
+ e->x.rem = 0;
+ } else {
+ e->x = floored_muldivrem (edge->top - edge->line.p1.y,
+ dx, dy);
+ e->x.quo += edge->line.p1.x;
+ }
+
+ if (_cairo_fixed_integer_part (edge->bottom) - _cairo_fixed_integer_part (edge->top) > 1) {
+ e->dxdy_full = floored_muldivrem (STEP_Y, dx, dy);
+ } else {
+ e->dxdy_full.quo = 0;
+ e->dxdy_full.rem = 0;
+ }
+ }
+
+ e->x.rem = -e->dy;
+ e->current_sign = 0;
+ e->runs = NULL;
+ e->flags = START;
+
+ self->num_edges++;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_botor_scan_converter_add_edge (void *converter,
+ const cairo_point_t *p1,
+ const cairo_point_t *p2,
+ int top, int bottom,
+ int dir)
+{
+ cairo_botor_scan_converter_t *self = converter;
+ cairo_edge_t edge;
+
+ edge.line.p1 = *p1;
+ edge.line.p2 = *p2;
+ edge.top = top;
+ edge.bottom = bottom;
+ edge.dir = dir;
+
+ return botor_add_edge (self, &edge);
+}
+
+static cairo_status_t
+_cairo_botor_scan_converter_add_polygon (void *converter,
+ const cairo_polygon_t *polygon)
+{
+ cairo_botor_scan_converter_t *self = converter;
+ cairo_status_t status;
+ int i;
+
+ for (i = 0; i < polygon->num_edges; i++) {
+ status = botor_add_edge (self, &polygon->edges[i]);
+ if (unlikely (status))
+ return status;
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static void
+_cairo_botor_scan_converter_destroy (void *converter)
+{
+ cairo_botor_scan_converter_t *self = converter;
+ struct _cairo_botor_scan_converter_chunk *chunk, *next;
+
+ for (chunk = self->chunks.next; chunk != NULL; chunk = next) {
+ next = chunk->next;
+ free (chunk);
+ }
+}
+
+void
+_cairo_botor_scan_converter_init (cairo_botor_scan_converter_t *self,
+ const cairo_box_t *extents,
+ cairo_fill_rule_t fill_rule)
+{
+ self->base.destroy = _cairo_botor_scan_converter_destroy;
+ self->base.add_edge = _cairo_botor_scan_converter_add_edge;
+ self->base.add_polygon = _cairo_botor_scan_converter_add_polygon;
+ self->base.generate = _cairo_botor_scan_converter_generate;
+
+ self->extents = *extents;
+ self->fill_rule = fill_rule;
+
+ self->xmin = _cairo_fixed_integer_floor (extents->p1.x);
+ self->xmax = _cairo_fixed_integer_ceil (extents->p2.x);
+
+ self->chunks.base = self->buf;
+ self->chunks.next = NULL;
+ self->chunks.count = 0;
+ self->chunks.size = sizeof (self->buf) / sizeof (edge_t);
+ self->tail = &self->chunks;
+
+ self->num_edges = 0;
+}
diff --git a/src/cairo-compiler-private.h b/src/cairo-compiler-private.h
index 403c3f7..34da73c 100644
--- a/src/cairo-compiler-private.h
+++ b/src/cairo-compiler-private.h
@@ -44,6 +44,15 @@
#include "config.h"
#endif
+/* Size in bytes of buffer to use off the stack per functions.
+ * Mostly used by text functions. For larger allocations, they'll
+ * malloc(). */
+#ifndef CAIRO_STACK_BUFFER_SIZE
+#define CAIRO_STACK_BUFFER_SIZE (512 * sizeof (int))
+#endif
+
+#define CAIRO_STACK_ARRAY_LENGTH(T) (CAIRO_STACK_BUFFER_SIZE / sizeof(T))
+
#if __GNUC__ >= 3 && defined(__ELF__) && !defined(__sun)
# define slim_hidden_proto(name) slim_hidden_proto1(name, slim_hidden_int_name(name)) cairo_private
# define slim_hidden_proto_no_warn(name) slim_hidden_proto1(name, slim_hidden_int_name(name)) cairo_private_no_warn
@@ -134,9 +143,11 @@
#if __GNUC__ >= 3
#define cairo_pure __attribute__((pure))
#define cairo_const __attribute__((const))
+#define always_inline inline __attribute__((always_inline))
#else
#define cairo_pure
#define cairo_const
+#define always_inline inline
#endif
#if defined(__GNUC__) && (__GNUC__ > 2) && defined(__OPTIMIZE__)
diff --git a/src/cairo-fixed-private.h b/src/cairo-fixed-private.h
index 68fa577..1e44902 100644
--- a/src/cairo-fixed-private.h
+++ b/src/cairo-fixed-private.h
@@ -148,12 +148,30 @@ _cairo_fixed_is_integer (cairo_fixed_t f)
}
static inline int
+_cairo_fixed_floor (cairo_fixed_t f)
+{
+ return f & ~CAIRO_FIXED_FRAC_MASK;
+}
+
+static inline int
_cairo_fixed_integer_part (cairo_fixed_t f)
{
return f >> CAIRO_FIXED_FRAC_BITS;
}
static inline int
+_cairo_fixed_integer_round (cairo_fixed_t f)
+{
+ return (f + (CAIRO_FIXED_FRAC_MASK+1)/2) >> CAIRO_FIXED_FRAC_BITS;
+}
+
+static inline int
+_cairo_fixed_fractional_part (cairo_fixed_t f)
+{
+ return f & CAIRO_FIXED_FRAC_MASK;
+}
+
+static inline int
_cairo_fixed_integer_floor (cairo_fixed_t f)
{
if (f >= 0)
@@ -221,9 +239,9 @@ static inline int
_cairo_fixed_16_16_floor (cairo_fixed_t f)
{
if (f >= 0)
- return f >> 16;
+ return f >> 16;
else
- return -((-f - 1) >> 16) - 1;
+ return -((-f - 1) >> 16) - 1;
}
#if CAIRO_FIXED_BITS == 32
diff --git a/src/cairo-freelist-private.h b/src/cairo-freelist-private.h
index 5be22b1..43dde29 100644
--- a/src/cairo-freelist-private.h
+++ b/src/cairo-freelist-private.h
@@ -54,6 +54,7 @@ struct _cairo_freelist_pool {
typedef struct _cairo_freepool {
cairo_freelist_node_t *first_free_node;
cairo_freelist_pool_t *pools;
+ cairo_freelist_pool_t *freepools;
unsigned nodesize;
cairo_freelist_pool_t embedded_pool;
uint8_t embedded_data[1000];
@@ -96,6 +97,21 @@ _cairo_freepool_init (cairo_freepool_t *freepool, unsigned nodesize);
cairo_private void
_cairo_freepool_fini (cairo_freepool_t *freepool);
+static inline void
+_cairo_freepool_reset (cairo_freepool_t *freepool)
+{
+ while (freepool->pools != &freepool->embedded_pool) {
+ cairo_freelist_pool_t *pool = freepool->pools;
+ freepool->pools = pool->next;
+ pool->next = freepool->freepools;
+ freepool->freepools = pool;
+ }
+
+ freepool->embedded_pool.rem = sizeof (freepool->embedded_data);
+ freepool->embedded_pool.data = freepool->embedded_data;
+}
+
+
cairo_private void *
_cairo_freepool_alloc_from_new_pool (cairo_freepool_t *freepool);
diff --git a/src/cairo-freelist.c b/src/cairo-freelist.c
index a62976e..eb42043 100644
--- a/src/cairo-freelist.c
+++ b/src/cairo-freelist.c
@@ -90,6 +90,7 @@ _cairo_freepool_init (cairo_freepool_t *freepool, unsigned nodesize)
{
freepool->first_free_node = NULL;
freepool->pools = &freepool->embedded_pool;
+ freepool->freepools = NULL;
freepool->nodesize = nodesize;
freepool->embedded_pool.next = NULL;
@@ -104,12 +105,22 @@ _cairo_freepool_init (cairo_freepool_t *freepool, unsigned nodesize)
void
_cairo_freepool_fini (cairo_freepool_t *freepool)
{
- cairo_freelist_pool_t *pool = freepool->pools;
+ cairo_freelist_pool_t *pool;
+
+ pool = freepool->pools;
while (pool != &freepool->embedded_pool) {
cairo_freelist_pool_t *next = pool->next;
free (pool);
pool = next;
}
+
+ pool = freepool->freepools;
+ while (pool != NULL) {
+ cairo_freelist_pool_t *next = pool->next;
+ free (pool);
+ pool = next;
+ }
+
VG (VALGRIND_MAKE_MEM_NOACCESS (freepool, sizeof (freepool)));
}
@@ -119,18 +130,27 @@ _cairo_freepool_alloc_from_new_pool (cairo_freepool_t *freepool)
cairo_freelist_pool_t *pool;
int poolsize;
- if (freepool->pools != &freepool->embedded_pool)
- poolsize = 2 * freepool->pools->size;
- else
- poolsize = (128 * freepool->nodesize + 8191) & -8192;
- pool = malloc (sizeof (cairo_freelist_pool_t) + poolsize);
- if (unlikely (pool == NULL))
- return pool;
+ if (freepool->freepools != NULL) {
+ pool = freepool->freepools;
+ freepool->freepools = pool->next;
+
+ poolsize = pool->size;
+ } else {
+ if (freepool->pools != &freepool->embedded_pool)
+ poolsize = 2 * freepool->pools->size;
+ else
+ poolsize = (128 * freepool->nodesize + 8191) & -8192;
+
+ pool = malloc (sizeof (cairo_freelist_pool_t) + poolsize);
+ if (unlikely (pool == NULL))
+ return pool;
+
+ pool->size = poolsize;
+ }
pool->next = freepool->pools;
freepool->pools = pool;
- pool->size = poolsize;
pool->rem = poolsize - freepool->nodesize;
pool->data = (uint8_t *) (pool + 1) + freepool->nodesize;
diff --git a/src/cairo-spans-private.h b/src/cairo-spans-private.h
index af3b38c..c2be867 100644
--- a/src/cairo-spans-private.h
+++ b/src/cairo-spans-private.h
@@ -103,6 +103,29 @@ _cairo_tor_scan_converter_create (int xmin,
int ymax,
cairo_fill_rule_t fill_rule);
+typedef struct _cairo_botor_scan_converter {
+ cairo_scan_converter_t base;
+
+ cairo_box_t extents;
+ cairo_fill_rule_t fill_rule;
+
+ int xmin, xmax;
+
+ struct _cairo_botor_scan_converter_chunk {
+ struct _cairo_botor_scan_converter_chunk *next;
+ void *base;
+ int count;
+ int size;
+ } chunks, *tail;
+ char buf[CAIRO_STACK_BUFFER_SIZE];
+ int num_edges;
+} cairo_botor_scan_converter_t;
+
+cairo_private void
+_cairo_botor_scan_converter_init (cairo_botor_scan_converter_t *self,
+ const cairo_box_t *extents,
+ cairo_fill_rule_t fill_rule);
+
/* cairo-spans.c: */
cairo_private cairo_scan_converter_t *
diff --git a/src/cairoint.h b/src/cairoint.h
index b2592c9..aea2b92 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -136,15 +136,6 @@ _cairo_win32_tmpfile (void);
#endif
-/* Size in bytes of buffer to use off the stack per functions.
- * Mostly used by text functions. For larger allocations, they'll
- * malloc(). */
-#ifndef CAIRO_STACK_BUFFER_SIZE
-#define CAIRO_STACK_BUFFER_SIZE (512 * sizeof (int))
-#endif
-
-#define CAIRO_STACK_ARRAY_LENGTH(T) (CAIRO_STACK_BUFFER_SIZE / sizeof(T))
-
#define ASSERT_NOT_REACHED \
do { \
static const int NOT_REACHED = 0; \
commit 424dcf296378a107286a164aaf135a34e40c42ac
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Tue Jan 19 19:11:31 2010 +0000
boxes: Enable generation of boxes from rectilinear polygons.
Extend the special case rectilinear tessellator to also produce boxes.
diff --git a/src/cairo-bentley-ottmann-rectilinear.c b/src/cairo-bentley-ottmann-rectilinear.c
index c0b4fcc..dfad964 100644
--- a/src/cairo-bentley-ottmann-rectilinear.c
+++ b/src/cairo-bentley-ottmann-rectilinear.c
@@ -38,6 +38,7 @@
/* Provide definitions for standalone compilation */
#include "cairoint.h"
+#include "cairo-boxes-private.h"
#include "cairo-combsort-private.h"
#include "cairo-error-private.h"
@@ -216,20 +217,33 @@ edges_collinear (const cairo_bo_edge_t *a, const cairo_bo_edge_t *b)
static cairo_status_t
_cairo_bo_edge_end_trap (cairo_bo_edge_t *left,
int32_t bot,
- cairo_traps_t *traps)
+ cairo_bool_t do_traps,
+ void *container)
{
cairo_bo_trap_t *trap = &left->deferred_trap;
+ cairo_status_t status = CAIRO_STATUS_SUCCESS;
/* Only emit (trivial) non-degenerate trapezoids with positive height. */
if (likely (trap->top < bot)) {
- _cairo_traps_add_trap (traps,
- trap->top, bot,
- &left->edge.line, &trap->right->edge.line);
+ if (do_traps) {
+ _cairo_traps_add_trap (container,
+ trap->top, bot,
+ &left->edge.line, &trap->right->edge.line);
+ status = _cairo_traps_status ((cairo_traps_t *) container);
+ } else {
+ cairo_box_t box;
+
+ box.p1.x = left->edge.line.p1.x;
+ box.p1.y = trap->top;
+ box.p2.x = trap->right->edge.line.p1.x;
+ box.p2.y = bot;
+ status = _cairo_boxes_add (container, &box);
+ }
}
trap->right = NULL;
- return _cairo_traps_status (traps);
+ return status;
}
/* Start a new trapezoid at the given top y coordinate, whose edges
@@ -241,7 +255,8 @@ static inline cairo_status_t
_cairo_bo_edge_start_or_continue_trap (cairo_bo_edge_t *left,
cairo_bo_edge_t *right,
int top,
- cairo_traps_t *traps)
+ cairo_bool_t do_traps,
+ void *container)
{
cairo_status_t status;
@@ -256,7 +271,7 @@ _cairo_bo_edge_start_or_continue_trap (cairo_bo_edge_t *left,
return CAIRO_STATUS_SUCCESS;
}
- status = _cairo_bo_edge_end_trap (left, top, traps);
+ status = _cairo_bo_edge_end_trap (left, top, do_traps, container);
if (unlikely (status))
return status;
}
@@ -273,7 +288,8 @@ static inline cairo_status_t
_active_edges_to_traps (cairo_bo_edge_t *left,
int32_t top,
cairo_fill_rule_t fill_rule,
- cairo_traps_t *traps)
+ cairo_bool_t do_traps,
+ void *container)
{
cairo_bo_edge_t *right;
cairo_status_t status;
@@ -304,7 +320,7 @@ _active_edges_to_traps (cairo_bo_edge_t *left,
right = left->next;
while (right != NULL) {
if (right->deferred_trap.right != NULL) {
- status = _cairo_bo_edge_end_trap (right, top, traps);
+ status = _cairo_bo_edge_end_trap (right, top, do_traps, container);
if (unlikely (status))
return status;
}
@@ -322,8 +338,8 @@ _active_edges_to_traps (cairo_bo_edge_t *left,
right = right->next;
}
- status = _cairo_bo_edge_start_or_continue_trap (left, right,
- top, traps);
+ status = _cairo_bo_edge_start_or_continue_trap (left, right, top,
+ do_traps, container);
if (unlikely (status))
return status;
@@ -338,7 +354,7 @@ _active_edges_to_traps (cairo_bo_edge_t *left,
right = left->next;
while (right != NULL) {
if (right->deferred_trap.right != NULL) {
- status = _cairo_bo_edge_end_trap (right, top, traps);
+ status = _cairo_bo_edge_end_trap (right, top, do_traps, container);
if (unlikely (status))
return status;
}
@@ -359,8 +375,8 @@ _active_edges_to_traps (cairo_bo_edge_t *left,
right = right->next;
}
- status = _cairo_bo_edge_start_or_continue_trap (left, right,
- top, traps);
+ status = _cairo_bo_edge_start_or_continue_trap (left, right, top,
+ do_traps, container);
if (unlikely (status))
return status;
@@ -377,7 +393,8 @@ static cairo_status_t
_cairo_bentley_ottmann_tessellate_rectilinear (cairo_bo_event_t **start_events,
int num_events,
cairo_fill_rule_t fill_rule,
- cairo_traps_t *traps)
+ cairo_bool_t do_traps,
+ void *container)
{
cairo_bo_sweep_line_t sweep_line;
cairo_bo_event_t *event;
@@ -389,7 +406,7 @@ _cairo_bentley_ottmann_tessellate_rectilinear (cairo_bo_event_t **start_events
if (event->point.y != sweep_line.current_y) {
status = _active_edges_to_traps (sweep_line.head,
sweep_line.current_y,
- fill_rule, traps);
+ fill_rule, do_traps, container);
if (unlikely (status))
return status;
@@ -407,7 +424,7 @@ _cairo_bentley_ottmann_tessellate_rectilinear (cairo_bo_event_t **start_events
if (event->edge->deferred_trap.right != NULL) {
status = _cairo_bo_edge_end_trap (event->edge,
sweep_line.current_y,
- traps);
+ do_traps, container);
if (unlikely (status))
return status;
}
@@ -477,7 +494,8 @@ _cairo_bentley_ottmann_tessellate_rectilinear_polygon (cairo_traps_t *traps,
}
status = _cairo_bentley_ottmann_tessellate_rectilinear (event_ptrs, j,
- fill_rule, traps);
+ fill_rule,
+ TRUE, traps);
if (events != stack_events)
free (events);
@@ -487,6 +505,72 @@ _cairo_bentley_ottmann_tessellate_rectilinear_polygon (cairo_traps_t *traps,
}
cairo_status_t
+_cairo_bentley_ottmann_tessellate_rectilinear_polygon_to_boxes (const cairo_polygon_t *polygon,
+ cairo_fill_rule_t fill_rule,
+ cairo_boxes_t *boxes)
+{
+ cairo_status_t status;
+ cairo_bo_event_t stack_events[CAIRO_STACK_ARRAY_LENGTH (cairo_bo_event_t)];
+ cairo_bo_event_t *events;
+ cairo_bo_event_t *stack_event_ptrs[ARRAY_LENGTH (stack_events) + 1];
+ cairo_bo_event_t **event_ptrs;
+ cairo_bo_edge_t stack_edges[ARRAY_LENGTH (stack_events)];
+ cairo_bo_edge_t *edges;
+ int num_events;
+ int i, j;
+
+ if (unlikely (polygon->num_edges == 0))
+ return CAIRO_STATUS_SUCCESS;
+
+ num_events = 2 * polygon->num_edges;
+
+ events = stack_events;
+ event_ptrs = stack_event_ptrs;
+ edges = stack_edges;
+ if (num_events > ARRAY_LENGTH (stack_events)) {
+ events = _cairo_malloc_ab_plus_c (num_events,
+ sizeof (cairo_bo_event_t) +
+ sizeof (cairo_bo_edge_t) +
+ sizeof (cairo_bo_event_t *),
+ sizeof (cairo_bo_event_t *));
+ if (unlikely (events == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+ event_ptrs = (cairo_bo_event_t **) (events + num_events);
+ edges = (cairo_bo_edge_t *) (event_ptrs + num_events + 1);
+ }
+
+ for (i = j = 0; i < polygon->num_edges; i++) {
+ edges[i].edge = polygon->edges[i];
+ edges[i].deferred_trap.right = NULL;
+ edges[i].prev = NULL;
+ edges[i].next = NULL;
+
+ event_ptrs[j] = &events[j];
+ events[j].type = CAIRO_BO_EVENT_TYPE_START;
+ events[j].point.y = polygon->edges[i].top;
+ events[j].point.x = polygon->edges[i].line.p1.x;
+ events[j].edge = &edges[i];
+ j++;
+
+ event_ptrs[j] = &events[j];
+ events[j].type = CAIRO_BO_EVENT_TYPE_STOP;
+ events[j].point.y = polygon->edges[i].bottom;
+ events[j].point.x = polygon->edges[i].line.p1.x;
+ events[j].edge = &edges[i];
+ j++;
+ }
+
+ status = _cairo_bentley_ottmann_tessellate_rectilinear (event_ptrs, j,
+ fill_rule,
+ FALSE, boxes);
+ if (events != stack_events)
+ free (events);
+
+ return status;
+}
+
+cairo_status_t
_cairo_bentley_ottmann_tessellate_rectilinear_traps (cairo_traps_t *traps,
cairo_fill_rule_t fill_rule)
{
@@ -573,7 +657,7 @@ _cairo_bentley_ottmann_tessellate_rectilinear_traps (cairo_traps_t *traps,
_cairo_traps_clear (traps);
status = _cairo_bentley_ottmann_tessellate_rectilinear (event_ptrs, j,
fill_rule,
- traps);
+ TRUE, traps);
traps->is_rectilinear = TRUE;
if (events != stack_events)
diff --git a/src/cairoint.h b/src/cairoint.h
index 295f2e1..b2592c9 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -2451,6 +2451,11 @@ cairo_private cairo_status_t
_cairo_bentley_ottmann_tessellate_rectilinear_traps (cairo_traps_t *traps,
cairo_fill_rule_t fill_rule);
+cairo_private cairo_status_t
+_cairo_bentley_ottmann_tessellate_rectilinear_polygon_to_boxes (const cairo_polygon_t *polygon,
+ cairo_fill_rule_t fill_rule,
+ cairo_boxes_t *boxes);
+
cairo_private int
_cairo_traps_contain (const cairo_traps_t *traps,
double x, double y);
commit b83f1c347dfd77139e9485745d43da946b086b74
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Tue Jan 19 19:09:10 2010 +0000
boxes: Enable tessellation
Extend the special case rectangular tessellator to handle generation of
cairo_boxes_t.
diff --git a/src/cairo-bentley-ottmann-rectangular.c b/src/cairo-bentley-ottmann-rectangular.c
index 4a65655..ce4e01f 100644
--- a/src/cairo-bentley-ottmann-rectangular.c
+++ b/src/cairo-bentley-ottmann-rectangular.c
@@ -38,31 +38,30 @@
/* Provide definitions for standalone compilation */
#include "cairoint.h"
+#include "cairo-boxes-private.h"
#include "cairo-error-private.h"
#include "cairo-combsort-private.h"
#include "cairo-list-private.h"
-typedef struct _cairo_bo_rectangle cairo_bo_rectangle_t;
-typedef struct _cairo_bo_edge cairo_bo_edge_t;
+#include <setjmp.h>
-/* A deferred trapezoid of an edge */
-typedef struct _cairo_bo_trap {
- cairo_bo_edge_t *right;
- int32_t top;
-} cairo_bo_trap_t;
+typedef struct _rectangle rectangle_t;
+typedef struct _edge edge_t;
-struct _cairo_bo_edge {
- int x;
+struct _edge {
+ edge_t *next, *prev;
+ edge_t *right;
+ cairo_fixed_t x, top;
int dir;
- cairo_bo_trap_t deferred_trap;
- cairo_list_t link;
};
-struct _cairo_bo_rectangle {
- cairo_bo_edge_t left, right;
- int top, bottom;
+struct _rectangle {
+ edge_t left, right;
+ int32_t top, bottom;
};
+#define UNROLL3(x) x x x
+
/* the parent is always given by index/2 */
#define PQ_PARENT_INDEX(i) ((i) >> 1)
#define PQ_FIRST_ENTRY 1
@@ -73,18 +72,22 @@ struct _cairo_bo_rectangle {
typedef struct _pqueue {
int size, max_size;
- cairo_bo_rectangle_t **elements;
- cairo_bo_rectangle_t *elements_embedded[1024];
+ rectangle_t **elements;
+ rectangle_t *elements_embedded[1024];
} pqueue_t;
-typedef struct _cairo_bo_sweep_line {
- cairo_bo_rectangle_t **rectangles;
- pqueue_t stop;
- cairo_list_t sweep;
- cairo_list_t *current_left, *current_right;
+typedef struct _sweep_line {
+ rectangle_t **rectangles;
+ pqueue_t pq;
+ edge_t head, tail;
+ edge_t *insert_left, *insert_right;
int32_t current_y;
int32_t last_y;
-} cairo_bo_sweep_line_t;
+
+ cairo_fill_rule_t fill_rule;
+
+ jmp_buf unwind;
+} sweep_line_t;
#define DEBUG_TRAPS 0
@@ -122,21 +125,21 @@ dump_traps (cairo_traps_t *traps, const char *filename)
#endif
static inline int
-cairo_bo_rectangle_compare_start (const cairo_bo_rectangle_t *a,
- const cairo_bo_rectangle_t *b)
+rectangle_compare_start (const rectangle_t *a,
+ const rectangle_t *b)
{
return a->top - b->top;
}
static inline int
-_cairo_bo_rectangle_compare_stop (const cairo_bo_rectangle_t *a,
- const cairo_bo_rectangle_t *b)
+rectangle_compare_stop (const rectangle_t *a,
+ const rectangle_t *b)
{
return a->bottom - b->bottom;
}
static inline void
-_pqueue_init (pqueue_t *pq)
+pqueue_init (pqueue_t *pq)
{
pq->max_size = ARRAY_LENGTH (pq->elements_embedded);
pq->size = 0;
@@ -146,73 +149,69 @@ _pqueue_init (pqueue_t *pq)
}
static inline void
-_pqueue_fini (pqueue_t *pq)
+pqueue_fini (pqueue_t *pq)
{
if (pq->elements != pq->elements_embedded)
free (pq->elements);
}
-static cairo_status_t
-_pqueue_grow (pqueue_t *pq)
+static cairo_bool_t
+pqueue_grow (pqueue_t *pq)
{
- cairo_bo_rectangle_t **new_elements;
+ rectangle_t **new_elements;
pq->max_size *= 2;
if (pq->elements == pq->elements_embedded) {
new_elements = _cairo_malloc_ab (pq->max_size,
- sizeof (cairo_bo_rectangle_t *));
+ sizeof (rectangle_t *));
if (unlikely (new_elements == NULL))
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ return FALSE;
memcpy (new_elements, pq->elements_embedded,
sizeof (pq->elements_embedded));
} else {
new_elements = _cairo_realloc_ab (pq->elements,
pq->max_size,
- sizeof (cairo_bo_rectangle_t *));
+ sizeof (rectangle_t *));
if (unlikely (new_elements == NULL))
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ return FALSE;
}
pq->elements = new_elements;
- return CAIRO_STATUS_SUCCESS;
+ return TRUE;
}
-static inline cairo_status_t
-_pqueue_push (pqueue_t *pq, cairo_bo_rectangle_t *rectangle)
+static inline void
+pqueue_push (sweep_line_t *sweep, rectangle_t *rectangle)
{
- cairo_bo_rectangle_t **elements;
+ rectangle_t **elements;
int i, parent;
- if (unlikely (pq->size + 1 == pq->max_size)) {
- cairo_status_t status;
-
- status = _pqueue_grow (pq);
- if (unlikely (status))
- return status;
+ if (unlikely (sweep->pq.size + 1 == sweep->pq.max_size)) {
+ if (unlikely (! pqueue_grow (&sweep->pq))) {
+ longjmp (sweep->unwind,
+ _cairo_error (CAIRO_STATUS_NO_MEMORY));
+ }
}
- elements = pq->elements;
-
- for (i = ++pq->size;
+ elements = sweep->pq.elements;
+ for (i = ++sweep->pq.size;
i != PQ_FIRST_ENTRY &&
- _cairo_bo_rectangle_compare_stop (rectangle,
- elements[parent = PQ_PARENT_INDEX (i)]) < 0;
+ rectangle_compare_stop (rectangle,
+ elements[parent = PQ_PARENT_INDEX (i)]) < 0;
i = parent)
{
elements[i] = elements[parent];
}
elements[i] = rectangle;
-
- return CAIRO_STATUS_SUCCESS;
}
static inline void
-_pqueue_pop (pqueue_t *pq)
+pqueue_pop (pqueue_t *pq)
{
- cairo_bo_rectangle_t **elements = pq->elements;
- cairo_bo_rectangle_t *tail;
+ rectangle_t **elements = pq->elements;
+ rectangle_t *tail;
int child, i;
tail = elements[pq->size--];
@@ -226,13 +225,13 @@ _pqueue_pop (pqueue_t *pq)
i = child)
{
if (child != pq->size &&
- _cairo_bo_rectangle_compare_stop (elements[child+1],
- elements[child]) < 0)
+ rectangle_compare_stop (elements[child+1],
+ elements[child]) < 0)
{
child++;
}
- if (_cairo_bo_rectangle_compare_stop (elements[child], tail) >= 0)
+ if (rectangle_compare_stop (elements[child], tail) >= 0)
break;
elements[i] = elements[child];
@@ -240,74 +239,94 @@ _pqueue_pop (pqueue_t *pq)
elements[i] = tail;
}
-static inline cairo_bo_rectangle_t *
-_cairo_bo_rectangle_pop_start (cairo_bo_sweep_line_t *sweep_line)
+static inline rectangle_t *
+rectangle_pop_start (sweep_line_t *sweep_line)
{
return *sweep_line->rectangles++;
}
-static inline cairo_bo_rectangle_t *
-_cairo_bo_rectangle_peek_stop (cairo_bo_sweep_line_t *sweep_line)
+static inline rectangle_t *
+rectangle_peek_stop (sweep_line_t *sweep_line)
{
- return sweep_line->stop.elements[PQ_FIRST_ENTRY];
+ return sweep_line->pq.elements[PQ_FIRST_ENTRY];
}
-CAIRO_COMBSORT_DECLARE (_cairo_bo_rectangle_sort,
- cairo_bo_rectangle_t *,
- cairo_bo_rectangle_compare_start)
+CAIRO_COMBSORT_DECLARE (_rectangle_sort,
+ rectangle_t *,
+ rectangle_compare_start)
static void
-_cairo_bo_sweep_line_init (cairo_bo_sweep_line_t *sweep_line,
- cairo_bo_rectangle_t **rectangles,
- int num_rectangles)
+sweep_line_init (sweep_line_t *sweep_line,
+ rectangle_t **rectangles,
+ int num_rectangles,
+ cairo_fill_rule_t fill_rule)
{
- _cairo_bo_rectangle_sort (rectangles, num_rectangles);
+ _rectangle_sort (rectangles, num_rectangles);
rectangles[num_rectangles] = NULL;
sweep_line->rectangles = rectangles;
- cairo_list_init (&sweep_line->sweep);
- sweep_line->current_left = &sweep_line->sweep;
- sweep_line->current_right = &sweep_line->sweep;
+ sweep_line->head.x = INT32_MIN;
+ sweep_line->head.right = NULL;
+ sweep_line->head.dir = 0;
+ sweep_line->head.next = &sweep_line->tail;
+ sweep_line->tail.x = INT32_MAX;
+ sweep_line->tail.right = NULL;
+ sweep_line->tail.dir = 0;
+ sweep_line->tail.prev = &sweep_line->head;
+
+ sweep_line->insert_left = &sweep_line->tail;
+ sweep_line->insert_right = &sweep_line->tail;
+
sweep_line->current_y = INT32_MIN;
sweep_line->last_y = INT32_MIN;
- _pqueue_init (&sweep_line->stop);
-}
+ sweep_line->fill_rule = fill_rule;
-static void
-_cairo_bo_sweep_line_fini (cairo_bo_sweep_line_t *sweep_line)
-{
- _pqueue_fini (&sweep_line->stop);
+ pqueue_init (&sweep_line->pq);
}
-static inline cairo_bo_edge_t *
-link_to_edge (cairo_list_t *elt)
+static void
+sweep_line_fini (sweep_line_t *sweep_line)
{
- return cairo_container_of (elt, cairo_bo_edge_t, link);
+ pqueue_fini (&sweep_line->pq);
}
-static cairo_status_t
-_cairo_bo_edge_end_trap (cairo_bo_edge_t *left,
- int32_t bot,
- cairo_traps_t *traps)
+static void
+edge_end_box (sweep_line_t *sweep_line,
+ edge_t *left,
+ int32_t bot,
+ cairo_bool_t do_traps,
+ void *container)
{
- cairo_bo_trap_t *trap = &left->deferred_trap;
+ cairo_status_t status = CAIRO_STATUS_SUCCESS;
/* Only emit (trivial) non-degenerate trapezoids with positive height. */
- if (likely (trap->top < bot)) {
- cairo_line_t _left = {
- { left->x, trap->top },
- { left->x, bot },
- }, _right = {
- { trap->right->x, trap->top },
- { trap->right->x, bot },
- };
- _cairo_traps_add_trap (traps, trap->top, bot, &_left, &_right);
- }
+ if (likely (left->top < bot)) {
+ if (do_traps) {
+ cairo_line_t _left = {
+ { left->x, left->top },
+ { left->x, bot },
+ }, _right = {
+ { left->right->x, left->top },
+ { left->right->x, bot },
+ };
+ _cairo_traps_add_trap (container, left->top, bot, &_left, &_right);
+ status = _cairo_traps_status ((cairo_traps_t *) container);
+ } else {
+ cairo_box_t box;
- trap->right = NULL;
+ box.p1.x = left->x;
+ box.p1.y = left->top;
+ box.p2.x = left->right->x;
+ box.p2.y = bot;
+
+ status = _cairo_boxes_add (container, &box);
+ }
+ }
+ if (unlikely (status))
+ longjmp (sweep_line->unwind, status);
- return _cairo_traps_status (traps);
+ left->right = NULL;
}
/* Start a new trapezoid at the given top y coordinate, whose edges
@@ -315,75 +334,78 @@ _cairo_bo_edge_end_trap (cairo_bo_edge_t *left,
* then either add it to the traps in `traps', if the trapezoid's
* right edge differs from `edge->next', or do nothing if the new
* trapezoid would be a continuation of the existing one. */
-static inline cairo_status_t
-_cairo_bo_edge_start_or_continue_trap (cairo_bo_edge_t *left,
- cairo_bo_edge_t *right,
- int top,
- cairo_traps_t *traps)
+static inline void
+edge_start_or_continue_box (sweep_line_t *sweep_line,
+ edge_t *left,
+ edge_t *right,
+ int top,
+ cairo_bool_t do_traps,
+ void *container)
{
- cairo_status_t status;
-
- if (left->deferred_trap.right == right)
- return CAIRO_STATUS_SUCCESS;
+ if (left->right == right)
+ return;
- if (left->deferred_trap.right != NULL) {
- if (right != NULL && left->deferred_trap.right->x == right->x) {
+ if (left->right != NULL) {
+ if (right != NULL && left->right->x == right->x) {
/* continuation on right, so just swap edges */
- left->deferred_trap.right = right;
- return CAIRO_STATUS_SUCCESS;
+ left->right = right;
+ return;
}
- status = _cairo_bo_edge_end_trap (left, top, traps);
- if (unlikely (status))
- return status;
+ edge_end_box (sweep_line,
+ left, top, do_traps, container);
}
if (right != NULL && left->x != right->x) {
- left->deferred_trap.top = top;
- left->deferred_trap.right = right;
+ left->top = top;
+ left->right = right;
}
-
- return CAIRO_STATUS_SUCCESS;
}
-static inline cairo_status_t
-_active_edges_to_traps (cairo_bo_sweep_line_t *sweep,
- cairo_fill_rule_t fill_rule,
- cairo_traps_t *traps)
+static inline void
+active_edges_to_traps (sweep_line_t *sweep,
+ cairo_bool_t do_traps,
+ void *container)
{
int top = sweep->current_y;
- cairo_list_t *pos = &sweep->sweep;
- cairo_status_t status;
+ edge_t *pos;
if (sweep->last_y == sweep->current_y)
- return CAIRO_STATUS_SUCCESS;
+ return;
+
+ pos = sweep->head.next;
+ if (pos == &sweep->tail)
+ return;
- if (fill_rule == CAIRO_FILL_RULE_WINDING) {
+ if (sweep->fill_rule == CAIRO_FILL_RULE_WINDING) {
do {
- cairo_bo_edge_t *left, *right;
- int in_out;
+ edge_t *left, *right;
+ int winding;
- pos = pos->next;
- if (pos == &sweep->sweep)
- break;
+ left = pos;
+ winding = left->dir;
- left = link_to_edge (pos);
- in_out = left->dir;
+ right = left->next;
/* Check if there is a co-linear edge with an existing trap */
- if (left->deferred_trap.right == NULL) {
- right = link_to_edge (pos->next);
+ if (left->right == NULL) {
while (unlikely (right->x == left->x)) {
- if (right->deferred_trap.right != NULL) {
+ winding += right->dir;
+ if (right->right != NULL) {
/* continuation on left */
- left->deferred_trap = right->deferred_trap;
- right->deferred_trap.right = NULL;
+ left->top = right->top;
+ left->right = right->right;
+ right->right = NULL;
+ winding -= right->dir;
break;
}
- if (right->link.next == &sweep->sweep)
- break;
- right = link_to_edge (right->link.next);
+ right = right->next;
+ }
+
+ if (winding == 0) {
+ pos = right;
+ continue;
}
}
@@ -391,277 +413,234 @@ _active_edges_to_traps (cairo_bo_sweep_line_t *sweep,
* maximal span width with the minimal number of trapezoids.
*/
- right = link_to_edge (left->link.next);
do {
/* End all subsumed traps */
- if (right->deferred_trap.right != NULL) {
- status = _cairo_bo_edge_end_trap (right, top, traps);
- if (unlikely (status))
- return status;
+ if (unlikely (right->right != NULL)) {
+ edge_end_box (sweep,
+ right, top, do_traps, container);
}
- in_out += right->dir;
- if (in_out == 0) {
+ winding += right->dir;
+ if (winding == 0) {
/* skip co-linear edges */
- if (likely (right->link.next == &sweep->sweep ||
- right->x != link_to_edge (right->link.next)->x))
- {
+ if (likely (right->x != right->next->x))
break;
- }
}
- right = link_to_edge (right->link.next);
+ right = right->next;
} while (TRUE);
- status = _cairo_bo_edge_start_or_continue_trap (left, right,
- top, traps);
- if (unlikely (status))
- return status;
+ edge_start_or_continue_box (sweep,
+ left, right, top,
+ do_traps, container);
- pos = &right->link;
- } while (TRUE);
+ pos = right->next;
+ } while (pos != &sweep->tail);
} else {
- cairo_bo_edge_t *left, *right;
+ edge_t *left, *right;
do {
- int in_out = 0;
-
- pos = pos->next;
- if (pos == &sweep->sweep)
- break;
-
- left = link_to_edge (pos);
-
- pos = pos->next;
+ left = pos;
+ pos = left->next;
do {
- right = link_to_edge (pos);
- if (right->deferred_trap.right != NULL) {
- status = _cairo_bo_edge_end_trap (right, top, traps);
- if (unlikely (status))
- return status;
- }
-
- if ((in_out++ & 1) == 0) {
- cairo_list_t *next;
- cairo_bool_t skip = FALSE;
-
- /* skip co-linear edges */
- next = pos->next;
- if (next != &sweep->sweep)
- skip = right->x == link_to_edge (next)->x;
+ right = pos;
+ pos = pos->next;
- if (! skip)
- break;
+ if (right->right != NULL) {
+ edge_end_box (sweep,
+ right, top, do_traps, container);
}
- pos = pos->next;
+
+ /* skip co-linear edges */
+ if (right->x != pos->x)
+ break;
} while (TRUE);
- right = pos == &sweep->sweep ? NULL : link_to_edge (pos);
- status = _cairo_bo_edge_start_or_continue_trap (left, right,
- top, traps);
- if (unlikely (status))
- return status;
- } while (right != NULL);
+ edge_start_or_continue_box (sweep,
+ left, right, top,
+ do_traps, container);
+ } while (pos != &sweep->tail);
}
sweep->last_y = sweep->current_y;
- return CAIRO_STATUS_SUCCESS;
}
-static inline cairo_status_t
-_cairo_bo_sweep_line_delete_edge (cairo_bo_sweep_line_t *sweep_line,
- cairo_bo_edge_t *edge,
- cairo_traps_t *traps)
+static inline void
+sweep_line_delete_edge (sweep_line_t *sweep_line,
+ edge_t *edge,
+ cairo_bool_t do_traps,
+ void *container)
{
- if (edge->deferred_trap.right != NULL) {
- cairo_bo_edge_t *next = link_to_edge (edge->link.next);
- if (&next->link != &sweep_line->sweep && next->x == edge->x) {
- next->deferred_trap = edge->deferred_trap;
+ if (edge->right != NULL) {
+ edge_t *next = edge->next;
+ if (next->x == edge->x) {
+ next->top = edge->top;
+ next->right = edge->right;
} else {
- cairo_status_t status;
-
- status = _cairo_bo_edge_end_trap (edge,
- sweep_line->current_y,
- traps);
- if (unlikely (status))
- return status;
+ edge_end_box (sweep_line,
+ edge,
+ sweep_line->current_y,
+ do_traps, container);
}
}
- if (sweep_line->current_left == &edge->link)
- sweep_line->current_left = edge->link.prev;
-
- if (sweep_line->current_right == &edge->link)
- sweep_line->current_right = edge->link.next;
-
- cairo_list_del (&edge->link);
+ if (sweep_line->insert_left == edge)
+ sweep_line->insert_left = edge->next;
+ if (sweep_line->insert_right == edge)
+ sweep_line->insert_right = edge->next;
- return CAIRO_STATUS_SUCCESS;
+ edge->prev->next = edge->next;
+ edge->next->prev = edge->prev;
}
-static inline cairo_status_t
-_cairo_bo_sweep_line_delete (cairo_bo_sweep_line_t *sweep_line,
- cairo_bo_rectangle_t *rectangle,
- cairo_fill_rule_t fill_rule,
- cairo_traps_t *traps)
+static inline cairo_bool_t
+sweep_line_delete (sweep_line_t *sweep,
+ rectangle_t *rectangle,
+ cairo_bool_t do_traps,
+ void *container)
{
- cairo_status_t status;
-
- if (rectangle->bottom != sweep_line->current_y) {
- status = _active_edges_to_traps (sweep_line, fill_rule, traps);
- if (unlikely (status))
- return status;
+ cairo_bool_t update;
- sweep_line->current_y = rectangle->bottom;
+ update = TRUE;
+ if (sweep->fill_rule == CAIRO_FILL_RULE_WINDING &&
+ rectangle->left.prev->dir == rectangle->left.dir)
+ {
+ update = rectangle->left.next != &rectangle->right;
}
- status = _cairo_bo_sweep_line_delete_edge (sweep_line,
- &rectangle->left,
- traps);
- if (unlikely (status))
- return status;
+ sweep_line_delete_edge (sweep,
+ &rectangle->left,
+ do_traps, container);
- status = _cairo_bo_sweep_line_delete_edge (sweep_line,
- &rectangle->right,
- traps);
- if (unlikely (status))
- return status;
+ sweep_line_delete_edge (sweep,
+ &rectangle->right,
+ do_traps, container);
- _pqueue_pop (&sweep_line->stop);
- return CAIRO_STATUS_SUCCESS;
+ pqueue_pop (&sweep->pq);
+ return update;
}
-static cairo_bool_t
-validate_sweep_line (cairo_bo_sweep_line_t *sweep_line)
-{
- int32_t last_x = INT32_MIN;
- cairo_bo_edge_t *edge;
- cairo_list_foreach_entry (edge, cairo_bo_edge_t, &sweep_line->sweep, link) {
- if (edge->x < last_x)
- return FALSE;
- last_x = edge->x;
- }
- return TRUE;
-}
-static inline cairo_status_t
-_cairo_bo_sweep_line_insert (cairo_bo_sweep_line_t *sweep_line,
- cairo_bo_rectangle_t *rectangle,
- cairo_fill_rule_t fill_rule,
- cairo_traps_t *traps)
+static inline void
+insert_edge (edge_t *edge, edge_t *pos)
{
- cairo_list_t *pos;
- cairo_status_t status;
-
- if (rectangle->top != sweep_line->current_y) {
- cairo_bo_rectangle_t *stop;
-
- stop = _cairo_bo_rectangle_peek_stop (sweep_line);
- while (stop != NULL && stop->bottom < rectangle->top) {
- status = _cairo_bo_sweep_line_delete (sweep_line, stop,
- fill_rule, traps);
- if (unlikely (status))
- return status;
-
- stop = _cairo_bo_rectangle_peek_stop (sweep_line);
+ if (pos->x != edge->x) {
+ if (pos->x > edge->x) {
+ do {
+ UNROLL3({
+ if (pos->prev->x <= edge->x)
+ break;
+ pos = pos->prev;
+ })
+ } while (TRUE);
+ } else {
+ do {
+ UNROLL3({
+ pos = pos->next;
+ if (pos->x >= edge->x)
+ break;
+ })
+ } while (TRUE);
}
+ }
- status = _active_edges_to_traps (sweep_line, fill_rule, traps);
- if (unlikely (status))
- return status;
+ pos->prev->next = edge;
+ edge->prev = pos->prev;
+ edge->next = pos;
+ pos->prev = edge;
+}
- sweep_line->current_y = rectangle->top;
- }
+static inline cairo_bool_t
+sweep_line_insert (sweep_line_t *sweep,
+ rectangle_t *rectangle)
+{
+ edge_t *pos;
/* right edge */
- pos = sweep_line->current_right;
- if (pos == &sweep_line->sweep)
- pos = sweep_line->sweep.prev;
- if (pos != &sweep_line->sweep) {
- int cmp;
-
- cmp = link_to_edge (pos)->x - rectangle->right.x;
- if (cmp < 0) {
- while (pos->next != &sweep_line->sweep &&
- link_to_edge (pos->next)->x - rectangle->right.x < 0)
- {
- pos = pos->next;
- }
- } else if (cmp > 0) {
- do {
- pos = pos->prev;
- } while (pos != &sweep_line->sweep &&
- link_to_edge (pos)->x - rectangle->right.x > 0);
- }
-
- cairo_list_add (&rectangle->right.link, pos);
- } else {
- cairo_list_add_tail (&rectangle->right.link, pos);
- }
- sweep_line->current_right = &rectangle->right.link;
- assert (validate_sweep_line (sweep_line));
+ pos = sweep->insert_right;
+ insert_edge (&rectangle->right, pos);
+ sweep->insert_right = &rectangle->right;
/* left edge */
- pos = sweep_line->current_left;
- if (pos == &sweep_line->sweep)
- pos = sweep_line->sweep.next;
- if (pos != &sweep_line->sweep) {
- int cmp;
-
- if (link_to_edge (pos)->x >= rectangle->right.x) {
- pos = rectangle->right.link.prev;
- if (pos == &sweep_line->sweep)
- goto left_done;
- }
+ pos = sweep->insert_left;
+ if (pos->x > sweep->insert_right->x)
+ pos = sweep->insert_right->prev;
+ insert_edge (&rectangle->left, pos);
+ sweep->insert_left = &rectangle->left;
- cmp = link_to_edge (pos)->x - rectangle->left.x;
- if (cmp < 0) {
- while (pos->next != &sweep_line->sweep &&
- link_to_edge (pos->next)->x - rectangle->left.x < 0)
- {
- pos = pos->next;
- }
- } else if (cmp > 0) {
- do {
- pos = pos->prev;
- } while (pos != &sweep_line->sweep &&
- link_to_edge (pos)->x - rectangle->left.x > 0);
- }
+ pqueue_push (sweep, rectangle);
+
+ if (sweep->fill_rule == CAIRO_FILL_RULE_WINDING &&
+ rectangle->left.prev->dir == rectangle->left.dir)
+ {
+ return rectangle->left.next != &rectangle->right;
}
- left_done:
- cairo_list_add (&rectangle->left.link, pos);
- sweep_line->current_left = &rectangle->left.link;
- assert (validate_sweep_line (sweep_line));
- return _pqueue_push (&sweep_line->stop, rectangle);
+ return TRUE;
}
static cairo_status_t
-_cairo_bentley_ottmann_tessellate_rectangular (cairo_bo_rectangle_t **rectangles,
+_cairo_bentley_ottmann_tessellate_rectangular (rectangle_t **rectangles,
int num_rectangles,
cairo_fill_rule_t fill_rule,
- cairo_traps_t *traps)
+ cairo_bool_t do_traps,
+ void *container)
{
- cairo_bo_sweep_line_t sweep_line;
- cairo_bo_rectangle_t *rectangle;
- cairo_status_t status = CAIRO_STATUS_SUCCESS;
+ sweep_line_t sweep_line;
+ rectangle_t *rectangle;
+ cairo_status_t status;
+ cairo_bool_t update = FALSE;
+
+ sweep_line_init (&sweep_line, rectangles, num_rectangles, fill_rule);
+ if ((status = setjmp (sweep_line.unwind)))
+ goto unwind;
+
+ rectangle = rectangle_pop_start (&sweep_line);
+ do {
+ if (rectangle->top != sweep_line.current_y) {
+ rectangle_t *stop;
+
+ stop = rectangle_peek_stop (&sweep_line);
+ while (stop != NULL && stop->bottom < rectangle->top) {
+ if (stop->bottom != sweep_line.current_y) {
+ if (update) {
+ active_edges_to_traps (&sweep_line,
+ do_traps, container);
+ update = FALSE;
+ }
- _cairo_bo_sweep_line_init (&sweep_line, rectangles, num_rectangles);
+ sweep_line.current_y = stop->bottom;
+ }
- while ((rectangle = _cairo_bo_rectangle_pop_start (&sweep_line)) != NULL) {
- status = _cairo_bo_sweep_line_insert (&sweep_line, rectangle,
- fill_rule, traps);
- if (unlikely (status))
- goto BAIL;
- }
+ update |= sweep_line_delete (&sweep_line, stop, do_traps, container);
+
+ stop = rectangle_peek_stop (&sweep_line);
+ }
- while ((rectangle = _cairo_bo_rectangle_peek_stop (&sweep_line)) != NULL) {
- status = _cairo_bo_sweep_line_delete (&sweep_line, rectangle,
- fill_rule, traps);
- if (unlikely (status))
- goto BAIL;
+ if (update) {
+ active_edges_to_traps (&sweep_line, do_traps, container);
+ update = FALSE;
+ }
+
+ sweep_line.current_y = rectangle->top;
+ }
+
+ update |= sweep_line_insert (&sweep_line, rectangle);
+ } while ((rectangle = rectangle_pop_start (&sweep_line)) != NULL);
+
+ while ((rectangle = rectangle_peek_stop (&sweep_line)) != NULL) {
+ if (rectangle->bottom != sweep_line.current_y) {
+ if (update) {
+ active_edges_to_traps (&sweep_line, do_traps, container);
+ update = FALSE;
+ }
+
+ sweep_line.current_y = rectangle->bottom;
+ }
+
+ update |= sweep_line_delete (&sweep_line, rectangle, do_traps, container);
}
-BAIL:
- _cairo_bo_sweep_line_fini (&sweep_line);
+unwind:
+ sweep_line_fini (&sweep_line);
return status;
}
@@ -669,14 +648,14 @@ cairo_status_t
_cairo_bentley_ottmann_tessellate_rectangular_traps (cairo_traps_t *traps,
cairo_fill_rule_t fill_rule)
{
- cairo_bo_rectangle_t stack_rectangles[CAIRO_STACK_ARRAY_LENGTH (cairo_bo_rectangle_t)];
- cairo_bo_rectangle_t *rectangles;
- cairo_bo_rectangle_t *stack_rectangles_ptrs[ARRAY_LENGTH (stack_rectangles) + 1];
- cairo_bo_rectangle_t **rectangles_ptrs;
+ rectangle_t stack_rectangles[CAIRO_STACK_ARRAY_LENGTH (rectangle_t)];
+ rectangle_t *rectangles;
+ rectangle_t *stack_rectangles_ptrs[ARRAY_LENGTH (stack_rectangles) + 1];
+ rectangle_t **rectangles_ptrs;
cairo_status_t status;
int i;
- if (unlikely (traps->num_traps == 0))
+ if (unlikely (traps->num_traps <= 1))
return CAIRO_STATUS_SUCCESS;
assert (traps->is_rectangular);
@@ -687,13 +666,13 @@ _cairo_bentley_ottmann_tessellate_rectangular_traps (cairo_traps_t *traps,
rectangles_ptrs = stack_rectangles_ptrs;
if (traps->num_traps > ARRAY_LENGTH (stack_rectangles)) {
rectangles = _cairo_malloc_ab_plus_c (traps->num_traps,
- sizeof (cairo_bo_rectangle_t) +
- sizeof (cairo_bo_rectangle_t *),
- sizeof (cairo_bo_rectangle_t *));
+ sizeof (rectangle_t) +
+ sizeof (rectangle_t *),
+ sizeof (rectangle_t *));
if (unlikely (rectangles == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
- rectangles_ptrs = (cairo_bo_rectangle_t **) (rectangles + traps->num_traps);
+ rectangles_ptrs = (rectangle_t **) (rectangles + traps->num_traps);
}
for (i = 0; i < traps->num_traps; i++) {
@@ -711,11 +690,8 @@ _cairo_bentley_ottmann_tessellate_rectangular_traps (cairo_traps_t *traps,
rectangles[i].left.dir = -1;
}
- rectangles[i].left.deferred_trap.right = NULL;
- cairo_list_init (&rectangles[i].left.link);
-
- rectangles[i].right.deferred_trap.right = NULL;
- cairo_list_init (&rectangles[i].right.link);
+ rectangles[i].left.right = NULL;
+ rectangles[i].right.right = NULL;
rectangles[i].top = traps->traps[i].top;
rectangles[i].bottom = traps->traps[i].bottom;
@@ -726,7 +702,7 @@ _cairo_bentley_ottmann_tessellate_rectangular_traps (cairo_traps_t *traps,
_cairo_traps_clear (traps);
status = _cairo_bentley_ottmann_tessellate_rectangular (rectangles_ptrs, i,
fill_rule,
- traps);
+ TRUE, traps);
traps->is_rectilinear = TRUE;
traps->is_rectangular = TRUE;
@@ -738,3 +714,71 @@ _cairo_bentley_ottmann_tessellate_rectangular_traps (cairo_traps_t *traps,
return status;
}
+
+cairo_status_t
+_cairo_bentley_ottmann_tessellate_boxes (const cairo_boxes_t *in,
+ cairo_fill_rule_t fill_rule,
+ cairo_boxes_t *out)
+{
+ rectangle_t stack_rectangles[CAIRO_STACK_ARRAY_LENGTH (rectangle_t)];
+ rectangle_t *rectangles;
+ rectangle_t *stack_rectangles_ptrs[ARRAY_LENGTH (stack_rectangles) + 1];
+ rectangle_t **rectangles_ptrs;
+ const struct _cairo_boxes_chunk *chunk;
+ cairo_status_t status;
+ int i, j;
+
+ if (unlikely (in->num_boxes <= 1))
+ return CAIRO_STATUS_SUCCESS;
+
+ rectangles = stack_rectangles;
+ rectangles_ptrs = stack_rectangles_ptrs;
+ if (in->num_boxes > ARRAY_LENGTH (stack_rectangles)) {
+ rectangles = _cairo_malloc_ab_plus_c (in->num_boxes,
+ sizeof (rectangle_t) +
+ sizeof (rectangle_t *),
+ sizeof (rectangle_t *));
+ if (unlikely (rectangles == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+ rectangles_ptrs = (rectangle_t **) (rectangles + in->num_boxes);
+ }
+
+ j = 0;
+ for (chunk = &in->chunks; chunk != NULL; chunk = chunk->next) {
+ const cairo_box_t *box = chunk->base;
+ for (i = 0; i < chunk->count; i++) {
+ if (box[i].p1.x < box[i].p2.x) {
+ rectangles[j].left.x = box[i].p1.x;
+ rectangles[j].left.dir = 1;
+
+ rectangles[j].right.x = box[i].p2.x;
+ rectangles[j].right.dir = -1;
+ } else {
+ rectangles[j].right.x = box[i].p1.x;
+ rectangles[j].right.dir = 1;
+
+ rectangles[j].left.x = box[i].p2.x;
+ rectangles[j].left.dir = -1;
+ }
+
+ rectangles[j].left.right = NULL;
+ rectangles[j].right.right = NULL;
+
+ rectangles[j].top = box[i].p1.y;
+ rectangles[j].bottom = box[i].p2.y;
+
+ rectangles_ptrs[j] = &rectangles[j];
+ j++;
+ }
+ }
+
+ _cairo_boxes_clear (out);
+ status = _cairo_bentley_ottmann_tessellate_rectangular (rectangles_ptrs, j,
+ fill_rule,
+ FALSE, out);
+ if (rectangles != stack_rectangles)
+ free (rectangles);
+
+ return status;
+}
diff --git a/src/cairoint.h b/src/cairoint.h
index 0ea68e5..295f2e1 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -2443,6 +2443,11 @@ _cairo_bentley_ottmann_tessellate_rectangular_traps (cairo_traps_t *traps,
cairo_fill_rule_t fill_rule);
cairo_private cairo_status_t
+_cairo_bentley_ottmann_tessellate_boxes (const cairo_boxes_t *in,
+ cairo_fill_rule_t fill_rule,
+ cairo_boxes_t *out);
+
+cairo_private cairo_status_t
_cairo_bentley_ottmann_tessellate_rectilinear_traps (cairo_traps_t *traps,
cairo_fill_rule_t fill_rule);
commit 43beaa5873b9ad10620bfe7ed5f9212a3c44effd
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Tue Jan 19 18:11:26 2010 +0000
boxes: Efficient storage for an array of cairo_box_t.
Currently we use cairo_traps_t to also pass around arrays of boxes. This
is woefully inefficient in terms of storage, but also means that we
repeatedly have to verify that the traps are a set of boxes. By
explicitly passing around a cairo_boxes_t we avoid the semantic loss.
This will be heavily used in pending commits.
diff --git a/src/Makefile.sources b/src/Makefile.sources
index 391f285..ad7428a 100644
--- a/src/Makefile.sources
+++ b/src/Makefile.sources
@@ -55,6 +55,7 @@ cairo_private = \
cairo-analysis-surface-private.h \
cairo-arc-private.h \
cairo-atomic-private.h \
+ cairo-boxes-private.h \
cairo-cache-private.h \
cairo-clip-private.h \
cairo-combsort-private.h \
@@ -111,6 +112,7 @@ cairo_sources = \
cairo-bentley-ottmann.c \
cairo-bentley-ottmann-rectangular.c \
cairo-bentley-ottmann-rectilinear.c \
+ cairo-boxes.c \
cairo.c \
cairo-cache.c \
cairo-clip.c \
diff --git a/src/cairo-boxes-private.h b/src/cairo-boxes-private.h
new file mode 100644
index 0000000..881ac3d
--- /dev/null
+++ b/src/cairo-boxes-private.h
@@ -0,0 +1,80 @@
+/* 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.
+ *
+ * Contributor(s):
+ * Chris Wilson <chris at chris-wilson.co.uk>
+ */
+
+#ifndef CAIRO_BOXES_H
+#define CAIRO_BOXES_H
+
+#include "cairo-types-private.h"
+#include "cairo-compiler-private.h"
+
+struct _cairo_boxes_t {
+ cairo_status_t status;
+ cairo_box_t limit;
+ const cairo_box_t *limits;
+ int num_limits;
+ int num_boxes;
+ unsigned int is_pixel_aligned : 1;
+
+ struct _cairo_boxes_chunk {
+ struct _cairo_boxes_chunk *next;
+ cairo_box_t *base;
+ int count;
+ int size;
+ } chunks, *tail;
+ cairo_box_t boxes_embedded[32];
+};
+
+cairo_private void
+_cairo_boxes_init (cairo_boxes_t *boxes);
+
+cairo_private void
+_cairo_boxes_init_for_array (cairo_boxes_t *boxes,
+ cairo_box_t *array,
+ int num_boxes);
+
+cairo_private void
+_cairo_boxes_limit (cairo_boxes_t *boxes,
+ const cairo_box_t *limits,
+ int num_limits);
+
+cairo_private cairo_status_t
+_cairo_boxes_add (cairo_boxes_t *boxes,
+ const cairo_box_t *box);
+
+cairo_private void
+_cairo_boxes_clear (cairo_boxes_t *boxes);
+
+cairo_private void
+_cairo_boxes_fini (cairo_boxes_t *boxes);
+
+#endif /* CAIRO_BOXES_H */
diff --git a/src/cairo-boxes.c b/src/cairo-boxes.c
new file mode 100644
index 0000000..d2b9e7e
--- /dev/null
+++ b/src/cairo-boxes.c
@@ -0,0 +1,269 @@
+/* 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.
+ *
+ * Contributor(s):
+ * Chris Wilson <chris at chris-wilson.co.uk>
+ */
+
+#include "cairoint.h"
+
+#include "cairo-boxes-private.h"
+#include "cairo-error-private.h"
+
+void
+_cairo_boxes_init (cairo_boxes_t *boxes)
+{
+ boxes->status = CAIRO_STATUS_SUCCESS;
+ boxes->num_limits = 0;
+ boxes->num_boxes = 0;
+
+ boxes->tail = &boxes->chunks;
+ boxes->chunks.next = NULL;
+ boxes->chunks.base = boxes->boxes_embedded;
+ boxes->chunks.size = ARRAY_LENGTH (boxes->boxes_embedded);
+ boxes->chunks.count = 0;
+
+ boxes->is_pixel_aligned = TRUE;
+}
+
+void
+_cairo_boxes_init_for_array (cairo_boxes_t *boxes,
+ cairo_box_t *array,
+ int num_boxes)
+{
+ int n;
+
+ boxes->status = CAIRO_STATUS_SUCCESS;
+ boxes->num_limits = 0;
+ boxes->num_boxes = num_boxes;
+
+ boxes->tail = &boxes->chunks;
+ boxes->chunks.next = NULL;
+ boxes->chunks.base = array;
+ boxes->chunks.size = num_boxes;
+ boxes->chunks.count = num_boxes;
+
+ for (n = 0; n < num_boxes; n++) {
+ if (! _cairo_fixed_is_integer (array[n].p1.x) ||
+ ! _cairo_fixed_is_integer (array[n].p1.y) ||
+ ! _cairo_fixed_is_integer (array[n].p2.x) ||
+ ! _cairo_fixed_is_integer (array[n].p2.y))
+ {
+ break;
+ }
+ }
+
+ boxes->is_pixel_aligned = n == num_boxes;
+}
+
+void
+_cairo_boxes_limit (cairo_boxes_t *boxes,
+ const cairo_box_t *limits,
+ int num_limits)
+{
+ int n;
+
+ boxes->limits = limits;
+ boxes->num_limits = num_limits;
+
+ if (boxes->num_limits) {
+ boxes->limit = limits[0];
+ for (n = 1; n < num_limits; n++) {
+ if (limits[n].p1.x < boxes->limit.p1.x)
+ boxes->limit.p1.x = limits[n].p1.x;
+
+ if (limits[n].p1.y < boxes->limit.p1.y)
+ boxes->limit.p1.y = limits[n].p1.y;
+
+ if (limits[n].p2.x > boxes->limit.p2.x)
+ boxes->limit.p2.x = limits[n].p2.x;
+
+ if (limits[n].p2.y > boxes->limit.p2.y)
+ boxes->limit.p2.y = limits[n].p2.y;
+ }
+ }
+}
+
+static void
+_cairo_boxes_add_internal (cairo_boxes_t *boxes,
+ const cairo_box_t *box)
+{
+ struct _cairo_boxes_chunk *chunk;
+
+ if (unlikely (boxes->status))
+ return;
+
+ chunk = boxes->tail;
+ if (unlikely (chunk->count == chunk->size)) {
+ int size;
+
+ size = chunk->size * 2;
+ chunk->next = _cairo_malloc_ab_plus_c (size,
+ sizeof (cairo_box_t),
+ sizeof (struct _cairo_boxes_chunk));
+
+ if (unlikely (chunk == NULL)) {
+ boxes->status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ return;
+ }
+
+ chunk = chunk->next;
+ boxes->tail = chunk;
+
+ chunk->next = NULL;
+ chunk->count = 0;
+ chunk->size = size;
+ chunk->base = (cairo_box_t *) (chunk + 1);
+ }
+
+ chunk->base[chunk->count++] = *box;
+ boxes->num_boxes++;
+
+ if (boxes->is_pixel_aligned) {
+ boxes->is_pixel_aligned =
+ _cairo_fixed_is_integer (box->p1.x) &&
+ _cairo_fixed_is_integer (box->p1.y) &&
+ _cairo_fixed_is_integer (box->p2.x) &&
+ _cairo_fixed_is_integer (box->p2.y);
+ }
+}
+
+cairo_status_t
+_cairo_boxes_add (cairo_boxes_t *boxes,
+ const cairo_box_t *box)
+{
+ if (box->p1.y == box->p2.y)
+ return CAIRO_STATUS_SUCCESS;
+
+ if (box->p1.x == box->p2.x)
+ return CAIRO_STATUS_SUCCESS;
+
+ if (boxes->num_limits) {
+ cairo_point_t p1, p2;
+ cairo_bool_t reversed = FALSE;
+ int n;
+
+ /* support counter-clockwise winding for rectangular tessellation */
+ if (box->p1.x < box->p2.x) {
+ p1.x = box->p1.x;
+ p2.x = box->p2.x;
+ } else {
+ p2.x = box->p1.x;
+ p1.x = box->p2.x;
+ reversed = ! reversed;
+ }
+
+ if (p1.x >= boxes->limit.p2.x || p2.x <= boxes->limit.p1.x)
+ return CAIRO_STATUS_SUCCESS;
+
+ if (box->p1.y < box->p2.y) {
+ p1.y = box->p1.y;
+ p2.y = box->p2.y;
+ } else {
+ p2.y = box->p1.y;
+ p1.y = box->p2.y;
+ reversed = ! reversed;
+ }
+
+ if (p1.y >= boxes->limit.p2.y || p2.y <= boxes->limit.p1.y)
+ return CAIRO_STATUS_SUCCESS;
+
+ for (n = 0; n < boxes->num_limits; n++) {
+ const cairo_box_t *limits = &boxes->limits[n];
+ cairo_box_t _box;
+ cairo_point_t _p1, _p2;
+
+ if (p1.x >= limits->p2.x || p2.x <= limits->p1.x)
+ continue;
+ if (p1.y >= limits->p2.y || p2.y <= limits->p1.y)
+ continue;
+
+ /* Otherwise, clip the box to the limits. */
+ _p1 = p1;
+ if (_p1.x < limits->p1.x)
+ _p1.x = limits->p1.x;
+ if (_p1.y < limits->p1.y)
+ _p1.y = limits->p1.y;
+
+ _p2 = p2;
+ if (_p2.x > limits->p2.x)
+ _p2.x = limits->p2.x;
+ if (_p2.y > limits->p2.y)
+ _p2.y = limits->p2.y;
+
+ if (_p2.y <= _p1.y || _p2.x <= _p1.x)
+ continue;
+
+ _box.p1.y = _p1.y;
+ _box.p2.y = _p2.y;
+ if (reversed) {
+ _box.p1.x = _p2.x;
+ _box.p2.x = _p1.x;
+ } else {
+ _box.p1.x = _p1.x;
+ _box.p2.x = _p2.x;
+ }
+
+ _cairo_boxes_add_internal (boxes, &_box);
+ }
+ } else {
+ _cairo_boxes_add_internal (boxes, box);
+ }
+
+ return boxes->status;
+}
+
+void
+_cairo_boxes_clear (cairo_boxes_t *boxes)
+{
+ struct _cairo_boxes_chunk *chunk, *next;
+
+ for (chunk = boxes->chunks.next; chunk != NULL; chunk = next) {
+ next = chunk->next;
+ free (chunk);
+ }
+
+ boxes->tail = &boxes->chunks;
+ boxes->chunks.next = 0;
+ boxes->chunks.count = 0;
+ boxes->num_boxes = 0;
+
+ boxes->is_pixel_aligned = TRUE;
+}
+
+void
+_cairo_boxes_fini (cairo_boxes_t *boxes)
+{
+ struct _cairo_boxes_chunk *chunk, *next;
+
+ for (chunk = boxes->chunks.next; chunk != NULL; chunk = next) {
+ next = chunk->next;
+ free (chunk);
+ }
+}
diff --git a/src/cairo-types-private.h b/src/cairo-types-private.h
index f4f600c..66370e3 100644
--- a/src/cairo-types-private.h
+++ b/src/cairo-types-private.h
@@ -46,6 +46,7 @@
typedef struct _cairo_array cairo_array_t;
typedef struct _cairo_backend cairo_backend_t;
+typedef struct _cairo_boxes_t cairo_boxes_t;
typedef struct _cairo_cache cairo_cache_t;
typedef struct _cairo_composite_rectangles cairo_composite_rectangles_t;
typedef struct _cairo_clip cairo_clip_t;
commit ae25f1c360b79f0b7b1bb73e9ebc47eb794d8007
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Tue Jan 19 17:11:55 2010 +0000
Alter definition of cairo_composite_rectangles_t
This is a more useful definition that is able to individually track the
rectangles that compose the composite operation. This will be used by
the specialist compositors as a means to perform the common extents
determination for an operation.
diff --git a/src/Makefile.sources b/src/Makefile.sources
index 20829e7..391f285 100644
--- a/src/Makefile.sources
+++ b/src/Makefile.sources
@@ -59,6 +59,7 @@ cairo_private = \
cairo-clip-private.h \
cairo-combsort-private.h \
cairo-compiler-private.h \
+ cairo-composite-rectangles-private.h \
cairo-device-private.h \
cairo-error-private.h \
cairo-fixed-private.h \
@@ -114,6 +115,7 @@ cairo_sources = \
cairo-cache.c \
cairo-clip.c \
cairo-color.c \
+ cairo-composite-rectangles.c \
cairo-debug.c \
cairo-device.c \
cairo-fixed.c \
diff --git a/src/cairo-composite-rectangles-private.h b/src/cairo-composite-rectangles-private.h
new file mode 100644
index 0000000..be1a16a
--- /dev/null
+++ b/src/cairo-composite-rectangles-private.h
@@ -0,0 +1,105 @@
+/* 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 University of Southern
+ * California.
+ *
+ * Contributor(s):
+ * Chris Wilson <chris at chris-wilson.co.u>
+ */
+
+#ifndef CAIRO_COMPOSITE_RECTANGLES_PRIVATE_H
+#define CAIRO_COMPOSITE_RECTANGLES_PRIVATE_H
+
+#include "cairo-types-private.h"
+
+CAIRO_BEGIN_DECLS
+
+/* Rectangles that take part in a composite operation.
+ *
+ * The source and mask track the extents of the respective patterns in device
+ * space. The unbounded rectangle is essentially the clip rectangle. And the
+ * intersection of all is the bounded rectangle, which is the minimum extents
+ * the operation may require. Whether or not the operation is actually bounded
+ * is tracked in the is_bounded boolean.
+ *
+ */
+struct _cairo_composite_rectangles {
+ cairo_rectangle_int_t source;
+ cairo_rectangle_int_t mask;
+ cairo_rectangle_int_t bounded; /* dst */
+ cairo_rectangle_int_t unbounded; /* clip */
+ uint32_t is_bounded;
+};
+
+cairo_private cairo_int_status_t
+_cairo_composite_rectangles_init_for_paint (cairo_composite_rectangles_t *extents,
+ int surface_width, int surface_height,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_clip_t *clip);
+
+cairo_private cairo_int_status_t
+_cairo_composite_rectangles_init_for_mask (cairo_composite_rectangles_t *extents,
+ int surface_width, int surface_height,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ const cairo_pattern_t *mask,
+ cairo_clip_t *clip);
+
+cairo_private cairo_int_status_t
+_cairo_composite_rectangles_init_for_stroke (cairo_composite_rectangles_t *extents,
+ int surface_width, int surface_height,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_path_fixed_t *path,
+ const cairo_stroke_style_t *style,
+ const cairo_matrix_t *ctm,
+ cairo_clip_t *clip);
+
+cairo_private cairo_int_status_t
+_cairo_composite_rectangles_init_for_fill (cairo_composite_rectangles_t *extents,
+ int surface_width, int surface_height,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_path_fixed_t *path,
+ cairo_clip_t *clip);
+
+cairo_private cairo_int_status_t
+_cairo_composite_rectangles_init_for_glyphs (cairo_composite_rectangles_t *extents,
+ int surface_width, int surface_height,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_scaled_font_t *scaled_font,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_clip_t *clip,
+ cairo_bool_t *overlap);
+
+#endif /* CAIRO_COMPOSITE_RECTANGLES_PRIVATE_H */
diff --git a/src/cairo-composite-rectangles.c b/src/cairo-composite-rectangles.c
new file mode 100644
index 0000000..2bd823f
--- /dev/null
+++ b/src/cairo-composite-rectangles.c
@@ -0,0 +1,197 @@
+/* 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 Red Hat, Inc.
+ *
+ * Contributor(s):
+ * Chris Wilson <chris at chris-wilson.co.uk>
+ */
+
+#include "cairoint.h"
+
+#include "cairo-error-private.h"
+#include "cairo-composite-rectangles-private.h"
+
+/* A collection of routines to facilitate writing compositors. */
+
+static inline cairo_bool_t
+_cairo_composite_rectangles_init (cairo_composite_rectangles_t *extents,
+ int width, int height,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_clip_t *clip)
+{
+ extents->unbounded.x = extents->unbounded.y = 0;
+ extents->unbounded.width = width;
+ extents->unbounded.height = height;
+
+ if (clip != NULL) {
+ const cairo_rectangle_int_t *clip_extents;
+
+ clip_extents = _cairo_clip_get_extents (clip);
+ if (clip_extents == NULL)
+ return FALSE;
+
+ if (! _cairo_rectangle_intersect (&extents->unbounded, clip_extents))
+ return FALSE;
+ }
+
+ extents->bounded = extents->unbounded;
+ extents->is_bounded = _cairo_operator_bounded_by_either (op);
+
+ _cairo_pattern_get_extents (source, &extents->source);
+ if (extents->is_bounded & CAIRO_OPERATOR_BOUND_BY_SOURCE) {
+ if (! _cairo_rectangle_intersect (&extents->bounded, &extents->source))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+cairo_int_status_t
+_cairo_composite_rectangles_init_for_paint (cairo_composite_rectangles_t *extents,
+ int surface_width, int surface_height,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_clip_t *clip)
+{
+ if (! _cairo_composite_rectangles_init (extents,
+ surface_width, surface_height,
+ op, source, clip))
+ {
+ return CAIRO_INT_STATUS_NOTHING_TO_DO;
+ }
+
+ extents->mask = extents->bounded;
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+_cairo_composite_rectangles_intersect (cairo_composite_rectangles_t *extents)
+{
+ cairo_bool_t ret;
+
+ ret = _cairo_rectangle_intersect (&extents->bounded, &extents->mask);
+ if (! ret && extents->is_bounded & CAIRO_OPERATOR_BOUND_BY_MASK)
+ return CAIRO_INT_STATUS_NOTHING_TO_DO;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+cairo_int_status_t
+_cairo_composite_rectangles_init_for_mask (cairo_composite_rectangles_t *extents,
+ int surface_width, int surface_height,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ const cairo_pattern_t *mask,
+ cairo_clip_t *clip)
+{
+ if (! _cairo_composite_rectangles_init (extents,
+ surface_width, surface_height,
+ op, source, clip))
+ {
+ return CAIRO_INT_STATUS_NOTHING_TO_DO;
+ }
+
+ _cairo_pattern_get_extents (mask, &extents->mask);
+
+ return _cairo_composite_rectangles_intersect (extents);
+}
+
+cairo_int_status_t
+_cairo_composite_rectangles_init_for_stroke (cairo_composite_rectangles_t *extents,
+ int surface_width, int surface_height,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_path_fixed_t *path,
+ const cairo_stroke_style_t *style,
+ const cairo_matrix_t *ctm,
+ cairo_clip_t *clip)
+{
+ if (! _cairo_composite_rectangles_init (extents,
+ surface_width, surface_height,
+ op, source, clip))
+ {
+ return CAIRO_INT_STATUS_NOTHING_TO_DO;
+ }
+
+ _cairo_path_fixed_approximate_stroke_extents (path, style, ctm, &extents->mask);
+
+ return _cairo_composite_rectangles_intersect (extents);
+}
+
+cairo_int_status_t
+_cairo_composite_rectangles_init_for_fill (cairo_composite_rectangles_t *extents,
+ int surface_width, int surface_height,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_path_fixed_t *path,
+ cairo_clip_t *clip)
+{
+ if (! _cairo_composite_rectangles_init (extents,
+ surface_width, surface_height,
+ op, source, clip))
+ {
+ return CAIRO_INT_STATUS_NOTHING_TO_DO;
+ }
+
+ _cairo_path_fixed_approximate_fill_extents (path, &extents->mask);
+
+ return _cairo_composite_rectangles_intersect (extents);
+}
+
+cairo_int_status_t
+_cairo_composite_rectangles_init_for_glyphs (cairo_composite_rectangles_t *extents,
+ int surface_width, int surface_height,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_scaled_font_t *scaled_font,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_clip_t *clip,
+ cairo_bool_t *overlap)
+{
+ cairo_status_t status;
+
+ if (! _cairo_composite_rectangles_init (extents,
+ surface_width, surface_height,
+ op, source, clip))
+ {
+ return CAIRO_INT_STATUS_NOTHING_TO_DO;
+ }
+
+ status = _cairo_scaled_font_glyph_device_extents (scaled_font,
+ glyphs, num_glyphs,
+ &extents->mask,
+ overlap);
+ if (unlikely (status))
+ return status;
+
+ return _cairo_composite_rectangles_intersect (extents);
+}
diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index 30f6d44..35b946c 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -37,6 +37,7 @@
#include "cairoint.h"
+#include "cairo-composite-rectangles-private.h"
#include "cairo-error-private.h"
#include "cairo-gl-private.h"
@@ -2261,6 +2262,7 @@ _cairo_gl_surface_create_span_renderer (cairo_operator_t op,
cairo_gl_surface_span_renderer_t *renderer;
cairo_status_t status;
cairo_surface_attributes_t *src_attributes;
+ const cairo_rectangle_int_t *extents;
GLenum err;
renderer = calloc (1, sizeof (*renderer));
@@ -2269,21 +2271,24 @@ _cairo_gl_surface_create_span_renderer (cairo_operator_t op,
renderer->base.destroy = _cairo_gl_surface_span_renderer_destroy;
renderer->base.finish = _cairo_gl_surface_span_renderer_finish;
- if (_cairo_operator_bounded_by_mask (op))
+ if (rects->is_bounded) {
renderer->base.render_rows = _cairo_gl_render_bounded_spans;
- else
+ extents = &rects->bounded;
+ } else {
renderer->base.render_rows = _cairo_gl_render_unbounded_spans;
- renderer->xmin = rects->mask.x;
- renderer->xmax = rects->mask.x + rects->width;
+ extents = &rects->unbounded;
+ }
+ renderer->xmin = extents->x;
+ renderer->xmax = extents->x + extents->width;
renderer->op = op;
renderer->antialias = antialias;
renderer->dst = dst;
renderer->clip = clip_region;
status = _cairo_gl_operand_init (&renderer->setup.src, src, dst,
- rects->src.x, rects->src.y,
- rects->dst.x, rects->dst.y,
- rects->width, rects->height);
+ rects->source.x, rects->source.y,
+ extents->x, extents->y,
+ extents->width, extents->height);
if (unlikely (status)) {
free (renderer);
return _cairo_span_renderer_create_in_error (status);
diff --git a/src/cairo-image-surface.c b/src/cairo-image-surface.c
index d3bc6ca..b50a994 100644
--- a/src/cairo-image-surface.c
+++ b/src/cairo-image-surface.c
@@ -38,6 +38,7 @@
#include "cairoint.h"
#include "cairo-clip-private.h"
+#include "cairo-composite-rectangles-private.h"
#include "cairo-error-private.h"
#include "cairo-region-private.h"
@@ -1484,28 +1485,28 @@ _cairo_image_surface_span_renderer_finish (void *abstract_renderer)
cairo_image_surface_t *src = renderer->src;
cairo_image_surface_t *dst = renderer->dst;
cairo_surface_attributes_t *src_attributes = &renderer->src_attributes;
- int width = rects->width;
- int height = rects->height;
+ int width = rects->bounded.width;
+ int height = rects->bounded.height;
pixman_image_composite (_pixman_operator (renderer->op),
src->pixman_image,
renderer->mask->pixman_image,
dst->pixman_image,
- rects->src.x + src_attributes->x_offset,
- rects->src.y + src_attributes->y_offset,
+ rects->bounded.x + src_attributes->x_offset,
+ rects->bounded.y + src_attributes->y_offset,
0, 0, /* mask.x, mask.y */
- rects->dst.x, rects->dst.y,
+ rects->bounded.x, rects->bounded.y,
width, height);
- if (! _cairo_operator_bounded_by_mask (renderer->op)) {
+ if (! rects->is_bounded) {
status = _cairo_surface_composite_shape_fixup_unbounded (
&dst->base,
src_attributes,
src->width, src->height,
width, height,
- rects->src.x, rects->src.y,
+ rects->bounded.x, rects->bounded.y,
0, 0, /* mask.x, mask.y */
- rects->dst.x, rects->dst.y,
+ rects->bounded.x, rects->bounded.y,
width, height,
dst->clip_region);
}
@@ -1540,8 +1541,6 @@ _cairo_image_surface_create_span_renderer (cairo_operator_t op,
cairo_image_surface_t *dst = abstract_dst;
cairo_image_surface_span_renderer_t *renderer = calloc(1, sizeof(*renderer));
cairo_status_t status;
- int width = rects->width;
- int height = rects->height;
status = _cairo_image_surface_set_clip_region (dst, clip_region);
if (unlikely (status))
@@ -1562,8 +1561,8 @@ _cairo_image_surface_create_span_renderer (cairo_operator_t op,
status = _cairo_pattern_acquire_surface (
renderer->pattern, &renderer->dst->base,
- rects->src.x, rects->src.y,
- width, height,
+ rects->bounded.x, rects->bounded.y,
+ rects->bounded.width, rects->bounded.height,
CAIRO_PATTERN_ACQUIRE_NONE,
(cairo_surface_t **) &renderer->src,
&renderer->src_attributes);
@@ -1572,7 +1571,8 @@ _cairo_image_surface_create_span_renderer (cairo_operator_t op,
status = _cairo_image_surface_set_attributes (
renderer->src, &renderer->src_attributes,
- rects->dst.x + width/2, rects->dst.y + height/2);
+ rects->bounded.x + rects->bounded.width/2,
+ rects->bounded.y + rects->bounded.height/2);
if (status)
goto unwind;
@@ -1580,7 +1580,8 @@ _cairo_image_surface_create_span_renderer (cairo_operator_t op,
* compositing to pixman.) */
renderer->mask = (cairo_image_surface_t *)
cairo_image_surface_create (CAIRO_FORMAT_A8,
- width, height);
+ rects->bounded.width,
+ rects->bounded.height);
status = cairo_surface_status (&renderer->mask->base);
@@ -1590,7 +1591,7 @@ _cairo_image_surface_create_span_renderer (cairo_operator_t op,
return _cairo_span_renderer_create_in_error (status);
}
- renderer->mask_data = renderer->mask->data - rects->mask.x - rects->mask.y * renderer->mask->stride;
+ renderer->mask_data = renderer->mask->data - rects->bounded.x - rects->bounded.y * renderer->mask->stride;
renderer->mask_stride = renderer->mask->stride;
return &renderer->base;
}
diff --git a/src/cairo-misc.c b/src/cairo-misc.c
index 5f9cba5..cd1032a 100644
--- a/src/cairo-misc.c
+++ b/src/cairo-misc.c
@@ -421,6 +421,47 @@ _cairo_operator_bounded_by_source (cairo_operator_t op)
return FALSE;
}
+uint32_t
+_cairo_operator_bounded_by_either (cairo_operator_t op)
+{
+ switch (op) {
+ default:
+ ASSERT_NOT_REACHED;
+ case CAIRO_OPERATOR_OVER:
+ case CAIRO_OPERATOR_ATOP:
+ case CAIRO_OPERATOR_DEST:
+ case CAIRO_OPERATOR_DEST_OVER:
+ case CAIRO_OPERATOR_DEST_OUT:
+ case CAIRO_OPERATOR_XOR:
+ case CAIRO_OPERATOR_ADD:
+ case CAIRO_OPERATOR_SATURATE:
+ case CAIRO_OPERATOR_MULTIPLY:
+ case CAIRO_OPERATOR_SCREEN:
+ case CAIRO_OPERATOR_OVERLAY:
+ case CAIRO_OPERATOR_DARKEN:
+ case CAIRO_OPERATOR_LIGHTEN:
+ case CAIRO_OPERATOR_COLOR_DODGE:
+ case CAIRO_OPERATOR_COLOR_BURN:
+ case CAIRO_OPERATOR_HARD_LIGHT:
+ case CAIRO_OPERATOR_SOFT_LIGHT:
+ case CAIRO_OPERATOR_DIFFERENCE:
+ case CAIRO_OPERATOR_EXCLUSION:
+ case CAIRO_OPERATOR_HSL_HUE:
+ case CAIRO_OPERATOR_HSL_SATURATION:
+ case CAIRO_OPERATOR_HSL_COLOR:
+ case CAIRO_OPERATOR_HSL_LUMINOSITY:
+ return CAIRO_OPERATOR_BOUND_BY_MASK | CAIRO_OPERATOR_BOUND_BY_SOURCE;
+ case CAIRO_OPERATOR_CLEAR:
+ case CAIRO_OPERATOR_SOURCE:
+ return CAIRO_OPERATOR_BOUND_BY_MASK;
+ case CAIRO_OPERATOR_OUT:
+ case CAIRO_OPERATOR_IN:
+ case CAIRO_OPERATOR_DEST_IN:
+ case CAIRO_OPERATOR_DEST_ATOP:
+ return 0;
+ }
+
+}
/* This function is identical to the C99 function lround(), except that it
* performs arithmetic rounding (floor(d + .5) instead of away-from-zero rounding) and
diff --git a/src/cairo-rectangle.c b/src/cairo-rectangle.c
index e887c75..2bc4535 100644
--- a/src/cairo-rectangle.c
+++ b/src/cairo-rectangle.c
@@ -246,24 +246,3 @@ _cairo_box_contains_point (cairo_box_t *box, const cairo_point_t *point)
return FALSE;
return TRUE;
}
-
-void
-_cairo_composite_rectangles_init(
- cairo_composite_rectangles_t *rects,
- int all_x,
- int all_y,
- int width,
- int height)
-{
- rects->src.x = all_x;
- rects->src.y = all_y;
- rects->mask.x = all_x;
- rects->mask.y = all_y;
- rects->clip.x = all_x;
- rects->clip.y = all_y;
- rects->dst.x = all_x;
- rects->dst.y = all_y;
-
- rects->width = width;
- rects->height = height;
-}
diff --git a/src/cairo-spans.c b/src/cairo-spans.c
index 0b0f40c..e8ef0cf 100644
--- a/src/cairo-spans.c
+++ b/src/cairo-spans.c
@@ -26,6 +26,7 @@
*/
#include "cairoint.h"
+#include "cairo-composite-rectangles-private.h"
#include "cairo-fixed-private.h"
static cairo_scan_converter_t *
@@ -38,10 +39,10 @@ _create_scan_converter (cairo_fill_rule_t fill_rule,
return NULL;
}
- return _cairo_tor_scan_converter_create (rects->mask.x,
- rects->mask.y,
- rects->mask.x + rects->width,
- rects->mask.y + rects->height,
+ return _cairo_tor_scan_converter_create (rects->bounded.x,
+ rects->bounded.y,
+ rects->bounded.x + rects->bounded.width,
+ rects->bounded.y + rects->bounded.height,
fill_rule);
}
@@ -100,14 +101,22 @@ _cairo_surface_composite_trapezoids_as_polygon (cairo_surface_t *surface,
cairo_composite_rectangles_t rects;
cairo_status_t status;
- rects.src.x = src_x;
- rects.src.y = src_y;
- rects.dst.x = dst_x;
- rects.dst.y = dst_y;
+ rects.source.x = src_x;
+ rects.source.y = src_y;
+ rects.source.width = width;
+ rects.source.height = height;
+
rects.mask.x = dst_x;
rects.mask.y = dst_y;
- rects.width = width;
- rects.height = height;
+ rects.mask.width = width;
+ rects.mask.height = height;
+
+ rects.bounded.x = dst_x;
+ rects.bounded.y = dst_y;
+ rects.bounded.width = width;
+ rects.bounded.height = height;
+
+ rects.unbounded = rects.bounded;
converter = _create_scan_converter (CAIRO_FILL_RULE_WINDING,
antialias,
diff --git a/src/cairo-surface-fallback.c b/src/cairo-surface-fallback.c
index dbc2a21..a20bd68 100644
--- a/src/cairo-surface-fallback.c
+++ b/src/cairo-surface-fallback.c
@@ -42,6 +42,7 @@
#include "cairo-surface-fallback-private.h"
#include "cairo-clip-private.h"
+#include "cairo-composite-rectangles-private.h"
#include "cairo-error-private.h"
#include "cairo-region-private.h"
#include "cairo-spans-private.h"
@@ -883,15 +884,15 @@ _composite_spans_draw_func (void *closure,
cairo_composite_rectangles_t rects;
cairo_composite_spans_info_t *info = closure;
- _cairo_composite_rectangles_init (&rects,
- extents->x, extents->y,
- extents->width, extents->height);
-
+ rects.source = *extents;
+ rects.mask = *extents;
+ rects.bounded = *extents;
/* The incoming dst_x/y are where we're pretending the origin of
* the dst surface is -- *not* the offset of a rectangle where
* we'd like to place the result. */
- rects.dst.x -= dst_x;
- rects.dst.y -= dst_y;
+ rects.bounded.x -= dst_x;
+ rects.bounded.y -= dst_y;
+ rects.unbounded = rects.bounded;;
return _cairo_surface_composite_polygon (dst, op, src,
info->fill_rule,
diff --git a/src/cairo-types-private.h b/src/cairo-types-private.h
index 051a0ae..f4f600c 100644
--- a/src/cairo-types-private.h
+++ b/src/cairo-types-private.h
@@ -47,6 +47,7 @@
typedef struct _cairo_array cairo_array_t;
typedef struct _cairo_backend cairo_backend_t;
typedef struct _cairo_cache cairo_cache_t;
+typedef struct _cairo_composite_rectangles cairo_composite_rectangles_t;
typedef struct _cairo_clip cairo_clip_t;
typedef struct _cairo_clip_path cairo_clip_path_t;
typedef struct _cairo_color cairo_color_t;
@@ -214,29 +215,6 @@ typedef struct _cairo_point_int {
#define CAIRO_RECT_INT_MIN (INT_MIN >> CAIRO_FIXED_FRAC_BITS)
#define CAIRO_RECT_INT_MAX (INT_MAX >> CAIRO_FIXED_FRAC_BITS)
-/* Rectangles that take part in a composite operation.
- *
- * This defines four translations that define which pixels of the
- * source pattern, mask, clip and destination surface take part in a
- * general composite operation. The idea is that the pixels at
- *
- * (i,j)+(src.x, src.y) of the source,
- * (i,j)+(mask.x, mask.y) of the mask,
- * (i,j)+(clip.x, clip.y) of the clip and
- * (i,j)+(dst.x, dst.y) of the destination
- *
- * all combine together to form the result at (i,j)+(dst.x,dst.y),
- * for i,j ranging in [0,width) and [0,height) respectively.
- */
-typedef struct _cairo_composite_rectangles {
- cairo_point_int_t src;
- cairo_point_int_t mask;
- cairo_point_int_t clip;
- cairo_point_int_t dst;
- int width;
- int height;
-} cairo_composite_rectangles_t;
-
typedef enum _cairo_direction {
CAIRO_DIRECTION_FORWARD,
CAIRO_DIRECTION_REVERSE
diff --git a/src/cairo-win32-surface.c b/src/cairo-win32-surface.c
index 2bc0bdc..3f5180e 100644
--- a/src/cairo-win32-surface.c
+++ b/src/cairo-win32-surface.c
@@ -48,6 +48,7 @@
#include "cairoint.h"
#include "cairo-clip-private.h"
+#include "cairo-composite-rectangles-private.h"
#include "cairo-error-private.h"
#include "cairo-paginated-private.h"
#include "cairo-win32-private.h"
@@ -1930,11 +1931,10 @@ _cairo_win32_surface_span_renderer_finish (void *abstract_renderer)
status = dst->image->backend->composite (renderer->op,
renderer->pattern, mask_pattern, dst->image,
- rects->src.x,
- rects->src.y,
+ rects->bounded.x, rects->bounded.y,
0, 0, /* mask.x, mask.y */
- rects->dst.x, rects->dst.y,
- rects->width, rects->height,
+ rects->bounded.x, rects->bounded.y,
+ rects->bounded.width, rects->bounded.height,
renderer->clip_region);
} else {
/* otherwise go through the fallback_composite path which
@@ -1942,11 +1942,10 @@ _cairo_win32_surface_span_renderer_finish (void *abstract_renderer)
status = _cairo_surface_fallback_composite (
renderer->op,
renderer->pattern, mask_pattern, &dst->base,
- rects->src.x,
- rects->src.y,
+ rects->bounded.x, rects->bounded.y,
0, 0, /* mask.x, mask.y */
- rects->dst.x, rects->dst.y,
- rects->width, rects->height,
+ rects->bounded.x, rects->bounded.y,
+ rects->bounded.width, rects->bounded.height,
renderer->clip_region);
}
cairo_pattern_destroy (mask_pattern);
@@ -1982,8 +1981,8 @@ _cairo_win32_surface_create_span_renderer (cairo_operator_t op,
cairo_win32_surface_t *dst = abstract_dst;
cairo_win32_surface_span_renderer_t *renderer;
cairo_status_t status;
- int width = rects->width;
- int height = rects->height;
+ int width = rects->bounded.width;
+ int height = rects->bounded.height;
renderer = calloc(1, sizeof(*renderer));
if (renderer == NULL)
@@ -2013,7 +2012,7 @@ _cairo_win32_surface_create_span_renderer (cairo_operator_t op,
return _cairo_span_renderer_create_in_error (status);
}
- renderer->mask_data = renderer->mask->data - rects->mask.x - rects->mask.y * renderer->mask->stride;
+ renderer->mask_data = renderer->mask->data - rects->bounded.x - rects->bounded.y * renderer->mask->stride;
renderer->mask_stride = renderer->mask->stride;
return &renderer->base;
}
diff --git a/src/cairoint.h b/src/cairoint.h
index 4e9762e..0ea68e5 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -294,13 +294,6 @@ cairo_private cairo_bool_t
_cairo_box_contains_point (cairo_box_t *box,
const cairo_point_t *point) cairo_pure;
-cairo_private void
-_cairo_composite_rectangles_init (cairo_composite_rectangles_t *rects,
- int all_x,
- int all_y,
- int width,
- int height);
-
/* cairo-array.c structures and functions */
cairo_private void
@@ -1293,6 +1286,13 @@ _cairo_operator_bounded_by_mask (cairo_operator_t op) cairo_const;
cairo_private cairo_bool_t
_cairo_operator_bounded_by_source (cairo_operator_t op) cairo_const;
+enum {
+ CAIRO_OPERATOR_BOUND_BY_MASK = 1 << 1,
+ CAIRO_OPERATOR_BOUND_BY_SOURCE = 1 << 2,
+};
+
+cairo_private uint32_t
+_cairo_operator_bounded_by_either (cairo_operator_t op) cairo_const;
/* cairo-color.c */
cairo_private const cairo_color_t *
_cairo_stock_color (cairo_stock_t stock) cairo_pure;
commit 9cd9137843f8f1c3d32bedb6510259ab3638a2c5
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Tue Jan 19 17:11:11 2010 +0000
spans: Pass multiple rows of identical spans to the renders.
It is quite common amongst our geometry to have rows of repeated span
data, for example a rounded rectangle will have repeating data between
the top and bottom rounded corners. By passing the repeat length to the
renderers, they may be able to use that information more efficiently,
and the scan converters can avoid recomputing the same span data.
diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index 1f542cb..30f6d44 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -1981,6 +1981,8 @@ typedef struct _cairo_gl_surface_span_renderer {
cairo_gl_composite_setup_t setup;
+ int xmin, xmax;
+
cairo_operator_t op;
cairo_antialias_t antialias;
@@ -1988,7 +1990,6 @@ typedef struct _cairo_gl_surface_span_renderer {
cairo_gl_context_t *ctx;
cairo_region_t *clip;
- cairo_composite_rectangles_t composite_rectangles;
GLuint vbo;
void *vbo_base;
unsigned int vbo_size;
@@ -2019,11 +2020,11 @@ _cairo_gl_span_renderer_flush (cairo_gl_surface_span_renderer_t *renderer)
cairo_region_get_rectangle (renderer->clip, i, &rect);
glScissor (rect.x, rect.y, rect.width, rect.height);
- glDrawArrays (GL_LINES, 0, count);
+ glDrawArrays (GL_QUADS, 0, count);
}
glDisable (GL_SCISSOR_TEST);
} else {
- glDrawArrays (GL_LINES, 0, count);
+ glDrawArrays (GL_QUADS, 0, count);
}
}
@@ -2104,72 +2105,87 @@ _cairo_gl_emit_span_vertex (cairo_gl_surface_span_renderer_t *renderer,
static void
_cairo_gl_emit_span (cairo_gl_surface_span_renderer_t *renderer,
- int x1, int x2, int y, uint8_t alpha)
+ int x, int y1, int y2,
+ uint8_t alpha)
{
float *vertices = _cairo_gl_span_renderer_get_vbo (renderer, 2);
- _cairo_gl_emit_span_vertex (renderer, x1, y, alpha, vertices);
- _cairo_gl_emit_span_vertex (renderer, x2, y, alpha,
+ _cairo_gl_emit_span_vertex (renderer, x, y1, alpha, vertices);
+ _cairo_gl_emit_span_vertex (renderer, x, y2, alpha,
vertices + renderer->vertex_size / 4);
}
-/* Emits the contents of the span renderer rows as GL_LINES with the span's
- * alpha.
- *
- * Unlike the image surface, which is compositing into a temporary, we emit
- * coverage even for alpha == 0, in case we're using an unbounded operator.
- * But it means we avoid having to do the fixup.
- */
+static void
+_cairo_gl_emit_rectangle (cairo_gl_surface_span_renderer_t *renderer,
+ int x1, int y1,
+ int x2, int y2,
+ int coverage)
+{
+ _cairo_gl_emit_span (renderer, x1, y1, y2, coverage);
+ _cairo_gl_emit_span (renderer, x2, y2, y1, coverage);
+}
+
static cairo_status_t
-_cairo_gl_surface_span_renderer_render_row (
- void *abstract_renderer,
- int y,
- const cairo_half_open_span_t *spans,
- unsigned num_spans)
+_cairo_gl_render_bounded_spans (void *abstract_renderer,
+ int y, int height,
+ const cairo_half_open_span_t *spans,
+ unsigned num_spans)
{
cairo_gl_surface_span_renderer_t *renderer = abstract_renderer;
- int xmin = renderer->composite_rectangles.mask.x;
- int xmax = xmin + renderer->composite_rectangles.width;
- int prev_x = xmin;
- int prev_alpha = 0;
- unsigned i;
- int x_translate;
-
- /* Make sure we're within y-range. */
- if (y < renderer->composite_rectangles.mask.y ||
- y >= renderer->composite_rectangles.mask.y +
- renderer->composite_rectangles.height)
+
+ if (num_spans == 0)
return CAIRO_STATUS_SUCCESS;
- x_translate = renderer->composite_rectangles.dst.x -
- renderer->composite_rectangles.mask.x;
- y += renderer->composite_rectangles.dst.y -
- renderer->composite_rectangles.mask.y;
+ do {
+ if (spans[0].coverage) {
+ _cairo_gl_emit_rectangle (renderer,
+ spans[0].x, y,
+ spans[1].x, y + height,
+ spans[0].coverage);
+ }
- /* Find the first span within x-range. */
- for (i=0; i < num_spans && spans[i].x < xmin; i++) {}
- if (i>0)
- prev_alpha = spans[i-1].coverage;
+ spans++;
+ } while (--num_spans > 1);
- /* Set the intermediate spans. */
- for (; i < num_spans; i++) {
- int x = spans[i].x;
+ return CAIRO_STATUS_SUCCESS;
+}
- if (x >= xmax)
- break;
+static cairo_status_t
+_cairo_gl_render_unbounded_spans (void *abstract_renderer,
+ int y, int height,
+ const cairo_half_open_span_t *spans,
+ unsigned num_spans)
+{
+ cairo_gl_surface_span_renderer_t *renderer = abstract_renderer;
- _cairo_gl_emit_span (renderer,
- prev_x + x_translate, x + x_translate, y,
- prev_alpha);
+ if (num_spans == 0) {
+ _cairo_gl_emit_rectangle (renderer,
+ renderer->xmin, y,
+ renderer->xmax, y + height,
+ 0);
+ return CAIRO_STATUS_SUCCESS;
+ }
- prev_x = x;
- prev_alpha = spans[i].coverage;
+ if (spans[0].x != renderer->xmin) {
+ _cairo_gl_emit_rectangle (renderer,
+ renderer->xmin, y,
+ spans[0].x, y + height,
+ 0);
}
- if (prev_x < xmax) {
- _cairo_gl_emit_span (renderer,
- prev_x + x_translate, xmax + x_translate, y,
- prev_alpha);
+ do {
+ _cairo_gl_emit_rectangle (renderer,
+ spans[0].x, y,
+ spans[1].x, y + height,
+ spans[0].coverage);
+ spans++;
+ } while (--num_spans > 1);
+
+ if (spans[0].x != renderer->xmax) {
+ _cairo_gl_emit_rectangle (renderer,
+ spans[0].x, y,
+ renderer->xmax, y + height,
+ 0);
}
return CAIRO_STATUS_SUCCESS;
@@ -2244,8 +2260,6 @@ _cairo_gl_surface_create_span_renderer (cairo_operator_t op,
cairo_gl_surface_t *dst = abstract_dst;
cairo_gl_surface_span_renderer_t *renderer;
cairo_status_t status;
- int width = rects->width;
- int height = rects->height;
cairo_surface_attributes_t *src_attributes;
GLenum err;
@@ -2255,31 +2269,30 @@ _cairo_gl_surface_create_span_renderer (cairo_operator_t op,
renderer->base.destroy = _cairo_gl_surface_span_renderer_destroy;
renderer->base.finish = _cairo_gl_surface_span_renderer_finish;
- renderer->base.render_row =
- _cairo_gl_surface_span_renderer_render_row;
+ if (_cairo_operator_bounded_by_mask (op))
+ renderer->base.render_rows = _cairo_gl_render_bounded_spans;
+ else
+ renderer->base.render_rows = _cairo_gl_render_unbounded_spans;
+ renderer->xmin = rects->mask.x;
+ renderer->xmax = rects->mask.x + rects->width;
renderer->op = op;
renderer->antialias = antialias;
renderer->dst = dst;
renderer->clip = clip_region;
- renderer->composite_rectangles = *rects;
-
status = _cairo_gl_operand_init (&renderer->setup.src, src, dst,
rects->src.x, rects->src.y,
rects->dst.x, rects->dst.y,
- width, height);
+ rects->width, rects->height);
if (unlikely (status)) {
- cairo_status_t status_ignored;
-
- status_ignored = _cairo_gl_context_acquire (dst->base.device, &renderer->ctx);
-
- _cairo_gl_surface_span_renderer_destroy (renderer);
+ free (renderer);
return _cairo_span_renderer_create_in_error (status);
}
status = _cairo_gl_context_acquire (dst->base.device, &renderer->ctx);
if (unlikely (status)) {
- _cairo_gl_surface_span_renderer_destroy (renderer);
+ _cairo_gl_operand_destroy (&renderer->setup.src);
+ free (renderer);
return _cairo_span_renderer_create_in_error (status);
}
_cairo_gl_set_destination (dst);
diff --git a/src/cairo-image-surface.c b/src/cairo-image-surface.c
index e42534f..d3bc6ca 100644
--- a/src/cairo-image-surface.c
+++ b/src/cairo-image-surface.c
@@ -1393,11 +1393,13 @@ typedef struct _cairo_image_surface_span_renderer {
const cairo_pattern_t *pattern;
cairo_antialias_t antialias;
+ uint8_t *mask_data;
+ uint32_t mask_stride;
+
cairo_image_surface_t *src;
cairo_surface_attributes_t src_attributes;
cairo_image_surface_t *mask;
cairo_image_surface_t *dst;
-
cairo_composite_rectangles_t composite_rectangles;
} cairo_image_surface_span_renderer_t;
@@ -1406,66 +1408,46 @@ _cairo_image_surface_span_render_row (
int y,
const cairo_half_open_span_t *spans,
unsigned num_spans,
- cairo_image_surface_t *mask,
- const cairo_composite_rectangles_t *rects)
+ uint8_t *data,
+ uint32_t stride)
{
- int xmin = rects->mask.x;
- int xmax = xmin + rects->width;
uint8_t *row;
- int prev_x = xmin;
- int prev_alpha = 0;
unsigned i;
- /* Make sure we're within y-range. */
- y -= rects->mask.y;
- if (y < 0 || y >= rects->height)
+ if (num_spans == 0)
return;
- row = (uint8_t*)(mask->data) + y*(size_t)mask->stride - xmin;
-
- /* Find the first span within x-range. */
- for (i=0; i < num_spans && spans[i].x < xmin; i++) {}
- if (i>0)
- prev_alpha = spans[i-1].coverage;
-
- /* Set the intermediate spans. */
- for (; i < num_spans; i++) {
- int x = spans[i].x;
-
- if (x >= xmax)
- break;
-
- if (prev_alpha != 0) {
- /* We implement setting rendering the most common single
- * pixel wide span case to avoid the overhead of a memset
- * call. Open coding setting longer spans didn't show a
- * noticeable improvement over memset. */
- if (x == prev_x + 1) {
- row[prev_x] = prev_alpha;
- }
- else {
- memset(row + prev_x, prev_alpha, x - prev_x);
- }
+ row = data + y * stride;
+ for (i = 0; i < num_spans - 1; i++) {
+ if (! spans[i].coverage)
+ continue;
+
+ /* We implement setting the most common single pixel wide
+ * span case to avoid the overhead of a memset call.
+ * Open coding setting longer spans didn't show a
+ * noticeable improvement over memset.
+ */
+ if (spans[i+1].x == spans[i].x + 1) {
+ row[spans[i].x] = spans[i].coverage;
+ } else {
+ memset (row + spans[i].x,
+ spans[i].coverage,
+ spans[i+1].x - spans[i].x);
}
-
- prev_x = x;
- prev_alpha = spans[i].coverage;
- }
-
- if (prev_alpha != 0 && prev_x < xmax) {
- memset(row + prev_x, prev_alpha, xmax - prev_x);
}
}
static cairo_status_t
-_cairo_image_surface_span_renderer_render_row (
+_cairo_image_surface_span_renderer_render_rows (
void *abstract_renderer,
int y,
+ int height,
const cairo_half_open_span_t *spans,
unsigned num_spans)
{
cairo_image_surface_span_renderer_t *renderer = abstract_renderer;
- _cairo_image_surface_span_render_row (y, spans, num_spans, renderer->mask, &renderer->composite_rectangles);
+ while (height--)
+ _cairo_image_surface_span_render_row (y++, spans, num_spans, renderer->mask_data, renderer->mask_stride);
return CAIRO_STATUS_SUCCESS;
}
@@ -1520,11 +1502,11 @@ _cairo_image_surface_span_renderer_finish (void *abstract_renderer)
&dst->base,
src_attributes,
src->width, src->height,
- rects->width, rects->height,
+ width, height,
rects->src.x, rects->src.y,
0, 0, /* mask.x, mask.y */
rects->dst.x, rects->dst.y,
- rects->width, rects->height,
+ width, height,
dst->clip_region);
}
}
@@ -1570,7 +1552,7 @@ _cairo_image_surface_create_span_renderer (cairo_operator_t op,
renderer->base.destroy = _cairo_image_surface_span_renderer_destroy;
renderer->base.finish = _cairo_image_surface_span_renderer_finish;
- renderer->base.render_row = _cairo_image_surface_span_renderer_render_row;
+ renderer->base.render_rows = _cairo_image_surface_span_renderer_render_rows;
renderer->op = op;
renderer->pattern = pattern;
renderer->antialias = antialias;
@@ -1607,6 +1589,9 @@ _cairo_image_surface_create_span_renderer (cairo_operator_t op,
_cairo_image_surface_span_renderer_destroy (renderer);
return _cairo_span_renderer_create_in_error (status);
}
+
+ renderer->mask_data = renderer->mask->data - rects->mask.x - rects->mask.y * renderer->mask->stride;
+ renderer->mask_stride = renderer->mask->stride;
return &renderer->base;
}
diff --git a/src/cairo-spans-private.h b/src/cairo-spans-private.h
index e29a567..af3b38c 100644
--- a/src/cairo-spans-private.h
+++ b/src/cairo-spans-private.h
@@ -47,26 +47,24 @@ typedef struct _cairo_half_open_span {
* surfaces if they want to composite spans instead of trapezoids. */
typedef struct _cairo_span_renderer cairo_span_renderer_t;
struct _cairo_span_renderer {
+ /* Private status variable. */
+ cairo_status_t status;
+
/* Called to destroy the renderer. */
cairo_destroy_func_t destroy;
- /* Render the spans on row y of the source by whatever compositing
- * method is required. The function should ignore spans outside
- * the bounding box set by the init() function. */
- cairo_status_t (*render_row)(
- void *abstract_renderer,
- int y,
- const cairo_half_open_span_t *coverages,
- unsigned num_coverages);
+ /* Render the spans on row y of the destination by whatever compositing
+ * method is required. */
+ cairo_warn cairo_status_t
+ (*render_rows) (void *abstract_renderer,
+ int y, int height,
+ const cairo_half_open_span_t *coverages,
+ unsigned num_coverages);
/* Called after all rows have been rendered to perform whatever
* final rendering step is required. This function is called just
* once before the renderer is destroyed. */
- cairo_status_t (*finish)(
- void *abstract_renderer);
-
- /* Private status variable. */
- cairo_status_t status;
+ cairo_status_t (*finish) (void *abstract_renderer);
};
/* Scan converter interface. */
diff --git a/src/cairo-spans.c b/src/cairo-spans.c
index 7067a5e..0b0f40c 100644
--- a/src/cairo-spans.c
+++ b/src/cairo-spans.c
@@ -277,13 +277,15 @@ _cairo_scan_converter_create_in_error (cairo_status_t status)
}
static cairo_status_t
-_cairo_nil_span_renderer_render_row (
+_cairo_nil_span_renderer_render_rows (
void *abstract_renderer,
int y,
+ int height,
const cairo_half_open_span_t *coverages,
unsigned num_coverages)
{
(void) y;
+ (void) height;
(void) coverages;
(void) num_coverages;
return _cairo_span_renderer_status (abstract_renderer);
@@ -312,7 +314,7 @@ _cairo_span_renderer_set_error (
ASSERT_NOT_REACHED;
}
if (renderer->status == CAIRO_STATUS_SUCCESS) {
- renderer->render_row = _cairo_nil_span_renderer_render_row;
+ renderer->render_rows = _cairo_nil_span_renderer_render_rows;
renderer->finish = _cairo_nil_span_renderer_finish;
renderer->status = error;
}
diff --git a/src/cairo-tor-scan-converter.c b/src/cairo-tor-scan-converter.c
index d18b25a..1f8160e 100644
--- a/src/cairo-tor-scan-converter.c
+++ b/src/cairo-tor-scan-converter.c
@@ -129,27 +129,29 @@ blit_with_span_renderer(
cairo_span_renderer_t *span_renderer,
struct pool *span_pool,
int y,
+ int height,
int xmin,
int xmax);
static glitter_status_t
-blit_empty_with_span_renderer (cairo_span_renderer_t *renderer, int y);
+blit_empty_with_span_renderer (cairo_span_renderer_t *renderer, int y, int height);
#define GLITTER_BLIT_COVERAGES_ARGS \
cairo_span_renderer_t *span_renderer, \
struct pool *span_pool
-#define GLITTER_BLIT_COVERAGES(cells, y, xmin, xmax) do { \
+#define GLITTER_BLIT_COVERAGES(cells, y, height,xmin, xmax) do { \
cairo_status_t status = blit_with_span_renderer (cells, \
span_renderer, \
span_pool, \
- y, xmin, xmax); \
+ y, height, \
+ xmin, xmax); \
if (unlikely (status)) \
return status; \
} while (0)
-#define GLITTER_BLIT_COVERAGES_EMPTY(y, xmin, xmax) do { \
- cairo_status_t status = blit_empty_with_span_renderer (span_renderer, y); \
+#define GLITTER_BLIT_COVERAGES_EMPTY(y, height, xmin, xmax) do { \
+ cairo_status_t status = blit_empty_with_span_renderer (span_renderer, y, height); \
if (unlikely (status)) \
return status; \
} while (0)
@@ -310,8 +312,8 @@ typedef int grid_area_t;
#define UNROLL3(x) x x x
struct quorem {
- int quo;
- int rem;
+ int32_t quo;
+ int32_t rem;
};
/* Header for a chunk of memory in a memory pool. */
@@ -383,6 +385,7 @@ struct edge {
/* Original sign of the edge: +1 for downwards, -1 for upwards
* edges. */
int dir;
+ int vertical;
};
/* Number of subsample rows per y-bucket. Must be GRID_Y. */
@@ -703,7 +706,6 @@ static void
cell_list_fini(struct cell_list *cells)
{
pool_fini (cells->cell_pool.base);
- cell_list_init (cells);
}
/* Empty the cell list. This is called at the start of every pixel
@@ -716,6 +718,26 @@ cell_list_reset (struct cell_list *cells)
pool_reset (cells->cell_pool.base);
}
+static struct cell *
+cell_list_alloc (struct cell_list *cells,
+ struct cell **cursor,
+ struct cell *tail,
+ int x)
+{
+ struct cell *cell;
+
+ cell = pool_alloc (cells->cell_pool.base, sizeof (struct cell));
+ if (unlikely (NULL == cell))
+ return NULL;
+
+ *cursor = cell;
+ cell->next = tail;
+ cell->x = x;
+ cell->uncovered_area = 0;
+ cell->covered_height = 0;
+ return cell;
+}
+
/* Find a cell at the given x-coordinate. Returns %NULL if a new cell
* needed to be allocated but couldn't be. Cells must be found with
* non-decreasing x-coordinate until the cell list is rewound using
@@ -738,22 +760,10 @@ cell_list_find (struct cell_list *cells, int x)
}
cells->cursor = cursor;
- if (tail->x == x) {
+ if (tail->x == x)
return tail;
- } else {
- struct cell *cell;
-
- cell = pool_alloc (cells->cell_pool.base, sizeof (struct cell));
- if (unlikely (NULL == cell))
- return NULL;
- *cursor = cell;
- cell->next = tail;
- cell->x = x;
- cell->uncovered_area = 0;
- cell->covered_height = 0;
- return cell;
- }
+ return cell_list_alloc (cells, cursor, tail, x);
}
/* Find two cells at x1 and x2. This is exactly equivalent
@@ -833,9 +843,8 @@ cell_list_find_pair(struct cell_list *cells, int x1, int x2)
/* Add an unbounded subpixel span covering subpixels >= x to the
* coverage cells. */
static glitter_status_t
-cell_list_add_unbounded_subspan(
- struct cell_list *cells,
- grid_scaled_x_t x)
+cell_list_add_unbounded_subspan (struct cell_list *cells,
+ grid_scaled_x_t x)
{
struct cell *cell;
int ix, fx;
@@ -908,20 +917,24 @@ cell_list_render_edge(
struct edge *edge,
int sign)
{
- struct quorem x1 = edge->x;
- struct quorem x2 = x1;
grid_scaled_y_t y1, y2, dy;
grid_scaled_x_t dx;
int ix1, ix2;
grid_scaled_x_t fx1, fx2;
- x2.quo += edge->dxdy_full.quo;
- x2.rem += edge->dxdy_full.rem;
- if (x2.rem >= 0) {
- ++x2.quo;
- x2.rem -= edge->dy;
+ struct quorem x1 = edge->x;
+ struct quorem x2 = x1;
+
+ if (! edge->vertical) {
+ x2.quo += edge->dxdy_full.quo;
+ x2.rem += edge->dxdy_full.rem;
+ if (x2.rem >= 0) {
+ ++x2.quo;
+ x2.rem -= edge->dy;
+ }
+
+ edge->x = x2;
}
- edge->x = x2;
GRID_X_TO_INT_FRAC(x1.quo, ix1, fx1);
GRID_X_TO_INT_FRAC(x2.quo, ix2, fx2);
@@ -1046,10 +1059,9 @@ polygon_fini (struct polygon *polygon)
* receive new edges and clip them to the vertical range
* [ymin,ymax). */
static glitter_status_t
-polygon_reset(
- struct polygon *polygon,
- grid_scaled_y_t ymin,
- grid_scaled_y_t ymax)
+polygon_reset (struct polygon *polygon,
+ grid_scaled_y_t ymin,
+ grid_scaled_y_t ymax)
{
unsigned h = ymax - ymin;
unsigned num_buckets = EDGE_Y_BUCKET_INDEX(ymax + EDGE_Y_BUCKET_HEIGHT-1,
@@ -1116,30 +1128,38 @@ polygon_add_edge (struct polygon *polygon,
dx = edge->line.p2.x - edge->line.p1.x;
dy = edge->line.p2.y - edge->line.p1.y;
e->dy = dy;
- e->dxdy = floored_divrem (dx, dy);
-
- if (ymin <= edge->top)
- ytop = edge->top;
- else
- ytop = ymin;
- if (ytop == edge->line.p1.y) {
- e->x.quo = edge->line.p1.x;
- e->x.rem = 0;
- } else {
- e->x = floored_muldivrem (ytop - edge->line.p1.y, dx, dy);
- e->x.quo += edge->line.p1.x;
- }
-
e->dir = edge->dir;
+
+ ytop = edge->top >= ymin ? edge->top : ymin;
+ ybot = edge->bottom <= ymax ? edge->bottom : ymax;
e->ytop = ytop;
- ybot = edge->bottom < ymax ? edge->bottom : ymax;
e->height_left = ybot - ytop;
- if (e->height_left >= GRID_Y) {
- e->dxdy_full = floored_muldivrem (GRID_Y, dx, dy);
- } else {
+ if (dx == 0) {
+ e->vertical = TRUE;
+ e->x.quo = edge->line.p1.x;
+ e->x.rem = 0;
+ e->dxdy.quo = 0;
+ e->dxdy.rem = 0;
e->dxdy_full.quo = 0;
e->dxdy_full.rem = 0;
+ } else {
+ e->vertical = FALSE;
+ e->dxdy = floored_divrem (dx, dy);
+ if (ytop == edge->line.p1.y) {
+ e->x.quo = edge->line.p1.x;
+ e->x.rem = 0;
+ } else {
+ e->x = floored_muldivrem (ytop - edge->line.p1.y, dx, dy);
+ e->x.quo += edge->line.p1.x;
+ }
+
+ if (e->height_left >= GRID_Y) {
+ e->dxdy_full = floored_muldivrem (GRID_Y, dx, dy);
+ } else {
+ e->dxdy_full.quo = 0;
+ e->dxdy_full.rem = 0;
+ }
}
_polygon_insert_edge_into_its_y_bucket (polygon, e);
@@ -1162,31 +1182,30 @@ active_list_init(struct active_list *active)
active_list_reset(active);
}
-static void
-active_list_fini(
- struct active_list *active)
-{
- active_list_reset(active);
-}
-
/* Merge the edges in an unsorted list of edges into a sorted
* list. The sort order is edges ascending by edge->x.quo. Returns
* the new head of the sorted list. */
static struct edge *
merge_unsorted_edges(struct edge *sorted_head, struct edge *unsorted_head)
{
- struct edge *head = unsorted_head;
struct edge **cursor = &sorted_head;
int x;
- while (NULL != head) {
+ if (sorted_head == NULL) {
+ sorted_head = unsorted_head;
+ unsorted_head = unsorted_head->next;
+ sorted_head->next = NULL;
+ if (unsorted_head == NULL)
+ return sorted_head;
+ }
+
+ do {
+ struct edge *next = unsorted_head->next;
struct edge *prev = *cursor;
- struct edge *next = head->next;
- x = head->x.quo;
- if (NULL == prev || x < prev->x.quo) {
+ x = unsorted_head->x.quo;
+ if (x < prev->x.quo)
cursor = &sorted_head;
- }
while (1) {
UNROLL3({
@@ -1197,26 +1216,28 @@ merge_unsorted_edges(struct edge *sorted_head, struct edge *unsorted_head)
});
}
- head->next = *cursor;
- *cursor = head;
+ unsorted_head->next = *cursor;
+ *cursor = unsorted_head;
+ unsorted_head = next;
+ } while (unsorted_head != NULL);
- head = next;
- }
return sorted_head;
}
/* Test if the edges on the active list can be safely advanced by a
* full row without intersections or any edges ending. */
inline static int
-active_list_can_step_full_row(
- struct active_list *active)
+active_list_can_step_full_row (struct active_list *active)
{
+ const struct edge *e;
+ int prev_x = INT_MIN;
+
/* Recomputes the minimum height of all edges on the active
* list if we have been dropping edges. */
if (active->min_height <= 0) {
- struct edge *e = active->head;
int min_height = INT_MAX;
+ e = active->head;
while (NULL != e) {
if (e->height_left < min_height)
min_height = e->height_left;
@@ -1226,27 +1247,29 @@ active_list_can_step_full_row(
active->min_height = min_height;
}
- /* Check for intersections only if no edges end during the next
- * row. */
- if (active->min_height >= GRID_Y) {
- grid_scaled_x_t prev_x = INT_MIN;
- struct edge *e = active->head;
- while (NULL != e) {
- struct quorem x = e->x;
+ if (active->min_height < GRID_Y)
+ return 0;
+ /* Check for intersections as no edges end during the next row. */
+ e = active->head;
+ while (NULL != e) {
+ struct quorem x = e->x;
+
+ if (! e->vertical) {
x.quo += e->dxdy_full.quo;
x.rem += e->dxdy_full.rem;
if (x.rem >= 0)
++x.quo;
-
- if (x.quo <= prev_x)
- return 0;
- prev_x = x.quo;
- e = e->next;
}
- return 1;
+
+ if (x.quo <= prev_x)
+ return 0;
+
+ prev_x = x.quo;
+ e = e->next;
}
- return 0;
+
+ return 1;
}
/* Merges edges on the given subpixel row from the polygon to the
@@ -1278,8 +1301,10 @@ active_list_merge_edges_from_polygon(
ptail = &tail->next;
}
}
- active->head = merge_unsorted_edges(active->head, subrow_edges);
- active->min_height = min_height;
+ if (subrow_edges) {
+ active->head = merge_unsorted_edges(active->head, subrow_edges);
+ active->min_height = min_height;
+ }
}
/* Advance the edges on the active list by one subsample row by
@@ -1440,11 +1465,13 @@ apply_nonzero_fill_rule_and_step_edges (struct active_list *active,
}
}
- right_edge->x.quo += right_edge->dxdy_full.quo;
- right_edge->x.rem += right_edge->dxdy_full.rem;
- if (right_edge->x.rem >= 0) {
- ++right_edge->x.quo;
- right_edge->x.rem -= right_edge->dy;
+ if (! right_edge->vertical) {
+ right_edge->x.quo += right_edge->dxdy_full.quo;
+ right_edge->x.rem += right_edge->dxdy_full.rem;
+ if (right_edge->x.rem >= 0) {
+ ++right_edge->x.quo;
+ right_edge->x.rem -= right_edge->dy;
+ }
}
}
@@ -1497,11 +1524,13 @@ apply_evenodd_fill_rule_and_step_edges (struct active_list *active,
break;
}
- right_edge->x.quo += right_edge->dxdy_full.quo;
- right_edge->x.rem += right_edge->dxdy_full.rem;
- if (right_edge->x.rem >= 0) {
- ++right_edge->x.quo;
- right_edge->x.rem -= right_edge->dy;
+ if (! right_edge->vertical) {
+ right_edge->x.quo += right_edge->dxdy_full.quo;
+ right_edge->x.rem += right_edge->dxdy_full.rem;
+ if (right_edge->x.rem >= 0) {
+ ++right_edge->x.quo;
+ right_edge->x.rem -= right_edge->dy;
+ }
}
}
@@ -1538,8 +1567,14 @@ blit_span(
}
}
-#define GLITTER_BLIT_COVERAGES(coverages, y, xmin, xmax) \
- blit_cells(coverages, raster_pixels + (y)*raster_stride, xmin, xmax)
+#define GLITTER_BLIT_COVERAGES(coverages, y, height, xmin, xmax) \
+ do { \
+ int __y = y; \
+ int __h = height; \
+ do { \
+ blit_cells(coverages, raster_pixels + (__y)*raster_stride, xmin, xmax); \
+ } while (--__h); \
+ } while (0)
static void
blit_cells(
@@ -1598,7 +1633,6 @@ static void
_glitter_scan_converter_fini(glitter_scan_converter_t *converter)
{
polygon_fini(converter->polygon);
- active_list_fini(converter->active);
cell_list_fini(converter->coverages);
converter->xmin=0;
converter->ymin=0;
@@ -1712,16 +1746,44 @@ glitter_scan_converter_add_edge (glitter_scan_converter_t *converter,
#endif
#ifndef GLITTER_BLIT_COVERAGES_EMPTY
-# define GLITTER_BLIT_COVERAGES_EMPTY(y, xmin, xmax)
+# define GLITTER_BLIT_COVERAGES_EMPTY(y0, y1, xmin, xmax)
#endif
+static cairo_bool_t
+active_list_is_vertical (struct active_list *active)
+{
+ struct edge *e;
+
+ for (e = active->head; e != NULL; e = e->next) {
+ if (! e->vertical)
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static void
+step_edges (struct active_list *active, int count)
+{
+ struct edge **cursor = &active->head;
+ struct edge *edge;
+
+ for (edge = *cursor; edge != NULL; edge = *cursor) {
+ edge->height_left -= GRID_Y * count;
+ if (edge->height_left)
+ cursor = &edge->next;
+ else
+ *cursor = edge->next;
+ }
+}
+
I glitter_status_t
glitter_scan_converter_render(
glitter_scan_converter_t *converter,
int nonzero_fill,
GLITTER_BLIT_COVERAGES_ARGS)
{
- int i;
+ int i, j;
int ymax_i = converter->ymax / GRID_Y;
int ymin_i = converter->ymin / GRID_Y;
int xmin_i, xmax_i;
@@ -1739,23 +1801,25 @@ glitter_scan_converter_render(
GLITTER_BLIT_COVERAGES_BEGIN;
/* Render each pixel row. */
- for (i=0; i<h; i++) {
+ for (i = 0; i < h; i = j) {
int do_full_step = 0;
glitter_status_t status = 0;
+ j = i + 1;
+
/* Determine if we can ignore this row or use the full pixel
* stepper. */
if (GRID_Y == EDGE_Y_BUCKET_HEIGHT && ! polygon->y_buckets[i]) {
if (! active->head) {
- GLITTER_BLIT_COVERAGES_EMPTY (i+ymin_i, xmin_i, xmax_i);
+ for (; j < h && ! polygon->y_buckets[j]; j++)
+ ;
+ GLITTER_BLIT_COVERAGES_EMPTY (i+ymin_i, j-i, xmin_i, xmax_i);
continue;
}
do_full_step = active_list_can_step_full_row (active);
}
- cell_list_reset (coverages);
-
if (do_full_step) {
/* Step by a full pixel row's worth. */
if (nonzero_fill) {
@@ -1765,9 +1829,22 @@ glitter_scan_converter_render(
status = apply_evenodd_fill_rule_and_step_edges (active,
coverages);
}
+
+ if (active_list_is_vertical (active)) {
+ while (j < h &&
+ polygon->y_buckets[j] == NULL &&
+ active->min_height >= 2*GRID_Y)
+ {
+ active->min_height -= GRID_Y;
+ j++;
+ }
+ if (j != i + 1)
+ step_edges (active, j - (i + 1));
+ }
} else {
- /* Subsample this row. */
grid_scaled_y_t suby;
+
+ /* Subsample this row. */
for (suby = 0; suby < GRID_Y; suby++) {
grid_scaled_y_t y = (i+ymin_i)*GRID_Y + suby;
@@ -1788,13 +1865,13 @@ glitter_scan_converter_render(
if (unlikely (status))
return status;
- GLITTER_BLIT_COVERAGES(coverages, i+ymin_i, xmin_i, xmax_i);
+ GLITTER_BLIT_COVERAGES(coverages, i+ymin_i, j-i, xmin_i, xmax_i);
+ cell_list_reset (coverages);
- if (! active->head) {
+ if (! active->head)
active->min_height = INT_MAX;
- } else {
+ else
active->min_height -= GRID_Y;
- }
}
/* Clean up the coverage blitter. */
@@ -1808,21 +1885,20 @@ glitter_scan_converter_render(
* scan converter subclass. */
static glitter_status_t
-blit_with_span_renderer(
- struct cell_list *cells,
- cairo_span_renderer_t *renderer,
- struct pool *span_pool,
- int y,
- int xmin,
- int xmax)
+blit_with_span_renderer (struct cell_list *cells,
+ cairo_span_renderer_t *renderer,
+ struct pool *span_pool,
+ int y, int height,
+ int xmin, int xmax)
{
struct cell *cell = cells->head;
int prev_x = xmin;
int cover = 0;
cairo_half_open_span_t *spans;
unsigned num_spans;
+
if (cell == NULL)
- return CAIRO_STATUS_SUCCESS;
+ return blit_empty_with_span_renderer (renderer, y, height);
/* Skip cells to the left of the clip region. */
while (cell != NULL && cell->x < xmin) {
@@ -1834,12 +1910,12 @@ blit_with_span_renderer(
/* Count number of cells remaining. */
{
struct cell *next = cell;
- num_spans = 0;
- while (next) {
+ num_spans = 1;
+ while (next != NULL) {
next = next->next;
++num_spans;
}
- num_spans = 2*num_spans + 1;
+ num_spans = 2*num_spans;
}
/* Allocate enough spans for the row. */
@@ -1854,6 +1930,7 @@ blit_with_span_renderer(
for (; cell != NULL; cell = cell->next) {
int x = cell->x;
int area;
+
if (x >= xmax)
break;
@@ -1873,20 +1950,26 @@ blit_with_span_renderer(
prev_x = x+1;
}
- if (prev_x < xmax) {
+ if (prev_x <= xmax) {
spans[num_spans].x = prev_x;
spans[num_spans].coverage = GRID_AREA_TO_ALPHA (cover);
++num_spans;
}
+ if (prev_x < xmax && cover) {
+ spans[num_spans].x = xmax;
+ spans[num_spans].coverage = 0;
+ ++num_spans;
+ }
+
/* Dump them into the renderer. */
- return renderer->render_row (renderer, y, spans, num_spans);
+ return renderer->render_rows (renderer, y, height, spans, num_spans);
}
static glitter_status_t
-blit_empty_with_span_renderer (cairo_span_renderer_t *renderer, int y)
+blit_empty_with_span_renderer (cairo_span_renderer_t *renderer, int y, int height)
{
- return renderer->render_row (renderer, y, NULL, 0);
+ return renderer->render_rows (renderer, y, height, NULL, 0);
}
struct _cairo_tor_scan_converter {
diff --git a/src/cairo-win32-surface.c b/src/cairo-win32-surface.c
index 45a5eab..2bc0bdc 100644
--- a/src/cairo-win32-surface.c
+++ b/src/cairo-win32-surface.c
@@ -1874,6 +1874,9 @@ typedef struct _cairo_win32_surface_span_renderer {
const cairo_pattern_t *pattern;
cairo_antialias_t antialias;
+ uint8_t *mask_data;
+ uint32_t mask_stride;
+
cairo_image_surface_t *mask;
cairo_win32_surface_t *dst;
cairo_region_t *clip_region;
@@ -1885,11 +1888,13 @@ static cairo_status_t
_cairo_win32_surface_span_renderer_render_row (
void *abstract_renderer,
int y,
+ int height,
const cairo_half_open_span_t *spans,
unsigned num_spans)
{
cairo_win32_surface_span_renderer_t *renderer = abstract_renderer;
- _cairo_image_surface_span_render_row (y, spans, num_spans, renderer->mask, &renderer->composite_rectangles);
+ while (height--)
+ _cairo_image_surface_span_render_row (y++, spans, num_spans, renderer->mask_data, renderer->mask_stride);
return CAIRO_STATUS_SUCCESS;
}
@@ -1986,8 +1991,7 @@ _cairo_win32_surface_create_span_renderer (cairo_operator_t op,
renderer->base.destroy = _cairo_win32_surface_span_renderer_destroy;
renderer->base.finish = _cairo_win32_surface_span_renderer_finish;
- renderer->base.render_row =
- _cairo_win32_surface_span_renderer_render_row;
+ renderer->base.render_row = _cairo_win32_surface_span_renderer_render_rows;
renderer->op = op;
renderer->pattern = pattern;
renderer->antialias = antialias;
@@ -2008,6 +2012,9 @@ _cairo_win32_surface_create_span_renderer (cairo_operator_t op,
_cairo_win32_surface_span_renderer_destroy (renderer);
return _cairo_span_renderer_create_in_error (status);
}
+
+ renderer->mask_data = renderer->mask->data - rects->mask.x - rects->mask.y * renderer->mask->stride;
+ renderer->mask_stride = renderer->mask->stride;
return &renderer->base;
}
diff --git a/src/cairoint.h b/src/cairoint.h
index 780d111..4e9762e 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -2236,8 +2236,8 @@ cairo_private void
_cairo_image_surface_span_render_row (int y,
const cairo_half_open_span_t *spans,
unsigned num_spans,
- cairo_image_surface_t *mask,
- const cairo_composite_rectangles_t *rects);
+ uint8_t *data,
+ uint32_t stride);
cairo_private cairo_image_transparency_t
_cairo_image_analyze_transparency (cairo_image_surface_t *image);
commit a04873c0770df5eaed078493df5216ca28322de7
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Mon Jan 18 23:40:00 2010 +0000
qt: Trivial compile fix for boilerplate.
diff --git a/boilerplate/cairo-boilerplate-qt.cpp b/boilerplate/cairo-boilerplate-qt.cpp
index 8f19811..ea1f4ee 100644
--- a/boilerplate/cairo-boilerplate-qt.cpp
+++ b/boilerplate/cairo-boilerplate-qt.cpp
@@ -92,6 +92,7 @@ static const cairo_boilerplate_target_t targets[] = {
{
"qt", "qt", NULL, NULL,
CAIRO_SURFACE_TYPE_QT, CAIRO_CONTENT_COLOR_ALPHA, 0,
+ "cairo_qt_surface_create",
_cairo_boilerplate_qt_create_surface,
NULL, NULL,
_cairo_boilerplate_get_image_surface,
@@ -101,6 +102,7 @@ static const cairo_boilerplate_target_t targets[] = {
{
"qt", "qt", NULL, NULL,
CAIRO_SURFACE_TYPE_QT, CAIRO_CONTENT_COLOR, 0,
+ "cairo_qt_surface_create",
_cairo_boilerplate_qt_create_surface,
NULL, NULL,
_cairo_boilerplate_get_image_surface,
commit 0f09349dd85b15d5de14248e2f3f17a91fbcbb5e
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Mon Jan 18 23:37:36 2010 +0000
gl: Exercise Window destinations with boilerplate
Add a gl-window boilerplate target to exercise using GL to render to a
visible Drawable -- for instance, a window has a different coordinate
system to a framebuffer...
diff --git a/boilerplate/cairo-boilerplate-gl.c b/boilerplate/cairo-boilerplate-gl.c
index 8dfe6e9..d4f5e37 100644
--- a/boilerplate/cairo-boilerplate-gl.c
+++ b/boilerplate/cairo-boilerplate-gl.c
@@ -138,6 +138,93 @@ _cairo_boilerplate_gl_create_surface (const char *name,
return surface;
}
+static cairo_surface_t *
+_cairo_boilerplate_gl_create_window (const char *name,
+ cairo_content_t content,
+ double width,
+ double height,
+ double max_width,
+ double max_height,
+ cairo_boilerplate_mode_t mode,
+ int id,
+ void **closure)
+{
+ int rgb_attribs[] = { GLX_RGBA,
+ GLX_RED_SIZE, 1,
+ GLX_GREEN_SIZE, 1,
+ GLX_BLUE_SIZE, 1,
+ GLX_DOUBLEBUFFER,
+ None };
+ XVisualInfo *vi;
+ GLXContext ctx;
+ gl_target_closure_t *gltc;
+ cairo_surface_t *surface;
+ Display *dpy;
+ XSetWindowAttributes attr;
+
+ gltc = calloc (1, sizeof (gl_target_closure_t));
+ *closure = gltc;
+
+ if (width == 0)
+ width = 1;
+ if (height == 0)
+ height = 1;
+
+ dpy = XOpenDisplay (NULL);
+ gltc->dpy = dpy;
+ if (!gltc->dpy) {
+ fprintf (stderr, "Failed to open display: %s\n", XDisplayName(0));
+ free (gltc);
+ return NULL;
+ }
+
+ if (mode == CAIRO_BOILERPLATE_MODE_TEST)
+ XSynchronize (gltc->dpy, 1);
+
+ vi = glXChooseVisual (dpy, DefaultScreen (dpy), rgb_attribs);
+ if (vi == NULL) {
+ fprintf (stderr, "Failed to create RGB, double-buffered visual\n");
+ XCloseDisplay (dpy);
+ free (gltc);
+ return NULL;
+ }
+
+ attr.colormap = XCreateColormap (dpy,
+ RootWindow (dpy, vi->screen),
+ vi->visual,
+ AllocNone);
+ attr.border_pixel = 0;
+ attr.override_redirect = True;
+ gltc->drawable = XCreateWindow (dpy, DefaultRootWindow (dpy), 0, 0,
+ width, height, 0, vi->depth,
+ InputOutput, vi->visual,
+ CWOverrideRedirect | CWBorderPixel | CWColormap,
+ &attr);
+ XMapWindow (dpy, gltc->drawable);
+
+ ctx = glXCreateContext (dpy, vi, NULL, True);
+ XFree (vi);
+
+ gltc->ctx = ctx;
+ gltc->device = cairo_glx_device_create (dpy, ctx);
+
+ gltc->surface = surface = cairo_gl_surface_create_for_window (gltc->device,
+ gltc->drawable,
+ ceil (width),
+ ceil (height));
+ if (cairo_surface_status (surface))
+ _cairo_boilerplate_gl_cleanup (gltc);
+
+ return surface;
+}
+
+static cairo_status_t
+_cairo_boilerplate_gl_finish_window (cairo_surface_t *surface)
+{
+ cairo_gl_surface_swapbuffers (surface);
+ return CAIRO_STATUS_SUCCESS;
+}
+
static void
_cairo_boilerplate_gl_synchronize (void *closure)
{
@@ -169,5 +256,17 @@ static const cairo_boilerplate_target_t targets[] = {
_cairo_boilerplate_gl_cleanup,
_cairo_boilerplate_gl_synchronize
},
+ {
+ "gl-window", "gl", NULL, NULL,
+ CAIRO_SURFACE_TYPE_GL, CAIRO_CONTENT_COLOR_ALPHA, 1,
+ "cairo_gl_surface_create_for_window",
+ _cairo_boilerplate_gl_create_window,
+ NULL,
+ _cairo_boilerplate_gl_finish_window,
+ _cairo_boilerplate_get_image_surface,
+ cairo_surface_write_to_png,
+ _cairo_boilerplate_gl_cleanup,
+ _cairo_boilerplate_gl_synchronize
+ },
};
CAIRO_BOILERPLATE (gl, targets)
commit ccea7fd7c1a2d7144e892c19615488e368529bc0
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Mon Jan 18 23:37:11 2010 +0000
gl: Port to cairo_device_t
diff --git a/boilerplate/cairo-boilerplate-gl.c b/boilerplate/cairo-boilerplate-gl.c
index 8f3669a..8dfe6e9 100644
--- a/boilerplate/cairo-boilerplate-gl.c
+++ b/boilerplate/cairo-boilerplate-gl.c
@@ -37,9 +37,10 @@
typedef struct _gl_target_closure {
Display *dpy;
int screen;
+ Window drawable;
- GLXContext gl_ctx;
- cairo_gl_context_t *ctx;
+ GLXContext ctx;
+ cairo_device_t *device;
cairo_surface_t *surface;
} gl_target_closure_t;
@@ -48,9 +49,15 @@ _cairo_boilerplate_gl_cleanup (void *closure)
{
gl_target_closure_t *gltc = closure;
- cairo_gl_context_destroy (gltc->ctx);
- glXDestroyContext (gltc->dpy, gltc->gl_ctx);
+ cairo_device_finish (gltc->device);
+ cairo_device_destroy (gltc->device);
+
+ glXDestroyContext (gltc->dpy, gltc->ctx);
+
+ if (gltc->drawable)
+ XDestroyWindow (gltc->dpy, gltc->drawable);
XCloseDisplay (gltc->dpy);
+
free (gltc);
}
@@ -79,12 +86,12 @@ _cairo_boilerplate_gl_create_surface (const char *name,
GLX_DOUBLEBUFFER,
None };
XVisualInfo *visinfo;
- GLXContext gl_ctx;
+ GLXContext ctx;
gl_target_closure_t *gltc;
cairo_surface_t *surface;
Display *dpy;
- gltc = malloc (sizeof (gl_target_closure_t));
+ gltc = calloc (1, sizeof (gl_target_closure_t));
*closure = gltc;
if (width == 0)
@@ -115,13 +122,14 @@ _cairo_boilerplate_gl_create_surface (const char *name,
return NULL;
}
- gl_ctx = glXCreateContext (dpy, visinfo, NULL, True);
+ ctx = glXCreateContext (dpy, visinfo, NULL, True);
XFree (visinfo);
- gltc->gl_ctx = gl_ctx;
- gltc->ctx = cairo_glx_context_create (dpy, gl_ctx);
+ gltc->ctx = ctx;
+ gltc->device = cairo_glx_device_create (dpy, ctx);
- gltc->surface = surface = cairo_gl_surface_create (gltc->ctx, content,
+ gltc->surface = surface = cairo_gl_surface_create (gltc->device,
+ content,
ceil (width),
ceil (height));
if (cairo_surface_status (surface))
diff --git a/src/cairo-eagle-context.c b/src/cairo-eagle-context.c
index 72efc2e..199a34d 100644
--- a/src/cairo-eagle-context.c
+++ b/src/cairo-eagle-context.c
@@ -41,6 +41,7 @@
#include "cairo-gl-private.h"
#include "cairo-error-private.h"
+
#include <i915_drm.h> /* XXX dummy surface for glewInit() */
#include <sys/ioctl.h>
@@ -129,19 +130,18 @@ _eagle_init (EGLDisplay display, EGLContext context)
eagleMakeCurrent (display, dummy, dummy, context);
}
-cairo_gl_context_t *
+cairo_device_t *
cairo_eagle_context_create (EGLDisplay display, EGLContext context)
{
cairo_eagle_context_t *ctx;
cairo_status_t status;
- if (! _eagle_init (display, context)) {
- return _cairo_gl_context_create_in_error (CAIRO_STATUS_NO_MEMORY);
- }
+ if (! _eagle_init (display, context))
+ return _cairo_device_create_in_error (CAIRO_STATUS_NO_MEMORY);
ctx = calloc (1, sizeof (cairo_eagle_context_t));
if (ctx == NULL)
- return _cairo_gl_context_create_in_error (CAIRO_STATUS_NO_MEMORY);
+ return _cairo_device_create_in_error (CAIRO_STATUS_NO_MEMORY);
ctx->display = display;
ctx->context = context;
@@ -153,28 +153,31 @@ cairo_eagle_context_create (EGLDisplay display, EGLContext context)
status = _cairo_gl_context_init (&ctx->base);
if (status) {
free (ctx);
- return _cairo_gl_context_create_in_error (status);
+ return _cairo_device_create_in_error (status);
}
- return &ctx->base;
+ return &ctx->base.base;
}
cairo_surface_t *
-cairo_gl_surface_create_for_eagle (cairo_gl_context_t *ctx,
+cairo_gl_surface_create_for_eagle (cairo_device_t *device,
EGLSurface eagle,
int width,
int height)
{
cairo_eagle_surface_t *surface;
- if (ctx->status)
- return _cairo_surface_create_in_error (ctx->status);
+ if (unlikely (device->status))
+ return _cairo_surface_create_in_error (device->status);
+
+ if (unlikely (device->backend->type != CAIRO_DEVICE_TYPE_GL))
+ return _cairo_surface_create_in_error (CAIRO_STATUS_DEVICE_TYPE_MISMATCH);
surface = calloc (1, sizeof (cairo_eagle_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_gl_surface_init (device, &surface->base,
CAIRO_CONTENT_COLOR_ALPHA, width, height);
surface->eagle = eagle;
diff --git a/src/cairo-gl-glyphs.c b/src/cairo-gl-glyphs.c
index 35546ff..dd6e3f2 100644
--- a/src/cairo-gl-glyphs.c
+++ b/src/cairo-gl-glyphs.c
@@ -208,12 +208,12 @@ static cairo_bool_t
_cairo_gl_surface_owns_font (cairo_gl_surface_t *surface,
cairo_scaled_font_t *scaled_font)
{
- cairo_gl_context_t *font_private;
+ cairo_device_t *font_private;
font_private = scaled_font->surface_private;
if ((scaled_font->surface_backend != NULL &&
scaled_font->surface_backend != &_cairo_gl_surface_backend) ||
- (font_private != NULL && font_private != surface->ctx))
+ (font_private != NULL && font_private != surface->base.device))
{
return FALSE;
}
@@ -448,7 +448,9 @@ _render_glyphs (cairo_gl_surface_t *dst,
if (unlikely (status))
return status;
- ctx = _cairo_gl_context_acquire (dst->ctx);
+ status = _cairo_gl_context_acquire (dst->base.device, &ctx);
+ if (unlikely (status))
+ return status;
_cairo_gl_set_destination (dst);
@@ -619,31 +621,43 @@ _cairo_gl_surface_show_glyphs_via_mask (cairo_gl_surface_t *dst,
cairo_clip_t *clip,
int *remaining_glyphs)
{
+ cairo_gl_context_t *ctx;
cairo_surface_t *mask;
cairo_status_t status;
cairo_solid_pattern_t solid;
cairo_bool_t has_component_alpha;
int i;
+ status = _cairo_gl_context_acquire (dst->base.device, &ctx);
+ if (unlikely (status))
+ return status;
+
/* XXX: For non-CA, this should be CAIRO_CONTENT_ALPHA to save memory */
- if (dst->ctx->glyphs_temporary_mask) {
- if (glyph_extents->width <= dst->ctx->glyphs_temporary_mask->width &&
- glyph_extents->height <= dst->ctx->glyphs_temporary_mask->height)
+ if (ctx->glyphs_temporary_mask) {
+ if (glyph_extents->width <= ctx->glyphs_temporary_mask->width &&
+ glyph_extents->height <= ctx->glyphs_temporary_mask->height)
{
- _cairo_gl_surface_clear (dst->ctx->glyphs_temporary_mask);
- mask = &dst->ctx->glyphs_temporary_mask->base;
+ status = _cairo_gl_surface_clear (ctx->glyphs_temporary_mask);
+ if (unlikely (status)) {
+ _cairo_gl_context_release (ctx);
+ return status;
+ }
+
+ mask = &ctx->glyphs_temporary_mask->base;
} else {
- cairo_surface_destroy (&dst->ctx->glyphs_temporary_mask->base);
- dst->ctx->glyphs_temporary_mask = NULL;
+ cairo_surface_destroy (&ctx->glyphs_temporary_mask->base);
+ ctx->glyphs_temporary_mask = NULL;
}
}
- if (!mask) {
- mask = cairo_gl_surface_create (dst->ctx,
+ if (mask == NULL) {
+ mask = cairo_gl_surface_create (dst->base.device,
CAIRO_CONTENT_COLOR_ALPHA,
glyph_extents->width,
glyph_extents->height);
- if (unlikely (mask->status))
+ if (unlikely (mask->status)) {
+ _cairo_gl_context_release (ctx);
return mask->status;
+ }
}
for (i = 0; i < num_glyphs; i++) {
@@ -676,8 +690,10 @@ _cairo_gl_surface_show_glyphs_via_mask (cairo_gl_surface_t *dst,
*remaining_glyphs = num_glyphs;
}
- if (!dst->ctx->glyphs_temporary_mask)
- dst->ctx->glyphs_temporary_mask = (cairo_gl_surface_t *)mask;
+ if (ctx->glyphs_temporary_mask == NULL)
+ ctx->glyphs_temporary_mask = (cairo_gl_surface_t *) mask;
+
+ _cairo_gl_context_release (ctx);
return status;
}
diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h
index 7d157d8..91f1bd4 100644
--- a/src/cairo-gl-private.h
+++ b/src/cairo-gl-private.h
@@ -40,6 +40,7 @@
#define CAIRO_GL_PRIVATE_H
#include "cairoint.h"
+#include "cairo-device-private.h"
#include "cairo-rtree-private.h"
#include <GL/glew.h>
@@ -66,7 +67,6 @@
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. */
@@ -79,11 +79,9 @@ typedef struct cairo_gl_glyph_cache {
unsigned int width, height;
} cairo_gl_glyph_cache_t;
-struct _cairo_gl_context {
- cairo_reference_count_t ref_count;
- cairo_status_t status;
+typedef struct _cairo_gl_context {
+ cairo_device_t base;
- cairo_mutex_t mutex; /* needed? */
GLuint dummy_tex;
GLint fill_rectangles_shader;
GLint fill_rectangles_color_uniform;
@@ -97,7 +95,7 @@ struct _cairo_gl_context {
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_gl_context_t;
enum cairo_gl_composite_operand_type {
OPERAND_CONSTANT,
@@ -130,14 +128,17 @@ typedef struct _cairo_gl_composite_setup {
cairo_private extern const cairo_surface_backend_t _cairo_gl_surface_backend;
-cairo_private cairo_gl_context_t *
-_cairo_gl_context_create_in_error (cairo_status_t status);
+static inline cairo_device_t *
+_cairo_gl_context_create_in_error (cairo_status_t status)
+{
+ return (cairo_device_t *) _cairo_device_create_in_error (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_init (cairo_device_t *device,
cairo_gl_surface_t *surface,
cairo_content_t content,
int width, int height);
@@ -157,11 +158,26 @@ _cairo_gl_operand_init (cairo_gl_composite_operand_t *operand,
int dst_x, int dst_y,
int width, int height);
-cairo_private cairo_gl_context_t *
-_cairo_gl_context_acquire (cairo_gl_context_t *ctx);
+static inline cairo_status_t cairo_warn
+_cairo_gl_context_acquire (cairo_device_t *device,
+ cairo_gl_context_t **ctx)
+{
+ cairo_status_t status;
+
+ status = cairo_device_acquire (device);
+ if (unlikely (status))
+ return status;
+
+ *ctx = (cairo_gl_context_t *) device;
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static inline void
+_cairo_gl_context_release (cairo_gl_context_t *ctx)
+{
+ cairo_device_release (&ctx->base);
+}
-cairo_private void
-_cairo_gl_context_release (cairo_gl_context_t *ctx);
cairo_private void
_cairo_gl_set_destination (cairo_gl_surface_t *surface);
@@ -169,7 +185,7 @@ _cairo_gl_set_destination (cairo_gl_surface_t *surface);
cairo_private cairo_bool_t
_cairo_gl_operator_is_supported (cairo_operator_t op);
-cairo_private void
+cairo_private cairo_status_t
_cairo_gl_surface_clear (cairo_gl_surface_t *surface);
cairo_private void
diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index 0080dc5..1f542cb 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -40,9 +40,6 @@
#include "cairo-error-private.h"
#include "cairo-gl-private.h"
-slim_hidden_proto (cairo_gl_context_reference);
-slim_hidden_proto (cairo_gl_context_destroy);
-
static cairo_int_status_t
_cairo_gl_surface_fill_rectangles (void *abstract_surface,
cairo_operator_t op,
@@ -64,42 +61,36 @@ int_as_float (uint32_t val)
return fi.f;
}
-static const cairo_gl_context_t _nil_context = {
- CAIRO_REFERENCE_COUNT_INVALID,
- CAIRO_STATUS_NO_MEMORY
-};
-
-static const cairo_gl_context_t _nil_context__invalid_format = {
- CAIRO_REFERENCE_COUNT_INVALID,
- CAIRO_STATUS_INVALID_FORMAT
-};
-
static cairo_bool_t _cairo_surface_is_gl (cairo_surface_t *surface)
{
return surface->backend == &_cairo_gl_surface_backend;
}
-cairo_gl_context_t *
-_cairo_gl_context_create_in_error (cairo_status_t status)
+static void
+_gl_destroy (void *device)
{
- if (status == CAIRO_STATUS_NO_MEMORY)
- return (cairo_gl_context_t *) &_nil_context;
+ cairo_gl_context_t *ctx = device;
- if (status == CAIRO_STATUS_INVALID_FORMAT)
- return (cairo_gl_context_t *) &_nil_context__invalid_format;
-
- ASSERT_NOT_REACHED;
- return NULL;
+ ctx->destroy (ctx);
+ free (ctx);
}
+static const cairo_device_backend_t _cairo_gl_device_backend = {
+ CAIRO_DEVICE_TYPE_GL,
+
+ NULL, NULL, /* lock, unlock */
+
+ NULL, /* flush */
+ NULL, /* finish */
+ _gl_destroy,
+};
+
cairo_status_t
_cairo_gl_context_init (cairo_gl_context_t *ctx)
{
int n;
- ctx->status = CAIRO_STATUS_SUCCESS;
- CAIRO_REFERENCE_COUNT_INIT (&ctx->ref_count, 1);
- CAIRO_MUTEX_INIT (ctx->mutex);
+ _cairo_device_init (&ctx->base, &_cairo_gl_device_backend);
memset (ctx->glyph_cache, 0, sizeof (ctx->glyph_cache));
@@ -139,57 +130,6 @@ _cairo_gl_context_init (cairo_gl_context_t *ctx)
return CAIRO_STATUS_SUCCESS;
}
-cairo_gl_context_t *
-cairo_gl_context_reference (cairo_gl_context_t *context)
-{
- if (context == NULL ||
- CAIRO_REFERENCE_COUNT_IS_INVALID (&context->ref_count))
- {
- return context;
- }
-
- assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&context->ref_count));
- _cairo_reference_count_inc (&context->ref_count);
-
- return context;
-}
-slim_hidden_def (cairo_gl_context_reference);
-
-void
-cairo_gl_context_destroy (cairo_gl_context_t *context)
-{
- int n;
-
- if (context == NULL ||
- CAIRO_REFERENCE_COUNT_IS_INVALID (&context->ref_count))
- {
- return;
- }
-
- assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&context->ref_count));
- if (! _cairo_reference_count_dec_and_test (&context->ref_count))
- return;
-
- glDeleteTextures (1, &context->dummy_tex);
-
- for (n = 0; n < ARRAY_LENGTH (context->glyph_cache); n++)
- _cairo_gl_glyph_cache_fini (&context->glyph_cache[n]);
-
- context->destroy (context);
-
- cairo_surface_destroy (&context->glyphs_temporary_mask->base);
-
- free (context);
-}
-slim_hidden_def (cairo_gl_context_destroy);
-
-cairo_gl_context_t *
-_cairo_gl_context_acquire (cairo_gl_context_t *ctx)
-{
- CAIRO_MUTEX_LOCK (ctx->mutex);
- return ctx;
-}
-
cairo_bool_t
_cairo_gl_get_image_format_and_type (pixman_format_code_t pixman_format,
GLenum *internal_format, GLenum *format,
@@ -314,15 +254,9 @@ _cairo_gl_get_image_format_and_type (pixman_format_code_t pixman_format,
}
void
-_cairo_gl_context_release (cairo_gl_context_t *ctx)
-{
- CAIRO_MUTEX_UNLOCK (ctx->mutex);
-}
-
-void
_cairo_gl_set_destination (cairo_gl_surface_t *surface)
{
- cairo_gl_context_t *ctx = surface->ctx;
+ cairo_gl_context_t *ctx = (cairo_gl_context_t *) surface->base.device;
if (ctx->current_target != surface) {
ctx->current_target = surface;
@@ -455,17 +389,16 @@ _cairo_gl_set_texture_surface (int tex_unit, GLuint tex,
}
void
-_cairo_gl_surface_init (cairo_gl_context_t *ctx,
+_cairo_gl_surface_init (cairo_device_t *device,
cairo_gl_surface_t *surface,
cairo_content_t content,
int width, int height)
{
_cairo_surface_init (&surface->base,
&_cairo_gl_surface_backend,
- NULL, /* device */
+ device,
content);
- surface->ctx = cairo_gl_context_reference (ctx);
surface->width = width;
surface->height = height;
}
@@ -480,8 +413,8 @@ _cairo_gl_surface_create_scratch (cairo_gl_context_t *ctx,
GLenum err, format;
cairo_status_t status;
- if (ctx->status)
- return _cairo_surface_create_in_error (ctx->status);
+ if (ctx->base.status)
+ return _cairo_surface_create_in_error (ctx->base.status);
assert (width <= ctx->max_framebuffer_size && height <= ctx->max_framebuffer_size);
@@ -489,7 +422,7 @@ _cairo_gl_surface_create_scratch (cairo_gl_context_t *ctx,
if (unlikely (surface == NULL))
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
- _cairo_gl_surface_init (ctx, surface, content, width, height);
+ _cairo_gl_surface_init (&ctx->base, surface, content, width, height);
switch (content) {
default:
@@ -545,12 +478,16 @@ _cairo_gl_surface_create_scratch (cairo_gl_context_t *ctx,
return &surface->base;
}
-void
+cairo_status_t
_cairo_gl_surface_clear (cairo_gl_surface_t *surface)
{
cairo_gl_context_t *ctx;
+ cairo_status_t status;
+
+ status = _cairo_gl_context_acquire (surface->base.device, &ctx);
+ if (unlikely (status))
+ return status;
- ctx = _cairo_gl_context_acquire (surface->ctx);
_cairo_gl_set_destination (surface);
if (surface->base.content == CAIRO_CONTENT_COLOR)
glClearColor (0.0, 0.0, 0.0, 1.0);
@@ -561,17 +498,20 @@ _cairo_gl_surface_clear (cairo_gl_surface_t *surface)
surface->base.is_clear = TRUE;
+ return CAIRO_STATUS_SUCCESS;
}
cairo_surface_t *
-cairo_gl_surface_create (cairo_gl_context_t *ctx,
- cairo_content_t content,
- int width,
- int height)
+cairo_gl_surface_create (cairo_device_t *abstract_device,
+ cairo_content_t content,
+ int width,
+ int height)
{
+ cairo_gl_context_t *ctx = (cairo_gl_context_t *) abstract_device;
cairo_gl_surface_t *surface;
+ cairo_status_t status;
- if (!CAIRO_CONTENT_VALID (content))
+ if (! CAIRO_CONTENT_VALID (content))
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_CONTENT));
if (ctx == NULL) {
@@ -579,13 +519,20 @@ cairo_gl_surface_create (cairo_gl_context_t *ctx,
width, height);
}
+ if (ctx->base.backend->type != CAIRO_DEVICE_TYPE_GL)
+ return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH));
+
surface = (cairo_gl_surface_t *)
_cairo_gl_surface_create_scratch (ctx, content, width, height);
if (unlikely (surface->base.status))
return &surface->base;
/* Cairo surfaces start out initialized to transparent (black) */
- _cairo_gl_surface_clear (surface);
+ status = _cairo_gl_surface_clear (surface);
+ if (unlikely (status)) {
+ cairo_surface_destroy (&surface->base);
+ return _cairo_surface_create_in_error (status);
+ }
return &surface->base;
}
@@ -631,7 +578,6 @@ cairo_gl_surface_get_height (cairo_surface_t *abstract_surface)
return surface->height;
}
-
void
cairo_gl_surface_swapbuffers (cairo_surface_t *abstract_surface)
{
@@ -644,8 +590,10 @@ cairo_gl_surface_swapbuffers (cairo_surface_t *abstract_surface)
return;
}
- if (! surface->fb)
- surface->ctx->swap_buffers (surface->ctx, surface);
+ if (! surface->fb) {
+ cairo_gl_context_t *ctx = (cairo_gl_context_t *) surface->base.device;
+ ctx->swap_buffers (ctx, surface);
+ }
}
static cairo_surface_t *
@@ -655,11 +603,12 @@ _cairo_gl_surface_create_similar (void *abstract_surface,
int height)
{
cairo_gl_surface_t *surface = abstract_surface;
+ cairo_gl_context_t *ctx = (cairo_gl_context_t *) surface->base.device;
assert (CAIRO_CONTENT_VALID (content));
- if (width > surface->ctx->max_framebuffer_size ||
- height > surface->ctx->max_framebuffer_size)
+ if (width > ctx->max_framebuffer_size ||
+ height > ctx->max_framebuffer_size)
{
return NULL;
}
@@ -669,7 +618,7 @@ _cairo_gl_surface_create_similar (void *abstract_surface,
if (height < 1)
height = 1;
- return _cairo_gl_surface_create_scratch (surface->ctx, content, width, height);
+ return _cairo_gl_surface_create_scratch (ctx, content, width, height);
}
cairo_status_t
@@ -685,10 +634,10 @@ _cairo_gl_surface_draw_image (cairo_gl_surface_t *dst,
int cpp;
if (! _cairo_gl_get_image_format_and_type (src->pixman_format,
- &internal_format,
- &format,
- &type,
- &has_alpha))
+ &internal_format,
+ &format,
+ &type,
+ &has_alpha))
{
cairo_bool_t is_supported;
@@ -815,14 +764,13 @@ static cairo_status_t
_cairo_gl_surface_finish (void *abstract_surface)
{
cairo_gl_surface_t *surface = abstract_surface;
+ cairo_gl_context_t *ctx = (cairo_gl_context_t *) surface->base.device;
glDeleteFramebuffersEXT (1, &surface->fb);
glDeleteTextures (1, &surface->tex);
- if (surface->ctx->current_target == surface)
- surface->ctx->current_target = NULL;
-
- cairo_gl_context_destroy (surface->ctx);
+ if (ctx->current_target == surface)
+ ctx->current_target = NULL;
return CAIRO_STATUS_SUCCESS;
}
@@ -1418,7 +1366,13 @@ _cairo_gl_surface_composite_component_alpha (cairo_operator_t op,
}
mask_attributes = &setup.mask.operand.texture.attributes;
- ctx = _cairo_gl_context_acquire (dst->ctx);
+ status = _cairo_gl_context_acquire (dst->base.device, &ctx);
+ if (unlikely (status)) {
+ _cairo_gl_operand_destroy (&setup.src);
+ _cairo_gl_operand_destroy (&setup.mask);
+ return status;
+ }
+
_cairo_gl_set_destination (dst);
if (clip_region != NULL) {
@@ -1610,7 +1564,10 @@ _cairo_gl_surface_composite (cairo_operator_t op,
mask_attributes = &setup.mask.operand.texture.attributes;
}
- ctx = _cairo_gl_context_acquire (dst->ctx);
+ status = _cairo_gl_context_acquire (dst->base.device, &ctx);
+ if (unlikely (status))
+ goto CLEANUP_SHADER;
+
_cairo_gl_set_destination (dst);
_cairo_gl_set_operator (dst, op, FALSE);
@@ -1748,6 +1705,7 @@ _cairo_gl_surface_composite (cairo_operator_t op,
CONTEXT_RELEASE:
_cairo_gl_context_release (ctx);
+ CLEANUP_SHADER:
_cairo_gl_operand_destroy (&setup.src);
if (mask != NULL)
_cairo_gl_operand_destroy (&setup.mask);
@@ -1827,11 +1785,14 @@ _cairo_gl_surface_fill_rectangles_fixed (void *abstract_surface,
int i;
GLfloat *vertices;
GLfloat *colors;
+ cairo_status_t status;
if (! _cairo_gl_operator_is_supported (op))
return UNSUPPORTED ("unsupported operator");
- ctx = _cairo_gl_context_acquire (surface->ctx);
+ status = _cairo_gl_context_acquire (surface->base.device, &ctx);
+ if (unlikely (status))
+ return status;
_cairo_gl_set_destination (surface);
_cairo_gl_set_operator (surface, op, FALSE);
@@ -1926,13 +1887,17 @@ _cairo_gl_surface_fill_rectangles_glsl (void *abstract_surface,
if (! _cairo_gl_operator_is_supported (op))
return UNSUPPORTED ("unsupported operator");
- ctx = _cairo_gl_context_acquire (surface->ctx);
+ status = _cairo_gl_context_acquire (surface->base.device, &ctx);
+ if (unlikely (status))
+ return status;
if (ctx->fill_rectangles_shader == 0) {
status = _cairo_gl_load_glsl (&ctx->fill_rectangles_shader,
fill_vs_source, fill_fs_source);
- if (_cairo_status_is_error (status))
+ if (_cairo_status_is_error (status)) {
+ _cairo_gl_context_release (ctx);
return status;
+ }
ctx->fill_rectangles_color_uniform =
glGetUniformLocationARB (ctx->fill_rectangles_shader, "color");
@@ -2020,6 +1985,7 @@ typedef struct _cairo_gl_surface_span_renderer {
cairo_antialias_t antialias;
cairo_gl_surface_t *dst;
+ cairo_gl_context_t *ctx;
cairo_region_t *clip;
cairo_composite_rectangles_t composite_rectangles;
@@ -2218,7 +2184,7 @@ _cairo_gl_surface_span_renderer_destroy (void *abstract_renderer)
return;
_cairo_gl_operand_destroy (&renderer->setup.src);
- _cairo_gl_context_release (renderer->dst->ctx);
+ _cairo_gl_context_release (renderer->ctx);
free (renderer);
}
@@ -2303,23 +2269,30 @@ _cairo_gl_surface_create_span_renderer (cairo_operator_t op,
rects->dst.x, rects->dst.y,
width, height);
if (unlikely (status)) {
- _cairo_gl_context_acquire (dst->ctx);
+ cairo_status_t status_ignored;
+
+ status_ignored = _cairo_gl_context_acquire (dst->base.device, &renderer->ctx);
+
_cairo_gl_surface_span_renderer_destroy (renderer);
return _cairo_span_renderer_create_in_error (status);
}
- _cairo_gl_context_acquire (dst->ctx);
+ status = _cairo_gl_context_acquire (dst->base.device, &renderer->ctx);
+ if (unlikely (status)) {
+ _cairo_gl_surface_span_renderer_destroy (renderer);
+ return _cairo_span_renderer_create_in_error (status);
+ }
_cairo_gl_set_destination (dst);
src_attributes = &renderer->setup.src.operand.texture.attributes;
_cairo_gl_set_operator (dst, op, FALSE);
- _cairo_gl_set_src_operand (dst->ctx, &renderer->setup);
+ _cairo_gl_set_src_operand (renderer->ctx, &renderer->setup);
/* Set up the mask to source from the incoming vertex color. */
glActiveTexture (GL_TEXTURE1);
/* Have to have a dummy texture bound in order to use the combiner unit. */
- glBindTexture (GL_TEXTURE_2D, dst->ctx->dummy_tex);
+ glBindTexture (GL_TEXTURE_2D, renderer->ctx->dummy_tex);
glEnable (GL_TEXTURE_2D);
glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
@@ -2372,11 +2345,8 @@ _cairo_gl_surface_paint (void *abstract_surface,
cairo_clip_t *clip)
{
/* simplify the common case of clearing the surface */
- if (op == CAIRO_OPERATOR_CLEAR && clip == NULL) {
- _cairo_gl_surface_clear (abstract_surface);
-
- return CAIRO_STATUS_SUCCESS;
- }
+ if (op == CAIRO_OPERATOR_CLEAR && clip == NULL)
+ return _cairo_gl_surface_clear (abstract_surface);
return CAIRO_INT_STATUS_UNSUPPORTED;
}
diff --git a/src/cairo-gl.h b/src/cairo-gl.h
index 1b8f795..79b241a 100644
--- a/src/cairo-gl.h
+++ b/src/cairo-gl.h
@@ -40,16 +40,8 @@
CAIRO_BEGIN_DECLS
-typedef struct _cairo_gl_context cairo_gl_context_t;
-
-cairo_public cairo_gl_context_t *
-cairo_gl_context_reference (cairo_gl_context_t *context);
-
-cairo_public void
-cairo_gl_context_destroy (cairo_gl_context_t *context);
-
cairo_public cairo_surface_t *
-cairo_gl_surface_create (cairo_gl_context_t *ctx,
+cairo_gl_surface_create (cairo_device_t *device,
cairo_content_t content,
int width, int height);
@@ -71,11 +63,11 @@ cairo_gl_surface_glfinish (cairo_surface_t *surface);
#if CAIRO_HAS_GLX_FUNCTIONS
#include <GL/glx.h>
-cairo_public cairo_gl_context_t *
-cairo_glx_context_create (Display *dpy, GLXContext gl_ctx);
+cairo_public cairo_device_t *
+cairo_glx_device_create (Display *dpy, GLXContext gl_ctx);
cairo_public cairo_surface_t *
-cairo_gl_surface_create_for_window (cairo_gl_context_t *ctx,
+cairo_gl_surface_create_for_window (cairo_device_t *device,
Window win,
int width, int height);
#endif
@@ -83,11 +75,11 @@ cairo_gl_surface_create_for_window (cairo_gl_context_t *ctx,
#if CAIRO_HAS_EAGLE_FUNCTIONS
#include <eagle.h>
-cairo_public cairo_gl_context_t *
-cairo_eagle_context_create (EGLDisplay display, EGLContext context);
+cairo_public cairo_device_t *
+cairo_eagle_device_create (EGLDisplay display, EGLContext context);
cairo_public cairo_surface_t *
-cairo_gl_surface_create_for_eagle (cairo_gl_context_t *ctx,
+cairo_gl_surface_create_for_eagle (cairo_device_t *device,
EGLSurface surface,
int width, int height);
#endif
diff --git a/src/cairo-glx-context.c b/src/cairo-glx-context.c
index 3fd6317..0cc31d3 100644
--- a/src/cairo-glx-context.c
+++ b/src/cairo-glx-context.c
@@ -88,6 +88,8 @@ _glx_destroy (void *abstract_ctx)
if (ctx->dummy_window != None)
XDestroyWindow (ctx->display, ctx->dummy_window);
+
+ glXMakeCurrent (ctx->display, 0, 0);
}
static cairo_status_t
@@ -142,8 +144,8 @@ _glx_dummy_ctx (Display *dpy, GLXContext gl_ctx, Window *dummy)
return CAIRO_STATUS_SUCCESS;
}
-cairo_gl_context_t *
-cairo_glx_context_create (Display *dpy, GLXContext gl_ctx)
+cairo_device_t *
+cairo_glx_device_create (Display *dpy, GLXContext gl_ctx)
{
cairo_glx_context_t *ctx;
cairo_status_t status;
@@ -171,25 +173,28 @@ cairo_glx_context_create (Display *dpy, GLXContext gl_ctx)
return _cairo_gl_context_create_in_error (status);
}
- return &ctx->base;
+ return &ctx->base.base;
}
cairo_surface_t *
-cairo_gl_surface_create_for_window (cairo_gl_context_t *ctx,
- Window win,
- int width,
- int height)
+cairo_gl_surface_create_for_window (cairo_device_t *device,
+ Window win,
+ int width,
+ int height)
{
cairo_glx_surface_t *surface;
- if (unlikely (ctx->status))
- return _cairo_surface_create_in_error (ctx->status);
+ if (unlikely (device->status))
+ return _cairo_surface_create_in_error (device->status);
+
+ if (device->backend->type != CAIRO_DEVICE_TYPE_GL)
+ return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH));
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_gl_surface_init (device, &surface->base,
CAIRO_CONTENT_COLOR_ALPHA, width, height);
surface->win = win;
commit 3acd520c9dec89e72d7ff61adb1ae30bab12e256
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Mon Jan 18 23:11:19 2010 +0000
xml: Port to cairo_device_t
diff --git a/src/cairo-xml-surface.c b/src/cairo-xml-surface.c
index 1677c4c..53247a0 100644
--- a/src/cairo-xml-surface.c
+++ b/src/cairo-xml-surface.c
@@ -45,6 +45,7 @@
#include "cairo-xml.h"
#include "cairo-clip-private.h"
+#include "cairo-device-private.h"
#include "cairo-error-private.h"
#include "cairo-output-stream-private.h"
#include "cairo-recording-surface-private.h"
@@ -53,30 +54,21 @@
typedef struct _cairo_xml_surface cairo_xml_surface_t;
-struct _cairo_xml {
- cairo_status_t status;
-
- int ref;
+typedef struct _cairo_xml {
+ cairo_device_t base;
cairo_output_stream_t *stream;
int indent;
-};
+} cairo_xml_t;
struct _cairo_xml_surface {
cairo_surface_t base;
- cairo_xml_t *xml;
-
double width, height;
};
slim_hidden_proto (cairo_xml_for_recording_surface);
-static const cairo_xml_t _nil_xml = {
- CAIRO_STATUS_NO_MEMORY,
- -1
-};
-
static const cairo_surface_backend_t _cairo_xml_surface_backend;
static const char *
@@ -232,25 +224,53 @@ _format_to_string (cairo_format_t format)
return names[format];
}
-static cairo_xml_t *
+static void
+_device_flush (void *abstract_device)
+{
+ cairo_xml_t *xml = abstract_device;
+ cairo_status_t status;
+
+ status = _cairo_output_stream_flush (xml->stream);
+}
+
+static void
+_device_destroy (void *abstract_device)
+{
+ cairo_xml_t *xml = abstract_device;
+ cairo_status_t status;
+
+ status = _cairo_output_stream_destroy (xml->stream);
+
+ free (xml);
+}
+
+static const cairo_device_backend_t _cairo_xml_device_backend = {
+ CAIRO_DEVICE_TYPE_XML,
+
+ NULL, NULL, /* lock, unlock */
+
+ _device_flush,
+ NULL, /* finish */
+ _device_destroy
+};
+
+static cairo_device_t *
_cairo_xml_create_internal (cairo_output_stream_t *stream)
{
cairo_xml_t *xml;
xml = malloc (sizeof (cairo_xml_t));
- if (unlikely (xml == NULL)) {
- _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
- return (cairo_xml_t *) &_nil_xml;
- }
+ if (unlikely (xml == NULL))
+ return _cairo_device_create_in_error (CAIRO_STATUS_NO_MEMORY);
memset (xml, 0, sizeof (cairo_xml_t));
- xml->status = CAIRO_STATUS_SUCCESS;
- xml->ref = 1;
- xml->indent = 0;
+ _cairo_device_init (&xml->base, &_cairo_xml_device_backend);
+
+ xml->indent = 0;
xml->stream = stream;
- return xml;
+ return &xml->base;
}
static void
@@ -321,22 +341,6 @@ _cairo_xml_printf_end (cairo_xml_t *xml, const char *fmt, ...)
_cairo_output_stream_write (xml->stream, "\n", 1);
}
-static cairo_status_t
-_cairo_xml_destroy_internal (cairo_xml_t *xml)
-{
- cairo_status_t status;
-
- assert (xml->ref > 0);
- if (--xml->ref)
- return _cairo_output_stream_flush (xml->stream);
-
- status = _cairo_output_stream_destroy (xml->stream);
-
- free (xml);
-
- return status;
-}
-
static cairo_surface_t *
_cairo_xml_surface_create_similar (void *abstract_surface,
cairo_content_t content,
@@ -352,14 +356,6 @@ _cairo_xml_surface_create_similar (void *abstract_surface,
return cairo_recording_surface_create (content, &extents);
}
-static cairo_status_t
-_cairo_xml_surface_finish (void *abstract_surface)
-{
- cairo_xml_surface_t *surface = abstract_surface;
-
- return _cairo_xml_destroy_internal (surface->xml);
-}
-
static cairo_bool_t
_cairo_xml_surface_get_extents (void *abstract_surface,
cairo_rectangle_int_t *rectangle)
@@ -382,8 +378,8 @@ _cairo_xml_move_to (void *closure,
const cairo_point_t *p1)
{
_cairo_xml_printf_continue (closure, " %f %f m",
- _cairo_fixed_to_double (p1->x),
- _cairo_fixed_to_double (p1->y));
+ _cairo_fixed_to_double (p1->x),
+ _cairo_fixed_to_double (p1->y));
return CAIRO_STATUS_SUCCESS;
}
@@ -393,8 +389,8 @@ _cairo_xml_line_to (void *closure,
const cairo_point_t *p1)
{
_cairo_xml_printf_continue (closure, " %f %f l",
- _cairo_fixed_to_double (p1->x),
- _cairo_fixed_to_double (p1->y));
+ _cairo_fixed_to_double (p1->x),
+ _cairo_fixed_to_double (p1->y));
return CAIRO_STATUS_SUCCESS;
}
@@ -406,12 +402,13 @@ _cairo_xml_curve_to (void *closure,
const cairo_point_t *p3)
{
_cairo_xml_printf_continue (closure, " %f %f %f %f %f %f c",
- _cairo_fixed_to_double (p1->x),
- _cairo_fixed_to_double (p1->y),
- _cairo_fixed_to_double (p2->x),
- _cairo_fixed_to_double (p2->y),
- _cairo_fixed_to_double (p3->x),
- _cairo_fixed_to_double (p3->y));
+ _cairo_fixed_to_double (p1->x),
+ _cairo_fixed_to_double (p1->y),
+ _cairo_fixed_to_double (p2->x),
+ _cairo_fixed_to_double (p2->y),
+ _cairo_fixed_to_double (p3->x),
+ _cairo_fixed_to_double (p3->y));
+
return CAIRO_STATUS_SUCCESS;
}
@@ -419,6 +416,7 @@ static cairo_status_t
_cairo_xml_close_path (void *closure)
{
_cairo_xml_printf_continue (closure, " h");
+
return CAIRO_STATUS_SUCCESS;
}
@@ -456,12 +454,19 @@ _cairo_xml_emit_double (cairo_xml_t *xml,
_cairo_xml_printf (xml, "<%s>%f</%s>", node, data, node);
}
+static cairo_xml_t *
+to_xml (cairo_xml_surface_t *surface)
+{
+ return (cairo_xml_t *) surface->base.device;
+}
+
static cairo_status_t
_cairo_xml_surface_emit_clip_path (cairo_xml_surface_t *surface,
cairo_clip_path_t *clip_path)
{
cairo_box_t box;
cairo_status_t status;
+ cairo_xml_t *xml;
if (clip_path->prev != NULL) {
status = _cairo_xml_surface_emit_clip_path (surface, clip_path->prev);
@@ -482,18 +487,20 @@ _cairo_xml_surface_emit_clip_path (cairo_xml_surface_t *surface,
}
}
- _cairo_xml_printf_start (surface->xml, "<clip>");
- _cairo_xml_indent (surface->xml, 2);
+ xml = to_xml (surface);
- _cairo_xml_emit_path (surface->xml, &clip_path->path);
- _cairo_xml_emit_double (surface->xml, "tolerance", clip_path->tolerance);
- _cairo_xml_emit_string (surface->xml, "antialias",
+ _cairo_xml_printf_start (xml, "<clip>");
+ _cairo_xml_indent (xml, 2);
+
+ _cairo_xml_emit_path (xml, &clip_path->path);
+ _cairo_xml_emit_double (xml, "tolerance", clip_path->tolerance);
+ _cairo_xml_emit_string (xml, "antialias",
_antialias_to_string (clip_path->antialias));
- _cairo_xml_emit_string (surface->xml, "fill-rule",
+ _cairo_xml_emit_string (xml, "fill-rule",
_fill_rule_to_string (clip_path->fill_rule));
- _cairo_xml_indent (surface->xml, -2);
- _cairo_xml_printf_end (surface->xml, "</clip>");
+ _cairo_xml_indent (xml, -2);
+ _cairo_xml_printf_end (xml, "</clip>");
return CAIRO_STATUS_SUCCESS;
}
@@ -625,7 +632,7 @@ _cairo_xml_emit_surface (cairo_xml_t *xml,
cairo_status_t status;
if (_cairo_surface_is_recording (source)) {
- status = cairo_xml_for_recording_surface (xml, source);
+ status = cairo_xml_for_recording_surface (&xml->base, source);
} else {
cairo_image_surface_t *image;
void *image_extra;
@@ -695,7 +702,7 @@ _cairo_xml_surface_paint (void *abstract_surface,
cairo_clip_t *clip)
{
cairo_xml_surface_t *surface = abstract_surface;
- cairo_xml_t *xml = surface->xml;
+ cairo_xml_t *xml = to_xml (surface);
cairo_status_t status;
_cairo_xml_printf (xml, "<paint>");
@@ -725,7 +732,7 @@ _cairo_xml_surface_mask (void *abstract_surface,
cairo_clip_t *clip)
{
cairo_xml_surface_t *surface = abstract_surface;
- cairo_xml_t *xml = surface->xml;
+ cairo_xml_t *xml = to_xml (surface);
cairo_status_t status;
_cairo_xml_printf (xml, "<mask>");
@@ -764,7 +771,7 @@ _cairo_xml_surface_stroke (void *abstract_surface,
cairo_clip_t *clip)
{
cairo_xml_surface_t *surface = abstract_surface;
- cairo_xml_t *xml = surface->xml;
+ cairo_xml_t *xml = to_xml (surface);
cairo_status_t status;
_cairo_xml_printf (xml, "<stroke>");
@@ -795,7 +802,7 @@ _cairo_xml_surface_stroke (void *abstract_surface,
_cairo_xml_printf_end (xml, "</dash>");
}
- _cairo_xml_emit_path (surface->xml, path);
+ _cairo_xml_emit_path (xml, path);
_cairo_xml_emit_double (xml, "tolerance", tolerance);
_cairo_xml_emit_string (xml, "antialias", _antialias_to_string (antialias));
@@ -818,7 +825,7 @@ _cairo_xml_surface_fill (void *abstract_surface,
cairo_clip_t *clip)
{
cairo_xml_surface_t *surface = abstract_surface;
- cairo_xml_t *xml = surface->xml;
+ cairo_xml_t *xml = to_xml (surface);
cairo_status_t status;
_cairo_xml_printf (xml, "<fill>");
@@ -834,7 +841,7 @@ _cairo_xml_surface_fill (void *abstract_surface,
if (unlikely (status))
return status;
- _cairo_xml_emit_path (surface->xml, path);
+ _cairo_xml_emit_path (xml, path);
_cairo_xml_emit_double (xml, "tolerance", tolerance);
_cairo_xml_emit_string (xml, "antialias", _antialias_to_string (antialias));
_cairo_xml_emit_string (xml, "fill-rule", _fill_rule_to_string (fill_rule));
@@ -958,7 +965,7 @@ _cairo_xml_surface_glyphs (void *abstract_surface,
int *remaining_glyphs)
{
cairo_xml_surface_t *surface = abstract_surface;
- cairo_xml_t *xml = surface->xml;
+ cairo_xml_t *xml = to_xml (surface);
cairo_status_t status;
int i;
@@ -997,7 +1004,7 @@ static const cairo_surface_backend_t
_cairo_xml_surface_backend = {
CAIRO_SURFACE_TYPE_XML,
_cairo_xml_surface_create_similar,
- _cairo_xml_surface_finish,
+ NULL,
NULL, NULL, /* source image */
NULL, NULL, /* dst image */
NULL, /* clone_similar */
@@ -1034,82 +1041,88 @@ _cairo_xml_surface_backend = {
};
static cairo_surface_t *
-_cairo_xml_surface_create_internal (cairo_xml_t *xml,
+_cairo_xml_surface_create_internal (cairo_device_t *device,
cairo_content_t content,
double width,
double height)
{
cairo_xml_surface_t *surface;
- if (unlikely (xml == NULL))
- return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NULL_POINTER));
-
surface = malloc (sizeof (cairo_xml_surface_t));
if (unlikely (surface == NULL))
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
_cairo_surface_init (&surface->base,
&_cairo_xml_surface_backend,
- NULL, /* device */
+ device,
content);
- surface->xml = xml;
- xml->ref++;
-
surface->width = width;
surface->height = height;
return &surface->base;
}
-cairo_xml_t *
+cairo_device_t *
cairo_xml_create (const char *filename)
{
cairo_output_stream_t *stream;
+ cairo_status_t status;
stream = _cairo_output_stream_create_for_filename (filename);
- if (_cairo_output_stream_get_status (stream))
- return (cairo_xml_t *) &_nil_xml;
+ if ((status = _cairo_output_stream_get_status (stream)))
+ return _cairo_device_create_in_error (status);
return _cairo_xml_create_internal (stream);
}
-cairo_xml_t *
+cairo_device_t *
cairo_xml_create_for_stream (cairo_write_func_t write_func,
void *closure)
{
cairo_output_stream_t *stream;
+ cairo_status_t status;
stream = _cairo_output_stream_create (write_func, NULL, closure);
- if (_cairo_output_stream_get_status (stream))
- return (cairo_xml_t *) &_nil_xml;
+ if ((status = _cairo_output_stream_get_status (stream)))
+ return _cairo_device_create_in_error (status);
return _cairo_xml_create_internal (stream);
}
cairo_surface_t *
-cairo_xml_surface_create (cairo_xml_t *xml,
+cairo_xml_surface_create (cairo_device_t *device,
cairo_content_t content,
double width, double height)
{
- return _cairo_xml_surface_create_internal (xml, content, width, height);
+ if (unlikely (device->backend->type != CAIRO_DEVICE_TYPE_XML))
+ return _cairo_surface_create_in_error (CAIRO_STATUS_DEVICE_TYPE_MISMATCH);
+
+ if (unlikely (device->status))
+ return _cairo_surface_create_in_error (device->status);
+
+ return _cairo_xml_surface_create_internal (device, content, width, height);
}
cairo_status_t
-cairo_xml_for_recording_surface (cairo_xml_t *xml,
+cairo_xml_for_recording_surface (cairo_device_t *device,
cairo_surface_t *recording_surface)
{
cairo_box_t bbox;
cairo_rectangle_int_t extents;
cairo_surface_t *surface;
+ cairo_xml_t *xml;
cairo_status_t status;
- if (unlikely (xml->status))
- return xml->status;
+ if (unlikely (device->status))
+ return device->status;
if (unlikely (recording_surface->status))
return recording_surface->status;
+ if (unlikely (device->backend->type != CAIRO_DEVICE_TYPE_XML))
+ return _cairo_error (CAIRO_STATUS_DEVICE_TYPE_MISMATCH);
+
if (unlikely (! _cairo_surface_is_recording (recording_surface)))
return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
@@ -1119,13 +1132,15 @@ cairo_xml_for_recording_surface (cairo_xml_t *xml,
return status;
_cairo_box_round_to_rectangle (&bbox, &extents);
- surface = _cairo_xml_surface_create_internal (xml,
+ surface = _cairo_xml_surface_create_internal (device,
recording_surface->content,
extents.width,
extents.height);
if (unlikely (surface->status))
return surface->status;
+ xml = (cairo_xml_t *) device;
+
_cairo_xml_printf (xml,
"<surface content='%s' width='%d' height='%d'>",
_content_to_string (recording_surface->content),
@@ -1142,14 +1157,3 @@ cairo_xml_for_recording_surface (cairo_xml_t *xml,
return status;
}
slim_hidden_def (cairo_xml_for_recording_surface);
-
-void
-cairo_xml_destroy (cairo_xml_t *xml)
-{
- cairo_status_t status_ignored;
-
- if (xml == NULL || xml->ref < 0)
- return;
-
- status_ignored = _cairo_xml_destroy_internal (xml);
-}
diff --git a/src/cairo-xml.h b/src/cairo-xml.h
index bba8adc..3ad6559 100644
--- a/src/cairo-xml.h
+++ b/src/cairo-xml.h
@@ -42,25 +42,20 @@
CAIRO_BEGIN_DECLS
-typedef struct _cairo_xml cairo_xml_t;
-
-cairo_public cairo_xml_t *
+cairo_public cairo_device_t *
cairo_xml_create (const char *filename);
-cairo_public cairo_xml_t *
+cairo_public cairo_device_t *
cairo_xml_create_for_stream (cairo_write_func_t write_func,
void *closure);
-cairo_public void
-cairo_xml_destroy (cairo_xml_t *context);
-
cairo_public cairo_surface_t *
-cairo_xml_surface_create (cairo_xml_t *xml,
+cairo_xml_surface_create (cairo_device_t *xml,
cairo_content_t content,
double width, double height);
cairo_public cairo_status_t
-cairo_xml_for_recording_surface (cairo_xml_t *context,
+cairo_xml_for_recording_surface (cairo_device_t *xml,
cairo_surface_t *surface);
CAIRO_END_DECLS
diff --git a/util/trace-to-xml.c b/util/trace-to-xml.c
index 416d8e1..a0f03cc 100644
--- a/util/trace-to-xml.c
+++ b/util/trace-to-xml.c
@@ -11,7 +11,8 @@
static cairo_surface_t *
_surface_create (void *_closure,
cairo_content_t content,
- double width, double height)
+ double width, double height,
+ long uid)
{
cairo_surface_t **closure = _closure;
cairo_surface_t *surface;
@@ -59,11 +60,11 @@ main (int argc, char **argv)
cairo_script_interpreter_destroy (csi);
if (surface != NULL) {
- cairo_xml_t *xml;
+ cairo_device_t *xml;
xml = cairo_xml_create_for_stream (stdio_write, out);
cairo_xml_for_recording_surface (xml, surface);
- cairo_xml_destroy (xml);
+ cairo_device_destroy (xml);
cairo_surface_destroy (surface);
}
commit 49ab86772a44d7a044464d875324bd0af96af728
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Mon Jan 18 22:43:24 2010 +0000
script: Port cairo_script_context_t to cairo_device_t
Use the unifying cairo_device_t for cairo_script_context_t and replace.
diff --git a/boilerplate/cairo-boilerplate-script.c b/boilerplate/cairo-boilerplate-script.c
index e37fdf1..7c052a3 100644
--- a/boilerplate/cairo-boilerplate-script.c
+++ b/boilerplate/cairo-boilerplate-script.c
@@ -48,7 +48,7 @@ _cairo_boilerplate_script_create_surface (const char *name,
void **closure)
{
script_target_closure_t *ptc;
- cairo_script_context_t *ctx;
+ cairo_device_t *ctx;
cairo_surface_t *surface;
cairo_status_t status;
@@ -60,9 +60,9 @@ _cairo_boilerplate_script_create_surface (const char *name,
xasprintf (&ptc->filename, "%s.out.cs", name);
xunlink (ptc->filename);
- ctx = cairo_script_context_create (ptc->filename);
+ ctx = cairo_script_create (ptc->filename);
surface = cairo_script_surface_create (ctx, content, width, height);
- cairo_script_context_destroy (ctx);
+ cairo_device_destroy (ctx);
status = cairo_surface_set_user_data (surface,
&script_closure_key, ptc, NULL);
diff --git a/boilerplate/cairo-boilerplate.c b/boilerplate/cairo-boilerplate.c
index 401e613..d3f312f 100644
--- a/boilerplate/cairo-boilerplate.c
+++ b/boilerplate/cairo-boilerplate.c
@@ -203,13 +203,13 @@ _cairo_boilerplate_get_image_surface (cairo_surface_t *src,
test_name = cairo_surface_get_user_data (src,
&cairo_boilerplate_output_basename_key);
if (test_name != NULL) {
- cairo_script_context_t *ctx;
+ cairo_device_t *ctx;
char *filename;
xasprintf (&filename, "%s.out.trace", test_name);
- ctx = cairo_script_context_create (filename);
+ ctx = cairo_script_create (filename);
surface = cairo_script_surface_create_for_target (ctx, image);
- cairo_script_context_destroy (ctx);
+ cairo_device_destroy (ctx);
free (filename);
}
}
diff --git a/src/cairo-script-surface.c b/src/cairo-script-surface.c
index 897fcab..53cfb7a 100644
--- a/src/cairo-script-surface.c
+++ b/src/cairo-script-surface.c
@@ -47,6 +47,7 @@
#include "cairo-script.h"
#include "cairo-analysis-surface-private.h"
+#include "cairo-device-private.h"
#include "cairo-error-private.h"
#include "cairo-ft-private.h"
#include "cairo-list-private.h"
@@ -63,6 +64,7 @@
#define static cairo_warn static
+typedef struct _cairo_script_context cairo_script_context_t;
typedef struct _cairo_script_surface cairo_script_surface_t;
typedef struct _cairo_script_implicit_context cairo_script_implicit_context_t;
typedef struct _cairo_script_surface_font_private cairo_script_surface_font_private_t;
@@ -82,9 +84,8 @@ struct deferred_finish {
};
struct _cairo_script_context {
- cairo_status_t status;
+ cairo_device_t base;
- int ref;
int active;
cairo_output_stream_t *stream;
@@ -134,7 +135,6 @@ struct _cairo_script_surface {
cairo_surface_wrapper_t wrapper;
- cairo_script_context_t *ctx;
cairo_surface_clipper_t clipper;
operand_t operand;
@@ -158,9 +158,6 @@ _cairo_script_surface_create_internal (cairo_script_context_t *ctx,
double height,
cairo_surface_t *passthrough);
-static cairo_status_t
-_context_destroy (cairo_script_context_t *ctx);
-
static void
_cairo_script_surface_scaled_font_fini (cairo_scaled_font_t *scaled_font);
@@ -371,17 +368,23 @@ _line_join_to_string (cairo_line_join_t line_join)
return names[line_join];
}
+static inline cairo_script_context_t *
+to_context (cairo_script_surface_t *surface)
+{
+ return (cairo_script_context_t *) surface->base.device;
+}
+
static cairo_bool_t
target_is_active (cairo_script_surface_t *surface)
{
return cairo_list_is_first (&surface->operand.link,
- &surface->ctx->operands);
+ &to_context (surface)->operands);
}
static void
target_push (cairo_script_surface_t *surface)
{
- cairo_list_move (&surface->operand.link, &surface->ctx->operands);
+ cairo_list_move (&surface->operand.link, &to_context (surface)->operands);
}
static int
@@ -390,7 +393,7 @@ target_depth (cairo_script_surface_t *surface)
cairo_list_t *link;
int depth = 0;
- cairo_list_foreach (link, &surface->ctx->operands) {
+ cairo_list_foreach (link, &to_context (surface)->operands) {
if (link == &surface->operand.link)
break;
depth++;
@@ -402,7 +405,7 @@ target_depth (cairo_script_surface_t *surface)
static void
_get_target (cairo_script_surface_t *surface)
{
- cairo_script_context_t *ctx = surface->ctx;
+ cairo_script_context_t *ctx = to_context (surface);
if (surface->defined) {
_cairo_output_stream_printf (ctx->stream, "s%u ",
@@ -416,10 +419,10 @@ _get_target (cairo_script_surface_t *surface)
_cairo_output_stream_puts (ctx->stream, "/target get exch pop ");
} else {
if (depth == 1) {
- _cairo_output_stream_puts (surface->ctx->stream,
+ _cairo_output_stream_puts (ctx->stream,
"exch\n");
} else {
- _cairo_output_stream_printf (surface->ctx->stream,
+ _cairo_output_stream_printf (ctx->stream,
"%d -1 roll\n",
depth);
}
@@ -446,11 +449,13 @@ _content_to_string (cairo_content_t content)
static cairo_status_t
_emit_surface (cairo_script_surface_t *surface)
{
- _cairo_output_stream_printf (surface->ctx->stream,
+ cairo_script_context_t *ctx = to_context (surface);
+
+ _cairo_output_stream_printf (ctx->stream,
"<< /content //%s",
_content_to_string (surface->base.content));
if (surface->width != -1 && surface->height != -1) {
- _cairo_output_stream_printf (surface->ctx->stream,
+ _cairo_output_stream_printf (ctx->stream,
" /width %f /height %f",
surface->width,
surface->height);
@@ -461,7 +466,7 @@ _emit_surface (cairo_script_surface_t *surface)
surface->base.y_fallback_resolution !=
CAIRO_SURFACE_FALLBACK_RESOLUTION_DEFAULT)
{
- _cairo_output_stream_printf (surface->ctx->stream,
+ _cairo_output_stream_printf (ctx->stream,
" /fallback-resolution [%f %f]",
surface->base.x_fallback_resolution,
surface->base.y_fallback_resolution);
@@ -472,14 +477,14 @@ _emit_surface (cairo_script_surface_t *surface)
{
/* XXX device offset is encoded into the pattern matrices etc. */
if (0) {
- _cairo_output_stream_printf (surface->ctx->stream,
+ _cairo_output_stream_printf (ctx->stream,
" /device-offset [%f %f]",
surface->base.device_transform.x0,
surface->base.device_transform.y0);
}
}
- _cairo_output_stream_puts (surface->ctx->stream, " >> surface context\n");
+ _cairo_output_stream_puts (ctx->stream, " >> surface context\n");
surface->emitted = TRUE;
return CAIRO_STATUS_SUCCESS;
}
@@ -487,7 +492,7 @@ _emit_surface (cairo_script_surface_t *surface)
static cairo_status_t
_emit_context (cairo_script_surface_t *surface)
{
- cairo_script_context_t *ctx = surface->ctx;
+ cairo_script_context_t *ctx = to_context (surface);
if (target_is_active (surface))
return CAIRO_STATUS_SUCCESS;
@@ -563,7 +568,7 @@ _emit_operator (cairo_script_surface_t *surface,
surface->cr.current_operator = op;
- _cairo_output_stream_printf (surface->ctx->stream,
+ _cairo_output_stream_printf (to_context (surface)->stream,
"//%s set-operator\n",
_operator_to_string (op));
return CAIRO_STATUS_SUCCESS;
@@ -580,7 +585,7 @@ _emit_fill_rule (cairo_script_surface_t *surface,
surface->cr.current_fill_rule = fill_rule;
- _cairo_output_stream_printf (surface->ctx->stream,
+ _cairo_output_stream_printf (to_context (surface)->stream,
"//%s set-fill-rule\n",
_fill_rule_to_string (fill_rule));
return CAIRO_STATUS_SUCCESS;
@@ -602,7 +607,7 @@ _emit_tolerance (cairo_script_surface_t *surface,
surface->cr.current_tolerance = tolerance;
- _cairo_output_stream_printf (surface->ctx->stream,
+ _cairo_output_stream_printf (to_context (surface)->stream,
"%f set-tolerance\n",
tolerance);
return CAIRO_STATUS_SUCCESS;
@@ -619,7 +624,7 @@ _emit_antialias (cairo_script_surface_t *surface,
surface->cr.current_antialias = antialias;
- _cairo_output_stream_printf (surface->ctx->stream,
+ _cairo_output_stream_printf (to_context (surface)->stream,
"//%s set-antialias\n",
_antialias_to_string (antialias));
@@ -642,7 +647,7 @@ _emit_line_width (cairo_script_surface_t *surface,
surface->cr.current_style.line_width = line_width;
- _cairo_output_stream_printf (surface->ctx->stream,
+ _cairo_output_stream_printf (to_context (surface)->stream,
"%f set-line-width\n",
line_width);
return CAIRO_STATUS_SUCCESS;
@@ -659,7 +664,7 @@ _emit_line_cap (cairo_script_surface_t *surface,
surface->cr.current_style.line_cap = line_cap;
- _cairo_output_stream_printf (surface->ctx->stream,
+ _cairo_output_stream_printf (to_context (surface)->stream,
"//%s set-line-cap\n",
_line_cap_to_string (line_cap));
return CAIRO_STATUS_SUCCESS;
@@ -676,7 +681,7 @@ _emit_line_join (cairo_script_surface_t *surface,
surface->cr.current_style.line_join = line_join;
- _cairo_output_stream_printf (surface->ctx->stream,
+ _cairo_output_stream_printf (to_context (surface)->stream,
"//%s set-line-join\n",
_line_join_to_string (line_join));
return CAIRO_STATUS_SUCCESS;
@@ -698,7 +703,7 @@ _emit_miter_limit (cairo_script_surface_t *surface,
surface->cr.current_style.miter_limit = miter_limit;
- _cairo_output_stream_printf (surface->ctx->stream,
+ _cairo_output_stream_printf (to_context (surface)->stream,
"%f set-miter-limit\n",
miter_limit);
return CAIRO_STATUS_SUCCESS;
@@ -762,13 +767,13 @@ _emit_dash (cairo_script_surface_t *surface,
surface->cr.current_style.num_dashes = num_dashes;
surface->cr.current_style.dash_offset = offset;
- _cairo_output_stream_puts (surface->ctx->stream, "[");
+ _cairo_output_stream_puts (to_context (surface)->stream, "[");
for (n = 0; n < num_dashes; n++) {
- _cairo_output_stream_printf (surface->ctx->stream, "%f", dash[n]);
+ _cairo_output_stream_printf (to_context (surface)->stream, "%f", dash[n]);
if (n < num_dashes-1)
- _cairo_output_stream_puts (surface->ctx->stream, " ");
+ _cairo_output_stream_puts (to_context (surface)->stream, " ");
}
- _cairo_output_stream_printf (surface->ctx->stream,
+ _cairo_output_stream_printf (to_context (surface)->stream,
"] %f set-dash\n",
offset);
@@ -827,6 +832,7 @@ _emit_solid_pattern (cairo_script_surface_t *surface,
const cairo_pattern_t *pattern)
{
cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) pattern;
+ cairo_script_context_t *ctx = to_context (surface);
if (solid->content & CAIRO_CONTENT_ALPHA &&
! CAIRO_COLOR_IS_OPAQUE (&solid->color))
@@ -837,13 +843,13 @@ _emit_solid_pattern (cairo_script_surface_t *surface,
(solid->color.green_short == 0 || solid->color.green_short == 0xffff) &&
(solid->color.blue_short == 0 || solid->color.blue_short == 0xffff) ))
{
- _cairo_output_stream_printf (surface->ctx->stream,
+ _cairo_output_stream_printf (ctx->stream,
"%f a",
solid->color.alpha);
}
else
{
- _cairo_output_stream_printf (surface->ctx->stream,
+ _cairo_output_stream_printf (ctx->stream,
"%f %f %f %f rgba",
solid->color.red,
solid->color.green,
@@ -856,13 +862,13 @@ _emit_solid_pattern (cairo_script_surface_t *surface,
if (solid->color.red_short == solid->color.green_short &&
solid->color.red_short == solid->color.blue_short)
{
- _cairo_output_stream_printf (surface->ctx->stream,
+ _cairo_output_stream_printf (ctx->stream,
"%f g",
solid->color.red);
}
else
{
- _cairo_output_stream_printf (surface->ctx->stream,
+ _cairo_output_stream_printf (ctx->stream,
"%f %f %f rgb",
solid->color.red,
solid->color.green,
@@ -897,28 +903,30 @@ static cairo_status_t
_emit_linear_pattern (cairo_script_surface_t *surface,
const cairo_pattern_t *pattern)
{
+ cairo_script_context_t *ctx = to_context (surface);
cairo_linear_pattern_t *linear;
linear = (cairo_linear_pattern_t *) pattern;
- _cairo_output_stream_printf (surface->ctx->stream,
+ _cairo_output_stream_printf (ctx->stream,
"%f %f %f %f linear",
_cairo_fixed_to_double (linear->p1.x),
_cairo_fixed_to_double (linear->p1.y),
_cairo_fixed_to_double (linear->p2.x),
_cairo_fixed_to_double (linear->p2.y));
- return _emit_gradient_color_stops (&linear->base, surface->ctx->stream);
+ return _emit_gradient_color_stops (&linear->base, ctx->stream);
}
static cairo_status_t
_emit_radial_pattern (cairo_script_surface_t *surface,
const cairo_pattern_t *pattern)
{
+ cairo_script_context_t *ctx = to_context (surface);
cairo_radial_pattern_t *radial;
radial = (cairo_radial_pattern_t *) pattern;
- _cairo_output_stream_printf (surface->ctx->stream,
+ _cairo_output_stream_printf (ctx->stream,
"%f %f %f %f %f %f radial",
_cairo_fixed_to_double (radial->c1.x),
_cairo_fixed_to_double (radial->c1.y),
@@ -926,7 +934,7 @@ _emit_radial_pattern (cairo_script_surface_t *surface,
_cairo_fixed_to_double (radial->c2.x),
_cairo_fixed_to_double (radial->c2.y),
_cairo_fixed_to_double (radial->r2));
- return _emit_gradient_color_stops (&radial->base, surface->ctx->stream);
+ return _emit_gradient_color_stops (&radial->base, ctx->stream);
}
static cairo_status_t
@@ -952,7 +960,7 @@ _emit_recording_surface_pattern (cairo_script_surface_t *surface,
/* convert to extents so that it matches the public api */
_cairo_box_round_to_rectangle (&bbox, &rect);
- similar = _cairo_script_surface_create_internal (surface->ctx,
+ similar = _cairo_script_surface_create_internal (to_context (surface),
source->content,
rect.width,
rect.height,
@@ -964,7 +972,7 @@ _emit_recording_surface_pattern (cairo_script_surface_t *surface,
surface->is_clear = TRUE;
_get_target (surface);
- _cairo_output_stream_printf (surface->ctx->stream,
+ _cairo_output_stream_printf (to_context (surface)->stream,
"%d %d //%s similar dup context\n",
rect.width, rect.height,
_content_to_string (source->content));
@@ -984,7 +992,7 @@ _emit_recording_surface_pattern (cairo_script_surface_t *surface,
cairo_list_del (&similar->operand.link);
assert (target_is_active (surface));
- _cairo_output_stream_puts (surface->ctx->stream, "pop pattern");
+ _cairo_output_stream_puts (to_context (surface)->stream, "pop pattern");
cairo_surface_destroy (&similar->base);
return CAIRO_STATUS_SUCCESS;
@@ -1001,7 +1009,7 @@ _emit_script_surface_pattern (cairo_script_surface_t *surface,
source = (cairo_script_surface_t *) surface_pattern->surface;
_get_target (source);
- _cairo_output_stream_puts (surface->ctx->stream, "pattern");
+ _cairo_output_stream_puts (to_context (surface)->stream, "pattern");
return CAIRO_STATUS_SUCCESS;
}
@@ -1115,8 +1123,9 @@ _write_image_surface (cairo_output_stream_t *output,
static cairo_int_status_t
_emit_png_surface (cairo_script_surface_t *surface,
- cairo_image_surface_t *image)
+ cairo_image_surface_t *image)
{
+ cairo_script_context_t *ctx = to_context (surface);
cairo_output_stream_t *base85_stream;
cairo_status_t status;
const uint8_t *mime_data;
@@ -1127,7 +1136,7 @@ _emit_png_surface (cairo_script_surface_t *surface,
if (mime_data == NULL)
return CAIRO_INT_STATUS_UNSUPPORTED;
- _cairo_output_stream_printf (surface->ctx->stream,
+ _cairo_output_stream_printf (ctx->stream,
"<< "
"/width %d "
"/height %d "
@@ -1137,13 +1146,13 @@ _emit_png_surface (cairo_script_surface_t *surface,
image->width, image->height,
_format_to_string (image->format));
- base85_stream = _cairo_base85_stream_create (surface->ctx->stream);
+ base85_stream = _cairo_base85_stream_create (ctx->stream);
_cairo_output_stream_write (base85_stream, mime_data, mime_data_length);
status = _cairo_output_stream_destroy (base85_stream);
if (unlikely (status))
return status;
- _cairo_output_stream_puts (surface->ctx->stream, "~> >> image ");
+ _cairo_output_stream_puts (ctx->stream, "~> >> image ");
return CAIRO_STATUS_SUCCESS;
}
@@ -1168,6 +1177,7 @@ static cairo_status_t
_emit_image_surface (cairo_script_surface_t *surface,
cairo_image_surface_t *image)
{
+ cairo_script_context_t *ctx = to_context (surface);
cairo_output_stream_t *base85_stream;
cairo_output_stream_t *zlib_stream;
cairo_status_t status, status2;
@@ -1176,9 +1186,9 @@ _emit_image_surface (cairo_script_surface_t *surface,
struct def *tag;
if (_cairo_user_data_array_get_data (&image->base.user_data,
- (cairo_user_data_key_t *) surface->ctx))
+ (cairo_user_data_key_t *) ctx))
{
- _cairo_output_stream_printf (surface->ctx->stream,
+ _cairo_output_stream_printf (ctx->stream,
"s%u pattern ",
image->base.unique_id);
return CAIRO_STATUS_SUCCESS;
@@ -1200,7 +1210,7 @@ _emit_image_surface (cairo_script_surface_t *surface,
cairo_surface_reference (&image->base);
}
- _cairo_output_stream_printf (surface->ctx->stream,
+ _cairo_output_stream_printf (ctx->stream,
"<< "
"/width %d "
"/height %d "
@@ -1226,9 +1236,9 @@ _emit_image_surface (cairo_script_surface_t *surface,
len *= clone->height;
if (len > 24) {
- _cairo_output_stream_puts (surface->ctx->stream, "<|");
+ _cairo_output_stream_puts (ctx->stream, "<|");
- base85_stream = _cairo_base85_stream_create (surface->ctx->stream);
+ base85_stream = _cairo_base85_stream_create (ctx->stream);
_cairo_output_stream_write (base85_stream, &len, sizeof (len));
@@ -1244,9 +1254,9 @@ _emit_image_surface (cairo_script_surface_t *surface,
if (unlikely (status))
return status;
} else {
- _cairo_output_stream_puts (surface->ctx->stream, "<~");
+ _cairo_output_stream_puts (ctx->stream, "<~");
- base85_stream = _cairo_base85_stream_create (surface->ctx->stream);
+ base85_stream = _cairo_base85_stream_create (ctx->stream);
status = _write_image_surface (base85_stream, clone);
status2 = _cairo_output_stream_destroy (base85_stream);
if (status == CAIRO_STATUS_SUCCESS)
@@ -1254,7 +1264,7 @@ _emit_image_surface (cairo_script_surface_t *surface,
if (unlikely (status))
return status;
}
- _cairo_output_stream_puts (surface->ctx->stream, "~> >> image ");
+ _cairo_output_stream_puts (ctx->stream, "~> >> image ");
cairo_surface_destroy (&clone->base);
}
@@ -1263,55 +1273,55 @@ _emit_image_surface (cairo_script_surface_t *surface,
if (unlikely (tag == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
- tag->ctx = surface->ctx;
+ tag->ctx = ctx;
tag->tag = image->base.unique_id;
tag->user_data = &image->base.user_data;
- cairo_list_add (&tag->link, &surface->ctx->defines);
+ cairo_list_add (&tag->link, &ctx->defines);
status = _cairo_user_data_array_set_data (&image->base.user_data,
- (cairo_user_data_key_t *) surface->ctx,
+ (cairo_user_data_key_t *) ctx,
tag, _undef);
if (unlikely (status)) {
free (tag);
return status;
}
- _cairo_output_stream_printf (surface->ctx->stream,
+ _cairo_output_stream_printf (ctx->stream,
"dup /s%u exch def ",
image->base.unique_id);
cairo_surface_get_mime_data (&image->base, CAIRO_MIME_TYPE_JPEG,
&mime_data, &mime_data_length);
if (mime_data != NULL) {
- _cairo_output_stream_printf (surface->ctx->stream,
+ _cairo_output_stream_printf (ctx->stream,
"\n (%s) <~",
CAIRO_MIME_TYPE_JPEG);
- base85_stream = _cairo_base85_stream_create (surface->ctx->stream);
+ base85_stream = _cairo_base85_stream_create (ctx->stream);
_cairo_output_stream_write (base85_stream, mime_data, mime_data_length);
status = _cairo_output_stream_destroy (base85_stream);
if (unlikely (status))
return status;
- _cairo_output_stream_puts (surface->ctx->stream, "~> set-mime-data\n");
+ _cairo_output_stream_puts (ctx->stream, "~> set-mime-data\n");
}
cairo_surface_get_mime_data (&image->base, CAIRO_MIME_TYPE_JP2,
&mime_data, &mime_data_length);
if (mime_data != NULL) {
- _cairo_output_stream_printf (surface->ctx->stream,
+ _cairo_output_stream_printf (ctx->stream,
"\n (%s) <~",
CAIRO_MIME_TYPE_JP2);
- base85_stream = _cairo_base85_stream_create (surface->ctx->stream);
+ base85_stream = _cairo_base85_stream_create (ctx->stream);
_cairo_output_stream_write (base85_stream, mime_data, mime_data_length);
status = _cairo_output_stream_destroy (base85_stream);
if (unlikely (status))
return status;
- _cairo_output_stream_puts (surface->ctx->stream, "~> set-mime-data\n");
+ _cairo_output_stream_puts (ctx->stream, "~> set-mime-data\n");
}
- _cairo_output_stream_puts (surface->ctx->stream, "pattern");
+ _cairo_output_stream_puts (ctx->stream, "pattern");
return CAIRO_STATUS_SUCCESS;
}
@@ -1321,17 +1331,22 @@ _emit_image_surface_pattern (cairo_script_surface_t *surface,
const cairo_pattern_t *pattern)
{
cairo_surface_pattern_t *surface_pattern;
+ cairo_surface_t *snapshot;
cairo_image_surface_t *image;
cairo_status_t status;
+ void *extra;
/* XXX keeping a copy is nasty, but we want to hook into the surface's
* lifetime. Using a snapshot is a convenient method.
*/
surface_pattern = (cairo_surface_pattern_t *) pattern;
- image = (cairo_image_surface_t *)
- _cairo_surface_snapshot (surface_pattern->surface);
- status = _emit_image_surface (surface, image);
- cairo_surface_destroy (&image->base);
+ snapshot = _cairo_surface_snapshot (surface_pattern->surface);
+ status = _cairo_surface_acquire_source_image (snapshot, &image, &extra);
+ if (likely (status == CAIRO_STATUS_SUCCESS)) {
+ status = _emit_image_surface (surface, image);
+ _cairo_surface_release_source_image (snapshot, image, extra);
+ }
+ cairo_surface_destroy (snapshot);
return status;
}
@@ -1360,6 +1375,7 @@ static cairo_status_t
_emit_pattern (cairo_script_surface_t *surface,
const cairo_pattern_t *pattern)
{
+ cairo_script_context_t *ctx = to_context (surface);
cairo_status_t status;
cairo_bool_t is_default_extend;
cairo_bool_t need_newline = TRUE;
@@ -1391,11 +1407,11 @@ _emit_pattern (cairo_script_surface_t *surface,
if (! _cairo_matrix_is_identity (&pattern->matrix)) {
if (need_newline) {
- _cairo_output_stream_puts (surface->ctx->stream, "\n ");
+ _cairo_output_stream_puts (ctx->stream, "\n ");
need_newline = FALSE;
}
- _cairo_output_stream_printf (surface->ctx->stream,
+ _cairo_output_stream_printf (ctx->stream,
" [%f %f %f %f %f %f] set-matrix\n ",
pattern->matrix.xx, pattern->matrix.yx,
pattern->matrix.xy, pattern->matrix.yy,
@@ -1405,27 +1421,27 @@ _emit_pattern (cairo_script_surface_t *surface,
/* XXX need to discriminate the user explicitly setting the default */
if (pattern->filter != CAIRO_FILTER_DEFAULT) {
if (need_newline) {
- _cairo_output_stream_puts (surface->ctx->stream, "\n ");
+ _cairo_output_stream_puts (ctx->stream, "\n ");
need_newline = FALSE;
}
- _cairo_output_stream_printf (surface->ctx->stream,
+ _cairo_output_stream_printf (ctx->stream,
" //%s set-filter\n ",
_filter_to_string (pattern->filter));
}
if (! is_default_extend ){
if (need_newline) {
- _cairo_output_stream_puts (surface->ctx->stream, "\n ");
+ _cairo_output_stream_puts (ctx->stream, "\n ");
need_newline = FALSE;
}
- _cairo_output_stream_printf (surface->ctx->stream,
+ _cairo_output_stream_printf (ctx->stream,
" //%s set-extend\n ",
_extend_to_string (pattern->extend));
}
if (need_newline)
- _cairo_output_stream_puts (surface->ctx->stream, "\n ");
+ _cairo_output_stream_puts (ctx->stream, "\n ");
return CAIRO_STATUS_SUCCESS;
}
@@ -1439,7 +1455,7 @@ _emit_identity (cairo_script_surface_t *surface,
if (_cairo_matrix_is_identity (&surface->cr.current_ctm))
return CAIRO_STATUS_SUCCESS;
- _cairo_output_stream_puts (surface->ctx->stream,
+ _cairo_output_stream_puts (to_context (surface)->stream,
"identity set-matrix\n");
*matrix_updated = TRUE;
@@ -1480,7 +1496,7 @@ _emit_source (cairo_script_surface_t *surface,
if (unlikely (status))
return status;
- _cairo_output_stream_puts (surface->ctx->stream,
+ _cairo_output_stream_puts (to_context (surface)->stream,
" set-source\n");
return CAIRO_STATUS_SUCCESS;
}
@@ -1540,6 +1556,7 @@ static cairo_status_t
_emit_path (cairo_script_surface_t *surface,
cairo_path_fixed_t *path)
{
+ cairo_script_context_t *ctx = to_context (surface);
cairo_box_t box;
cairo_status_t status;
@@ -1551,7 +1568,7 @@ _emit_path (cairo_script_surface_t *surface,
_cairo_path_fixed_fini (&surface->cr.current_path);
- _cairo_output_stream_puts (surface->ctx->stream, "n");
+ _cairo_output_stream_puts (ctx->stream, "n");
if (path == NULL) {
_cairo_path_fixed_init (&surface->cr.current_path);
@@ -1565,7 +1582,7 @@ _emit_path (cairo_script_surface_t *surface,
if (unlikely (status))
return status;
- _cairo_output_stream_printf (surface->ctx->stream,
+ _cairo_output_stream_printf (ctx->stream,
" %f %f %f %f rectangle",
x1, y1, x2 - x1, y2 - y1);
} else {
@@ -1581,12 +1598,12 @@ _emit_path (cairo_script_surface_t *surface,
_path_line_to,
_path_curve_to,
_path_close,
- surface->ctx->stream);
+ ctx->stream);
if (unlikely (status))
return status;
}
- _cairo_output_stream_puts (surface->ctx->stream, "\n");
+ _cairo_output_stream_puts (ctx->stream, "\n");
return CAIRO_STATUS_SUCCESS;
}
@@ -1605,6 +1622,7 @@ _emit_scaling_matrix (cairo_script_surface_t *surface,
const cairo_matrix_t *ctm,
cairo_bool_t *matrix_updated)
{
+ cairo_script_context_t *ctx = to_context (surface);
cairo_bool_t was_identity;
assert (target_is_active (surface));
@@ -1619,17 +1637,17 @@ _emit_scaling_matrix (cairo_script_surface_t *surface,
surface->cr.current_ctm.y0 = 0.;
if (_cairo_matrix_is_identity (&surface->cr.current_ctm)) {
- _cairo_output_stream_puts (surface->ctx->stream,
+ _cairo_output_stream_puts (ctx->stream,
"identity set-matrix\n");
} else if (was_identity && fabs (ctm->yx) < 1e-5 && fabs (ctm->xy) < 1e-5) {
- _cairo_output_stream_printf (surface->ctx->stream,
- "%f %f scale\n",
- ctm->xx, ctm->yy);
+ _cairo_output_stream_printf (ctx->stream,
+ "%f %f scale\n",
+ ctm->xx, ctm->yy);
} else {
- _cairo_output_stream_printf (surface->ctx->stream,
- "[%f %f %f %f 0 0] set-matrix\n",
- ctm->xx, ctm->yx,
- ctm->xy, ctm->yy);
+ _cairo_output_stream_printf (ctx->stream,
+ "[%f %f %f %f 0 0] set-matrix\n",
+ ctm->xx, ctm->yx,
+ ctm->xy, ctm->yy);
}
return CAIRO_STATUS_SUCCESS;
@@ -1639,6 +1657,7 @@ static cairo_status_t
_emit_font_matrix (cairo_script_surface_t *surface,
const cairo_matrix_t *font_matrix)
{
+ cairo_script_context_t *ctx = to_context (surface);
assert (target_is_active (surface));
if (memcmp (&surface->cr.current_font_matrix,
@@ -1651,14 +1670,14 @@ _emit_font_matrix (cairo_script_surface_t *surface,
surface->cr.current_font_matrix = *font_matrix;
if (_cairo_matrix_is_identity (font_matrix)) {
- _cairo_output_stream_puts (surface->ctx->stream,
+ _cairo_output_stream_puts (ctx->stream,
"identity set-font-matrix\n");
} else {
- _cairo_output_stream_printf (surface->ctx->stream,
- "[%f %f %f %f %f %f] set-font-matrix\n",
- font_matrix->xx, font_matrix->yx,
- font_matrix->xy, font_matrix->yy,
- font_matrix->x0, font_matrix->y0);
+ _cairo_output_stream_printf (ctx->stream,
+ "[%f %f %f %f %f %f] set-font-matrix\n",
+ font_matrix->xx, font_matrix->yx,
+ font_matrix->xy, font_matrix->yy,
+ font_matrix->x0, font_matrix->y0);
}
return CAIRO_STATUS_SUCCESS;
@@ -1675,7 +1694,7 @@ _cairo_script_surface_create_similar (void *abstract_surface,
cairo_script_context_t *ctx;
cairo_status_t status;
- ctx = other->ctx;
+ ctx = to_context (other);
if (! other->emitted) {
status = _emit_surface (other);
@@ -1716,15 +1735,12 @@ _cairo_script_surface_create_similar (void *abstract_surface,
return &surface->base;
}
-static cairo_status_t
-_context_destroy (cairo_script_context_t *ctx)
+static void
+_device_destroy (void *abstract_device)
{
+ cairo_script_context_t *ctx = abstract_device;
cairo_status_t status;
- assert (ctx->ref > 0);
- if (--ctx->ref)
- return _cairo_output_stream_flush (ctx->stream);
-
while (! cairo_list_is_empty (&ctx->fonts)) {
cairo_script_surface_font_private_t *font;
@@ -1748,8 +1764,6 @@ _context_destroy (cairo_script_context_t *ctx)
status = _cairo_output_stream_destroy (ctx->stream);
free (ctx);
-
- return status;
}
static cairo_status_t
@@ -1785,6 +1799,7 @@ static cairo_status_t
_cairo_script_surface_finish (void *abstract_surface)
{
cairo_script_surface_t *surface = abstract_surface;
+ cairo_script_context_t *ctx = to_context (surface);
cairo_status_t status = CAIRO_STATUS_SUCCESS, status2;
_cairo_surface_wrapper_fini (&surface->wrapper);
@@ -1801,17 +1816,17 @@ _cairo_script_surface_finish (void *abstract_surface)
assert (! surface->active);
if (! cairo_list_is_empty (&surface->operand.link)) {
- if (! surface->ctx->active) {
+ if (! ctx->active) {
if (target_is_active (surface)) {
- _cairo_output_stream_printf (surface->ctx->stream,
+ _cairo_output_stream_printf (ctx->stream,
"pop\n");
} else {
int depth = target_depth (surface);
if (depth == 1) {
- _cairo_output_stream_printf (surface->ctx->stream,
+ _cairo_output_stream_printf (ctx->stream,
"exch pop\n");
} else {
- _cairo_output_stream_printf (surface->ctx->stream,
+ _cairo_output_stream_printf (ctx->stream,
"%d -1 roll pop\n",
depth);
}
@@ -1828,22 +1843,18 @@ _cairo_script_surface_finish (void *abstract_surface)
link->operand.type = DEFERRED;
cairo_list_swap (&link->operand.link,
&surface->operand.link);
- cairo_list_add (&link->link, &surface->ctx->deferred);
+ cairo_list_add (&link->link, &ctx->deferred);
}
}
}
if (surface->defined) {
- _cairo_output_stream_printf (surface->ctx->stream,
+ _cairo_output_stream_printf (ctx->stream,
"/s%u undef\n",
surface->base.unique_id);
}
}
- status2 = _context_destroy (surface->ctx);
- if (status == CAIRO_STATUS_SUCCESS)
- status = status2;
-
return status;
}
@@ -1857,7 +1868,7 @@ _cairo_script_surface_copy_page (void *abstract_surface)
if (unlikely (status))
return status;
- _cairo_output_stream_puts (surface->ctx->stream, "copy-page\n");
+ _cairo_output_stream_puts (to_context (surface)->stream, "copy-page\n");
return CAIRO_STATUS_SUCCESS;
}
@@ -1872,7 +1883,7 @@ _cairo_script_surface_show_page (void *abstract_surface)
if (unlikely (status))
return status;
- _cairo_output_stream_puts (surface->ctx->stream, "show-page\n");
+ _cairo_output_stream_puts (to_context (surface)->stream, "show-page\n");
return CAIRO_STATUS_SUCCESS;
}
@@ -1887,6 +1898,7 @@ _cairo_script_surface_clipper_intersect_clip_path (cairo_surface_clipper_t *clip
cairo_script_surface_t *surface = cairo_container_of (clipper,
cairo_script_surface_t,
clipper);
+ cairo_script_context_t *ctx = to_context (surface);
cairo_bool_t matrix_updated = FALSE;
cairo_status_t status;
cairo_box_t box;
@@ -1897,7 +1909,7 @@ _cairo_script_surface_clipper_intersect_clip_path (cairo_surface_clipper_t *clip
if (path == NULL) {
if (surface->cr.has_clip) {
- _cairo_output_stream_puts (surface->ctx->stream, "reset-clip\n");
+ _cairo_output_stream_puts (ctx->stream, "reset-clip\n");
surface->cr.has_clip = FALSE;
}
return CAIRO_STATUS_SUCCESS;
@@ -1939,7 +1951,7 @@ _cairo_script_surface_clipper_intersect_clip_path (cairo_surface_clipper_t *clip
if (unlikely (status))
return status;
- _cairo_output_stream_puts (surface->ctx->stream, "clip+\n");
+ _cairo_output_stream_puts (ctx->stream, "clip+\n");
surface->cr.has_clip = TRUE;
return CAIRO_STATUS_SUCCESS;
@@ -1949,13 +1961,13 @@ static void
active (cairo_script_surface_t *surface)
{
if (surface->active++ == 0)
- surface->ctx->active++;
+ to_context (surface)->active++;
}
static void
inactive (cairo_script_surface_t *surface)
{
- cairo_script_context_t *ctx = surface->ctx;
+ cairo_script_context_t *ctx = to_context (surface);
cairo_list_t sorted;
if (--surface->active)
@@ -2065,7 +2077,7 @@ _cairo_script_surface_paint (void *abstract_surface,
if (unlikely (status))
return status;
- _cairo_output_stream_puts (surface->ctx->stream,
+ _cairo_output_stream_puts (to_context (surface)->stream,
"paint\n");
surface->is_clear = op == CAIRO_OPERATOR_CLEAR && clip == NULL;
@@ -2115,7 +2127,7 @@ _cairo_script_surface_mask (void *abstract_surface,
return status;
if (_cairo_pattern_equal (source, mask)) {
- _cairo_output_stream_puts (surface->ctx->stream, "/source get");
+ _cairo_output_stream_puts (to_context (surface)->stream, "/source get");
} else {
status = _emit_pattern (surface, mask);
if (unlikely (status))
@@ -2124,7 +2136,7 @@ _cairo_script_surface_mask (void *abstract_surface,
assert (surface->cr.current_operator == op);
- _cairo_output_stream_puts (surface->ctx->stream,
+ _cairo_output_stream_puts (to_context (surface)->stream,
" mask\n");
surface->is_clear = FALSE;
@@ -2145,9 +2157,9 @@ _cairo_script_surface_stroke (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_path_fixed_t *path,
- const cairo_stroke_style_t *style,
- const cairo_matrix_t *ctm,
- const cairo_matrix_t *ctm_inverse,
+ const cairo_stroke_style_t *style,
+ const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
cairo_clip_t *clip)
@@ -2216,7 +2228,7 @@ _cairo_script_surface_stroke (void *abstract_surface,
if (unlikely (status))
return status;
- _cairo_output_stream_puts (surface->ctx->stream, "stroke+\n");
+ _cairo_output_stream_puts (to_context (surface)->stream, "stroke+\n");
surface->is_clear = FALSE;
@@ -2299,7 +2311,7 @@ _cairo_script_surface_fill (void *abstract_surface,
if (unlikely (status))
return status;
- _cairo_output_stream_puts (surface->ctx->stream, "fill+\n");
+ _cairo_output_stream_puts (to_context (surface)->stream, "fill+\n");
surface->is_clear = FALSE;
@@ -2374,16 +2386,18 @@ static cairo_status_t
_emit_font_options (cairo_script_surface_t *surface,
cairo_font_options_t *font_options)
{
+ cairo_script_context_t *ctx = to_context (surface);
+
if (cairo_font_options_equal (&surface->cr.current_font_options,
font_options))
{
return CAIRO_STATUS_SUCCESS;
}
- _cairo_output_stream_printf (surface->ctx->stream, "<<");
+ _cairo_output_stream_printf (ctx->stream, "<<");
if (font_options->antialias != surface->cr.current_font_options.antialias) {
- _cairo_output_stream_printf (surface->ctx->stream,
+ _cairo_output_stream_printf (ctx->stream,
" /antialias //%s",
_antialias_to_string (font_options->antialias));
}
@@ -2391,7 +2405,7 @@ _emit_font_options (cairo_script_surface_t *surface,
if (font_options->subpixel_order !=
surface->cr.current_font_options.subpixel_order)
{
- _cairo_output_stream_printf (surface->ctx->stream,
+ _cairo_output_stream_printf (ctx->stream,
" /subpixel-order //%s",
_subpixel_order_to_string (font_options->subpixel_order));
}
@@ -2399,7 +2413,7 @@ _emit_font_options (cairo_script_surface_t *surface,
if (font_options->hint_style !=
surface->cr.current_font_options.hint_style)
{
- _cairo_output_stream_printf (surface->ctx->stream,
+ _cairo_output_stream_printf (ctx->stream,
" /hint-style //%s",
_hint_style_to_string (font_options->hint_style));
}
@@ -2407,12 +2421,12 @@ _emit_font_options (cairo_script_surface_t *surface,
if (font_options->hint_metrics !=
surface->cr.current_font_options.hint_metrics)
{
- _cairo_output_stream_printf (surface->ctx->stream,
+ _cairo_output_stream_printf (ctx->stream,
" /hint-metrics //%s",
_hint_metrics_to_string (font_options->hint_metrics));
}
- _cairo_output_stream_printf (surface->ctx->stream,
+ _cairo_output_stream_printf (ctx->stream,
" >> set-font-options\n");
surface->cr.current_font_options = *font_options;
@@ -2443,6 +2457,7 @@ static cairo_status_t
_emit_type42_font (cairo_script_surface_t *surface,
cairo_scaled_font_t *scaled_font)
{
+ cairo_script_context_t *ctx = to_context (surface);
const cairo_scaled_font_backend_t *backend;
cairo_script_surface_font_private_t *font_private;
cairo_output_stream_t *base85_stream;
@@ -2473,7 +2488,7 @@ _emit_type42_font (cairo_script_surface_t *surface,
}
load_flags = _cairo_ft_scaled_font_get_load_flags (scaled_font);
- _cairo_output_stream_printf (surface->ctx->stream,
+ _cairo_output_stream_printf (ctx->stream,
"<< "
"/type 42 "
"/index 0 "
@@ -2481,7 +2496,7 @@ _emit_type42_font (cairo_script_surface_t *surface,
"/source <|",
load_flags);
- base85_stream = _cairo_base85_stream_create (surface->ctx->stream);
+ base85_stream = _cairo_base85_stream_create (ctx->stream);
len = size;
_cairo_output_stream_write (base85_stream, &len, sizeof (len));
@@ -2499,7 +2514,7 @@ _emit_type42_font (cairo_script_surface_t *surface,
status = status2;
font_private = scaled_font->surface_private;
- _cairo_output_stream_printf (surface->ctx->stream,
+ _cairo_output_stream_printf (ctx->stream,
"~> >> font dup /f%lu exch def set-font-face",
font_private->id);
@@ -2510,6 +2525,7 @@ static cairo_status_t
_emit_scaled_font_init (cairo_script_surface_t *surface,
cairo_scaled_font_t *scaled_font)
{
+ cairo_script_context_t *ctx = to_context (surface);
cairo_script_surface_font_private_t *font_private;
cairo_status_t status;
@@ -2517,14 +2533,14 @@ _emit_scaled_font_init (cairo_script_surface_t *surface,
if (unlikely (font_private == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
- font_private->ctx = surface->ctx;
+ font_private->ctx = ctx;
font_private->parent = scaled_font;
font_private->subset_glyph_index = 0;
font_private->has_sfnt = TRUE;
- cairo_list_add (&font_private->link, &surface->ctx->fonts);
+ cairo_list_add (&font_private->link, &ctx->fonts);
- status = _bitmap_next_id (&surface->ctx->font_id,
+ status = _bitmap_next_id (&ctx->font_id,
&font_private->id);
if (unlikely (status)) {
free (font_private);
@@ -2543,7 +2559,7 @@ _emit_scaled_font_init (cairo_script_surface_t *surface,
return status;
font_private->has_sfnt = FALSE;
- _cairo_output_stream_printf (surface->ctx->stream,
+ _cairo_output_stream_printf (ctx->stream,
"dict\n"
" /type 3 set\n"
" /metrics [%f %f %f %f %f] set\n"
@@ -2563,6 +2579,7 @@ static cairo_status_t
_emit_scaled_font (cairo_script_surface_t *surface,
cairo_scaled_font_t *scaled_font)
{
+ cairo_script_context_t *ctx = to_context (surface);
cairo_matrix_t matrix;
cairo_font_options_t options;
cairo_bool_t matrix_updated = FALSE;
@@ -2605,11 +2622,11 @@ _emit_scaled_font (cairo_script_surface_t *surface,
assert (font_private != NULL);
assert (target_is_active (surface));
- _cairo_output_stream_printf (surface->ctx->stream,
+ _cairo_output_stream_printf (ctx->stream,
" /scaled-font get /sf%lu exch def\n",
font_private->id);
} else {
- _cairo_output_stream_printf (surface->ctx->stream,
+ _cairo_output_stream_printf (ctx->stream,
"sf%lu set-scaled-font\n",
font_private->id);
}
@@ -2622,6 +2639,7 @@ _emit_scaled_glyph_vector (cairo_script_surface_t *surface,
cairo_scaled_font_t *scaled_font,
cairo_scaled_glyph_t *scaled_glyph)
{
+ cairo_script_context_t *ctx = to_context (surface);
cairo_script_surface_font_private_t *font_private;
cairo_script_implicit_context_t old_cr;
cairo_status_t status;
@@ -2631,7 +2649,7 @@ _emit_scaled_glyph_vector (cairo_script_surface_t *surface,
index = ++font_private->subset_glyph_index;
scaled_glyph->surface_private = (void *) index;
- _cairo_output_stream_printf (surface->ctx->stream,
+ _cairo_output_stream_printf (ctx->stream,
"%lu <<\n"
" /metrics [%f %f %f %f %f %f]\n"
" /render {\n",
@@ -2644,7 +2662,7 @@ _emit_scaled_glyph_vector (cairo_script_surface_t *surface,
scaled_glyph->fs_metrics.y_advance);
if (! _cairo_matrix_is_identity (&scaled_font->scale_inverse)) {
- _cairo_output_stream_printf (surface->ctx->stream,
+ _cairo_output_stream_printf (ctx->stream,
"[%f %f %f %f %f %f] transform\n",
scaled_font->scale_inverse.xx,
scaled_font->scale_inverse.yx,
@@ -2660,7 +2678,7 @@ _emit_scaled_glyph_vector (cairo_script_surface_t *surface,
&surface->base);
surface->cr = old_cr;
- _cairo_output_stream_puts (surface->ctx->stream, "} >> set\n");
+ _cairo_output_stream_puts (ctx->stream, "} >> set\n");
return status;
}
@@ -2670,6 +2688,7 @@ _emit_scaled_glyph_bitmap (cairo_script_surface_t *surface,
cairo_scaled_font_t *scaled_font,
cairo_scaled_glyph_t *scaled_glyph)
{
+ cairo_script_context_t *ctx = to_context (surface);
cairo_script_surface_font_private_t *font_private;
cairo_status_t status;
unsigned long index;
@@ -2678,7 +2697,7 @@ _emit_scaled_glyph_bitmap (cairo_script_surface_t *surface,
index = ++font_private->subset_glyph_index;
scaled_glyph->surface_private = (void *) index;
- _cairo_output_stream_printf (surface->ctx->stream,
+ _cairo_output_stream_printf (ctx->stream,
"%lu <<\n"
" /metrics [%f %f %f %f %f %f]\n"
" /render {\n"
@@ -2698,7 +2717,7 @@ _emit_scaled_glyph_bitmap (cairo_script_surface_t *surface,
return status;
if (! _cairo_matrix_is_identity (&scaled_font->font_matrix)) {
- _cairo_output_stream_printf (surface->ctx->stream,
+ _cairo_output_stream_printf (ctx->stream,
"\n [%f %f %f %f %f %f] set-matrix\n",
scaled_font->font_matrix.xx,
scaled_font->font_matrix.yx,
@@ -2707,7 +2726,7 @@ _emit_scaled_glyph_bitmap (cairo_script_surface_t *surface,
scaled_font->font_matrix.x0,
scaled_font->font_matrix.y0);
}
- _cairo_output_stream_puts (surface->ctx->stream,
+ _cairo_output_stream_puts (ctx->stream,
"mask\n} >> set\n");
return CAIRO_STATUS_SUCCESS;
@@ -2723,7 +2742,7 @@ _emit_scaled_glyph_prologue (cairo_script_surface_t *surface,
font_private = scaled_font->surface_private;
- _cairo_output_stream_printf (surface->ctx->stream,
+ _cairo_output_stream_printf (to_context (surface)->stream,
"f%lu /glyphs get\n",
font_private->id);
@@ -2815,7 +2834,7 @@ _emit_scaled_glyphs (cairo_script_surface_t *surface,
_cairo_scaled_font_thaw_cache (scaled_font);
if (have_glyph_prologue) {
- _cairo_output_stream_puts (surface->ctx->stream, "pop pop\n");
+ _cairo_output_stream_puts (to_context (surface)->stream, "pop pop\n");
}
return status;
@@ -2825,10 +2844,11 @@ static void
_emit_string_literal (cairo_script_surface_t *surface,
const char *utf8, int len)
{
+ cairo_script_context_t *ctx = to_context (surface);
char c;
const char *end;
- _cairo_output_stream_puts (surface->ctx->stream, "(");
+ _cairo_output_stream_puts (ctx->stream, "(");
if (utf8 == NULL) {
end = utf8;
@@ -2859,11 +2879,11 @@ _emit_string_literal (cairo_script_surface_t *surface,
case '(':
case ')':
ESCAPED_CHAR:
- _cairo_output_stream_printf (surface->ctx->stream, "\\%c", c);
+ _cairo_output_stream_printf (ctx->stream, "\\%c", c);
break;
default:
if (isprint (c) || isspace (c)) {
- _cairo_output_stream_printf (surface->ctx->stream, "%c", c);
+ _cairo_output_stream_printf (ctx->stream, "%c", c);
} else {
int octal = 0;
while (c) {
@@ -2871,13 +2891,13 @@ ESCAPED_CHAR:
octal += c&7;
c /= 8;
}
- _cairo_output_stream_printf (surface->ctx->stream,
+ _cairo_output_stream_printf (ctx->stream,
"\\%03d", octal);
}
break;
}
}
- _cairo_output_stream_puts (surface->ctx->stream, ")");
+ _cairo_output_stream_puts (ctx->stream, ")");
}
static cairo_int_status_t
@@ -2895,6 +2915,7 @@ _cairo_script_surface_show_text_glyphs (void *abstract_surface,
cairo_clip_t *clip)
{
cairo_script_surface_t *surface = abstract_surface;
+ cairo_script_context_t *ctx = to_context (surface);
cairo_script_surface_font_private_t *font_private;
cairo_scaled_glyph_t *scaled_glyph;
cairo_matrix_t matrix;
@@ -2939,7 +2960,7 @@ _cairo_script_surface_show_text_glyphs (void *abstract_surface,
if (utf8 != NULL && clusters != NULL) {
_emit_string_literal (surface, utf8, utf8_len);
- _cairo_output_stream_puts (surface->ctx->stream, " ");
+ _cairo_output_stream_puts (ctx->stream, " ");
}
matrix = surface->cr.current_ctm;
@@ -2955,7 +2976,7 @@ _cairo_script_surface_show_text_glyphs (void *abstract_surface,
_cairo_scaled_font_freeze_cache (scaled_font);
font_private = scaled_font->surface_private;
- _cairo_output_stream_printf (surface->ctx->stream,
+ _cairo_output_stream_printf (ctx->stream,
"[%f %f ",
ix, iy);
@@ -2979,10 +3000,10 @@ _cairo_script_surface_show_text_glyphs (void *abstract_surface,
}
if (n == num_glyphs) {
- _cairo_output_stream_puts (surface->ctx->stream, "<~");
- base85_stream = _cairo_base85_stream_create (surface->ctx->stream);
+ _cairo_output_stream_puts (ctx->stream, "<~");
+ base85_stream = _cairo_base85_stream_create (ctx->stream);
} else
- _cairo_output_stream_puts (surface->ctx->stream, "[");
+ _cairo_output_stream_puts (ctx->stream, "[");
for (n = 0; n < num_glyphs; n++) {
double dx, dy;
@@ -3003,11 +3024,11 @@ _cairo_script_surface_show_text_glyphs (void *abstract_surface,
break;
}
- _cairo_output_stream_printf (surface->ctx->stream,
+ _cairo_output_stream_printf (ctx->stream,
"~> %f <~", glyphs[n].x - x);
- base85_stream = _cairo_base85_stream_create (surface->ctx->stream);
+ base85_stream = _cairo_base85_stream_create (ctx->stream);
} else {
- _cairo_output_stream_printf (surface->ctx->stream,
+ _cairo_output_stream_printf (ctx->stream,
" ] %f [ ", glyphs[n].x - x);
}
@@ -3025,12 +3046,12 @@ _cairo_script_surface_show_text_glyphs (void *abstract_surface,
break;
}
- _cairo_output_stream_printf (surface->ctx->stream,
+ _cairo_output_stream_printf (ctx->stream,
"~> %f %f <~",
ix, iy);
- base85_stream = _cairo_base85_stream_create (surface->ctx->stream);
+ base85_stream = _cairo_base85_stream_create (ctx->stream);
} else {
- _cairo_output_stream_printf (surface->ctx->stream,
+ _cairo_output_stream_printf (ctx->stream,
" ] %f %f [ ",
ix, iy);
}
@@ -3047,10 +3068,10 @@ _cairo_script_surface_show_text_glyphs (void *abstract_surface,
_cairo_output_stream_write (base85_stream, &c, 1);
} else {
if (font_private->has_sfnt)
- _cairo_output_stream_printf (surface->ctx->stream, " %lu",
+ _cairo_output_stream_printf (ctx->stream, " %lu",
glyphs[n].index);
else
- _cairo_output_stream_printf (surface->ctx->stream, " %lu",
+ _cairo_output_stream_printf (ctx->stream, " %lu",
(long unsigned) scaled_glyph->surface_private);
}
@@ -3069,9 +3090,9 @@ _cairo_script_surface_show_text_glyphs (void *abstract_surface,
if (status == CAIRO_STATUS_SUCCESS)
status = status2;
- _cairo_output_stream_printf (surface->ctx->stream, "~>");
+ _cairo_output_stream_printf (ctx->stream, "~>");
} else {
- _cairo_output_stream_puts (surface->ctx->stream, " ]");
+ _cairo_output_stream_puts (ctx->stream, " ]");
}
if (unlikely (status))
return status;
@@ -3086,19 +3107,19 @@ _cairo_script_surface_show_text_glyphs (void *abstract_surface,
}
if (n < num_clusters) {
- _cairo_output_stream_puts (surface->ctx->stream, "] [ ");
+ _cairo_output_stream_puts (ctx->stream, "] [ ");
for (n = 0; n < num_clusters; n++) {
- _cairo_output_stream_printf (surface->ctx->stream,
+ _cairo_output_stream_printf (ctx->stream,
"%d %d ",
clusters[n].num_bytes,
clusters[n].num_glyphs);
}
- _cairo_output_stream_puts (surface->ctx->stream, "]");
+ _cairo_output_stream_puts (ctx->stream, "]");
}
else
{
- _cairo_output_stream_puts (surface->ctx->stream, "] <~");
- base85_stream = _cairo_base85_stream_create (surface->ctx->stream);
+ _cairo_output_stream_puts (ctx->stream, "] <~");
+ base85_stream = _cairo_base85_stream_create (ctx->stream);
for (n = 0; n < num_clusters; n++) {
uint8_t c[2];
c[0] = clusters[n].num_bytes;
@@ -3109,14 +3130,14 @@ _cairo_script_surface_show_text_glyphs (void *abstract_surface,
if (unlikely (status))
return status;
- _cairo_output_stream_puts (surface->ctx->stream, "~>");
+ _cairo_output_stream_puts (ctx->stream, "~>");
}
- _cairo_output_stream_printf (surface->ctx->stream,
+ _cairo_output_stream_printf (ctx->stream,
" //%s show-text-glyphs\n",
_direction_to_string (backward));
} else {
- _cairo_output_stream_puts (surface->ctx->stream,
+ _cairo_output_stream_puts (ctx->stream,
"] show-glyphs\n");
}
@@ -3257,7 +3278,7 @@ _cairo_script_surface_create_internal (cairo_script_context_t *ctx,
_cairo_surface_init (&surface->base,
&_cairo_script_surface_backend,
- NULL, /* device */
+ &ctx->base,
content);
_cairo_surface_wrapper_init (&surface->wrapper, passthrough);
@@ -3265,9 +3286,6 @@ _cairo_script_surface_create_internal (cairo_script_context_t *ctx,
_cairo_surface_clipper_init (&surface->clipper,
_cairo_script_surface_clipper_intersect_clip_path);
- surface->ctx = ctx;
- ctx->ref++;
-
surface->width = width;
surface->height = height;
@@ -3283,25 +3301,28 @@ _cairo_script_surface_create_internal (cairo_script_context_t *ctx,
return surface;
}
-static const cairo_script_context_t _nil_context = {
- CAIRO_STATUS_NO_MEMORY,
- -1
+static const cairo_device_backend_t _cairo_script_device_backend = {
+ CAIRO_DEVICE_TYPE_SCRIPT,
+
+ NULL, NULL, /* lock, unlock */
+
+ NULL, /* flush */
+ NULL, /* finish */
+ _device_destroy
};
-static cairo_script_context_t *
+static cairo_device_t *
_cairo_script_context_create_internal (cairo_output_stream_t *stream)
{
cairo_script_context_t *ctx;
ctx = malloc (sizeof (cairo_script_context_t));
- if (unlikely (ctx == NULL)) {
- _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
- return (cairo_script_context_t *) &_nil_context;
- }
+ if (unlikely (ctx == NULL))
+ return _cairo_device_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
memset (ctx, 0, sizeof (cairo_script_context_t));
- ctx->status = CAIRO_STATUS_SUCCESS;
- ctx->ref = 1;
+
+ _cairo_device_init (&ctx->base, &_cairo_script_device_backend);
cairo_list_init (&ctx->operands);
cairo_list_init (&ctx->deferred);
@@ -3313,39 +3334,43 @@ _cairo_script_context_create_internal (cairo_output_stream_t *stream)
_cairo_output_stream_puts (ctx->stream, "%!CairoScript\n");
- return ctx;
+ return &ctx->base;
}
-cairo_script_context_t *
-cairo_script_context_create (const char *filename)
+cairo_device_t *
+cairo_script_create (const char *filename)
{
cairo_output_stream_t *stream;
+ cairo_status_t status;
stream = _cairo_output_stream_create_for_filename (filename);
- if (_cairo_output_stream_get_status (stream))
- return (cairo_script_context_t *) &_nil_context;
+ if ((status = _cairo_output_stream_get_status (stream)))
+ return _cairo_device_create_in_error (status);
return _cairo_script_context_create_internal (stream);
}
-cairo_script_context_t *
-cairo_script_context_create_for_stream (cairo_write_func_t write_func,
- void *closure)
+cairo_device_t *
+cairo_script_create_for_stream (cairo_write_func_t write_func,
+ void *closure)
{
cairo_output_stream_t *stream;
+ cairo_status_t status;
stream = _cairo_output_stream_create (write_func, NULL, closure);
- if (_cairo_output_stream_get_status (stream))
- return (cairo_script_context_t *) &_nil_context;
+ if ((status = _cairo_output_stream_get_status (stream)))
+ return _cairo_device_create_in_error (status);
return _cairo_script_context_create_internal (stream);
}
void
-cairo_script_context_write_comment (cairo_script_context_t *context,
- const char *comment,
- int len)
+cairo_script_write_comment (cairo_device_t *device,
+ const char *comment,
+ int len)
{
+ cairo_script_context_t *context = (cairo_script_context_t *) device;
+
if (len < 0)
len = strlen (comment);
@@ -3355,43 +3380,59 @@ cairo_script_context_write_comment (cairo_script_context_t *context,
}
void
-cairo_script_context_set_mode (cairo_script_context_t *context,
- cairo_script_mode_t mode)
+cairo_script_set_mode (cairo_device_t *device,
+ cairo_script_mode_t mode)
{
+ cairo_script_context_t *context = (cairo_script_context_t *) device;
+
context->mode = mode;
}
cairo_script_mode_t
-cairo_script_context_get_mode (cairo_script_context_t *context)
+cairo_script_get_mode (cairo_device_t *device)
{
+ cairo_script_context_t *context = (cairo_script_context_t *) device;
+
return context->mode;
}
cairo_surface_t *
-cairo_script_surface_create (cairo_script_context_t *context,
+cairo_script_surface_create (cairo_device_t *device,
cairo_content_t content,
double width,
double height)
{
- return &_cairo_script_surface_create_internal (context,
+ if (unlikely (device->backend->type != CAIRO_DEVICE_TYPE_SCRIPT))
+ return _cairo_surface_create_in_error (CAIRO_STATUS_DEVICE_TYPE_MISMATCH);
+
+ if (unlikely (device->status))
+ return _cairo_surface_create_in_error (device->status);
+
+ return &_cairo_script_surface_create_internal ((cairo_script_context_t *) device,
content,
width, height,
NULL)->base;
}
cairo_surface_t *
-cairo_script_surface_create_for_target (cairo_script_context_t *context,
+cairo_script_surface_create_for_target (cairo_device_t *device,
cairo_surface_t *target)
{
cairo_rectangle_int_t extents;
+ if (unlikely (device->backend->type != CAIRO_DEVICE_TYPE_SCRIPT))
+ return _cairo_surface_create_in_error (CAIRO_STATUS_DEVICE_TYPE_MISMATCH);
+
+ if (unlikely (device->status))
+ return _cairo_surface_create_in_error (device->status);
+
if (unlikely (target->status))
return _cairo_surface_create_in_error (target->status);
if (! _cairo_surface_get_extents (target, &extents))
extents.width = extents.height = -1;
- return &_cairo_script_surface_create_internal (context,
+ return &_cairo_script_surface_create_internal ((cairo_script_context_t *) device,
target->content,
extents.width,
extents.height,
@@ -3399,7 +3440,7 @@ cairo_script_surface_create_for_target (cairo_script_context_t *context,
}
cairo_status_t
-cairo_script_from_recording_surface (cairo_script_context_t *context,
+cairo_script_from_recording_surface (cairo_device_t *device,
cairo_surface_t *recording_surface)
{
cairo_box_t bbox;
@@ -3407,8 +3448,11 @@ cairo_script_from_recording_surface (cairo_script_context_t *context,
cairo_surface_t *surface;
cairo_status_t status;
- if (unlikely (context->status))
- return context->status;
+ if (unlikely (device->backend->type != CAIRO_DEVICE_TYPE_SCRIPT))
+ return _cairo_error (CAIRO_STATUS_DEVICE_TYPE_MISMATCH);
+
+ if (unlikely (device->status))
+ return _cairo_error (device->status);
if (unlikely (recording_surface->status))
return recording_surface->status;
@@ -3423,7 +3467,7 @@ cairo_script_from_recording_surface (cairo_script_context_t *context,
_cairo_box_round_to_rectangle (&bbox, &extents);
- surface = &_cairo_script_surface_create_internal (context,
+ surface = &_cairo_script_surface_create_internal ((cairo_script_context_t *) device,
recording_surface->content,
extents.width,
extents.height,
@@ -3437,14 +3481,3 @@ cairo_script_from_recording_surface (cairo_script_context_t *context,
return status;
}
-
-void
-cairo_script_context_destroy (cairo_script_context_t *context)
-{
- cairo_status_t status_ignored;
-
- if (context == NULL || context->ref < 0)
- return;
-
- status_ignored = _context_destroy (context);
-}
diff --git a/src/cairo-script.h b/src/cairo-script.h
index 5af625c..376232d 100644
--- a/src/cairo-script.h
+++ b/src/cairo-script.h
@@ -42,48 +42,43 @@
CAIRO_BEGIN_DECLS
-typedef struct _cairo_script_context cairo_script_context_t;
-
typedef enum {
CAIRO_SCRIPT_MODE_BINARY,
CAIRO_SCRIPT_MODE_ASCII
} cairo_script_mode_t;
-cairo_public cairo_script_context_t *
-cairo_script_context_create (const char *filename);
+cairo_public cairo_device_t *
+cairo_script_create (const char *filename);
-cairo_public cairo_script_context_t *
-cairo_script_context_create_for_stream (cairo_write_func_t write_func,
- void *closure);
+cairo_public cairo_device_t *
+cairo_script_create_for_stream (cairo_write_func_t write_func,
+ void *closure);
cairo_public void
-cairo_script_context_write_comment (cairo_script_context_t *context,
- const char *comment,
- int len);
+cairo_script_write_comment (cairo_device_t *script,
+ const char *comment,
+ int len);
cairo_public void
-cairo_script_context_set_mode (cairo_script_context_t *context,
- cairo_script_mode_t mode);
+cairo_script_set_mode (cairo_device_t *script,
+ cairo_script_mode_t mode);
cairo_public cairo_script_mode_t
-cairo_script_context_get_mode (cairo_script_context_t *context);
-
-cairo_public void
-cairo_script_context_destroy (cairo_script_context_t *context);
+cairo_script_get_mode (cairo_device_t *script);
cairo_public cairo_surface_t *
-cairo_script_surface_create (cairo_script_context_t *context,
+cairo_script_surface_create (cairo_device_t *script,
cairo_content_t content,
double width,
double height);
cairo_public cairo_surface_t *
-cairo_script_surface_create_for_target (cairo_script_context_t *context,
+cairo_script_surface_create_for_target (cairo_device_t *script,
cairo_surface_t *target);
cairo_public cairo_status_t
-cairo_script_from_recording_surface (cairo_script_context_t *context,
- cairo_surface_t *recording_surface);
+cairo_script_from_recording_surface (cairo_device_t *script,
+ cairo_surface_t *recording_surface);
CAIRO_END_DECLS
diff --git a/test/cairo-test-trace.c b/test/cairo-test-trace.c
index b7cae20..ed81eb2 100644
--- a/test/cairo-test-trace.c
+++ b/test/cairo-test-trace.c
@@ -864,17 +864,18 @@ static void
write_trace (const char *trace, struct slave *slave)
{
#if CAIRO_HAS_SCRIPT_SURFACE
- cairo_script_context_t *ctx;
+ cairo_device_t *ctx,
cairo_surface_t *script;
char *filename;
cairo_t *cr;
xasprintf (&filename, "%s-fail.trace", trace);
- ctx = cairo_script_context_create (filename);
+ ctx = cairo_script_create (filename);
script = cairo_script_surface_create (ctx,
+ cairo_surface_get_content (slave->image),
slave->width,
slave->height);
- cairo_script_context_destroy (ctx);
+ cairo_device_destroy (ctx);
free (filename);
cr = cairo_create (slave->image);
diff --git a/util/cairo-fdr/fdr.c b/util/cairo-fdr/fdr.c
index 05c77e5..30f2dda 100644
--- a/util/cairo-fdr/fdr.c
+++ b/util/cairo-fdr/fdr.c
@@ -52,10 +52,10 @@ static int fdr_dump;
static const cairo_user_data_key_t fdr_key;
static void
-fdr_replay_to_script (cairo_surface_t *recording, cairo_script_context_t *ctx)
+fdr_replay_to_script (cairo_surface_t *recording, cairo_device_t *ctx)
{
if (recording != NULL) {
- DLCALL (cairo_script_context_write_comment, ctx, "--- fdr ---", -1);
+ DLCALL (cairo_script_write_comment, ctx, "--- fdr ---", -1);
DLCALL (cairo_script_from_recording_surface, ctx, recording);
}
}
@@ -63,10 +63,10 @@ fdr_replay_to_script (cairo_surface_t *recording, cairo_script_context_t *ctx)
static void
fdr_dump_ringbuffer (void)
{
- cairo_script_context_t *ctx;
+ cairo_device_t *ctx;
int n;
- ctx = DLCALL (cairo_script_context_create, "/tmp/fdr.trace");
+ ctx = DLCALL (cairo_script_create, "/tmp/fdr.trace");
for (n = fdr_position; n < RINGBUFFER_SIZE; n++)
fdr_replay_to_script (fdr_ringbuffer[n], ctx);
@@ -74,7 +74,7 @@ fdr_dump_ringbuffer (void)
for (n = 0; n < fdr_position; n++)
fdr_replay_to_script (fdr_ringbuffer[n], ctx);
- DLCALL (cairo_script_context_destroy, ctx);
+ DLCALL (cairo_device_destroy, ctx);
}
static void
diff --git a/util/cairo-script/csi-trace.c b/util/cairo-script/csi-trace.c
index d118067..c57a56b 100644
--- a/util/cairo-script/csi-trace.c
+++ b/util/cairo-script/csi-trace.c
@@ -8,9 +8,10 @@
static cairo_surface_t *
_script_surface_create (void *closure,
cairo_content_t content,
- double width, double height)
+ double width, double height,
+ long uid)
{
- return cairo_script_surface_create (closure, width, height);
+ return cairo_script_surface_create (closure, content, width, height);
}
int
@@ -28,12 +29,12 @@ main (int argc, char **argv)
char buf[4096];
snprintf (buf, sizeof (buf), "%s.trace", basename (argv[i]));
- cairo_script_context_destroy (hooks.closure);
- hooks.closure = cairo_script_context_create (buf);
+ cairo_device_destroy (hooks.closure);
+ hooks.closure = cairo_script_create (buf);
cairo_script_interpreter_install_hooks (csi, &hooks);
cairo_script_interpreter_run (csi, argv[i]);
}
- cairo_script_context_destroy (hooks.closure);
+ cairo_device_destroy (hooks.closure);
return cairo_script_interpreter_destroy (csi);
}
diff --git a/util/cairo-sphinx/fdr.c b/util/cairo-sphinx/fdr.c
index 9c66608..31945f6 100644
--- a/util/cairo-sphinx/fdr.c
+++ b/util/cairo-sphinx/fdr.c
@@ -46,7 +46,7 @@ static void *_dlhandle = RTLD_NEXT;
(*name##_real) (args); \
})
-static cairo_script_context_t *fdr_context;
+static cairo_device_t *fdr_context;
static const cairo_user_data_key_t fdr_key;
static void
@@ -126,7 +126,7 @@ cairo_create (cairo_surface_t *surface)
if (fdr_context == NULL) {
const char *env = getenv ("CAIRO_SPHINX_FD");
int fd = env ? atoi (env) : 1;
- fdr_context = DLCALL (cairo_script_context_create_for_stream,
+ fdr_context = DLCALL (cairo_script_create_for_stream,
fdr_write, (void *) (intptr_t) fd);
}
diff --git a/util/cairo-sphinx/sphinx.c b/util/cairo-sphinx/sphinx.c
index d5f0e93..6d2cda7 100644
--- a/util/cairo-sphinx/sphinx.c
+++ b/util/cairo-sphinx/sphinx.c
@@ -135,7 +135,7 @@ daemonize (void)
/* Let the parent go. */
switch (fork ()) {
case -1: return -1;
- case 0: break;
+ case 0: break;
default: _exit (0);
}
@@ -145,13 +145,11 @@ daemonize (void)
/* Refork to yield session leadership. */
oldhup = signal (SIGHUP, SIG_IGN);
-
- switch (fork ()) { /* refork to yield session leadership. */
+ switch (fork ()) {
case -1: return -1;
- case 0: break;
+ case 0: break;
default: _exit (0);
}
-
signal (SIGHUP, oldhup);
/* Establish stdio. */
@@ -427,6 +425,7 @@ u8_cmp (const void *A, const void *B)
static uint8_t
median (uint8_t *values, int count)
{
+ /* XXX could use a fast median here if we cared */
qsort (values, count, 1, u8_cmp);
return values[count/2];
}
@@ -667,16 +666,16 @@ checksum (const char *filename)
static void
write_trace (struct clients *clients)
{
- cairo_script_context_t *ctx;
+ cairo_device_t *ctx;
gchar *csum;
char buf[4096];
int i;
mkdir ("output", 0777);
- ctx = cairo_script_context_create ("output/cairo-sphinx.trace");
+ ctx = cairo_script_create ("output/cairo-sphinx.trace");
cairo_script_from_recording_surface (ctx, clients->recording);
- cairo_script_context_destroy (ctx);
+ cairo_device_destroy (ctx);
csum = checksum ("output/cairo-sphinx.trace");
@@ -1262,7 +1261,7 @@ do_server (const char *path)
}
} else if (strncmp (line, ".complete", 9) == 0) {
clients_complete (&clients, pfd[n].fd);
- } else if (strncmp (line, ".recording", 5) == 0) {
+ } else if (strncmp (line, ".recording", 10) == 0) {
clients_recording (&clients, pfd[n].fd, line + 6);
} else {
printf ("do_command (%s)\n", line);
diff --git a/util/cairo-trace/trace.c b/util/cairo-trace/trace.c
index f624c0f..46ec7f2 100644
--- a/util/cairo-trace/trace.c
+++ b/util/cairo-trace/trace.c
@@ -4567,7 +4567,7 @@ cairo_xlib_surface_create_with_xrender_format (Display *dpy,
#if CAIRO_HAS_SCRIPT_SURFACE
#include <cairo-script.h>
cairo_surface_t *
-cairo_script_surface_create (cairo_script_context_t *ctx,
+cairo_script_surface_create (cairo_device_t *device,
cairo_content_t content,
double width,
double height)
@@ -4577,7 +4577,7 @@ cairo_script_surface_create (cairo_script_context_t *ctx,
_enter_trace ();
- ret = DLCALL (cairo_script_surface_create, ctx, content, width, height);
+ ret = DLCALL (cairo_script_surface_create, device, content, width, height);
surface_id = _create_surface_id (ret);
_emit_line_info ();
@@ -4602,7 +4602,7 @@ cairo_script_surface_create (cairo_script_context_t *ctx,
}
cairo_surface_t *
-cairo_script_surface_create_for_target (cairo_script_context_t *ctx,
+cairo_script_surface_create_for_target (cairo_device_t *device,
cairo_surface_t *target)
{
cairo_surface_t *ret;
@@ -4610,7 +4610,7 @@ cairo_script_surface_create_for_target (cairo_script_context_t *ctx,
_enter_trace ();
- ret = DLCALL (cairo_script_surface_create_for_target, ctx, target);
+ ret = DLCALL (cairo_script_surface_create_for_target, device, target);
surface_id = _create_surface_id (ret);
_emit_line_info ();
commit f617d5fc982f749d0981c81c1de1be8dc3632717
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Mon Jan 18 21:53:42 2010 +0000
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.
diff --git a/src/Makefile.sources b/src/Makefile.sources
index d1ced09..20829e7 100644
--- a/src/Makefile.sources
+++ b/src/Makefile.sources
@@ -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 \
diff --git a/src/cairo-analysis-surface.c b/src/cairo-analysis-surface.c
index b777abc..1922bc5 100644
--- a/src/cairo-analysis-surface.c
+++ b/src/cairo-analysis-surface.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;
}
diff --git a/src/cairo-beos-surface.cpp b/src/cairo-beos-surface.cpp
index 68d0814..ebf62d9 100644
--- a/src/cairo-beos-surface.cpp
+++ b/src/cairo-beos-surface.cpp
@@ -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;
diff --git a/src/cairo-device-private.h b/src/cairo-device-private.h
new file mode 100644
index 0000000..39bf67b
--- /dev/null
+++ b/src/cairo-device-private.h
@@ -0,0 +1,85 @@
+/* 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 at 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_ */
diff --git a/src/cairo-device.c b/src/cairo-device.c
new file mode 100644
index 0000000..f0614ea
--- /dev/null
+++ b/src/cairo-device.c
@@ -0,0 +1,265 @@
+/* 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 at 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);
+}
diff --git a/src/cairo-directfb-surface.c b/src/cairo-directfb-surface.c
index 0d39e4b..e3ee366 100644
--- a/src/cairo-directfb-surface.c
+++ b/src/cairo-directfb-surface.c
@@ -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;
diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index 4fa0790..0080dc5 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -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);
diff --git a/src/cairo-glitz-surface.c b/src/cairo-glitz-surface.c
index 73bc995..0aabed9 100644
--- a/src/cairo-glitz-surface.c
+++ b/src/cairo-glitz-surface.c
@@ -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);
diff --git a/src/cairo-image-surface.c b/src/cairo-image-surface.c
index 339e4d2..e42534f 100644
--- a/src/cairo-image-surface.c
+++ b/src/cairo-image-surface.c
@@ -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;
diff --git a/src/cairo-misc.c b/src/cairo-misc.c
index c0a792e..5f9cba5 100644
--- a/src/cairo-misc.c
+++ b/src/cairo-misc.c
@@ -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>";
diff --git a/src/cairo-os2-surface.c b/src/cairo-os2-surface.c
index d9eaafa..7c524ea 100644
--- a/src/cairo-os2-surface.c
+++ b/src/cairo-os2-surface.c
@@ -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;
diff --git a/src/cairo-paginated-surface.c b/src/cairo-paginated-surface.c
index c6e20cc..5e7d704 100644
--- a/src/cairo-paginated-surface.c
+++ b/src/cairo-paginated-surface.c
@@ -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
diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c
index 46928aa..b32b8ec 100644
--- a/src/cairo-pdf-surface.c
+++ b/src/cairo-pdf-surface.c
@@ -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;
diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c
index d2000ec..a50250f 100644
--- a/src/cairo-ps-surface.c
+++ b/src/cairo-ps-surface.c
@@ -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;
diff --git a/src/cairo-qt-surface.cpp b/src/cairo-qt-surface.cpp
index 188b688..3d01094 100644
--- a/src/cairo-qt-surface.cpp
+++ b/src/cairo-qt-surface.cpp
@@ -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);
diff --git a/src/cairo-quartz-image-surface.c b/src/cairo-quartz-image-surface.c
index 6fdb35c..f34b2ec 100644
--- a/src/cairo-quartz-image-surface.c
+++ b/src/cairo-quartz-image-surface.c
@@ -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;
diff --git a/src/cairo-quartz-surface.c b/src/cairo-quartz-surface.c
index 6e86cb2..1128536 100644
--- a/src/cairo-quartz-surface.c
+++ b/src/cairo-quartz-surface.c
@@ -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);
diff --git a/src/cairo-recording-surface.c b/src/cairo-recording-surface.c
index 3b886d4..7d2dda4 100644
--- a/src/cairo-recording-surface.c
+++ b/src/cairo-recording-surface.c
@@ -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;
diff --git a/src/cairo-script-surface.c b/src/cairo-script-surface.c
index 64526c2..897fcab 100644
--- a/src/cairo-script-surface.c
+++ b/src/cairo-script-surface.c
@@ -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);
diff --git a/src/cairo-skia-surface.cpp b/src/cairo-skia-surface.cpp
index 5ca3c0d..17d96cf 100644
--- a/src/cairo-skia-surface.cpp
+++ b/src/cairo-skia-surface.cpp
@@ -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,
diff --git a/src/cairo-spans.c b/src/cairo-spans.c
index af3b85f..7067a5e 100644
--- a/src/cairo-spans.c
+++ b/src/cairo-spans.c
@@ -266,6 +266,8 @@ _cairo_scan_converter_create_in_error (cairo_status_t status)
case CAIRO_STATUS_NO_MEMORY: RETURN_NIL;
case CAIRO_STATUS_INVALID_SIZE: RETURN_NIL;
case CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED: RETURN_NIL;
+ case CAIRO_STATUS_DEVICE_TYPE_MISMATCH: RETURN_NIL;
+ case CAIRO_STATUS_DEVICE_ERROR: RETURN_NIL;
default:
break;
}
@@ -372,6 +374,8 @@ _cairo_span_renderer_create_in_error (cairo_status_t status)
case CAIRO_STATUS_NO_MEMORY: RETURN_NIL;
case CAIRO_STATUS_INVALID_SIZE: RETURN_NIL;
case CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED: RETURN_NIL;
+ case CAIRO_STATUS_DEVICE_TYPE_MISMATCH: RETURN_NIL;
+ case CAIRO_STATUS_DEVICE_ERROR: RETURN_NIL;
default:
break;
}
diff --git a/src/cairo-surface-private.h b/src/cairo-surface-private.h
index 994df0e..c598806 100644
--- a/src/cairo-surface-private.h
+++ b/src/cairo-surface-private.h
@@ -48,6 +48,7 @@ typedef void (*cairo_surface_func_t) (cairo_surface_t *);
struct _cairo_surface {
const cairo_surface_backend_t *backend;
+ cairo_device_t *device;
/* We allow surfaces to override the backend->type by shoving something
* else into surface->type. This is for "wrapper" surfaces that want to
diff --git a/src/cairo-surface-snapshot.c b/src/cairo-surface-snapshot.c
index e59a9e1..8ab6fa6 100644
--- a/src/cairo-surface-snapshot.c
+++ b/src/cairo-surface-snapshot.c
@@ -199,6 +199,7 @@ _cairo_surface_snapshot (cairo_surface_t *surface)
_cairo_surface_init (&snapshot->base,
&_cairo_surface_snapshot_backend,
+ NULL, /* device */
surface->content);
snapshot->target = surface;
diff --git a/src/cairo-surface-subsurface.c b/src/cairo-surface-subsurface.c
index 55fe7a3..f027c8c 100644
--- a/src/cairo-surface-subsurface.c
+++ b/src/cairo-surface-subsurface.c
@@ -451,6 +451,7 @@ cairo_surface_create_for_region (cairo_surface_t *target,
_cairo_surface_init (&surface->base,
&_cairo_surface_subsurface_backend,
+ NULL, /* device */
target->content);
surface->base.type = target->type;
diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index 44eef55..bab13cc 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -40,6 +40,7 @@
#include "cairo-surface-fallback-private.h"
#include "cairo-clip-private.h"
+#include "cairo-device-private.h"
#include "cairo-error-private.h"
#include "cairo-recording-surface-private.h"
#include "cairo-region-private.h"
@@ -48,6 +49,7 @@
#define DEFINE_NIL_SURFACE(status, name) \
const cairo_surface_t name = { \
NULL, /* backend */ \
+ NULL, /* device */ \
CAIRO_SURFACE_TYPE_IMAGE, /* type */ \
CAIRO_CONTENT_COLOR, /* content */ \
CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */ \
@@ -92,6 +94,8 @@ static DEFINE_NIL_SURFACE(CAIRO_STATUS_READ_ERROR, _cairo_surface_nil_read_error
static DEFINE_NIL_SURFACE(CAIRO_STATUS_WRITE_ERROR, _cairo_surface_nil_write_error);
static DEFINE_NIL_SURFACE(CAIRO_STATUS_INVALID_STRIDE, _cairo_surface_nil_invalid_stride);
static DEFINE_NIL_SURFACE(CAIRO_STATUS_INVALID_SIZE, _cairo_surface_nil_invalid_size);
+static DEFINE_NIL_SURFACE(CAIRO_STATUS_DEVICE_TYPE_MISMATCH, _cairo_surface_nil_device_type_mismatch);
+static DEFINE_NIL_SURFACE(CAIRO_STATUS_DEVICE_ERROR, _cairo_surface_nil_device_error);
/**
* _cairo_surface_set_error:
@@ -210,6 +214,23 @@ _cairo_surface_allocate_unique_id (void)
#endif
}
+/**
+ * cairo_surface_get_device:
+ * @surface: a #cairo_surface_t
+ *
+ * This function returns the device for a @surface.
+ * See #cairo_device_t.
+ *
+ * Return value: The device for @surface.
+ *
+ * Since: 1.10
+ **/
+cairo_device_t *
+cairo_surface_get_device (cairo_surface_t *surface)
+{
+ return surface->device;
+}
+
static cairo_bool_t
_cairo_surface_has_snapshots (cairo_surface_t *surface)
{
@@ -330,11 +351,13 @@ _cairo_surface_begin_modification (cairo_surface_t *surface)
void
_cairo_surface_init (cairo_surface_t *surface,
const cairo_surface_backend_t *backend,
+ cairo_device_t *device,
cairo_content_t content)
{
CAIRO_MUTEX_INITIALIZE ();
surface->backend = backend;
+ surface->device = cairo_device_reference (device);
surface->content = content;
surface->type = backend->type;
@@ -579,6 +602,8 @@ cairo_surface_destroy (cairo_surface_t *surface)
/* paranoid check that nobody took a reference whilst finishing */
assert (! CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&surface->ref_count));
+ cairo_device_destroy (surface->device);
+
_cairo_user_data_array_fini (&surface->user_data);
_cairo_user_data_array_fini (&surface->mime_data);
_cairo_array_fini (&surface->snapshots);
@@ -2931,6 +2956,10 @@ _cairo_surface_create_in_error (cairo_status_t status)
return (cairo_surface_t *) &_cairo_surface_nil_invalid_stride;
case CAIRO_STATUS_INVALID_SIZE:
return (cairo_surface_t *) &_cairo_surface_nil_invalid_size;
+ case CAIRO_STATUS_DEVICE_TYPE_MISMATCH:
+ return (cairo_surface_t *) &_cairo_surface_nil_device_type_mismatch;
+ case CAIRO_STATUS_DEVICE_ERROR:
+ return (cairo_surface_t *) &_cairo_surface_nil_device_error;
case CAIRO_STATUS_SUCCESS:
case CAIRO_STATUS_LAST_STATUS:
ASSERT_NOT_REACHED;
diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c
index da6bc60..fe09f58 100644
--- a/src/cairo-svg-surface.c
+++ b/src/cairo-svg-surface.c
@@ -416,7 +416,9 @@ _cairo_svg_surface_create_for_document (cairo_svg_document_t *document,
if (unlikely (surface == NULL))
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
- _cairo_surface_init (&surface->base, &cairo_svg_surface_backend,
+ _cairo_surface_init (&surface->base,
+ &cairo_svg_surface_backend,
+ NULL, /* device */
content);
surface->width = width;
diff --git a/src/cairo-tee-surface.c b/src/cairo-tee-surface.c
index 5cc6f5e..3b2ccf6 100644
--- a/src/cairo-tee-surface.c
+++ b/src/cairo-tee-surface.c
@@ -444,6 +444,7 @@ cairo_tee_surface_create (cairo_surface_t *master)
_cairo_surface_init (&surface->base,
&cairo_tee_surface_backend,
+ master->device,
master->content);
_cairo_surface_wrapper_init (&surface->master, master);
diff --git a/src/cairo-type3-glyph-surface.c b/src/cairo-type3-glyph-surface.c
index 8df6ef8..5a15153 100644
--- a/src/cairo-type3-glyph-surface.c
+++ b/src/cairo-type3-glyph-surface.c
@@ -84,7 +84,9 @@ _cairo_type3_glyph_surface_create (cairo_scaled_font_t *scaled_font,
if (unlikely (surface == NULL))
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
- _cairo_surface_init (&surface->base, &cairo_type3_glyph_surface_backend,
+ _cairo_surface_init (&surface->base,
+ &cairo_type3_glyph_surface_backend,
+ NULL, /* device */
CAIRO_CONTENT_COLOR_ALPHA);
surface->scaled_font = scaled_font;
diff --git a/src/cairo-types-private.h b/src/cairo-types-private.h
index e10d11e..051a0ae 100644
--- a/src/cairo-types-private.h
+++ b/src/cairo-types-private.h
@@ -50,6 +50,7 @@ typedef struct _cairo_cache cairo_cache_t;
typedef struct _cairo_clip cairo_clip_t;
typedef struct _cairo_clip_path cairo_clip_path_t;
typedef struct _cairo_color cairo_color_t;
+typedef struct _cairo_device_backend cairo_device_backend_t;
typedef struct _cairo_font_face_backend cairo_font_face_backend_t;
typedef struct _cairo_gstate cairo_gstate_t;
typedef struct _cairo_hash_entry cairo_hash_entry_t;
diff --git a/src/cairo-vg-surface.c b/src/cairo-vg-surface.c
index a8a3db6..b3eef52 100644
--- a/src/cairo-vg-surface.c
+++ b/src/cairo-vg-surface.c
@@ -1606,6 +1606,7 @@ _vg_surface_create_internal (cairo_vg_context_t *context,
_cairo_surface_init (&surface->base,
&cairo_vg_surface_backend,
+ NULL, /* device */
_vg_format_to_content (format));
surface->width = width;
diff --git a/src/cairo-win32-printing-surface.c b/src/cairo-win32-printing-surface.c
index 8eae55d..ac4bc43 100644
--- a/src/cairo-win32-printing-surface.c
+++ b/src/cairo-win32-printing-surface.c
@@ -1807,6 +1807,7 @@ cairo_win32_printing_surface_create (HDC hdc)
_cairo_win32_printing_surface_init_language_pack (surface);
_cairo_surface_init (&surface->base,
&cairo_win32_printing_surface_backend,
+ NULL, /* device */
CAIRO_CONTENT_COLOR_ALPHA);
paginated = _cairo_paginated_surface_create (&surface->base,
diff --git a/src/cairo-win32-surface.c b/src/cairo-win32-surface.c
index 0ec48be..45a5eab 100644
--- a/src/cairo-win32-surface.c
+++ b/src/cairo-win32-surface.c
@@ -367,7 +367,9 @@ _cairo_win32_surface_create_for_dc (HDC original_dc,
surface->extents = surface->clip_rect;
surface->font_subsets = NULL;
- _cairo_surface_init (&surface->base, &cairo_win32_surface_backend,
+ _cairo_surface_init (&surface->base,
+ &cairo_win32_surface_backend,
+ NULL, /* device */
_cairo_content_from_format (format));
return &surface->base;
@@ -1676,7 +1678,9 @@ cairo_win32_surface_create (HDC hdc)
surface->flags = _cairo_win32_flags_for_dc (surface->dc);
- _cairo_surface_init (&surface->base, &cairo_win32_surface_backend,
+ _cairo_surface_init (&surface->base,
+ &cairo_win32_surface_backend,
+ NULL, /* device */
_cairo_content_from_format (format));
return (cairo_surface_t *)surface;
diff --git a/src/cairo-xcb-surface.c b/src/cairo-xcb-surface.c
index 1932c4e..c9d5c92 100644
--- a/src/cairo-xcb-surface.c
+++ b/src/cairo-xcb-surface.c
@@ -2041,7 +2041,9 @@ _cairo_xcb_surface_create_internal (xcb_connection_t *dpy,
xrender_format = NULL;
}
- _cairo_surface_init (&surface->base, &cairo_xcb_surface_backend,
+ _cairo_surface_init (&surface->base,
+ &cairo_xcb_surface_backend,
+ NULL, /* device */
_xcb_render_format_to_content (xrender_format));
surface->dpy = dpy;
diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c
index 544e733..918e4ad 100644
--- a/src/cairo-xlib-surface.c
+++ b/src/cairo-xlib-surface.c
@@ -2941,7 +2941,9 @@ found:
surface->render_minor = -1;
}
- _cairo_surface_init (&surface->base, &cairo_xlib_surface_backend,
+ _cairo_surface_init (&surface->base,
+ &cairo_xlib_surface_backend,
+ NULL, /* device */
_xrender_format_to_content (xrender_format));
surface->screen = _cairo_xlib_screen_reference (screen);
diff --git a/src/cairo-xml-surface.c b/src/cairo-xml-surface.c
index d7d9b56..1677c4c 100644
--- a/src/cairo-xml-surface.c
+++ b/src/cairo-xml-surface.c
@@ -1050,6 +1050,7 @@ _cairo_xml_surface_create_internal (cairo_xml_t *xml,
_cairo_surface_init (&surface->base,
&_cairo_xml_surface_backend,
+ NULL, /* device */
content);
surface->xml = xml;
diff --git a/src/cairo.h b/src/cairo.h
index 4b6c5a6..453874d 100644
--- a/src/cairo.h
+++ b/src/cairo.h
@@ -147,6 +147,22 @@ typedef struct _cairo cairo_t;
typedef struct _cairo_surface cairo_surface_t;
/**
+ * cairo_device_t:
+ *
+ * A #cairo_device_t represents the driver interface for drawing
+ * operations to a #cairo_surface_t. There are different subtypes of
+ * #cairo_device_t for different drawing backends; for example,
+ * cairo_xcb_device_create() creates a device that wraps the connection
+ * to an X Windows System using the XCB library.
+ *
+ * The type of a surface can be queried with cairo_device_get_type().
+ *
+ * Memory management of #cairo_device_t is done with
+ * cairo_device_reference() and cairo_device_destroy().
+ **/
+typedef struct _cairo_device cairo_device_t;
+
+/**
* cairo_matrix_t:
* @xx: xx component of the affine transformation
* @yx: yx component of the affine transformation
@@ -250,6 +266,8 @@ typedef struct _cairo_user_data_key {
* @CAIRO_STATUS_INVALID_WEIGHT: invalid value for an input #cairo_font_weight_t (Since 1.8)
* @CAIRO_STATUS_INVALID_SIZE: invalid value (typically too big) for the size of the input (surface, pattern, etc.) (Since 1.10)
* @CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED: user-font method not implemented (Since 1.10)
+ * @CAIRO_STATUS_DEVICE_TYPE_MISMATCH: the device type is not appropriate for the operation (Since 1.10)
+ * @CAIRO_STATUS_DEVICE_ERROR: an operation to the device caused an unspecified error (Since 1.10)
* @CAIRO_STATUS_LAST_STATUS: this is a special value indicating the number of
* status values defined in this enumeration. When using this value, note
* that the version of cairo at run-time may have additional status values
@@ -299,6 +317,8 @@ typedef enum _cairo_status {
CAIRO_STATUS_INVALID_WEIGHT,
CAIRO_STATUS_INVALID_SIZE,
CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED,
+ CAIRO_STATUS_DEVICE_TYPE_MISMATCH,
+ CAIRO_STATUS_DEVICE_ERROR,
CAIRO_STATUS_LAST_STATUS
} cairo_status_t;
@@ -1912,6 +1932,100 @@ cairo_status (cairo_t *cr);
cairo_public const char *
cairo_status_to_string (cairo_status_t status);
+/* Backend device manipulation */
+
+cairo_public cairo_device_t *
+cairo_device_reference (cairo_device_t *device);
+
+/**
+ * cairo_device_type_t:
+ * @CAIRO_DEVICE_TYPE_IMAGE: The surface is of type image
+ * @CAIRO_DEVICE_TYPE_PDF: The surface is of type pdf
+ * @CAIRO_DEVICE_TYPE_PS: The surface is of type ps
+ * @CAIRO_DEVICE_TYPE_XLIB: The surface is of type xlib
+ * @CAIRO_DEVICE_TYPE_XCB: The surface is of type xcb
+ * @CAIRO_DEVICE_TYPE_GLITZ: The surface is of type glitz
+ * @CAIRO_DEVICE_TYPE_QUARTZ: The surface is of type quartz
+ * @CAIRO_DEVICE_TYPE_WIN32: The surface is of type win32
+ * @CAIRO_DEVICE_TYPE_BEOS: The surface is of type beos
+ * @CAIRO_DEVICE_TYPE_DIRECTFB: The surface is of type directfb
+ * @CAIRO_DEVICE_TYPE_SVG: The surface is of type svg
+ * @CAIRO_DEVICE_TYPE_OS2: The surface is of type os2
+ * @CAIRO_DEVICE_TYPE_WIN32_PRINTING: The surface is a win32 printing surface
+ * @CAIRO_DEVICE_TYPE_QUARTZ_IMAGE: The surface is of type quartz_image
+ * @CAIRO_DEVICE_TYPE_SCRIPT: The surface is of type script
+ * @CAIRO_DEVICE_TYPE_QT: The surface is of type Qt
+ * @CAIRO_DEVICE_TYPE_RECORDING: The surface is of type recording
+ * @CAIRO_DEVICE_TYPE_VG: The surface is a OpenVG surface
+ * @CAIRO_DEVICE_TYPE_GL: The surface is of type OpenGL
+ * @CAIRO_DEVICE_TYPE_DRM: The surface is of type Direct Render Manager
+ * @CAIRO_DEVICE_TYPE_XML: The surface is of type XML
+ * @CAIRO_DEVICE_TYPE_SKIA: The surface is of type Skia
+ *
+ * #cairo_device_type_t is used to describe the type of a given
+ * device. The devices types are also known as "backends" within cairo.
+ *
+ * The device type can be queried with cairo_device_get_type()
+ *
+ * The various #cairo_device_t functions can be used with surfaces of
+ * any type, but some backends also provide type-specific functions
+ * that must only be called with a device of the appropriate
+ * type. These functions have names that begin with
+ * cairo_<emphasis>type</emphasis>_device<!-- --> such as cairo_xcb_device_debug_set_render_version().
+ *
+ * The behavior of calling a type-specific function with a surface of
+ * the wrong type is undefined.
+ *
+ * New entries may be added in future versions.
+ *
+ * Since: 1.10
+ **/
+typedef enum _cairo_device_type {
+ CAIRO_DEVICE_TYPE_IMAGE,
+ CAIRO_DEVICE_TYPE_PDF,
+ CAIRO_DEVICE_TYPE_PS,
+ CAIRO_DEVICE_TYPE_XLIB,
+ CAIRO_DEVICE_TYPE_XCB,
+ CAIRO_DEVICE_TYPE_GLITZ,
+ CAIRO_DEVICE_TYPE_QUARTZ,
+ CAIRO_DEVICE_TYPE_WIN32,
+ CAIRO_DEVICE_TYPE_BEOS,
+ CAIRO_DEVICE_TYPE_DIRECTFB,
+ CAIRO_DEVICE_TYPE_SVG,
+ CAIRO_DEVICE_TYPE_OS2,
+ CAIRO_DEVICE_TYPE_WIN32_PRINTING,
+ CAIRO_DEVICE_TYPE_QUARTZ_IMAGE,
+ CAIRO_DEVICE_TYPE_SCRIPT,
+ CAIRO_DEVICE_TYPE_QT,
+ CAIRO_DEVICE_TYPE_RECORDING,
+ CAIRO_DEVICE_TYPE_VG,
+ CAIRO_DEVICE_TYPE_GL,
+ CAIRO_DEVICE_TYPE_DRM,
+ CAIRO_DEVICE_TYPE_XML,
+ CAIRO_DEVICE_TYPE_SKIA
+} cairo_device_type_t;
+
+cairo_public cairo_device_type_t
+cairo_device_get_type (cairo_device_t *device);
+
+cairo_public cairo_status_t
+cairo_device_status (cairo_device_t *device);
+
+cairo_public cairo_status_t
+cairo_device_acquire (cairo_device_t *device);
+
+cairo_public void
+cairo_device_release (cairo_device_t *device);
+
+cairo_public void
+cairo_device_flush (cairo_device_t *device);
+
+cairo_public void
+cairo_device_finish (cairo_device_t *device);
+
+cairo_public void
+cairo_device_destroy (cairo_device_t *device);
+
/* Surface manipulation */
cairo_public cairo_surface_t *
@@ -1936,6 +2050,9 @@ cairo_surface_finish (cairo_surface_t *surface);
cairo_public void
cairo_surface_destroy (cairo_surface_t *surface);
+cairo_public cairo_device_t *
+cairo_surface_get_device (cairo_surface_t *surface);
+
cairo_public unsigned int
cairo_surface_get_reference_count (cairo_surface_t *surface);
diff --git a/src/cairoint.h b/src/cairoint.h
index 0ca3c87..780d111 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -1813,6 +1813,7 @@ _cairo_surface_repaint_solid_pattern_surface (cairo_surface_t *other,
cairo_private void
_cairo_surface_init (cairo_surface_t *surface,
const cairo_surface_backend_t *backend,
+ cairo_device_t *device,
cairo_content_t content);
cairo_private void
diff --git a/src/drm/cairo-drm-gallium-surface.c b/src/drm/cairo-drm-gallium-surface.c
index b61e902..c2f331b 100644
--- a/src/drm/cairo-drm-gallium-surface.c
+++ b/src/drm/cairo-drm-gallium-surface.c
@@ -444,6 +444,7 @@ gallium_surface_create_internal (gallium_device_t *device,
_cairo_surface_init (&surface->base.base,
&gallium_surface_backend,
+ NULL, /* device */
content);
_cairo_drm_surface_init (&surface->base, &device->base);
@@ -550,6 +551,7 @@ gallium_surface_create_for_name (cairo_drm_device_t *base_dev,
content = _cairo_content_from_format (format);
_cairo_surface_init (&surface->base.base,
&gallium_surface_backend,
+ NULL, /* device */
content);
_cairo_drm_surface_init (&surface->base, base_dev);
diff --git a/src/drm/cairo-drm-intel-surface.c b/src/drm/cairo-drm-intel-surface.c
index 2210d07..e9e1cac 100644
--- a/src/drm/cairo-drm-intel-surface.c
+++ b/src/drm/cairo-drm-intel-surface.c
@@ -279,7 +279,10 @@ intel_surface_init (intel_surface_t *surface,
cairo_content_t content,
cairo_drm_device_t *device)
{
- _cairo_surface_init (&surface->base.base, &intel_surface_backend, content);
+ _cairo_surface_init (&surface->base.base,
+ &intel_surface_backend,
+ NULL, /* device */
+ content);
_cairo_drm_surface_init (&surface->base, device);
switch (content) {
diff --git a/src/drm/cairo-drm-radeon-surface.c b/src/drm/cairo-drm-radeon-surface.c
index d4b3bbe..858f353 100644
--- a/src/drm/cairo-drm-radeon-surface.c
+++ b/src/drm/cairo-drm-radeon-surface.c
@@ -276,7 +276,10 @@ radeon_surface_init (radeon_surface_t *surface,
cairo_content_t content,
cairo_drm_device_t *device)
{
- _cairo_surface_init (&surface->base.base, &radeon_surface_backend, content);
+ _cairo_surface_init (&surface->base.base,
+ &radeon_surface_backend,
+ NULL, /* device */
+ content);
_cairo_drm_surface_init (&surface->base, device);
switch (content) {
diff --git a/src/test-fallback-surface.c b/src/test-fallback-surface.c
index 78f339f..f32483f 100644
--- a/src/test-fallback-surface.c
+++ b/src/test-fallback-surface.c
@@ -85,7 +85,9 @@ _cairo_test_fallback_surface_create (cairo_content_t content,
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
}
- _cairo_surface_init (&surface->base, &test_fallback_surface_backend,
+ _cairo_surface_init (&surface->base,
+ &test_fallback_surface_backend,
+ NULL, /* device */
content);
surface->backing = backing;
diff --git a/src/test-fallback16-surface.c b/src/test-fallback16-surface.c
index 45a7b46..5094f43 100644
--- a/src/test-fallback16-surface.c
+++ b/src/test-fallback16-surface.c
@@ -81,6 +81,7 @@ _cairo_test_fallback16_surface_create (cairo_content_t content,
_cairo_surface_init (&surface->base,
&test_fallback16_surface_backend,
+ NULL, /* device */
content);
surface->backing = backing;
diff --git a/src/test-null-surface.c b/src/test-null-surface.c
index 44a284e..86f115e 100644
--- a/src/test-null-surface.c
+++ b/src/test-null-surface.c
@@ -179,7 +179,10 @@ _cairo_test_null_surface_create (cairo_content_t content)
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
}
- _cairo_surface_init (surface, &null_surface_backend, content);
+ _cairo_surface_init (surface,
+ &null_surface_backend,
+ NULL, /* device */
+ content);
return surface;
}
diff --git a/src/test-paginated-surface.c b/src/test-paginated-surface.c
index 73b6617..a9ef3d6 100644
--- a/src/test-paginated-surface.c
+++ b/src/test-paginated-surface.c
@@ -76,7 +76,9 @@ _cairo_test_paginated_surface_create (cairo_surface_t *target)
if (unlikely (surface == NULL))
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
- _cairo_surface_init (&surface->base, &test_paginated_surface_backend,
+ _cairo_surface_init (&surface->base,
+ &test_paginated_surface_backend,
+ NULL, /* device */
target->content);
surface->target = cairo_surface_reference (target);
diff --git a/src/test-wrapping-surface.c b/src/test-wrapping-surface.c
index 3c14cc8..98e1862 100644
--- a/src/test-wrapping-surface.c
+++ b/src/test-wrapping-surface.c
@@ -69,6 +69,7 @@ _cairo_test_wrapping_surface_create (cairo_surface_t *target)
_cairo_surface_init (&surface->base,
&test_wrapping_surface_backend,
+ NULL, /* device */
target->content);
_cairo_surface_wrapper_init (&surface->wrapper, target);
diff --git a/util/cairo-trace/trace.c b/util/cairo-trace/trace.c
index 41481a5..f624c0f 100644
--- a/util/cairo-trace/trace.c
+++ b/util/cairo-trace/trace.c
@@ -1487,6 +1487,8 @@ _status_to_string (cairo_status_t status)
f(INVALID_WEIGHT);
f(INVALID_SIZE);
f(USER_FONT_NOT_IMPLEMENTED);
+ f(DEVICE_TYPE_MISMATCH);
+ f(DEVICE_ERROR);
case CAIRO_STATUS_LAST_STATUS:
break;
}
commit 82f8aa548d70acf51b319000d7a5c176fc73da64
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Mon Jan 18 22:02:09 2010 +0000
Recursive mutex.
Implement a recursive mutex which will be needed for cairo_device_t.
In particular only pthreads by default is a non-recursive mutex (to my
knowledge) - both win32 critical sections and mutexes on Quartz are
recursive.
diff --git a/src/cairo-mutex-impl-private.h b/src/cairo-mutex-impl-private.h
index 06938b5..3604aba 100644
--- a/src/cairo-mutex-impl-private.h
+++ b/src/cairo-mutex-impl-private.h
@@ -168,6 +168,13 @@
# define CAIRO_MUTEX_IMPL_UNLOCK(mutex) CAIRO_MUTEX_IMPL_NOOP1(mutex)
# define CAIRO_MUTEX_IMPL_NIL_INITIALIZER 0
+# define CAIRO_MUTEX_HAS_RECURSIVE_IMPL 1
+
+ typedef int cairo_recursive_mutex_impl_t;
+
+# define CAIRO_RECURSIVE_MUTEX_IMPL_INIT(mutex)
+# define CAIRO_RECURSIVE_MUTEX_IMPL_NIL_INITIALIZER 0
+
#elif defined(_WIN32) /******************************************************/
#define WIN32_LEAN_AND_MEAN
@@ -221,6 +228,7 @@
# include <pthread.h>
typedef pthread_mutex_t cairo_mutex_impl_t;
+ typedef pthread_mutex_t cairo_recursive_mutex_impl_t;
# define CAIRO_MUTEX_IMPL_PTHREAD 1
#if HAVE_LOCKDEP
@@ -239,11 +247,31 @@
#endif
# define CAIRO_MUTEX_IMPL_NIL_INITIALIZER PTHREAD_MUTEX_INITIALIZER
+# define CAIRO_MUTEX_HAS_RECURSIVE_IMPL 1
+# define CAIRO_RECURSIVE_MUTEX_IMPL_INIT(mutex) do { \
+ pthread_mutexattr_t attr; \
+ pthread_mutexattr_init (&attr); \
+ pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_RECURSIVE); \
+ pthread_mutex_init (&(mutex), &attr); \
+ pthread_mutexattr_destroy (&attr); \
+} while (0)
+# define CAIRO_RECURSIVE_MUTEX_IMPL_NIL_INITIALIZER PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
#else /**********************************************************************/
# error "XXX: No mutex implementation found. Cairo will not work with multiple threads. Define CAIRO_NO_MUTEX to 1 to acknowledge and accept this limitation and compile cairo without thread-safety support."
+#endif
+
+/* By default mutex implementations are assumed to be recursive */
+#if ! CAIRO_MUTEX_HAS_RECURSIVE_IMPL
+
+# define CAIRO_MUTEX_HAS_RECURSIVE_IMPL 1
+
+ typedef cairo_mutex_impl_t cairo_recursive_mutex_impl_t;
+
+# define CAIRO_RECURSIVE_MUTEX_IMPL_INIT(mutex) CAIRO_MUTEX_IMPL_INIT(mutex)
+# define CAIRO_RECURSIVE_MUTEX_IMPL_NIL_INITIALIZER CAIRO_MUTEX_IMPL_NIL_INITIALIZER
#endif
diff --git a/src/cairo-mutex-type-private.h b/src/cairo-mutex-type-private.h
index adf17bb..4f34f50 100644
--- a/src/cairo-mutex-type-private.h
+++ b/src/cairo-mutex-type-private.h
@@ -44,7 +44,7 @@
#include "cairo-compiler-private.h"
#include "cairo-mutex-impl-private.h"
-/* Only the following three are mandatory at this point */
+/* Only the following four are mandatory at this point */
#ifndef CAIRO_MUTEX_IMPL_LOCK
# error "CAIRO_MUTEX_IMPL_LOCK not defined. Check cairo-mutex-impl-private.h."
#endif
@@ -54,6 +54,9 @@
#ifndef CAIRO_MUTEX_IMPL_NIL_INITIALIZER
# error "CAIRO_MUTEX_IMPL_NIL_INITIALIZER not defined. Check cairo-mutex-impl-private.h."
#endif
+#ifndef CAIRO_RECURSIVE_MUTEX_IMPL_INIT
+# error "CAIRO_RECURSIVE_MUTEX_IMPL_INIT not defined. Check cairo-mutex-impl-private.h."
+#endif
/* make sure implementations don't fool us: we decide these ourself */
@@ -156,6 +159,7 @@
#ifndef CAIRO_MUTEX_DEBUG
typedef cairo_mutex_impl_t cairo_mutex_t;
+typedef cairo_recursive_mutex_impl_t cairo_recursive_mutex_t;
#else
# define cairo_mutex_t cairo_mutex_impl_t
#endif
@@ -168,6 +172,9 @@ typedef cairo_mutex_impl_t cairo_mutex_t;
#define CAIRO_MUTEX_FINI CAIRO_MUTEX_IMPL_FINI
#define CAIRO_MUTEX_NIL_INITIALIZER CAIRO_MUTEX_IMPL_NIL_INITIALIZER
+#define CAIRO_RECURSIVE_MUTEX_INIT CAIRO_RECURSIVE_MUTEX_IMPL_INIT
+#define CAIRO_RECURSIVE_MUTEX_NIL_INITIALIZER CAIRO_RECURSIVE_MUTEX_IMPL_NIL_INITIALIZER
+
#ifndef CAIRO_MUTEX_IS_LOCKED
# define CAIRO_MUTEX_IS_LOCKED(name) 1
#endif
commit d2f251f84b326c5f8825c9a631ea729f21891580
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Mon Jan 18 22:12:23 2010 +0000
configure: Globally define AC_GNU_SOURCE
We were using _GNU_SOURCE throughout the codebase, so simply define it
once during configure. This is the easiest method to enable recursive
mutexes using pthreads, as required in a pending patch.
diff --git a/boilerplate/cairo-boilerplate-pdf.c b/boilerplate/cairo-boilerplate-pdf.c
index dd14bfa..6790abd 100644
--- a/boilerplate/cairo-boilerplate-pdf.c
+++ b/boilerplate/cairo-boilerplate-pdf.c
@@ -30,6 +30,10 @@
#include <cairo-pdf-surface-private.h>
#include <cairo-paginated-surface-private.h>
+#if HAVE_SIGNAL_H
+#include <signal.h>
+#endif
+
#if ! CAIRO_HAS_RECORDING_SURFACE
#define CAIRO_SURFACE_TYPE_RECORDING CAIRO_INTERNAL_SURFACE_TYPE_RECORDING
#endif
diff --git a/boilerplate/cairo-boilerplate-ps.c b/boilerplate/cairo-boilerplate-ps.c
index 2a9bc75..5ba68ab 100644
--- a/boilerplate/cairo-boilerplate-ps.c
+++ b/boilerplate/cairo-boilerplate-ps.c
@@ -31,6 +31,10 @@
#include <cairo-ps-surface-private.h>
#include <cairo-paginated-surface-private.h>
+#if HAVE_SIGNAL_H
+#include <signal.h>
+#endif
+
#if ! CAIRO_HAS_RECORDING_SURFACE
#define CAIRO_SURFACE_TYPE_RECORDING CAIRO_INTERNAL_SURFACE_TYPE_RECORDING
#endif
diff --git a/configure.ac b/configure.ac
index 27404cd..d704353 100644
--- a/configure.ac
+++ b/configure.ac
@@ -3,6 +3,7 @@ CAIRO_PARSE_VERSION
AC_INIT([cairo],
[cairo_version_major.cairo_version_minor.cairo_version_micro],
[http://bugs.freedesktop.org/enter_bug.cgi?product=cairo])
+AC_USE_SYSTEM_EXTENSIONS
AC_CONFIG_SRCDIR(src/cairo.h)
AC_CONFIG_HEADERS(config.h)
AC_CONFIG_AUX_DIR(build)
@@ -13,6 +14,8 @@ AC_PROG_LIBTOOL dnl ([1.4]) Don't remove!
DOLT dnl Make my libtool fast!
GTK_DOC_CHECK([1.6])
+AC_GNU_SOURCE
+
dnl ===========================================================================
dnl
dnl The order of the includes here is rather important
diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c
index 3fbdb1e..03e408d 100644
--- a/src/cairo-gstate.c
+++ b/src/cairo-gstate.c
@@ -35,8 +35,6 @@
* Carl D. Worth <cworth at cworth.org>
*/
-#define _GNU_SOURCE
-
#include "cairoint.h"
#include "cairo-clip-private.h"
diff --git a/src/cairo-matrix.c b/src/cairo-matrix.c
index bf97273..75f091b 100644
--- a/src/cairo-matrix.c
+++ b/src/cairo-matrix.c
@@ -34,8 +34,6 @@
* Carl D. Worth <cworth at cworth.org>
*/
-#define _GNU_SOURCE
-
#include "cairoint.h"
#include "cairo-error-private.h"
diff --git a/src/cairo-scaled-font.c b/src/cairo-scaled-font.c
index 91d8917..0e24bbd 100644
--- a/src/cairo-scaled-font.c
+++ b/src/cairo-scaled-font.c
@@ -38,8 +38,6 @@
* Chris Wilson <chris at chris-wilson.co.uk>
*/
-#define _GNU_SOURCE
-
#include "cairoint.h"
#include "cairo-error-private.h"
#include "cairo-scaled-font-private.h"
commit 934d0d0d6585eb7638c7db597c40dd821092c034
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Mon Jan 18 19:05:34 2010 +0000
Real zero-copy cow snapshotting
The first iteration of COW snapshotting always made an initial copy when
the snapshot was requested (and reused that copy until the surface was
modified). However, in a few circumstances we can avoid even that copy
so long as the surface is still alive and unmodified between the
snapshotting and its use. In order to do so, we need a new proxy surface
that can automatically perform the copy if the target should disappear
prior to use.
diff --git a/src/Makefile.sources b/src/Makefile.sources
index 5fc9fbb..d1ced09 100644
--- a/src/Makefile.sources
+++ b/src/Makefile.sources
@@ -91,6 +91,7 @@ cairo_private = \
cairo-surface-clipper-private.h \
cairo-surface-offset-private.h \
cairo-surface-subsurface-private.h \
+ cairo-surface-snapshot-private.h \
cairo-surface-wrapper-private.h \
cairo-tee-surface-private.h \
cairo-types-private.h \
@@ -153,6 +154,7 @@ cairo_sources = \
cairo-surface-fallback.c \
cairo-surface-clipper.c \
cairo-surface-offset.c \
+ cairo-surface-snapshot.c \
cairo-surface-subsurface.c \
cairo-surface-wrapper.c \
cairo-system.c \
diff --git a/src/cairo-paginated-surface.c b/src/cairo-paginated-surface.c
index 80e4b72..c6e20cc 100644
--- a/src/cairo-paginated-surface.c
+++ b/src/cairo-paginated-surface.c
@@ -156,8 +156,11 @@ _cairo_paginated_surface_finish (void *abstract_surface)
cairo_status_t status = CAIRO_STATUS_SUCCESS;
if (surface->page_is_blank == FALSE || surface->page_num == 1) {
- cairo_surface_show_page (abstract_surface);
- status = cairo_surface_status (abstract_surface);
+ /* Bypass some of the sanity checking in cairo-surface.c, as we
+ * know that the surface is finished...
+ */
+ if (surface->base.backend->show_page != NULL)
+ status = surface->base.backend->show_page (&surface->base);
}
/* XXX We want to propagate any errors from destroy(), but those are not
diff --git a/src/cairo-surface-snapshot-private.h b/src/cairo-surface-snapshot-private.h
new file mode 100644
index 0000000..cbab545
--- /dev/null
+++ b/src/cairo-surface-snapshot-private.h
@@ -0,0 +1,48 @@
+/* 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.
+ *
+ * Contributor(s):
+ * Chris Wilson <chris at chris-wilson.co.uk>
+ */
+
+#ifndef CAIRO_SURFACE_SNAPSHOT_PRIVATE_H
+#define CAIRO_SURFACE_SNAPSHOT_PRIVATE_H
+
+#include "cairo-surface-private.h"
+
+struct _cairo_surface_snapshot {
+ cairo_surface_t base;
+
+ cairo_surface_t *target;
+ cairo_surface_t *clone;
+};
+
+#endif /* CAIRO_SURFACE_SNAPSHOT_PRIVATE_H */
diff --git a/src/cairo-surface-snapshot.c b/src/cairo-surface-snapshot.c
new file mode 100644
index 0000000..e59a9e1
--- /dev/null
+++ b/src/cairo-surface-snapshot.c
@@ -0,0 +1,225 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2002 University of Southern California
+ * Copyright © 2005 Red Hat, Inc.
+ * 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 University of Southern
+ * California.
+ *
+ * Contributor(s):
+ * Carl D. Worth <cworth at cworth.org>
+ * Chris Wilson <chris at chris-wilson.co.uk>
+ */
+
+#include "cairoint.h"
+
+#include "cairo-error-private.h"
+#include "cairo-surface-snapshot-private.h"
+
+static cairo_status_t
+_cairo_surface_snapshot_finish (void *abstract_surface)
+{
+ cairo_surface_snapshot_t *surface = abstract_surface;
+
+ cairo_surface_destroy (surface->clone);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_surface_snapshot_acquire_source_image (void *abstract_surface,
+ cairo_image_surface_t **image_out,
+ void **extra_out)
+{
+ cairo_surface_snapshot_t *surface = abstract_surface;
+
+ return _cairo_surface_acquire_source_image (surface->target, image_out, extra_out);
+}
+
+static void
+_cairo_surface_snapshot_release_source_image (void *abstract_surface,
+ cairo_image_surface_t *image,
+ void *extra)
+{
+ cairo_surface_snapshot_t *surface = abstract_surface;
+
+ _cairo_surface_release_source_image (surface->target, image, extra);
+}
+
+static cairo_bool_t
+_cairo_surface_snapshot_get_extents (void *abstract_surface,
+ cairo_rectangle_int_t *extents)
+{
+ cairo_surface_snapshot_t *surface = abstract_surface;
+
+ return _cairo_surface_get_extents (surface->target, extents);
+}
+
+static const cairo_surface_backend_t _cairo_surface_snapshot_backend = {
+ CAIRO_INTERNAL_SURFACE_TYPE_SNAPSHOT,
+
+ NULL, /* create similar */
+ _cairo_surface_snapshot_finish,
+
+ _cairo_surface_snapshot_acquire_source_image,
+ _cairo_surface_snapshot_release_source_image,
+ NULL, NULL, /* acquire, release dest */
+ NULL, /* clone similar */
+ NULL, /* composite */
+ NULL, /* fill rectangles */
+ NULL, /* composite trapezoids */
+ NULL, /* create span renderer */
+ NULL, /* check span renderer */
+ NULL, /* copy_page */
+ NULL, /* show_page */
+ _cairo_surface_snapshot_get_extents,
+};
+
+static void
+_cairo_surface_snapshot_copy_on_write (cairo_surface_t *surface)
+{
+ cairo_surface_snapshot_t *snapshot = (cairo_surface_snapshot_t *) surface;
+ cairo_image_surface_t *image;
+ cairo_image_surface_t *clone;
+ void *extra;
+ cairo_status_t status;
+
+ /* We need to make an image copy of the original surface since the
+ * snapshot may exceed the lifetime of the original device, i.e.
+ * when we later need to use the snapshot the data may have already
+ * been lost.
+ */
+
+ status = _cairo_surface_acquire_source_image (snapshot->target, &image, &extra);
+ if (unlikely (status)) {
+ snapshot->target = _cairo_surface_create_in_error (status);
+ return;
+ }
+
+ clone = (cairo_image_surface_t *)
+ _cairo_image_surface_create_with_pixman_format (NULL,
+ image->pixman_format,
+ image->width,
+ image->height,
+ 0);
+ if (likely (clone->base.status == CAIRO_STATUS_SUCCESS)) {
+ pixman_image_composite (PIXMAN_OP_SRC,
+ image->pixman_image, NULL, clone->pixman_image,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ image->width, image->height);
+ clone->base.is_clear = FALSE;
+
+ snapshot->clone = &clone->base;
+ } else {
+ snapshot->clone = &clone->base;
+ }
+
+ _cairo_surface_release_source_image (snapshot->target, image, extra);
+ snapshot->target = snapshot->clone;
+}
+
+/**
+ * _cairo_surface_snapshot
+ * @surface: a #cairo_surface_t
+ *
+ * Make an immutable reference to @surface. It is an error to call a
+ * surface-modifying function on the result of this function. The
+ * resulting 'snapshot' is a lazily copied-on-write surface i.e. it
+ * remains a reference to the original surface until that surface is
+ * written to again, at which time a copy is made of the original surface
+ * and the snapshot then points to that instead. Multiple snapshots of the
+ * same unmodified surface point to the same copy.
+ *
+ * The caller owns the return value and should call
+ * cairo_surface_destroy() when finished with it. This function will not
+ * return %NULL, but will return a nil surface instead.
+ *
+ * Return value: The snapshot surface. Note that the return surface
+ * may not necessarily be of the same type as @surface.
+ **/
+cairo_surface_t *
+_cairo_surface_snapshot (cairo_surface_t *surface)
+{
+ cairo_surface_snapshot_t *snapshot;
+ cairo_status_t status;
+
+ if (unlikely (surface->status))
+ return _cairo_surface_create_in_error (surface->status);
+
+ if (surface->finished)
+ return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
+
+ if (surface->snapshot_of != NULL)
+ return cairo_surface_reference (surface);
+
+ if (surface->backend->snapshot != NULL) {
+ cairo_surface_t *snap;
+
+ snap = surface->backend->snapshot (surface);
+ if (snap != NULL)
+ return snap;
+ }
+
+ snapshot = (cairo_surface_snapshot_t *)
+ _cairo_surface_has_snapshot (surface, &_cairo_surface_snapshot_backend);
+ if (snapshot != NULL)
+ return cairo_surface_reference (&snapshot->base);
+
+ snapshot = malloc (sizeof (cairo_surface_snapshot_t));
+ if (unlikely (snapshot == NULL))
+ return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
+
+ _cairo_surface_init (&snapshot->base,
+ &_cairo_surface_snapshot_backend,
+ surface->content);
+
+ snapshot->target = surface;
+ snapshot->clone = NULL;
+
+ status = _cairo_surface_copy_mime_data (&snapshot->base, surface);
+ if (unlikely (status)) {
+ cairo_surface_destroy (&snapshot->base);
+ return _cairo_surface_create_in_error (status);
+ }
+
+ snapshot->base.device_transform = surface->device_transform;
+ snapshot->base.device_transform_inverse = surface->device_transform_inverse;
+
+ status = _cairo_surface_attach_snapshot (surface,
+ &snapshot->base,
+ _cairo_surface_snapshot_copy_on_write);
+ if (unlikely (status)) {
+ cairo_surface_destroy (&snapshot->base);
+ return _cairo_surface_create_in_error (status);
+ }
+
+ return &snapshot->base;
+}
diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index 0ce0da3..44eef55 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -225,8 +225,6 @@ _cairo_surface_detach_snapshots (cairo_surface_t *surface)
if (! _cairo_surface_has_snapshots (surface))
return;
- /* XXX do something intelligent! */
-
snapshots = _cairo_array_index (&surface->snapshots, 0);
for (i = 0; i < surface->snapshots.num_elements; i++) {
snapshots[i]->snapshot_of = NULL;
@@ -578,6 +576,9 @@ cairo_surface_destroy (cairo_surface_t *surface)
if (! surface->finished)
cairo_surface_finish (surface);
+ /* paranoid check that nobody took a reference whilst finishing */
+ assert (! CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&surface->ref_count));
+
_cairo_user_data_array_fini (&surface->user_data);
_cairo_user_data_array_fini (&surface->mime_data);
_cairo_array_fini (&surface->snapshots);
@@ -640,6 +641,12 @@ cairo_surface_finish (cairo_surface_t *surface)
if (surface->finished)
return;
+ /* update the snapshots *before* we declare the surface as finished */
+ _cairo_surface_detach_snapshots (surface);
+ if (surface->snapshot_of != NULL)
+ _cairo_surface_detach_snapshot (surface);
+
+ surface->finished = TRUE;
cairo_surface_flush (surface);
/* call finish even if in error mode */
@@ -648,11 +655,6 @@ cairo_surface_finish (cairo_surface_t *surface)
if (unlikely (status))
status = _cairo_surface_set_error (surface, status);
}
-
- surface->finished = TRUE;
-
- if (surface->snapshot_of != NULL)
- _cairo_surface_detach_snapshot (surface);
}
slim_hidden_def (cairo_surface_finish);
@@ -1593,91 +1595,6 @@ _cairo_surface_clone_similar (cairo_surface_t *surface,
return status;
}
-/* XXX: Shouldn't really need to do this here. */
-#include "cairo-recording-surface-private.h"
-
-/**
- * _cairo_surface_snapshot
- * @surface: a #cairo_surface_t
- *
- * Make an immutable copy of @surface. It is an error to call a
- * surface-modifying function on the result of this function.
- *
- * The caller owns the return value and should call
- * cairo_surface_destroy() when finished with it. This function will not
- * return %NULL, but will return a nil surface instead.
- *
- * Return value: The snapshot surface. Note that the return surface
- * may not necessarily be of the same type as @surface.
- **/
-cairo_surface_t *
-_cairo_surface_snapshot (cairo_surface_t *surface)
-{
- cairo_surface_t *snapshot;
- cairo_status_t status;
-
- if (surface->status)
- return _cairo_surface_create_in_error (surface->status);
-
- if (surface->finished)
- return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
-
- if (surface->snapshot_of != NULL)
- return cairo_surface_reference (surface);
-
- snapshot = _cairo_surface_has_snapshot (surface, surface->backend);
- if (snapshot != NULL)
- return cairo_surface_reference (snapshot);
-
- if (surface->backend->snapshot != NULL) {
- snapshot = surface->backend->snapshot (surface);
- if (snapshot != NULL) {
- if (unlikely (snapshot->status))
- return snapshot;
-
- /* Is this surface just a proxy - e.g. paginated surfaces? */
- if (snapshot->backend != surface->backend) {
- cairo_surface_t *previous;
-
- previous = _cairo_surface_has_snapshot (surface,
- snapshot->backend);
- if (previous != NULL) {
- cairo_surface_destroy (snapshot);
- return cairo_surface_reference (previous);
- }
- }
- }
- }
-
- if (snapshot == NULL) {
- snapshot = _cairo_surface_has_snapshot (surface,
- &_cairo_image_surface_backend);
- if (snapshot != NULL)
- return cairo_surface_reference (snapshot);
-
- snapshot = _cairo_surface_fallback_snapshot (surface);
- if (unlikely (snapshot->status))
- return snapshot;
- }
-
- status = _cairo_surface_copy_mime_data (snapshot, surface);
- if (unlikely (status)) {
- cairo_surface_destroy (snapshot);
- return _cairo_surface_create_in_error (status);
- }
-
- snapshot->device_transform = surface->device_transform;
- snapshot->device_transform_inverse = surface->device_transform_inverse;
-
- status = _cairo_surface_attach_snapshot (surface, snapshot, NULL);
- if (unlikely (status)) {
- cairo_surface_destroy (snapshot);
- return _cairo_surface_create_in_error (status);
- }
-
- return snapshot;
-}
-
/**
* _cairo_surface_is_similar
* @surface_a: a #cairo_surface_t
diff --git a/src/cairo-types-private.h b/src/cairo-types-private.h
index 125874b..e10d11e 100644
--- a/src/cairo-types-private.h
+++ b/src/cairo-types-private.h
@@ -64,6 +64,7 @@ typedef struct _cairo_scaled_font_backend cairo_scaled_font_backend_t;
typedef struct _cairo_scaled_font_subsets cairo_scaled_font_subsets_t;
typedef struct _cairo_solid_pattern cairo_solid_pattern_t;
typedef struct _cairo_surface_backend cairo_surface_backend_t;
+typedef struct _cairo_surface_snapshot cairo_surface_snapshot_t;
typedef struct _cairo_surface_subsurface cairo_surface_subsurface_t;
typedef struct _cairo_surface_wrapper cairo_surface_wrapper_t;
typedef struct _cairo_unscaled_font_backend cairo_unscaled_font_backend_t;
@@ -166,6 +167,7 @@ typedef enum _cairo_int_status {
typedef enum _cairo_internal_surface_type {
CAIRO_INTERNAL_SURFACE_TYPE_SUBSURFACE = 0x1000,
+ CAIRO_INTERNAL_SURFACE_TYPE_SNAPSHOT,
CAIRO_INTERNAL_SURFACE_TYPE_PAGINATED,
CAIRO_INTERNAL_SURFACE_TYPE_ANALYSIS,
CAIRO_INTERNAL_SURFACE_TYPE_TEST_FALLBACK,
commit 6b3e19aa434d159db7878b2a7fb28a026b2d1756
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Mon Jan 18 19:12:25 2010 +0000
Remove content matching from snapshot lookup.
This was never used, so remove the complexity from the interface.
diff --git a/src/cairo-recording-surface.c b/src/cairo-recording-surface.c
index 4c86c5b..3b886d4 100644
--- a/src/cairo-recording-surface.c
+++ b/src/cairo-recording-surface.c
@@ -245,8 +245,7 @@ _cairo_recording_surface_acquire_source_image (void *abstract_surface,
cairo_surface_t *image;
image = _cairo_surface_has_snapshot (&surface->base,
- &_cairo_image_surface_backend,
- surface->content);
+ &_cairo_image_surface_backend);
if (image != NULL) {
*image_out = (cairo_image_surface_t *) cairo_surface_reference (image);
*image_extra = NULL;
diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index dee6207..0ce0da3 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -266,19 +266,16 @@ _cairo_surface_attach_snapshot (cairo_surface_t *surface,
cairo_surface_t *
_cairo_surface_has_snapshot (cairo_surface_t *surface,
- const cairo_surface_backend_t *backend,
- cairo_content_t content)
+ const cairo_surface_backend_t *backend)
{
cairo_surface_t **snapshots;
unsigned int i;
+ /* XXX is_similar? */
snapshots = _cairo_array_index (&surface->snapshots, 0);
for (i = 0; i < surface->snapshots.num_elements; i++) {
- if (snapshots[i]->backend == backend &&
- snapshots[i]->content == content)
- {
+ if (snapshots[i]->backend == backend)
return snapshots[i];
- }
}
return NULL;
@@ -1425,9 +1422,7 @@ _cairo_recording_surface_clone_similar (cairo_surface_t *surface,
cairo_surface_t *similar;
cairo_status_t status;
- similar = _cairo_surface_has_snapshot (src,
- surface->backend,
- src->content);
+ similar = _cairo_surface_has_snapshot (src, surface->backend);
if (similar != NULL) {
*clone_out = cairo_surface_reference (similar);
*clone_offset_x = 0;
@@ -1630,9 +1625,7 @@ _cairo_surface_snapshot (cairo_surface_t *surface)
if (surface->snapshot_of != NULL)
return cairo_surface_reference (surface);
- snapshot = _cairo_surface_has_snapshot (surface,
- surface->backend,
- surface->content);
+ snapshot = _cairo_surface_has_snapshot (surface, surface->backend);
if (snapshot != NULL)
return cairo_surface_reference (snapshot);
@@ -1647,8 +1640,7 @@ _cairo_surface_snapshot (cairo_surface_t *surface)
cairo_surface_t *previous;
previous = _cairo_surface_has_snapshot (surface,
- snapshot->backend,
- snapshot->content);
+ snapshot->backend);
if (previous != NULL) {
cairo_surface_destroy (snapshot);
return cairo_surface_reference (previous);
@@ -1659,8 +1651,7 @@ _cairo_surface_snapshot (cairo_surface_t *surface)
if (snapshot == NULL) {
snapshot = _cairo_surface_has_snapshot (surface,
- &_cairo_image_surface_backend,
- surface->content);
+ &_cairo_image_surface_backend);
if (snapshot != NULL)
return cairo_surface_reference (snapshot);
diff --git a/src/cairo-vg-surface.c b/src/cairo-vg-surface.c
index 30da7ea..a8a3db6 100644
--- a/src/cairo-vg-surface.c
+++ b/src/cairo-vg-surface.c
@@ -959,8 +959,7 @@ _vg_setup_surface_source (cairo_vg_context_t *context,
cairo_status_t status;
snapshot = _cairo_surface_has_snapshot (spat->surface,
- &cairo_vg_surface_backend,
- spat->surface->content);
+ &cairo_vg_surface_backend);
if (snapshot != NULL) {
clone = (cairo_vg_surface_t *) cairo_surface_reference (snapshot);
goto DONE;
diff --git a/src/cairoint.h b/src/cairoint.h
index d8ed782..0ca3c87 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -2057,8 +2057,7 @@ _cairo_surface_attach_snapshot (cairo_surface_t *surface,
cairo_private cairo_surface_t *
_cairo_surface_has_snapshot (cairo_surface_t *surface,
- const cairo_surface_backend_t *backend,
- cairo_content_t content);
+ const cairo_surface_backend_t *backend);
cairo_private void
_cairo_surface_detach_snapshot (cairo_surface_t *snapshot);
diff --git a/src/drm/cairo-drm-intel-surface.c b/src/drm/cairo-drm-intel-surface.c
index b69eaf3..2210d07 100644
--- a/src/drm/cairo-drm-intel-surface.c
+++ b/src/drm/cairo-drm-intel-surface.c
@@ -93,8 +93,7 @@ intel_surface_acquire_source_image (void *abstract_surface,
}
image = _cairo_surface_has_snapshot (&surface->base.base,
- &_cairo_image_surface_backend,
- surface->base.base.content);
+ &_cairo_image_surface_backend);
if (image != NULL)
goto DONE;
diff --git a/src/drm/cairo-drm-radeon-surface.c b/src/drm/cairo-drm-radeon-surface.c
index 7a26be4..d4b3bbe 100644
--- a/src/drm/cairo-drm-radeon-surface.c
+++ b/src/drm/cairo-drm-radeon-surface.c
@@ -91,8 +91,7 @@ radeon_surface_acquire_source_image (void *abstract_surface,
}
image = _cairo_surface_has_snapshot (&surface->base.base,
- &_cairo_image_surface_backend,
- surface->base.base.content);
+ &_cairo_image_surface_backend);
if (image != NULL)
goto DONE;
commit dc8290814c0e98b38828953bac6dd0893c31c9ad
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Mon Jan 18 18:06:51 2010 +0000
Add subsurface.
A subsurface is a region of another surface that may be used either to
restrict the writable area of a context or the readable extents of a
source. Whilst writing, access to the exterior of the subsurface is
prevented via clipping and when used as a source reads from the exterior
of the subsurface are governed via the extend mechanism of the pattern.
diff --git a/src/Makefile.sources b/src/Makefile.sources
index 6bfef7f..5fc9fbb 100644
--- a/src/Makefile.sources
+++ b/src/Makefile.sources
@@ -90,6 +90,7 @@ cairo_private = \
cairo-surface-private.h \
cairo-surface-clipper-private.h \
cairo-surface-offset-private.h \
+ cairo-surface-subsurface-private.h \
cairo-surface-wrapper-private.h \
cairo-tee-surface-private.h \
cairo-types-private.h \
@@ -152,6 +153,7 @@ cairo_sources = \
cairo-surface-fallback.c \
cairo-surface-clipper.c \
cairo-surface-offset.c \
+ cairo-surface-subsurface.c \
cairo-surface-wrapper.c \
cairo-system.c \
cairo-tee-surface.c \
diff --git a/src/cairo-surface-subsurface-private.h b/src/cairo-surface-subsurface-private.h
new file mode 100644
index 0000000..0f38c05
--- /dev/null
+++ b/src/cairo-surface-subsurface-private.h
@@ -0,0 +1,48 @@
+/* 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.
+ *
+ * Contributor(s):
+ * Chris Wilson <chris at chris-wilson.co.uk>
+ */
+
+#ifndef CAIRO_SURFACE_SUBSURFACE_PRIVATE_H
+#define CAIRO_SURFACE_SUBSURFACE_PRIVATE_H
+
+#include "cairo-surface-private.h"
+
+struct _cairo_surface_subsurface {
+ cairo_surface_t base;
+
+ cairo_surface_t *target;
+ cairo_rectangle_int_t extents;
+};
+
+#endif /* CAIRO_SURFACE_SUBSURFACE_PRIVATE_H */
diff --git a/src/cairo-surface-subsurface.c b/src/cairo-surface-subsurface.c
new file mode 100644
index 0000000..55fe7a3
--- /dev/null
+++ b/src/cairo-surface-subsurface.c
@@ -0,0 +1,464 @@
+/* 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.
+ *
+ * Contributor(s):
+ * Chris Wilson <chris at chris-wilson.co.uk>
+ */
+
+#include "cairoint.h"
+
+#include "cairo-error-private.h"
+#include "cairo-surface-offset-private.h"
+#include "cairo-surface-subsurface-private.h"
+
+static cairo_status_t
+_cairo_surface_subsurface_finish (void *abstract_surface)
+{
+ cairo_surface_subsurface_t *surface = abstract_surface;
+
+ cairo_surface_destroy (surface->target);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_surface_t *
+_cairo_surface_subsurface_create_similar (void *other,
+ cairo_content_t content,
+ int width, int height)
+{
+ cairo_surface_subsurface_t *surface = other;
+ return surface->target->backend->create_similar (surface->target, content, width, height);
+}
+
+static cairo_int_status_t
+_cairo_surface_subsurface_paint (void *abstract_surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_clip_t *clip)
+{
+ cairo_surface_subsurface_t *surface = abstract_surface;
+ cairo_rectangle_int_t rect = { 0, 0, surface->extents.width, surface->extents.height };
+ cairo_status_t status;
+ cairo_clip_t target_clip;
+
+ status = _cairo_clip_rectangle (_cairo_clip_init_copy (&target_clip, clip), &rect);
+ if (unlikely (status))
+ goto CLEANUP;
+
+ status = _cairo_surface_offset_paint (surface->target,
+ -surface->extents.x, -surface->extents.y,
+ op, source, &target_clip);
+ CLEANUP:
+ _cairo_clip_fini (&target_clip);
+ return status;
+}
+
+static cairo_int_status_t
+_cairo_surface_subsurface_mask (void *abstract_surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ const cairo_pattern_t *mask,
+ cairo_clip_t *clip)
+{
+ cairo_surface_subsurface_t *surface = abstract_surface;
+ cairo_rectangle_int_t rect = { 0, 0, surface->extents.width, surface->extents.height };
+ cairo_status_t status;
+ cairo_clip_t target_clip;
+
+ status = _cairo_clip_rectangle (_cairo_clip_init_copy (&target_clip, clip), &rect);
+ if (unlikely (status))
+ goto CLEANUP;
+
+ status = _cairo_surface_offset_mask (surface->target,
+ -surface->extents.x, -surface->extents.y,
+ op, source, mask, &target_clip);
+ CLEANUP:
+ _cairo_clip_fini (&target_clip);
+ return status;
+}
+
+static cairo_int_status_t
+_cairo_surface_subsurface_fill (void *abstract_surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_path_fixed_t *path,
+ cairo_fill_rule_t fill_rule,
+ double tolerance,
+ cairo_antialias_t antialias,
+ cairo_clip_t *clip)
+{
+ cairo_surface_subsurface_t *surface = abstract_surface;
+ cairo_rectangle_int_t rect = { 0, 0, surface->extents.width, surface->extents.height };
+ cairo_status_t status;
+ cairo_clip_t target_clip;
+
+ status = _cairo_clip_rectangle (_cairo_clip_init_copy (&target_clip, clip), &rect);
+ if (unlikely (status))
+ goto CLEANUP;
+
+ status = _cairo_surface_offset_fill (surface->target,
+ -surface->extents.x, -surface->extents.y,
+ op, source, path, fill_rule, tolerance, antialias,
+ &target_clip);
+ CLEANUP:
+ _cairo_clip_fini (&target_clip);
+ return status;
+}
+
+static cairo_int_status_t
+_cairo_surface_subsurface_stroke (void *abstract_surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_path_fixed_t *path,
+ const cairo_stroke_style_t *stroke_style,
+ const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm_inverse,
+ double tolerance,
+ cairo_antialias_t antialias,
+ cairo_clip_t *clip)
+{
+ cairo_surface_subsurface_t *surface = abstract_surface;
+ cairo_rectangle_int_t rect = { 0, 0, surface->extents.width, surface->extents.height };
+ cairo_status_t status;
+ cairo_clip_t target_clip;
+
+ status = _cairo_clip_rectangle (_cairo_clip_init_copy (&target_clip, clip), &rect);
+ if (unlikely (status))
+ goto CLEANUP;
+
+ status = _cairo_surface_offset_stroke (surface->target,
+ -surface->extents.x, -surface->extents.y,
+ op, source, path, stroke_style, ctm, ctm_inverse,
+ tolerance, antialias,
+ &target_clip);
+ CLEANUP:
+ _cairo_clip_fini (&target_clip);
+ return status;
+}
+
+static cairo_int_status_t
+_cairo_surface_subsurface_glyphs (void *abstract_surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_scaled_font_t *scaled_font,
+ cairo_clip_t *clip,
+ int *remaining_glyphs)
+{
+ cairo_surface_subsurface_t *surface = abstract_surface;
+ cairo_rectangle_int_t rect = { 0, 0, surface->extents.width, surface->extents.height };
+ cairo_status_t status;
+ cairo_clip_t target_clip;
+
+ status = _cairo_clip_rectangle (_cairo_clip_init_copy (&target_clip, clip), &rect);
+ if (unlikely (status))
+ goto CLEANUP;
+
+ status = _cairo_surface_offset_glyphs (surface->target,
+ -surface->extents.x, -surface->extents.y,
+ op, source,
+ scaled_font, glyphs, num_glyphs,
+ &target_clip);
+ *remaining_glyphs = 0;
+ CLEANUP:
+ _cairo_clip_fini (&target_clip);
+ return status;
+}
+
+static cairo_status_t
+_cairo_surface_subsurface_flush (void *abstract_surface)
+{
+ cairo_surface_subsurface_t *surface = abstract_surface;
+ cairo_status_t status;
+
+ status = CAIRO_STATUS_SUCCESS;
+ if (surface->target->backend->flush != NULL)
+ status = surface->target->backend->flush (surface->target);
+
+ return status;
+}
+
+static cairo_status_t
+_cairo_surface_subsurface_mark_dirty (void *abstract_surface,
+ int x, int y,
+ int width, int height)
+{
+ cairo_surface_subsurface_t *surface = abstract_surface;
+ cairo_status_t status;
+
+ status = CAIRO_STATUS_SUCCESS;
+ if (surface->target->backend->mark_dirty_rectangle != NULL) {
+ cairo_rectangle_int_t rect, extents;
+
+ rect.x = x;
+ rect.y = y;
+ rect.width = width;
+ rect.height = height;
+
+ extents.x = extents.y = 0;
+ extents.width = surface->extents.width;
+ extents.height = surface->extents.height;
+
+ if (_cairo_rectangle_intersect (&rect, &extents)) {
+ status = surface->target->backend->mark_dirty_rectangle (surface->target,
+ rect.x + surface->extents.x,
+ rect.y + surface->extents.y,
+ rect.width, rect.height);
+ }
+ }
+
+ return status;
+}
+
+static cairo_bool_t
+_cairo_surface_subsurface_get_extents (void *abstract_surface,
+ cairo_rectangle_int_t *extents)
+{
+ cairo_surface_subsurface_t *surface = abstract_surface;
+
+ extents->x = 0;
+ extents->y = 0;
+ extents->width = surface->extents.width;
+ extents->height = surface->extents.height;
+
+ return TRUE;
+}
+
+static void
+_cairo_surface_subsurface_get_font_options (void *abstract_surface,
+ cairo_font_options_t *options)
+{
+ cairo_surface_subsurface_t *surface = abstract_surface;
+
+ if (surface->target->backend->get_font_options != NULL)
+ surface->target->backend->get_font_options (surface->target, options);
+}
+
+struct extra {
+ cairo_image_surface_t *image;
+ void *image_extra;
+};
+
+static cairo_status_t
+_cairo_surface_subsurface_acquire_source_image (void *abstract_surface,
+ cairo_image_surface_t **image_out,
+ void **extra_out)
+{
+ cairo_surface_subsurface_t *surface = abstract_surface;
+ cairo_image_surface_t *image;
+ cairo_status_t status;
+ struct extra *extra;
+ uint8_t *data;
+
+ extra = malloc (sizeof (struct extra));
+ if (unlikely (extra == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+ status = _cairo_surface_acquire_source_image (surface->target, &extra->image, &extra->image_extra);
+ if (unlikely (status))
+ goto CLEANUP;
+
+ /* only copy if we need to perform sub-byte manipulation */
+ if (PIXMAN_FORMAT_BPP (extra->image->pixman_format) > 8) {
+ assert ((PIXMAN_FORMAT_BPP (extra->image->pixman_format) % 8) == 0);
+
+ data = extra->image->data + surface->extents.y * extra->image->stride;
+ data += PIXMAN_FORMAT_BPP (extra->image->pixman_format) / 8 * surface->extents.x;
+
+ image = (cairo_image_surface_t *)
+ _cairo_image_surface_create_with_pixman_format (data,
+ extra->image->pixman_format,
+ surface->extents.width,
+ surface->extents.height,
+ extra->image->stride);
+ if (unlikely ((status = image->base.status)))
+ goto CLEANUP_IMAGE;
+ } else {
+ image = (cairo_image_surface_t *)
+ _cairo_image_surface_create_with_pixman_format (NULL,
+ extra->image->pixman_format,
+ surface->extents.width,
+ surface->extents.height,
+ 0);
+ if (unlikely ((status = image->base.status)))
+ goto CLEANUP_IMAGE;
+
+ pixman_image_composite (PIXMAN_OP_SRC,
+ image->pixman_image, NULL, extra->image->pixman_image,
+ surface->extents.x, surface->extents.y,
+ 0, 0,
+ 0, 0,
+ surface->extents.width, surface->extents.height);
+ }
+
+ *image_out = image;
+ *extra_out = extra;
+ return CAIRO_STATUS_SUCCESS;
+
+CLEANUP_IMAGE:
+ _cairo_surface_release_source_image (surface->target, extra->image, extra->image_extra);
+CLEANUP:
+ free (extra);
+ return status;
+}
+
+static void
+_cairo_surface_subsurface_release_source_image (void *abstract_surface,
+ cairo_image_surface_t *image,
+ void *abstract_extra)
+{
+ cairo_surface_subsurface_t *surface = abstract_surface;
+ struct extra *extra = abstract_extra;
+
+ _cairo_surface_release_source_image (surface->target, extra->image, extra->image_extra);
+ free (extra);
+
+ cairo_surface_destroy (&image->base);
+}
+
+static cairo_surface_t *
+_cairo_surface_subsurface_snapshot (void *abstract_surface)
+{
+ cairo_surface_subsurface_t *surface = abstract_surface;
+ cairo_image_surface_t *image, *clone;
+ void *image_extra;
+ cairo_status_t status;
+
+ /* XXX Alternatively we could snapshot the target and return a subsurface
+ * of that.
+ */
+
+ status = _cairo_surface_acquire_source_image (surface->target, &image, &image_extra);
+ if (unlikely (status))
+ return _cairo_surface_create_in_error (status);
+
+ clone = (cairo_image_surface_t *)
+ _cairo_image_surface_create_with_pixman_format (NULL,
+ image->pixman_format,
+ surface->extents.width,
+ surface->extents.height,
+ 0);
+ if (unlikely (clone->base.status))
+ return &clone->base;
+
+ pixman_image_composite (PIXMAN_OP_SRC,
+ image->pixman_image, NULL, clone->pixman_image,
+ surface->extents.x, surface->extents.y,
+ 0, 0,
+ 0, 0,
+ surface->extents.width, surface->extents.height);
+
+ _cairo_surface_release_source_image (surface->target, image, image_extra);
+
+ return &clone->base;
+}
+
+static const cairo_surface_backend_t _cairo_surface_subsurface_backend = {
+ CAIRO_INTERNAL_SURFACE_TYPE_SUBSURFACE,
+ _cairo_surface_subsurface_create_similar,
+ _cairo_surface_subsurface_finish,
+
+ _cairo_surface_subsurface_acquire_source_image,
+ _cairo_surface_subsurface_release_source_image,
+ NULL, NULL, /* acquire, release dest */
+ NULL, /* clone similar */
+ NULL, /* composite */
+ NULL, /* fill rectangles */
+ NULL, /* composite trapezoids */
+ NULL, /* create span renderer */
+ NULL, /* check span renderer */
+ NULL, /* copy_page */
+ NULL, /* show_page */
+ _cairo_surface_subsurface_get_extents,
+ NULL, /* old_show_glyphs */
+ _cairo_surface_subsurface_get_font_options,
+ _cairo_surface_subsurface_flush,
+ _cairo_surface_subsurface_mark_dirty,
+ NULL, /* font_fini */
+ NULL, /* glyph_fini */
+
+ _cairo_surface_subsurface_paint,
+ _cairo_surface_subsurface_mask,
+ _cairo_surface_subsurface_stroke,
+ _cairo_surface_subsurface_fill,
+ _cairo_surface_subsurface_glyphs,
+
+ _cairo_surface_subsurface_snapshot,
+};
+
+cairo_surface_t *
+cairo_surface_create_for_region (cairo_surface_t *target,
+ int x, int y,
+ int width, int height)
+{
+ cairo_surface_subsurface_t *surface;
+
+ if (unlikely (target->status))
+ return _cairo_surface_create_in_error (target->status);
+
+ if (target->backend->type == CAIRO_INTERNAL_SURFACE_TYPE_SUBSURFACE) {
+ /* Maintain subsurfaces as 1-depth */
+ cairo_surface_subsurface_t *sub = (cairo_surface_subsurface_t *) target;
+ cairo_rectangle_int_t r;
+ cairo_bool_t is_empty;
+
+ r.x = x;
+ r.y = y;
+ r.width = width;
+ r.height = height;
+
+ is_empty = _cairo_rectangle_intersect (&r, &sub->extents);
+
+ x = r.x;
+ y = r.y;
+ width = r.width;
+ height = r.height;
+ target = sub->target;
+ }
+
+ surface = malloc (sizeof (cairo_surface_subsurface_t));
+ if (unlikely (surface == NULL))
+ return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
+
+ _cairo_surface_init (&surface->base,
+ &_cairo_surface_subsurface_backend,
+ target->content);
+ surface->base.type = target->type;
+
+ surface->target = cairo_surface_reference (target);
+ surface->extents.x = x;
+ surface->extents.y = y;
+ surface->extents.width = width;
+ surface->extents.height = height;
+
+ return &surface->base;
+}
diff --git a/src/cairo-types-private.h b/src/cairo-types-private.h
index 3a3b849..125874b 100644
--- a/src/cairo-types-private.h
+++ b/src/cairo-types-private.h
@@ -64,6 +64,7 @@ typedef struct _cairo_scaled_font_backend cairo_scaled_font_backend_t;
typedef struct _cairo_scaled_font_subsets cairo_scaled_font_subsets_t;
typedef struct _cairo_solid_pattern cairo_solid_pattern_t;
typedef struct _cairo_surface_backend cairo_surface_backend_t;
+typedef struct _cairo_surface_subsurface cairo_surface_subsurface_t;
typedef struct _cairo_surface_wrapper cairo_surface_wrapper_t;
typedef struct _cairo_unscaled_font_backend cairo_unscaled_font_backend_t;
typedef struct _cairo_xlib_screen_info cairo_xlib_screen_info_t;
@@ -164,7 +165,8 @@ typedef enum _cairo_int_status {
} cairo_int_status_t;
typedef enum _cairo_internal_surface_type {
- CAIRO_INTERNAL_SURFACE_TYPE_PAGINATED = 0x1000,
+ CAIRO_INTERNAL_SURFACE_TYPE_SUBSURFACE = 0x1000,
+ CAIRO_INTERNAL_SURFACE_TYPE_PAGINATED,
CAIRO_INTERNAL_SURFACE_TYPE_ANALYSIS,
CAIRO_INTERNAL_SURFACE_TYPE_TEST_FALLBACK,
CAIRO_INTERNAL_SURFACE_TYPE_TEST_PAGINATED,
diff --git a/src/cairo.h b/src/cairo.h
index 8be8043..4b6c5a6 100644
--- a/src/cairo.h
+++ b/src/cairo.h
@@ -1921,6 +1921,13 @@ cairo_surface_create_similar (cairo_surface_t *other,
int height);
cairo_public cairo_surface_t *
+cairo_surface_create_for_region (cairo_surface_t *target,
+ int x,
+ int y,
+ int width,
+ int height);
+
+cairo_public cairo_surface_t *
cairo_surface_reference (cairo_surface_t *surface);
cairo_public void
diff --git a/test/Makefile.am b/test/Makefile.am
index 6dbf6bf..b820dd5 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -933,6 +933,9 @@ REFERENCE_IMAGES = \
stroke-image.quartz.ref.png \
stroke-image.ref.png \
stroke-image.xlib.ref.png \
+ subsurface.ref.png \
+ subsurface-repeat.ref.png \
+ subsurface-similar-repeat.ref.png \
surface-pattern-big-scale-down.ref.png \
surface-pattern-big-scale-down.ps.xfail.png \
surface-pattern-operator.argb32.ref.png \
diff --git a/test/Makefile.sources b/test/Makefile.sources
index 52d4f85..d90f04a 100644
--- a/test/Makefile.sources
+++ b/test/Makefile.sources
@@ -210,6 +210,9 @@ test_sources = \
source-clip-scale.c \
source-surface-scale-paint.c \
spline-decomposition.c \
+ subsurface.c \
+ subsurface-repeat.c \
+ subsurface-similar-repeat.c \
surface-finish-twice.c \
surface-pattern.c \
surface-pattern-big-scale-down.c \
diff --git a/test/subsurface-repeat.c b/test/subsurface-repeat.c
new file mode 100644
index 0000000..59c3c54
--- /dev/null
+++ b/test/subsurface-repeat.c
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2009 Intel Corporation
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of
+ * Intel not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior
+ * permission. Intel makes no representations about the
+ * suitability of this software for any purpose. It is provided "as
+ * is" without express or implied warranty.
+ *
+ * INTEL CORPORATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL INTEL CORPORATION BE LIABLE FOR ANY SPECIAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Chris Wilson <chris at chris-wilson.co.uk>
+ */
+
+#include "cairo-test.h"
+
+static cairo_test_status_t
+draw (cairo_t *cr, int width, int height)
+{
+ cairo_surface_t *region;
+ cairo_t *cr_region;
+
+ cairo_set_source_rgb (cr, .5, .5, .5);
+ cairo_paint (cr);
+
+ /* fill the centre */
+ region = cairo_surface_create_for_region (cairo_get_target (cr),
+ 0, 0, 20, 20);
+ cr_region = cairo_create (region);
+ cairo_surface_destroy (region);
+
+ cairo_set_source_rgb (cr_region, 1, 1, 1);
+ cairo_rectangle (cr_region, 0, 0, 10, 10);
+ cairo_fill (cr_region);
+
+ cairo_set_source_rgb (cr_region, 1, 0, 0);
+ cairo_rectangle (cr_region, 10, 0, 10, 10);
+ cairo_fill (cr_region);
+
+ cairo_set_source_rgb (cr_region, 0, 1, 0);
+ cairo_rectangle (cr_region, 0, 10, 10, 10);
+ cairo_fill (cr_region);
+
+ cairo_set_source_rgb (cr_region, 0, 0, 1);
+ cairo_rectangle (cr_region, 10, 10, 10, 10);
+ cairo_fill (cr_region);
+
+ cairo_set_source_surface (cr, cairo_get_target (cr_region), 20, 20);
+ cairo_destroy (cr_region);
+ cairo_pattern_set_extend (cairo_get_source (cr), CAIRO_EXTEND_REPEAT);
+ cairo_paint (cr);
+
+ return CAIRO_TEST_SUCCESS;
+}
+
+CAIRO_TEST (subsurface_repeat,
+ "Tests source clipping with repeat",
+ "subsurface, repeat", /* keywords */
+ NULL, /* requirements */
+ 60, 60,
+ NULL, draw)
diff --git a/test/subsurface-repeat.ref.png b/test/subsurface-repeat.ref.png
new file mode 100644
index 0000000..c37e22e
Binary files /dev/null and b/test/subsurface-repeat.ref.png differ
diff --git a/test/subsurface-similar-repeat.c b/test/subsurface-similar-repeat.c
new file mode 100644
index 0000000..ad63cc8
--- /dev/null
+++ b/test/subsurface-similar-repeat.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2009 Intel Corporation
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of
+ * Intel not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior
+ * permission. Intel makes no representations about the
+ * suitability of this software for any purpose. It is provided "as
+ * is" without express or implied warranty.
+ *
+ * INTEL CORPORATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL INTEL CORPORATION BE LIABLE FOR ANY SPECIAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Chris Wilson <chris at chris-wilson.co.uk>
+ */
+
+#include "cairo-test.h"
+
+static cairo_test_status_t
+draw (cairo_t *cr, int width, int height)
+{
+ cairo_surface_t *similar;
+ cairo_surface_t *region;
+ cairo_t *cr_region;
+
+ cairo_set_source_rgb (cr, .5, .5, .5);
+ cairo_paint (cr);
+
+ similar = cairo_surface_create_similar (cairo_get_target (cr),
+ CAIRO_CONTENT_COLOR,
+ 60, 60);
+ cr_region = cairo_create (similar);
+ cairo_surface_destroy (similar);
+ cairo_set_source_rgb (cr_region, .5, .5, .0);
+ cairo_paint (cr_region);
+ similar = cairo_surface_reference (cairo_get_target (cr_region));
+ cairo_destroy (cr_region);
+
+ /* fill the centre */
+ region = cairo_surface_create_for_region (similar, 20, 20, 20, 20);
+ cairo_surface_destroy (similar);
+ cr_region = cairo_create (region);
+ cairo_surface_destroy (region);
+
+ cairo_set_source_rgb (cr_region, 1, 1, 1);
+ cairo_rectangle (cr_region, 0, 0, 10, 10);
+ cairo_fill (cr_region);
+
+ cairo_set_source_rgb (cr_region, 1, 0, 0);
+ cairo_rectangle (cr_region, 10, 0, 10, 10);
+ cairo_fill (cr_region);
+
+ cairo_set_source_rgb (cr_region, 0, 1, 0);
+ cairo_rectangle (cr_region, 0, 10, 10, 10);
+ cairo_fill (cr_region);
+
+ cairo_set_source_rgb (cr_region, 0, 0, 1);
+ cairo_rectangle (cr_region, 10, 10, 10, 10);
+ cairo_fill (cr_region);
+
+ cairo_set_source_surface (cr, cairo_get_target (cr_region), 20, 20);
+ cairo_destroy (cr_region);
+ cairo_pattern_set_extend (cairo_get_source (cr), CAIRO_EXTEND_REPEAT);
+ cairo_paint (cr);
+
+ return CAIRO_TEST_SUCCESS;
+}
+
+CAIRO_TEST (subsurface_similar_repeat,
+ "Tests source clipping through an intermediate with repeat",
+ "subsurface, repeat", /* keywords */
+ NULL, /* requirements */
+ 60, 60,
+ NULL, draw)
diff --git a/test/subsurface-similar-repeat.ref.png b/test/subsurface-similar-repeat.ref.png
new file mode 100644
index 0000000..c37e22e
Binary files /dev/null and b/test/subsurface-similar-repeat.ref.png differ
diff --git a/test/subsurface.c b/test/subsurface.c
new file mode 100644
index 0000000..f325888
--- /dev/null
+++ b/test/subsurface.c
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2009 Intel Corporation
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of
+ * Intel not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior
+ * permission. Intel makes no representations about the
+ * suitability of this software for any purpose. It is provided "as
+ * is" without express or implied warranty.
+ *
+ * INTEL CORPORATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL INTEL CORPORATION BE LIABLE FOR ANY SPECIAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Chris Wilson <chris at chris-wilson.co.uk>
+ */
+
+#include "cairo-test.h"
+
+static cairo_test_status_t
+draw (cairo_t *cr, int width, int height)
+{
+ cairo_surface_t *region[5];
+ const char *text = "Cairo";
+ int i;
+
+ cairo_set_source_rgb (cr, 1, 1, 1);
+ cairo_paint (cr);
+ cairo_set_source_rgb (cr, 0, 0, 0);
+
+ for (i = 0; i < 5; i++) {
+ cairo_t *cr_region;
+ cairo_text_extents_t extents;
+ char buf[2] = { text[i], '\0' };
+
+ region[i] = cairo_surface_create_for_region (cairo_get_target (cr),
+ 20 * i, 0, 20, 20);
+
+ cr_region = cairo_create (region[i]);
+ cairo_surface_destroy (region[i]);
+
+ cairo_select_font_face (cr_region, "@cairo:",
+ CAIRO_FONT_WEIGHT_NORMAL,
+ CAIRO_FONT_SLANT_NORMAL);
+ cairo_set_font_size (cr_region, 20);
+ cairo_text_extents (cr_region, buf, &extents);
+ cairo_move_to (cr_region,
+ 10 - (extents.width/2 + extents.x_bearing),
+ 10 - (extents.height/2 + extents.y_bearing));
+ cairo_show_text (cr_region, buf);
+
+ region[i] = cairo_surface_reference (cairo_get_target (cr_region));
+ cairo_destroy (cr_region);
+ }
+
+ for (i = 0; i < 5; i++) {
+ cairo_set_source_surface (cr, region[5-i-1], 20 * i, 20);
+ cairo_paint_with_alpha (cr, .5);
+ }
+
+ for (i = 0; i < 5; i++)
+ cairo_surface_destroy (region[i]);
+
+ return CAIRO_TEST_SUCCESS;
+}
+
+CAIRO_TEST (subsurface,
+ "Tests clipping of both source and destination using subsurfaces",
+ "subsurface", /* keywords */
+ NULL, /* requirements */
+ 100, 40,
+ NULL, draw)
diff --git a/test/subsurface.ref.png b/test/subsurface.ref.png
new file mode 100644
index 0000000..54fc0d0
Binary files /dev/null and b/test/subsurface.ref.png differ
commit b8eacbfae1c155f412d84120411103cb610e383b
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Mon Jan 18 18:09:11 2010 +0000
Add surface-offset internal API.
This is a simplified version of the wrapping surface where the target
surface is just a subsurface onto which we wish to draw the current
operation. In particular this is useful for the subsurface API as well
as fallbacks.
diff --git a/src/Makefile.sources b/src/Makefile.sources
index 197f346..6bfef7f 100644
--- a/src/Makefile.sources
+++ b/src/Makefile.sources
@@ -89,6 +89,7 @@ cairo_private = \
cairo-surface-fallback-private.h \
cairo-surface-private.h \
cairo-surface-clipper-private.h \
+ cairo-surface-offset-private.h \
cairo-surface-wrapper-private.h \
cairo-tee-surface-private.h \
cairo-types-private.h \
@@ -150,6 +151,7 @@ cairo_sources = \
cairo-surface.c \
cairo-surface-fallback.c \
cairo-surface-clipper.c \
+ cairo-surface-offset.c \
cairo-surface-wrapper.c \
cairo-system.c \
cairo-tee-surface.c \
diff --git a/src/cairo-surface-offset-private.h b/src/cairo-surface-offset-private.h
new file mode 100644
index 0000000..3968dbf
--- /dev/null
+++ b/src/cairo-surface-offset-private.h
@@ -0,0 +1,95 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2002 University of Southern California
+ * Copyright © 2005 Red Hat, Inc.
+ * Copyright © 2009 Chris Wilson
+ *
+ * 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 University of Southern
+ * California.
+ *
+ * Contributor(s):
+ * Chris Wilson <chris at chris-wilson.co.u>
+ */
+
+#ifndef CAIRO_SURFACE_OFFSET_PRIVATE_H
+#define CAIRO_SURFACE_OFFSET_PRIVATE_H
+
+#include "cairo-types-private.h"
+
+CAIRO_BEGIN_DECLS
+
+cairo_private cairo_status_t
+_cairo_surface_offset_paint (cairo_surface_t *target,
+ int x, int y,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_clip_t *clip);
+
+cairo_private cairo_status_t
+_cairo_surface_offset_mask (cairo_surface_t *target,
+ int x, int y,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ const cairo_pattern_t *mask,
+ cairo_clip_t *clip);
+
+cairo_private cairo_status_t
+_cairo_surface_offset_stroke (cairo_surface_t *surface,
+ int x, int y,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_path_fixed_t *path,
+ const cairo_stroke_style_t *stroke_style,
+ const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm_inverse,
+ double tolerance,
+ cairo_antialias_t antialias,
+ cairo_clip_t *clip);
+
+cairo_private cairo_status_t
+_cairo_surface_offset_fill (cairo_surface_t *surface,
+ int x, int y,
+ cairo_operator_t op,
+ const cairo_pattern_t*source,
+ cairo_path_fixed_t *path,
+ cairo_fill_rule_t fill_rule,
+ double tolerance,
+ cairo_antialias_t antialias,
+ cairo_clip_t *clip);
+
+cairo_private cairo_status_t
+_cairo_surface_offset_glyphs (cairo_surface_t *surface,
+ int x, int y,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_scaled_font_t *scaled_font,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_clip_t *clip);
+
+#endif /* CAIRO_SURFACE_OFFSET_PRIVATE_H */
diff --git a/src/cairo-surface-offset.c b/src/cairo-surface-offset.c
new file mode 100644
index 0000000..36ffcff
--- /dev/null
+++ b/src/cairo-surface-offset.c
@@ -0,0 +1,354 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2005 Red Hat, Inc
+ * Copyright © 2007 Adrian Johnson
+ * Copyright © 2009 Chris Wilson
+ *
+ * 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):
+ * Chris Wilson <chris at chris-wilson.co.uk>
+ */
+
+#include "cairoint.h"
+
+#include "cairo-error-private.h"
+#include "cairo-surface-offset-private.h"
+
+/* A collection of routines to facilitate drawing to an alternate surface. */
+
+static void
+_copy_transformed_pattern (cairo_pattern_t *pattern,
+ const cairo_pattern_t *original,
+ const cairo_matrix_t *ctm_inverse)
+{
+ _cairo_pattern_init_static_copy (pattern, original);
+
+ /* apply device_transform first so that it is transformed by ctm_inverse */
+ if (original->type == CAIRO_PATTERN_TYPE_SURFACE) {
+ cairo_surface_pattern_t *surface_pattern;
+ cairo_surface_t *surface;
+
+ surface_pattern = (cairo_surface_pattern_t *) original;
+ surface = surface_pattern->surface;
+
+ if (_cairo_surface_has_device_transform (surface))
+ _cairo_pattern_transform (pattern, &surface->device_transform);
+ }
+
+ if (! _cairo_matrix_is_identity (ctm_inverse))
+ _cairo_pattern_transform (pattern, ctm_inverse);
+}
+
+cairo_status_t
+_cairo_surface_offset_paint (cairo_surface_t *target,
+ int x, int y,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_clip_t *clip)
+{
+ cairo_status_t status;
+ cairo_clip_t clip_copy, *dev_clip = clip;
+ cairo_pattern_union_t source_copy;
+
+ if (unlikely (target->status))
+ return target->status;
+
+ if (clip && clip->all_clipped)
+ return CAIRO_STATUS_SUCCESS;
+
+ if (x | y) {
+ cairo_matrix_t m;
+
+ if (clip != NULL) {
+ cairo_matrix_init_translate (&m, -x, -y);
+ status = _cairo_clip_init_copy_transformed (&clip_copy, clip, &m);
+ if (unlikely (status))
+ goto FINISH;
+
+ dev_clip = &clip_copy;
+ }
+
+ cairo_matrix_init_translate (&m, x, y);
+ _copy_transformed_pattern (&source_copy.base, source, &m);
+ source = &source_copy.base;
+ }
+
+ status = _cairo_surface_paint (target, op, source, dev_clip);
+
+ FINISH:
+ if (dev_clip != clip)
+ _cairo_clip_reset (dev_clip);
+
+ return status;
+}
+
+cairo_status_t
+_cairo_surface_offset_mask (cairo_surface_t *target,
+ int x, int y,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ const cairo_pattern_t *mask,
+ cairo_clip_t *clip)
+{
+ cairo_status_t status;
+ cairo_clip_t clip_copy, *dev_clip = clip;
+ cairo_pattern_union_t source_copy;
+ cairo_pattern_union_t mask_copy;
+
+ if (unlikely (target->status))
+ return target->status;
+
+ if (clip && clip->all_clipped)
+ return CAIRO_STATUS_SUCCESS;
+
+ if (x | y) {
+ cairo_matrix_t m;
+
+ if (clip != NULL) {
+ cairo_matrix_init_translate (&m, -x, -y);
+ status = _cairo_clip_init_copy_transformed (&clip_copy, clip, &m);
+ if (unlikely (status))
+ goto FINISH;
+
+ dev_clip = &clip_copy;
+ }
+
+ cairo_matrix_init_translate (&m, x, y);
+ _copy_transformed_pattern (&source_copy.base, source, &m);
+ _copy_transformed_pattern (&mask_copy.base, mask, &m);
+ source = &source_copy.base;
+ mask = &mask_copy.base;
+ }
+
+ status = _cairo_surface_mask (target, op,
+ &source_copy.base, &mask_copy.base,
+ dev_clip);
+
+ FINISH:
+ if (dev_clip != clip)
+ _cairo_clip_reset (dev_clip);
+
+ return status;
+}
+
+cairo_status_t
+_cairo_surface_offset_stroke (cairo_surface_t *surface,
+ int x, int y,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_path_fixed_t *path,
+ const cairo_stroke_style_t*stroke_style,
+ const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm_inverse,
+ double tolerance,
+ cairo_antialias_t antialias,
+ cairo_clip_t *clip)
+{
+ cairo_path_fixed_t path_copy, *dev_path = path;
+ cairo_clip_t clip_copy, *dev_clip = clip;
+ cairo_matrix_t dev_ctm = *ctm;
+ cairo_matrix_t dev_ctm_inverse = *ctm_inverse;
+ cairo_pattern_union_t source_copy;
+ cairo_status_t status;
+
+ if (unlikely (surface->status))
+ return surface->status;
+
+ if (clip && clip->all_clipped)
+ return CAIRO_STATUS_SUCCESS;
+
+ if (x | y) {
+ cairo_matrix_t m;
+
+ status = _cairo_path_fixed_init_copy (&path_copy, dev_path);
+ if (unlikely (status))
+ goto FINISH;
+
+ _cairo_path_fixed_translate (&path_copy,
+ _cairo_fixed_from_int (-x),
+ _cairo_fixed_from_int (-y));
+ dev_path = &path_copy;
+
+ cairo_matrix_init_translate (&m, -x, -y);
+ cairo_matrix_multiply (&dev_ctm, &dev_ctm, &m);
+ if (clip != NULL) {
+ status = _cairo_clip_init_copy_transformed (&clip_copy, clip, &m);
+ if (unlikely (status))
+ goto FINISH;
+
+ dev_clip = &clip_copy;
+ }
+
+ cairo_matrix_init_translate (&m, x, y);
+ _copy_transformed_pattern (&source_copy.base, source, &m);
+ source = &source_copy.base;
+ cairo_matrix_multiply (&dev_ctm_inverse, &m, &dev_ctm_inverse);
+ }
+
+ status = _cairo_surface_stroke (surface, op, source,
+ dev_path, stroke_style,
+ &dev_ctm, &dev_ctm_inverse,
+ tolerance, antialias,
+ dev_clip);
+
+ FINISH:
+ if (dev_path != path)
+ _cairo_path_fixed_fini (dev_path);
+ if (dev_clip != clip)
+ _cairo_clip_reset (dev_clip);
+
+ return status;
+}
+
+cairo_status_t
+_cairo_surface_offset_fill (cairo_surface_t *surface,
+ int x, int y,
+ cairo_operator_t op,
+ const cairo_pattern_t*source,
+ cairo_path_fixed_t *path,
+ cairo_fill_rule_t fill_rule,
+ double tolerance,
+ cairo_antialias_t antialias,
+ cairo_clip_t *clip)
+{
+ cairo_status_t status;
+ cairo_path_fixed_t path_copy, *dev_path = path;
+ cairo_clip_t clip_copy, *dev_clip = clip;
+ cairo_pattern_union_t source_copy;
+
+ if (unlikely (surface->status))
+ return surface->status;
+
+ if (clip && clip->all_clipped)
+ return CAIRO_STATUS_SUCCESS;
+
+ if (x | y) {
+ cairo_matrix_t m;
+
+ status = _cairo_path_fixed_init_copy (&path_copy, dev_path);
+ if (unlikely (status))
+ goto FINISH;
+
+ _cairo_path_fixed_translate (&path_copy,
+ _cairo_fixed_from_int (-x),
+ _cairo_fixed_from_int (-y));
+ dev_path = &path_copy;
+
+ if (clip != NULL) {
+ cairo_matrix_init_translate (&m, -x, -y);
+ status = _cairo_clip_init_copy_transformed (&clip_copy, clip, &m);
+ if (unlikely (status))
+ goto FINISH;
+
+ dev_clip = &clip_copy;
+ }
+
+ cairo_matrix_init_translate (&m, x, y);
+ _copy_transformed_pattern (&source_copy.base, source, &m);
+ source = &source_copy.base;
+ }
+
+ status = _cairo_surface_fill (surface, op, source,
+ dev_path, fill_rule,
+ tolerance, antialias,
+ dev_clip);
+
+ FINISH:
+ if (dev_path != path)
+ _cairo_path_fixed_fini (dev_path);
+ if (dev_clip != clip)
+ _cairo_clip_reset (dev_clip);
+
+ return status;
+}
+
+cairo_status_t
+_cairo_surface_offset_glyphs (cairo_surface_t *surface,
+ int x, int y,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_scaled_font_t *scaled_font,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_clip_t *clip)
+{
+ cairo_status_t status;
+ cairo_clip_t clip_copy, *dev_clip = clip;
+ cairo_pattern_union_t source_copy;
+ cairo_glyph_t *dev_glyphs;
+ int i;
+
+ if (unlikely (surface->status))
+ return surface->status;
+
+ if (clip && clip->all_clipped)
+ return CAIRO_STATUS_SUCCESS;
+
+ dev_glyphs = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t));
+ if (dev_glyphs == NULL)
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+ memcpy (dev_glyphs, glyphs, sizeof (cairo_glyph_t) * num_glyphs);
+
+ if (x | y) {
+ cairo_matrix_t m;
+
+ if (clip != NULL) {
+ cairo_matrix_init_translate (&m, -x, -y);
+ status = _cairo_clip_init_copy_transformed (&clip_copy, clip, &m);
+ if (unlikely (status))
+ goto FINISH;
+
+ dev_clip = &clip_copy;
+ }
+
+ cairo_matrix_init_translate (&m, x, y);
+ _copy_transformed_pattern (&source_copy.base, source, &m);
+ source = &source_copy.base;
+
+ for (i = 0; i < num_glyphs; i++) {
+ dev_glyphs[i].x -= x;
+ dev_glyphs[i].y -= y;
+ }
+ }
+
+ status = _cairo_surface_show_text_glyphs (surface, op, source,
+ NULL, 0,
+ dev_glyphs, num_glyphs,
+ NULL, 0, 0,
+ scaled_font,
+ dev_clip);
+
+ FINISH:
+ if (dev_clip != clip)
+ _cairo_clip_reset (dev_clip);
+ free (dev_glyphs);
+
+ return status;
+}
commit f2c32d01836379766bc287edf77381123767daeb
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Tue Jan 19 18:06:54 2010 +0000
Unify the two freed object pools
Discard some duplicate code and shared a single freed object pointer
pool between the pattern and clip.
diff --git a/src/Makefile.sources b/src/Makefile.sources
index 6dbe3fb..197f346 100644
--- a/src/Makefile.sources
+++ b/src/Makefile.sources
@@ -63,6 +63,7 @@ cairo_private = \
cairo-fixed-private.h \
cairo-fixed-type-private.h \
cairo-freelist-private.h \
+ cairo-freed-pool-private.h \
cairo-gstate-private.h \
cairo-hash-private.h \
cairo-image-info-private.h \
@@ -116,6 +117,7 @@ cairo_sources = \
cairo-font-face-twin-data.c \
cairo-font-options.c \
cairo-freelist.c \
+ cairo-freed-pool.c \
cairo-gstate.c \
cairo-hash.c \
cairo-hull.c \
diff --git a/src/cairo-clip.c b/src/cairo-clip.c
index 2a50385..b3d3034 100644
--- a/src/cairo-clip.c
+++ b/src/cairo-clip.c
@@ -42,95 +42,13 @@
#include "cairoint.h"
#include "cairo-clip-private.h"
#include "cairo-error-private.h"
+#include "cairo-freed-pool-private.h"
#include "cairo-path-fixed-private.h"
#include "cairo-region-private.h"
-/* Keep a stash of recently freed clip_paths, since we need to
- * reallocate them frequently.
- */
-#define MAX_FREED_POOL_SIZE 4
-typedef struct {
- void *pool[MAX_FREED_POOL_SIZE];
- int top;
-} freed_pool_t;
-
+#if HAS_FREED_POOL
static freed_pool_t clip_path_pool;
-
-static void *
-_atomic_fetch (void **slot)
-{
- return _cairo_atomic_ptr_cmpxchg (slot, *slot, NULL);
-}
-
-static cairo_bool_t
-_atomic_store (void **slot, void *ptr)
-{
- return _cairo_atomic_ptr_cmpxchg (slot, NULL, ptr) == NULL;
-}
-
-static void *
-_freed_pool_get (freed_pool_t *pool)
-{
- void *ptr;
- int i;
-
- i = pool->top - 1;
- if (i < 0)
- i = 0;
-
- ptr = _atomic_fetch (&pool->pool[i]);
- if (ptr != NULL) {
- pool->top = i;
- return ptr;
- }
-
- /* either empty or contended */
- for (i = ARRAY_LENGTH (pool->pool); i--;) {
- ptr = _atomic_fetch (&pool->pool[i]);
- if (ptr != NULL) {
- pool->top = i;
- return ptr;
- }
- }
-
- /* empty */
- pool->top = 0;
- return NULL;
-}
-
-static void
-_freed_pool_put (freed_pool_t *pool, void *ptr)
-{
- int i = pool->top;
-
- if (_atomic_store (&pool->pool[i], ptr)) {
- pool->top = i + 1;
- return;
- }
-
- /* either full or contended */
- for (i = 0; i < ARRAY_LENGTH (pool->pool); i++) {
- if (_atomic_store (&pool->pool[i], ptr)) {
- pool->top = i + 1;
- return;
- }
- }
-
- /* full */
- pool->top = ARRAY_LENGTH (pool->pool);
- free (ptr);
-}
-
-static void
-_freed_pool_reset (freed_pool_t *pool)
-{
- int i;
-
- for (i = 0; i < ARRAY_LENGTH (pool->pool); i++) {
- free (pool->pool[i]);
- pool->pool[i] = NULL;
- }
-}
+#endif
static cairo_clip_path_t *
_cairo_clip_path_create (cairo_clip_t *clip)
diff --git a/src/cairo-freed-pool-private.h b/src/cairo-freed-pool-private.h
new file mode 100644
index 0000000..c8a6902
--- /dev/null
+++ b/src/cairo-freed-pool-private.h
@@ -0,0 +1,121 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2009 Chris Wilson
+ *
+ * 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 University of Southern
+ * California.
+ *
+ * Contributor(s):
+ * Chris Wilson <chris at chris-wilson.co.uk>
+ */
+
+#ifndef CAIRO_FREED_POOL_H
+#define CAIRO_FREED_POOL_H
+
+#include "cairoint.h"
+#include "cairo-atomic-private.h"
+
+#if HAS_ATOMIC_OPS
+/* Keep a stash of recently freed clip_paths, since we need to
+ * reallocate them frequently.
+ */
+#define MAX_FREED_POOL_SIZE 4
+typedef struct {
+ void *pool[MAX_FREED_POOL_SIZE];
+ int top;
+} freed_pool_t;
+
+static inline void *
+_atomic_fetch (void **slot)
+{
+ return _cairo_atomic_ptr_cmpxchg (slot, *slot, NULL);
+}
+
+static inline cairo_bool_t
+_atomic_store (void **slot, void *ptr)
+{
+ return _cairo_atomic_ptr_cmpxchg (slot, NULL, ptr) == NULL;
+}
+
+cairo_private void *
+_freed_pool_get_search (freed_pool_t *pool);
+
+static inline void *
+_freed_pool_get (freed_pool_t *pool)
+{
+ void *ptr;
+ int i;
+
+ i = pool->top - 1;
+ if (i < 0)
+ i = 0;
+
+ ptr = _atomic_fetch (&pool->pool[i]);
+ if (likely (ptr != NULL)) {
+ pool->top = i;
+ return ptr;
+ }
+
+ /* either empty or contended */
+ return _freed_pool_get_search (pool);
+}
+
+cairo_private void
+_freed_pool_put_search (freed_pool_t *pool, void *ptr);
+
+static inline void
+_freed_pool_put (freed_pool_t *pool, void *ptr)
+{
+ int i;
+
+ i = pool->top;
+ if (likely (_atomic_store (&pool->pool[i], ptr))) {
+ pool->top = i + 1;
+ return;
+ }
+
+ /* either full or contended */
+ _freed_pool_put_search (pool, ptr);
+}
+
+cairo_private void
+_freed_pool_reset (freed_pool_t *pool);
+
+#define HAS_FREED_POOL 1
+
+#else
+
+typedef int freed_pool_t;
+
+#define _freed_pool_get(pool) NULL
+#define _freed_pool_put(pool, ptr) free(ptr)
+#define _freed_pool_reset(ptr)
+
+#endif
+
+#endif /* CAIRO_FREED_POOL_PRIVATE_H */
diff --git a/src/cairo-freed-pool.c b/src/cairo-freed-pool.c
new file mode 100644
index 0000000..e225db4
--- /dev/null
+++ b/src/cairo-freed-pool.c
@@ -0,0 +1,91 @@
+/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2009 Chris Wilson
+ *
+ * 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 University of Southern
+ * California.
+ *
+ * Contributor(s):
+ * Chris Wilson <chris at chris-wilson.co.uk>
+ */
+
+#include "cairoint.h"
+
+#include "cairo-freed-pool-private.h"
+
+#if HAS_FREED_POOL
+
+void *
+_freed_pool_get_search (freed_pool_t *pool)
+{
+ void *ptr;
+ int i;
+
+ for (i = ARRAY_LENGTH (pool->pool); i--;) {
+ ptr = _atomic_fetch (&pool->pool[i]);
+ if (ptr != NULL) {
+ pool->top = i;
+ return ptr;
+ }
+ }
+
+ /* empty */
+ pool->top = 0;
+ return NULL;
+}
+
+void
+_freed_pool_put_search (freed_pool_t *pool, void *ptr)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_LENGTH (pool->pool); i++) {
+ if (_atomic_store (&pool->pool[i], ptr)) {
+ pool->top = i + 1;
+ return;
+ }
+ }
+
+ /* full */
+ pool->top = ARRAY_LENGTH (pool->pool);
+ free (ptr);
+}
+
+void
+_freed_pool_reset (freed_pool_t *pool)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_LENGTH (pool->pool); i++) {
+ free (pool->pool[i]);
+ pool->pool[i] = NULL;
+ }
+}
+
+#endif
diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c
index f5e5b9d..00d6c07 100644
--- a/src/cairo-pattern.c
+++ b/src/cairo-pattern.c
@@ -30,6 +30,11 @@
#include "cairoint.h"
#include "cairo-error-private.h"
+#include "cairo-freed-pool-private.h"
+
+#if HAS_FREED_POOL
+static freed_pool_t freed_pattern_pool[4];
+#endif
static const cairo_solid_pattern_t _cairo_pattern_nil = {
{ CAIRO_PATTERN_TYPE_SOLID, /* type */
@@ -456,98 +461,6 @@ _cairo_pattern_init_radial (cairo_radial_pattern_t *pattern,
pattern->r2 = _cairo_fixed_from_double (fabs (radius1));
}
-/* We use a small freed pattern cache here, because we don't want to
- * constantly reallocate simple colors. */
-#define MAX_PATTERN_CACHE_SIZE 4
-typedef struct {
- void *pool[MAX_PATTERN_CACHE_SIZE];
- int top;
-} freed_pool_t;
-
-static freed_pool_t freed_pattern_pool[4];
-
-static void *
-_atomic_fetch (void **slot)
-{
- return _cairo_atomic_ptr_cmpxchg (slot, *slot, NULL);
-}
-
-static cairo_bool_t
-_atomic_store (void **slot, void *pattern)
-{
- return _cairo_atomic_ptr_cmpxchg (slot, NULL, pattern) == NULL;
-}
-
-static void *
-_freed_pattern_get (freed_pool_t *pool)
-{
- cairo_pattern_t *pattern;
- int i;
-
- i = pool->top - 1;
- if (i < 0)
- i = 0;
-
- pattern = _atomic_fetch (&pool->pool[i]);
- if (likely (pattern != NULL)) {
- pool->top = i;
- return pattern;
- }
-
- /* either empty or contended */
- for (i = ARRAY_LENGTH (pool->pool); i--;) {
- pattern = _atomic_fetch (&pool->pool[i]);
- if (pattern != NULL) {
- pool->top = i;
- return pattern;
- }
- }
-
- /* empty */
- pool->top = 0;
- return NULL;
-}
-
-static void
-_freed_pattern_put (freed_pool_t *pool,
- cairo_pattern_t *pattern)
-{
- int i = pool->top;
-
- if (likely (i < ARRAY_LENGTH (pool->pool) &&
- _atomic_store (&pool->pool[i], pattern)))
- {
- pool->top = i + 1;
- return;
- }
-
- /* either full or contended */
- for (i = 0; i < ARRAY_LENGTH (pool->pool); i++) {
- if (_atomic_store (&pool->pool[i], pattern)) {
- pool->top = i + 1;
- return;
- }
- }
-
- /* full */
- pool->top = ARRAY_LENGTH (pool->pool);
- free (pattern);
-}
-
-static void
-_freed_patterns_reset (void)
-{
- int i, j;
-
- for (i = 0; i < ARRAY_LENGTH (freed_pattern_pool); i++) {
- freed_pool_t *pool = &freed_pattern_pool[i];
- for (j = 0; j < ARRAY_LENGTH (pool->pool); j++) {
- free (pool->pool[j]);
- pool->pool[j] = NULL;
- }
- }
-}
-
cairo_pattern_t *
_cairo_pattern_create_solid (const cairo_color_t *color,
cairo_content_t content)
@@ -555,7 +468,7 @@ _cairo_pattern_create_solid (const cairo_color_t *color,
cairo_solid_pattern_t *pattern;
pattern =
- _freed_pattern_get (&freed_pattern_pool[CAIRO_PATTERN_TYPE_SOLID]);
+ _freed_pool_get (&freed_pattern_pool[CAIRO_PATTERN_TYPE_SOLID]);
if (unlikely (pattern == NULL)) {
/* None cached, need to create a new pattern. */
pattern = malloc (sizeof (cairo_solid_pattern_t));
@@ -694,7 +607,7 @@ cairo_pattern_create_for_surface (cairo_surface_t *surface)
return _cairo_pattern_create_in_error (surface->status);
pattern =
- _freed_pattern_get (&freed_pattern_pool[CAIRO_PATTERN_TYPE_SURFACE]);
+ _freed_pool_get (&freed_pattern_pool[CAIRO_PATTERN_TYPE_SURFACE]);
if (unlikely (pattern == NULL)) {
pattern = malloc (sizeof (cairo_surface_pattern_t));
if (unlikely (pattern == NULL)) {
@@ -744,7 +657,7 @@ cairo_pattern_create_linear (double x0, double y0, double x1, double y1)
cairo_linear_pattern_t *pattern;
pattern =
- _freed_pattern_get (&freed_pattern_pool[CAIRO_PATTERN_TYPE_LINEAR]);
+ _freed_pool_get (&freed_pattern_pool[CAIRO_PATTERN_TYPE_LINEAR]);
if (unlikely (pattern == NULL)) {
pattern = malloc (sizeof (cairo_linear_pattern_t));
if (unlikely (pattern == NULL)) {
@@ -796,7 +709,7 @@ cairo_pattern_create_radial (double cx0, double cy0, double radius0,
cairo_radial_pattern_t *pattern;
pattern =
- _freed_pattern_get (&freed_pattern_pool[CAIRO_PATTERN_TYPE_RADIAL]);
+ _freed_pool_get (&freed_pattern_pool[CAIRO_PATTERN_TYPE_RADIAL]);
if (unlikely (pattern == NULL)) {
pattern = malloc (sizeof (cairo_radial_pattern_t));
if (unlikely (pattern == NULL)) {
@@ -900,7 +813,7 @@ cairo_pattern_destroy (cairo_pattern_t *pattern)
_cairo_pattern_fini (pattern);
/* maintain a small cache of freed patterns */
- _freed_pattern_put (&freed_pattern_pool[type], pattern);
+ _freed_pool_put (&freed_pattern_pool[type], pattern);
}
slim_hidden_def (cairo_pattern_destroy);
@@ -3135,6 +3048,12 @@ cairo_pattern_get_radial_circles (cairo_pattern_t *pattern,
void
_cairo_pattern_reset_static_data (void)
{
- _freed_patterns_reset ();
+#if HAS_FREED_POOL
+ int i;
+
+ for (i = 0; i < ARRAY_LENGTH (freed_pattern_pool); i++)
+ _freed_pool_reset (&freed_pattern_pool[i]);
+#endif
+
_cairo_pattern_reset_solid_surface_cache ();
}
commit cfd204824fada7d2b4bcf4994c4200ae9b5a8b26
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Mon Jan 18 18:20:16 2010 +0000
Constify stroke style and matrices.
As a simple step to ensure that we do not inadvertently modify (or at least
generate compiler warns if we try) user data, mark the incoming style
and matrices as constant.
diff --git a/src/cairo-analysis-surface.c b/src/cairo-analysis-surface.c
index 019dc30..b777abc 100644
--- a/src/cairo-analysis-surface.c
+++ b/src/cairo-analysis-surface.c
@@ -397,9 +397,9 @@ _cairo_analysis_surface_stroke (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_path_fixed_t *path,
- cairo_stroke_style_t *style,
- cairo_matrix_t *ctm,
- cairo_matrix_t *ctm_inverse,
+ const cairo_stroke_style_t *style,
+ const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
cairo_clip_t *clip)
@@ -832,9 +832,9 @@ typedef cairo_int_status_t
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_path_fixed_t *path,
- cairo_stroke_style_t *style,
- cairo_matrix_t *ctm,
- cairo_matrix_t *ctm_inverse,
+ const cairo_stroke_style_t *style,
+ const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
cairo_clip_t *clip);
diff --git a/src/cairo-paginated-surface.c b/src/cairo-paginated-surface.c
index b5f619b..80e4b72 100644
--- a/src/cairo-paginated-surface.c
+++ b/src/cairo-paginated-surface.c
@@ -544,9 +544,9 @@ _cairo_paginated_surface_stroke (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_path_fixed_t *path,
- cairo_stroke_style_t *style,
- cairo_matrix_t *ctm,
- cairo_matrix_t *ctm_inverse,
+ const cairo_stroke_style_t *style,
+ const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
cairo_clip_t *clip)
diff --git a/src/cairo-path-bounds.c b/src/cairo-path-bounds.c
index d3bc449..7b7ae68 100644
--- a/src/cairo-path-bounds.c
+++ b/src/cairo-path-bounds.c
@@ -246,8 +246,8 @@ _cairo_path_fixed_fill_extents (const cairo_path_fixed_t *path,
/* Adjusts the fill extents (above) by the device-space pen. */
void
_cairo_path_fixed_approximate_stroke_extents (const cairo_path_fixed_t *path,
- cairo_stroke_style_t *style,
- const cairo_matrix_t *ctm,
+ const cairo_stroke_style_t *style,
+ const const cairo_matrix_t *ctm,
cairo_rectangle_int_t *extents)
{
cairo_path_bounder_t bounder;
@@ -295,7 +295,7 @@ _cairo_path_fixed_approximate_stroke_extents (const cairo_path_fixed_t *path,
cairo_status_t
_cairo_path_fixed_stroke_extents (const cairo_path_fixed_t *path,
- cairo_stroke_style_t *stroke_style,
+ const cairo_stroke_style_t *stroke_style,
const cairo_matrix_t *ctm,
const cairo_matrix_t *ctm_inverse,
double tolerance,
diff --git a/src/cairo-path-stroke.c b/src/cairo-path-stroke.c
index 9c79d77..264157f 100644
--- a/src/cairo-path-stroke.c
+++ b/src/cairo-path-stroke.c
@@ -57,7 +57,7 @@ typedef struct _cairo_stroker_dash {
} cairo_stroker_dash_t;
typedef struct cairo_stroker {
- cairo_stroke_style_t *style;
+ cairo_stroke_style_t style;
const cairo_matrix_t *ctm;
const cairo_matrix_t *ctm_inverse;
@@ -164,14 +164,14 @@ _cairo_stroker_dash_init (cairo_stroker_dash_t *dash,
static cairo_status_t
_cairo_stroker_init (cairo_stroker_t *stroker,
- cairo_stroke_style_t *stroke_style,
+ const cairo_stroke_style_t *stroke_style,
const cairo_matrix_t *ctm,
const cairo_matrix_t *ctm_inverse,
double tolerance)
{
cairo_status_t status;
- stroker->style = stroke_style;
+ stroker->style = *stroke_style;
stroker->ctm = ctm;
stroker->ctm_inverse = ctm_inverse;
stroker->tolerance = tolerance;
@@ -214,7 +214,7 @@ _cairo_stroker_limit (cairo_stroker_t *stroker,
* of the bounds but which might generate rendering that's within bounds.
*/
- _cairo_stroke_style_max_distance_from_path (stroker->style, stroker->ctm,
+ _cairo_stroke_style_max_distance_from_path (&stroker->style, stroker->ctm,
&dx, &dy);
fdx = _cairo_fixed_from_double (dx);
@@ -457,7 +457,7 @@ _cairo_stroker_join (cairo_stroker_t *stroker,
outpt = &out->cw;
}
- switch (stroker->style->line_join) {
+ switch (stroker->style.line_join) {
case CAIRO_LINE_JOIN_ROUND:
/* construct a fan around the common midpoint */
return _tessellate_fan (stroker,
@@ -471,7 +471,7 @@ _cairo_stroker_join (cairo_stroker_t *stroker,
/* dot product of incoming slope vector with outgoing slope vector */
double in_dot_out = -in->usr_vector.x * out->usr_vector.x +
-in->usr_vector.y * out->usr_vector.y;
- double ml = stroker->style->miter_limit;
+ double ml = stroker->style.miter_limit;
/* Check the miter limit -- lines meeting at an acute angle
* can generate long miters, the limit converts them to bevel
@@ -666,7 +666,7 @@ static cairo_status_t
_cairo_stroker_add_cap (cairo_stroker_t *stroker,
const cairo_stroke_face_t *f)
{
- switch (stroker->style->line_cap) {
+ switch (stroker->style.line_cap) {
case CAIRO_LINE_CAP_ROUND: {
cairo_slope_t slope;
@@ -688,8 +688,8 @@ _cairo_stroker_add_cap (cairo_stroker_t *stroker,
dx = f->usr_vector.x;
dy = f->usr_vector.y;
- dx *= stroker->style->line_width / 2.0;
- dy *= stroker->style->line_width / 2.0;
+ dx *= stroker->style.line_width / 2.0;
+ dy *= stroker->style.line_width / 2.0;
cairo_matrix_transform_distance (stroker->ctm, &dx, &dy);
fvector.dx = _cairo_fixed_from_double (dx);
fvector.dy = _cairo_fixed_from_double (dy);
@@ -827,13 +827,13 @@ _compute_face (const cairo_point_t *point, cairo_slope_t *dev_slope,
*/
if (stroker->ctm_det_positive)
{
- face_dx = - slope_dy * (stroker->style->line_width / 2.0);
- face_dy = slope_dx * (stroker->style->line_width / 2.0);
+ face_dx = - slope_dy * (stroker->style.line_width / 2.0);
+ face_dy = slope_dx * (stroker->style.line_width / 2.0);
}
else
{
- face_dx = slope_dy * (stroker->style->line_width / 2.0);
- face_dy = - slope_dx * (stroker->style->line_width / 2.0);
+ face_dx = slope_dy * (stroker->style.line_width / 2.0);
+ face_dy = - slope_dx * (stroker->style.line_width / 2.0);
}
/* back to device space */
@@ -867,7 +867,7 @@ _cairo_stroker_add_caps (cairo_stroker_t *stroker)
if (stroker->has_initial_sub_path
&& ! stroker->has_first_face
&& ! stroker->has_current_face
- && stroker->style->line_cap == CAIRO_LINE_JOIN_ROUND)
+ && stroker->style.line_cap == CAIRO_LINE_JOIN_ROUND)
{
/* pick an arbitrary slope to use */
double dx = 1.0, dy = 0.0;
@@ -1232,8 +1232,8 @@ _cairo_stroker_curve_to (void *closure,
/* Temporarily modify the stroker to use round joins to guarantee
* smooth stroked curves. */
- line_join_save = stroker->style->line_join;
- stroker->style->line_join = CAIRO_LINE_JOIN_ROUND;
+ line_join_save = stroker->style.line_join;
+ stroker->style.line_join = CAIRO_LINE_JOIN_ROUND;
status = _cairo_spline_decompose (&spline, stroker->tolerance);
if (unlikely (status))
@@ -1259,7 +1259,7 @@ _cairo_stroker_curve_to (void *closure,
stroker->current_face = face;
}
- stroker->style->line_join = line_join_save;
+ stroker->style.line_join = line_join_save;
return CAIRO_STATUS_SUCCESS;
}
@@ -1300,9 +1300,9 @@ _cairo_stroker_close_path (void *closure)
cairo_status_t
_cairo_path_fixed_stroke_to_shaper (cairo_path_fixed_t *path,
- cairo_stroke_style_t *stroke_style,
- cairo_matrix_t *ctm,
- cairo_matrix_t *ctm_inverse,
+ const cairo_stroke_style_t *stroke_style,
+ const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_status_t (*add_triangle) (void *closure,
const cairo_point_t triangle[3]),
@@ -1351,7 +1351,7 @@ BAIL:
cairo_status_t
_cairo_path_fixed_stroke_to_polygon (const cairo_path_fixed_t *path,
- cairo_stroke_style_t *stroke_style,
+ const cairo_stroke_style_t *stroke_style,
const cairo_matrix_t *ctm,
const cairo_matrix_t *ctm_inverse,
double tolerance,
@@ -1395,7 +1395,7 @@ BAIL:
cairo_status_t
_cairo_path_fixed_stroke_to_traps (const cairo_path_fixed_t *path,
- cairo_stroke_style_t *stroke_style,
+ const cairo_stroke_style_t *stroke_style,
const cairo_matrix_t *ctm,
const cairo_matrix_t *ctm_inverse,
double tolerance,
@@ -1422,11 +1422,11 @@ _cairo_path_fixed_stroke_to_traps (const cairo_path_fixed_t *path,
_cairo_polygon_limit (&polygon, traps->limits, traps->num_limits);
status = _cairo_path_fixed_stroke_to_polygon (path,
- stroke_style,
- ctm,
- ctm_inverse,
- tolerance,
- &polygon);
+ stroke_style,
+ ctm,
+ ctm_inverse,
+ tolerance,
+ &polygon);
if (unlikely (status))
goto BAIL;
@@ -1450,7 +1450,7 @@ typedef struct _segment_t {
} segment_t;
typedef struct _cairo_rectilinear_stroker {
- cairo_stroke_style_t *stroke_style;
+ const cairo_stroke_style_t *stroke_style;
const cairo_matrix_t *ctm;
cairo_fixed_t half_line_width;
@@ -1487,7 +1487,7 @@ _cairo_rectilinear_stroker_limit (cairo_rectilinear_stroker_t *stroker,
static void
_cairo_rectilinear_stroker_init (cairo_rectilinear_stroker_t *stroker,
- cairo_stroke_style_t *stroke_style,
+ const cairo_stroke_style_t *stroke_style,
const cairo_matrix_t *ctm,
cairo_traps_t *traps)
{
@@ -1979,7 +1979,7 @@ _cairo_rectilinear_stroker_close_path (void *closure)
cairo_int_status_t
_cairo_path_fixed_stroke_rectilinear_to_traps (const cairo_path_fixed_t *path,
- cairo_stroke_style_t *stroke_style,
+ const cairo_stroke_style_t *stroke_style,
const cairo_matrix_t *ctm,
cairo_traps_t *traps)
{
diff --git a/src/cairo-pdf-operators-private.h b/src/cairo-pdf-operators-private.h
index 4ef0fca..839ae55 100644
--- a/src/cairo-pdf-operators-private.h
+++ b/src/cairo-pdf-operators-private.h
@@ -132,16 +132,16 @@ _cairo_pdf_operators_clip (cairo_pdf_operators_t *pdf_operators,
cairo_fill_rule_t fill_rule);
cairo_private cairo_int_status_t
-_cairo_pdf_operators_emit_stroke_style (cairo_pdf_operators_t *pdf_operators,
- cairo_stroke_style_t *style,
- double scale);
+_cairo_pdf_operators_emit_stroke_style (cairo_pdf_operators_t *pdf_operators,
+ const cairo_stroke_style_t *style,
+ double scale);
cairo_private cairo_int_status_t
-_cairo_pdf_operators_stroke (cairo_pdf_operators_t *pdf_operators,
+_cairo_pdf_operators_stroke (cairo_pdf_operators_t *pdf_operators,
cairo_path_fixed_t *path,
- cairo_stroke_style_t *style,
- cairo_matrix_t *ctm,
- cairo_matrix_t *ctm_inverse);
+ const cairo_stroke_style_t *style,
+ const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm_inverse);
cairo_private cairo_int_status_t
_cairo_pdf_operators_fill (cairo_pdf_operators_t *pdf_operators,
@@ -149,12 +149,12 @@ _cairo_pdf_operators_fill (cairo_pdf_operators_t *pdf_operators,
cairo_fill_rule_t fill_rule);
cairo_private cairo_int_status_t
-_cairo_pdf_operators_fill_stroke (cairo_pdf_operators_t *pdf_operators,
+_cairo_pdf_operators_fill_stroke (cairo_pdf_operators_t *pdf_operators,
cairo_path_fixed_t *path,
- cairo_fill_rule_t fill_rule,
- cairo_stroke_style_t *style,
- cairo_matrix_t *ctm,
- cairo_matrix_t *ctm_inverse);
+ cairo_fill_rule_t fill_rule,
+ const cairo_stroke_style_t *style,
+ const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm_inverse);
cairo_private cairo_int_status_t
_cairo_pdf_operators_show_text_glyphs (cairo_pdf_operators_t *pdf_operators,
diff --git a/src/cairo-pdf-operators.c b/src/cairo-pdf-operators.c
index e4a0723..8c3849b 100644
--- a/src/cairo-pdf-operators.c
+++ b/src/cairo-pdf-operators.c
@@ -544,9 +544,9 @@ _cairo_pdf_line_join (cairo_line_join_t join)
}
cairo_int_status_t
-_cairo_pdf_operators_emit_stroke_style (cairo_pdf_operators_t *pdf_operators,
- cairo_stroke_style_t *style,
- double scale)
+_cairo_pdf_operators_emit_stroke_style (cairo_pdf_operators_t *pdf_operators,
+ const cairo_stroke_style_t *style,
+ double scale)
{
double *dash = style->dash;
int num_dashes = style->num_dashes;
@@ -701,12 +701,12 @@ _cairo_matrix_factor_out_scale (cairo_matrix_t *m, double *scale)
}
static cairo_int_status_t
-_cairo_pdf_operators_emit_stroke (cairo_pdf_operators_t *pdf_operators,
- cairo_path_fixed_t *path,
- cairo_stroke_style_t *style,
- cairo_matrix_t *ctm,
- cairo_matrix_t *ctm_inverse,
- const char *pdf_operator)
+_cairo_pdf_operators_emit_stroke (cairo_pdf_operators_t *pdf_operators,
+ cairo_path_fixed_t *path,
+ const cairo_stroke_style_t *style,
+ const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm_inverse,
+ const char *pdf_operator)
{
cairo_status_t status;
cairo_matrix_t m, path_transform;
@@ -792,11 +792,11 @@ _cairo_pdf_operators_emit_stroke (cairo_pdf_operators_t *pdf_operators,
}
cairo_int_status_t
-_cairo_pdf_operators_stroke (cairo_pdf_operators_t *pdf_operators,
- cairo_path_fixed_t *path,
- cairo_stroke_style_t *style,
- cairo_matrix_t *ctm,
- cairo_matrix_t *ctm_inverse)
+_cairo_pdf_operators_stroke (cairo_pdf_operators_t *pdf_operators,
+ cairo_path_fixed_t *path,
+ const cairo_stroke_style_t *style,
+ const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm_inverse)
{
return _cairo_pdf_operators_emit_stroke (pdf_operators,
path,
@@ -846,12 +846,12 @@ _cairo_pdf_operators_fill (cairo_pdf_operators_t *pdf_operators,
}
cairo_int_status_t
-_cairo_pdf_operators_fill_stroke (cairo_pdf_operators_t *pdf_operators,
+_cairo_pdf_operators_fill_stroke (cairo_pdf_operators_t *pdf_operators,
cairo_path_fixed_t *path,
- cairo_fill_rule_t fill_rule,
- cairo_stroke_style_t *style,
- cairo_matrix_t *ctm,
- cairo_matrix_t *ctm_inverse)
+ cairo_fill_rule_t fill_rule,
+ const cairo_stroke_style_t *style,
+ const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm_inverse)
{
const char *operator;
diff --git a/src/cairo-pdf-surface-private.h b/src/cairo-pdf-surface-private.h
index 5c28f70..a509699 100644
--- a/src/cairo-pdf-surface-private.h
+++ b/src/cairo-pdf-surface-private.h
@@ -95,10 +95,9 @@ typedef enum _cairo_pdf_operation {
PDF_SHOW_GLYPHS
} cairo_pdf_operation_t;
-typedef struct _cairo_pdf_smask_group
-{
- double width;
- double height;
+typedef struct _cairo_pdf_smask_group {
+ double width;
+ double height;
cairo_pdf_resource_t group_res;
cairo_pdf_operation_t operation;
cairo_pattern_t *source;
@@ -106,10 +105,10 @@ typedef struct _cairo_pdf_smask_group
cairo_pattern_t *mask;
cairo_path_fixed_t path;
cairo_fill_rule_t fill_rule;
- cairo_stroke_style_t *style;
+ cairo_stroke_style_t style;
cairo_matrix_t ctm;
cairo_matrix_t ctm_inverse;
- char *utf8;
+ char *utf8;
int utf8_len;
cairo_glyph_t *glyphs;
int num_glyphs;
diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c
index 515e9f6..46928aa 100644
--- a/src/cairo-pdf-surface.c
+++ b/src/cairo-pdf-surface.c
@@ -4889,7 +4889,7 @@ _cairo_pdf_surface_write_smask_group (cairo_pdf_surface_t *surface,
case PDF_STROKE:
status = _cairo_pdf_operators_stroke (&surface->pdf_operators,
&group->path,
- group->style,
+ &group->style,
&group->ctm,
&group->ctm_inverse);
break;
@@ -5509,9 +5509,9 @@ _cairo_pdf_surface_stroke (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_path_fixed_t *path,
- cairo_stroke_style_t *style,
- cairo_matrix_t *ctm,
- cairo_matrix_t *ctm_inverse,
+ const cairo_stroke_style_t *style,
+ const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
cairo_clip_t *clip)
@@ -5570,7 +5570,7 @@ _cairo_pdf_surface_stroke (void *abstract_surface,
return status;
}
- group->style = style;
+ group->style = *style;
group->ctm = *ctm;
group->ctm_inverse = *ctm_inverse;
status = _cairo_pdf_surface_add_smask_group (surface, group);
@@ -5750,21 +5750,21 @@ _cairo_pdf_surface_fill (void *abstract_surface,
}
static cairo_int_status_t
-_cairo_pdf_surface_fill_stroke (void *abstract_surface,
- cairo_operator_t fill_op,
- const cairo_pattern_t *fill_source,
- cairo_fill_rule_t fill_rule,
- double fill_tolerance,
- cairo_antialias_t fill_antialias,
- cairo_path_fixed_t *path,
- cairo_operator_t stroke_op,
- const cairo_pattern_t *stroke_source,
- cairo_stroke_style_t *stroke_style,
- cairo_matrix_t *stroke_ctm,
- cairo_matrix_t *stroke_ctm_inverse,
- double stroke_tolerance,
- cairo_antialias_t stroke_antialias,
- cairo_clip_t *clip)
+_cairo_pdf_surface_fill_stroke (void *abstract_surface,
+ cairo_operator_t fill_op,
+ const cairo_pattern_t *fill_source,
+ cairo_fill_rule_t fill_rule,
+ double fill_tolerance,
+ cairo_antialias_t fill_antialias,
+ cairo_path_fixed_t *path,
+ cairo_operator_t stroke_op,
+ const cairo_pattern_t *stroke_source,
+ const cairo_stroke_style_t *stroke_style,
+ const cairo_matrix_t *stroke_ctm,
+ const cairo_matrix_t *stroke_ctm_inverse,
+ double stroke_tolerance,
+ cairo_antialias_t stroke_antialias,
+ cairo_clip_t *clip)
{
cairo_pdf_surface_t *surface = abstract_surface;
cairo_status_t status;
diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c
index 72dcbd4..d2000ec 100644
--- a/src/cairo-ps-surface.c
+++ b/src/cairo-ps-surface.c
@@ -3498,9 +3498,9 @@ _cairo_ps_surface_stroke (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_path_fixed_t *path,
- cairo_stroke_style_t *style,
- cairo_matrix_t *ctm,
- cairo_matrix_t *ctm_inverse,
+ const cairo_stroke_style_t *style,
+ const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
cairo_clip_t *clip)
diff --git a/src/cairo-qt-surface.cpp b/src/cairo-qt-surface.cpp
index 58d59b5..188b688 100644
--- a/src/cairo-qt-surface.cpp
+++ b/src/cairo-qt-surface.cpp
@@ -326,7 +326,7 @@ _qmatrix_from_cairo_matrix (const cairo_matrix_t& m)
/** Path conversion **/
typedef struct _qpainter_path_transform {
QPainterPath path;
- cairo_matrix_t *ctm_inverse;
+ const cairo_matrix_t *ctm_inverse;
} qpainter_path_data;
/* cairo path -> execute in context */
@@ -394,7 +394,7 @@ _cairo_path_to_qpainterpath_close_path (void *closure)
static inline QPainterPath
path_to_qt (cairo_path_fixed_t *path,
- cairo_matrix_t *ctm_inverse = NULL)
+ const cairo_matrix_t *ctm_inverse = NULL)
{
qpainter_path_data data;
cairo_status_t status;
@@ -699,7 +699,7 @@ _cairo_qt_surface_get_extents (void *abstract_surface,
extents->x = qs->window.x();
extents->y = qs->window.y();
- extents->width = qs->window.width();
+ extents->width = qs->window.width();
extents->height = qs->window.height();
return TRUE;
@@ -1044,7 +1044,7 @@ struct PatternToBrushConverter {
struct PatternToPenConverter {
PatternToPenConverter (const cairo_pattern_t *source,
- cairo_stroke_style_t *style) :
+ const cairo_stroke_style_t *style) :
mBrushConverter(source)
{
Qt::PenJoinStyle join = Qt::MiterJoin;
@@ -1332,9 +1332,9 @@ _cairo_qt_surface_stroke (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_path_fixed_t *path,
- cairo_stroke_style_t *style,
- cairo_matrix_t *ctm,
- cairo_matrix_t *ctm_inverse,
+ const cairo_stroke_style_t *style,
+ const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
cairo_clip_t *clip)
diff --git a/src/cairo-quartz-surface.c b/src/cairo-quartz-surface.c
index 78ef3ee..6e86cb2 100644
--- a/src/cairo-quartz-surface.c
+++ b/src/cairo-quartz-surface.c
@@ -2012,9 +2012,9 @@ _cairo_quartz_surface_stroke (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_path_fixed_t *path,
- cairo_stroke_style_t *style,
- cairo_matrix_t *ctm,
- cairo_matrix_t *ctm_inverse,
+ const cairo_stroke_style_t *style,
+ const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
cairo_clip_t *clip)
diff --git a/src/cairo-recording-surface.c b/src/cairo-recording-surface.c
index 54260e0..4c86c5b 100644
--- a/src/cairo-recording-surface.c
+++ b/src/cairo-recording-surface.c
@@ -397,9 +397,9 @@ _cairo_recording_surface_stroke (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_path_fixed_t *path,
- cairo_stroke_style_t *style,
- cairo_matrix_t *ctm,
- cairo_matrix_t *ctm_inverse,
+ const cairo_stroke_style_t *style,
+ const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
cairo_clip_t *clip)
diff --git a/src/cairo-script-surface.c b/src/cairo-script-surface.c
index 8b04c8a..64526c2 100644
--- a/src/cairo-script-surface.c
+++ b/src/cairo-script-surface.c
@@ -2145,9 +2145,9 @@ _cairo_script_surface_stroke (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_path_fixed_t *path,
- cairo_stroke_style_t *style,
- cairo_matrix_t *ctm,
- cairo_matrix_t *ctm_inverse,
+ const cairo_stroke_style_t *style,
+ const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
cairo_clip_t *clip)
diff --git a/src/cairo-stroke-style.c b/src/cairo-stroke-style.c
index eac69db..6ef85f4 100644
--- a/src/cairo-stroke-style.c
+++ b/src/cairo-stroke-style.c
@@ -53,7 +53,7 @@ _cairo_stroke_style_init (cairo_stroke_style_t *style)
cairo_status_t
_cairo_stroke_style_init_copy (cairo_stroke_style_t *style,
- cairo_stroke_style_t *other)
+ const cairo_stroke_style_t *other)
{
if (CAIRO_INJECT_FAULT ())
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
diff --git a/src/cairo-surface-fallback-private.h b/src/cairo-surface-fallback-private.h
index c63c36e..2dc2e97 100644
--- a/src/cairo-surface-fallback-private.h
+++ b/src/cairo-surface-fallback-private.h
@@ -59,9 +59,9 @@ _cairo_surface_fallback_stroke (cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_path_fixed_t *path,
- cairo_stroke_style_t *stroke_style,
- cairo_matrix_t *ctm,
- cairo_matrix_t *ctm_inverse,
+ const cairo_stroke_style_t *stroke_style,
+ const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
cairo_clip_t *clip);
diff --git a/src/cairo-surface-fallback.c b/src/cairo-surface-fallback.c
index c9f9a01..dbc2a21 100644
--- a/src/cairo-surface-fallback.c
+++ b/src/cairo-surface-fallback.c
@@ -1149,9 +1149,9 @@ _cairo_surface_fallback_stroke (cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_path_fixed_t *path,
- cairo_stroke_style_t *stroke_style,
- cairo_matrix_t *ctm,
- cairo_matrix_t *ctm_inverse,
+ const cairo_stroke_style_t *stroke_style,
+ const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
cairo_clip_t *clip)
diff --git a/src/cairo-surface-wrapper-private.h b/src/cairo-surface-wrapper-private.h
index 7da4cda..a993348 100644
--- a/src/cairo-surface-wrapper-private.h
+++ b/src/cairo-surface-wrapper-private.h
@@ -85,9 +85,9 @@ _cairo_surface_wrapper_stroke (cairo_surface_wrapper_t *wrapper,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_path_fixed_t *path,
- cairo_stroke_style_t *stroke_style,
- cairo_matrix_t *ctm,
- cairo_matrix_t *ctm_inverse,
+ const cairo_stroke_style_t *stroke_style,
+ const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
cairo_clip_t *clip);
@@ -102,9 +102,9 @@ _cairo_surface_wrapper_fill_stroke (cairo_surface_wrapper_t *wrapper,
cairo_path_fixed_t *path,
cairo_operator_t stroke_op,
const cairo_pattern_t *stroke_source,
- cairo_stroke_style_t *stroke_style,
- cairo_matrix_t *stroke_ctm,
- cairo_matrix_t *stroke_ctm_inverse,
+ const cairo_stroke_style_t *stroke_style,
+ const cairo_matrix_t *stroke_ctm,
+ const cairo_matrix_t *stroke_ctm_inverse,
double stroke_tolerance,
cairo_antialias_t stroke_antialias,
cairo_clip_t *clip);
diff --git a/src/cairo-surface-wrapper.c b/src/cairo-surface-wrapper.c
index d03c203..468a8d0 100644
--- a/src/cairo-surface-wrapper.c
+++ b/src/cairo-surface-wrapper.c
@@ -193,9 +193,9 @@ _cairo_surface_wrapper_stroke (cairo_surface_wrapper_t *wrapper,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_path_fixed_t *path,
- cairo_stroke_style_t *stroke_style,
- cairo_matrix_t *ctm,
- cairo_matrix_t *ctm_inverse,
+ const cairo_stroke_style_t *stroke_style,
+ const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
cairo_clip_t *clip)
@@ -273,9 +273,9 @@ _cairo_surface_wrapper_fill_stroke (cairo_surface_wrapper_t *wrapper,
cairo_path_fixed_t *path,
cairo_operator_t stroke_op,
const cairo_pattern_t *stroke_source,
- cairo_stroke_style_t *stroke_style,
- cairo_matrix_t *stroke_ctm,
- cairo_matrix_t *stroke_ctm_inverse,
+ const cairo_stroke_style_t *stroke_style,
+ const cairo_matrix_t *stroke_ctm,
+ const cairo_matrix_t *stroke_ctm_inverse,
double stroke_tolerance,
cairo_antialias_t stroke_antialias,
cairo_clip_t *clip)
diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index 5753277..dee6207 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -2004,9 +2004,9 @@ _cairo_surface_fill_stroke (cairo_surface_t *surface,
cairo_path_fixed_t *path,
cairo_operator_t stroke_op,
const cairo_pattern_t *stroke_source,
- cairo_stroke_style_t *stroke_style,
- cairo_matrix_t *stroke_ctm,
- cairo_matrix_t *stroke_ctm_inverse,
+ const cairo_stroke_style_t *stroke_style,
+ const cairo_matrix_t *stroke_ctm,
+ const cairo_matrix_t *stroke_ctm_inverse,
double stroke_tolerance,
cairo_antialias_t stroke_antialias,
cairo_clip_t *clip)
@@ -2071,9 +2071,9 @@ _cairo_surface_stroke (cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_path_fixed_t *path,
- cairo_stroke_style_t *stroke_style,
- cairo_matrix_t *ctm,
- cairo_matrix_t *ctm_inverse,
+ const cairo_stroke_style_t *stroke_style,
+ const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
cairo_clip_t *clip)
@@ -2908,7 +2908,7 @@ _cairo_surface_stroke_extents (cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_path_fixed_t *path,
- cairo_stroke_style_t *style,
+ const cairo_stroke_style_t *style,
const cairo_matrix_t *ctm,
const cairo_matrix_t *ctm_inverse,
double tolerance,
diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c
index 88765f3..da6bc60 100644
--- a/src/cairo-svg-surface.c
+++ b/src/cairo-svg-surface.c
@@ -66,9 +66,9 @@ static const cairo_svg_version_t _cairo_svg_versions[] =
#define CAIRO_SVG_VERSION_LAST ARRAY_LENGTH (_cairo_svg_versions)
static void
-_cairo_svg_surface_emit_path (cairo_output_stream_t *output,
- cairo_path_fixed_t *path,
- cairo_matrix_t *ctm_inverse);
+_cairo_svg_surface_emit_path (cairo_output_stream_t *output,
+ cairo_path_fixed_t *path,
+ const cairo_matrix_t *ctm_inverse);
static cairo_bool_t
_cairo_svg_version_has_page_set_support (cairo_svg_version_t version)
@@ -590,7 +590,7 @@ _cairo_svg_surface_emit_transform (cairo_output_stream_t *output,
typedef struct {
cairo_output_stream_t *output;
- cairo_matrix_t *ctm_inverse;
+ const cairo_matrix_t *ctm_inverse;
} svg_path_info_t;
static cairo_status_t
@@ -663,9 +663,9 @@ _cairo_svg_path_close_path (void *closure)
}
static void
-_cairo_svg_surface_emit_path (cairo_output_stream_t *output,
- cairo_path_fixed_t *path,
- cairo_matrix_t *ctm_inverse)
+_cairo_svg_surface_emit_path (cairo_output_stream_t *output,
+ cairo_path_fixed_t *path,
+ const cairo_matrix_t *ctm_inverse)
{
cairo_status_t status;
svg_path_info_t info;
@@ -1948,7 +1948,7 @@ _cairo_svg_surface_emit_fill_style (cairo_output_stream_t *output,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_fill_rule_t fill_rule,
- cairo_matrix_t *parent_matrix)
+ const cairo_matrix_t *parent_matrix)
{
_cairo_output_stream_printf (output,
"fill-rule:%s;",
@@ -1959,12 +1959,12 @@ _cairo_svg_surface_emit_fill_style (cairo_output_stream_t *output,
}
static cairo_status_t
-_cairo_svg_surface_emit_stroke_style (cairo_output_stream_t *output,
- cairo_svg_surface_t *surface,
- cairo_operator_t op,
- const cairo_pattern_t *source,
- cairo_stroke_style_t *stroke_style,
- cairo_matrix_t *parent_matrix)
+_cairo_svg_surface_emit_stroke_style (cairo_output_stream_t *output,
+ cairo_svg_surface_t *surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ const cairo_stroke_style_t *stroke_style,
+ const cairo_matrix_t *parent_matrix)
{
cairo_status_t status;
const char *line_cap, *line_join;
@@ -2046,9 +2046,9 @@ _cairo_svg_surface_fill_stroke (void *abstract_surface,
cairo_path_fixed_t *path,
cairo_operator_t stroke_op,
const cairo_pattern_t *stroke_source,
- cairo_stroke_style_t *stroke_style,
- cairo_matrix_t *stroke_ctm,
- cairo_matrix_t *stroke_ctm_inverse,
+ const cairo_stroke_style_t *stroke_style,
+ const cairo_matrix_t *stroke_ctm,
+ const cairo_matrix_t *stroke_ctm_inverse,
double stroke_tolerance,
cairo_antialias_t stroke_antialias,
cairo_clip_t *clip)
@@ -2337,9 +2337,9 @@ _cairo_svg_surface_stroke (void *abstract_dst,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_path_fixed_t *path,
- cairo_stroke_style_t *stroke_style,
- cairo_matrix_t *ctm,
- cairo_matrix_t *ctm_inverse,
+ const cairo_stroke_style_t *stroke_style,
+ const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
cairo_clip_t *clip)
diff --git a/src/cairo-tee-surface.c b/src/cairo-tee-surface.c
index 76f4b9d..5cc6f5e 100644
--- a/src/cairo-tee-surface.c
+++ b/src/cairo-tee-surface.c
@@ -252,9 +252,9 @@ _cairo_tee_surface_stroke (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_path_fixed_t *path,
- cairo_stroke_style_t *style,
- cairo_matrix_t *ctm,
- cairo_matrix_t *ctm_inverse,
+ const cairo_stroke_style_t *style,
+ const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
cairo_clip_t *clip)
diff --git a/src/cairo-type3-glyph-surface.c b/src/cairo-type3-glyph-surface.c
index 60698d4..8df6ef8 100644
--- a/src/cairo-type3-glyph-surface.c
+++ b/src/cairo-type3-glyph-surface.c
@@ -233,9 +233,9 @@ _cairo_type3_glyph_surface_stroke (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_path_fixed_t *path,
- cairo_stroke_style_t *style,
- cairo_matrix_t *ctm,
- cairo_matrix_t *ctm_inverse,
+ const cairo_stroke_style_t *style,
+ const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
cairo_clip_t *clip)
diff --git a/src/cairo-win32-printing-surface.c b/src/cairo-win32-printing-surface.c
index aff71ec..8eae55d 100644
--- a/src/cairo-win32-printing-surface.c
+++ b/src/cairo-win32-printing-surface.c
@@ -1246,9 +1246,9 @@ _cairo_win32_printing_surface_stroke (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_path_fixed_t *path,
- cairo_stroke_style_t *style,
- cairo_matrix_t *stroke_ctm,
- cairo_matrix_t *stroke_ctm_inverse,
+ const cairo_stroke_style_t *style,
+ const cairo_matrix_t *stroke_ctm,
+ const cairo_matrix_t *stroke_ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
cairo_clip_t *clip)
diff --git a/src/cairo-xml-surface.c b/src/cairo-xml-surface.c
index f32ea9d..d7d9b56 100644
--- a/src/cairo-xml-surface.c
+++ b/src/cairo-xml-surface.c
@@ -756,9 +756,9 @@ _cairo_xml_surface_stroke (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_path_fixed_t *path,
- cairo_stroke_style_t *style,
- cairo_matrix_t *ctm,
- cairo_matrix_t *ctm_inverse,
+ const cairo_stroke_style_t *style,
+ const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
cairo_clip_t *clip)
diff --git a/src/cairoint.h b/src/cairoint.h
index a224347..d8ed782 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -780,9 +780,9 @@ struct _cairo_surface_backend {
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_path_fixed_t *path,
- cairo_stroke_style_t *style,
- cairo_matrix_t *ctm,
- cairo_matrix_t *ctm_inverse,
+ const cairo_stroke_style_t *style,
+ const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
cairo_clip_t *clip);
@@ -825,9 +825,9 @@ struct _cairo_surface_backend {
cairo_path_fixed_t *path,
cairo_operator_t stroke_op,
const cairo_pattern_t *stroke_source,
- cairo_stroke_style_t *stroke_style,
- cairo_matrix_t *stroke_ctm,
- cairo_matrix_t *stroke_ctm_inverse,
+ const cairo_stroke_style_t *stroke_style,
+ const cairo_matrix_t *stroke_ctm,
+ const cairo_matrix_t *stroke_ctm_inverse,
double stroke_tolerance,
cairo_antialias_t stroke_antialias,
cairo_clip_t *clip);
@@ -1522,13 +1522,13 @@ _cairo_path_fixed_fill_extents (const cairo_path_fixed_t *path,
cairo_private void
_cairo_path_fixed_approximate_stroke_extents (const cairo_path_fixed_t *path,
- cairo_stroke_style_t *style,
+ const cairo_stroke_style_t *style,
const cairo_matrix_t *ctm,
cairo_rectangle_int_t *extents);
cairo_private cairo_status_t
_cairo_path_fixed_stroke_extents (const cairo_path_fixed_t *path,
- cairo_stroke_style_t *style,
+ const cairo_stroke_style_t *style,
const cairo_matrix_t *ctm,
const cairo_matrix_t *ctm_inverse,
double tolerance,
@@ -1584,7 +1584,7 @@ _cairo_path_fixed_fill_to_traps (const cairo_path_fixed_t *path,
/* cairo-path-stroke.c */
cairo_private cairo_status_t
_cairo_path_fixed_stroke_to_polygon (const cairo_path_fixed_t *path,
- cairo_stroke_style_t *stroke_style,
+ const cairo_stroke_style_t *stroke_style,
const cairo_matrix_t *ctm,
const cairo_matrix_t *ctm_inverse,
double tolerance,
@@ -1592,12 +1592,12 @@ _cairo_path_fixed_stroke_to_polygon (const cairo_path_fixed_t *path,
cairo_private cairo_int_status_t
_cairo_path_fixed_stroke_rectilinear_to_traps (const cairo_path_fixed_t *path,
- cairo_stroke_style_t *stroke_style,
+ const cairo_stroke_style_t *stroke_style,
const cairo_matrix_t *ctm,
cairo_traps_t *traps);
cairo_private cairo_status_t
_cairo_path_fixed_stroke_to_traps (const cairo_path_fixed_t *path,
- cairo_stroke_style_t *stroke_style,
+ const cairo_stroke_style_t *stroke_style,
const cairo_matrix_t *ctm,
const cairo_matrix_t *ctm_inverse,
double tolerance,
@@ -1605,9 +1605,9 @@ _cairo_path_fixed_stroke_to_traps (const cairo_path_fixed_t *path,
cairo_private cairo_status_t
_cairo_path_fixed_stroke_to_shaper (cairo_path_fixed_t *path,
- cairo_stroke_style_t *stroke_style,
- cairo_matrix_t *ctm,
- cairo_matrix_t *ctm_inverse,
+ const cairo_stroke_style_t *stroke_style,
+ const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_status_t (*add_triangle) (void *closure,
const cairo_point_t triangle[3]),
@@ -1739,7 +1739,7 @@ _cairo_stroke_style_init (cairo_stroke_style_t *style);
cairo_private cairo_status_t
_cairo_stroke_style_init_copy (cairo_stroke_style_t *style,
- cairo_stroke_style_t *other);
+ const cairo_stroke_style_t *other);
cairo_private void
_cairo_stroke_style_fini (cairo_stroke_style_t *style);
@@ -1879,9 +1879,9 @@ _cairo_surface_fill_stroke (cairo_surface_t *surface,
cairo_path_fixed_t *path,
cairo_operator_t stroke_op,
const cairo_pattern_t *stroke_source,
- cairo_stroke_style_t *stroke_style,
- cairo_matrix_t *stroke_ctm,
- cairo_matrix_t *stroke_ctm_inverse,
+ const cairo_stroke_style_t *stroke_style,
+ const cairo_matrix_t *stroke_ctm,
+ const cairo_matrix_t *stroke_ctm_inverse,
double stroke_tolerance,
cairo_antialias_t stroke_antialias,
cairo_clip_t *clip);
@@ -1891,9 +1891,9 @@ _cairo_surface_stroke (cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_path_fixed_t *path,
- cairo_stroke_style_t *style,
- cairo_matrix_t *ctm,
- cairo_matrix_t *ctm_inverse,
+ const cairo_stroke_style_t *style,
+ const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
cairo_clip_t *clip);
@@ -1942,7 +1942,7 @@ _cairo_surface_stroke_extents (cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_path_fixed_t *path,
- cairo_stroke_style_t *style,
+ const cairo_stroke_style_t *style,
const cairo_matrix_t *ctm,
const cairo_matrix_t *ctm_inverse,
double tolerance,
diff --git a/src/drm/cairo-drm-private.h b/src/drm/cairo-drm-private.h
index 4a32c68..0f1b735 100644
--- a/src/drm/cairo-drm-private.h
+++ b/src/drm/cairo-drm-private.h
@@ -198,9 +198,9 @@ _cairo_drm_surface_stroke (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_path_fixed_t *path,
- cairo_stroke_style_t *style,
- cairo_matrix_t *ctm,
- cairo_matrix_t *ctm_inverse,
+ const cairo_stroke_style_t *style,
+ const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
cairo_clip_t *clip);
diff --git a/src/drm/cairo-drm-surface.c b/src/drm/cairo-drm-surface.c
index a8f9ab1..429b528 100644
--- a/src/drm/cairo-drm-surface.c
+++ b/src/drm/cairo-drm-surface.c
@@ -143,9 +143,9 @@ _cairo_drm_surface_stroke (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_path_fixed_t *path,
- cairo_stroke_style_t *style,
- cairo_matrix_t *ctm,
- cairo_matrix_t *ctm_inverse,
+ const cairo_stroke_style_t *style,
+ const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
cairo_clip_t *clip)
diff --git a/src/test-null-surface.c b/src/test-null-surface.c
index 5a260bb..44a284e 100644
--- a/src/test-null-surface.c
+++ b/src/test-null-surface.c
@@ -69,9 +69,9 @@ typedef cairo_int_status_t
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_path_fixed_t *path,
- cairo_stroke_style_t *style,
- cairo_matrix_t *ctm,
- cairo_matrix_t *ctm_inverse,
+ const cairo_stroke_style_t *style,
+ const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
cairo_clip_t *clip);
diff --git a/src/test-paginated-surface.c b/src/test-paginated-surface.c
index 62e5cb6..73b6617 100644
--- a/src/test-paginated-surface.c
+++ b/src/test-paginated-surface.c
@@ -150,9 +150,9 @@ _test_paginated_surface_stroke (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_path_fixed_t *path,
- cairo_stroke_style_t *style,
- cairo_matrix_t *ctm,
- cairo_matrix_t *ctm_inverse,
+ const cairo_stroke_style_t *style,
+ const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
cairo_clip_t *clip)
diff --git a/src/test-wrapping-surface.c b/src/test-wrapping-surface.c
index d76218f..3c14cc8 100644
--- a/src/test-wrapping-surface.c
+++ b/src/test-wrapping-surface.c
@@ -161,9 +161,9 @@ _test_wrapping_surface_stroke (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
cairo_path_fixed_t *path,
- cairo_stroke_style_t *style,
- cairo_matrix_t *ctm,
- cairo_matrix_t *ctm_inverse,
+ const cairo_stroke_style_t *style,
+ const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
cairo_clip_t *clip)
commit 3e17c559b04e2df208f28125746d7e0acfb4b476
Author: Benjamin Otte <otte at gnome.org>
Date: Wed Dec 9 19:46:28 2009 +0100
[test] Add pthread-same-source test
Multiple threads render using the same source surface, but with
different extend and filter.
diff --git a/test/Makefile.am b/test/Makefile.am
index a47e8ae..6dbf6bf 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -771,6 +771,7 @@ REFERENCE_IMAGES = \
pdf-surface-source.svg12.rgb24.xfail.png \
pixman-rotate.ref.png \
pixman-rotate.rgb24.ref.png \
+ pthread-same-source.ref.png \
pthread-similar.ref.png \
ps-surface-source.rgb24.ref.png \
ps-surface-source.argb32.ref.png \
diff --git a/test/Makefile.sources b/test/Makefile.sources
index 48f65a6..52d4f85 100644
--- a/test/Makefile.sources
+++ b/test/Makefile.sources
@@ -245,6 +245,7 @@ test_sources = \
zero-alpha.c
pthread_test_sources = \
+ pthread-same-source.c \
pthread-show-text.c \
pthread-similar.c \
$(NULL)
diff --git a/test/pthread-same-source.c b/test/pthread-same-source.c
new file mode 100644
index 0000000..570c91d
--- /dev/null
+++ b/test/pthread-same-source.c
@@ -0,0 +1,160 @@
+/*
+ * Copyright 2009 Benjamin Otte
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of
+ * Benjamin Otte not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior
+ * permission. Benjamin Otte makes no representations about the
+ * suitability of this software for any purpose. It is provided "as
+ * is" without express or implied warranty.
+ *
+ * BENJAMIN OTTE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL BENJAMIN OTTE BE LIABLE FOR ANY SPECIAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Benjamin Otte <otte at gnome.org>
+ */
+
+#include "cairo-test.h"
+#include <pthread.h>
+
+#define N_THREADS 8
+
+#define WIDTH 64
+#define HEIGHT 8
+
+typedef struct {
+ cairo_surface_t *target;
+ cairo_surface_t *source;
+ int id;
+} thread_data_t;
+
+static void *
+draw_thread (void *arg)
+{
+ thread_data_t *thread_data = arg;
+ cairo_surface_t *surface;
+ cairo_pattern_t *pattern;
+ cairo_matrix_t pattern_matrix = { 2, 0, 0, 2, 0, 0 };
+ cairo_t *cr;
+ int x, y;
+
+ cr = cairo_create (thread_data->target);
+ cairo_surface_destroy (thread_data->target);
+
+ pattern = cairo_pattern_create_for_surface (thread_data->source);
+ cairo_surface_destroy (thread_data->source);
+ cairo_pattern_set_extend (pattern, thread_data->id % 4);
+ cairo_pattern_set_filter (pattern, thread_data->id >= 4 ? CAIRO_FILTER_BILINEAR : CAIRO_FILTER_NEAREST);
+ cairo_pattern_set_matrix (pattern, &pattern_matrix);
+
+ for (y = 0; y < HEIGHT; y++) {
+ for (x = 0; x < WIDTH; x++) {
+ cairo_save (cr);
+ cairo_translate (cr, 4 * x + 1, 4 * y + 1);
+ cairo_rectangle (cr, 0, 0, 2, 2);
+ cairo_set_source (cr, pattern);
+ cairo_fill (cr);
+ cairo_restore (cr);
+ }
+ }
+ cairo_pattern_destroy (pattern);
+
+ surface = cairo_surface_reference (cairo_get_target (cr));
+ cairo_destroy (cr);
+
+ return surface;
+}
+
+static cairo_surface_t *
+create_source (cairo_surface_t *similar)
+{
+ cairo_surface_t *source;
+ cairo_t *cr;
+ double colors[4][3] = {
+ { 0.75, 0, 0 },
+ { 0, 0.75, 0 },
+ { 0, 0, 0.75 },
+ { 0.75, 0.75, 0 }
+ };
+ int i;
+
+ source = cairo_surface_create_similar (similar,
+ CAIRO_CONTENT_COLOR_ALPHA,
+ 2, 2);
+
+ cr = cairo_create (source);
+ for (i = 0; i < 4; i++) {
+ cairo_set_source_rgb (cr, colors[i][0], colors[i][1], colors[i][2]);
+ cairo_rectangle (cr, i % 2, i / 2, 1, 1);
+ cairo_fill (cr);
+ }
+ cairo_destroy (cr);
+
+ return source;
+}
+
+static cairo_test_status_t
+draw (cairo_t *cr, int width, int height)
+{
+ pthread_t threads[N_THREADS];
+ thread_data_t thread_data[N_THREADS];
+ cairo_test_status_t test_status = CAIRO_TEST_SUCCESS;
+ cairo_surface_t *source;
+ int i;
+
+ source = create_source (cairo_get_target (cr));
+
+ for (i = 0; i < N_THREADS; i++) {
+ thread_data[i].target = cairo_surface_create_similar (cairo_get_target (cr),
+ CAIRO_CONTENT_COLOR_ALPHA,
+ 4 * WIDTH, 4 * HEIGHT);
+ thread_data[i].source = cairo_surface_reference (source);
+ thread_data[i].id = i;
+ if (pthread_create (&threads[i], NULL, draw_thread, &thread_data[i]) != 0) {
+ threads[i] = pthread_self (); /* to indicate error */
+ cairo_surface_destroy (thread_data[i].target);
+ cairo_surface_destroy (thread_data[i].source);
+ test_status = CAIRO_TEST_FAILURE;
+ break;
+ }
+ }
+
+ cairo_set_source_rgb (cr, 0.5, 0.5, 0.5);
+ cairo_paint (cr);
+
+ for (i = 0; i < N_THREADS; i++) {
+ void *surface;
+
+ if (pthread_equal (threads[i], pthread_self ()))
+ break;
+
+ if (pthread_join (threads[i], &surface) != 0) {
+ test_status = CAIRO_TEST_FAILURE;
+ break;
+ }
+
+ cairo_set_source_surface (cr, surface, 0, 0);
+ cairo_surface_destroy (surface);
+ cairo_paint (cr);
+
+ cairo_translate (cr, 0, 4 * HEIGHT);
+ }
+
+ return test_status;
+}
+
+CAIRO_TEST (pthread_same_source,
+ "Use the same source for drawing in different threads",
+ "threads", /* keywords */
+ NULL, /* requirements */
+ 4 * WIDTH, 4 * HEIGHT * N_THREADS,
+ NULL, draw)
diff --git a/test/pthread-same-source.ref.png b/test/pthread-same-source.ref.png
new file mode 100644
index 0000000..cfb519d
Binary files /dev/null and b/test/pthread-same-source.ref.png differ
commit 30a12f802f4ff46f13dc36e60936cd857585a9ea
Author: Benjamin Otte <otte at gnome.org>
Date: Wed Nov 25 18:55:05 2009 +0100
[test] Add a simple multithreading test
diff --git a/test/Makefile.am b/test/Makefile.am
index 51fced5..a47e8ae 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -771,6 +771,7 @@ REFERENCE_IMAGES = \
pdf-surface-source.svg12.rgb24.xfail.png \
pixman-rotate.ref.png \
pixman-rotate.rgb24.ref.png \
+ pthread-similar.ref.png \
ps-surface-source.rgb24.ref.png \
ps-surface-source.argb32.ref.png \
ps-surface-source.svg12.argb32.xfail.png \
diff --git a/test/Makefile.sources b/test/Makefile.sources
index af91ed6..48f65a6 100644
--- a/test/Makefile.sources
+++ b/test/Makefile.sources
@@ -244,7 +244,10 @@ test_sources = \
xcomposite-projection.c \
zero-alpha.c
-pthread_test_sources = pthread-show-text.c
+pthread_test_sources = \
+ pthread-show-text.c \
+ pthread-similar.c \
+ $(NULL)
ft_font_test_sources = \
bitmap-font.c \
diff --git a/test/pthread-similar.c b/test/pthread-similar.c
new file mode 100644
index 0000000..15196ad
--- /dev/null
+++ b/test/pthread-similar.c
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2009 Benjamin Otte
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of
+ * Benjamin Otte not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior
+ * permission. Benjamin Otte makes no representations about the
+ * suitability of this software for any purpose. It is provided "as
+ * is" without express or implied warranty.
+ *
+ * BENJAMIN OTTE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL BENJAMIN OTTE BE LIABLE FOR ANY SPECIAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Benjamin Otte <otte at gnome.org>
+ */
+
+#include "cairo-test.h"
+#include <pthread.h>
+
+#define N_THREADS 8
+
+#define WIDTH 64
+#define HEIGHT 8
+
+static void *
+draw_thread (void *arg)
+{
+ cairo_surface_t *surface = arg;
+ cairo_t *cr;
+ int x, y;
+
+ cr = cairo_create (surface);
+ cairo_surface_destroy (surface);
+
+ for (y = 0; y < HEIGHT; y++) {
+ for (x = 0; x < WIDTH; x++) {
+ cairo_rectangle (cr, x, y, 1, 1);
+ cairo_set_source_rgba (cr, 0, 0.75, 0.75, (double) x / WIDTH);
+ cairo_fill (cr);
+ }
+ }
+
+ surface = cairo_surface_reference (cairo_get_target (cr));
+ cairo_destroy (cr);
+
+ return surface;
+}
+
+static cairo_test_status_t
+draw (cairo_t *cr, int width, int height)
+{
+ pthread_t threads[N_THREADS];
+ cairo_test_status_t test_status = CAIRO_TEST_SUCCESS;
+ int i;
+
+ for (i = 0; i < N_THREADS; i++) {
+ cairo_surface_t *surface;
+
+ surface = cairo_surface_create_similar (cairo_get_target (cr),
+ CAIRO_CONTENT_COLOR,
+ WIDTH, HEIGHT);
+ if (pthread_create (&threads[i], NULL, draw_thread, surface) != 0) {
+ threads[i] = pthread_self ();
+ test_status = cairo_test_status_from_status (cairo_test_get_context (cr),
+ cairo_surface_status (surface));
+ cairo_surface_destroy (surface);
+ break;
+ }
+ }
+
+ for (i = 0; i < N_THREADS; i++) {
+ void *surface;
+
+ if (pthread_equal (threads[i], pthread_self ()))
+ break;
+
+ if (pthread_join (threads[i], &surface) != 0) {
+ test_status = CAIRO_TEST_FAILURE;
+ break;
+ }
+
+ cairo_set_source_surface (cr, surface, 0, 0);
+ cairo_surface_destroy (surface);
+ cairo_paint (cr);
+
+ cairo_translate (cr, 0, HEIGHT);
+ }
+
+ return test_status;
+}
+
+CAIRO_TEST (pthread_similar,
+ "Draw lots of 1x1 rectangles on similar surfaces in lots of threads",
+ "threads", /* keywords */
+ NULL, /* requirements */
+ WIDTH, HEIGHT * N_THREADS,
+ NULL, draw)
diff --git a/test/pthread-similar.ref.png b/test/pthread-similar.ref.png
new file mode 100644
index 0000000..a22210d
Binary files /dev/null and b/test/pthread-similar.ref.png differ
commit 038829eb84e53532a6e3c75225933ad85da50cfc
Author: Benjamin Otte <otte at gnome.org>
Date: Sun Dec 6 17:47:50 2009 +0100
[test] Add new test checking is_clear is handled properly
This test does various operations with a clear source surface with
various content types.
The idea is to make sure optimizations done when surface->is_clear ==
TRUE only happen in the proper cases.
diff --git a/test/Makefile.sources b/test/Makefile.sources
index 068858a..af91ed6 100644
--- a/test/Makefile.sources
+++ b/test/Makefile.sources
@@ -13,6 +13,7 @@ test_sources = \
caps-joins-curve.c \
caps-sub-paths.c \
clear.c \
+ clear-source.c \
clip-all.c \
clip-disjoint.c \
clip-device-offset.c \
diff --git a/test/clear-source.c b/test/clear-source.c
new file mode 100644
index 0000000..36f46b3
--- /dev/null
+++ b/test/clear-source.c
@@ -0,0 +1,163 @@
+/*
+ * Copyright 2009 Benjamin Otte
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of
+ * Benjamin Otte not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior
+ * permission. Benjamin Otte makes no representations about the
+ * suitability of this software for any purpose. It is provided "as
+ * is" without express or implied warranty.
+ *
+ * BENJAMIN OTTE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL BENJAMIN OTTE BE LIABLE FOR ANY SPECIAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Benjamin Otte <otte at gnome.org>
+ */
+
+#include "cairo-test.h"
+
+#define ARRAY_LENGTH(x) (sizeof(x) / sizeof(x[0]))
+typedef enum {
+ CLEAR,
+ CLEARED,
+ PAINTED
+} surface_type_t;
+
+#define SIZE 10
+#define SPACE 5
+
+static cairo_surface_t *
+create_surface (cairo_t *target, cairo_content_t content, surface_type_t type)
+{
+ cairo_surface_t *surface;
+ cairo_t *cr;
+
+ surface = cairo_surface_create_similar (cairo_get_target (target),
+ content,
+ SIZE, SIZE);
+
+ if (type == CLEAR)
+ return surface;
+
+ cr = cairo_create (surface);
+ cairo_set_source_rgb (cr, 0.75, 0, 0);
+ cairo_paint (cr);
+ cairo_destroy (cr);
+
+ if (type == PAINTED)
+ return surface;
+
+ cr = cairo_create (surface);
+ cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
+ cairo_paint (cr);
+ cairo_destroy (cr);
+
+ return surface;
+}
+
+static void
+paint (cairo_t *cr, cairo_surface_t *surface)
+{
+ cairo_set_source_surface (cr, surface, 0, 0);
+ cairo_paint (cr);
+}
+
+static void
+fill (cairo_t *cr, cairo_surface_t *surface)
+{
+ cairo_set_source_surface (cr, surface, 0, 0);
+ cairo_rectangle (cr, -SPACE, -SPACE, SIZE + 2 * SPACE, SIZE + 2 * SPACE);
+ cairo_fill (cr);
+}
+
+static void
+stroke (cairo_t *cr, cairo_surface_t *surface)
+{
+ cairo_set_source_surface (cr, surface, 0, 0);
+ cairo_set_line_width (cr, 2.0);
+ cairo_rectangle (cr, 1, 1, SIZE - 2, SIZE - 2);
+ cairo_stroke (cr);
+}
+
+static void
+mask (cairo_t *cr, cairo_surface_t *surface)
+{
+ cairo_set_source_rgb (cr, 0, 0, 0.75);
+ cairo_mask_surface (cr, surface, 0, 0);
+}
+
+static void
+mask_self (cairo_t *cr, cairo_surface_t *surface)
+{
+ cairo_set_source_surface (cr, surface, 0, 0);
+ cairo_mask_surface (cr, surface, 0, 0);
+}
+
+static void
+glyphs (cairo_t *cr, cairo_surface_t *surface)
+{
+ cairo_set_source_surface (cr, surface, 0, 0);
+ cairo_select_font_face (cr,
+ "@cairo:",
+ CAIRO_FONT_SLANT_NORMAL,
+ CAIRO_FONT_WEIGHT_NORMAL);
+ cairo_set_font_size (cr, 16);
+ cairo_translate (cr, 0, SIZE);
+ cairo_show_text (cr, "C");
+}
+
+typedef void (* operation_t) (cairo_t *cr, cairo_surface_t *surface);
+static operation_t operations[] = {
+ paint,
+ fill,
+ stroke,
+ mask,
+ mask_self,
+ glyphs
+};
+
+static cairo_test_status_t
+draw (cairo_t *cr, int width, int height)
+{
+ cairo_content_t contents[] = { CAIRO_CONTENT_COLOR_ALPHA, CAIRO_CONTENT_COLOR, CAIRO_CONTENT_ALPHA };
+ unsigned int content, type, ops;
+ cairo_surface_t *surface;
+
+ cairo_set_source_rgb (cr, 0.5, 0.5, 0.5);
+ cairo_paint (cr);
+ cairo_translate (cr, SPACE, SPACE);
+
+ for (type = 0; type <= PAINTED; type++) {
+ for (content = 0; content < ARRAY_LENGTH (contents); content++) {
+ surface = create_surface (cr, contents[content], type);
+
+ cairo_save (cr);
+ for (ops = 0; ops < ARRAY_LENGTH (operations); ops++) {
+ cairo_save (cr);
+ operations[ops] (cr, surface);
+ cairo_restore (cr);
+ cairo_translate (cr, 0, SIZE + SPACE);
+ }
+ cairo_restore (cr);
+ cairo_translate (cr, SIZE + SPACE, 0);
+ }
+ }
+
+ return CAIRO_TEST_SUCCESS;
+}
+
+CAIRO_TEST (clear_source,
+ "Check painting with cleared surfaces works as expected",
+ NULL, /* keywords */
+ NULL, /* requirements */
+ (SIZE + SPACE) * 9 + SPACE, ARRAY_LENGTH (operations) * (SIZE + SPACE) + SPACE,
+ NULL, draw)
diff --git a/test/clear-source.ref.png b/test/clear-source.ref.png
new file mode 100644
index 0000000..4948c5e
Binary files /dev/null and b/test/clear-source.ref.png differ
commit bf7fb4e0e09d05f42425cc7969c64992d4dc9ff9
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Mon Jan 18 17:18:08 2010 +0000
script: Handle cache allocation failure more gracefully
Instead of bailing out if we cannot store the glyph cache on the font,
simply do not store the glyph cache on the font...
diff --git a/util/cairo-script/cairo-script-operators.c b/util/cairo-script/cairo-script-operators.c
index b9c8eed..91188d9 100644
--- a/util/cairo-script/cairo-script-operators.c
+++ b/util/cairo-script/cairo-script-operators.c
@@ -2507,30 +2507,41 @@ _glyph_string (csi_t *ctx,
cairo_scaled_font_t *scaled_font,
cairo_glyph_t *glyphs)
{
- double x,y, dx;
- csi_integer_t nglyphs, i, j;
+ struct glyph_advance_cache uncached;
struct glyph_advance_cache *cache;
+ csi_integer_t nglyphs, i, j;
+ double x, y, dx;
cairo_status_t status;
+ if (cairo_scaled_font_status (scaled_font))
+ return 0;
+
cache = cairo_scaled_font_get_user_data (scaled_font,
(cairo_user_data_key_t *) ctx);
if (cache == NULL) {
cache = _csi_alloc (ctx, sizeof (*cache));
- if (cache == NULL)
- return -1;
+ if (_csi_likely (cache != NULL)) {
+ cache->ctx = ctx;
+ memset (cache->have_glyph_advance, 0xff,
+ sizeof (cache->have_glyph_advance));
+
+ status = cairo_scaled_font_set_user_data (scaled_font,
+ (cairo_user_data_key_t *) ctx,
+ cache,
+ glyph_advance_cache_destroy);
+ if (_csi_unlikely (status)) {
+ _csi_free (ctx, cache);
+ cache = NULL;
+ }
+ }
+ }
+
+ if (_csi_unlikely (cache == NULL)) {
+ cache = &uncached;
cache->ctx = ctx;
memset (cache->have_glyph_advance, 0xff,
sizeof (cache->have_glyph_advance));
-
- status = cairo_scaled_font_set_user_data (scaled_font,
- (cairo_user_data_key_t *) ctx,
- cache,
- glyph_advance_cache_destroy);
- if (status) {
- _csi_free (ctx, cache);
- return -1;
- }
}
nglyphs = 0;
@@ -2668,6 +2679,7 @@ _glyph_path (csi_t *ctx)
if (nglyphs > ARRAY_LENGTH (stack_glyphs)) {
if (_csi_unlikely ((unsigned) nglyphs >= INT_MAX / sizeof (cairo_glyph_t)))
return _csi_error (CSI_STATUS_NO_MEMORY);
+
glyphs = _csi_alloc (ctx, sizeof (cairo_glyph_t) * nglyphs);
if (_csi_unlikely (glyphs == NULL))
return _csi_error (CSI_STATUS_NO_MEMORY);
@@ -2675,13 +2687,6 @@ _glyph_path (csi_t *ctx)
glyphs = stack_glyphs;
nglyphs = _glyph_string (ctx, array, cairo_get_scaled_font (cr), glyphs);
- if (_csi_unlikely (nglyphs < 0)) {
- if (glyphs != stack_glyphs)
- _csi_free (ctx, glyphs);
-
- return _csi_error (CSI_STATUS_NO_MEMORY);
- }
-
cairo_glyph_path (cr, glyphs, nglyphs);
if (glyphs != stack_glyphs)
@@ -5289,6 +5294,7 @@ _show_glyphs (csi_t *ctx)
if (nglyphs > ARRAY_LENGTH (stack_glyphs)) {
if (_csi_unlikely ((unsigned) nglyphs >= INT_MAX / sizeof (cairo_glyph_t)))
return _csi_error (CSI_STATUS_NO_MEMORY);
+
glyphs = _csi_alloc (ctx, sizeof (cairo_glyph_t) * nglyphs);
if (_csi_unlikely (glyphs == NULL))
return _csi_error (CSI_STATUS_NO_MEMORY);
@@ -5296,12 +5302,6 @@ _show_glyphs (csi_t *ctx)
glyphs = stack_glyphs;
nglyphs = _glyph_string (ctx, array, cairo_get_scaled_font (cr), glyphs);
- if (_csi_unlikely (nglyphs < 0)) {
- if (glyphs != stack_glyphs)
- _csi_free (ctx, glyphs);
- return _csi_error (CSI_STATUS_NO_MEMORY);
- }
-
cairo_show_glyphs (cr, glyphs, nglyphs);
if (glyphs != stack_glyphs)
@@ -5399,30 +5399,22 @@ _show_text_glyphs (csi_t *ctx)
break;
}
}
- if (nglyphs == 0)
+ if (nglyphs == 0) {
+ pop (4);
return CSI_STATUS_SUCCESS;
+ }
if (nglyphs > ARRAY_LENGTH (stack_glyphs)) {
- if (_csi_unlikely ((unsigned) nglyphs >= INT_MAX / sizeof (cairo_glyph_t)))
- return _csi_error (CSI_STATUS_NO_MEMORY);
+ if (_csi_unlikely ((unsigned) nglyphs >= INT_MAX / sizeof (cairo_glyph_t)))
+ return _csi_error (CSI_STATUS_NO_MEMORY);
+
glyphs = _csi_alloc (ctx, sizeof (cairo_glyph_t) * nglyphs);
- if (_csi_unlikely (glyphs == NULL)) {
+ if (_csi_unlikely (glyphs == NULL))
return _csi_error (CSI_STATUS_NO_MEMORY);
- }
} else
glyphs = stack_glyphs;
nglyphs = _glyph_string (ctx, array, cairo_get_scaled_font (cr), glyphs);
- if (_csi_unlikely (nglyphs < 0)) {
- if (clusters != stack_clusters)
- _csi_free (ctx, clusters);
-
- if (glyphs != stack_glyphs)
- _csi_free (ctx, glyphs);
-
- return _csi_error (CSI_STATUS_NO_MEMORY);
- }
-
cairo_show_text_glyphs (cr,
utf8_string->string, utf8_string->len,
glyphs, nglyphs,
commit 2b312806f138da6f88d03bb3c0c3852b342eb220
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Mon Jan 18 17:14:24 2010 +0000
script: Free the correct pattern after failure.
The error path attempted to free the resolved pattern which it had just
discovered was NULL and not the locally allocated pattern...
diff --git a/util/cairo-script/cairo-script-operators.c b/util/cairo-script/cairo-script-operators.c
index 7946042..b9c8eed 100644
--- a/util/cairo-script/cairo-script-operators.c
+++ b/util/cairo-script/cairo-script-operators.c
@@ -1894,7 +1894,7 @@ _ft_create_for_pattern (csi_t *ctx,
/* prior to 1.9, you needed to pass a resolved pattern */
resolved = FcFontMatch (NULL, pattern, NULL);
if (_csi_unlikely (resolved == NULL)) {
- FcPatternDestroy (resolved);
+ FcPatternDestroy (pattern);
return _csi_error (CSI_STATUS_NO_MEMORY);
}
}
commit bc2d0ad114f8fc0b0579851154fe9d39c0aa0fc9
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Fri Nov 27 17:30:51 2009 +0000
script: Permit surface operations on the context
By implicitly reference the target of the context instead, i.e.
this reduces the use of:
/target get (example.png) write-to-png pop
as a common idiom where the context is kept on the stack and the surface
forgotten.
diff --git a/util/cairo-script/cairo-script-operators.c b/util/cairo-script/cairo-script-operators.c
index 31ab58e..7946042 100644
--- a/util/cairo-script/cairo-script-operators.c
+++ b/util/cairo-script/cairo-script-operators.c
@@ -351,12 +351,20 @@ static csi_status_t
_csi_ostack_get_surface (csi_t *ctx, unsigned int i, cairo_surface_t **out)
{
csi_object_t *obj;
+ int type;
obj = _csi_peek_ostack (ctx, i);
- if (_csi_unlikely (csi_object_get_type (obj) != CSI_OBJECT_TYPE_SURFACE))
+ type = csi_object_get_type (obj);
+ switch (type) {
+ case CSI_OBJECT_TYPE_CONTEXT:
+ *out = cairo_get_target (obj->datum.cr);
+ break;
+ case CSI_OBJECT_TYPE_SURFACE:
+ *out = obj->datum.surface;
+ break;
+ default:
return _csi_error (CSI_STATUS_INVALID_SCRIPT);
-
- *out = obj->datum.surface;
+ }
return CSI_STATUS_SUCCESS;
}
commit 411c09eed7ebff7335948a7f96d2b29d82ed817a
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Sun Nov 1 08:40:41 2009 +0000
perf: Enable a surface cache for perf-trace
Real applications that control their Drawable externally to Cairo are
'disadvantaged' by cairo-perf-trace when it creates a similar surface
for each new instance of the same Drawable. The difficulty in
maintaining one perf surface for every application surface is that the
traces do not track lifetimes for the application surfaces, so we would
just accumulate stale surfaces. The surface cache takes a different
approach and returns the same surface for each active Drawable, and
maintains a hold-over of the MRU 16 surfaces. This achieves 60-80% hit
rate with firefox, which is probably as good as can be expected.
Obviously for double-buffered applications we only every draw to freshly
created surfaces (and Gtk+ bypasses cairo to do the final copy -- the
ideal application would just use a push-group for double buffering, in
which case we would capture and replay the entire expose event).
To enable use of the surface cache whilst replaying use -c:
./cairo-perf-trace -c firefox-talos-gfx
diff --git a/perf/Makefile.am b/perf/Makefile.am
index 809f2d5..441aee6 100644
--- a/perf/Makefile.am
+++ b/perf/Makefile.am
@@ -79,7 +79,8 @@ libcairoperf_la_SOURCES = \
cairo-stats.h
cairo_perf_trace_SOURCES = \
- cairo-perf-trace.c
+ cairo-perf-trace.c \
+ ../src/cairo-hash.c
if CAIRO_HAS_WIN32_SURFACE
cairo_perf_trace_SOURCES += cairo-perf-win32.c
else
diff --git a/perf/cairo-perf-trace.c b/perf/cairo-perf-trace.c
index dd8cc69..5487eaf 100644
--- a/perf/cairo-perf-trace.c
+++ b/perf/cairo-perf-trace.c
@@ -39,6 +39,10 @@
#include <cairo-script-interpreter.h>
#include <cairo-types-private.h> /* for INTERNAL_SURFACE_TYPE */
+/* rudely reuse bits of the library... */
+#include "../src/cairo-hash-private.h"
+#include "../src/cairo-error-private.h"
+
/* For basename */
#ifdef HAVE_LIBGEN_H
#include <libgen.h>
@@ -193,12 +197,125 @@ clear_surface (cairo_surface_t *surface)
cairo_destroy (cr);
}
+struct scache {
+ cairo_hash_entry_t entry;
+ cairo_content_t content;
+ int width, height;
+ cairo_surface_t *surface;
+};
+
+static cairo_hash_table_t *surface_cache;
+static cairo_surface_t *surface_holdovers[16];
+
+static cairo_bool_t
+scache_equal (const void *A, const void *B)
+{
+ const struct scache *a = A, *b = B;
+ return a->entry.hash == b->entry.hash;
+}
+
+#define ARRAY_SIZE(A) (sizeof(A)/sizeof(A[0]))
+static void
+scache_mark_active (cairo_surface_t *surface)
+{
+ cairo_surface_t *t0, *t1;
+ unsigned n;
+
+ if (surface_cache == NULL)
+ return;
+
+ t0 = cairo_surface_reference (surface);
+ for (n = 0; n < ARRAY_SIZE (surface_holdovers); n++) {
+ if (surface_holdovers[n] == surface) {
+ surface_holdovers[n] = t0;
+ t0 = surface;
+ break;
+ }
+
+ t1 = surface_holdovers[n];
+ surface_holdovers[n] = t0;
+ t0 = t1;
+ }
+ cairo_surface_destroy (t0);
+}
+
+static void
+scache_clear (void)
+{
+ unsigned n;
+
+ if (surface_cache == NULL)
+ return;
+
+ for (n = 0; n < ARRAY_SIZE (surface_holdovers); n++) {
+ cairo_surface_destroy (surface_holdovers[n]);
+ surface_holdovers[n] = NULL;
+ }
+}
+
+static void
+scache_remove (void *closure)
+{
+ _cairo_hash_table_remove (surface_cache, closure);
+ free (closure);
+}
+
static cairo_surface_t *
_similar_surface_create (void *closure,
cairo_content_t content,
- double width, double height)
+ double width, double height,
+ long uid)
{
- return cairo_surface_create_similar (closure, content, width, height);
+ cairo_surface_t *surface;
+ struct scache skey, *s;
+
+ if (uid == 0 || surface_cache == NULL)
+ return cairo_surface_create_similar (closure, content, width, height);
+
+ skey.entry.hash = uid;
+ s = _cairo_hash_table_lookup (surface_cache, &skey.entry);
+ if (s != NULL) {
+ if (s->content == content &&
+ s->width == width &&
+ s->height == height)
+ {
+ return cairo_surface_reference (s->surface);
+ }
+
+ /* The surface has been resized, allow the original entry to expire
+ * as it becomes inactive.
+ */
+ }
+
+ surface = cairo_surface_create_similar (closure, content, width, height);
+ s = malloc (sizeof (struct scache));
+ if (s == NULL)
+ return surface;
+
+ s->entry.hash = uid;
+ s->content = content;
+ s->width = width;
+ s->height = height;
+ s->surface = surface;
+ if (_cairo_hash_table_insert (surface_cache, &s->entry)) {
+ free (s);
+ } else if (cairo_surface_set_user_data
+ (surface,
+ (const cairo_user_data_key_t *) &surface_cache,
+ s, scache_remove))
+ {
+ scache_remove (s);
+ }
+
+ return surface;
+}
+
+static cairo_t *
+_context_create (void *closure,
+ cairo_surface_t *surface)
+{
+ scache_mark_active (surface);
+ return cairo_create (surface);
}
static int user_interrupt;
@@ -227,7 +344,8 @@ execute (cairo_perf_t *perf,
char *trace_cpy, *name, *dot;
const cairo_script_interpreter_hooks_t hooks = {
.closure = target,
- .surface_create = _similar_surface_create
+ .surface_create = _similar_surface_create,
+ .context_create = _context_create
};
trace_cpy = xstrdup (trace);
@@ -287,6 +405,8 @@ execute (cairo_perf_t *perf,
times[i] = cairo_perf_timer_elapsed ();
cairo_script_interpreter_finish (csi);
+ scache_clear ();
+
line_no = cairo_script_interpreter_get_line_number (csi);
status = cairo_script_interpreter_destroy (csi);
if (status) {
@@ -488,6 +608,7 @@ parse_options (cairo_perf_t *perf, int argc, char *argv[])
const char *iters;
char *end;
int verbose = 0;
+ int use_surface_cache = 0;
if ((iters = getenv ("CAIRO_PERF_ITERATIONS")) && *iters)
perf->iterations = strtol (iters, NULL, 0);
@@ -505,7 +626,7 @@ parse_options (cairo_perf_t *perf, int argc, char *argv[])
perf->num_exclude_names = 0;
while (1) {
- c = _cairo_getopt (argc, argv, "i:x:lrv");
+ c = _cairo_getopt (argc, argv, "i:x:lrvc");
if (c == -1)
break;
@@ -529,6 +650,9 @@ parse_options (cairo_perf_t *perf, int argc, char *argv[])
case 'v':
verbose = 1;
break;
+ case 'c':
+ use_surface_cache = 1;
+ break;
case 'x':
if (! read_excludes (perf, optarg)) {
fprintf (stderr, "Invalid argument for -x (not readable file): %s\n",
@@ -554,6 +678,9 @@ parse_options (cairo_perf_t *perf, int argc, char *argv[])
perf->names = &argv[optind];
perf->num_names = argc - optind;
}
+
+ if (use_surface_cache)
+ surface_cache = _cairo_hash_table_create (scache_equal);
}
static void
@@ -762,3 +889,9 @@ main (int argc, char *argv[])
return 0;
}
+
+cairo_status_t
+_cairo_error (cairo_status_t status)
+{
+ return status;
+}
diff --git a/test/any2ppm.c b/test/any2ppm.c
index c93e457..4d215e0 100644
--- a/test/any2ppm.c
+++ b/test/any2ppm.c
@@ -236,8 +236,8 @@ write_ppm (cairo_surface_t *surface, int fd)
static cairo_surface_t *
_create_image (void *closure,
cairo_content_t content,
- double width, double height)
- //csi_object_t *dictionary)
+ double width, double height,
+ long uid)
{
cairo_surface_t **out = closure;
cairo_format_t format;
diff --git a/util/cairo-script/cairo-script-interpreter.h b/util/cairo-script/cairo-script-interpreter.h
index 52e6b3a..6180574 100644
--- a/util/cairo-script/cairo-script-interpreter.h
+++ b/util/cairo-script/cairo-script-interpreter.h
@@ -52,7 +52,8 @@ typedef cairo_surface_t *
(*csi_surface_create_func_t) (void *closure,
cairo_content_t content,
double width,
- double height);
+ double height,
+ long uid);
typedef cairo_t *
(*csi_context_create_func_t) (void *closure,
cairo_surface_t *surface);
diff --git a/util/cairo-script/cairo-script-operators.c b/util/cairo-script/cairo-script-operators.c
index aea1a0f..31ab58e 100644
--- a/util/cairo-script/cairo-script-operators.c
+++ b/util/cairo-script/cairo-script-operators.c
@@ -5511,6 +5511,7 @@ _surface (csi_t *ctx)
csi_surface_create_func_t hook;
long content;
cairo_surface_t *surface;
+ long uid;
csi_status_t status;
check (1);
@@ -5531,10 +5532,20 @@ _surface (csi_t *ctx)
if (_csi_unlikely (status))
return status;
+ uid = 0;
+ status = _csi_dictionary_get_integer (ctx, dict, "uid", TRUE, &uid);
+ if (_csi_unlikely (status))
+ return status;
+ if (uid == 0) {
+ status = _csi_dictionary_get_integer (ctx, dict, "drawable", TRUE, &uid);
+ if (_csi_unlikely (status))
+ return status;
+ }
+
hook = ctx->hooks.surface_create;
assert (hook != NULL);
- surface = hook (ctx->hooks.closure, content, width, height);
+ surface = hook (ctx->hooks.closure, content, width, height, uid);
if (_csi_unlikely (surface == NULL)) {
return _csi_error (CSI_STATUS_NULL_POINTER);
}
diff --git a/util/cairo-sphinx/sphinx.c b/util/cairo-sphinx/sphinx.c
index 9fb5ce0..d5f0e93 100644
--- a/util/cairo-sphinx/sphinx.c
+++ b/util/cairo-sphinx/sphinx.c
@@ -963,7 +963,8 @@ send_recording (struct client *c,
static cairo_surface_t *
_surface_create (void *closure,
cairo_content_t content,
- double width, double height)
+ double width, double height,
+ long uid)
{
struct client *c = closure;
cairo_surface_t *surface;
commit c50c8b90c0033686b465e6766fba4772c1d698c6
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Mon Jan 18 16:58:40 2010 +0000
Move _cairo_error() to a standalone header
A pending commit will want to include some utility code from cairo and
so we need to extricate the error handling from the PLT symbol hiding.
diff --git a/src/Makefile.sources b/src/Makefile.sources
index 71d0abd..6dbe3fb 100644
--- a/src/Makefile.sources
+++ b/src/Makefile.sources
@@ -59,6 +59,7 @@ cairo_private = \
cairo-clip-private.h \
cairo-combsort-private.h \
cairo-compiler-private.h \
+ cairo-error-private.h \
cairo-fixed-private.h \
cairo-fixed-type-private.h \
cairo-freelist-private.h \
diff --git a/src/cairo-analysis-surface.c b/src/cairo-analysis-surface.c
index 0ba667d..019dc30 100644
--- a/src/cairo-analysis-surface.c
+++ b/src/cairo-analysis-surface.c
@@ -37,6 +37,7 @@
#include "cairoint.h"
#include "cairo-analysis-surface-private.h"
+#include "cairo-error-private.h"
#include "cairo-paginated-private.h"
#include "cairo-recording-surface-private.h"
#include "cairo-region-private.h"
diff --git a/src/cairo-array.c b/src/cairo-array.c
index fcd1246..bb6450a 100644
--- a/src/cairo-array.c
+++ b/src/cairo-array.c
@@ -36,6 +36,7 @@
*/
#include "cairoint.h"
+#include "cairo-error-private.h"
/**
* _cairo_array_init:
diff --git a/src/cairo-base64-stream.c b/src/cairo-base64-stream.c
index 2b211ff..b663cfe 100644
--- a/src/cairo-base64-stream.c
+++ b/src/cairo-base64-stream.c
@@ -37,6 +37,7 @@
*/
#include "cairoint.h"
+#include "cairo-error-private.h"
#include "cairo-output-stream-private.h"
typedef struct _cairo_base64_stream {
diff --git a/src/cairo-base85-stream.c b/src/cairo-base85-stream.c
index 791e801..6aefb05 100644
--- a/src/cairo-base85-stream.c
+++ b/src/cairo-base85-stream.c
@@ -35,6 +35,7 @@
*/
#include "cairoint.h"
+#include "cairo-error-private.h"
#include "cairo-output-stream-private.h"
typedef struct _cairo_base85_stream {
diff --git a/src/cairo-bentley-ottmann-rectangular.c b/src/cairo-bentley-ottmann-rectangular.c
index 9887b82..4a65655 100644
--- a/src/cairo-bentley-ottmann-rectangular.c
+++ b/src/cairo-bentley-ottmann-rectangular.c
@@ -38,6 +38,7 @@
/* Provide definitions for standalone compilation */
#include "cairoint.h"
+#include "cairo-error-private.h"
#include "cairo-combsort-private.h"
#include "cairo-list-private.h"
diff --git a/src/cairo-bentley-ottmann-rectilinear.c b/src/cairo-bentley-ottmann-rectilinear.c
index c7e738b..c0b4fcc 100644
--- a/src/cairo-bentley-ottmann-rectilinear.c
+++ b/src/cairo-bentley-ottmann-rectilinear.c
@@ -39,6 +39,7 @@
#include "cairoint.h"
#include "cairo-combsort-private.h"
+#include "cairo-error-private.h"
typedef struct _cairo_bo_edge cairo_bo_edge_t;
typedef struct _cairo_bo_trap cairo_bo_trap_t;
diff --git a/src/cairo-bentley-ottmann.c b/src/cairo-bentley-ottmann.c
index cb508f5..81cca79 100644
--- a/src/cairo-bentley-ottmann.c
+++ b/src/cairo-bentley-ottmann.c
@@ -38,6 +38,7 @@
/* Provide definitions for standalone compilation */
#include "cairoint.h"
+#include "cairo-error-private.h"
#include "cairo-freelist-private.h"
#include "cairo-combsort-private.h"
diff --git a/src/cairo-beos-surface.cpp b/src/cairo-beos-surface.cpp
index 6fbdc47..68d0814 100644
--- a/src/cairo-beos-surface.cpp
+++ b/src/cairo-beos-surface.cpp
@@ -40,6 +40,8 @@
#include "cairo-beos.h"
+#include "cairo-error-private.h"
+
#include <new>
#include <Bitmap.h>
diff --git a/src/cairo-cache.c b/src/cairo-cache.c
index 025dd9f..1bc3089 100644
--- a/src/cairo-cache.c
+++ b/src/cairo-cache.c
@@ -37,6 +37,7 @@
*/
#include "cairoint.h"
+#include "cairo-error-private.h"
static void
_cairo_cache_shrink_to_accommodate (cairo_cache_t *cache,
diff --git a/src/cairo-cff-subset.c b/src/cairo-cff-subset.c
index 1f4cb92..1ccc53c 100644
--- a/src/cairo-cff-subset.c
+++ b/src/cairo-cff-subset.c
@@ -41,6 +41,7 @@
#define _BSD_SOURCE /* for snprintf(), strdup() */
#include "cairoint.h"
+#include "cairo-error-private.h"
#if CAIRO_HAS_FONT_SUBSET
diff --git a/src/cairo-clip.c b/src/cairo-clip.c
index 8d66a5f..2a50385 100644
--- a/src/cairo-clip.c
+++ b/src/cairo-clip.c
@@ -41,6 +41,7 @@
#include "cairoint.h"
#include "cairo-clip-private.h"
+#include "cairo-error-private.h"
#include "cairo-path-fixed-private.h"
#include "cairo-region-private.h"
diff --git a/src/cairo-deflate-stream.c b/src/cairo-deflate-stream.c
index 863189f..f4c41ca 100644
--- a/src/cairo-deflate-stream.c
+++ b/src/cairo-deflate-stream.c
@@ -35,6 +35,7 @@
*/
#include "cairoint.h"
+#include "cairo-error-private.h"
#include "cairo-output-stream-private.h"
#include <zlib.h>
diff --git a/src/cairo-directfb-surface.c b/src/cairo-directfb-surface.c
index afad270..0d39e4b 100644
--- a/src/cairo-directfb-surface.c
+++ b/src/cairo-directfb-surface.c
@@ -39,6 +39,7 @@
#include "cairo-directfb.h"
#include "cairo-clip-private.h"
+#include "cairo-error-private.h"
#include <pixman.h>
diff --git a/src/cairo-eagle-context.c b/src/cairo-eagle-context.c
index 23766a9..72efc2e 100644
--- a/src/cairo-eagle-context.c
+++ b/src/cairo-eagle-context.c
@@ -40,6 +40,7 @@
#include "cairo-gl-private.h"
+#include "cairo-error-private.h"
#include <i915_drm.h> /* XXX dummy surface for glewInit() */
#include <sys/ioctl.h>
diff --git a/src/cairo-error-private.h b/src/cairo-error-private.h
new file mode 100644
index 0000000..6bcda75
--- /dev/null
+++ b/src/cairo-error-private.h
@@ -0,0 +1,60 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2002 University of Southern California
+ * 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 University of Southern
+ * California.
+ *
+ * Contributor(s):
+ * Carl D. Worth <cworth at cworth.org>
+ */
+
+#ifndef _CAIRO_ERROR_PRIVATE_H_
+#define _CAIRO_ERROR_PRIVATE_H_
+
+#include "cairo.h"
+#include "cairo-compiler-private.h"
+
+CAIRO_BEGIN_DECLS
+
+#define _cairo_status_is_error(status) \
+ (status != CAIRO_STATUS_SUCCESS && status <= CAIRO_STATUS_LAST_STATUS)
+
+cairo_private cairo_status_t
+_cairo_error (cairo_status_t status);
+
+/* hide compiler warnings when discarding the return value */
+#define _cairo_error_throw(status) do { \
+ cairo_status_t status__ = _cairo_error (status); \
+ (void) status__; \
+} while (0)
+
+CAIRO_END_DECLS
+
+#endif /* _CAIRO_ERROR_PRIVATE_H_ */
diff --git a/src/cairo-font-face-twin.c b/src/cairo-font-face-twin.c
index 56ebaea..2ce0858 100644
--- a/src/cairo-font-face-twin.c
+++ b/src/cairo-font-face-twin.c
@@ -35,6 +35,7 @@
*/
#include "cairoint.h"
+#include "cairo-error-private.h"
#include <math.h>
diff --git a/src/cairo-font-face.c b/src/cairo-font-face.c
index 6744899..3e73aac 100644
--- a/src/cairo-font-face.c
+++ b/src/cairo-font-face.c
@@ -39,6 +39,7 @@
*/
#include "cairoint.h"
+#include "cairo-error-private.h"
/* #cairo_font_face_t */
diff --git a/src/cairo-font-options.c b/src/cairo-font-options.c
index b2cb230..9d10075 100644
--- a/src/cairo-font-options.c
+++ b/src/cairo-font-options.c
@@ -35,6 +35,7 @@
*/
#include "cairoint.h"
+#include "cairo-error-private.h"
static const cairo_font_options_t _cairo_font_options_nil = {
CAIRO_ANTIALIAS_DEFAULT,
diff --git a/src/cairo-freelist.c b/src/cairo-freelist.c
index acf3157..a62976e 100644
--- a/src/cairo-freelist.c
+++ b/src/cairo-freelist.c
@@ -22,6 +22,7 @@
#include "cairoint.h"
+#include "cairo-error-private.h"
#include "cairo-freelist-private.h"
void
diff --git a/src/cairo-ft-font.c b/src/cairo-ft-font.c
index 447855c..1c56031 100644
--- a/src/cairo-ft-font.c
+++ b/src/cairo-ft-font.c
@@ -41,6 +41,7 @@
#define _BSD_SOURCE /* for strdup() */
#include "cairoint.h"
+#include "cairo-error-private.h"
#include "cairo-ft-private.h"
#include <float.h>
diff --git a/src/cairo-gl-glyphs.c b/src/cairo-gl-glyphs.c
index ecbbd0b..35546ff 100644
--- a/src/cairo-gl-glyphs.c
+++ b/src/cairo-gl-glyphs.c
@@ -33,6 +33,8 @@
#include "cairoint.h"
#include "cairo-gl-private.h"
+
+#include "cairo-error-private.h"
#include "cairo-rtree-private.h"
#define GLYPH_CACHE_WIDTH 1024
diff --git a/src/cairo-gl-shaders.c b/src/cairo-gl-shaders.c
index f06991e..5eb8e68 100644
--- a/src/cairo-gl-shaders.c
+++ b/src/cairo-gl-shaders.c
@@ -32,6 +32,7 @@
#include "cairoint.h"
#include "cairo-gl-private.h"
+#include "cairo-error-private.h"
static GLint
_cairo_gl_compile_glsl(GLenum type, GLint *shader_out, const char *source)
diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index 5335e4b..4fa0790 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -37,6 +37,7 @@
#include "cairoint.h"
+#include "cairo-error-private.h"
#include "cairo-gl-private.h"
slim_hidden_proto (cairo_gl_context_reference);
diff --git a/src/cairo-glitz-surface.c b/src/cairo-glitz-surface.c
index 5f97f65..73bc995 100644
--- a/src/cairo-glitz-surface.c
+++ b/src/cairo-glitz-surface.c
@@ -27,6 +27,8 @@
#include "cairoint.h"
#include "cairo-glitz.h"
#include "cairo-glitz-private.h"
+
+#include "cairo-error-private.h"
#include "cairo-region-private.h"
typedef struct _cairo_glitz_surface {
diff --git a/src/cairo-glx-context.c b/src/cairo-glx-context.c
index b442a1f..3fd6317 100644
--- a/src/cairo-glx-context.c
+++ b/src/cairo-glx-context.c
@@ -40,6 +40,8 @@
#include "cairo-gl-private.h"
+#include "cairo-error-private.h"
+
#include <X11/Xutil.h>
/* XXX needs hooking into XCloseDisplay() */
diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c
index 2799392..3fbdb1e 100644
--- a/src/cairo-gstate.c
+++ b/src/cairo-gstate.c
@@ -40,6 +40,7 @@
#include "cairoint.h"
#include "cairo-clip-private.h"
+#include "cairo-error-private.h"
#include "cairo-gstate-private.h"
#if _XOPEN_SOURCE >= 600 || defined (_ISOC99_SOURCE)
diff --git a/src/cairo-hash.c b/src/cairo-hash.c
index 15159d9..86b6277 100644
--- a/src/cairo-hash.c
+++ b/src/cairo-hash.c
@@ -37,6 +37,7 @@
*/
#include "cairoint.h"
+#include "cairo-error-private.h"
/*
* An entry can be in one of three states:
diff --git a/src/cairo-hull.c b/src/cairo-hull.c
index 8a1a31e..abd8dbf 100644
--- a/src/cairo-hull.c
+++ b/src/cairo-hull.c
@@ -36,6 +36,7 @@
#include "cairoint.h"
+#include "cairo-error-private.h"
#include "cairo-slope-private.h"
typedef struct cairo_hull {
diff --git a/src/cairo-image-surface.c b/src/cairo-image-surface.c
index e644aad..339e4d2 100644
--- a/src/cairo-image-surface.c
+++ b/src/cairo-image-surface.c
@@ -38,6 +38,7 @@
#include "cairoint.h"
#include "cairo-clip-private.h"
+#include "cairo-error-private.h"
#include "cairo-region-private.h"
/* Limit on the width / height of an image surface in pixels. This is
diff --git a/src/cairo-lzw.c b/src/cairo-lzw.c
index a4fdf73..c295f86 100644
--- a/src/cairo-lzw.c
+++ b/src/cairo-lzw.c
@@ -35,6 +35,7 @@
*/
#include "cairoint.h"
+#include "cairo-error-private.h"
typedef struct _lzw_buf {
cairo_status_t status;
diff --git a/src/cairo-matrix.c b/src/cairo-matrix.c
index bf20ee4..bf97273 100644
--- a/src/cairo-matrix.c
+++ b/src/cairo-matrix.c
@@ -37,6 +37,7 @@
#define _GNU_SOURCE
#include "cairoint.h"
+#include "cairo-error-private.h"
#if _XOPEN_SOURCE >= 600 || defined (_ISOC99_SOURCE)
#define ISFINITE(x) isfinite (x)
diff --git a/src/cairo-misc.c b/src/cairo-misc.c
index 56c7d0b..c0a792e 100644
--- a/src/cairo-misc.c
+++ b/src/cairo-misc.c
@@ -39,6 +39,7 @@
*/
#include "cairoint.h"
+#include "cairo-error-private.h"
COMPILE_TIME_ASSERT (CAIRO_STATUS_LAST_STATUS < CAIRO_INT_STATUS_UNSUPPORTED);
COMPILE_TIME_ASSERT (CAIRO_INT_STATUS_LAST_STATUS <= 127);
diff --git a/src/cairo-os2-surface.c b/src/cairo-os2-surface.c
index 3fda0b4..d9eaafa 100644
--- a/src/cairo-os2-surface.c
+++ b/src/cairo-os2-surface.c
@@ -38,6 +38,7 @@
#include "cairoint.h"
#include "cairo-os2-private.h"
+#include "cairo-error-private.h"
#if CAIRO_HAS_FC_FONT
#include <fontconfig/fontconfig.h>
diff --git a/src/cairo-output-stream.c b/src/cairo-output-stream.c
index 20f676c..ceaa506 100644
--- a/src/cairo-output-stream.c
+++ b/src/cairo-output-stream.c
@@ -37,6 +37,7 @@
#include "cairoint.h"
#include "cairo-output-stream-private.h"
+#include "cairo-error-private.h"
#include "cairo-compiler-private.h"
#include <stdio.h>
diff --git a/src/cairo-paginated-surface.c b/src/cairo-paginated-surface.c
index dff5e83..b5f619b 100644
--- a/src/cairo-paginated-surface.c
+++ b/src/cairo-paginated-surface.c
@@ -48,6 +48,7 @@
#include "cairo-paginated-surface-private.h"
#include "cairo-recording-surface-private.h"
#include "cairo-analysis-surface-private.h"
+#include "cairo-error-private.h"
static const cairo_surface_backend_t cairo_paginated_surface_backend;
diff --git a/src/cairo-path-fill.c b/src/cairo-path-fill.c
index 037b807..e3c9129 100644
--- a/src/cairo-path-fill.c
+++ b/src/cairo-path-fill.c
@@ -35,6 +35,7 @@
*/
#include "cairoint.h"
+#include "cairo-error-private.h"
#include "cairo-path-fixed-private.h"
#include "cairo-region-private.h"
diff --git a/src/cairo-path-fixed.c b/src/cairo-path-fixed.c
index 34de6a3..958c85c 100644
--- a/src/cairo-path-fixed.c
+++ b/src/cairo-path-fixed.c
@@ -38,6 +38,7 @@
#include "cairoint.h"
+#include "cairo-error-private.h"
#include "cairo-path-fixed-private.h"
#include "cairo-slope-private.h"
diff --git a/src/cairo-path-stroke.c b/src/cairo-path-stroke.c
index 6e1986a..9c79d77 100644
--- a/src/cairo-path-stroke.c
+++ b/src/cairo-path-stroke.c
@@ -39,6 +39,7 @@
#define _BSD_SOURCE /* for hypot() */
#include "cairoint.h"
+#include "cairo-error-private.h"
#include "cairo-path-fixed-private.h"
#include "cairo-slope-private.h"
diff --git a/src/cairo-path.c b/src/cairo-path.c
index 0544505..29c968e 100644
--- a/src/cairo-path.c
+++ b/src/cairo-path.c
@@ -37,6 +37,7 @@
#include "cairoint.h"
#include "cairo-private.h"
+#include "cairo-error-private.h"
#include "cairo-path-private.h"
#include "cairo-path-fixed-private.h"
diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c
index 598d204..f5e5b9d 100644
--- a/src/cairo-pattern.c
+++ b/src/cairo-pattern.c
@@ -29,6 +29,7 @@
*/
#include "cairoint.h"
+#include "cairo-error-private.h"
static const cairo_solid_pattern_t _cairo_pattern_nil = {
{ CAIRO_PATTERN_TYPE_SOLID, /* type */
diff --git a/src/cairo-pdf-operators.c b/src/cairo-pdf-operators.c
index 7b88092..e4a0723 100644
--- a/src/cairo-pdf-operators.c
+++ b/src/cairo-pdf-operators.c
@@ -43,6 +43,7 @@
#if CAIRO_HAS_PDF_OPERATORS
+#include "cairo-error-private.h"
#include "cairo-pdf-operators-private.h"
#include "cairo-path-fixed-private.h"
#include "cairo-output-stream-private.h"
diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c
index a1be10a..515e9f6 100644
--- a/src/cairo-pdf-surface.c
+++ b/src/cairo-pdf-surface.c
@@ -45,6 +45,7 @@
#include "cairo-pdf-surface-private.h"
#include "cairo-pdf-operators-private.h"
#include "cairo-analysis-surface-private.h"
+#include "cairo-error-private.h"
#include "cairo-image-info-private.h"
#include "cairo-recording-surface-private.h"
#include "cairo-output-stream-private.h"
diff --git a/src/cairo-pen.c b/src/cairo-pen.c
index cfb67ca..01b3465 100644
--- a/src/cairo-pen.c
+++ b/src/cairo-pen.c
@@ -38,6 +38,7 @@
#include "cairoint.h"
+#include "cairo-error-private.h"
#include "cairo-slope-private.h"
static int
diff --git a/src/cairo-png.c b/src/cairo-png.c
index d4f0476..f89e03f 100644
--- a/src/cairo-png.c
+++ b/src/cairo-png.c
@@ -37,6 +37,8 @@
*/
#include "cairoint.h"
+
+#include "cairo-error-private.h"
#include "cairo-output-stream-private.h"
#include <stdio.h>
diff --git a/src/cairo-polygon.c b/src/cairo-polygon.c
index 9cb76e5..68c69e8 100644
--- a/src/cairo-polygon.c
+++ b/src/cairo-polygon.c
@@ -36,6 +36,7 @@
#include "cairoint.h"
+#include "cairo-error-private.h"
#include "cairo-slope-private.h"
void
diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c
index fd3c73d..72dcbd4 100644
--- a/src/cairo-ps-surface.c
+++ b/src/cairo-ps-surface.c
@@ -58,6 +58,7 @@
#include "cairo-ps.h"
#include "cairo-ps-surface-private.h"
#include "cairo-pdf-operators-private.h"
+#include "cairo-error-private.h"
#include "cairo-scaled-font-subsets-private.h"
#include "cairo-paginated-private.h"
#include "cairo-recording-surface-private.h"
diff --git a/src/cairo-qt-surface.cpp b/src/cairo-qt-surface.cpp
index 29ca0be..58d59b5 100644
--- a/src/cairo-qt-surface.cpp
+++ b/src/cairo-qt-surface.cpp
@@ -38,10 +38,12 @@
#define __STDC_LIMIT_MACROS
#include "cairoint.h"
-#include "cairo-types-private.h"
+
#include "cairo-clip-private.h"
-#include "cairo-surface-clipper-private.h"
+#include "cairo-error-private.h"
#include "cairo-region-private.h"
+#include "cairo-surface-clipper-private.h"
+#include "cairo-types-private.h"
#include "cairo-qt.h"
diff --git a/src/cairo-quartz-font.c b/src/cairo-quartz-font.c
index a8a9fc5..0ed2a50 100644
--- a/src/cairo-quartz-font.c
+++ b/src/cairo-quartz-font.c
@@ -41,6 +41,8 @@
#include "cairo-quartz.h"
#include "cairo-quartz-private.h"
+#include "cairo-error-private.h"
+
/* CreateWithFontName exists in 10.5, but not in 10.4; CreateWithName isn't public in 10.4 */
static CGFontRef (*CGFontCreateWithFontNamePtr) (CFStringRef) = NULL;
static CGFontRef (*CGFontCreateWithNamePtr) (const char *) = NULL;
diff --git a/src/cairo-quartz-image-surface.c b/src/cairo-quartz-image-surface.c
index 27d8d6d..6fdb35c 100644
--- a/src/cairo-quartz-image-surface.c
+++ b/src/cairo-quartz-image-surface.c
@@ -39,6 +39,8 @@
#include "cairo-quartz-image.h"
#include "cairo-quartz-private.h"
+#include "cairo-error-private.h"
+
#define SURFACE_ERROR_NO_MEMORY (_cairo_surface_create_in_error(_cairo_error(CAIRO_STATUS_NO_MEMORY)))
#define SURFACE_ERROR_TYPE_MISMATCH (_cairo_surface_create_in_error(_cairo_error(CAIRO_STATUS_SURFACE_TYPE_MISMATCH)))
#define SURFACE_ERROR_INVALID_SIZE (_cairo_surface_create_in_error(_cairo_error(CAIRO_STATUS_INVALID_SIZE)))
diff --git a/src/cairo-quartz-surface.c b/src/cairo-quartz-surface.c
index 9e1cf5f..78ef3ee 100644
--- a/src/cairo-quartz-surface.c
+++ b/src/cairo-quartz-surface.c
@@ -38,6 +38,8 @@
#include "cairoint.h"
#include "cairo-quartz-private.h"
+
+#include "cairo-error-private.h"
#include "cairo-surface-clipper-private.h"
#include <dlfcn.h>
diff --git a/src/cairo-recording-surface.c b/src/cairo-recording-surface.c
index c50b330..54260e0 100644
--- a/src/cairo-recording-surface.c
+++ b/src/cairo-recording-surface.c
@@ -74,8 +74,9 @@
#include "cairoint.h"
#include "cairo-analysis-surface-private.h"
-#include "cairo-recording-surface-private.h"
#include "cairo-clip-private.h"
+#include "cairo-error-private.h"
+#include "cairo-recording-surface-private.h"
#include "cairo-surface-wrapper-private.h"
typedef enum {
diff --git a/src/cairo-region.c b/src/cairo-region.c
index 2148fca..6ccd735 100644
--- a/src/cairo-region.c
+++ b/src/cairo-region.c
@@ -38,6 +38,7 @@
#include "cairoint.h"
+#include "cairo-error-private.h"
#include "cairo-region-private.h"
/* XXX need to update pixman headers to be const as appropriate */
diff --git a/src/cairo-rtree.c b/src/cairo-rtree.c
index d4bdbd4..8006113 100644
--- a/src/cairo-rtree.c
+++ b/src/cairo-rtree.c
@@ -36,6 +36,7 @@
#include "cairoint.h"
+#include "cairo-error-private.h"
#include "cairo-rtree-private.h"
cairo_rtree_node_t *
diff --git a/src/cairo-scaled-font-subsets.c b/src/cairo-scaled-font-subsets.c
index 0547829..e911f31 100644
--- a/src/cairo-scaled-font-subsets.c
+++ b/src/cairo-scaled-font-subsets.c
@@ -42,6 +42,7 @@
#define _BSD_SOURCE /* for snprintf(), strdup() */
#include "cairoint.h"
+#include "cairo-error-private.h"
#if CAIRO_HAS_FONT_SUBSET
diff --git a/src/cairo-scaled-font.c b/src/cairo-scaled-font.c
index e4010e9..91d8917 100644
--- a/src/cairo-scaled-font.c
+++ b/src/cairo-scaled-font.c
@@ -41,6 +41,7 @@
#define _GNU_SOURCE
#include "cairoint.h"
+#include "cairo-error-private.h"
#include "cairo-scaled-font-private.h"
#if _XOPEN_SOURCE >= 600 || defined (_ISOC99_SOURCE)
diff --git a/src/cairo-script-surface.c b/src/cairo-script-surface.c
index ec06364..8b04c8a 100644
--- a/src/cairo-script-surface.c
+++ b/src/cairo-script-surface.c
@@ -47,6 +47,7 @@
#include "cairo-script.h"
#include "cairo-analysis-surface-private.h"
+#include "cairo-error-private.h"
#include "cairo-ft-private.h"
#include "cairo-list-private.h"
#include "cairo-recording-surface-private.h"
diff --git a/src/cairo-stroke-style.c b/src/cairo-stroke-style.c
index 36afeeb..eac69db 100644
--- a/src/cairo-stroke-style.c
+++ b/src/cairo-stroke-style.c
@@ -34,6 +34,7 @@
*/
#include "cairoint.h"
+#include "cairo-error-private.h"
void
_cairo_stroke_style_init (cairo_stroke_style_t *style)
diff --git a/src/cairo-surface-fallback.c b/src/cairo-surface-fallback.c
index c5ef274..c9f9a01 100644
--- a/src/cairo-surface-fallback.c
+++ b/src/cairo-surface-fallback.c
@@ -42,6 +42,7 @@
#include "cairo-surface-fallback-private.h"
#include "cairo-clip-private.h"
+#include "cairo-error-private.h"
#include "cairo-region-private.h"
#include "cairo-spans-private.h"
diff --git a/src/cairo-surface-wrapper.c b/src/cairo-surface-wrapper.c
index c5fe44d..d03c203 100644
--- a/src/cairo-surface-wrapper.c
+++ b/src/cairo-surface-wrapper.c
@@ -37,6 +37,7 @@
#include "cairoint.h"
+#include "cairo-error-private.h"
#include "cairo-surface-wrapper-private.h"
/* A collection of routines to facilitate surface wrapping */
diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index 9aa707f..5753277 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -40,6 +40,7 @@
#include "cairo-surface-fallback-private.h"
#include "cairo-clip-private.h"
+#include "cairo-error-private.h"
#include "cairo-recording-surface-private.h"
#include "cairo-region-private.h"
#include "cairo-tee-surface-private.h"
diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c
index fa25b82..88765f3 100644
--- a/src/cairo-svg-surface.c
+++ b/src/cairo-svg-surface.c
@@ -43,6 +43,7 @@
#include "cairoint.h"
#include "cairo-svg.h"
#include "cairo-analysis-surface-private.h"
+#include "cairo-error-private.h"
#include "cairo-image-info-private.h"
#include "cairo-recording-surface-private.h"
#include "cairo-output-stream-private.h"
diff --git a/src/cairo-tee-surface.c b/src/cairo-tee-surface.c
index 1111fa1..76f4b9d 100644
--- a/src/cairo-tee-surface.c
+++ b/src/cairo-tee-surface.c
@@ -40,6 +40,7 @@
#include "cairoint.h"
+#include "cairo-error-private.h"
#include "cairo-tee-surface-private.h"
#include "cairo-surface-wrapper-private.h"
diff --git a/src/cairo-tor-scan-converter.c b/src/cairo-tor-scan-converter.c
index 29262c2..d18b25a 100644
--- a/src/cairo-tor-scan-converter.c
+++ b/src/cairo-tor-scan-converter.c
@@ -95,6 +95,7 @@
*/
#include "cairoint.h"
#include "cairo-spans-private.h"
+#include "cairo-error-private.h"
#include <assert.h>
#include <stdlib.h>
diff --git a/src/cairo-toy-font-face.c b/src/cairo-toy-font-face.c
index e7c841a..74177d7 100644
--- a/src/cairo-toy-font-face.c
+++ b/src/cairo-toy-font-face.c
@@ -41,6 +41,7 @@
#define _BSD_SOURCE /* for strdup() */
#include "cairoint.h"
+#include "cairo-error-private.h"
static const cairo_font_face_t _cairo_font_face_null_pointer = {
diff --git a/src/cairo-traps.c b/src/cairo-traps.c
index 70d4c69..8c7e7a8 100644
--- a/src/cairo-traps.c
+++ b/src/cairo-traps.c
@@ -39,6 +39,7 @@
#include "cairoint.h"
+#include "cairo-error-private.h"
#include "cairo-region-private.h"
#include "cairo-slope-private.h"
diff --git a/src/cairo-truetype-subset.c b/src/cairo-truetype-subset.c
index 3a813ee..b006065 100644
--- a/src/cairo-truetype-subset.c
+++ b/src/cairo-truetype-subset.c
@@ -42,6 +42,7 @@
#define _BSD_SOURCE /* for snprintf(), strdup() */
#include "cairoint.h"
+#include "cairo-error-private.h"
#if CAIRO_HAS_FONT_SUBSET
diff --git a/src/cairo-type1-fallback.c b/src/cairo-type1-fallback.c
index 1023bbd..e43fd40 100644
--- a/src/cairo-type1-fallback.c
+++ b/src/cairo-type1-fallback.c
@@ -35,6 +35,7 @@
#define _BSD_SOURCE /* for snprintf(), strdup() */
#include "cairoint.h"
+#include "cairo-error-private.h"
#if CAIRO_HAS_FONT_SUBSET
diff --git a/src/cairo-type1-subset.c b/src/cairo-type1-subset.c
index 7ded39a..0c4e0a5 100644
--- a/src/cairo-type1-subset.c
+++ b/src/cairo-type1-subset.c
@@ -41,6 +41,7 @@
#define _BSD_SOURCE /* for snprintf(), strdup() */
#include "cairoint.h"
+#include "cairo-error-private.h"
#if CAIRO_HAS_FONT_SUBSET
diff --git a/src/cairo-type3-glyph-surface.c b/src/cairo-type3-glyph-surface.c
index 6878bba..60698d4 100644
--- a/src/cairo-type3-glyph-surface.c
+++ b/src/cairo-type3-glyph-surface.c
@@ -42,6 +42,7 @@
#include "cairo-output-stream-private.h"
#include "cairo-recording-surface-private.h"
#include "cairo-analysis-surface-private.h"
+#include "cairo-error-private.h"
#include "cairo-surface-clipper-private.h"
static const cairo_surface_backend_t cairo_type3_glyph_surface_backend;
diff --git a/src/cairo-unicode.c b/src/cairo-unicode.c
index b1567d4..5bb6604 100644
--- a/src/cairo-unicode.c
+++ b/src/cairo-unicode.c
@@ -41,6 +41,7 @@
*/
#include "cairoint.h"
+#include "cairo-error-private.h"
#define UTF8_COMPUTE(Char, Mask, Len) \
if (Char < 128) \
diff --git a/src/cairo-user-font.c b/src/cairo-user-font.c
index 3304392..d73a71a 100644
--- a/src/cairo-user-font.c
+++ b/src/cairo-user-font.c
@@ -38,6 +38,7 @@
#include "cairo-user-font-private.h"
#include "cairo-recording-surface-private.h"
#include "cairo-analysis-surface-private.h"
+#include "cairo-error-private.h"
typedef struct _cairo_user_scaled_font_methods {
cairo_user_scaled_font_init_func_t init;
diff --git a/src/cairo-vg-surface.c b/src/cairo-vg-surface.c
index 5ca01b6..30da7ea 100644
--- a/src/cairo-vg-surface.c
+++ b/src/cairo-vg-surface.c
@@ -38,10 +38,11 @@
#include "cairo-vg.h"
+#include "cairo-cache-private.h"
+#include "cairo-error-private.h"
#include "cairo-path-fixed-private.h"
#include "cairo-recording-surface-private.h"
#include "cairo-surface-clipper-private.h"
-#include "cairo-cache-private.h"
#include <pixman.h>
#include <VG/openvg.h>
diff --git a/src/cairo-win32-font.c b/src/cairo-win32-font.c
index 7a86cc8..bb4f1b0 100644
--- a/src/cairo-win32-font.c
+++ b/src/cairo-win32-font.c
@@ -45,6 +45,7 @@
#include "cairoint.h"
#include "cairo-win32-private.h"
+#include "cairo-error-private.h"
#ifndef SPI_GETFONTSMOOTHINGTYPE
#define SPI_GETFONTSMOOTHINGTYPE 0x200a
diff --git a/src/cairo-win32-printing-surface.c b/src/cairo-win32-printing-surface.c
index 173c933..aff71ec 100644
--- a/src/cairo-win32-printing-surface.c
+++ b/src/cairo-win32-printing-surface.c
@@ -46,6 +46,7 @@
#include "cairoint.h"
+#include "cairo-error-private.h"
#include "cairo-paginated-private.h"
#include "cairo-clip-private.h"
diff --git a/src/cairo-win32-surface.c b/src/cairo-win32-surface.c
index c250668..0ec48be 100644
--- a/src/cairo-win32-surface.c
+++ b/src/cairo-win32-surface.c
@@ -48,6 +48,7 @@
#include "cairoint.h"
#include "cairo-clip-private.h"
+#include "cairo-error-private.h"
#include "cairo-paginated-private.h"
#include "cairo-win32-private.h"
#include "cairo-scaled-font-subsets-private.h"
diff --git a/src/cairo-xcb-surface.c b/src/cairo-xcb-surface.c
index 8cd82f0..1932c4e 100644
--- a/src/cairo-xcb-surface.c
+++ b/src/cairo-xcb-surface.c
@@ -38,8 +38,9 @@
#include "cairo-xcb.h"
#include "cairo-xcb-xrender.h"
#include "cairo-clip-private.h"
-#include "cairo-list-private.h"
+#include "cairo-error-private.h"
#include "cairo-freelist-private.h"
+#include "cairo-list-private.h"
#include <xcb/xcb_renderutil.h>
#define AllPlanes ((unsigned long)~0L)
diff --git a/src/cairo-xlib-display.c b/src/cairo-xlib-display.c
index 56ea7c8..d8715c6 100644
--- a/src/cairo-xlib-display.c
+++ b/src/cairo-xlib-display.c
@@ -38,6 +38,7 @@
#include "cairo-xlib-private.h"
#include "cairo-xlib-xrender-private.h"
+#include "cairo-error-private.h"
#include "cairo-freelist-private.h"
#include <X11/Xlibint.h> /* For XESetCloseDisplay */
diff --git a/src/cairo-xlib-screen.c b/src/cairo-xlib-screen.c
index 09a2a81..699b7d5 100644
--- a/src/cairo-xlib-screen.c
+++ b/src/cairo-xlib-screen.c
@@ -58,6 +58,7 @@
#include "cairo-xlib-xrender-private.h"
#include "cairo-xlib-surface-private.h"
+#include "cairo-error-private.h"
#include <fontconfig/fontconfig.h>
diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c
index 7e5935d..544e733 100644
--- a/src/cairo-xlib-surface.c
+++ b/src/cairo-xlib-surface.c
@@ -50,6 +50,7 @@
#include "cairo-xlib-private.h"
#include "cairo-xlib-surface-private.h"
#include "cairo-clip-private.h"
+#include "cairo-error-private.h"
#include "cairo-scaled-font-private.h"
#include "cairo-region-private.h"
diff --git a/src/cairo-xlib-visual.c b/src/cairo-xlib-visual.c
index 7dbe86c..aa16722 100644
--- a/src/cairo-xlib-visual.c
+++ b/src/cairo-xlib-visual.c
@@ -37,6 +37,8 @@
#include "cairo-xlib-private.h"
+#include "cairo-error-private.h"
+
/* A perceptual distance metric between two colors. No sqrt needed
* since the square of the distance is still a valid metric. */
diff --git a/src/cairo-xml-surface.c b/src/cairo-xml-surface.c
index 25e0bb2..f32ea9d 100644
--- a/src/cairo-xml-surface.c
+++ b/src/cairo-xml-surface.c
@@ -45,6 +45,7 @@
#include "cairo-xml.h"
#include "cairo-clip-private.h"
+#include "cairo-error-private.h"
#include "cairo-output-stream-private.h"
#include "cairo-recording-surface-private.h"
diff --git a/src/cairo.c b/src/cairo.c
index 3c9d892..4be3e44 100644
--- a/src/cairo.c
+++ b/src/cairo.c
@@ -40,6 +40,7 @@
#include "cairo-private.h"
#include "cairo-arc-private.h"
+#include "cairo-error-private.h"
#include "cairo-path-private.h"
#define CAIRO_TOLERANCE_MINIMUM _cairo_fixed_to_double(1)
diff --git a/src/cairoint.h b/src/cairoint.h
index 14a9491..a224347 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -2618,18 +2618,6 @@ _cairo_utf8_to_utf16 (const char *str,
int *items_written);
#endif
-#define _cairo_status_is_error(status) \
- (status != CAIRO_STATUS_SUCCESS && status <= CAIRO_STATUS_LAST_STATUS)
-
-cairo_private cairo_status_t
-_cairo_error (cairo_status_t status);
-
-/* hide compiler warnings when discarding the return value */
-#define _cairo_error_throw(status) do { \
- cairo_status_t status__ = _cairo_error (status); \
- (void) status__; \
-} while (0)
-
/* Avoid unnecessary PLT entries. */
slim_hidden_proto (cairo_clip_preserve);
slim_hidden_proto (cairo_close_path);
diff --git a/src/drm/cairo-drm-bo.c b/src/drm/cairo-drm-bo.c
index 3346fc9..980484a 100644
--- a/src/drm/cairo-drm-bo.c
+++ b/src/drm/cairo-drm-bo.c
@@ -31,6 +31,7 @@
#include "cairo-drm-private.h"
#include "cairo-drm-ioctl-private.h"
+#include "cairo-error-private.h"
#include <sys/ioctl.h>
#include <errno.h>
diff --git a/src/drm/cairo-drm-intel-surface.c b/src/drm/cairo-drm-intel-surface.c
index 2152c59..b69eaf3 100644
--- a/src/drm/cairo-drm-intel-surface.c
+++ b/src/drm/cairo-drm-intel-surface.c
@@ -31,6 +31,7 @@
#include "cairo-drm-private.h"
#include "cairo-drm-intel-private.h"
+#include "cairo-error-private.h"
/* Basic generic/stub surface for intel chipsets */
diff --git a/src/drm/cairo-drm-intel.c b/src/drm/cairo-drm-intel.c
index 5a37f00..6c8a8fd 100644
--- a/src/drm/cairo-drm-intel.c
+++ b/src/drm/cairo-drm-intel.c
@@ -32,6 +32,7 @@
#include "cairo-drm-private.h"
#include "cairo-drm-ioctl-private.h"
#include "cairo-drm-intel-private.h"
+#include "cairo-error-private.h"
#include "cairo-freelist-private.h"
#include <sys/ioctl.h>
diff --git a/src/drm/cairo-drm-radeon-surface.c b/src/drm/cairo-drm-radeon-surface.c
index 9493162..7a26be4 100644
--- a/src/drm/cairo-drm-radeon-surface.c
+++ b/src/drm/cairo-drm-radeon-surface.c
@@ -31,6 +31,7 @@
#include "cairo-drm-private.h"
#include "cairo-drm-radeon-private.h"
+#include "cairo-error-private.h"
/* Basic stub surface for radeon chipsets */
diff --git a/src/drm/cairo-drm-radeon.c b/src/drm/cairo-drm-radeon.c
index 9654be6..e435d70 100644
--- a/src/drm/cairo-drm-radeon.c
+++ b/src/drm/cairo-drm-radeon.c
@@ -32,6 +32,7 @@
#include "cairo-drm-private.h"
#include "cairo-drm-radeon-private.h"
#include "cairo-drm-ioctl-private.h"
+#include "cairo-error-private.h"
#include <sys/ioctl.h>
#include <sys/mman.h>
diff --git a/src/drm/cairo-drm-surface.c b/src/drm/cairo-drm-surface.c
index 860d099..a8f9ab1 100644
--- a/src/drm/cairo-drm-surface.c
+++ b/src/drm/cairo-drm-surface.c
@@ -33,6 +33,7 @@
#include "cairoint.h"
#include "cairo-drm-private.h"
+#include "cairo-error-private.h"
#include "cairo-surface-fallback-private.h"
cairo_surface_t *
diff --git a/src/drm/cairo-drm.c b/src/drm/cairo-drm.c
index 9d227b3..a218fa5 100644
--- a/src/drm/cairo-drm.c
+++ b/src/drm/cairo-drm.c
@@ -33,6 +33,7 @@
#include "cairoint.h"
#include "cairo-drm-private.h"
+#include "cairo-error-private.h"
#define LIBUDEV_I_KNOW_THE_API_IS_SUBJECT_TO_CHANGE
#include <libudev.h>
diff --git a/src/test-fallback-surface.c b/src/test-fallback-surface.c
index 3b62e55..78f339f 100644
--- a/src/test-fallback-surface.c
+++ b/src/test-fallback-surface.c
@@ -54,6 +54,7 @@
#include "cairoint.h"
#include "test-fallback-surface.h"
+#include "cairo-error-private.h"
typedef struct _test_fallback_surface {
cairo_surface_t base;
diff --git a/src/test-fallback16-surface.c b/src/test-fallback16-surface.c
index 91699ef..45a7b46 100644
--- a/src/test-fallback16-surface.c
+++ b/src/test-fallback16-surface.c
@@ -43,6 +43,7 @@
#include "cairoint.h"
#include "test-fallback16-surface.h"
+#include "cairo-error-private.h"
typedef struct _test_fallback16_surface {
cairo_surface_t base;
diff --git a/src/test-null-surface.c b/src/test-null-surface.c
index 59761a3..5a260bb 100644
--- a/src/test-null-surface.c
+++ b/src/test-null-surface.c
@@ -40,6 +40,8 @@
#include "test-null-surface.h"
+#include "cairo-error-private.h"
+
slim_hidden_proto (_cairo_test_null_surface_create);
static cairo_int_status_t
diff --git a/src/test-paginated-surface.c b/src/test-paginated-surface.c
index 164d4a7..62e5cb6 100644
--- a/src/test-paginated-surface.c
+++ b/src/test-paginated-surface.c
@@ -49,6 +49,7 @@
#include "test-paginated-surface.h"
+#include "cairo-error-private.h"
#include "cairo-paginated-private.h"
typedef struct _test_paginated_surface {
diff --git a/src/test-wrapping-surface.c b/src/test-wrapping-surface.c
index a634b48..d76218f 100644
--- a/src/test-wrapping-surface.c
+++ b/src/test-wrapping-surface.c
@@ -43,6 +43,7 @@
#include "test-wrapping-surface.h"
+#include "cairo-error-private.h"
#include "cairo-surface-wrapper-private.h"
typedef struct _test_wrapping_surface {
commit 558f9501700ba569f04f345f7c64d16b1870e37c
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Mon Jan 18 22:47:34 2010 +0000
surface-wrapper: Avoid copying patterns and clips unless transformed.
An older variant of the fixes for moving the device transformation out
of the surface layer, but languished in a side branch. The only benefit
of this patch is that it avoids the copy where possible.
diff --git a/src/cairo-surface-wrapper.c b/src/cairo-surface-wrapper.c
index af1ef9c..c5fe44d 100644
--- a/src/cairo-surface-wrapper.c
+++ b/src/cairo-surface-wrapper.c
@@ -41,6 +41,29 @@
/* A collection of routines to facilitate surface wrapping */
+static void
+_copy_transformed_pattern (cairo_pattern_t *pattern,
+ const cairo_pattern_t *original,
+ const cairo_matrix_t *ctm_inverse)
+{
+ _cairo_pattern_init_static_copy (pattern, original);
+
+ /* apply device_transform first so that it is transformed by ctm_inverse */
+ if (original->type == CAIRO_PATTERN_TYPE_SURFACE) {
+ cairo_surface_pattern_t *surface_pattern;
+ cairo_surface_t *surface;
+
+ surface_pattern = (cairo_surface_pattern_t *) original;
+ surface = surface_pattern->surface;
+
+ if (_cairo_surface_has_device_transform (surface))
+ _cairo_pattern_transform (pattern, &surface->device_transform);
+ }
+
+ if (! _cairo_matrix_is_identity (ctm_inverse))
+ _cairo_pattern_transform (pattern, ctm_inverse);
+}
+
static cairo_bool_t
_cairo_surface_wrapper_needs_device_transform (cairo_surface_wrapper_t *wrapper,
cairo_matrix_t *matrix)
@@ -72,28 +95,16 @@ _cairo_surface_wrapper_release_source_image (cairo_surface_wrapper_t *wrapper,
_cairo_surface_release_source_image (wrapper->target, image, image_extra);
}
-static void
-_cairo_surface_wrapper_transform_pattern (cairo_surface_wrapper_t *wrapper,
- cairo_pattern_t *pattern,
- const cairo_pattern_t *original)
-{
- _cairo_pattern_init_static_copy (pattern, original);
-
- if (_cairo_surface_has_device_transform (wrapper->target))
- _cairo_pattern_transform (pattern,
- &wrapper->target->device_transform_inverse);
-}
-
cairo_status_t
_cairo_surface_wrapper_paint (cairo_surface_wrapper_t *wrapper,
- cairo_operator_t op,
- const cairo_pattern_t *source,
- cairo_clip_t *clip)
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_clip_t *clip)
{
cairo_status_t status;
cairo_matrix_t device_transform;
cairo_clip_t clip_copy, *dev_clip = clip;
- cairo_pattern_union_t source_pattern;
+ cairo_pattern_union_t source_copy;
if (unlikely (wrapper->target->status))
return wrapper->target->status;
@@ -101,25 +112,25 @@ _cairo_surface_wrapper_paint (cairo_surface_wrapper_t *wrapper,
if (clip && clip->all_clipped)
return CAIRO_STATUS_SUCCESS;
- if (clip != NULL) {
- if (_cairo_surface_wrapper_needs_device_transform (wrapper,
- &device_transform))
- {
+ if (_cairo_surface_wrapper_needs_device_transform (wrapper,
+ &device_transform))
+ {
+ if (clip != NULL) {
status = _cairo_clip_init_copy_transformed (&clip_copy, clip,
&device_transform);
if (unlikely (status))
goto FINISH;
-
} else {
_cairo_clip_init_copy (&clip_copy, clip);
}
dev_clip = &clip_copy;
- }
- _cairo_surface_wrapper_transform_pattern (wrapper, &source_pattern.base, source);
+ _copy_transformed_pattern (&source_copy.base, source, &device_transform);
+ source = &source_copy.base;
+ }
- status = _cairo_surface_paint (wrapper->target, op, &source_pattern.base, dev_clip);
+ status = _cairo_surface_paint (wrapper->target, op, source, dev_clip);
FINISH:
if (dev_clip != clip)
@@ -137,7 +148,8 @@ _cairo_surface_wrapper_mask (cairo_surface_wrapper_t *wrapper,
cairo_status_t status;
cairo_matrix_t device_transform;
cairo_clip_t clip_copy, *dev_clip = clip;
- cairo_pattern_union_t source_pattern, mask_pattern;
+ cairo_pattern_union_t source_copy;
+ cairo_pattern_union_t mask_copy;
if (unlikely (wrapper->target->status))
return wrapper->target->status;
@@ -145,10 +157,10 @@ _cairo_surface_wrapper_mask (cairo_surface_wrapper_t *wrapper,
if (clip && clip->all_clipped)
return CAIRO_STATUS_SUCCESS;
- if (clip != NULL) {
- if (_cairo_surface_wrapper_needs_device_transform (wrapper,
- &device_transform))
- {
+ if (_cairo_surface_wrapper_needs_device_transform (wrapper,
+ &device_transform))
+ {
+ if (clip != NULL) {
status = _cairo_clip_init_copy_transformed (&clip_copy, clip,
&device_transform);
if (unlikely (status))
@@ -159,14 +171,15 @@ _cairo_surface_wrapper_mask (cairo_surface_wrapper_t *wrapper,
}
dev_clip = &clip_copy;
- }
- _cairo_surface_wrapper_transform_pattern (wrapper, &source_pattern.base, source);
- _cairo_surface_wrapper_transform_pattern (wrapper, &mask_pattern.base, mask);
+ _copy_transformed_pattern (&source_copy.base, source, &device_transform);
+ source = &source_copy.base;
+
+ _copy_transformed_pattern (&mask_copy.base, mask, &device_transform);
+ mask = &mask_copy.base;
+ }
- status = _cairo_surface_mask (wrapper->target, op,
- &source_pattern.base, &mask_pattern.base,
- dev_clip);
+ status = _cairo_surface_mask (wrapper->target, op, source, mask, dev_clip);
FINISH:
if (dev_clip != clip)
@@ -192,7 +205,7 @@ _cairo_surface_wrapper_stroke (cairo_surface_wrapper_t *wrapper,
cairo_clip_t clip_copy, *dev_clip = clip;
cairo_matrix_t dev_ctm = *ctm;
cairo_matrix_t dev_ctm_inverse = *ctm_inverse;
- cairo_pattern_union_t source_pattern;
+ cairo_pattern_union_t source_copy;
if (unlikely (wrapper->target->status))
return wrapper->target->status;
@@ -225,6 +238,9 @@ _cairo_surface_wrapper_stroke (cairo_surface_wrapper_t *wrapper,
cairo_matrix_multiply (&dev_ctm_inverse,
&device_transform,
&dev_ctm_inverse);
+
+ _copy_transformed_pattern (&source_copy.base, source, &device_transform);
+ source = &source_copy.base;
} else {
if (clip != NULL) {
dev_clip = &clip_copy;
@@ -232,9 +248,7 @@ _cairo_surface_wrapper_stroke (cairo_surface_wrapper_t *wrapper,
}
}
- _cairo_surface_wrapper_transform_pattern (wrapper, &source_pattern.base, source);
-
- status = _cairo_surface_stroke (wrapper->target, op, &source_pattern.base,
+ status = _cairo_surface_stroke (wrapper->target, op, source,
dev_path, stroke_style,
&dev_ctm, &dev_ctm_inverse,
tolerance, antialias,
@@ -271,7 +285,8 @@ _cairo_surface_wrapper_fill_stroke (cairo_surface_wrapper_t *wrapper,
cairo_clip_t clip_copy, *dev_clip = clip;
cairo_matrix_t dev_ctm = *stroke_ctm;
cairo_matrix_t dev_ctm_inverse = *stroke_ctm_inverse;
- cairo_pattern_union_t fill_pattern, stroke_pattern;
+ cairo_pattern_union_t stroke_source_copy;
+ cairo_pattern_union_t fill_source_copy;
if (unlikely (wrapper->target->status))
return wrapper->target->status;
@@ -304,6 +319,12 @@ _cairo_surface_wrapper_fill_stroke (cairo_surface_wrapper_t *wrapper,
cairo_matrix_multiply (&dev_ctm_inverse,
&device_transform,
&dev_ctm_inverse);
+
+ _copy_transformed_pattern (&stroke_source_copy.base, stroke_source, &device_transform);
+ stroke_source = &stroke_source_copy.base;
+
+ _copy_transformed_pattern (&fill_source_copy.base, fill_source, &device_transform);
+ fill_source = &fill_source_copy.base;
} else {
if (clip != NULL) {
dev_clip = &clip_copy;
@@ -311,14 +332,11 @@ _cairo_surface_wrapper_fill_stroke (cairo_surface_wrapper_t *wrapper,
}
}
- _cairo_surface_wrapper_transform_pattern (wrapper, &fill_pattern.base, fill_source);
- _cairo_surface_wrapper_transform_pattern (wrapper, &stroke_pattern.base, stroke_source);
-
status = _cairo_surface_fill_stroke (wrapper->target,
- fill_op, &fill_pattern.base, fill_rule,
+ fill_op, fill_source, fill_rule,
fill_tolerance, fill_antialias,
dev_path,
- stroke_op, &stroke_pattern.base,
+ stroke_op, stroke_source,
stroke_style,
&dev_ctm, &dev_ctm_inverse,
stroke_tolerance, stroke_antialias,
@@ -346,7 +364,7 @@ _cairo_surface_wrapper_fill (cairo_surface_wrapper_t *wrapper,
cairo_matrix_t device_transform;
cairo_path_fixed_t path_copy, *dev_path = path;
cairo_clip_t clip_copy, *dev_clip = clip;
- cairo_pattern_union_t source_pattern;
+ cairo_pattern_union_t source_copy;
if (unlikely (wrapper->target->status))
return wrapper->target->status;
@@ -372,6 +390,9 @@ _cairo_surface_wrapper_fill (cairo_surface_wrapper_t *wrapper,
dev_clip = &clip_copy;
}
+
+ _copy_transformed_pattern (&source_copy.base, source, &device_transform);
+ source = &source_copy.base;
} else {
if (clip != NULL) {
dev_clip = &clip_copy;
@@ -379,10 +400,7 @@ _cairo_surface_wrapper_fill (cairo_surface_wrapper_t *wrapper,
}
}
- _cairo_surface_wrapper_transform_pattern (wrapper, &source_pattern.base, source);
-
- status = _cairo_surface_fill (wrapper->target, op,
- &source_pattern.base,
+ status = _cairo_surface_fill (wrapper->target, op, source,
dev_path, fill_rule,
tolerance, antialias,
dev_clip);
@@ -411,9 +429,9 @@ _cairo_surface_wrapper_show_text_glyphs (cairo_surface_wrapper_t *wrapper,
{
cairo_status_t status;
cairo_matrix_t device_transform;
- cairo_pattern_union_t source_pattern;
cairo_clip_t clip_copy, *dev_clip = clip;
cairo_glyph_t *dev_glyphs = glyphs;
+ cairo_pattern_union_t source_copy;
if (unlikely (wrapper->target->status))
return wrapper->target->status;
@@ -449,6 +467,9 @@ _cairo_surface_wrapper_show_text_glyphs (cairo_surface_wrapper_t *wrapper,
&dev_glyphs[i].x,
&dev_glyphs[i].y);
}
+
+ _copy_transformed_pattern (&source_copy.base, source, &device_transform);
+ source = &source_copy.base;
} else {
if (clip != NULL) {
dev_clip = &clip_copy;
@@ -456,10 +477,7 @@ _cairo_surface_wrapper_show_text_glyphs (cairo_surface_wrapper_t *wrapper,
}
}
- _cairo_surface_wrapper_transform_pattern (wrapper, &source_pattern.base, source);
-
- status = _cairo_surface_show_text_glyphs (wrapper->target, op,
- &source_pattern.base,
+ status = _cairo_surface_show_text_glyphs (wrapper->target, op, source,
utf8, utf8_len,
dev_glyphs, num_glyphs,
clusters, num_clusters,
@@ -480,10 +498,8 @@ _cairo_surface_wrapper_create_similar (cairo_surface_wrapper_t *wrapper,
int width,
int height)
{
- return _cairo_surface_create_similar_solid (wrapper->target,
- content, width, height,
- CAIRO_COLOR_TRANSPARENT,
- TRUE);
+ return _cairo_surface_create_similar_scratch (wrapper->target,
+ content, width, height);
}
cairo_bool_t
commit 8f694817227366f4a4c6bbbf46e6cdddb4a065df
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Tue Jan 19 17:12:47 2010 +0000
gitignore: refresh
Add forgotten local targets to .gitignore
diff --git a/.gitignore b/.gitignore
index 6719acc..cef6930 100644
--- a/.gitignore
+++ b/.gitignore
@@ -29,3 +29,4 @@ stamp-h.in
*.orig
*.rej
*-uninstalled.pc
+.vimrc
diff --git a/perf/.gitignore b/perf/.gitignore
index 3764715..bc8b9bf 100644
--- a/perf/.gitignore
+++ b/perf/.gitignore
@@ -25,3 +25,4 @@ index.html
*.pdb
*~
.*.sw?
+*.data
diff --git a/util/.gitignore b/util/.gitignore
index 01eb637..ff7ffbd 100644
--- a/util/.gitignore
+++ b/util/.gitignore
@@ -5,6 +5,8 @@ Makefile.in
show-edges
show-events
show-traps
+xml-to-trace
+trace-to-xml
*.so
*.la
*.lo
diff --git a/util/cairo-script/.gitignore b/util/cairo-script/.gitignore
index 855d640..8ecaee3 100644
--- a/util/cairo-script/.gitignore
+++ b/util/cairo-script/.gitignore
@@ -1,2 +1,3 @@
csi-replay
csi-exec
+csi-trace
More information about the cairo-commit
mailing list