diff options
38 files changed, 5323 insertions, 1311 deletions
diff --git a/boilerplate/Makefile.win32.features b/boilerplate/Makefile.win32.features index 31bd4e06..50ee95cb 100644 --- a/boilerplate/Makefile.win32.features +++ b/boilerplate/Makefile.win32.features @@ -169,6 +169,16 @@ enabled_cairo_boilerplate_private += $(cairo_boilerplate_drm_private) enabled_cairo_boilerplate_sources += $(cairo_boilerplate_drm_sources) endif +unsupported_cairo_boilerplate_headers += $(cairo_boilerplate_drm_xr_headers) +all_cairo_boilerplate_headers += $(cairo_boilerplate_drm_xr_headers) +all_cairo_boilerplate_private += $(cairo_boilerplate_drm_xr_private) +all_cairo_boilerplate_sources += $(cairo_boilerplate_drm_xr_sources) +ifeq ($(CAIRO_HAS_DRM_XR_FUNCTIONS),1) +enabled_cairo_boilerplate_headers += $(cairo_boilerplate_drm_xr_headers) +enabled_cairo_boilerplate_private += $(cairo_boilerplate_drm_xr_private) +enabled_cairo_boilerplate_sources += $(cairo_boilerplate_drm_xr_sources) +endif + unsupported_cairo_boilerplate_headers += $(cairo_boilerplate_gallium_headers) all_cairo_boilerplate_headers += $(cairo_boilerplate_gallium_headers) all_cairo_boilerplate_private += $(cairo_boilerplate_gallium_private) @@ -199,6 +209,14 @@ enabled_cairo_boilerplate_private += $(cairo_boilerplate_png_private) enabled_cairo_boilerplate_sources += $(cairo_boilerplate_png_sources) endif +supported_cairo_boilerplate_headers += $(cairo_boilerplate_glew_headers) +all_cairo_boilerplate_headers += $(cairo_boilerplate_glew_headers) +all_cairo_boilerplate_private += $(cairo_boilerplate_glew_private) +all_cairo_boilerplate_sources += $(cairo_boilerplate_glew_sources) +enabled_cairo_boilerplate_headers += $(cairo_boilerplate_glew_headers) +enabled_cairo_boilerplate_private += $(cairo_boilerplate_glew_private) +enabled_cairo_boilerplate_sources += $(cairo_boilerplate_glew_sources) + unsupported_cairo_boilerplate_headers += $(cairo_boilerplate_gl_headers) all_cairo_boilerplate_headers += $(cairo_boilerplate_gl_headers) all_cairo_boilerplate_private += $(cairo_boilerplate_gl_private) diff --git a/boilerplate/cairo-boilerplate-drm.c b/boilerplate/cairo-boilerplate-drm.c index f79bcca7..93709afe 100644 --- a/boilerplate/cairo-boilerplate-drm.c +++ b/boilerplate/cairo-boilerplate-drm.c @@ -46,12 +46,20 @@ _cairo_boilerplate_drm_create_surface (const char *name, void **closure) { cairo_device_t *device; + cairo_format_t format; device = cairo_drm_device_default (); if (device == NULL) return NULL; /* skip tests if no supported h/w found */ - return *closure = cairo_drm_surface_create (device, content, width, height); + switch (content) { + case CAIRO_CONTENT_ALPHA: format = CAIRO_FORMAT_A8; break; + case CAIRO_CONTENT_COLOR: format = CAIRO_FORMAT_RGB24; break; + default: + case CAIRO_CONTENT_COLOR_ALPHA: format = CAIRO_FORMAT_ARGB32; break; + } + + return *closure = cairo_drm_surface_create (device, format, width, height); } static void @@ -59,7 +67,7 @@ _cairo_boilerplate_drm_synchronize (void *closure) { cairo_surface_t *image; - image = cairo_drm_surface_map (closure); + image = cairo_drm_surface_map_to_image (closure); if (cairo_surface_status (image) == CAIRO_STATUS_SUCCESS) cairo_drm_surface_unmap (closure, image); } diff --git a/build/Makefile.win32.features b/build/Makefile.win32.features index 2f40eb2f..5c283ac4 100644 --- a/build/Makefile.win32.features +++ b/build/Makefile.win32.features @@ -15,6 +15,7 @@ CAIRO_HAS_SKIA_SURFACE=0 CAIRO_HAS_OS2_SURFACE=0 CAIRO_HAS_BEOS_SURFACE=0 CAIRO_HAS_DRM_SURFACE=0 +CAIRO_HAS_DRM_XR_FUNCTIONS=0 CAIRO_HAS_GALLIUM_SURFACE=0 CAIRO_HAS_XCB_DRM_FUNCTIONS=0 CAIRO_HAS_PNG_FUNCTIONS=1 diff --git a/build/Makefile.win32.features-h b/build/Makefile.win32.features-h index f7c07acc..f5eae809 100644 --- a/build/Makefile.win32.features-h +++ b/build/Makefile.win32.features-h @@ -50,6 +50,9 @@ endif ifeq ($(CAIRO_HAS_DRM_SURFACE),1) @echo "#define CAIRO_HAS_DRM_SURFACE 1" >> src/cairo-features.h endif +ifeq ($(CAIRO_HAS_DRM_XR_FUNCTIONS),1) + @echo "#define CAIRO_HAS_DRM_XR_FUNCTIONS 1" >> src/cairo-features.h +endif ifeq ($(CAIRO_HAS_GALLIUM_SURFACE),1) @echo "#define CAIRO_HAS_GALLIUM_SURFACE 1" >> src/cairo-features.h endif @@ -59,6 +62,7 @@ endif ifeq ($(CAIRO_HAS_PNG_FUNCTIONS),1) @echo "#define CAIRO_HAS_PNG_FUNCTIONS 1" >> src/cairo-features.h endif + @echo "#define CAIRO_HAS_GLEW_FUNCTIONS 1" >> src/cairo-features.h ifeq ($(CAIRO_HAS_GL_SURFACE),1) @echo "#define CAIRO_HAS_GL_SURFACE 1" >> src/cairo-features.h endif diff --git a/build/configure.ac.features b/build/configure.ac.features index 593f4a6a..1e40de85 100644 --- a/build/configure.ac.features +++ b/build/configure.ac.features @@ -394,6 +394,7 @@ AC_DEFUN([CAIRO_REPORT], echo " X11-xcb functions: $use_xlib_xcb" echo " XCB-drm functions: $use_xcb_drm" echo " XCB-shm functions: $use_xcb_shm" + echo " DRM-Xr functions: $use_drm_xr" echo "" echo "The following features and utilities:" echo " cairo-trace: $use_trace" diff --git a/configure.ac b/configure.ac index 5c3e0bad..493fdc1c 100644 --- a/configure.ac +++ b/configure.ac @@ -258,6 +258,19 @@ CAIRO_ENABLE_SURFACE_BACKEND(drm, DRM, no, [ use_drm="no (requires $drm_REQUIRES, udev is available from git://git.kernel.org/pub/scm/linux/hotplug/udev.git)"]) ]) +CAIRO_ENABLE_FUNCTIONS(drm_xr, DRM Xr (DDX), no, [ + if test "x$use_drm" == "xyes"; then + drm_xr_REQUIRES="xorg-server >= 1.6 xproto xextproto >= 7.0.99.1 renderproto x11" + PKG_CHECK_MODULES(drm_xr, $drm_xr_REQUIRES, , + [AC_MSG_RESULT(no) + use_drm_xr="no (requires $drm_xr)"]) + drm_xr_CFLAGS=`echo "$drm_xr_CFLAGS" | $SED -e 's/-fvisibility=hidden//g'` + else + use_drm_xr="no (requires --enable-drm)" + fi +]) +AM_CONDITIONAL(BUILD_DRM_XR, test "x$use_drm_xr" = "xyes") + CAIRO_ENABLE_SURFACE_BACKEND(gallium, Gallium3D, no, [ if test "x$use_drm" = "xyes"; then AC_ARG_WITH([gallium], diff --git a/src/Makefile.sources b/src/Makefile.sources index a40404bf..c45e339e 100644 --- a/src/Makefile.sources +++ b/src/Makefile.sources @@ -356,6 +356,13 @@ cairo_drm_sources = drm/cairo-drm.c \ drm/cairo-drm-radeon-surface.c cairo_gallium_sources = drm/cairo-drm-gallium-surface.c +if BUILD_DRM_XR +cairo_drm_headers += cairo-drm-xr.h +cairo_drm_sources += \ + drm/cairo-drm-xr.c \ + $(NULL) +endif + cairo_script_headers = cairo-script.h cairo_script_sources = cairo-script-surface.c diff --git a/src/Makefile.win32.features b/src/Makefile.win32.features index 42fb6964..c9223c26 100644 --- a/src/Makefile.win32.features +++ b/src/Makefile.win32.features @@ -231,6 +231,20 @@ ifeq ($(CAIRO_HAS_DRM_SURFACE),1) enabled_cairo_pkgconf += cairo-drm.pc endif +unsupported_cairo_headers += $(cairo_drm_xr_headers) +all_cairo_headers += $(cairo_drm_xr_headers) +all_cairo_private += $(cairo_drm_xr_private) +all_cairo_sources += $(cairo_drm_xr_sources) +ifeq ($(CAIRO_HAS_DRM_XR_FUNCTIONS),1) +enabled_cairo_headers += $(cairo_drm_xr_headers) +enabled_cairo_private += $(cairo_drm_xr_private) +enabled_cairo_sources += $(cairo_drm_xr_sources) +endif +all_cairo_pkgconf += cairo-drm-xr.pc +ifeq ($(CAIRO_HAS_DRM_XR_FUNCTIONS),1) +enabled_cairo_pkgconf += cairo-drm-xr.pc +endif + unsupported_cairo_headers += $(cairo_gallium_headers) all_cairo_headers += $(cairo_gallium_headers) all_cairo_private += $(cairo_gallium_private) @@ -273,6 +287,14 @@ ifeq ($(CAIRO_HAS_PNG_FUNCTIONS),1) enabled_cairo_pkgconf += cairo-png.pc endif +supported_cairo_headers += $(cairo_glew_headers) +all_cairo_headers += $(cairo_glew_headers) +all_cairo_private += $(cairo_glew_private) +all_cairo_sources += $(cairo_glew_sources) +enabled_cairo_headers += $(cairo_glew_headers) +enabled_cairo_private += $(cairo_glew_private) +enabled_cairo_sources += $(cairo_glew_sources) + unsupported_cairo_headers += $(cairo_gl_headers) all_cairo_headers += $(cairo_gl_headers) all_cairo_private += $(cairo_gl_private) diff --git a/src/cairo-boxes-private.h b/src/cairo-boxes-private.h index 783fcc6b..3af0fbde 100644 --- a/src/cairo-boxes-private.h +++ b/src/cairo-boxes-private.h @@ -72,6 +72,10 @@ _cairo_boxes_add (cairo_boxes_t *boxes, const cairo_box_t *box); cairo_private void +_cairo_boxes_extents (const cairo_boxes_t *boxes, + cairo_rectangle_int_t *extents); + +cairo_private void _cairo_boxes_clear (cairo_boxes_t *boxes); cairo_private void diff --git a/src/cairo-boxes.c b/src/cairo-boxes.c index ca265365..31bfc0e4 100644 --- a/src/cairo-boxes.c +++ b/src/cairo-boxes.c @@ -240,6 +240,37 @@ _cairo_boxes_add (cairo_boxes_t *boxes, } void +_cairo_boxes_extents (const cairo_boxes_t *boxes, + cairo_rectangle_int_t *extents) +{ + const struct _cairo_boxes_chunk *chunk; + cairo_box_t box; + int i; + + box.p1.y = box.p1.x = INT_MAX; + box.p2.y = box.p2.x = INT_MIN; + + for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) { + const cairo_box_t *b = chunk->base; + for (i = 0; i < chunk->count; i++) { + if (b[i].p1.x < box.p1.x) + box.p1.x = b[i].p1.x; + + if (b[i].p1.y < box.p1.y) + box.p1.y = b[i].p1.y; + + if (b[i].p2.x > box.p2.x) + box.p2.x = b[i].p2.x; + + if (b[i].p2.y > box.p2.y) + box.p2.y = b[i].p2.y; + } + } + + _cairo_box_round_to_rectangle (&box, extents); +} + +void _cairo_boxes_clear (cairo_boxes_t *boxes) { struct _cairo_boxes_chunk *chunk, *next; diff --git a/src/cairo-composite-rectangles.c b/src/cairo-composite-rectangles.c index 0aebee36..ccd8884e 100644 --- a/src/cairo-composite-rectangles.c +++ b/src/cairo-composite-rectangles.c @@ -66,9 +66,10 @@ _cairo_composite_rectangles_init (cairo_composite_rectangles_t *extents, 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; + if (! _cairo_rectangle_intersect (&extents->bounded, &extents->source) && + extents->is_bounded & CAIRO_OPERATOR_BOUND_BY_SOURCE) + { + return FALSE; } return TRUE; diff --git a/src/cairo-drm-xr.h b/src/cairo-drm-xr.h new file mode 100644 index 00000000..d135924d --- /dev/null +++ b/src/cairo-drm-xr.h @@ -0,0 +1,66 @@ +/* Cairo - a vector graphics library with display and print output + * + * Copyright © 2010 Intel Coropration + * + * 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 Chris Wilson. + */ + +#ifndef CAIRO_DRM_XR_H +#define CAIRO_DRM_XR_H + +#include "cairo.h" + +#if CAIRO_HAS_DRM_XR_FUNCTIONS + +CAIRO_BEGIN_DECLS + +typedef struct _xr_screen xr_screen_t; + +cairo_public xr_screen_t * +cairo_drm_xr_enable (ScreenPtr screen, int fd); + +cairo_public void +cairo_drm_xr_pixmap_link_bo (xr_screen_t *xr, + PixmapPtr pixmap, + uint32_t name, + cairo_format_t format, + int width, + int height, + int stride); + +cairo_public void +cairo_drm_xr_pixmap_unlink_bo (xr_screen_t *xr, + PixmapPtr pixmap); + +CAIRO_END_DECLS + +#else /* CAIRO_HAS_DRM_XR_FUNCTIOSN */ +# error Cairo was not compiled with support for the DRM Xr DDX functions +#endif /* CAIRO_HAS_DRM_XR_FUNCTIOSN */ + +#endif /* CAIRO_DRM_XR_H */ diff --git a/src/cairo-drm.h b/src/cairo-drm.h index 80068e78..907610dc 100644 --- a/src/cairo-drm.h +++ b/src/cairo-drm.h @@ -58,7 +58,7 @@ cairo_drm_device_throttle (cairo_device_t *device); cairo_public cairo_surface_t * cairo_drm_surface_create (cairo_device_t *device, - cairo_content_t content, + cairo_format_t format, int width, int height); cairo_public cairo_surface_t * @@ -105,7 +105,7 @@ cairo_drm_surface_get_stride (cairo_surface_t *surface); * will also disassociate the mapping.) */ cairo_public cairo_surface_t * -cairo_drm_surface_map (cairo_surface_t *surface); +cairo_drm_surface_map_to_image (cairo_surface_t *surface); cairo_public void cairo_drm_surface_unmap (cairo_surface_t *drm_surface, diff --git a/src/cairo-fixed-private.h b/src/cairo-fixed-private.h index 9deec800..66898a20 100644 --- a/src/cairo-fixed-private.h +++ b/src/cairo-fixed-private.h @@ -135,6 +135,16 @@ _cairo_fixed_from_26_6 (uint32_t i) #endif } +static inline cairo_fixed_t +_cairo_fixed_from_16_16 (uint32_t i) +{ +#if CAIRO_FIXED_FRAC_BITS > 16 + return i << (CAIRO_FIXED_FRAC_BITS - 16); +#else + return i >> (16 - CAIRO_FIXED_FRAC_BITS); +#endif +} + static inline double _cairo_fixed_to_double (cairo_fixed_t f) { @@ -242,7 +252,7 @@ _cairo_fixed_16_16_from_double (double d) } static inline int -_cairo_fixed_16_16_floor (cairo_fixed_t f) +_cairo_fixed_16_16_floor (cairo_fixed_16_16_t f) { if (f >= 0) return f >> 16; @@ -250,6 +260,12 @@ _cairo_fixed_16_16_floor (cairo_fixed_t f) return -((-f - 1) >> 16) - 1; } +static inline double +_cairo_fixed_16_16_to_double (cairo_fixed_16_16_t f) +{ + return ((double) f) / (double) (1 << 16); +} + #if CAIRO_FIXED_BITS == 32 static inline cairo_fixed_t diff --git a/src/cairo-freelist-private.h b/src/cairo-freelist-private.h index 43dde29c..47ed2329 100644 --- a/src/cairo-freelist-private.h +++ b/src/cairo-freelist-private.h @@ -111,7 +111,6 @@ _cairo_freepool_reset (cairo_freepool_t *freepool) 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 eb42043b..d596eab8 100644 --- a/src/cairo-freelist.c +++ b/src/cairo-freelist.c @@ -84,7 +84,6 @@ _cairo_freelist_free (cairo_freelist_t *freelist, void *voidnode) } } - void _cairo_freepool_init (cairo_freepool_t *freepool, unsigned nodesize) { @@ -98,8 +97,7 @@ _cairo_freepool_init (cairo_freepool_t *freepool, unsigned nodesize) freepool->embedded_pool.rem = sizeof (freepool->embedded_data); freepool->embedded_pool.data = freepool->embedded_data; - VG (VALGRIND_MAKE_MEM_NOACCESS (freepool->embedded_data, - sizeof (freepool->embedded_data))); + VG (VALGRIND_MAKE_MEM_NOACCESS (freepool->embedded_data, sizeof (freepool->embedded_data))); } void @@ -154,8 +152,7 @@ _cairo_freepool_alloc_from_new_pool (cairo_freepool_t *freepool) pool->rem = poolsize - freepool->nodesize; pool->data = (uint8_t *) (pool + 1) + freepool->nodesize; - VG (VALGRIND_MAKE_MEM_NOACCESS (pool->data, poolsize)); - VG (VALGRIND_MAKE_MEM_UNDEFINED (pool->data, freepool->nodesize)); + VG (VALGRIND_MAKE_MEM_NOACCESS (pool->data, pool->rem)); return pool + 1; } diff --git a/src/cairo-image-surface.c b/src/cairo-image-surface.c index 92b30eff..b98d1085 100644 --- a/src/cairo-image-surface.c +++ b/src/cairo-image-surface.c @@ -264,7 +264,7 @@ _pixman_format_to_masks (pixman_format_code_t format, } } -static pixman_format_code_t +pixman_format_code_t _cairo_format_to_pixman_format_code (cairo_format_t format) { pixman_format_code_t ret; diff --git a/src/cairo-list-private.h b/src/cairo-list-private.h index 3d4bbed1..ddfd0a4c 100644 --- a/src/cairo-list-private.h +++ b/src/cairo-list-private.h @@ -73,19 +73,38 @@ typedef struct _cairo_list { &pos->member != (head); \ pos = cairo_list_entry(pos->member.prev, type, member)) +#define cairo_list_foreach_entry_reverse_safe(pos, n, type, head, member) \ + for (pos = cairo_list_entry((head)->prev, type, member),\ + n = cairo_list_entry (pos->member.prev, type, member);\ + &pos->member != (head); \ + pos = n, n = cairo_list_entry (n->member.prev, type, member)) + #ifdef CAIRO_LIST_DEBUG static inline void +_cairo_list_validate (const cairo_list_t *link) +{ + assert (link->next->prev == link); + assert (link->prev->next == link); +} +static inline void cairo_list_validate (const cairo_list_t *head) { cairo_list_t *link; - cairo_list_foreach (link, head) { - assert (link->next->prev == link); - assert (link->prev->next == link); - } + cairo_list_foreach (link, head) + _cairo_list_validate (link); +} +static inline cairo_bool_t +cairo_list_is_empty (const cairo_list_t *head); +static inline void +cairo_list_validate_is_empty (const cairo_list_t *head) +{ + assert (head->next == NULL || (cairo_list_is_empty (head) && head->next == head->prev)); } #else +#define _cairo_list_validate(link) #define cairo_list_validate(head) +#define cairo_list_validate_is_empty(head) #endif static inline void @@ -110,6 +129,7 @@ static inline void cairo_list_add (cairo_list_t *entry, cairo_list_t *head) { cairo_list_validate (head); + cairo_list_validate_is_empty (entry); __cairo_list_add (entry, head, head->next); cairo_list_validate (head); } @@ -118,6 +138,7 @@ static inline void cairo_list_add_tail (cairo_list_t *entry, cairo_list_t *head) { cairo_list_validate (head); + cairo_list_validate_is_empty (entry); __cairo_list_add (entry, head->prev, head); cairo_list_validate (head); } @@ -157,10 +178,8 @@ cairo_list_move_tail (cairo_list_t *entry, cairo_list_t *head) static inline void cairo_list_swap (cairo_list_t *entry, cairo_list_t *other) { - cairo_list_validate (head); __cairo_list_add (entry, other->prev, other->next); cairo_list_init (other); - cairo_list_validate (head); } static inline cairo_bool_t diff --git a/src/cairoint.h b/src/cairoint.h index 805c5744..5cf0bcf7 100644 --- a/src/cairoint.h +++ b/src/cairoint.h @@ -2180,6 +2180,9 @@ cairo_private cairo_surface_t * _cairo_image_surface_create_for_pixman_image (pixman_image_t *pixman_image, pixman_format_code_t pixman_format); +pixman_format_code_t +_cairo_format_to_pixman_format_code (cairo_format_t format); + cairo_private cairo_bool_t _pixman_format_from_masks (cairo_format_masks_t *masks, pixman_format_code_t *format_ret); @@ -2519,6 +2522,10 @@ _cairo_pattern_is_opaque (const cairo_pattern_t *pattern, cairo_private cairo_bool_t _cairo_pattern_is_clear (const cairo_pattern_t *pattern); +cairo_private_no_warn cairo_filter_t +_cairo_pattern_analyze_filter (const cairo_pattern_t *pattern, + double *pad_out); + enum { CAIRO_PATTERN_ACQUIRE_NONE = 0x0, CAIRO_PATTERN_ACQUIRE_NO_REFLECT = 0x1 diff --git a/src/drm/cairo-drm-i915-glyphs.c b/src/drm/cairo-drm-i915-glyphs.c index d2025003..40c8106c 100644 --- a/src/drm/cairo-drm-i915-glyphs.c +++ b/src/drm/cairo-drm-i915-glyphs.c @@ -41,6 +41,25 @@ #include "cairo-rtree-private.h" static void +i915_emit_glyph_rectangle_zero (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 + */ + + v = i915_add_rectangle (device); + *v++ = x2; *v++ = y2; + *v++ = x1; *v++ = y2; + *v++ = x1; *v++ = y1; +} + +static void i915_emit_glyph_rectangle_constant (i915_device_t *device, i915_shader_t *shader, int x1, int y1, @@ -91,6 +110,7 @@ i915_emit_glyph_rectangle_general (i915_device_t *device, *v++ = x2; *v++ = y2; s = x2, t = y2; switch (shader->source.type.vertex) { + case VS_ZERO: case VS_CONSTANT: break; case VS_LINEAR: @@ -111,6 +131,7 @@ i915_emit_glyph_rectangle_general (i915_device_t *device, *v++ = x1; *v++ = y2; s = x1, t = y2; switch (shader->source.type.vertex) { + case VS_ZERO: case VS_CONSTANT: break; case VS_LINEAR: @@ -131,6 +152,7 @@ i915_emit_glyph_rectangle_general (i915_device_t *device, *v++ = x1; *v++ = y1; s = x1, t = y2; switch (shader->source.type.vertex) { + case VS_ZERO: case VS_CONSTANT: break; case VS_LINEAR: @@ -168,7 +190,7 @@ i915_surface_mask_internal (i915_surface_t *dst, cairo_region_t *clip_region = NULL; cairo_status_t status; - i915_shader_init (&shader, dst, op); + i915_shader_init (&shader, dst, op, 1.); status = i915_shader_acquire_pattern (&shader, &shader.source, source, &extents->bounded); @@ -176,6 +198,7 @@ i915_surface_mask_internal (i915_surface_t *dst, return status; shader.mask.type.vertex = VS_TEXTURE_16; + shader.mask.type.pattern = PATTERN_TEXTURE; shader.mask.type.fragment = FS_TEXTURE; shader.mask.base.content = mask->intel.drm.base.content; shader.mask.base.texfmt = TEXCOORDFMT_2D_16; @@ -188,20 +211,19 @@ i915_surface_mask_internal (i915_surface_t *dst, i915_texture_extend (CAIRO_EXTEND_NONE); cairo_matrix_init_translate (&shader.mask.base.matrix, - -extents->bounded.x + NEAREST_BIAS, - -extents->bounded.y + NEAREST_BIAS); + -extents->bounded.x, + -extents->bounded.y); 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.bo = intel_bo_reference (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; @@ -240,7 +262,7 @@ i915_surface_mask_internal (i915_surface_t *dst, extents->bounded.y + extents->bounded.height); } - if ((extents->is_bounded & CAIRO_OPERATOR_BOUND_BY_MASK) == 0) + if (! extents->is_bounded) status = i915_fixup_unbounded (dst, extents, clip); CLEANUP_DEVICE: @@ -300,16 +322,32 @@ i915_surface_glyphs (void *abstract_surface, have_clip = TRUE; } - if (overlap || (extents.is_bounded & CAIRO_OPERATOR_BOUND_BY_MASK) == 0) { - cairo_content_t content; + if (clip != NULL) { + status = _cairo_clip_get_region (clip, &clip_region); + if (unlikely (_cairo_status_is_error (status) || + status == CAIRO_INT_STATUS_NOTHING_TO_DO)) + { + if (have_clip) + _cairo_clip_fini (&local_clip); + return status; + } + } + + if (i915_surface_needs_tiling (surface)) { + ASSERT_NOT_REACHED; + return CAIRO_INT_STATUS_UNSUPPORTED; + } + + if (overlap || ! extents.is_bounded) { + cairo_format_t format; - content = CAIRO_CONTENT_ALPHA; + format = CAIRO_FORMAT_A8; if (scaled_font->options.antialias == CAIRO_ANTIALIAS_SUBPIXEL) - content |= CAIRO_CONTENT_COLOR; + format = CAIRO_FORMAT_ARGB32; mask = (i915_surface_t *) i915_surface_create_internal (&i915_device (surface)->intel.base, - CAIRO_CONTENT_ALPHA, + format, extents.bounded.width, extents.bounded.height, I915_TILING_DEFAULT, @@ -317,16 +355,13 @@ i915_surface_glyphs (void *abstract_surface, 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); + status = i915_surface_clear (mask); if (unlikely (status)) { cairo_surface_destroy (&mask->intel.drm.base); return status; } - i915_shader_init (&shader, mask, CAIRO_OPERATOR_ADD); + i915_shader_init (&shader, mask, CAIRO_OPERATOR_ADD, 1.); status = i915_shader_acquire_pattern (&shader, &shader.source, &_cairo_pattern_white.base, @@ -339,7 +374,7 @@ i915_surface_glyphs (void *abstract_surface, mask_x = -extents.bounded.x; mask_y = -extents.bounded.y; } else { - i915_shader_init (&shader, surface, op); + i915_shader_init (&shader, surface, op, 1.); status = i915_shader_acquire_pattern (&shader, &shader.source, source, &extents.bounded); @@ -348,7 +383,6 @@ i915_surface_glyphs (void *abstract_surface, 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; @@ -370,6 +404,9 @@ i915_surface_glyphs (void *abstract_surface, i915_texture_extend (CAIRO_EXTEND_NONE); switch (shader.source.type.vertex) { + case VS_ZERO: + emit_func = i915_emit_glyph_rectangle_zero; + break; case VS_CONSTANT: emit_func = i915_emit_glyph_rectangle_constant; break; @@ -466,8 +503,13 @@ i915_surface_glyphs (void *abstract_surface, last_bo = cache->buffer.bo; } - x1 += mask_x; x2 += mask_x; - y1 += mask_y; y2 += mask_y; + x2 = x1 + glyph->width; + y2 = y1 + glyph->height; + + if (mask_x) + x1 += mask_x, x2 += mask_x; + if (mask_y) + y1 += mask_y, y2 += mask_y; /* XXX clip glyph */ emit_func (device, &shader, x1, y1, x2, y2, glyph); diff --git a/src/drm/cairo-drm-i915-private.h b/src/drm/cairo-drm-i915-private.h index e95375ff..f03d5d76 100644 --- a/src/drm/cairo-drm-i915-private.h +++ b/src/drm/cairo-drm-i915-private.h @@ -36,6 +36,8 @@ #include "cairo-drm-intel-ioctl-private.h" #include "cairo-freelist-private.h" +#include <setjmp.h> + #define I915_VERBOSE 1 #define I915_MAX_TEX_INDIRECT 4 @@ -652,17 +654,22 @@ struct i915_device { cairo_bool_t debug; + i915_shader_t *shader; /* note: only valid during geometry emission */ + 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; + size_t gtt_avail_size; + size_t est_gtt_size; + size_t total_gtt_size; - struct drm_i915_gem_relocation_entry reloc[I915_MAX_RELOCS]; + uint16_t fences; + uint16_t fences_avail; uint16_t reloc_count; - + uint16_t exec_count; uint16_t used; + + struct drm_i915_gem_exec_object2 exec[I915_MAX_RELOCS]; + struct drm_i915_gem_relocation_entry reloc[I915_MAX_RELOCS]; } batch; uint32_t vbo; @@ -677,8 +684,6 @@ struct i915_device { 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; @@ -691,9 +696,12 @@ struct i915_device { 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_samplers[2*4]; + uint32_t current_maps[4*4]; uint32_t current_n_samplers; + uint32_t current_n_maps; uint32_t last_source_fragment; + uint32_t clear_alpha; cairo_list_t image_caches[2]; @@ -709,6 +717,7 @@ enum { }; typedef enum { + VS_ZERO, VS_CONSTANT, VS_LINEAR, VS_TEXTURE, @@ -744,6 +753,7 @@ struct i915_surface { uint32_t map0, map1; uint32_t colorbuf; + cairo_bool_t deferred_clear; uint32_t offset; uint32_t is_current_texture; @@ -787,8 +797,10 @@ struct i915_shader { cairo_operator_t op; uint32_t blend; + float opacity; cairo_content_t content; + cairo_bool_t committed; cairo_bool_t need_combine; i915_add_rectangle_func_t add_rectangle; @@ -834,6 +846,8 @@ struct i915_shader { i915_packed_pixel_t pixel; } surface; } source, mask, clip, dst; + + jmp_buf unwind; }; enum i915_shader_linear_mode { @@ -862,11 +876,12 @@ i915_clip_and_composite_spans (i915_surface_t *dst, i915_spans_func_t draw_func, void *draw_closure, const cairo_composite_rectangles_t*extents, - cairo_clip_t *clip); + cairo_clip_t *clip, + double opacity); cairo_private cairo_surface_t * i915_surface_create_internal (cairo_drm_device_t *base_dev, - cairo_content_t content, + cairo_format_t format, int width, int height, uint32_t tiling, cairo_bool_t gpu_target); @@ -904,8 +919,9 @@ i915_tiling_stride (int format, uint32_t stride) { uint32_t tile_width; + /* use 64B alignment so that the buffer may be used as a scanout */ if (format == I915_TILING_NONE) - return (stride + 31) & -32; + return (stride + 63) & -64; tile_width = 512; /* XXX Currently the kernel enforces a tile_width of 512 for TILING_Y. @@ -943,7 +959,7 @@ i915_tiling_size (uint32_t tiling, uint32_t size) return fence; } -static inline cairo_bool_t cairo_pure +static inline cairo_bool_t cairo_const i915_texture_filter_is_nearest (cairo_filter_t filter) { switch (filter) { @@ -959,7 +975,7 @@ i915_texture_filter_is_nearest (cairo_filter_t filter) } } -static inline uint32_t cairo_pure +static inline uint32_t cairo_const i915_texture_filter (cairo_filter_t filter) { switch (filter) { @@ -979,7 +995,7 @@ i915_texture_filter (cairo_filter_t filter) } } -static inline uint32_t cairo_pure +static inline uint32_t cairo_const i915_texture_extend (cairo_extend_t extend) { switch (extend) { @@ -1003,7 +1019,7 @@ i915_texture_extend (cairo_extend_t extend) } } -static inline uint32_t cairo_pure +static inline uint32_t cairo_const BUF_tiling (uint32_t tiling) { switch (tiling) { @@ -1015,7 +1031,8 @@ BUF_tiling (uint32_t tiling) } #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 OUT_RELOC(surface, read, write) i915_batch_emit_reloc (device, to_intel_bo (surface->intel.drm.bo), surface->offset, read, write, FALSE) +#define OUT_RELOC_FENCED(surface, read, write) i915_batch_emit_reloc (device, to_intel_bo (surface->intel.drm.bo), surface->offset, read, write, TRUE) #define FS_LOCALS \ uint32_t *_shader_start @@ -1039,26 +1056,54 @@ i915_batch_space (i915_device_t *device) } static inline cairo_bool_t -i915_check_aperture_size (const i915_device_t *device, int relocs, size_t size) +i915_check_aperture_size (const i915_device_t *device, int relocs, size_t est_size, size_t size) { - return device->batch.reloc_count + relocs < I915_MAX_RELOCS && - device->batch.gtt_size + size <= device->intel.gtt_avail_size; + return device->batch.reloc_count + relocs < I915_MAX_RELOCS - 2 && + device->batch.est_gtt_size + est_size <= device->batch.gtt_avail_size && + device->batch.total_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; + uint32_t relocs = 0, est_size = 0, size = 0; + + while (count--) { + const intel_bo_t *bo = *bo_array++; + if (bo->exec == NULL) { + relocs++; + size += bo->base.size; + if (!bo->busy) + est_size += bo->base.size; + } + } + + return i915_check_aperture_size (device, relocs, est_size, size); +} + +static inline cairo_bool_t +i915_check_aperture_and_fences (const i915_device_t *device, intel_bo_t **bo_array, int count) +{ + uint32_t relocs = 0, est_size = 0, size = 0; + uint32_t fences = 0; while (count--) { const intel_bo_t *bo = *bo_array++; if (bo->exec == NULL) { relocs++; size += bo->base.size; + if (!bo->busy) + est_size += bo->base.size; + if (bo->tiling != I915_TILING_NONE) + fences++; + } else if (bo->tiling != I915_TILING_NONE) { + if ((bo->exec->flags & EXEC_OBJECT_NEEDS_FENCE) == 0) + fences++; } } - return i915_check_aperture_size (device, relocs, size); + return i915_check_aperture_size (device, relocs, est_size, size) && + device->batch.fences + fences <= device->batch.fences_avail; } #define BATCH_PTR(device) &(device)->batch_base[(device)->batch.used] @@ -1073,7 +1118,8 @@ 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); + uint32_t write_domain, + cairo_bool_t needs_fence); static inline void i915_batch_fill_reloc (i915_device_t *device, uint32_t pos, @@ -1084,7 +1130,8 @@ i915_batch_fill_reloc (i915_device_t *device, uint32_t pos, { i915_batch_add_reloc (device, pos, bo, offset, - read_domains, write_domain); + read_domains, write_domain, + FALSE); device->batch_base[pos] = bo->offset + offset; } @@ -1093,15 +1140,20 @@ i915_batch_emit_reloc (i915_device_t *device, intel_bo_t *bo, uint32_t offset, uint32_t read_domains, - uint32_t write_domain) + uint32_t write_domain, + cairo_bool_t needs_fence) { i915_batch_add_reloc (device, device->batch.used, bo, offset, - read_domains, write_domain); + read_domains, write_domain, + needs_fence); i915_batch_emit_dword (device, bo->offset + offset); } cairo_private void +i915_vbo_flush (i915_device_t *device); + +cairo_private void i915_vbo_finish (i915_device_t *device); cairo_private cairo_status_t @@ -1114,6 +1166,7 @@ i915_add_rectangle (i915_device_t *device) uint32_t size; assert (device->floats_per_vertex); + assert (device->rectangle_size == 3*device->floats_per_vertex*sizeof(float)); size = device->rectangle_size; if (unlikely (device->vbo_offset + size > I915_VBO_SIZE)) @@ -1131,10 +1184,17 @@ i915_device (i915_surface_t *surface) return (i915_device_t *) surface->intel.drm.base.device; } +cairo_private cairo_status_t +i915_surface_clear (i915_surface_t *dst); + +cairo_private void +i915_set_dst (i915_device_t *device, i915_surface_t *dst); + cairo_private void i915_shader_init (i915_shader_t *shader, i915_surface_t *dst, - cairo_operator_t op); + cairo_operator_t op, + double opacity); cairo_private cairo_status_t i915_shader_acquire_pattern (i915_shader_t *shader, @@ -1168,4 +1228,43 @@ i915_fixup_unbounded (i915_surface_t *dst, const cairo_composite_rectangles_t *extents, cairo_clip_t *clip); +static inline cairo_bool_t +i915_surface_needs_tiling (i915_surface_t *dst) +{ + return dst->intel.drm.width > 2048 || dst->intel.drm.height > 2048; +} + +cairo_private cairo_status_t +i915_surface_copy_subimage (i915_device_t *device, + i915_surface_t *src, + const cairo_rectangle_int_t *extents, + cairo_bool_t flush, + i915_surface_t **clone_out); + +static inline uint32_t +pack_float (float f) +{ + union { + float f; + uint32_t ui; + } t; + t.f = f; + return t.ui; +} + +static inline cairo_status_t +i915_surface_fallback_flush (i915_surface_t *surface) +{ + cairo_status_t status; + + if (unlikely (surface->intel.drm.fallback != NULL)) + return intel_surface_flush (&surface->intel); + + status = CAIRO_STATUS_SUCCESS; + if (unlikely (surface->deferred_clear)) + status = i915_surface_clear (surface); + + return status; +} + #endif /* CAIRO_DRM_I915_PRIVATE_H */ diff --git a/src/drm/cairo-drm-i915-shader.c b/src/drm/cairo-drm-i915-shader.c index 4a7c6b99..1ecf7621 100644 --- a/src/drm/cairo-drm-i915-shader.c +++ b/src/drm/cairo-drm-i915-shader.c @@ -35,6 +35,7 @@ #include "cairo-error-private.h" #include "cairo-drm-i915-private.h" +#include "cairo-surface-offset-private.h" #include "cairo-surface-subsurface-private.h" #include "cairo-surface-snapshot-private.h" @@ -149,7 +150,7 @@ i915_packed_pixel_surface_create (i915_device_t *device, content); surface->bo = intel_bo_create (&device->intel, size, FALSE); - assert (tiling == I915_TILING_NONE); + assert (surface->bo->tiling == I915_TILING_NONE); if (unlikely (surface->bo == NULL)) { free (surface); return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); @@ -233,8 +234,6 @@ i915_packed_pixel_surface_create (i915_device_t *device, data += size; } } - - intel_bo_unmap (surface->bo); } surface->device = device; @@ -535,13 +534,6 @@ i915_shader_get_num_tex_coords (const i915_shader_t *shader) (((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) @@ -563,6 +555,7 @@ i915_set_shader_program (i915_device_t *device, (i915_shader_channel_key (&shader->mask) << 8) | (i915_shader_channel_key (&shader->clip) << 16) | (shader->op << 24) | + ((shader->opacity < 1.) << 30) | (((shader->content & CAIRO_CONTENT_ALPHA) == CAIRO_CONTENT_ALPHA) << 31); if (n == device->current_program) return; @@ -814,6 +807,13 @@ i915_set_shader_program (i915_device_t *device, } } + if (shader->opacity < 1.) { + i915_fs_mul (source_reg, + i915_fs_operand_reg (source_reg), + i915_fs_operand_reg (FS_C0 + constant_offset)); + constant_offset++; + } + /* need to preserve order of src, mask, clip, dst */ mask_reg = ~0; if (shader->clip.type.fragment == FS_TEXTURE) { @@ -924,10 +924,15 @@ i915_set_shader_program (i915_device_t *device, source_reg = mask_reg; } else { out_reg = FS_OC; - if (shader->content == CAIRO_CONTENT_ALPHA) - out_reg = FS_R3; - i915_fs_mov (out_reg, - i915_fs_operand_reg_pure (mask_reg, source_pure)); + if ((shader->content & CAIRO_CONTENT_COLOR) == 0) { + if (source_pure & (1 << 3)) + i915_fs_mov (out_reg, i915_fs_operand (mask_reg, W, W, W, W)); + else + i915_fs_mov (out_reg, i915_fs_operand_zero ()); + } else { + i915_fs_mov (out_reg, + i915_fs_operand_impure (mask_reg, W, source_pure)); + } source_reg = out_reg; } } else if (mask_reg) { @@ -945,7 +950,7 @@ i915_set_shader_program (i915_device_t *device, source_reg = out_reg; } } else { - /* (source OP dest) LERP_clip dest */ + /* (source OP dest) LERP_clip dest */ if (source_reg == ~0U) { if (source_pure == 0) { i915_fs_mov (FS_R3, @@ -981,11 +986,15 @@ i915_set_shader_program (i915_device_t *device, } source_reg = FS_OC; - if (shader->content != CAIRO_CONTENT_COLOR_ALPHA) - source_reg = FS_R3; - i915_fs_add (source_reg, - i915_fs_operand_reg (FS_R3), - i915_fs_operand_reg (mask_reg)); + if ((shader->content & CAIRO_CONTENT_COLOR) == 0) { + i915_fs_add (source_reg, + i915_fs_operand (FS_R3, W, W, W, W), + i915_fs_operand (mask_reg, W, W, W, W)); + } else { + i915_fs_add (source_reg, + i915_fs_operand_reg (FS_R3), + i915_fs_operand_reg (mask_reg)); + } } } @@ -1147,7 +1156,7 @@ i915_shader_acquire_solid (i915_shader_t *shader, src->base.content = content; src->type.fragment = src == &shader->source ? FS_DIFFUSE : FS_CONSTANT; } - src->type.vertex = VS_CONSTANT; + src->type.vertex = src->type.fragment == FS_ZERO ? VS_ZERO : VS_CONSTANT; src->type.pattern = PATTERN_CONSTANT; return CAIRO_STATUS_SUCCESS; @@ -1276,20 +1285,38 @@ i915_surface_clone (i915_device_t *device, i915_surface_t *clone; cairo_status_t status; +#if 0 clone = i915_surface_create_from_cacheable_image_internal (device, image); if (unlikely (clone->intel.drm.base.status)) return clone->intel.drm.base.status; +#else + cairo_format_t format; - status = intel_snapshot_cache_insert (&device->intel, &clone->intel); - if (unlikely (status)) { - cairo_surface_destroy (&clone->intel.drm.base); - return status; - } + format = image->format; + if (format == CAIRO_FORMAT_A1) + format = CAIRO_FORMAT_A8; + + clone = (i915_surface_t *) + i915_surface_create_internal (&device->intel.base, + format, + image->width, + image->height, + I915_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), + image, + 0, 0, + image->width, image->height, + 0, 0); - _cairo_surface_attach_snapshot (&image->base, - &clone->intel.drm.base, - intel_surface_detach_snapshot); + if (unlikely (status)) + return status; +#endif *clone_out = clone; return CAIRO_STATUS_SUCCESS; @@ -1303,10 +1330,15 @@ i915_surface_clone_subimage (i915_device_t *device, { i915_surface_t *clone; cairo_status_t status; + cairo_format_t format; + + format = image->format; + if (format == CAIRO_FORMAT_A1) + format = CAIRO_FORMAT_A8; clone = (i915_surface_t *) i915_surface_create_internal (&device->intel.base, - image->base.content, + format, extents->width, extents->height, I915_TILING_NONE, @@ -1314,9 +1346,8 @@ i915_surface_clone_subimage (i915_device_t *device, 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), + status = intel_bo_put_image (&device->intel, to_intel_bo (clone->intel.drm.bo), - clone->intel.drm.stride, image, extents->x, extents->y, extents->width, extents->height, @@ -1330,6 +1361,60 @@ i915_surface_clone_subimage (i915_device_t *device, } static cairo_status_t +i915_surface_render_pattern (i915_device_t *device, + const cairo_surface_pattern_t *pattern, + const cairo_rectangle_int_t *extents, + i915_surface_t **clone_out) +{ + i915_surface_t *clone; + cairo_surface_t *image; + cairo_status_t status; + void *ptr; + + clone = (i915_surface_t *) + i915_surface_create_internal (&device->intel.base, + _cairo_format_from_content (pattern->surface->content), + extents->width, + extents->height, + I915_TILING_NONE, + FALSE); + if (unlikely (clone->intel.drm.base.status)) + return clone->intel.drm.base.status; + + ptr = intel_bo_map (&device->intel, + to_intel_bo (clone->intel.drm.bo)); + if (unlikely (ptr == NULL)) { + cairo_surface_destroy (&clone->intel.drm.base); + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + + image = cairo_image_surface_create_for_data (ptr, + clone->intel.drm.format, + clone->intel.drm.width, + clone->intel.drm.height, + clone->intel.drm.stride); + if (unlikely (image->status)) { + cairo_surface_destroy (&clone->intel.drm.base); + return image->status; + } + + status = _cairo_surface_offset_paint (image, + extents->x, extents->y, + CAIRO_OPERATOR_SOURCE, + &pattern->base, + NULL); + cairo_surface_destroy (image); + + if (unlikely (status)) { + cairo_surface_destroy (&clone->intel.drm.base); + 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, @@ -1385,6 +1470,46 @@ i915_shader_acquire_solid_surface (i915_shader_t *shader, return CAIRO_STATUS_SUCCESS; } +static cairo_filter_t +sampled_area (const cairo_surface_pattern_t *pattern, + const cairo_rectangle_int_t *extents, + cairo_rectangle_int_t *sample) +{ + cairo_rectangle_int_t surface_extents; + cairo_filter_t filter; + double x1, x2, y1, y2; + double pad; + + x1 = extents->x; + y1 = extents->y; + x2 = extents->x + (int) extents->width; + y2 = extents->y + (int) extents->height; + + if (_cairo_matrix_is_translation (&pattern->base.matrix)) { + x1 += pattern->base.matrix.x0; x2 += pattern->base.matrix.x0; + y1 += pattern->base.matrix.y0; y2 += pattern->base.matrix.y0; + } else { + _cairo_matrix_transform_bounding_box (&pattern->base.matrix, + &x1, &y1, &x2, &y2, + NULL); + } + + filter = _cairo_pattern_analyze_filter (&pattern->base, &pad); + sample->x = floor (x1 - pad); + sample->y = floor (y1 - pad); + sample->width = ceil (x2 + pad) - sample->x; + sample->height = ceil (y2 + pad) - sample->y; + + if (_cairo_surface_get_extents (pattern->surface, &surface_extents)) { + cairo_bool_t is_empty; + + is_empty = _cairo_rectangle_intersect (sample, + &surface_extents); + } + + return filter; +} + static cairo_status_t i915_shader_acquire_surface (i915_shader_t *shader, union i915_shader_channel *src, @@ -1399,10 +1524,15 @@ i915_shader_acquire_surface (i915_shader_t *shader, int src_x = 0, src_y = 0; cairo_surface_t *free_me = NULL; cairo_status_t status; + cairo_rectangle_int_t sample; assert (src->type.fragment == (i915_fragment_shader_t) -1); drm = surface = pattern->surface; + extend = pattern->base.extend; + src->base.matrix = pattern->base.matrix; + filter = sampled_area (pattern, extents, &sample); + #if CAIRO_HAS_XCB_SURFACE && CAIRO_HAS_XCB_DRM_FUNCTIONS if (surface->type == CAIRO_SURFACE_TYPE_XCB) { cairo_surface_t *xcb = surface; @@ -1440,11 +1570,11 @@ i915_shader_acquire_surface (i915_shader_t *shader, cairo_surface_subsurface_t *sub = (cairo_surface_subsurface_t *) surface; int x; - if (s->intel.drm.fallback != NULL) { - status = intel_surface_flush (s); - if (unlikely (status)) - return status; - } + status = i915_surface_fallback_flush (s); + if (unlikely (status)) + return status; + + /* XXX blt subimage and cache snapshot */ if (to_intel_bo (s->intel.drm.bo)->batch_write_domain) { /* XXX pipelined flush of RENDER/TEXTURE cache */ @@ -1473,18 +1603,23 @@ i915_shader_acquire_surface (i915_shader_t *shader, } } 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) - { - if (s->intel.drm.fallback != NULL) { - status = intel_surface_flush (s); + if (s->intel.drm.base.device == shader->target->intel.drm.base.device) { + status = i915_surface_fallback_flush (s); + if (unlikely (status)) + return status; + + if (s == shader->target || i915_surface_needs_tiling (s)) { + status = i915_surface_copy_subimage (i915_device (shader->target), + s, &sample, TRUE, &s); if (unlikely (status)) return status; - } + free_me = drm = &s->intel.drm.base; + } src->type.fragment = FS_TEXTURE; src->surface.pixel = NONE; + surface_width = s->intel.drm.width; surface_height = s->intel.drm.height; @@ -1509,8 +1644,6 @@ i915_shader_acquire_surface (i915_shader_t *shader, _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 @@ -1520,23 +1653,59 @@ i915_shader_acquire_surface (i915_shader_t *shader, 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); + if (sample.width > 2048 || sample.height > 2048) { + status = i915_surface_render_pattern (i915_device (shader->target), + pattern, extents, + &s); + if (unlikely (status)) + return status; + + extend = CAIRO_EXTEND_NONE; + filter = CAIRO_FILTER_NEAREST; + cairo_matrix_init_translate (&src->base.matrix, + -extents->x, -extents->y); } 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; - } + cairo_image_surface_t *image; + void *image_extra; + + status = _cairo_surface_acquire_source_image (surface, &image, &image_extra); + if (unlikely (status)) + return status; + + if (image->width < 2048 && + image->height < 2048 && + sample.width >= image->width / 4 && + sample.height >= image->height /4) + { + + status = i915_surface_clone (i915_device (shader->target), + image, &s); + + if (likely (status == CAIRO_STATUS_SUCCESS)) { + _cairo_surface_attach_snapshot (surface, + &s->intel.drm.base, + intel_surface_detach_snapshot); + + status = intel_snapshot_cache_insert (&i915_device (shader->target)->intel, + &s->intel); + if (unlikely (status)) { + cairo_surface_finish (&s->intel.drm.base); + cairo_surface_destroy (&s->intel.drm.base); + } + } + } + else + { + status = i915_surface_clone_subimage (i915_device (shader->target), + image, &sample, &s); + src_x = -extents->x; + src_y = -extents->y; + } - _cairo_surface_release_source_image (surface, image, image_extra); - if (unlikely (status)) - return status; + _cairo_surface_release_source_image (surface, image, image_extra); + if (unlikely (status)) + return status; + } free_me = &s->intel.drm.base; } @@ -1559,11 +1728,10 @@ i915_shader_acquire_surface (i915_shader_t *shader, /* 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) + sample.x >= 0 && sample.y >= 0 && + sample.x + sample.width <= surface_width && + sample.y + sample.height <= surface_height) { extend = CAIRO_EXTEND_NONE; } @@ -1576,10 +1744,6 @@ i915_shader_acquire_surface (i915_shader_t *shader, } 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); @@ -1588,11 +1752,8 @@ i915_shader_acquire_surface (i915_shader_t *shader, 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); @@ -1720,14 +1881,44 @@ i915_shader_channel_init (union i915_shader_channel *channel) channel->base.mode = 0; } +static void +i915_shader_channel_fini (i915_device_t *device, + union i915_shader_channel *channel) +{ + switch (channel->type.pattern) { + case PATTERN_TEXTURE: + case PATTERN_BASE: + case PATTERN_LINEAR: + case PATTERN_RADIAL: + if (channel->base.bo != NULL) + intel_bo_destroy (&device->intel, channel->base.bo); + break; + + default: + case PATTERN_CONSTANT: + break; + } +} + +static void +i915_shader_channel_reset (i915_device_t *device, + union i915_shader_channel *channel) +{ + i915_shader_channel_fini (device, channel); + i915_shader_channel_init (channel); +} + void i915_shader_init (i915_shader_t *shader, i915_surface_t *dst, - cairo_operator_t op) + cairo_operator_t op, + double opacity) { + shader->committed = FALSE; shader->device = i915_device (dst); shader->target = dst; shader->op = op; + shader->opacity = opacity; shader->blend = i915_get_blend (op, dst); shader->need_combine = FALSE; @@ -1744,216 +1935,219 @@ 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; + uint32_t n_samplers, n_maps, n; + uint32_t samplers[2*4]; + uint32_t maps[4*4]; + uint32_t mask, s, m; - n_samplers = + n_maps = shader->source.base.n_samplers + shader->mask.base.n_samplers + shader->clip.base.n_samplers + shader->dst.base.n_samplers; - assert (n_samplers <= 4); + assert (n_maps <= 4); - if (n_samplers == 0) + if (n_maps == 0) return; - mask = (1 << n_samplers) - 1; + n_samplers = + !! shader->source.base.bo + + !! shader->mask.base.bo + + !! shader->clip.base.bo + + !! shader->dst.base.bo; + + mask = (1 << n_maps) - 1; /* We check for repeated setting of sample state mainly to catch * continuation of text strings across multiple show-glyphs. */ - tu = 0; + s = m = 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]; + samplers[s++] = shader->source.base.sampler[0]; + samplers[s++] = shader->source.base.sampler[1]; + maps[m++] = shader->source.base.bo->base.handle; 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]; + maps[m++] = shader->source.base.offset[n]; + maps[m++] = shader->source.base.map[2*n+0]; + maps[m++] = 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]; + samplers[s++] = shader->mask.base.sampler[0]; + samplers[s++] = shader->mask.base.sampler[1]; + maps[m++] = shader->mask.base.bo->base.handle; 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]; + maps[m++] = shader->mask.base.offset[n]; + maps[m++] = shader->mask.base.map[2*n+0]; + maps[m++] = 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]; + samplers[s++] = shader->clip.base.sampler[0]; + samplers[s++] = shader->clip.base.sampler[1]; + maps[m++] = shader->clip.base.bo->base.handle; 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]; + maps[m++] = shader->clip.base.offset[n]; + maps[m++] = shader->clip.base.map[2*n+0]; + maps[m++] = 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]; + samplers[s++] = shader->dst.base.sampler[0]; + samplers[s++] = shader->dst.base.sampler[1]; + maps[m++] = shader->dst.base.bo->base.handle; 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]; + maps[m++] = shader->dst.base.offset[n]; + maps[m++] = shader->dst.base.map[2*n+0]; + maps[m++] = shader->dst.base.map[2*n+1]; } } - if (tu == device->current_n_samplers && - memcmp (device->current_samplers, - samplers, - tu * sizeof (uint32_t)) == 0) + if (n_maps > device->current_n_maps || + memcmp (device->current_maps, + maps, + m * sizeof (uint32_t))) { - return; - } - device->current_n_samplers = tu; - memcpy (device->current_samplers, samplers, tu * sizeof (uint32_t)); + memcpy (device->current_maps, maps, m * sizeof (uint32_t)); + device->current_n_maps = n_maps; - 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 (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; - } + 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; + 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; } - - default: + } else 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; - } + 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; + 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; } - - default: + } else 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) { + OUT_DWORD (_3DSTATE_MAP_STATE | (3 * n_maps)); + OUT_DWORD (mask); 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); + I915_GEM_DOMAIN_SAMPLER, 0, + FALSE); 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); + I915_GEM_DOMAIN_SAMPLER, 0, + FALSE); 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); + I915_GEM_DOMAIN_SAMPLER, 0, + FALSE); 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); + I915_GEM_DOMAIN_SAMPLER, 0, + FALSE); 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) { + if (n_samplers > device->current_n_samplers || + memcmp (device->current_samplers, + samplers, + s * sizeof (uint32_t))) + { + device->current_n_samplers = s; + memcpy (device->current_samplers, samplers, s * sizeof (uint32_t)); + + OUT_DWORD (_3DSTATE_SAMPLER_STATE | (3 * n_maps)); + OUT_DWORD (mask); + s = 0; 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)); + (s << SS3_TEXTUREMAP_INDEX_SHIFT)); OUT_DWORD (0x0); - tu++; + s++; } - } - 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)); + (s << SS3_TEXTUREMAP_INDEX_SHIFT)); OUT_DWORD (0x0); - tu++; + s++; } - } - 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)); + (s << SS3_TEXTUREMAP_INDEX_SHIFT)); OUT_DWORD (0x0); - tu++; + s++; } - } - 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)); + (s << SS3_TEXTUREMAP_INDEX_SHIFT)); OUT_DWORD (0x0); - tu++; + s++; } } } @@ -2047,17 +2241,6 @@ i915_set_constants (i915_device_t *device, 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) @@ -2108,7 +2291,7 @@ static void i915_set_shader_constants (i915_device_t *device, const i915_shader_t *shader) { - uint32_t constants[4*4*3]; + uint32_t constants[4*4*3+4]; unsigned n_constants; n_constants = 0; @@ -2131,6 +2314,14 @@ i915_set_shader_constants (i915_device_t *device, } n_constants += pack_constants (&shader->mask, constants + n_constants); + if (shader->opacity < 1.) { + constants[n_constants+0] = + constants[n_constants+1] = + constants[n_constants+2] = + constants[n_constants+3] = pack_float (shader->opacity); + n_constants += 4; + } + if (n_constants != 0 && (device->current_n_constants != n_constants || memcmp (device->current_constants, constants, n_constants*4))) @@ -2150,74 +2341,77 @@ i915_shader_needs_update (const i915_shader_t *shader, return TRUE; count = + !! shader->source.base.bo + + !! shader->mask.base.bo + + !! shader->clip.base.bo + + !! shader->dst.base.bo; + if (count > device->current_n_samplers) + 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) + if (count > device->current_n_maps) 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) + if (count) { + count = 0; + if (shader->source.base.bo != NULL) { + buf[count++] = shader->source.base.sampler[0]; + buf[count++] = shader->source.base.sampler[1]; + } + if (shader->mask.base.bo != NULL) { + buf[count++] = shader->mask.base.sampler[0]; + buf[count++] = shader->mask.base.sampler[1]; + } + if (shader->clip.base.bo != NULL) { + buf[count++] = shader->clip.base.sampler[0]; + buf[count++] = shader->clip.base.sampler[1]; + } + if (shader->dst.base.bo != NULL) { + buf[count++] = shader->dst.base.sampler[0]; + buf[count++] = shader->dst.base.sampler[1]; + } + if (memcmp (device->current_samplers, buf, count * sizeof (uint32_t))) 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]; - } + count = 0; + if (shader->source.base.bo != NULL) { + buf[count++] = shader->source.base.bo->base.handle; + 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->mask.base.bo != NULL) { + buf[count++] = shader->mask.base.bo->base.handle; + 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->clip.base.bo != NULL) { + buf[count++] = shader->clip.base.bo->base.handle; + 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]; - } + } + if (shader->dst.base.bo != NULL) { + buf[count++] = shader->dst.base.bo->base.handle; + 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 (memcmp (device->current_maps, buf, count * sizeof (uint32_t))) + return TRUE; } if (i915_shader_get_texcoords (shader) != device->current_texcoords) @@ -2253,30 +2447,30 @@ i915_shader_needs_update (const i915_shader_t *shader, (i915_shader_channel_key (&shader->mask) << 8) | (i915_shader_channel_key (&shader->clip) << 16) | (shader->op << 24) | + ((shader->opacity < 1.) << 30) | (((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) +void +i915_set_dst (i915_device_t *device, i915_surface_t *dst) { - i915_surface_t *dst; - intel_bo_t *bo; uint32_t size; - dst = shader->target; - if (device->current_target == dst) - return; + if (device->current_target != dst) { + intel_bo_t *bo; + + bo = to_intel_bo (dst->intel.drm.bo); + assert (bo != NULL); - 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); - 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); + device->current_target = dst; + } if (dst->colorbuf != device->current_colorbuf) { OUT_DWORD (_3DSTATE_DST_BUF_VARS_CMD); @@ -2293,8 +2487,13 @@ i915_set_shader_target (i915_device_t *device, OUT_DWORD (0); /* origin */ device->current_size = size; } +} - device->current_target = dst; +static void +i915_set_shader_target (i915_device_t *device, + const i915_shader_t *shader) +{ + i915_set_dst (device, shader->target); } int @@ -2354,47 +2553,9 @@ 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; - } + i915_shader_channel_fini (device, &shader->source); + i915_shader_channel_fini (device, &shader->mask); + i915_shader_channel_fini (device, &shader->clip); } void @@ -2411,7 +2572,6 @@ i915_shader_set_clip (i915_shader_t *shader, 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; @@ -2420,7 +2580,7 @@ i915_shader_set_clip (i915_shader_t *shader, 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.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; @@ -2437,8 +2597,7 @@ i915_shader_set_clip (i915_shader_t *shader, 1. / s->intel.drm.width, 1. / s->intel.drm.height); cairo_matrix_translate (&shader->clip.base.matrix, - NEAREST_BIAS - clip_x, - NEAREST_BIAS - clip_y); + -clip_x, -clip_y); } static cairo_status_t @@ -2473,7 +2632,7 @@ i915_shader_check_aperture (i915_shader_t *shader, } static void -i915_shader_combine_mask (i915_shader_t *shader) +i915_shader_combine_mask (i915_shader_t *shader, i915_device_t *device) { if (shader->mask.type.fragment == (i915_fragment_shader_t) -1 || shader->mask.type.fragment == FS_CONSTANT) @@ -2492,24 +2651,22 @@ i915_shader_combine_mask (i915_shader_t *shader) 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; + i915_shader_channel_reset (device, &shader->mask); } if (shader->mask.type.fragment == FS_ZERO) { + i915_shader_channel_fini (device, &shader->source); + shader->source.type.fragment = FS_ZERO; - shader->source.type.vertex = VS_CONSTANT; + shader->source.type.vertex = VS_ZERO; shader->source.base.texfmt = TEXCOORDFMT_NOT_PRESENT; shader->source.base.mode = 0; + shader->source.base.n_samplers = 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; + i915_shader_channel_reset (device, &shader->mask); + i915_shader_channel_reset (device, &shader->clip); } } @@ -2533,7 +2690,6 @@ i915_shader_setup_dst (i915_shader_t *shader) 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; @@ -2558,9 +2714,6 @@ i915_shader_setup_dst (i915_shader_t *shader) 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 @@ -2608,6 +2761,7 @@ i915_composite_vertex (float *v, *v++ = x; *v++ = y; switch (shader->source.type.vertex) { + case VS_ZERO: case VS_CONSTANT: break; case VS_LINEAR: @@ -2625,6 +2779,7 @@ i915_composite_vertex (float *v, break; } switch (shader->mask.type.vertex) { + case VS_ZERO: case VS_CONSTANT: break; case VS_LINEAR: @@ -2659,14 +2814,13 @@ i915_shader_add_rectangle_general (const i915_shader_t *shader, /* XXX overflow! */ } -static cairo_status_t +void i915_vbo_flush (i915_device_t *device) { + assert (device->floats_per_vertex); assert (device->vertex_count); if (device->vbo == 0) { - assert (device->floats_per_vertex); - OUT_DWORD (_3DSTATE_LOAD_STATE_IMMEDIATE_1 | I1_LOAD_S (0) | I1_LOAD_S (1) | @@ -2684,8 +2838,6 @@ i915_vbo_flush (i915_device_t *device) device->vertex_index += device->vertex_count; device->vertex_count = 0; - - return CAIRO_STATUS_SUCCESS; } cairo_status_t @@ -2697,9 +2849,20 @@ i915_shader_commit (i915_shader_t *shader, assert (CAIRO_MUTEX_IS_LOCKED (device->intel.base.base.mutex)); - i915_shader_combine_source (shader, device); - i915_shader_combine_mask (shader); - i915_shader_setup_dst (shader); + if (! shader->committed) { + device->shader = shader; + + i915_shader_combine_mask (shader, device); + i915_shader_combine_source (shader, device); + i915_shader_setup_dst (shader); + + shader->add_rectangle = i915_shader_add_rectangle_general; + + if ((status = setjmp (shader->unwind))) + return status; + + shader->committed = TRUE; + } if (i915_shader_needs_update (shader, device)) { if (i915_batch_space (device) < 256) { @@ -2708,11 +2871,8 @@ i915_shader_commit (i915_shader_t *shader, return status; } - if (device->vertex_count) { - status = i915_vbo_flush (device); - if (unlikely (status)) - return status; - } + if (device->vertex_count) + i915_vbo_flush (device); status = i915_shader_check_aperture (shader, device); if (unlikely (status)) @@ -2726,9 +2886,6 @@ i915_shader_commit (i915_shader_t *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; @@ -2741,11 +2898,8 @@ i915_shader_commit (i915_shader_t *shader, goto update_shader; } - if (device->vertex_count) { - status = i915_vbo_flush (device); - if (unlikely (status)) - return status; - } + if (device->vertex_count) + i915_vbo_flush (device); if (device->vbo) { device->batch_base[device->vbo_max_index] |= device->vertex_index; diff --git a/src/drm/cairo-drm-i915-spans.c b/src/drm/cairo-drm-i915-spans.c index 99a53d5e..b3f4e0af 100644 --- a/src/drm/cairo-drm-i915-spans.c +++ b/src/drm/cairo-drm-i915-spans.c @@ -78,8 +78,6 @@ struct _i915_spans { unsigned int count; } head, *tail; - int rectangle_size; - unsigned int vbo_offset; float *vbo_base; }; @@ -96,12 +94,10 @@ i915_accumulate_rectangle (i915_spans_t *spans) float *vertices; uint32_t size; - size = spans->rectangle_size; + size = spans->device->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! */ @@ -111,7 +107,9 @@ i915_accumulate_rectangle (i915_spans_t *spans) spans->tail = vbo; vbo->next = NULL; - vbo->bo = intel_bo_create (&spans->device->intel, I915_VBO_SIZE, FALSE); + vbo->bo = intel_bo_create (&spans->device->intel, + I915_VBO_SIZE, I915_VBO_SIZE, + FALSE, I915_TILING_NONE, 0); vbo->count = 0; spans->vbo_offset = 0; @@ -126,6 +124,25 @@ i915_accumulate_rectangle (i915_spans_t *spans) } static void +i915_span_zero (i915_spans_t *spans, + int x0, int x1, int y0, int y1, + int alpha) +{ + float *vertices; + + vertices = spans->get_rectangle (spans); + + *vertices++ = x1; + *vertices++ = y1; + + *vertices++ = x0; + *vertices++ = y1; + + *vertices++ = x0; + *vertices++ = y0; +} + +static void i915_span_constant (i915_spans_t *spans, int x0, int x1, int y0, int y1, int alpha) @@ -264,6 +281,7 @@ i915_span_generic (i915_spans_t *spans, *vertices++ = x1; *vertices++ = y1; s = x1, t = y1; switch (spans->shader.source.type.vertex) { + case VS_ZERO: case VS_CONSTANT: break; case VS_LINEAR: @@ -294,6 +312,7 @@ i915_span_generic (i915_spans_t *spans, *vertices++ = x0; *vertices++ = y1; s = x0, t = y1; switch (spans->shader.source.type.vertex) { + case VS_ZERO: case VS_CONSTANT: break; case VS_LINEAR: @@ -324,6 +343,7 @@ i915_span_generic (i915_spans_t *spans, *vertices++ = x0; *vertices++ = y0; s = x0, t = y0; switch (spans->shader.source.type.vertex) { + case VS_ZERO: case VS_CONSTANT: break; case VS_LINEAR: @@ -352,6 +372,78 @@ i915_span_generic (i915_spans_t *spans, } static cairo_status_t +i915_zero_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; + int x0, x1; + + if (num_spans == 0) + return CAIRO_STATUS_SUCCESS; + + do { + while (num_spans && half[0].coverage < 128) + half++, num_spans--; + if (num_spans == 0) + break; + + x0 = x1 = half[0].x; + while (num_spans--) { + half++; + + x1 = half[0].x; + if (half[0].coverage < 128) + break; + } + + i915_span_zero (spans, + x0, x1, + y, y + height, + 0); + } while (num_spans); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +i915_zero_spans (void *abstract_renderer, + int y, int height, + const cairo_half_open_span_t *half, + unsigned num_spans) +{ + i915_spans_t *spans = abstract_renderer; + int x0, x1; + + if (num_spans == 0) + return CAIRO_STATUS_SUCCESS; + + do { + while (num_spans && half[0].coverage == 0) + half++, num_spans--; + if (num_spans == 0) + break; + + x0 = x1 = half[0].x; + while (num_spans--) { + half++; + + x1 = half[0].x; + if (half[0].coverage == 0) + break; + } + + i915_span_zero (spans, + x0, x1, + y, y + height, + 0); + } while (num_spans); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t i915_bounded_spans_mono (void *abstract_renderer, int y, int height, const cairo_half_open_span_t *half, @@ -491,6 +583,7 @@ i915_spans_init (i915_spans_t *spans, const cairo_pattern_t *pattern, cairo_antialias_t antialias, cairo_clip_t *clip, + double opacity, const cairo_composite_rectangles_t *extents) { cairo_status_t status; @@ -542,7 +635,8 @@ i915_spans_init (i915_spans_t *spans, assert (! extents->is_bounded); spans->get_rectangle = i915_accumulate_rectangle; spans->head.bo = intel_bo_create (&spans->device->intel, - I915_VBO_SIZE, FALSE); + I915_VBO_SIZE, I915_VBO_SIZE, + FALSE, I915_TILING_NONE, 0); if (unlikely (spans->head.bo == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); @@ -550,7 +644,7 @@ i915_spans_init (i915_spans_t *spans, } spans->vbo_offset = 0; - i915_shader_init (&spans->shader, dst, op); + i915_shader_init (&spans->shader, dst, op, opacity); if (spans->need_clip_surface) i915_shader_set_clip (&spans->shader, clip); @@ -559,7 +653,6 @@ i915_spans_init (i915_spans_t *spans, if (unlikely (status)) return status; - spans->rectangle_size = 3 * (2 + i915_shader_num_texcoords (&spans->shader)); return CAIRO_STATUS_SUCCESS; } @@ -568,9 +661,6 @@ i915_spans_fini (i915_spans_t *spans) { i915_shader_fini (&spans->shader); - if (spans->tail->bo && spans->tail->bo->virtual) - intel_bo_unmap (spans->tail->bo); - if (spans->head.bo != NULL) { struct vbo *vbo, *next; @@ -591,19 +681,25 @@ i915_clip_and_composite_spans (i915_surface_t *dst, i915_spans_func_t draw_func, void *draw_closure, const cairo_composite_rectangles_t*extents, - cairo_clip_t *clip) + cairo_clip_t *clip, + double opacity) { i915_spans_t spans; i915_device_t *device; cairo_status_t status; struct vbo *vbo; + if (i915_surface_needs_tiling (dst)) { + ASSERT_NOT_REACHED; + return CAIRO_INT_STATUS_UNSUPPORTED; + } + 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); + status = i915_spans_init (&spans, dst, op, pattern, antialias, clip, opacity, extents); if (unlikely (status)) return status; @@ -615,13 +711,28 @@ i915_clip_and_composite_spans (i915_surface_t *dst, if (unlikely (status)) goto CLEANUP_SPANS; + if (dst->deferred_clear) { + status = i915_surface_clear (dst); + if (unlikely (status)) + goto CLEANUP_SPANS; + } + device = i915_device (dst); status = i915_shader_commit (&spans.shader, device); if (unlikely (status)) goto CLEANUP_DEVICE; - if (!spans.shader.need_combine && ! spans.need_clip_surface) { + if (! spans.shader.need_combine && ! spans.need_clip_surface) { switch (spans.shader.source.type.vertex) { + case VS_ZERO: + spans.span = i915_span_zero; + if (extents->is_bounded) { + if (antialias == CAIRO_ANTIALIAS_NONE) + spans.renderer.render_rows = i915_zero_spans_mono; + else + spans.renderer.render_rows = i915_zero_spans; + } + break; case VS_CONSTANT: spans.span = i915_span_constant; break; @@ -644,8 +755,6 @@ i915_clip_and_composite_spans (i915_surface_t *dst, 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); @@ -656,7 +765,8 @@ i915_clip_and_composite_spans (i915_surface_t *dst, 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); + I915_GEM_DOMAIN_VERTEX, 0, + FALSE); OUT_DWORD ((device->floats_per_vertex << S1_VERTEX_WIDTH_SHIFT) | (device->floats_per_vertex << S1_VERTEX_PITCH_SHIFT) | vbo->count); diff --git a/src/drm/cairo-drm-i915-surface.c b/src/drm/cairo-drm-i915-surface.c index 5e04982b..b9adf92a 100644 --- a/src/drm/cairo-drm-i915-surface.c +++ b/src/drm/cairo-drm-i915-surface.c @@ -114,16 +114,6 @@ #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, @@ -189,8 +179,6 @@ static const uint32_t i915_batch_setup[] = { 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); @@ -228,64 +216,85 @@ i915_bo_exec (i915_device_t *device, intel_bo_t *bo, uint32_t offset) 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; + if (device->debug & I915_DEBUG_SYNC && ret == 0) + ret = ! intel_bo_wait (&device->intel, bo); + + if (0 && ret) { + int n, m; 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, " gtt size: (%zd/%zd), (%zd/%zd)\n", + device->batch.est_gtt_size, device->batch.gtt_avail_size, + device->batch.total_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); + for (n = 0; n < device->batch.exec_count; n++) { + fprintf (stderr, " exec[%d] = %d, %d/%d bytes, gtt = %qx\n", + n, + device->batch.exec[n].handle, + n == device->batch.exec_count - 1 ? bo->base.size : device->batch.target_bo[n]->base.size, + n == device->batch.exec_count - 1 ? bo->full_size : device->batch.target_bo[n]->full_size, + device->batch.exec[n].offset); + } + for (n = 0; n < device->batch.reloc_count; n++) { + for (m = 0; m < device->batch.exec_count; m++) + if (device->batch.exec[m].handle == device->batch.reloc[n].target_handle) + break; + + fprintf (stderr, " reloc[%d] = %d @ %qx -> %qx + %qx\n", n, + device->batch.reloc[n].target_handle, + device->batch.reloc[n].offset, + (unsigned long long) device->batch.exec[m].offset, + (unsigned long long) device->batch.reloc[n].delta); + + device->batch_base[(device->batch.reloc[n].offset - sizeof (device->batch_header)) / 4] = + device->batch.exec[m].offset + device->batch.reloc[n].delta; } intel_dump_batchbuffer (device->batch_header, execbuf.batch_len, device->intel.base.chip_id); } + assert (ret == 0); VG (VALGRIND_MAKE_MEM_DEFINED (device->batch.exec, sizeof (device->batch.exec[0]) * i)); bo->offset = device->batch.exec[i].offset; + bo->busy = TRUE; + if (bo->virtual) + intel_bo_unmap (bo); + bo->cpu = FALSE; + 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]); + intel_bo_t *bo = device->batch.target_bo[cnt]; + + bo->offset = device->batch.exec[cnt].offset; + bo->exec = NULL; + bo->busy = TRUE; + bo->batch_read_domains = 0; + bo->batch_write_domain = 0; + cairo_list_del (&bo->cache_list); + + if (bo->virtual) + intel_bo_unmap (bo); + bo->cpu = FALSE; + + intel_bo_destroy (&device->intel, bo); } + assert (cairo_list_is_empty (&device->intel.bo_in_flight)); device->batch.exec_count = 0; device->batch.reloc_count = 0; + device->batch.fences = 0; - device->batch.gtt_size = I915_BATCH_SIZE; + device->batch.est_gtt_size = I915_BATCH_SIZE; + device->batch.total_gtt_size = I915_BATCH_SIZE; return ret == 0 ? CAIRO_STATUS_SUCCESS : _cairo_error (CAIRO_STATUS_NO_MEMORY); } @@ -296,12 +305,20 @@ i915_batch_add_reloc (i915_device_t *device, intel_bo_t *bo, uint32_t offset, uint32_t read_domains, - uint32_t write_domain) + uint32_t write_domain, + cairo_bool_t needs_fence) { int index; + assert (offset < bo->base.size); + if (bo->exec == NULL) { - device->batch.gtt_size += bo->base.size; + device->batch.total_gtt_size += bo->base.size; + + if (! bo->busy) + device->batch.est_gtt_size += bo->base.size; + + assert (device->batch.exec_count < ARRAY_LENGTH (device->batch.exec)); index = device->batch.exec_count++; device->batch.exec[index].handle = bo->base.handle; @@ -318,6 +335,31 @@ i915_batch_add_reloc (i915_device_t *device, bo->exec = &device->batch.exec[index]; } + if (bo->tiling != I915_TILING_NONE) { + uint32_t alignment; + +#if 0 + /* We presume that we will want to use a fence with X tiled objects... */ + if (needs_fence || bo->tiling == I915_TILING_X) + alignment = bo->full_size; + else + alignment = 2*((bo->stride + 4095) & -4096); +#else + alignment = bo->full_size; +#endif + if (bo->exec->alignment < alignment) + bo->exec->alignment = alignment; + + if (needs_fence && (bo->exec->flags & EXEC_OBJECT_NEEDS_FENCE) == 0) { + bo->exec->flags |= EXEC_OBJECT_NEEDS_FENCE; + device->batch.fences++; + + intel_bo_set_tiling (&device->intel, bo); + } + } + + assert (device->batch.reloc_count < ARRAY_LENGTH (device->batch.reloc)); + index = device->batch.reloc_count++; device->batch.reloc[index].offset = (pos << 2) + sizeof (device->batch_header); device->batch.reloc[index].delta = offset; @@ -334,20 +376,124 @@ i915_batch_add_reloc (i915_device_t *device, void i915_vbo_finish (i915_device_t *device) { + intel_bo_t *vbo; + assert (CAIRO_MUTEX_IS_LOCKED (device->intel.base.base.mutex)); + assert (device->vbo_used); + + if (device->vertex_count) { + if (device->vbo == 0) { + 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 (device->last_vbo != NULL) { + intel_bo_in_flight_add (&device->intel, device->last_vbo); + intel_bo_destroy (&device->intel, device->last_vbo); + } - if (device->vbo_used == 0) - return; + 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, device->vbo_used, + FALSE, I915_TILING_NONE, 0); + 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; + + device->vbo_used = device->vbo_offset = 0; + device->vertex_index = device->vertex_count = 0; + + if (! i915_check_aperture_size (device, 1, I915_VBO_SIZE, I915_VBO_SIZE)) { + cairo_status_t status; + + status = i915_batch_flush (device); + if (unlikely (status)) + longjmp (device->shader->unwind, status); + + status = i915_shader_commit (device->shader, device); + if (unlikely (status)) + longjmp (device->shader->unwind, status); + } +} + +/* 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_texcoords = ~0; + device->current_blend = 0; + device->current_n_constants = 0; + device->current_n_samplers = 0; + device->current_n_maps = 0; + device->current_colorbuf = 0; + device->current_diffuse = 0; + device->current_program = ~0; + device->clear_alpha = ~0; + + device->last_source_fragment = ~0; +} + +static void +i915_batch_cleanup (i915_device_t *device) +{ + int i; + + for (i = 0; i < device->batch.exec_count; i++) { + intel_bo_t *bo = device->batch.target_bo[i]; + + bo->exec = NULL; + bo->batch_read_domains = 0; + bo->batch_write_domain = 0; + cairo_list_del (&bo->cache_list); + + intel_bo_destroy (&device->intel, bo); + } + + device->batch.exec_count = 0; + device->batch.reloc_count = 0; +} + +static void +i915_batch_vbo_finish (i915_device_t *device) +{ + assert (CAIRO_MUTEX_IS_LOCKED (device->intel.base.base.mutex)); 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) | @@ -355,7 +501,7 @@ i915_vbo_finish (i915_device_t *device) 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)); + (device->floats_per_vertex << S1_VERTEX_PITCH_SHIFT)); } OUT_DWORD (PRIM3D_RECTLIST | @@ -364,18 +510,15 @@ i915_vbo_finish (i915_device_t *device) 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); + vbo = intel_bo_create (&device->intel, + device->vbo_used, device->vbo_used, + FALSE, I915_TILING_NONE, 0); i915_batch_fill_reloc (device, device->vbo, vbo, 0, I915_GEM_DOMAIN_VERTEX, 0); @@ -399,48 +542,6 @@ i915_vbo_finish (i915_device_t *device) 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) { @@ -451,7 +552,8 @@ i915_batch_flush (i915_device_t *device) assert (CAIRO_MUTEX_IS_LOCKED (device->intel.base.base.mutex)); - i915_vbo_finish (device); + if (device->vbo_used) + i915_batch_vbo_finish (device); if (device->batch.used == 0) return CAIRO_STATUS_SUCCESS; @@ -462,20 +564,12 @@ i915_batch_flush (i915_device_t *device) 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; @@ -487,10 +581,9 @@ i915_batch_flush (i915_device_t *device) 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); + batch = intel_bo_create (&device->intel, + length, length, + FALSE, I915_TILING_NONE, 0); if (unlikely (batch == NULL)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); i915_batch_cleanup (device); @@ -501,10 +594,6 @@ i915_batch_flush (i915_device_t *device) } 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: @@ -543,14 +632,44 @@ i915_add_rectangles (i915_device_t *device, int num_rects, int *count) } #endif +static cairo_surface_t * +i915_surface_create_similar (void *abstract_other, + cairo_content_t content, + int width, int height) +{ + i915_surface_t *other; + cairo_format_t format; + uint32_t tiling = I915_TILING_DEFAULT; + + other = abstract_other; + if (content == other->intel.drm.base.content) + format = other->intel.drm.format; + else + format = _cairo_format_from_content (content); + + if (width * _cairo_format_bits_per_pixel (format) > 8 * 32*1024 || height > 64*1024) + return NULL; + + /* we presume that a similar surface will be used for blitting */ + if (i915_surface_needs_tiling (other)) + tiling = I915_TILING_X; + + return i915_surface_create_internal ((cairo_drm_device_t *) other->intel.drm.base.device, + format, + width, height, + tiling, TRUE); +} + 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) + if (surface->stencil != NULL) { + intel_bo_in_flight_add (&device->intel, surface->stencil); intel_bo_destroy (&device->intel, surface->stencil); + } if (surface->is_current_texture) { if (surface->is_current_texture & CURRENT_SOURCE) @@ -570,6 +689,7 @@ i915_surface_finish (void *abstract_surface) intel_buffer_cache_t *cache = node->container; if (--cache->ref_count == 0) { + intel_bo_in_flight_add (&device->intel, cache->buffer.bo); intel_bo_destroy (&device->intel, cache->buffer.bo); _cairo_rtree_fini (&cache->rtree); cairo_list_del (&cache->link); @@ -581,7 +701,7 @@ i915_surface_finish (void *abstract_surface) } } - return _cairo_drm_surface_finish (&surface->intel.drm); + return intel_surface_finish (&surface->intel); } static cairo_status_t @@ -610,6 +730,7 @@ static cairo_status_t i915_surface_flush (void *abstract_surface) { i915_surface_t *surface = abstract_surface; + cairo_status_t status; if (surface->intel.drm.fallback == NULL) { if (surface->intel.drm.base.finished) { @@ -617,6 +738,12 @@ i915_surface_flush (void *abstract_surface) return CAIRO_STATUS_SUCCESS; } + if (surface->deferred_clear) { + status = i915_surface_clear (surface); + if (unlikely (status)) + return status; + } + return i915_surface_batch_flush (surface); } @@ -666,7 +793,7 @@ i915_fixup_unbounded (i915_surface_t *dst, cairo_region_t *clip_region = NULL; status = _cairo_clip_get_region (clip, &clip_region); - assert (status == CAIRO_STATUS_SUCCESS || CAIRO_INT_STATUS_UNSUPPORTED); + assert (status == CAIRO_STATUS_SUCCESS || status == CAIRO_INT_STATUS_UNSUPPORTED); assert (clip_region == NULL); if (status != CAIRO_INT_STATUS_UNSUPPORTED) @@ -680,7 +807,7 @@ i915_fixup_unbounded (i915_surface_t *dst, } if (clip != NULL) { - i915_shader_init (&shader, dst, CAIRO_OPERATOR_DEST_OVER); + i915_shader_init (&shader, dst, CAIRO_OPERATOR_DEST_OVER, 1.); i915_shader_set_clip (&shader, clip); status = i915_shader_acquire_pattern (&shader, &shader.source, @@ -688,7 +815,7 @@ i915_fixup_unbounded (i915_surface_t *dst, &extents->unbounded); assert (status == CAIRO_STATUS_SUCCESS); } else { - i915_shader_init (&shader, dst, CAIRO_OPERATOR_CLEAR); + i915_shader_init (&shader, dst, CAIRO_OPERATOR_CLEAR, 1.); status = i915_shader_acquire_pattern (&shader, &shader.source, &_cairo_pattern_clear.base, @@ -780,7 +907,7 @@ i915_fixup_unbounded_boxes (i915_surface_t *dst, if (clip != NULL) { status = _cairo_clip_get_region (clip, &clip_region); - assert (status == CAIRO_STATUS_SUCCESS || CAIRO_INT_STATUS_UNSUPPORTED); + assert (status == CAIRO_STATUS_SUCCESS || status == CAIRO_INT_STATUS_UNSUPPORTED); if (status != CAIRO_INT_STATUS_UNSUPPORTED) clip = NULL; } @@ -830,7 +957,7 @@ i915_fixup_unbounded_boxes (i915_surface_t *dst, i915_device_t *device; if (clip != NULL) { - i915_shader_init (&shader, dst, CAIRO_OPERATOR_DEST_OVER); + i915_shader_init (&shader, dst, CAIRO_OPERATOR_DEST_OVER, 1.); i915_shader_set_clip (&shader, clip); status = i915_shader_acquire_pattern (&shader, &shader.source, @@ -838,7 +965,7 @@ i915_fixup_unbounded_boxes (i915_surface_t *dst, &extents->unbounded); assert (status == CAIRO_STATUS_SUCCESS); } else { - i915_shader_init (&shader, dst, CAIRO_OPERATOR_CLEAR); + i915_shader_init (&shader, dst, CAIRO_OPERATOR_CLEAR, 1.); status = i915_shader_acquire_pattern (&shader, &shader.source, &_cairo_pattern_clear.base, @@ -876,6 +1003,573 @@ err_shader: return status; } +static cairo_bool_t +i915_can_blt (i915_surface_t *dst, + const cairo_pattern_t *pattern) +{ + const cairo_surface_pattern_t *spattern; + i915_surface_t *src; + + spattern = (const cairo_surface_pattern_t *) pattern; + src = (i915_surface_t *) spattern->surface; + + if (src->intel.drm.base.device != dst->intel.drm.base.device) + return FALSE; + + if (! i915_surface_needs_tiling (dst)) + return FALSE; + + if (! _cairo_matrix_is_translation (&pattern->matrix)) + return FALSE; + + if (! (pattern->filter == CAIRO_FILTER_NEAREST || + pattern->filter == CAIRO_FILTER_FAST)) + { + if (! _cairo_fixed_is_integer (_cairo_fixed_from_double (pattern->matrix.x0)) || + ! _cairo_fixed_is_integer (_cairo_fixed_from_double (pattern->matrix.y0))) + { + return FALSE; + } + } + + return _cairo_format_bits_per_pixel (src->intel.drm.format) == + _cairo_format_bits_per_pixel (dst->intel.drm.format); +} + +static cairo_status_t +i915_blt (i915_surface_t *src, + i915_surface_t *dst, + int src_x, int src_y, + int width, int height, + int dst_x, int dst_y, + cairo_bool_t flush) +{ + i915_device_t *device; + intel_bo_t *bo_array[2]; + cairo_status_t status; + int br13, cmd; + + bo_array[0] = to_intel_bo (dst->intel.drm.bo); + bo_array[1] = to_intel_bo (src->intel.drm.bo); + + status = i915_surface_fallback_flush (src); + if (unlikely (status)) + return status; + + device = i915_device (dst); + status = cairo_device_acquire (&device->intel.base.base); + if (unlikely (status)) + return status; + + if (! i915_check_aperture_and_fences (device, bo_array, 2) || + i915_batch_space (device) < 9) + { + status = i915_batch_flush (device); + if (unlikely (status)) + goto CLEANUP; + } + + cmd = XY_SRC_COPY_BLT_CMD; + br13 = (0xCC << 16) | dst->intel.drm.stride; + switch (dst->intel.drm.format) { + default: + case CAIRO_FORMAT_INVALID: + case CAIRO_FORMAT_A1: + ASSERT_NOT_REACHED; + case CAIRO_FORMAT_A8: + break; + case CAIRO_FORMAT_RGB16_565: + br13 |= BR13_565; + break; + case CAIRO_FORMAT_RGB24: + case CAIRO_FORMAT_ARGB32: + br13 |= BR13_8888; + cmd |= XY_BLT_WRITE_ALPHA | XY_BLT_WRITE_RGB; + break; + } + + OUT_DWORD (cmd); + OUT_DWORD (br13); + OUT_DWORD ((dst_y << 16) | dst_x); + OUT_DWORD (((dst_y + height) << 16) | (dst_x + width)); + OUT_RELOC_FENCED (dst, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER); + OUT_DWORD ((src_y << 16) | src_x); + OUT_DWORD (src->intel.drm.stride); + OUT_RELOC_FENCED (src, I915_GEM_DOMAIN_RENDER, 0); + /* require explicit RenderCache flush for 2D -> 3D sampler? */ + if (flush) + OUT_DWORD (MI_FLUSH); + +CLEANUP: + cairo_device_release (&device->intel.base.base); + return CAIRO_STATUS_SUCCESS; +} + +cairo_status_t +i915_surface_copy_subimage (i915_device_t *device, + i915_surface_t *src, + const cairo_rectangle_int_t *extents, + cairo_bool_t flush, + i915_surface_t **clone_out) +{ + i915_surface_t *clone; + cairo_status_t status; + + clone = (i915_surface_t *) + i915_surface_create_internal (&device->intel.base, + src->intel.drm.format, + extents->width, + extents->height, + I915_TILING_X, TRUE); + if (unlikely (clone->intel.drm.base.status)) + return clone->intel.drm.base.status; + + status = i915_blt (src, clone, + extents->x, extents->y, + extents->width, extents->height, + 0, 0, + flush); + + if (unlikely (status)) { + cairo_surface_destroy (&clone->intel.drm.base); + return status; + } + + *clone_out = clone; + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +i915_clear_boxes (i915_surface_t *dst, + const cairo_boxes_t *boxes) +{ + i915_device_t *device = i915_device (dst); + const struct _cairo_boxes_chunk *chunk; + cairo_status_t status; + intel_bo_t *bo_array[1] = { to_intel_bo (dst->intel.drm.bo) }; + int cmd, br13, clear = 0, i; + + cmd = XY_COLOR_BLT_CMD; + br13 = (0xCC << 16) | dst->intel.drm.stride; + switch (dst->intel.drm.format) { + default: + case CAIRO_FORMAT_INVALID: + case CAIRO_FORMAT_A1: + ASSERT_NOT_REACHED; + case CAIRO_FORMAT_A8: + break; + case CAIRO_FORMAT_RGB16_565: + br13 |= BR13_565; + break; + case CAIRO_FORMAT_RGB24: + clear = 0xff000000; + case CAIRO_FORMAT_ARGB32: + br13 |= BR13_8888; + cmd |= XY_BLT_WRITE_ALPHA | XY_BLT_WRITE_RGB; + break; + } + + status = cairo_device_acquire (&device->intel.base.base); + if (unlikely (status)) + return status; + + if (! i915_check_aperture_and_fences (device, bo_array, 1) || + i915_batch_space (device) < 6 * boxes->num_boxes) + { + status = i915_batch_flush (device); + if (unlikely (status)) + goto RELEASE; + } + + if (device->vertex_count) + i915_vbo_flush (device); + + 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 x2 = _cairo_fixed_integer_round (box[i].p2.x); + int y1 = _cairo_fixed_integer_round (box[i].p1.y); + int y2 = _cairo_fixed_integer_round (box[i].p2.y); + + if (x2 <= x1 || y2 <= y1) + continue; + + OUT_DWORD (cmd); + OUT_DWORD (br13); + OUT_DWORD ((y1 << 16) | x1); + OUT_DWORD ((y2 << 16) | x2); + OUT_RELOC_FENCED (dst, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER); + OUT_DWORD (clear); + } + } + +RELEASE: + cairo_device_release (&device->intel.base.base); + return status; +} + +static cairo_status_t +i915_surface_extract_X_from_Y (i915_device_t *device, + i915_surface_t *src, + const cairo_rectangle_int_t *extents, + i915_surface_t **clone_out) +{ + i915_surface_t *clone; + i915_shader_t shader; + cairo_surface_pattern_t pattern; + cairo_rectangle_int_t rect; + cairo_status_t status; + + status = i915_surface_fallback_flush (src); + if (unlikely (status)) + return status; + + clone = (i915_surface_t *) + i915_surface_create_internal (&device->intel.base, + src->intel.drm.format, + extents->width, + extents->height, + I915_TILING_X, TRUE); + if (unlikely (clone->intel.drm.base.status)) + return clone->intel.drm.base.status; + + i915_shader_init (&shader, clone, CAIRO_OPERATOR_SOURCE, 1.); + + _cairo_pattern_init_for_surface (&pattern, &src->intel.drm.base); + pattern.base.filter = CAIRO_FILTER_NEAREST; + cairo_matrix_init_translate (&pattern.base.matrix, extents->x, extents->y); + + rect.x = rect.y = 0; + rect.width = extents->width; + rect.height = extents->height; + status = i915_shader_acquire_pattern (&shader, &shader.source, &pattern.base, &rect); + _cairo_pattern_fini (&pattern.base); + + if (unlikely (status)) + goto err_shader; + + status = cairo_device_acquire (&device->intel.base.base); + if (unlikely (status)) + goto err_shader; + + status = i915_shader_commit (&shader, device); + if (unlikely (status)) + goto err_device; + + shader.add_rectangle (&shader, 0, 0, extents->width, extents->height); + + cairo_device_release (&device->intel.base.base); + i915_shader_fini (&shader); + + *clone_out = clone; + return CAIRO_STATUS_SUCCESS; + +err_device: + cairo_device_release (&device->intel.base.base); +err_shader: + i915_shader_fini (&shader); + cairo_surface_destroy (&clone->intel.drm.base); + return status; +} + +static cairo_status_t +i915_blt_boxes (i915_surface_t *dst, + const cairo_pattern_t *pattern, + const cairo_rectangle_int_t *extents, + const cairo_boxes_t *boxes) +{ + const cairo_surface_pattern_t *spattern; + i915_device_t *device; + i915_surface_t *src; + cairo_surface_t *free_me = NULL; + const struct _cairo_boxes_chunk *chunk; + cairo_status_t status; + int br13, cmd, tx, ty; + intel_bo_t *bo_array[2]; + int i; + + if (! i915_can_blt (dst, pattern)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + spattern = (const cairo_surface_pattern_t *) pattern; + src = (i915_surface_t *) spattern->surface; + + if (src->intel.drm.base.is_clear) + return i915_clear_boxes (dst, boxes); + + if (pattern->extend != CAIRO_EXTEND_NONE && + (extents->x + tx < 0 || + extents->y + ty < 0 || + extents->x + tx + extents->width > src->intel.drm.width || + extents->y + ty + extents->height > src->intel.drm.height)) + { + return CAIRO_INT_STATUS_UNSUPPORTED; + } + + status = i915_surface_fallback_flush (src); + if (unlikely (status)) + return status; + + tx = _cairo_lround (pattern->matrix.x0); + ty = _cairo_lround (pattern->matrix.y0); + + device = i915_device (dst); + if (to_intel_bo (src->intel.drm.bo)->tiling == I915_TILING_Y) { + cairo_rectangle_int_t extents; + + _cairo_boxes_extents (boxes, &extents); + extents.x += tx; + extents.y += ty; + + status = i915_surface_extract_X_from_Y (device, src, &extents, &src); + if (unlikely (status)) + return status; + + free_me = &src->intel.drm.base; + tx = -extents.x; + ty = -extents.y; + } + + bo_array[0] = to_intel_bo (dst->intel.drm.bo); + bo_array[1] = to_intel_bo (src->intel.drm.bo); + + status = cairo_device_acquire (&device->intel.base.base); + if (unlikely (status)) + goto CLEANUP_SURFACE; + + if (! i915_check_aperture_and_fences (device, bo_array, 2) || + i915_batch_space (device) < 8 * boxes->num_boxes) + { + status = i915_batch_flush (device); + if (unlikely (status)) + goto CLEANUP_DEVICE; + } + + cmd = XY_SRC_COPY_BLT_CMD; + br13 = (0xCC << 16) | dst->intel.drm.stride; + switch (dst->intel.drm.format) { + default: + case CAIRO_FORMAT_INVALID: + case CAIRO_FORMAT_A1: + ASSERT_NOT_REACHED; + case CAIRO_FORMAT_A8: + break; + case CAIRO_FORMAT_RGB16_565: + br13 |= BR13_565; + break; + case CAIRO_FORMAT_RGB24: + case CAIRO_FORMAT_ARGB32: + br13 |= BR13_8888; + cmd |= XY_BLT_WRITE_ALPHA | XY_BLT_WRITE_RGB; + break; + } + + 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 x2 = _cairo_fixed_integer_round (box[i].p2.x); + int y1 = _cairo_fixed_integer_round (box[i].p1.y); + int y2 = _cairo_fixed_integer_round (box[i].p2.y); + + if (x1 + tx < 0) + x1 = -tx; + if (x2 + tx > src->intel.drm.width) + x2 = src->intel.drm.width - tx; + + if (y1 + ty < 0) + y1 = -ty; + if (y2 + ty > src->intel.drm.height) + y2 = src->intel.drm.height - ty; + + if (x2 <= x1 || y2 <= y1) + continue; + if (x2 < 0 || y2 < 0) + continue; + if (x1 >= dst->intel.drm.width || y2 >= dst->intel.drm.height) + continue; + + OUT_DWORD (cmd); + OUT_DWORD (br13); + OUT_DWORD ((y1 << 16) | x1); + OUT_DWORD ((y2 << 16) | x2); + OUT_RELOC_FENCED (dst, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER); + OUT_DWORD (((y1 + ty) << 16) | (x1 + tx)); + OUT_DWORD (src->intel.drm.stride); + OUT_RELOC_FENCED (src, I915_GEM_DOMAIN_RENDER, 0); + } + } + + /* XXX fixup blank portions */ + +CLEANUP_DEVICE: + cairo_device_release (&device->intel.base.base); +CLEANUP_SURFACE: + cairo_surface_destroy (free_me); + return status; +} + +static cairo_status_t +_upload_image_inplace (i915_surface_t *surface, + const cairo_pattern_t *source, + const cairo_rectangle_int_t *extents, + const cairo_boxes_t *boxes) +{ + i915_device_t *device; + const cairo_surface_pattern_t *pattern; + cairo_image_surface_t *image; + const struct _cairo_boxes_chunk *chunk; + intel_bo_t *bo; + int tx, ty, i; + + if (source->type != CAIRO_PATTERN_TYPE_SURFACE) + return CAIRO_INT_STATUS_UNSUPPORTED; + + pattern = (const cairo_surface_pattern_t *) source; + if (pattern->surface->type != CAIRO_SURFACE_TYPE_IMAGE) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if (! _cairo_matrix_is_integer_translation (&source->matrix, &tx, &ty)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + image = (cairo_image_surface_t *) pattern->surface; + if (source->extend != CAIRO_EXTEND_NONE && + (extents->x + tx < 0 || + extents->y + ty < 0 || + extents->x + tx + extents->width > image->width || + extents->y + ty + extents->height > image->height)) + { + return CAIRO_INT_STATUS_UNSUPPORTED; + } + + device = i915_device (surface); + bo = to_intel_bo (surface->intel.drm.bo); + if (bo->exec != NULL || ! intel_bo_is_inactive (&device->intel, bo)) { + intel_bo_t *new_bo; + cairo_bool_t need_clear = FALSE; + + if (boxes->num_boxes != 1 || + extents->width < surface->intel.drm.width || + extents->height < surface->intel.drm.height) + { + if (! surface->intel.drm.base.is_clear) + return CAIRO_INT_STATUS_UNSUPPORTED; + + need_clear = TRUE; + } + + new_bo = intel_bo_create (&device->intel, + bo->full_size, bo->base.size, + FALSE, bo->tiling, bo->stride); + if (unlikely (new_bo == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + intel_bo_in_flight_add (&device->intel, bo); + intel_bo_destroy (&device->intel, bo); + + bo = new_bo; + surface->intel.drm.bo = &bo->base; + + if (need_clear) { + memset (intel_bo_map (&device->intel, bo), 0, + bo->stride * surface->intel.drm.height); + } + } + + if (image->format == surface->intel.drm.format) { + 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 x2 = _cairo_fixed_integer_round (box[i].p2.x); + int y1 = _cairo_fixed_integer_round (box[i].p1.y); + int y2 = _cairo_fixed_integer_round (box[i].p2.y); + cairo_status_t status; + + if (x1 + tx < 0) + x1 = -tx; + if (x2 + tx > image->width) + x2 = image->width - tx; + + if (y1 + ty < 0) + y1 = -ty; + if (y2 + ty > image->height) + y2 = image->height - ty; + + if (x2 <= x1 || y2 <= y1) + continue; + if (x2 < 0 || y2 < 0) + continue; + if (x1 >= surface->intel.drm.width || y2 >= surface->intel.drm.height) + continue; + + status = intel_bo_put_image (&device->intel, + bo, + image, + x1 + tx, y1 + ty, + x2 - x1, y2 - y1, + x1, y1); + if (unlikely (status)) + return status; + } + } + } else { + pixman_image_t *dst; + void *ptr; + + ptr = intel_bo_map (&device->intel, bo); + if (unlikely (ptr == NULL)) + return _cairo_error (CAIRO_STATUS_DEVICE_ERROR); + + dst = pixman_image_create_bits (_cairo_format_to_pixman_format_code (surface->intel.drm.format), + surface->intel.drm.width, + surface->intel.drm.height, + ptr, + surface->intel.drm.stride); + if (unlikely (dst == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + 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 x2 = _cairo_fixed_integer_round (box[i].p2.x); + int y1 = _cairo_fixed_integer_round (box[i].p1.y); + int y2 = _cairo_fixed_integer_round (box[i].p2.y); + + if (x1 + tx < 0) + x1 = -tx; + if (x2 + tx > image->width) + x2 = image->width - tx; + + if (y1 + ty < 0) + y1 = -ty; + if (y2 + ty > image->height) + y2 = image->height - ty; + + if (x2 <= x1 || y2 <= y1) + continue; + if (x2 < 0 || y2 < 0) + continue; + if (x1 >= surface->intel.drm.width || y2 >= surface->intel.drm.height) + continue; + + pixman_image_composite32 (PIXMAN_OP_SRC, + image->pixman_image, NULL, dst, + x1 + tx, y1 + ty, + 0, 0, + x1, y1, + x2 - x1, y2 - y1); + } + } + + pixman_image_unref (dst); + } + + return CAIRO_STATUS_SUCCESS; +} + static cairo_status_t _composite_boxes (i915_surface_t *dst, cairo_operator_t op, @@ -883,6 +1577,7 @@ _composite_boxes (i915_surface_t *dst, cairo_boxes_t *boxes, cairo_antialias_t antialias, cairo_clip_t *clip, + double opacity, const cairo_composite_rectangles_t *extents) { cairo_bool_t need_clip_surface = FALSE; @@ -899,7 +1594,24 @@ _composite_boxes (i915_surface_t *dst, return CAIRO_INT_STATUS_UNSUPPORTED; } - i915_shader_init (&shader, dst, op); + if (clip == NULL && op == CAIRO_OPERATOR_SOURCE && opacity == 1.) { + if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) { + status = i915_blt_boxes (dst, pattern, &extents->bounded, boxes); + if (status == CAIRO_INT_STATUS_UNSUPPORTED) { + status = _upload_image_inplace (dst, pattern, + &extents->bounded, boxes); + } + if (status != CAIRO_INT_STATUS_UNSUPPORTED) + return status; + } + } + + if (i915_surface_needs_tiling (dst)) { + ASSERT_NOT_REACHED; + return CAIRO_INT_STATUS_UNSUPPORTED; + } + + i915_shader_init (&shader, dst, op, opacity); status = i915_shader_acquire_pattern (&shader, &shader.source, @@ -910,7 +1622,7 @@ _composite_boxes (i915_surface_t *dst, if (clip != NULL) { status = _cairo_clip_get_region (clip, &clip_region); - assert (status == CAIRO_STATUS_SUCCESS || CAIRO_INT_STATUS_UNSUPPORTED); + assert (status == CAIRO_STATUS_SUCCESS || status == CAIRO_INT_STATUS_UNSUPPORTED); need_clip_surface = status == CAIRO_INT_STATUS_UNSUPPORTED; if (need_clip_surface) i915_shader_set_clip (&shader, clip); @@ -949,6 +1661,113 @@ _composite_boxes (i915_surface_t *dst, return status; } +cairo_status_t +i915_surface_clear (i915_surface_t *dst) +{ + i915_device_t *device; + cairo_status_t status; + intel_bo_t *bo_array[1] = { to_intel_bo (dst->intel.drm.bo) }; + + device = i915_device (dst); + status = cairo_device_acquire (&device->intel.base.base); + if (unlikely (status)) + return status; + + if (i915_surface_needs_tiling (dst)) { + int cmd, br13, clear = 0; + + if (! i915_check_aperture_and_fences (device, bo_array, 1) || + i915_batch_space (device) < 6) + { + status = i915_batch_flush (device); + if (unlikely (status)) { + cairo_device_release (&device->intel.base.base); + return status; + } + } + + if (device->vertex_count) + i915_vbo_flush (device); + + cmd = XY_COLOR_BLT_CMD; + br13 = (0xCC << 16) | dst->intel.drm.stride; + switch (dst->intel.drm.format) { + default: + case CAIRO_FORMAT_INVALID: + case CAIRO_FORMAT_A1: + ASSERT_NOT_REACHED; + case CAIRO_FORMAT_A8: + break; + case CAIRO_FORMAT_RGB16_565: + br13 |= BR13_565; + break; + case CAIRO_FORMAT_RGB24: + clear = 0xff000000; + case CAIRO_FORMAT_ARGB32: + br13 |= BR13_8888; + cmd |= XY_BLT_WRITE_ALPHA | XY_BLT_WRITE_RGB; + break; + } + + OUT_DWORD (cmd); + OUT_DWORD (br13); + OUT_DWORD (0); + OUT_DWORD ((dst->intel.drm.height << 16) | + dst->intel.drm.width); + OUT_RELOC_FENCED (dst, + I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER); + OUT_DWORD (clear); + } else { + if (! i915_check_aperture (device, bo_array, 1) || + i915_batch_space (device) < 24) + { + status = i915_batch_flush (device); + if (unlikely (status)) { + cairo_device_release (&device->intel.base.base); + return status; + } + } + + if (device->vertex_count) + i915_vbo_flush (device); + + i915_set_dst (device, dst); + + /* set clear parameters */ + if (device->clear_alpha != (dst->intel.drm.base.content & CAIRO_CONTENT_ALPHA)) { + device->clear_alpha = dst->intel.drm.base.content & CAIRO_CONTENT_ALPHA; + OUT_DWORD (_3DSTATE_CLEAR_PARAMETERS); + OUT_DWORD (CLEARPARAM_CLEAR_RECT | CLEARPARAM_WRITE_COLOR); + /* ZONE_INIT color */ + if (device->clear_alpha) /* XXX depends on pixel format, 16bit needs replication, 8bit? */ + OUT_DWORD (0x00000000); + else + OUT_DWORD (0xff000000); + OUT_DWORD (0); /* ZONE_INIT depth */ + /* CLEAR_RECT color */ + if (device->clear_alpha) + OUT_DWORD (0x00000000); + else + OUT_DWORD (0xff000000); + OUT_DWORD (0); /* CLEAR_RECT depth */ + OUT_DWORD (0); /* CLEAR_RECT stencil */ + } + + OUT_DWORD (PRIM3D_CLEAR_RECT | 5); + OUT_DWORD (pack_float (dst->intel.drm.width)); + OUT_DWORD (pack_float (dst->intel.drm.height)); + OUT_DWORD (0); + OUT_DWORD (pack_float (dst->intel.drm.height)); + OUT_DWORD (0); + OUT_DWORD (0); + } + + cairo_device_release (&device->intel.base.base); + + dst->deferred_clear = FALSE; + return status; +} + static cairo_status_t _clip_and_composite_boxes (i915_surface_t *dst, cairo_operator_t op, @@ -956,7 +1775,8 @@ _clip_and_composite_boxes (i915_surface_t *dst, cairo_boxes_t *boxes, cairo_antialias_t antialias, const cairo_composite_rectangles_t *extents, - cairo_clip_t *clip) + cairo_clip_t *clip, + double opacity) { cairo_status_t status; @@ -967,8 +1787,30 @@ _clip_and_composite_boxes (i915_surface_t *dst, return i915_fixup_unbounded (dst, extents, clip); } + if (clip == NULL && + (op == CAIRO_OPERATOR_SOURCE || (op == CAIRO_OPERATOR_OVER && dst->intel.drm.base.is_clear)) && + opacity == 1. && + boxes->num_boxes == 1 && + extents->bounded.width == dst->intel.drm.width && + extents->bounded.height == dst->intel.drm.height) + { + op = CAIRO_OPERATOR_SOURCE; + dst->deferred_clear = FALSE; + + status = _upload_image_inplace (dst, src, + &extents->bounded, boxes); + if (status != CAIRO_INT_STATUS_UNSUPPORTED) + return status; + } + + if (dst->deferred_clear) { + status = i915_surface_clear (dst); + if (unlikely (status)) + return status; + } + /* Use a fast path if the boxes are pixel aligned */ - status = _composite_boxes (dst, op, src, boxes, antialias, clip, extents); + status = _composite_boxes (dst, op, src, boxes, antialias, clip, opacity, extents); if (status != CAIRO_INT_STATUS_UNSUPPORTED) return status; @@ -977,7 +1819,7 @@ _clip_and_composite_boxes (i915_surface_t *dst, */ return i915_clip_and_composite_spans (dst, op, src, antialias, _composite_boxes_spans, boxes, - extents, clip); + extents, clip, opacity); } static cairo_clip_path_t * @@ -999,11 +1841,162 @@ _clip_get_solitary_path (cairo_clip_t *clip) return path; } +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_paint (void *abstract_dst, - cairo_operator_t op, - const cairo_pattern_t *source, - cairo_clip_t *clip) +i915_surface_fill_with_alpha (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, + double opacity) +{ + 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 (extents.is_bounded && clip != NULL) { + cairo_clip_path_t *clip_path; + + if (((clip_path = _clip_get_solitary_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 = _cairo_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, + opacity); + } + + _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, opacity); + +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_paint_with_alpha (void *abstract_dst, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_clip_t *clip, + double opacity) { i915_surface_t *dst = abstract_dst; cairo_composite_rectangles_t extents; @@ -1015,8 +2008,6 @@ i915_surface_paint (void *abstract_dst, 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, @@ -1050,19 +2041,19 @@ i915_surface_paint (void *abstract_dst, 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); + status = i915_surface_fill_with_alpha (dst, op, source, + &clip_path->path, + clip_path->fill_rule, + clip_path->tolerance, + clip_path->antialias, + NULL, opacity); } 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); + &extents, clip, opacity); } if (clip_boxes != boxes.boxes_embedded) free (clip_boxes); @@ -1074,6 +2065,24 @@ i915_surface_paint (void *abstract_dst, } 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; + + /* XXX unsupported operators? use pixel shader blending, eventually */ + + if (op == CAIRO_OPERATOR_CLEAR && clip == NULL) { + dst->deferred_clear = TRUE; + return CAIRO_STATUS_SUCCESS; + } + + return i915_surface_paint_with_alpha (dst, op, source, clip, 1.); +} + +static cairo_int_status_t i915_surface_mask (void *abstract_dst, cairo_operator_t op, const cairo_pattern_t *source, @@ -1090,6 +2099,11 @@ i915_surface_mask (void *abstract_dst, cairo_bool_t have_clip = FALSE; cairo_status_t status; + if (mask->type == CAIRO_PATTERN_TYPE_SOLID) { + const cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) mask; + return i915_surface_paint_with_alpha (dst, op, source, clip, solid->color.alpha); + } + status = _cairo_composite_rectangles_init_for_mask (&extents, dst->intel.drm.width, dst->intel.drm.height, @@ -1111,7 +2125,7 @@ i915_surface_mask (void *abstract_dst, have_clip = TRUE; } - i915_shader_init (&shader, dst, op); + i915_shader_init (&shader, dst, op, 1.); status = i915_shader_acquire_pattern (&shader, &shader.source, @@ -1129,10 +2143,38 @@ i915_surface_mask (void *abstract_dst, if (clip != NULL) { status = _cairo_clip_get_region (clip, &clip_region); - assert (status == CAIRO_STATUS_SUCCESS || CAIRO_INT_STATUS_UNSUPPORTED); + if (unlikely (_cairo_status_is_error (status) || + status == CAIRO_INT_STATUS_NOTHING_TO_DO)) + { + goto err_shader; + } + need_clip_surface = status == CAIRO_INT_STATUS_UNSUPPORTED; if (need_clip_surface) i915_shader_set_clip (&shader, clip); + + if (clip_region != NULL) { + cairo_rectangle_int_t rect; + cairo_bool_t is_empty; + + status = CAIRO_STATUS_SUCCESS; + cairo_region_get_extents (clip_region, &rect); + is_empty = ! _cairo_rectangle_intersect (&extents.unbounded, &rect); + if (unlikely (is_empty)) + goto err_shader; + + is_empty = ! _cairo_rectangle_intersect (&extents.bounded, &rect); + if (unlikely (is_empty && extents.is_bounded)) + goto err_shader; + + if (cairo_region_num_rectangles (clip_region) == 1) + clip_region = NULL; + } + } + + if (i915_surface_needs_tiling (dst)) { + ASSERT_NOT_REACHED; + return CAIRO_INT_STATUS_UNSUPPORTED; } device = i915_device (dst); @@ -1140,6 +2182,12 @@ i915_surface_mask (void *abstract_dst, if (unlikely (status)) goto err_shader; + if (dst->deferred_clear) { + status = i915_surface_clear (dst); + if (unlikely (status)) + goto err_shader; + } + status = i915_shader_commit (&shader, device); if (unlikely (status)) goto err_device; @@ -1177,38 +2225,6 @@ i915_surface_mask (void *abstract_dst, 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, @@ -1267,7 +2283,7 @@ i915_surface_stroke (void *abstract_dst, if (likely (status == CAIRO_STATUS_SUCCESS)) { status = _clip_and_composite_boxes (dst, op, source, &boxes, antialias, - &extents, clip); + &extents, clip, 1.); } _cairo_boxes_fini (&boxes); @@ -1297,7 +2313,7 @@ i915_surface_stroke (void *abstract_dst, if (info.polygon.num_edges == 0) { if (! extents.is_bounded) - status = i915_fixup_unbounded (dst, &extents, clip); + status = i915_fixup_unbounded (dst, &extents, clip); goto CLEANUP_POLYGON; } @@ -1306,7 +2322,7 @@ i915_surface_stroke (void *abstract_dst, info.antialias = antialias; status = i915_clip_and_composite_spans (dst, op, source, antialias, _composite_polygon_spans, &info, - &extents, clip); + &extents, clip, 1.); CLEANUP_POLYGON: _cairo_polygon_fini (&info.polygon); @@ -1331,116 +2347,13 @@ i915_surface_fill (void *abstract_dst, 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 (extents.is_bounded && clip != NULL) { - cairo_clip_path_t *clip_path; - - if (((clip_path = _clip_get_solitary_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 = _cairo_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; + return i915_surface_fill_with_alpha (abstract_dst, op, source, path, fill_rule, tolerance, antialias, clip, 1.); } static const cairo_surface_backend_t i915_surface_backend = { CAIRO_SURFACE_TYPE_DRM, - _cairo_drm_surface_create_similar, + i915_surface_create_similar, i915_surface_finish, intel_surface_acquire_source_image, intel_surface_release_source_image, @@ -1472,32 +2385,42 @@ static const cairo_surface_backend_t i915_surface_backend = { static void i915_surface_init (i915_surface_t *surface, - cairo_content_t content, - cairo_drm_device_t *device) + cairo_drm_device_t *device, + cairo_format_t format, + int width, int height) { - intel_surface_init (&surface->intel, &i915_surface_backend, device, content); + intel_surface_init (&surface->intel, &i915_surface_backend, device, + format, width, height); - switch (content) { + switch (format) { default: + case CAIRO_FORMAT_INVALID: + case CAIRO_FORMAT_A1: ASSERT_NOT_REACHED; - case CAIRO_CONTENT_COLOR_ALPHA: + case CAIRO_FORMAT_ARGB32: surface->map0 = MAPSURF_32BIT | MT_32BIT_ARGB8888; surface->colorbuf = COLR_BUF_ARGB8888 | DEPTH_FRMT_24_FIXED_8_OTHER; break; - case CAIRO_CONTENT_COLOR: + case CAIRO_FORMAT_RGB24: surface->map0 = MAPSURF_32BIT | MT_32BIT_XRGB8888; surface->colorbuf = COLR_BUF_ARGB8888 | DEPTH_FRMT_24_FIXED_8_OTHER; break; - case CAIRO_CONTENT_ALPHA: + case CAIRO_FORMAT_RGB16_565: + surface->map0 = MAPSURF_16BIT | MT_16BIT_RGB565; + surface->colorbuf = COLR_BUF_RGB565; + break; + case CAIRO_FORMAT_A8: 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->map0 |= ((height - 1) << MS3_HEIGHT_SHIFT) | + ((width - 1) << MS3_WIDTH_SHIFT); surface->map1 = 0; surface->is_current_texture = 0; + surface->deferred_clear = FALSE; surface->offset = 0; @@ -1507,7 +2430,7 @@ i915_surface_init (i915_surface_t *surface, cairo_surface_t * i915_surface_create_internal (cairo_drm_device_t *base_dev, - cairo_content_t content, + cairo_format_t format, int width, int height, uint32_t tiling, cairo_bool_t gpu_target) @@ -1519,48 +2442,58 @@ i915_surface_create_internal (cairo_drm_device_t *base_dev, if (unlikely (surface == NULL)) return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); - i915_surface_init (surface, content, base_dev); + i915_surface_init (surface, base_dev, format, width, height); 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); + uint32_t size, stride; + intel_bo_t *bo; width = (width + 3) & -4; - surface->intel.drm.stride = cairo_format_stride_for_width (surface->intel.drm.format, - width); + 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) + if (height * stride <= 4096) + tiling = I915_TILING_NONE; + if (tiling != I915_TILING_NONE && stride <= 512) + tiling = I915_TILING_NONE; + if (tiling != I915_TILING_NONE) { + if (height <= 8) + tiling = I915_TILING_NONE; + else if (height <= 16) + tiling = I915_TILING_X; + } + /* large surfaces we need to blt, so force TILING_X */ + if (height > 2048) + tiling = I915_TILING_X; + /* but there is a maximum limit to the tiling pitch */ + if (tiling != I915_TILING_NONE && stride > 8192) 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)); + stride = i915_tiling_stride (tiling, stride); + assert (stride >= (uint32_t) cairo_format_stride_for_width (surface->intel.drm.format, width)); + assert (tiling == I915_TILING_NONE || stride <= 8192); height = i915_tiling_height (tiling, height); - assert (height <= 2048); - - size = i915_tiling_size (tiling, surface->intel.drm.stride * height); + if (height > 64*1024) { + free (surface); + cairo_device_destroy (&base_dev->base); + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE)); + } - surface->intel.drm.bo = &intel_bo_create (to_intel_device (&base_dev->base), - size, gpu_target)->base; - if (surface->intel.drm.bo == NULL) { + size = stride * height; + bo = intel_bo_create (to_intel_device (&base_dev->base), + i915_tiling_size (tiling, size), size, + gpu_target, tiling, stride); + if (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)); } + assert (bo->base.size >= size); - 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->intel.drm.bo = &bo->base; + surface->intel.drm.stride = stride; - surface->map0 |= MS3_tiling (to_intel_bo (surface->intel.drm.bo)->tiling); - surface->map1 = (surface->intel.drm.stride/4 - 1) << MS4_PITCH_SHIFT; + surface->map0 |= MS3_tiling (tiling); + surface->map1 = (stride/4 - 1) << MS4_PITCH_SHIFT; } return &surface->intel.drm.base; @@ -1568,21 +2501,32 @@ i915_surface_create_internal (cairo_drm_device_t *base_dev, static cairo_surface_t * i915_surface_create (cairo_drm_device_t *base_dev, - cairo_content_t content, - int width, int height) + cairo_format_t format, + int width, int height) { - return i915_surface_create_internal (base_dev, content, width, height, + switch (format) { + case CAIRO_FORMAT_ARGB32: + case CAIRO_FORMAT_RGB16_565: + case CAIRO_FORMAT_RGB24: + case CAIRO_FORMAT_A8: + break; + case CAIRO_FORMAT_INVALID: + default: + case CAIRO_FORMAT_A1: + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT)); + } + + return i915_surface_create_internal (base_dev, format, 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) + 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 */ @@ -1598,14 +2542,9 @@ i915_surface_create_for_name (cairo_drm_device_t *base_dev, 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_RGB16_565: case CAIRO_FORMAT_RGB24: - content = CAIRO_CONTENT_COLOR; - break; case CAIRO_FORMAT_A8: - content = CAIRO_CONTENT_ALPHA; break; } @@ -1613,15 +2552,10 @@ i915_surface_create_for_name (cairo_drm_device_t *base_dev, if (unlikely (surface == NULL)) return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); - i915_surface_init (surface, content, base_dev); + i915_surface_init (surface, base_dev, format, width, height); 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 = @@ -1645,7 +2579,8 @@ i915_buffer_cache_init (intel_buffer_cache_t *cache, cairo_format_t format, int width, int height) { - const uint32_t tiling = I915_TILING_Y; + const uint32_t tiling = I915_TILING_DEFAULT; + uint32_t stride, size; assert ((width & 3) == 0); assert ((height & 1) == 0); @@ -1660,29 +2595,29 @@ i915_buffer_cache_init (intel_buffer_cache_t *cache, ASSERT_NOT_REACHED; case CAIRO_FORMAT_ARGB32: cache->buffer.map0 = MAPSURF_32BIT | MT_32BIT_ARGB8888; - cache->buffer.stride = width * 4; + stride = width * 4; break; case CAIRO_FORMAT_A8: cache->buffer.map0 = MAPSURF_8BIT | MT_8BIT_I8; - cache->buffer.stride = width; + 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 ((stride & 7) == 0); + assert (i915_tiling_stride (tiling, stride) == stride); assert (i915_tiling_height (tiling, height) == height); - cache->buffer.bo = intel_bo_create (&device->intel, - height * cache->buffer.stride, - FALSE); + size = height * stride; + assert (i915_tiling_size (tiling, size) == size); + cache->buffer.bo = intel_bo_create (&device->intel, size, size, FALSE, tiling, stride); 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->buffer.stride = cache->buffer.bo->stride; + + cache->buffer.map0 |= ((height - 1) << MS3_HEIGHT_SHIFT) | + ((width - 1) << MS3_WIDTH_SHIFT); + cache->buffer.map0 |= MS3_tiling (tiling); + cache->buffer.map1 = ((stride / 4) - 1) << MS4_PITCH_SHIFT; cache->ref_count = 0; cairo_list_init (&cache->link); @@ -1702,12 +2637,16 @@ i915_surface_create_from_cacheable_image_internal (i915_device_t *device, cairo_format_t format; int width, height, bpp; + format = image->format; + if (format == CAIRO_FORMAT_A1) + format = CAIRO_FORMAT_A8; + 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, + format, width, height, I915_TILING_NONE, FALSE); if (unlikely (surface->intel.drm.base.status)) @@ -1715,7 +2654,6 @@ i915_surface_create_from_cacheable_image_internal (i915_device_t *device, status = intel_bo_put_image (&device->intel, to_intel_bo (surface->intel.drm.bo), - surface->intel.drm.stride, image, 0, 0, width, height, @@ -1795,7 +2733,7 @@ i915_surface_create_from_cacheable_image_internal (i915_device_t *device, ((i915_image_private_t *) node)->container = cache; status = intel_bo_put_image (&device->intel, - cache->buffer.bo, cache->buffer.stride, + cache->buffer.bo, image, 0, 0, width, height, @@ -1809,15 +2747,12 @@ i915_surface_create_from_cacheable_image_internal (i915_device_t *device, goto CLEANUP_CACHE; } - i915_surface_init (surface, image->base.content, &device->intel.base); + i915_surface_init (surface, &device->intel.base, + format, width, height); - 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->map0 |= MS3_tiling (cache->buffer.bo->tiling); surface->map1 = (surface->intel.drm.stride/4 - 1) << MS4_PITCH_SHIFT; surface->intel.drm.bo = &intel_bo_reference (cache->buffer.bo)->base; @@ -1879,16 +2814,11 @@ i915_surface_enable_scan_out (void *abstract_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); - } + 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; } @@ -1967,12 +2897,20 @@ _cairo_drm_i915_device_create (int fd, dev_t dev_id, int vendor_id, int chip_id) device->debug = 0; if (getenv ("CAIRO_DEBUG_DRM") != NULL) - device->debug = I915_DEBUG_BATCH; + device->debug = I915_DEBUG_SYNC; - device->batch.gtt_size = I915_BATCH_SIZE; + n = intel_get (fd, I915_PARAM_NUM_FENCES_AVAIL); + if (n == 0) + n = 8; + device->batch.fences_avail = n - 2; /* conservative */ + + device->batch.gtt_avail_size = device->intel.gtt_avail_size / 4; + device->batch.est_gtt_size = I915_BATCH_SIZE; + device->batch.total_gtt_size = I915_BATCH_SIZE; device->batch.exec_count = 0; device->batch.reloc_count = 0; device->batch.used = 0; + device->batch.fences = 0; memcpy (device->batch_header, i915_batch_setup, sizeof (i915_batch_setup)); device->vbo = 0; @@ -1982,13 +2920,6 @@ _cairo_drm_i915_device_create (int fd, dev_t dev_id, int vendor_id, int chip_id) 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]); @@ -2004,9 +2935,14 @@ _cairo_drm_i915_device_create (int fd, dev_t dev_id, int vendor_id, int chip_id) device->intel.base.device.throttle = i915_device_throttle; device->intel.base.device.destroy = i915_device_destroy; + device->floats_per_vertex = 0; + device->current_source = NULL; + device->current_mask = NULL; + device->current_clip = NULL; + i915_device_reset (device); return _cairo_drm_device_init (&device->intel.base, fd, dev_id, vendor_id, chip_id, - 2048); + 16*1024); } diff --git a/src/drm/cairo-drm-i965-glyphs.c b/src/drm/cairo-drm-i965-glyphs.c index 01c4e39e..e1ec95d7 100644 --- a/src/drm/cairo-drm-i965-glyphs.c +++ b/src/drm/cairo-drm-i965-glyphs.c @@ -71,8 +71,6 @@ i965_glyphs_accumulate_rectangle (i965_glyphs_t *glyphs) 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! */ @@ -83,7 +81,8 @@ i965_glyphs_accumulate_rectangle (i965_glyphs_t *glyphs) vbo->next = NULL; vbo->bo = intel_bo_create (&glyphs->shader.device->intel, - I965_VERTEX_SIZE, FALSE); + I965_VERTEX_SIZE, I965_VERTEX_SIZE, + FALSE, I915_TILING_NONE, 0); vbo->count = 0; glyphs->vbo_offset = 0; @@ -152,8 +151,8 @@ i965_surface_mask_internal (i965_surface_t *dst, 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); + -extents->bounded.x, + -extents->bounded.y); cairo_matrix_scale (&shader.mask.base.matrix, 1. / mask->intel.drm.width, 1. / mask->intel.drm.height); @@ -266,15 +265,15 @@ i965_surface_glyphs (void *abstract_surface, } if (overlap || ! extents.is_bounded) { - cairo_content_t content; + cairo_format_t format; - content = CAIRO_CONTENT_ALPHA; + format = CAIRO_FORMAT_A8; if (scaled_font->options.antialias == CAIRO_ANTIALIAS_SUBPIXEL) - content |= CAIRO_CONTENT_COLOR; + format = CAIRO_FORMAT_ARGB32; mask = (i965_surface_t *) i965_surface_create_internal (&i965_device (surface)->intel.base, - content, + format, extents.bounded.width, extents.bounded.height, I965_TILING_DEFAULT, @@ -331,7 +330,8 @@ i965_surface_glyphs (void *abstract_surface, } else { glyphs.get_rectangle = i965_glyphs_accumulate_rectangle; glyphs.head.bo = intel_bo_create (&device->intel, - I965_VERTEX_SIZE, FALSE); + I965_VERTEX_SIZE, I965_VERTEX_SIZE, + FALSE, I915_TILING_NONE, 0); if (unlikely (glyphs.head.bo == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); @@ -431,16 +431,19 @@ i965_surface_glyphs (void *abstract_surface, last_bo = cache->buffer.bo; } - x1 += mask_x; x2 += mask_x; - y1 += mask_y; y2 += mask_y; + x2 = x1 + glyph->width; + y2 = y1 + glyph->height; + + if (mask_x) + x1 += mask_x, x2 += mask_x; + if (mask_y) + 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); + if (mask != NULL && clip_region != NULL) i965_clipped_vertices (device, &glyphs.head, clip_region); - } status = CAIRO_STATUS_SUCCESS; FINISH: @@ -449,9 +452,6 @@ i965_surface_glyphs (void *abstract_surface, CLEANUP_GLYPHS: i965_shader_fini (&glyphs.shader); - if (glyphs.tail->bo && glyphs.tail->bo->virtual) - intel_bo_unmap (glyphs.tail->bo); - if (glyphs.head.bo != NULL) { struct i965_vbo *vbo, *next; diff --git a/src/drm/cairo-drm-i965-private.h b/src/drm/cairo-drm-i965-private.h index e13ea78b..79568a63 100644 --- a/src/drm/cairo-drm-i965-private.h +++ b/src/drm/cairo-drm-i965-private.h @@ -646,7 +646,7 @@ i965_shader_add_rectangle (const i965_shader_t *shader, cairo_private cairo_surface_t * i965_surface_create_internal (cairo_drm_device_t *base_dev, - cairo_content_t content, + cairo_format_t format, int width, int height, uint32_t tiling, cairo_bool_t gpu_target); diff --git a/src/drm/cairo-drm-i965-shader.c b/src/drm/cairo-drm-i965-shader.c index 377b478d..078fcdd7 100644 --- a/src/drm/cairo-drm-i965-shader.c +++ b/src/drm/cairo-drm-i965-shader.c @@ -271,7 +271,6 @@ i965_surface_clone (i965_device_t *device, 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, @@ -317,7 +316,6 @@ i965_surface_clone_subimage (i965_device_t *device, 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, @@ -668,8 +666,6 @@ i965_shader_acquire_surface (i965_shader_t *shader, 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); @@ -793,8 +789,7 @@ i965_shader_set_clip (i965_shader_t *shader, 1. / s->intel.drm.height); cairo_matrix_translate (&shader->clip.base.matrix, - NEAREST_BIAS - clip_x, - NEAREST_BIAS - clip_y); + -clip_x, -clip_y); } static cairo_bool_t @@ -888,9 +883,6 @@ i965_shader_setup_dst (i965_shader_t *shader) 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; @@ -2827,7 +2819,6 @@ i965_clipped_vertices (i965_device_t *device, 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++) { diff --git a/src/drm/cairo-drm-i965-spans.c b/src/drm/cairo-drm-i965-spans.c index 2c06b25c..5cba7cec 100644 --- a/src/drm/cairo-drm-i965-spans.c +++ b/src/drm/cairo-drm-i965-spans.c @@ -87,8 +87,6 @@ i965_spans_accumulate_rectangle (i965_spans_t *spans) 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! */ @@ -98,7 +96,9 @@ i965_spans_accumulate_rectangle (i965_spans_t *spans) spans->tail = vbo; vbo->next = NULL; - vbo->bo = intel_bo_create (&spans->device->intel, I965_VERTEX_SIZE, FALSE); + vbo->bo = intel_bo_create (&spans->device->intel, + I965_VERTEX_SIZE, I965_VERTEX_SIZE, + FALSE, I915_TILING_NONE, 0); vbo->count = 0; spans->vbo_offset = 0; @@ -326,7 +326,8 @@ i965_spans_init (i965_spans_t *spans, } else { spans->get_rectangle = i965_spans_accumulate_rectangle; spans->head.bo = intel_bo_create (&spans->device->intel, - I965_VERTEX_SIZE, FALSE); + I965_VERTEX_SIZE, I965_VERTEX_SIZE, + FALSE, I915_TILING_NONE, 0); if (unlikely (spans->head.bo == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); @@ -344,9 +345,6 @@ i965_spans_fini (i965_spans_t *spans) { i965_shader_fini (&spans->shader); - if (spans->tail->bo && spans->tail->bo->virtual) - intel_bo_unmap (spans->tail->bo); - if (spans->head.bo != NULL) { struct i965_vbo *vbo, *next; @@ -397,10 +395,8 @@ i965_clip_and_composite_spans (i965_surface_t *dst, 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); + if (spans.clip_region != NULL && status == CAIRO_STATUS_SUCCESS) i965_clipped_vertices (device, &spans.head, spans.clip_region); - } CLEANUP_DEVICE: cairo_device_release (dst->intel.drm.base.device); diff --git a/src/drm/cairo-drm-i965-surface.c b/src/drm/cairo-drm-i965-surface.c index 8164c53e..a944fb3c 100644 --- a/src/drm/cairo-drm-i965-surface.c +++ b/src/drm/cairo-drm-i965-surface.c @@ -168,7 +168,9 @@ i965_stream_commit (i965_device_t *device, assert (stream->used); - bo = intel_bo_create (&device->intel, stream->used, FALSE); + bo = intel_bo_create (&device->intel, + stream->used, stream->used, + FALSE, I915_TILING_NONE, 0); /* apply pending relocations */ for (n = 0; n < stream->num_pending_relocations; n++) { @@ -373,22 +375,25 @@ i965_exec (i965_device_t *device, uint32_t offset) /* XXX any write target within the batch should now be in error */ for (i = 0; i < device->exec.count; i++) { + intel_bo_t *bo = device->exec.bo[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; + bo->offset = device->exec.exec[i].offset; + bo->exec = NULL; + bo->batch_read_domains = 0; + bo->batch_write_domain = 0; - if (device->exec.bo[i]->purgeable) { - ret = intel_bo_madvise (&device->intel, - device->exec.bo[i], - I915_MADV_DONTNEED); + if (bo->virtual) + intel_bo_unmap (bo); + bo->cpu = FALSE; + + if (bo->purgeable) + ret = intel_bo_madvise (&device->intel, bo, 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_del (&bo->cache_list); + cairo_list_init (&bo->link); + intel_bo_destroy (&device->intel, bo); } cairo_list_init (&device->flush); @@ -496,7 +501,8 @@ i965_device_flush (i965_device_t *device) bo = intel_bo_create (&device->intel, device->general.used, - FALSE); + device->general.used, + FALSE, I915_TILING_NONE, 0); if (unlikely (bo == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); @@ -547,7 +553,9 @@ i965_device_flush (i965_device_t *device) if (aligned <= 8192) max = aligned; - bo = intel_bo_create (&device->intel, max, FALSE); + bo = intel_bo_create (&device->intel, + max, max, + FALSE, I915_TILING_NONE, 0); if (unlikely (bo == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); @@ -615,7 +623,9 @@ i965_device_flush (i965_device_t *device) if (device->surface.used) i965_stream_commit (device, &device->surface); - bo = intel_bo_create (&device->intel, device->batch.used, FALSE); + bo = intel_bo_create (&device->intel, + device->batch.used, device->batch.used, + FALSE, I915_TILING_NONE, 0); if (unlikely (bo == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); @@ -638,8 +648,6 @@ i965_device_flush (i965_device_t *device) aligned = 0; } - intel_glyph_cache_unmap (&device->intel); - status = i965_exec (device, aligned); i965_stream_reset (&device->vertex); @@ -654,6 +662,29 @@ i965_device_flush (i965_device_t *device) return status; } +static cairo_surface_t * +i965_surface_create_similar (void *abstract_other, + cairo_content_t content, + int width, int height) +{ + i965_surface_t *other; + cairo_format_t format; + + if (width > 8192 || height > 8192) + return NULL; + + other = abstract_other; + if (content == other->intel.drm.base.content) + format = other->intel.drm.format; + else + format = _cairo_format_from_content (content); + + return i965_surface_create_internal ((cairo_drm_device_t *) other->intel.drm.base.device, + format, + width, height, + I965_TILING_DEFAULT, TRUE); +} + static cairo_status_t i965_surface_finish (void *abstract_surface) { @@ -1462,7 +1493,7 @@ CLEANUP_BOXES: static const cairo_surface_backend_t i965_surface_backend = { CAIRO_SURFACE_TYPE_DRM, - _cairo_drm_surface_create_similar, + i965_surface_create_similar, i965_surface_finish, intel_surface_acquire_source_image, intel_surface_release_source_image, @@ -1494,10 +1525,12 @@ static const cairo_surface_backend_t i965_surface_backend = { static void i965_surface_init (i965_surface_t *surface, - cairo_content_t content, - cairo_drm_device_t *device) + cairo_drm_device_t *device, + cairo_format_t format, + int width, int height) { - intel_surface_init (&surface->intel, &i965_surface_backend, device, content); + intel_surface_init (&surface->intel, &i965_surface_backend, device, + format, width, height); surface->stream = 0; } @@ -1523,7 +1556,7 @@ i965_tiling_height (uint32_t tiling, int height) cairo_surface_t * i965_surface_create_internal (cairo_drm_device_t *base_dev, - cairo_content_t content, + cairo_format_t format, int width, int height, uint32_t tiling, cairo_bool_t gpu_target) @@ -1535,47 +1568,36 @@ i965_surface_create_internal (cairo_drm_device_t *base_dev, if (unlikely (surface == NULL)) return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); - i965_surface_init (surface, content, base_dev); + i965_surface_init (surface, base_dev, format, width, height); if (width && height) { - uint32_t size; - - surface->intel.drm.width = width; - surface->intel.drm.height = height; + uint32_t size, stride; + intel_bo_t *bo; 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); + stride = cairo_format_stride_for_width (surface->intel.drm.format, width); + stride = (stride + 63) & ~63; + stride = i965_tiling_stride (tiling, stride); + surface->intel.drm.stride = 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) { + size = stride * height; + bo = intel_bo_create (to_intel_device (&base_dev->base), + size, size, + gpu_target, tiling, stride); + if (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); + bo->tiling = tiling; + bo->stride = stride; + surface->intel.drm.bo = &bo->base; - assert (surface->intel.drm.bo->size >= (size_t) surface->intel.drm.stride*height); + assert (bo->base.size >= (size_t) stride*height); } return &surface->intel.drm.base; @@ -1583,9 +1605,21 @@ i965_surface_create_internal (cairo_drm_device_t *base_dev, static cairo_surface_t * i965_surface_create (cairo_drm_device_t *device, - cairo_content_t content, int width, int height) + cairo_format_t format, int width, int height) { - return i965_surface_create_internal (device, content, width, height, + switch (format) { + case CAIRO_FORMAT_ARGB32: + case CAIRO_FORMAT_RGB16_565: + case CAIRO_FORMAT_RGB24: + case CAIRO_FORMAT_A8: + break; + case CAIRO_FORMAT_INVALID: + default: + case CAIRO_FORMAT_A1: + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT)); + } + + return i965_surface_create_internal (device, format, width, height, I965_TILING_DEFAULT, TRUE); } @@ -1597,7 +1631,6 @@ i965_surface_create_for_name (cairo_drm_device_t *base_dev, { i965_device_t *device; i965_surface_t *surface; - cairo_content_t content; cairo_status_t status_ignored; int min_stride; @@ -1610,14 +1643,9 @@ i965_surface_create_for_name (cairo_drm_device_t *base_dev, switch (format) { case CAIRO_FORMAT_ARGB32: - content = CAIRO_CONTENT_COLOR_ALPHA; - break; case CAIRO_FORMAT_RGB16_565: case CAIRO_FORMAT_RGB24: - content = CAIRO_CONTENT_COLOR; - break; case CAIRO_FORMAT_A8: - content = CAIRO_CONTENT_ALPHA; break; case CAIRO_FORMAT_INVALID: default: @@ -1629,7 +1657,7 @@ i965_surface_create_for_name (cairo_drm_device_t *base_dev, if (unlikely (surface == NULL)) return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); - i965_surface_init (surface, content, base_dev); + i965_surface_init (surface, base_dev, format, width, height); device = (i965_device_t *) base_dev; surface->intel.drm.bo = &intel_bo_create_for_name (&device->intel, name)->base; @@ -1639,8 +1667,6 @@ i965_surface_create_for_name (cairo_drm_device_t *base_dev, 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; diff --git a/src/drm/cairo-drm-intel-debug.c b/src/drm/cairo-drm-intel-debug.c index cc2e47a1..7068c933 100644 --- a/src/drm/cairo-drm-intel-debug.c +++ b/src/drm/cairo-drm-intel-debug.c @@ -720,6 +720,7 @@ debug_copy_blit (struct debug_stream *stream, 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++]); diff --git a/src/drm/cairo-drm-intel-ioctl-private.h b/src/drm/cairo-drm-intel-ioctl-private.h index d3476940..29fe88ad 100644 --- a/src/drm/cairo-drm-intel-ioctl-private.h +++ b/src/drm/cairo-drm-intel-ioctl-private.h @@ -32,6 +32,22 @@ #include "cairo-drm-intel-command-private.h" +#define I915_PARAM_IRQ_ACTIVE 1 +#define I915_PARAM_ALLOW_BATCHBUFFER 2 +#define I915_PARAM_LAST_DISPATCH 3 +#define I915_PARAM_CHIPSET_ID 4 +#define I915_PARAM_HAS_GEM 5 +#define I915_PARAM_NUM_FENCES_AVAIL 6 +#define I915_PARAM_HAS_OVERLAY 7 +#define I915_PARAM_HAS_PAGEFLIPPING 8 +#define I915_PARAM_HAS_EXECBUF2 9 + +struct intel_getparam { + int param; + int *value; +}; + + /** @{ * Intel memory domains * @@ -331,7 +347,9 @@ struct drm_i915_gem_get_aperture { uint64_t aper_available_size; }; +#define DRM_I915_GETPARAM 0x06 +#define DRM_IOCTL_I915_GETPARAM DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GETPARAM, struct intel_getparam) #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) @@ -414,4 +432,11 @@ struct drm_i915_gem_execbuffer2 { #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) +struct drm_i915_gem_real_size { + uint32_t handle; + uint64_t size; +}; +#define DRM_I915_GEM_REAL_SIZE 0x2a +#define DRM_IOCTL_I915_GEM_REAL_SIZE DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_GEM_REAL_SIZE, struct drm_i915_gem_real_size) + #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 738beb9e..aaba13d1 100644 --- a/src/drm/cairo-drm-intel-private.h +++ b/src/drm/cairo-drm-intel-private.h @@ -42,11 +42,8 @@ #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 @@ -57,24 +54,28 @@ typedef struct _intel_bo { cairo_drm_bo_t base; + cairo_list_t link; cairo_list_t cache_list; uint32_t offset; - void *virtual; - - uint32_t tiling; - uint32_t swizzle; - uint32_t stride; - cairo_bool_t purgeable; + uint32_t batch_read_domains; + uint32_t batch_write_domain; uint32_t opaque0; uint32_t opaque1; - struct drm_i915_gem_exec_object2 *exec; - uint32_t batch_read_domains; - uint32_t batch_write_domain; + uint32_t full_size; + uint16_t stride; + uint16_t _stride; + uint32_t bucket :4; + uint32_t tiling :4; + uint32_t _tiling :4; + uint32_t purgeable :1; + uint32_t busy :1; + uint32_t cpu :1; - cairo_list_t link; + struct drm_i915_gem_exec_object2 *exec; + void *virtual; } intel_bo_t; #define INTEL_BATCH_SIZE (64*1024) @@ -82,11 +83,10 @@ typedef struct _intel_bo { #define INTEL_MAX_RELOCS 2048 static inline void -intel_bo_mark_purgeable (intel_bo_t *bo, - cairo_bool_t purgeable) +intel_bo_mark_purgeable (intel_bo_t *bo) { if (bo->base.name == 0) - bo->purgeable = purgeable; + bo->purgeable = 1; } typedef struct _intel_vertex_buffer intel_vertex_buffer_t; @@ -168,6 +168,7 @@ typedef struct _intel_glyph { intel_buffer_cache_t *cache; void **owner; float texcoord[3]; + int width, height; } intel_glyph_t; typedef struct _intel_gradient_cache { @@ -200,11 +201,11 @@ typedef struct _intel_device { size_t bo_cache_size; size_t bo_max_cache_size_high; size_t bo_max_cache_size_low; + cairo_list_t bo_in_flight; cairo_mutex_t mutex; intel_batch_t batch; - cairo_bool_t glyph_cache_mapped; intel_buffer_cache_t glyph_cache[2]; cairo_list_t fonts; @@ -242,13 +243,23 @@ intel_bo_reference (intel_bo_t *bo) cairo_private cairo_bool_t intel_bo_madvise (intel_device_t *device, intel_bo_t *bo, int madv); - static cairo_always_inline void intel_bo_destroy (intel_device_t *device, intel_bo_t *bo) { cairo_drm_bo_destroy (&device->base.base, &bo->base); } +static inline void +intel_bo_in_flight_add (intel_device_t *device, + intel_bo_t *bo) +{ + if (bo->base.name == 0 && bo->exec != NULL && cairo_list_is_empty (&bo->cache_list)) + cairo_list_add (&bo->cache_list, &device->bo_in_flight); +} + +cairo_private int +intel_get (int fd, int param); + cairo_private cairo_bool_t intel_info (int fd, uint64_t *gtt_size); @@ -260,23 +271,24 @@ intel_device_fini (intel_device_t *dev); cairo_private intel_bo_t * intel_bo_create (intel_device_t *dev, - uint32_t size, - cairo_bool_t gpu_target); + uint32_t max_size, + uint32_t real_size, + cairo_bool_t gpu_target, + uint32_t tiling, + uint32_t stride); cairo_private intel_bo_t * intel_bo_create_for_name (intel_device_t *dev, uint32_t name); cairo_private void intel_bo_set_tiling (const intel_device_t *dev, - intel_bo_t *bo, - uint32_t tiling, - uint32_t stride); + intel_bo_t *bo); cairo_private cairo_bool_t intel_bo_is_inactive (const intel_device_t *device, - const intel_bo_t *bo); + intel_bo_t *bo); -cairo_private void +cairo_private cairo_bool_t intel_bo_wait (const intel_device_t *device, const intel_bo_t *bo); cairo_private void @@ -318,7 +330,7 @@ intel_bo_get_image (const intel_device_t *device, cairo_private cairo_status_t intel_bo_put_image (intel_device_t *dev, - intel_bo_t *bo, int stride, + intel_bo_t *bo, cairo_image_surface_t *src, int src_x, int src_y, int width, int height, @@ -328,7 +340,8 @@ 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_format_t format, + int width, int height); cairo_private cairo_status_t intel_buffer_cache_init (intel_buffer_cache_t *cache, @@ -354,9 +367,6 @@ 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 * @@ -404,17 +414,6 @@ 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) { @@ -426,6 +425,17 @@ MS3_tiling (uint32_t tiling) } } +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; +} + #define PCI_CHIP_I810 0x7121 #define PCI_CHIP_I810_DC100 0x7123 #define PCI_CHIP_I810_E 0x7125 diff --git a/src/drm/cairo-drm-intel-surface.c b/src/drm/cairo-drm-intel-surface.c index 9b06c228..96d46159 100644 --- a/src/drm/cairo-drm-intel-surface.c +++ b/src/drm/cairo-drm-intel-surface.c @@ -53,9 +53,18 @@ intel_surface_finish (void *abstract_surface) { intel_surface_t *surface = abstract_surface; + intel_bo_in_flight_add (to_intel_device (surface->drm.base.device), + to_intel_bo (surface->drm.bo)); return _cairo_drm_surface_finish (&surface->drm); } +static void +surface_finish_and_destroy (cairo_surface_t *surface) +{ + cairo_surface_finish (surface); + cairo_surface_destroy (surface); +} + cairo_status_t intel_surface_acquire_source_image (void *abstract_surface, cairo_image_surface_t **image_out, @@ -64,8 +73,7 @@ intel_surface_acquire_source_image (void *abstract_surface, intel_surface_t *surface = abstract_surface; cairo_surface_t *image; cairo_status_t status; - - /* XXX batch flush */ + void *ptr; if (surface->drm.fallback != NULL) { image = surface->drm.fallback; @@ -83,14 +91,20 @@ intel_surface_acquire_source_image (void *abstract_surface, return status; } - 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; + ptr = intel_bo_map (to_intel_device (surface->drm.base.device), + to_intel_bo (surface->drm.bo)); + if (unlikely (ptr == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); - _cairo_surface_attach_snapshot (&surface->drm.base, image, cairo_surface_destroy); + image = cairo_image_surface_create_for_data (ptr, + surface->drm.format, + surface->drm.width, + surface->drm.height, + surface->drm.stride); + if (unlikely (image->status)) + return image->status; + + _cairo_surface_attach_snapshot (&surface->drm.base, image, surface_finish_and_destroy); DONE: *image_out = (cairo_image_surface_t *) cairo_surface_reference (image); @@ -132,10 +146,8 @@ intel_surface_map_to_image (void *abstract_surface) surface->drm.width, surface->drm.height, surface->drm.stride); - if (unlikely (image->status)) { - intel_bo_unmap (to_intel_bo (surface->drm.bo)); + if (unlikely (image->status)) return image; - } surface->drm.fallback = image; } @@ -159,8 +171,6 @@ intel_surface_flush (void *abstract_surface) cairo_surface_destroy (surface->drm.fallback); surface->drm.fallback = NULL; - intel_bo_unmap (to_intel_bo (surface->drm.bo)); - return status; } @@ -271,34 +281,21 @@ void intel_surface_init (intel_surface_t *surface, const cairo_surface_backend_t *backend, cairo_drm_device_t *device, - cairo_content_t content) + cairo_format_t format, + int width, int height) { _cairo_surface_init (&surface->drm.base, backend, &device->base, - content); - _cairo_drm_surface_init (&surface->drm, device); - - switch (content) { - case CAIRO_CONTENT_ALPHA: - surface->drm.format = CAIRO_FORMAT_A8; - break; - case CAIRO_CONTENT_COLOR: - surface->drm.format = CAIRO_FORMAT_RGB24; - break; - default: - ASSERT_NOT_REACHED; - case CAIRO_CONTENT_COLOR_ALPHA: - surface->drm.format = CAIRO_FORMAT_ARGB32; - break; - } + _cairo_content_from_format (format)); + _cairo_drm_surface_init (&surface->drm, format, width, height); surface->snapshot_cache_entry.hash = 0; } static cairo_surface_t * intel_surface_create (cairo_drm_device_t *device, - cairo_content_t content, + cairo_format_t format, int width, int height) { intel_surface_t *surface; @@ -308,12 +305,10 @@ intel_surface_create (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, &intel_surface_backend, device, content); + intel_surface_init (surface, &intel_surface_backend, device, + format, width, height); if (width && height) { - surface->drm.width = width; - surface->drm.height = height; - /* Vol I, p134: size restrictions for textures */ width = (width + 3) & -4; height = (height + 1) & -2; @@ -321,7 +316,8 @@ intel_surface_create (cairo_drm_device_t *device, 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; + surface->drm.stride * height, + TRUE, I915_TILING_NONE, surface->drm.stride)->base; if (surface->drm.bo == NULL) { status = _cairo_drm_surface_finish (&surface->drm); free (surface); @@ -339,7 +335,6 @@ intel_surface_create_for_name (cairo_drm_device_t *device, int width, int height, int stride) { intel_surface_t *surface; - cairo_content_t content; cairo_status_t status; switch (format) { @@ -348,14 +343,9 @@ intel_surface_create_for_name (cairo_drm_device_t *device, 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_RGB16_565: case CAIRO_FORMAT_RGB24: - content = CAIRO_CONTENT_COLOR; - break; case CAIRO_FORMAT_A8: - content = CAIRO_CONTENT_ALPHA; break; } @@ -366,11 +356,10 @@ 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, &intel_surface_backend, device, content); + intel_surface_init (surface, &intel_surface_backend, + device, format, width, height); if (width && height) { - 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), @@ -394,14 +383,7 @@ intel_surface_enable_scan_out (void *abstract_surface) if (unlikely (surface->drm.bo == NULL)) return _cairo_error (CAIRO_STATUS_INVALID_SIZE); - 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->drm.bo)->tiling == I915_TILING_Y)) - return _cairo_error (CAIRO_STATUS_INVALID_FORMAT); /* XXX */ + to_intel_bo (surface->drm.bo)->tiling = I915_TILING_X; return CAIRO_STATUS_SUCCESS; } diff --git a/src/drm/cairo-drm-intel.c b/src/drm/cairo-drm-intel.c index b5386cd0..4d69f8ab 100644 --- a/src/drm/cairo-drm-intel.c +++ b/src/drm/cairo-drm-intel.c @@ -49,16 +49,38 @@ #define IMAGE_CACHE_WIDTH 1024 #define IMAGE_CACHE_HEIGHT 1024 +int +intel_get (int fd, int param) +{ + struct intel_getparam gp; + int value; + + gp.param = param; + gp.value = &value; + if (ioctl (fd, DRM_IOCTL_I915_GETPARAM, &gp) < 0) + return 0; + + VG (VALGRIND_MAKE_MEM_DEFINED (&value, sizeof (value))); + + return value; +} + cairo_bool_t intel_info (int fd, uint64_t *gtt_size) { struct drm_i915_gem_get_aperture info; - int ret; - ret = ioctl (fd, DRM_IOCTL_I915_GEM_GET_APERTURE, &info); - if (ret == -1) + if (! intel_get (fd, I915_PARAM_HAS_GEM)) + return FALSE; + + if (! intel_get (fd, I915_PARAM_HAS_EXECBUF2)) + return FALSE; + + if (ioctl (fd, DRM_IOCTL_I915_GEM_GET_APERTURE, &info) < 0) return FALSE; + VG (VALGRIND_MAKE_MEM_DEFINED (&info, sizeof (info))); + if (gtt_size != NULL) *gtt_size = info.aper_size; @@ -75,6 +97,15 @@ intel_bo_write (const intel_device_t *device, struct drm_i915_gem_pwrite pwrite; int ret; + assert (bo->tiling == I915_TILING_NONE); + assert (size); + assert (offset < bo->base.size); + assert (size+offset <= bo->base.size); + + intel_bo_set_tiling (device, bo); + + assert (bo->_tiling == I915_TILING_NONE); + memset (&pwrite, 0, sizeof (pwrite)); pwrite.handle = bo->base.handle; pwrite.offset = offset; @@ -83,6 +114,9 @@ intel_bo_write (const intel_device_t *device, do { ret = ioctl (device->base.fd, DRM_IOCTL_I915_GEM_PWRITE, &pwrite); } while (ret == -1 && errno == EINTR); + assert (ret == 0); + + bo->busy = FALSE; } void @@ -95,6 +129,15 @@ intel_bo_read (const intel_device_t *device, struct drm_i915_gem_pread pread; int ret; + assert (bo->tiling == I915_TILING_NONE); + assert (size); + assert (offset < bo->base.size); + assert (size+offset <= bo->base.size); + + intel_bo_set_tiling (device, bo); + + assert (bo->_tiling == I915_TILING_NONE); + memset (&pread, 0, sizeof (pread)); pread.handle = bo->base.handle; pread.offset = offset; @@ -103,25 +146,48 @@ intel_bo_read (const intel_device_t *device, do { ret = ioctl (device->base.fd, DRM_IOCTL_I915_GEM_PREAD, &pread); } while (ret == -1 && errno == EINTR); + assert (ret == 0); + + bo->cpu = TRUE; + bo->busy = FALSE; } void * intel_bo_map (const intel_device_t *device, intel_bo_t *bo) { struct drm_i915_gem_set_domain set_domain; - int ret; uint32_t domain; + int ret; - assert (bo->virtual == NULL); + intel_bo_set_tiling (device, bo); - if (bo->tiling != I915_TILING_NONE) { - struct drm_i915_gem_mmap_gtt mmap_arg; - void *ptr; + if (bo->virtual != NULL) + return bo->virtual; + + if (bo->cpu && bo->tiling == I915_TILING_NONE) { + struct drm_i915_gem_mmap mmap_arg; mmap_arg.handle = bo->base.handle; mmap_arg.offset = 0; + mmap_arg.size = bo->base.size; + mmap_arg.addr_ptr = 0; + + do { + ret = ioctl (device->base.fd, DRM_IOCTL_I915_GEM_MMAP, &mmap_arg); + } while (ret == -1 && errno == EINTR); + if (unlikely (ret != 0)) { + _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); + return NULL; + } + + bo->virtual = (void *) (uintptr_t) mmap_arg.addr_ptr; + domain = I915_GEM_DOMAIN_CPU; + } else { + struct drm_i915_gem_mmap_gtt mmap_arg; + void *ptr; /* Get the fake offset back... */ + mmap_arg.handle = bo->base.handle; do { ret = ioctl (device->base.fd, DRM_IOCTL_I915_GEM_MMAP_GTT, &mmap_arg); @@ -141,27 +207,11 @@ intel_bo_map (const intel_device_t *device, intel_bo_t *bo) } bo->virtual = ptr; - } else { - struct drm_i915_gem_mmap mmap_arg; - - mmap_arg.handle = bo->base.handle; - mmap_arg.offset = 0; - mmap_arg.size = bo->base.size; - mmap_arg.addr_ptr = 0; - - do { - ret = ioctl (device->base.fd, DRM_IOCTL_I915_GEM_MMAP, &mmap_arg); - } while (ret == -1 && errno == EINTR); - if (unlikely (ret != 0)) { - _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); - return NULL; - } - - bo->virtual = (void *) (uintptr_t) mmap_arg.addr_ptr; + domain = I915_GEM_DOMAIN_GTT; } - domain = bo->tiling == I915_TILING_NONE ? - I915_GEM_DOMAIN_CPU : I915_GEM_DOMAIN_GTT; + VG (VALGRIND_MAKE_MEM_DEFINED (bo->virtual, bo->base.size)); + set_domain.handle = bo->base.handle; set_domain.read_domains = domain; set_domain.write_domain = domain; @@ -178,6 +228,7 @@ intel_bo_map (const intel_device_t *device, intel_bo_t *bo) return NULL; } + bo->busy = FALSE; return bo->virtual; } @@ -189,19 +240,23 @@ intel_bo_unmap (intel_bo_t *bo) } cairo_bool_t -intel_bo_is_inactive (const intel_device_t *device, const intel_bo_t *bo) +intel_bo_is_inactive (const intel_device_t *device, intel_bo_t *bo) { struct drm_i915_gem_busy busy; + if (! bo->busy) + return TRUE; + /* Is this buffer busy for our intended usage pattern? */ busy.handle = bo->base.handle; busy.busy = 1; ioctl (device->base.fd, DRM_IOCTL_I915_GEM_BUSY, &busy); + bo->busy = busy.busy; return ! busy.busy; } -void +cairo_bool_t intel_bo_wait (const intel_device_t *device, const intel_bo_t *bo) { struct drm_i915_gem_set_domain set_domain; @@ -214,6 +269,8 @@ intel_bo_wait (const intel_device_t *device, const intel_bo_t *bo) do { ret = ioctl (device->base.fd, DRM_IOCTL_I915_GEM_SET_DOMAIN, &set_domain); } while (ret == -1 && errno == EINTR); + + return ret == 0; } static inline int @@ -238,11 +295,8 @@ intel_bo_cache_remove (intel_device_t *device, cairo_list_del (&bo->cache_list); - if (device->bo_cache[bucket].num_entries-- > - device->bo_cache[bucket].min_entries) - { - device->bo_cache_size -= bo->base.size; - } + device->bo_cache[bucket].num_entries--; + device->bo_cache_size -= 4096 * (1 << bucket); _cairo_freepool_free (&device->bo_pool, bo); } @@ -262,6 +316,36 @@ intel_bo_madvise (intel_device_t *device, } static void +intel_bo_set_real_size (intel_device_t *device, + intel_bo_t *bo, + size_t size) +{ + struct drm_i915_gem_real_size arg; + int ret; + + return; + + if (size == bo->base.size) + return; + + arg.handle = bo->base.handle; + arg.size = size; + do { + ret = ioctl (device->base.fd, DRM_IOCTL_I915_GEM_REAL_SIZE, &arg); + } while (ret == -1 && errno == EINTR); + + if (ret == 0) { + if (size > bo->base.size) { + assert (bo->exec == NULL); + bo->cpu = TRUE; + bo->busy = FALSE; + } + + bo->base.size = size; + } +} + +static void intel_bo_cache_purge (intel_device_t *device) { int bucket; @@ -282,89 +366,131 @@ intel_bo_cache_purge (intel_device_t *device) intel_bo_t * intel_bo_create (intel_device_t *device, - uint32_t size, - cairo_bool_t gpu_target) + uint32_t max_size, + uint32_t real_size, + cairo_bool_t gpu_target, + uint32_t tiling, + uint32_t stride) { - intel_bo_t *bo = NULL; + intel_bo_t *bo; uint32_t cache_size; struct drm_i915_gem_create create; int bucket; int ret; - cache_size = pot ((size + 4095) & -4096); + max_size = (max_size + 4095) & -4096; + real_size = (real_size + 4095) & -4096; + cache_size = pot (max_size); bucket = ffs (cache_size / 4096) - 1; + if (bucket >= INTEL_BO_CACHE_BUCKETS) + cache_size = max_size; + + if (gpu_target) { + intel_bo_t *first = NULL; + + cairo_list_foreach_entry (bo, intel_bo_t, + &device->bo_in_flight, + cache_list) + { + assert (bo->exec != NULL); + if (tiling && bo->_tiling && + (bo->_tiling != tiling || bo->_stride != stride)) + { + continue; + } + + if (real_size <= bo->base.size) { + if (real_size >= bo->base.size/2) { + cairo_list_del (&bo->cache_list); + bo = intel_bo_reference (bo); + goto DONE; + } + + if (first == NULL) + first = bo; + } + } + + if (first != NULL) { + cairo_list_del (&first->cache_list); + bo = intel_bo_reference (first); + goto DONE; + } + } + + bo = NULL; + CAIRO_MUTEX_LOCK (device->bo_mutex); if (bucket < INTEL_BO_CACHE_BUCKETS) { - size = cache_size; - + int loop = MIN (3, INTEL_BO_CACHE_BUCKETS - bucket); /* Our goal is to avoid clflush which occur on CPU->GPU * transitions, so we want to minimise reusing CPU * write buffers. However, by the time a buffer is freed * it is most likely in the GPU domain anyway (readback is rare!). */ - retry: - if (gpu_target) { - do { - cairo_list_foreach_entry_reverse (bo, - intel_bo_t, - &device->bo_cache[bucket].list, - cache_list) + do { + if (gpu_target) { + intel_bo_t *next; + + cairo_list_foreach_entry_reverse_safe (bo, next, + intel_bo_t, + &device->bo_cache[bucket].list, + cache_list) { + if (real_size > bo->base.size) + continue; + /* For a gpu target, by the time our batch fires, the * GPU will have finished using this buffer. However, * changing tiling may require a fence deallocation and * cause serialisation... */ - if (device->bo_cache[bucket].num_entries-- > - device->bo_cache[bucket].min_entries) + if (tiling && bo->_tiling && + (bo->_tiling != tiling || bo->_stride != stride)) { - device->bo_cache_size -= bo->base.size; + continue; } + + device->bo_cache[bucket].num_entries--; + device->bo_cache_size -= 4096 * (1 << bucket); cairo_list_del (&bo->cache_list); 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; + } else + goto INIT; } + } - /* As it is unlikely to trigger clflush, we can use the - * first available buffer into which we fit. - */ - } while (++bucket < INTEL_BO_CACHE_BUCKETS); - } else { - if (! cairo_list_is_empty (&device->bo_cache[bucket].list)) { + while (! cairo_list_is_empty (&device->bo_cache[bucket].list)) { bo = cairo_list_first_entry (&device->bo_cache[bucket].list, intel_bo_t, cache_list); if (intel_bo_is_inactive (device, bo)) { - if (device->bo_cache[bucket].num_entries-- > - device->bo_cache[bucket].min_entries) - { - device->bo_cache_size -= bo->base.size; - } + device->bo_cache[bucket].num_entries--; + device->bo_cache_size -= 4096 * (1 << bucket); cairo_list_del (&bo->cache_list); 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; - } + } else + goto SIZE; + } else + break; } - } + } while (--loop && ++bucket); } if (device->bo_cache_size > device->bo_max_cache_size_high) { + cairo_bool_t not_empty; + intel_bo_cache_purge (device); /* trim caches by discarding the most recent buffer in each bucket */ - while (device->bo_cache_size > device->bo_max_cache_size_low) { + do { + not_empty = FALSE; for (bucket = INTEL_BO_CACHE_BUCKETS; bucket--; ) { if (device->bo_cache[bucket].num_entries > device->bo_cache[bucket].min_entries) @@ -373,30 +499,36 @@ intel_bo_create (intel_device_t *device, intel_bo_t, cache_list); intel_bo_cache_remove (device, bo, bucket); + not_empty = TRUE; } } - } + } while (not_empty && device->bo_cache_size > device->bo_max_cache_size_low); } /* no cached buffer available, allocate fresh */ bo = _cairo_freepool_alloc (&device->bo_pool); if (unlikely (bo == NULL)) { _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); - goto UNLOCK; + CAIRO_MUTEX_UNLOCK (device->bo_mutex); + return bo; } cairo_list_init (&bo->cache_list); bo->base.name = 0; - bo->base.size = size; bo->offset = 0; bo->virtual = NULL; + bo->cpu = TRUE; - bo->tiling = I915_TILING_NONE; - bo->stride = 0; - bo->swizzle = I915_BIT_6_SWIZZLE_NONE; + bucket = ffs (cache_size / 4096) - 1; + if (bucket > INTEL_BO_CACHE_BUCKETS) + bucket = INTEL_BO_CACHE_BUCKETS; + bo->bucket = bucket; + bo->_tiling = I915_TILING_NONE; + bo->_stride = 0; bo->purgeable = 0; + bo->busy = FALSE; bo->opaque0 = 0; bo->opaque1 = 0; @@ -406,23 +538,27 @@ intel_bo_create (intel_device_t *device, bo->batch_write_domain = 0; cairo_list_init (&bo->link); - create.size = size; + create.size = cache_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); _cairo_freepool_free (&device->bo_pool, bo); - bo = NULL; - goto UNLOCK; + CAIRO_MUTEX_UNLOCK (device->bo_mutex); + return NULL; } bo->base.handle = create.handle; + bo->full_size = bo->base.size = create.size; -DONE: +SIZE: + intel_bo_set_real_size (device, bo, real_size); +INIT: CAIRO_REFERENCE_COUNT_INIT (&bo->base.ref_count, 1); -UNLOCK: CAIRO_MUTEX_UNLOCK (device->bo_mutex); - +DONE: + bo->tiling = tiling; + bo->stride = stride; return bo; } @@ -449,9 +585,13 @@ intel_bo_create_for_name (intel_device_t *device, uint32_t name) CAIRO_REFERENCE_COUNT_INIT (&bo->base.ref_count, 1); cairo_list_init (&bo->cache_list); + bo->full_size = bo->base.size; bo->offset = 0; bo->virtual = NULL; bo->purgeable = 0; + bo->busy = TRUE; + bo->cpu = FALSE; + bo->bucket = INTEL_BO_CACHE_BUCKETS; bo->opaque0 = 0; bo->opaque1 = 0; @@ -471,8 +611,7 @@ intel_bo_create_for_name (intel_device_t *device, uint32_t name) goto FAIL; } - bo->tiling = get_tiling.tiling_mode; - bo->swizzle = get_tiling.swizzle_mode; + bo->_tiling = bo->tiling = get_tiling.tiling_mode; // bo->stride = get_tiling.stride; /* XXX not available from get_tiling */ return bo; @@ -491,24 +630,26 @@ intel_bo_release (void *_dev, void *_bo) intel_bo_t *bo = _bo; int bucket; - assert (bo->virtual == NULL); + if (bo->virtual != NULL) + intel_bo_unmap (bo); + + assert (bo->exec == NULL); + assert (cairo_list_is_empty (&bo->cache_list)); - bucket = INTEL_BO_CACHE_BUCKETS; - if (bo->base.size & -bo->base.size) - bucket = ffs (bo->base.size / 4096) - 1; + bucket = bo->bucket; CAIRO_MUTEX_LOCK (device->bo_mutex); 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) - { - device->bo_cache_size += bo->base.size; - } + device->bo_cache[bucket].num_entries++; + device->bo_cache_size += 4096 * (1 << bucket); - cairo_list_add_tail (&bo->cache_list, &device->bo_cache[bucket].list); + if (bo->busy) + cairo_list_add_tail (&bo->cache_list, &device->bo_cache[bucket].list); + else + cairo_list_add (&bo->cache_list, &device->bo_cache[bucket].list); } else { @@ -520,36 +661,26 @@ intel_bo_release (void *_dev, void *_bo) void intel_bo_set_tiling (const intel_device_t *device, - intel_bo_t *bo, - uint32_t tiling, - uint32_t stride) + intel_bo_t *bo) { struct drm_i915_gem_set_tiling set_tiling; int ret; - if (bo->tiling == tiling && - (tiling == I915_TILING_NONE || bo->stride == stride)) - { + if (bo->tiling == bo->_tiling && + (bo->tiling == I915_TILING_NONE || bo->stride == bo->_stride)) return; - } - - assert (bo->exec == NULL); - - if (bo->virtual) - intel_bo_unmap (bo); do { set_tiling.handle = bo->base.handle; - set_tiling.tiling_mode = tiling; - set_tiling.stride = stride; + set_tiling.tiling_mode = bo->tiling; + set_tiling.stride = bo->stride; 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; - bo->stride = set_tiling.stride; - } + + assert (ret == 0); + bo->_tiling = bo->tiling; + bo->_stride = bo->stride; } cairo_surface_t * @@ -568,26 +699,11 @@ intel_bo_get_image (const intel_device_t *device, if (unlikely (image->base.status)) return &image->base; - if (bo->tiling == I915_TILING_NONE) { - if (image->stride == surface->stride) { - size = surface->stride * surface->height; - intel_bo_read (device, bo, 0, size, image->data); - } else { - int offset; - - size = surface->width; - if (surface->format != CAIRO_FORMAT_A8) - size *= 4; - - offset = 0; - row = surface->height; - dst = image->data; - while (row--) { - intel_bo_read (device, bo, offset, size, dst); - offset += surface->stride; - dst += image->stride; - } - } + intel_bo_set_tiling (device, bo); + + if (bo->tiling == I915_TILING_NONE && image->stride == surface->stride) { + size = surface->stride * surface->height; + intel_bo_read (device, bo, 0, size, image->data); } else { const uint8_t *src; @@ -606,16 +722,14 @@ intel_bo_get_image (const intel_device_t *device, dst += image->stride; src += surface->stride; } - - intel_bo_unmap (bo); } return &image->base; } static cairo_status_t -_intel_bo_put_a1_image (intel_device_t *dev, - intel_bo_t *bo, int stride, +_intel_bo_put_a1_image (intel_device_t *device, + intel_bo_t *bo, cairo_image_surface_t *src, int src_x, int src_y, int width, int height, @@ -628,13 +742,13 @@ _intel_bo_put_a1_image (intel_device_t *dev, data = src->data + src_y * src->stride; - if (bo->tiling == I915_TILING_NONE && width == stride) { + if (bo->tiling == I915_TILING_NONE && width == bo->stride) { uint8_t *p; int size; - size = stride * height; + size = bo->stride * height; if (size > (int) sizeof (buf)) { - a8 = _cairo_malloc_ab (stride, height); + a8 = _cairo_malloc_ab (bo->stride, height); if (a8 == NULL) return _cairo_error (CAIRO_STATUS_NO_MEMORY); } @@ -649,11 +763,11 @@ _intel_bo_put_a1_image (intel_device_t *dev, } data += src->stride; - p += stride; + p += bo->stride; } - intel_bo_write (dev, bo, - dst_y * stride + dst_x, /* XXX bo_offset */ + intel_bo_write (device, bo, + dst_y * bo->stride + dst_x, /* XXX bo_offset */ size, a8); } else { uint8_t *dst; @@ -664,14 +778,14 @@ _intel_bo_put_a1_image (intel_device_t *dev, return _cairo_error (CAIRO_STATUS_NO_MEMORY); } - dst = intel_bo_map (dev, bo); + dst = intel_bo_map (device, 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 */ + dst += dst_y * bo->stride + dst_x; /* XXX bo_offset */ while (height--) { for (x = 0; x < width; x++) { int i = src_x + x; @@ -681,10 +795,9 @@ _intel_bo_put_a1_image (intel_device_t *dev, } memcpy (dst, a8, width); - dst += stride; + dst += bo->stride; data += src->stride; } - intel_bo_unmap (bo); } if (a8 != buf) @@ -694,8 +807,8 @@ _intel_bo_put_a1_image (intel_device_t *dev, } cairo_status_t -intel_bo_put_image (intel_device_t *dev, - intel_bo_t *bo, int stride, +intel_bo_put_image (intel_device_t *device, + intel_bo_t *bo, cairo_image_surface_t *src, int src_x, int src_y, int width, int height, @@ -705,7 +818,9 @@ intel_bo_put_image (intel_device_t *dev, int size; int offset; - offset = dst_y * stride; + intel_bo_set_tiling (device, bo); + + offset = dst_y * bo->stride; data = src->data + src_y * src->stride; switch (src->format) { case CAIRO_FORMAT_ARGB32: @@ -725,8 +840,7 @@ intel_bo_put_image (intel_device_t *dev, size = width; break; case CAIRO_FORMAT_A1: - return _intel_bo_put_a1_image (dev, - bo, stride, src, + return _intel_bo_put_a1_image (device, bo, src, src_x, src_y, width, height, dst_x, dst_y); @@ -735,28 +849,21 @@ intel_bo_put_image (intel_device_t *dev, return _cairo_error (CAIRO_STATUS_INVALID_FORMAT); } - 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; - } + if (bo->tiling == I915_TILING_NONE && src->stride == bo->stride) { + intel_bo_write (device, bo, offset, bo->stride * height, data); } else { uint8_t *dst; - dst = intel_bo_map (dev, bo); + dst = intel_bo_map (device, bo); if (unlikely (dst == NULL)) return _cairo_error (CAIRO_STATUS_DEVICE_ERROR); dst += offset; while (height--) { memcpy (dst, data, size); - dst += stride; + dst += bo->stride; data += src->stride; } - intel_bo_unmap (bo); } return CAIRO_STATUS_SUCCESS; @@ -771,6 +878,7 @@ _intel_device_init_bo_cache (intel_device_t *device) device->bo_cache_size = 0; device->bo_max_cache_size_high = device->gtt_max_size / 2; device->bo_max_cache_size_low = device->gtt_max_size / 4; + cairo_list_init (&device->bo_in_flight); for (i = 0; i < INTEL_BO_CACHE_BUCKETS; i++) { struct _intel_bo_cache *cache = &device->bo_cache[i]; @@ -805,7 +913,6 @@ _intel_snapshot_cache_entry_destroy (void *closure) snapshot_cache_entry); surface->snapshot_cache_entry.hash = 0; - cairo_surface_destroy (&surface->drm.base); } cairo_status_t @@ -839,7 +946,6 @@ intel_device_init (intel_device_t *device, int fd) 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); @@ -926,25 +1032,6 @@ intel_throttle (intel_device_t *device) } 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; @@ -984,6 +1071,8 @@ intel_glyph_cache_add_glyph (intel_device_t *device, if (unlikely (status)) return status; + /* XXX streaming upload? */ + height = glyph_surface->height; src = glyph_surface->data; dst = cache->buffer.bo->virtual; @@ -1002,10 +1091,8 @@ intel_glyph_cache_add_glyph (intel_device_t *device, if (width > (int) sizeof (buf)) { a8 = malloc (width); - if (unlikely (a8 == NULL)) { - intel_bo_unmap (cache->buffer.bo); + if (unlikely (a8 == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); - } } dst += node->x; @@ -1051,9 +1138,6 @@ intel_glyph_cache_add_glyph (intel_device_t *device, return _cairo_error (CAIRO_STATUS_INVALID_FORMAT); } - /* leave mapped! */ - device->glyph_cache_mapped = TRUE; - scaled_glyph->surface_private = node; glyph= (intel_glyph_t *) node; @@ -1064,14 +1148,17 @@ intel_glyph_cache_add_glyph (intel_device_t *device, 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)); + texcoord_2d_16 (sf_x * (node->x + glyph_surface->width), + sf_y * (node->y + glyph_surface->height)); glyph->texcoord[1] = - texcoord_2d_16 (sf_x * (node->x + NEAREST_BIAS), - sf_y * (node->y + glyph_surface->height + NEAREST_BIAS)); + texcoord_2d_16 (sf_x * node->x, + sf_y * (node->y + glyph_surface->height)); glyph->texcoord[2] = - texcoord_2d_16 (sf_x * (node->x + NEAREST_BIAS), - sf_y * (node->y + NEAREST_BIAS)); + texcoord_2d_16 (sf_x * node->x, + sf_y * node->y); + + glyph->width = glyph_surface->width; + glyph->height = glyph_surface->height; return CAIRO_STATUS_SUCCESS; } @@ -1190,9 +1277,6 @@ intel_get_glyph (intel_device_t *device, assert (cache->buffer.bo->exec != NULL); - if (cache->buffer.bo->virtual != NULL) - intel_bo_unmap (cache->buffer.bo); - _cairo_rtree_reset (&cache->rtree); intel_bo_destroy (device, cache->buffer.bo); cache->buffer.bo = NULL; @@ -1225,6 +1309,7 @@ intel_buffer_cache_init (intel_buffer_cache_t *cache, int width, int height) { const uint32_t tiling = I915_TILING_Y; + uint32_t stride, size; assert ((width & 3) == 0); assert ((height & 1) == 0); @@ -1233,6 +1318,7 @@ intel_buffer_cache_init (intel_buffer_cache_t *cache, cache->buffer.height = height; switch (format) { + default: case CAIRO_FORMAT_A1: case CAIRO_FORMAT_RGB16_565: case CAIRO_FORMAT_RGB24: @@ -1241,25 +1327,28 @@ intel_buffer_cache_init (intel_buffer_cache_t *cache, return _cairo_error (CAIRO_STATUS_INVALID_FORMAT); case CAIRO_FORMAT_ARGB32: cache->buffer.map0 = MAPSURF_32BIT | MT_32BIT_ARGB8888; - cache->buffer.stride = width * 4; + stride = width * 4; break; case CAIRO_FORMAT_A8: cache->buffer.map0 = MAPSURF_8BIT | MT_8BIT_I8; - cache->buffer.stride = width; + 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; + size = height * stride; cache->buffer.bo = intel_bo_create (device, - height * cache->buffer.stride, FALSE); + size, size, + FALSE, tiling, stride); 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.stride = stride; - cache->buffer.map0 |= MS3_tiling (cache->buffer.bo->tiling); + cache->buffer.offset = 0; + cache->buffer.map0 |= MS3_tiling (tiling); + cache->buffer.map0 |= ((height - 1) << MS3_HEIGHT_SHIFT) | + ((width - 1) << MS3_WIDTH_SHIFT); + cache->buffer.map1 = ((stride / 4) - 1) << MS4_PITCH_SHIFT; cache->ref_count = 0; cairo_list_init (&cache->link); @@ -1272,16 +1361,8 @@ 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; + surface->snapshot_cache_entry.size = surface->drm.bo->size; if (surface->snapshot_cache_entry.size > device->snapshot_cache_max_size) { @@ -1291,6 +1372,7 @@ intel_snapshot_cache_insert (intel_device_t *device, if (device->snapshot_cache.freeze_count == 0) _cairo_cache_freeze (&device->snapshot_cache); + surface->snapshot_cache_entry.hash = (unsigned long) surface; status = _cairo_cache_insert (&device->snapshot_cache, &surface->snapshot_cache_entry); if (unlikely (status)) { @@ -1298,8 +1380,6 @@ intel_snapshot_cache_insert (intel_device_t *device, return status; } - cairo_surface_reference (&surface->drm.base); - return CAIRO_STATUS_SUCCESS; } @@ -1314,7 +1394,7 @@ intel_surface_detach_snapshot (cairo_surface_t *abstract_surface) device = (intel_device_t *) surface->drm.base.device; _cairo_cache_remove (&device->snapshot_cache, &surface->snapshot_cache_entry); - surface->snapshot_cache_entry.hash = 0; + assert (surface->snapshot_cache_entry.hash == 0); } } @@ -1470,12 +1550,13 @@ intel_gradient_render (intel_device_t *device, pixman_image_unref (gradient); - buffer->bo = intel_bo_create (device, 4*width, FALSE); + buffer->bo = intel_bo_create (device, + 4*width, 4*width, + FALSE, I915_TILING_NONE, 4*width); if (unlikely (buffer->bo == NULL)) { pixman_image_unref (image); return _cairo_error (CAIRO_STATUS_NO_MEMORY); } - intel_bo_set_tiling (device, buffer->bo, I915_TILING_NONE, 0); intel_bo_write (device, buffer->bo, 0, 4*width, pixman_image_get_data (image)); pixman_image_unref (image); @@ -1486,8 +1567,7 @@ intel_gradient_render (intel_device_t *device, 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->map0 |= ((width - 1) << MS3_WIDTH_SHIFT); buffer->map1 = (width - 1) << MS4_PITCH_SHIFT; if (device->gradient_cache.size < GRADIENT_CACHE_SIZE) { diff --git a/src/drm/cairo-drm-private.h b/src/drm/cairo-drm-private.h index df24b0ac..2db7f38d 100644 --- a/src/drm/cairo-drm-private.h +++ b/src/drm/cairo-drm-private.h @@ -63,7 +63,7 @@ typedef void typedef cairo_surface_t * (*cairo_drm_surface_create_func_t) (cairo_drm_device_t *device, - cairo_content_t content, + cairo_format_t format, int width, int height); typedef cairo_surface_t * @@ -172,16 +172,12 @@ _cairo_drm_bo_close (const cairo_drm_device_t *dev, cairo_private void _cairo_drm_surface_init (cairo_drm_surface_t *surface, - cairo_drm_device_t *device); + cairo_format_t format, + int width, int height); cairo_private cairo_status_t _cairo_drm_surface_finish (cairo_drm_surface_t *surface); -cairo_private cairo_surface_t * -_cairo_drm_surface_create_similar (void *abstract_src, - cairo_content_t content, - int width, - int height); cairo_private void _cairo_drm_surface_get_font_options (void *abstract_surface, cairo_font_options_t *options); diff --git a/src/drm/cairo-drm-radeon-surface.c b/src/drm/cairo-drm-radeon-surface.c index df95d8c6..cbcef2a5 100644 --- a/src/drm/cairo-drm-radeon-surface.c +++ b/src/drm/cairo-drm-radeon-surface.c @@ -283,34 +283,21 @@ static const cairo_surface_backend_t radeon_surface_backend = { static void radeon_surface_init (radeon_surface_t *surface, - cairo_content_t content, - cairo_drm_device_t *device) + cairo_drm_device_t *device, + cairo_format_t format, + int width, int height) { _cairo_surface_init (&surface->base.base, &radeon_surface_backend, &device->base, - content); - _cairo_drm_surface_init (&surface->base, device); - - switch (content) { - case CAIRO_CONTENT_ALPHA: - surface->base.format = CAIRO_FORMAT_A8; - break; - case CAIRO_CONTENT_COLOR: - surface->base.format = CAIRO_FORMAT_RGB24; - break; - default: - ASSERT_NOT_REACHED; - case CAIRO_CONTENT_COLOR_ALPHA: - surface->base.format = CAIRO_FORMAT_ARGB32; - break; - } + _cairo_content_from_format (format)); + _cairo_drm_surface_init (&surface->base, format, width, height); } static cairo_surface_t * radeon_surface_create_internal (cairo_drm_device_t *device, - cairo_content_t content, - int width, int height) + cairo_format_t format, + int width, int height) { radeon_surface_t *surface; cairo_status_t status; @@ -319,12 +306,9 @@ radeon_surface_create_internal (cairo_drm_device_t *device, if (unlikely (surface == NULL)) return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); - radeon_surface_init (surface, content, device); + radeon_surface_init (surface, device, format, width, height); if (width && height) { - surface->base.width = width; - surface->base.height = height; - surface->base.stride = cairo_format_stride_for_width (surface->base.format, width); @@ -344,10 +328,22 @@ radeon_surface_create_internal (cairo_drm_device_t *device, static cairo_surface_t * radeon_surface_create (cairo_drm_device_t *device, - cairo_content_t content, - int width, int height) + cairo_format_t format, + int width, int height) { - return radeon_surface_create_internal (device, content, width, height); + switch (format) { + default: + case CAIRO_FORMAT_INVALID: + case CAIRO_FORMAT_A1: + case CAIRO_FORMAT_RGB16_565: + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT)); + case CAIRO_FORMAT_ARGB32: + case CAIRO_FORMAT_RGB24: + case CAIRO_FORMAT_A8: + break; + } + + return radeon_surface_create_internal (device, format, width, height); } static cairo_surface_t * @@ -358,7 +354,6 @@ radeon_surface_create_for_name (cairo_drm_device_t *device, { radeon_surface_t *surface; cairo_status_t status; - cairo_content_t content; switch (format) { default: @@ -367,13 +362,8 @@ radeon_surface_create_for_name (cairo_drm_device_t *device, case CAIRO_FORMAT_RGB16_565: 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; } @@ -384,11 +374,9 @@ radeon_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)); - radeon_surface_init (surface, content, device); + radeon_surface_init (surface, device, format, width, height); if (width && height) { - surface->base.width = width; - surface->base.height = height; surface->base.stride = stride; surface->base.bo = radeon_bo_create_for_name (to_radeon_device (&device->base), diff --git a/src/drm/cairo-drm-surface.c b/src/drm/cairo-drm-surface.c index a94150b6..a8a8f32e 100644 --- a/src/drm/cairo-drm-surface.c +++ b/src/drm/cairo-drm-surface.c @@ -36,28 +36,15 @@ #include "cairo-error-private.h" -cairo_surface_t * -_cairo_drm_surface_create_similar (void *abstract_surface, - cairo_content_t content, - int width, - int height) -{ - cairo_drm_surface_t *surface = abstract_surface; - cairo_drm_device_t *device = (cairo_drm_device_t *) surface->base.device; - - if (width > device->max_surface_size || height > device->max_surface_size) - return NULL; - - return device->surface.create (device, content, width, height); -} - void _cairo_drm_surface_init (cairo_drm_surface_t *surface, - cairo_drm_device_t *device) + cairo_format_t format, + int width, int height) { surface->bo = NULL; - surface->width = 0; - surface->height = 0; + surface->format = format; + surface->width = width; + surface->height = height; surface->stride = 0; surface->fallback = NULL; @@ -100,15 +87,12 @@ _cairo_drm_surface_get_extents (void *abstract_surface, cairo_surface_t * cairo_drm_surface_create (cairo_device_t *abstract_device, - cairo_content_t content, + cairo_format_t format, 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->base.status) { surface = _cairo_surface_create_in_error (device->base.status); @@ -118,8 +102,7 @@ cairo_drm_surface_create (cairo_device_t *abstract_device, width == 0 || width > device->max_surface_size || height == 0 || height > device->max_surface_size) { - surface = cairo_image_surface_create (_cairo_format_from_content (content), - width, height); + surface = cairo_image_surface_create (format, width, height); } else if (device->base.finished) { @@ -127,7 +110,9 @@ cairo_drm_surface_create (cairo_device_t *abstract_device, } else { - surface = device->surface.create (device, content, width, height); + surface = device->surface.create (device, format, width, height); + if (surface->status == CAIRO_STATUS_INVALID_SIZE) + surface = cairo_image_surface_create (format, width, height); } return surface; @@ -334,7 +319,7 @@ cairo_drm_surface_get_stride (cairo_surface_t *abstract_surface) /* XXX drm or general surface layer? naming? */ cairo_surface_t * -cairo_drm_surface_map (cairo_surface_t *abstract_surface) +cairo_drm_surface_map_to_image (cairo_surface_t *abstract_surface) { cairo_drm_surface_t *surface; cairo_drm_device_t *device; diff --git a/src/drm/cairo-drm-xr.c b/src/drm/cairo-drm-xr.c new file mode 100644 index 00000000..c3b1bbdc --- /dev/null +++ b/src/drm/cairo-drm-xr.c @@ -0,0 +1,2377 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 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 + * 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@chris-wilson.co.uk> + */ + +/* + * Implement an X Acceleration Architecture using the cairo-drm + * backends. + */ + +#include "cairoint.h" +#include "cairo-drm-private.h" + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#else +#include <xorg-server.h> +#endif + +#include "xf86.h" +#include "gcstruct.h" +#include "scrnintstr.h" +#include "pixmapstr.h" +#include "windowstr.h" +#include "picturestr.h" +#include "mi.h" +#include "fb.h" +#ifdef MITSHM +#include <X11/extensions/shm.h> +#endif +#ifdef RENDER +#include "fbpict.h" +#include "glyphstr.h" +#endif + +#include "cairo-drm-xr.h" + +struct _xr_screen { + cairo_device_t *device; + + CreateGCProcPtr SavedCreateGC; + CloseScreenProcPtr SavedCloseScreen; + GetImageProcPtr SavedGetImage; + GetSpansProcPtr SavedGetSpans; + CreatePixmapProcPtr SavedCreatePixmap; + DestroyPixmapProcPtr SavedDestroyPixmap; + CopyWindowProcPtr SavedCopyWindow; + ChangeWindowAttributesProcPtr SavedChangeWindowAttributes; + BitmapToRegionProcPtr SavedBitmapToRegion; + +#ifdef RENDER + CompositeProcPtr SavedComposite; + GlyphsProcPtr SavedGlyphs; + CompositeRectsProcPtr SavedCompositeRects; + TrapezoidsProcPtr SavedTrapezoids; + TrianglesProcPtr SavedTriangles; + TriStripProcPtr SavedTriStrip; + TriFanProcPtr SavedTriFan; + AddTrianglesProcPtr SavedAddTriangles; + AddTrapsProcPtr SavedAddTraps; + + RealizeGlyphProcPtr SavedRealizeGlyph; + UnrealizeGlyphProcPtr SavedUnrealizeGlyph; +#endif +}; + +struct xr_access_gc { + cairo_surface_t *stipple; + cairo_surface_t *tile; +}; + +struct xr_access_window { + cairo_surface_t *background; + cairo_surface_t *border; +}; + +static int xr_screen_index; +static int xr_pixmap_index; + +static inline xr_screen_t * +xr_get_screen (ScreenPtr screen) +{ + return dixLookupPrivate (&screen->devPrivates, &xr_screen_index); +} + +static inline PixmapPtr +xr_drawable_get_pixmap (DrawablePtr drawable) +{ + if (drawable->type == DRAWABLE_WINDOW) + return drawable->pScreen->GetWindowPixmap ((WindowPtr) drawable); + else + return (PixmapPtr) drawable; +} + +static inline cairo_drm_surface_t * +xr_pixmap_get_drm_surface (PixmapPtr pixmap) +{ + return dixLookupPrivate (&pixmap->devPrivates, &xr_pixmap_index); +} + +static cairo_drm_surface_t * +xr_drawable_get_drm_surface (DrawablePtr drawable) +{ + return xr_pixmap_get_drm_surface (xr_drawable_get_pixmap (drawable)); +} + +static cairo_format_t +xr_format_for_depth (int depth) +{ + switch (depth) { + case 1: + return CAIRO_FORMAT_A1; + case 8: + return CAIRO_FORMAT_A8; + case 16: + return CAIRO_FORMAT_RGB16_565; + case 24: + return CAIRO_FORMAT_RGB24; + default: + case 32: + return CAIRO_FORMAT_ARGB32; + } +} + +static cairo_surface_t * +xr_pixmap_get_surface (PixmapPtr pixmap) +{ + cairo_drm_surface_t *drm; + + drm = xr_pixmap_get_drm_surface (pixmap); + if (drm != NULL) + return cairo_surface_reference (&drm->base); + + return cairo_image_surface_create_for_data (pixmap->devPrivate.ptr, + xr_format_for_depth (pixmap->drawable.depth), + pixmap->drawable.width, + pixmap->drawable.height, + pixmap->devKind); +} + +static cairo_surface_t * +xr_drawable_get_surface (DrawablePtr drawable) +{ + return xr_pixmap_get_surface (xr_drawable_get_pixmap (drawable)); +} + +static cairo_bool_t +xr_prepare_access (DrawablePtr drawable, + cairo_surface_t **image) +{ + PixmapPtr pixmap; + cairo_drm_surface_t *drm; + + *image = NULL; + + pixmap = xr_drawable_get_pixmap (drawable); + drm = xr_pixmap_get_drm_surface (pixmap); + if (drm == NULL) + return TRUE; + + *image = cairo_drm_surface_map_to_image (&drm->base); + if ((*image)->status) + return FALSE; + + pixmap->devPrivate.ptr = + ((cairo_image_surface_t *) *image)->data; + + return TRUE; +} + +static void +xr_finish_access (DrawablePtr drawable, + cairo_surface_t *image) +{ + if (image != NULL) { + cairo_drm_surface_unmap (&xr_drawable_get_drm_surface (drawable)->base, + image); + } +} + +static cairo_bool_t +xr_prepare_access_gc (GCPtr gc, + struct xr_access_gc *local) +{ + local->stipple = NULL; + local->tile = NULL; + + if (gc->stipple) { + if (! xr_prepare_access (&gc->stipple->drawable, &local->stipple)) + return FALSE; + } + + if (gc->fillStyle == FillTiled) { + if (! xr_prepare_access (&gc->tile.pixmap->drawable, + &local->tile)) + { + if (local->stipple) { + xr_finish_access (&gc->stipple->drawable, + local->stipple); + } + + return FALSE; + } + } + + return TRUE; +} + +static void +xr_finish_access_gc (GCPtr gc, + struct xr_access_gc *local) +{ + if (local->tile) { + xr_finish_access(&gc->tile.pixmap->drawable, + local->tile); + } + + if (local->stipple) { + xr_finish_access(&gc->stipple->drawable, + local->stipple); + } +} + +static void +xr_fill_spans (DrawablePtr drawable, + GCPtr gc, + int nspans, + DDXPointPtr ppt, + int *pwidth, + int fSorted) +{ + cairo_surface_t *image; + struct xr_access_gc access_gc; + + //ErrorF ("fallback: %s\n", __FUNCTION__); + if (xr_prepare_access (drawable, &image)) { + if (xr_prepare_access_gc (gc, &access_gc)) { + fbFillSpans (drawable, gc, + nspans, ppt, pwidth, + fSorted); + xr_finish_access_gc(gc, &access_gc); + } + xr_finish_access (drawable, image); + } +} + +static void +xr_set_spans (DrawablePtr drawable, + GCPtr gc, + char *psrc, + DDXPointPtr ppt, + int *pwidth, + int nspans, + int fSorted) +{ + cairo_surface_t *image; + + //ErrorF ("fallback: %s\n", __FUNCTION__); + if (xr_prepare_access (drawable, &image)) { + fbSetSpans (drawable, gc, psrc, ppt, pwidth, nspans, fSorted); + xr_finish_access (drawable, image); + } +} + +#define XR_PM_IS_SOLID(_pDrawable, _pm) \ + (((_pm) & FbFullMask((_pDrawable)->depth)) == \ + FbFullMask((_pDrawable)->depth)) + +static cairo_clip_t * +xr_gc_get_clip (GCPtr gc, int xoff, int yoff) +{ + return NULL; +} + +static cairo_bool_t +xr_do_put_image (DrawablePtr drawable, + GCPtr gc, + int depth, + int x, int y, + int width, int height, + int format, + char *bits, int src_stride) +{ + cairo_surface_t *surface; + cairo_clip_t *clip; + cairo_surface_t *image; + cairo_surface_pattern_t pattern; + cairo_status_t status; + cairo_path_fixed_t path; + cairo_fixed_t x1, y1, x2, y2; + + if (format != ZPixmap || drawable->bitsPerPixel < 8) + return FALSE; + + if (! XR_PM_IS_SOLID (drawable, gc->planemask) || gc->alu != GXcopy) + return FALSE; + + clip = xr_gc_get_clip (gc, drawable->x, drawable->y); + x1 = _cairo_fixed_from_int (x + drawable->x); + y1 = _cairo_fixed_from_int (y + drawable->y); + x2 = x1 + _cairo_fixed_from_int (width); + y2 = y1 + _cairo_fixed_from_int (height); + _cairo_path_fixed_init (&path); + if (_cairo_path_fixed_move_to (&path, x1, y1) || + _cairo_path_fixed_line_to (&path, x2, y1) || + _cairo_path_fixed_line_to (&path, x2, y2) || + _cairo_path_fixed_line_to (&path, x1, y2) || + _cairo_path_fixed_close_path (&path)) + { + goto err_path; + } + + image = cairo_image_surface_create_for_data ((uint8_t *) bits, + xr_format_for_depth (depth), + width, height, src_stride); + _cairo_pattern_init_for_surface (&pattern, image); + cairo_surface_destroy (image); + pattern.base.filter = CAIRO_FILTER_NEAREST; + cairo_matrix_init_translate (&pattern.base.matrix, + -x - drawable->x, + -y - drawable->x); + + surface = xr_drawable_get_surface (drawable); + status = _cairo_surface_fill (surface, + CAIRO_OPERATOR_SOURCE, + &pattern.base, + &path, + CAIRO_FILL_RULE_WINDING, + CAIRO_ANTIALIAS_DEFAULT, + CAIRO_GSTATE_TOLERANCE_DEFAULT, + clip); + cairo_surface_destroy (surface); + _cairo_pattern_fini (&pattern.base); +err_path: + _cairo_path_fixed_fini (&path); + + (void) status; + return TRUE; +} + +static void +xr_put_image(DrawablePtr drawable, + GCPtr gc, int depth, + int x, int y, + int w, int h, + int leftPad, + int format, + char *bits) +{ + if (! xr_do_put_image (drawable, + gc, + depth, + x, y, w, h, + format, + bits, + PixmapBytePad (w, drawable->depth))) + { + cairo_surface_t *image; + + //ErrorF ("fallback: %s\n", __FUNCTION__); + if (xr_prepare_access (drawable, &image)) { + fbPutImage (drawable, gc, depth, + x, y, w, h, + leftPad, format, bits); + xr_finish_access (drawable, image); + } + } +} + +static void +xr_pattern_init_for_drawable (cairo_surface_pattern_t *pattern, + DrawablePtr drawable) +{ + cairo_surface_t *surface; + + surface = xr_drawable_get_surface (drawable); + _cairo_pattern_init_for_surface (pattern, surface); + cairo_surface_destroy (surface); + + pattern->base.filter = CAIRO_FILTER_NEAREST; + pattern->base.extend = CAIRO_EXTEND_NONE; + cairo_matrix_init_translate (&pattern->base.matrix, + drawable->x, + drawable->y); +} + +static RegionPtr +xr_copy_area (DrawablePtr src, + DrawablePtr dst, + GCPtr gc, + int src_x, int src_y, + int width, int height, + int dst_x, int dst_y) +{ + cairo_surface_pattern_t pattern; + cairo_clip_t *clip; + cairo_surface_t *surface; + cairo_status_t status; + cairo_path_fixed_t path; + cairo_fixed_t x1, x2, y1, y2; + + xr_pattern_init_for_drawable (&pattern, src); + cairo_matrix_translate (&pattern.base.matrix, + src->x + src_x - dst_x - dst->x, + src->y + src_y - dst_y - dst->y); + + clip = xr_gc_get_clip (gc, dst->x, dst->y); + surface = xr_drawable_get_surface (dst); + + x1 = _cairo_fixed_from_int (dst_x + dst->x); + y1 = _cairo_fixed_from_int (dst_y + dst->y); + x2 = x1 + _cairo_fixed_from_int (width); + y2 = y1 + _cairo_fixed_from_int (height); + _cairo_path_fixed_init (&path); + if (_cairo_path_fixed_move_to (&path, x1, y1) || + _cairo_path_fixed_line_to (&path, x2, y1) || + _cairo_path_fixed_line_to (&path, x2, y2) || + _cairo_path_fixed_line_to (&path, x1, y2) || + _cairo_path_fixed_close_path (&path)) + { + goto err_path; + } + + status = _cairo_surface_fill (surface, + CAIRO_OPERATOR_SOURCE, + &pattern.base, + &path, + CAIRO_FILL_RULE_WINDING, + CAIRO_ANTIALIAS_DEFAULT, + CAIRO_GSTATE_TOLERANCE_DEFAULT, + clip); + (void) status; + +err_path: + _cairo_path_fixed_fini (&path); + _cairo_pattern_fini (&pattern.base); + cairo_surface_destroy (surface); + + return miGetCompositeClip (gc); +} + +static RegionPtr +xr_copy_plane (DrawablePtr src, + DrawablePtr dst, + GCPtr gc, + int src_x, int src_y, + int w, int h, + int dst_x, int dst_y, + unsigned long bitPlane) +{ + RegionPtr ret = NULL; + cairo_surface_t *src_image, *dst_image; + + //ErrorF ("fallback: %s\n", __FUNCTION__); + if (xr_prepare_access (dst, &dst_image)) { + if (xr_prepare_access (src, &src_image)) { + ret = fbCopyPlane (src, dst, gc, + src_x, src_y, + w, h, + dst_x, dst_y, + bitPlane); + xr_finish_access (src, src_image); + } + xr_finish_access (dst, dst_image); + } + return ret; +} + +static void +xr_poly_point (DrawablePtr drawable, + GCPtr gc, + int mode, + int npt, + DDXPointPtr ppt) +{ + cairo_surface_t *image; + + //ErrorF ("fallback: %s\n", __FUNCTION__); + if (xr_prepare_access (drawable, &image)) { + fbPolyPoint (drawable, gc, mode, npt, ppt); + xr_finish_access (drawable, image); + } +} + +static void +xr_poly_line (DrawablePtr drawable, + GCPtr gc, + int mode, + int npt, + DDXPointPtr ppt) +{ + cairo_surface_t *image; + + //ErrorF ("fallback: %s\n", __FUNCTION__); + if (xr_prepare_access (drawable, &image)) { + fbPolyLine (drawable, gc, mode, npt, ppt); + xr_finish_access (drawable, image); + } +} + +static void +xr_poly_segment (DrawablePtr drawable, + GCPtr gc, + int nseg, + xSegment *pSeg) +{ + cairo_surface_t *image; + + //ErrorF ("fallback: %s\n", __FUNCTION__); + if (xr_prepare_access (drawable, &image)) { + fbPolySegment (drawable, gc, nseg, pSeg); + xr_finish_access (drawable, image); + } +} + +static void +xr_poly_rectangle (DrawablePtr drawable, + GCPtr gc, + int nrect, + xRectangle *pRects) +{ + cairo_surface_t *image; + + //ErrorF ("fallback: %s\n", __FUNCTION__); + if (xr_prepare_access (drawable, &image)) { + fbPolyRectangle (drawable, gc, nrect, pRects); + xr_finish_access (drawable, image); + } +} + +static void +xr_poly_arc (DrawablePtr drawable, + GCPtr gc, + int narcs, + xArc *pArcs) +{ + cairo_surface_t *image; + + //ErrorF ("fallback: %s\n", __FUNCTION__); + if (xr_prepare_access (drawable, &image)) { + fbPolyArc (drawable, gc, narcs, pArcs); + xr_finish_access (drawable, image); + } +} + +static void +xr_poly_fill (DrawablePtr drawable, + GCPtr gc, + int shape, + int mode, + int count, + DDXPointPtr pPts) +{ + cairo_surface_t *image; + + //ErrorF ("fallback: %s\n", __FUNCTION__); + if (xr_prepare_access (drawable, &image)) { + fbFillPolygon (drawable, gc, shape, mode, count, pPts); + xr_finish_access (drawable, image); + } +} + +static void +xr_poly_fill_rect_fallback (DrawablePtr drawable, + GCPtr gc, + int nrect, + xRectangle *prect) +{ + cairo_surface_t *image; + + //ErrorF ("fallback: %s\n", __FUNCTION__); + if (xr_prepare_access (drawable, &image)) { + miPolyFillRect (drawable, gc, nrect, prect); + xr_finish_access (drawable, image); + } +} + + +static void +xr_poly_fill_rect (DrawablePtr drawable, + GCPtr gc, + int nrect, + xRectangle *rect) +{ + cairo_clip_t *clip; + cairo_surface_t *surface; + cairo_status_t status; + int n; + + if (gc->alu != GXcopy && gc->alu != GXclear) { + xr_poly_fill_rect_fallback (drawable, gc, nrect, rect); + return; + } + + if (gc->fillStyle != FillSolid && + !(gc->tileIsPixel && gc->fillStyle == FillTiled)) + { + xr_poly_fill_rect_fallback (drawable, gc, nrect, rect); + return; + } + + surface = xr_drawable_get_surface (drawable); + clip = xr_gc_get_clip (gc, drawable->x, drawable->y); + if (clip == NULL && nrect == 1 && + rect->x <= 0 && + rect->y <= 0 && + rect->width >= drawable->width && + rect->height >= drawable->height && + (gc->alu == GXclear || (gc->fgPixel & 0x00ffffff) == 0)) + { + status = _cairo_surface_paint (surface, + CAIRO_OPERATOR_CLEAR, + &_cairo_pattern_clear.base, + NULL); + } + else + { + cairo_path_fixed_t path; + cairo_fixed_t x_off, y_off; + cairo_solid_pattern_t pattern; + cairo_color_t color; + + x_off = _cairo_fixed_from_int (drawable->x); + y_off = _cairo_fixed_from_int (drawable->y); + _cairo_path_fixed_init (&path); + for (n = 0; n < nrect; n++) { + cairo_fixed_t x1 = x_off + _cairo_fixed_from_int (rect[n].x); + cairo_fixed_t x2 = x1 + _cairo_fixed_from_int (rect[n].width); + cairo_fixed_t y1 = y_off + _cairo_fixed_from_int (rect[n].y); + cairo_fixed_t y2 = y1 + _cairo_fixed_from_int (rect[n].height); + + if (_cairo_path_fixed_move_to (&path, x1, y1) || + _cairo_path_fixed_line_to (&path, x2, y1) || + _cairo_path_fixed_line_to (&path, x2, y2) || + _cairo_path_fixed_line_to (&path, x1, y2) || + _cairo_path_fixed_close_path (&path)) + { + goto err_path; + } + } + + _cairo_color_init_rgb (&color, + ((gc->fgPixel & 0x00ff0000) >> 16) / 255., + ((gc->fgPixel & 0x0000ff00) >> 8) / 255., + ((gc->fgPixel & 0x000000ff) >> 0) / 255.); + _cairo_pattern_init_solid (&pattern, &color, CAIRO_CONTENT_COLOR); + + status = _cairo_surface_fill (surface, + gc->alu == GXcopy ? CAIRO_OPERATOR_SOURCE : CAIRO_OPERATOR_CLEAR, + &pattern.base, + &path, + CAIRO_FILL_RULE_WINDING, + 1., + CAIRO_ANTIALIAS_DEFAULT, + clip); +err_path: + _cairo_path_fixed_fini (&path); + } + + cairo_surface_destroy (surface); + (void) status; +} + +static void +xr_poly_fill_arc (DrawablePtr drawable, + GCPtr gc, + int narc, + xArc *arc) +{ + cairo_surface_t *image; + + //ErrorF ("fallback: %s\n", __FUNCTION__); + if (xr_prepare_access (drawable, &image)) { + miPolyFillArc (drawable, gc, narc, arc); + xr_finish_access (drawable, image); + } +} + +static void +xr_image_glyph_blt (DrawablePtr drawable, GCPtr gc, + int x, int y, unsigned int nglyph, + CharInfoPtr * ppci, pointer pglyphBase) +{ + cairo_surface_t *image; + struct xr_access_gc local_gc; + + //ErrorF ("fallback: %s\n", __FUNCTION__); + if (xr_prepare_access (drawable, &image)) { + if (xr_prepare_access_gc (gc, &local_gc)) { + fbImageGlyphBlt (drawable, gc, + x, y, + nglyph, + ppci, + pglyphBase); + xr_finish_access_gc (gc, &local_gc); + } + xr_finish_access (drawable, image); + } +} + +static void +xr_poly_glyph_blt (DrawablePtr drawable, + GCPtr gc, + int x, int y, + unsigned int nglyph, + CharInfoPtr *ppci, + pointer pglyphBase) +{ + cairo_surface_t *image; + struct xr_access_gc local_gc; + + //ErrorF ("fallback: %s\n", __FUNCTION__); + if (xr_prepare_access (drawable, &image)) { + if (xr_prepare_access_gc (gc, &local_gc)) { + fbPolyGlyphBlt (drawable, gc, + x, y, + nglyph, + ppci, + pglyphBase); + xr_finish_access_gc (gc, &local_gc); + } + xr_finish_access (drawable, image); + } +} + +static void +xr_push_pixels (GCPtr gc, + PixmapPtr src, + DrawablePtr dst, + int w, int h, int x, int y) +{ + cairo_surface_t *src_image, *dst_image; + struct xr_access_gc local_gc; + + //ErrorF ("fallback: %s\n", __FUNCTION__); + if (xr_prepare_access (dst, &dst_image)) { + if (xr_prepare_access (&src->drawable, &src_image)) { + if (xr_prepare_access_gc (gc, &local_gc)) { + fbPushPixels (gc, src, dst, + w, h, x, y); + xr_finish_access_gc (gc, &local_gc); + } + xr_finish_access (&src->drawable, src_image); + } + xr_finish_access (dst, dst_image); + } +} + +static void +xr_validate_gc (GCPtr gc, + unsigned long changes, + DrawablePtr drawable) +{ + static const GCOps xr_ops = { + xr_fill_spans, + xr_set_spans, + xr_put_image, + xr_copy_area, + xr_copy_plane, + xr_poly_point, + xr_poly_line, + xr_poly_segment, + xr_poly_rectangle, + xr_poly_arc, + xr_poly_fill, + xr_poly_fill_rect, + xr_poly_fill_arc, + miPolyText8, + miPolyText16, + miImageText8, + miImageText16, + xr_image_glyph_blt, + xr_poly_glyph_blt, + xr_push_pixels, + }; + + /* fbValidateGC will do direct access to pixmaps if the tiling has + * changed. Preempt fbValidateGC by doing its work and masking the + * change out, so that we can do the prepare/finish access. + */ +#ifdef FB_24_32BIT + if (changes & GCTile && fbGetRotatedPixmap (gc)) { + gc->pScreen->DestroyPixmap (fbGetRotatedPixmap (gc)); + fbGetRotatedPixmap (gc) = 0; + } + + if (gc->fillStyle == FillTiled) { + PixmapPtr old; + + old = gc->tile.pixmap; + if (old->drawable.bitsPerPixel != drawable->bitsPerPixel) { + PixmapPtr new = fbGetRotatedPixmap (gc); + if (new == NULL || + new->drawable.bitsPerPixel != drawable->bitsPerPixel) + { + cairo_surface_t *image; + + if (new) + gc->pScreen->DestroyPixmap (new); + + /* fb24_32ReformatTile will do direct access + * of a newly-allocated pixmap. This isn't a + * problem yet, since we don't put pixmaps in + * FB until at least one accelerated UXA op. + */ + if (xr_prepare_access (&old->drawable, &image)) { + new = fb24_32ReformatTile (old, + drawable->bitsPerPixel); + xr_finish_access (&old->drawable, image); + } + } + + if (new) { + fbGetRotatedPixmap (gc) = old; + gc->tile.pixmap = new; + changes |= GCTile; + } + } + } +#endif + + if (changes & GCTile) { + if (! gc->tileIsPixel && + FbEvenTile (gc->tile.pixmap->drawable.width * + drawable->bitsPerPixel)) + { + cairo_surface_t *image; + + if (xr_prepare_access (&gc->tile.pixmap->drawable, + &image)) + { + fbPadPixmap(gc->tile.pixmap); + xr_finish_access(&gc->tile.pixmap->drawable, image); + } + } + + /* Mask out the GCTile change notification, now that we've + * done FB's job for it. + */ + changes &= ~GCTile; + } + + if (changes & GCStipple && gc->stipple) { + cairo_surface_t *image; + + /* We can't inline stipple handling like we do for GCTile + * because it sets fbgc privates. + */ + if (xr_prepare_access (&gc->stipple->drawable, &image)) { + fbValidateGC (gc, changes, drawable); + xr_finish_access (&gc->stipple->drawable, image); + } + } else { + fbValidateGC(gc, changes, drawable); + } + + gc->ops = (GCOps *) & xr_ops; +} + +static void +xr_change_gc (GCPtr gc, unsigned long mask) +{ +} + +static void +xr_copy_gc (GCPtr src, unsigned long changes, GCPtr dst) +{ +} + +static void +xr_destroy_gc (GCPtr gc) +{ + miDestroyGC (gc); +} + +static void +xr_destroy_clip (GCPtr gc) +{ + miDestroyClip (gc); +} + +static void +xr_change_clip (GCPtr gc, int type, pointer value, int nrects) +{ + xr_destroy_clip (gc); + + miChangeClip (gc, type, value, nrects); +} + +static void +xr_copy_clip (GCPtr dst, GCPtr src) +{ + miCopyClip (dst, src); +} + +static int xr_create_gc (GCPtr gc) +{ + static GCFuncs funcs = { + xr_validate_gc, + xr_change_gc, + xr_copy_gc, + xr_destroy_gc, + xr_change_clip, + xr_destroy_clip, + xr_copy_clip, + }; + + if (! fbCreateGC (gc)) + return FALSE; + + gc->funcs = &funcs; + return TRUE; +} + +static void +xr_get_image (DrawablePtr drawable, + int x, int y, int w, int h, + unsigned int format, unsigned long planeMask, + char *d) +{ + cairo_surface_t *image; + + //ErrorF ("fallback: %s\n", __FUNCTION__); + if (xr_prepare_access (drawable, &image)) { + fbGetImage (drawable, x, y, w, h, format, planeMask, d); + xr_finish_access (drawable, image); + } +} + +static void +xr_get_spans (DrawablePtr drawable, + int wMax, + DDXPointPtr ppt, + int *pwidth, + int nspans, + char *pdstStart) +{ + cairo_surface_t *image; + + //ErrorF ("fallback: %s\n", __FUNCTION__); + if (xr_prepare_access (drawable, &image)) { + fbGetSpans (drawable, wMax, ppt, pwidth, nspans, pdstStart); + xr_finish_access (drawable, image); + } +} + +static void +xr_copy_window (WindowPtr win, + DDXPointRec origin, + RegionPtr src_region) +{ + //ErrorF ("fallback: %s\n", __FUNCTION__); +#if 0 + RegionRec dst_region; + PixmapPtr pixmap; + int dx, dy; + + dx = origin.x - win->drawable.x; + dy = origin.y - win->drawable.y; + REGION_TRANSLATE (win->drawable.pScreen, src_region, -dx, -dy); + + REGION_INIT (win->drawable.pScreen, &dst_region, NullBox, 0); + + REGION_INTERSECT (win->drawable.pScreen, + &dst_region, &win->borderClip, + src_region); + pixmap = win->drawable.pScreen->GetWindowPixmap (win); +#ifdef COMPOSITE + if (pixmap->screen_x || pixmap->screen_y) + REGION_TRANSLATE (win->drawable.pScreen, &dst_region, + -pixmap->screen_x, -pixmap->screen_y); +#endif + + miCopyRegion (&pixmap->drawable, &pixmap->drawable, + NULL, &dst_region, dx, dy, + xr_copy_n_to_n, 0, NULL); + + REGION_UNINIT (win->drawable.pScreen, &dst_region); +#endif +} + +static cairo_bool_t +xr_prepare_access_window (WindowPtr win, + struct xr_access_window *local) +{ + local->background = NULL; + local->border = NULL; + + if (win->backgroundState == BackgroundPixmap) { + if (! xr_prepare_access (&win->background.pixmap->drawable, + &local->background)) + { + return FALSE; + } + } + + if (win->borderIsPixel == FALSE) { + if (! xr_prepare_access (&win->border.pixmap->drawable, + &local->border)) + { + if (local->background) { + xr_finish_access (&win->background.pixmap->drawable, + local->background); + } + return FALSE; + } + } + return TRUE; +} + +static void +xr_finish_access_window (WindowPtr win, + struct xr_access_window *local) +{ + if (local->background) { + xr_finish_access (&win->background.pixmap->drawable, + local->background); + } + + if (local->border) { + xr_finish_access (&win->border.pixmap->drawable, + local->border); + } +} + +static Bool +xr_change_window_attributes (WindowPtr win, + unsigned long mask) +{ + Bool ret = FALSE; + struct xr_access_window local; + + if (xr_prepare_access_window (win, &local)) { + ret = fbChangeWindowAttributes (win, mask); + xr_finish_access_window (win, &local); + } + + return ret; +} + +static RegionPtr +xr_bitmap_to_region (PixmapPtr pPix) +{ + RegionPtr ret = NULL; + cairo_surface_t *image; + + //ErrorF ("fallback: %s\n", __FUNCTION__); + if (xr_prepare_access (&pPix->drawable, &image)) { + ret = fbPixmapToRegion (pPix); + xr_finish_access (&pPix->drawable, image); + } + + return ret; +} + +static void +_color_from_pixel (cairo_color_t *color, uint32_t pixel) +{ + color->alpha_short = (pixel & 0xff000000 >> 24); + color->alpha_short |= color->alpha_short << 8; + + if (color->alpha_short == 0) { + color->red_short = color->green_short = color->blue_short = 0; + color->alpha = color->red = color->green = color->blue = 0.; + return; + } + + color->red_short = (pixel & 0x00ff0000 >> 16); + color->red_short |= color->red_short << 8; + + color->green_short = (pixel & 0x0000ff00 >> 8); + color->green_short |= color->green_short << 8; + + color->blue_short = (pixel & 0x000000ff >> 0); + color->blue_short |= color->blue_short << 8; + + color->alpha = color->alpha_short / (double) 0xffff; + color->red = color->red_short / (double) 0xffff / color->alpha; + color->green = color->green_short / (double) 0xffff / color->alpha; + color->blue = color->blue_short / (double) 0xffff / color->alpha; +} + +static uint32_t +_pixmap_first_pixel (PixmapPtr pixmap) +{ + cairo_surface_t *image; + uint32_t pixel; + void *fb; + + if (! xr_prepare_access (&pixmap->drawable, &image)) + return 0; + + fb = pixmap->devPrivate.ptr; + switch (pixmap->drawable.bitsPerPixel) { + case 32: + pixel = *(uint32_t *) fb; + break; + case 16: + pixel = *(uint16_t *) fb; + break; + default: + pixel = *(CARD8 *) fb; + break; + } + xr_finish_access (&pixmap->drawable, image); + + return pixel; +} + +static cairo_bool_t +_rgba_from_pixel (uint32_t pixel, + uint16_t *red, + uint16_t *green, + uint16_t *blue, + uint16_t *alpha, + uint32_t format) +{ + int rbits, bbits, gbits, abits; + int rshift, bshift, gshift, ashift; + + rbits = PICT_FORMAT_R(format); + gbits = PICT_FORMAT_G(format); + bbits = PICT_FORMAT_B(format); + abits = PICT_FORMAT_A(format); + + if (PICT_FORMAT_TYPE(format) == PICT_TYPE_A) { + rshift = gshift = bshift = ashift = 0; + } else if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ARGB) { + bshift = 0; + gshift = bbits; + rshift = gshift + gbits; + ashift = rshift + rbits; + } else if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ABGR) { + rshift = 0; + gshift = rbits; + bshift = gshift + gbits; + ashift = bshift + bbits; + } else { + return FALSE; + } + + if (rbits) { + *red = ((pixel >> rshift) & ((1 << rbits) - 1)) << (16 - rbits); + while (rbits < 16) { + *red |= *red >> rbits; + rbits <<= 1; + } + } else + *red = 0; + + if (gbits) { + *green = ((pixel >> gshift) & ((1 << gbits) - 1)) << (16 - gbits); + while (gbits < 16) { + *green |= *green >> gbits; + gbits <<= 1; + } + } else + *green = 0; + + if (bbits) { + *blue = ((pixel >> bshift) & ((1 << bbits) - 1)) << (16 - bbits); + while (bbits < 16) { + *blue |= *blue >> bbits; + bbits <<= 1; + } + } else + *blue = 0; + + if (abits) { + *alpha = + ((pixel >> ashift) & ((1 << abits) - 1)) << (16 - abits); + while (abits < 16) { + *alpha |= *alpha >> abits; + abits <<= 1; + } + } else + *alpha = 0xffff; + + return TRUE; +} + +static cairo_bool_t +_color_from_pixmap (PixmapPtr pixmap, + uint32_t src_format, + cairo_color_t *color) +{ + uint32_t pixel = _pixmap_first_pixel(pixmap); + if (! _rgba_from_pixel (pixel, + &color->red_short, + &color->green_short, + &color->blue_short, + &color->alpha_short, + src_format)) + { + return FALSE; + } + + if (color->alpha_short == 0) { + color->red_short = color->green_short = color->blue_short = 0; + color->alpha = color->red = color->green = color->blue = 0.; + return TRUE; + } + + color->alpha = color->alpha_short / (double) 0xffff; + color->red = color->red_short / (double) 0xffff / color->alpha; + color->green = color->green_short / (double) 0xffff / color->alpha; + color->blue = color->blue_short / (double) 0xffff / color->alpha; + return TRUE; +} + +static cairo_bool_t +xr_pattern_init_for_picture (cairo_pattern_union_t *pattern, + PicturePtr picture) +{ + cairo_color_t color; + + if (picture->pSourcePict) { + SourcePict *source = picture->pSourcePict; + switch (source->type) { + case SourcePictTypeSolidFill: + _color_from_pixel (&color, source->solidFill.color); + _cairo_pattern_init_solid (&pattern->solid, + &color, + CAIRO_CONTENT_COLOR_ALPHA); + break; + default: + return FALSE; + } + } else if (picture->pDrawable) { + cairo_surface_t *surface; + + if (picture->alphaMap) + return FALSE; + + if (picture->pDrawable->width == 1 && + picture->pDrawable->height == 1 && + picture->repeat == 1) + { + if (! _color_from_pixmap ((PixmapPtr) picture->pDrawable, + picture->format, + &color)) + goto use_surface; + + _cairo_pattern_init_solid (&pattern->solid, + &color, + CAIRO_CONTENT_COLOR_ALPHA); + } + else + { +use_surface: + surface = xr_drawable_get_surface (picture->pDrawable); + _cairo_pattern_init_for_surface (&pattern->surface, + surface); + cairo_surface_destroy (surface); + } + } else { + return FALSE; + } + + if (! picture->repeat) { + pattern->base.extend = CAIRO_EXTEND_NONE; + } else switch (picture->repeatType) { + case RepeatNormal: + pattern->base.extend = CAIRO_EXTEND_REPEAT; + break; + case RepeatPad: + pattern->base.extend = CAIRO_EXTEND_PAD; + break; + case RepeatReflect: + pattern->base.extend = CAIRO_EXTEND_REFLECT; + break; + default: + goto fail; + } + + switch (picture->filter) { + case PictFilterNearest: + pattern->base.filter = CAIRO_FILTER_NEAREST; + break; + case PictFilterBilinear: + pattern->base.filter = CAIRO_FILTER_BILINEAR; + break; + case PictFilterFast: + pattern->base.filter = CAIRO_FILTER_FAST; + break; + case PictFilterGood: + pattern->base.filter = CAIRO_FILTER_GOOD; + break; + case PictFilterBest: + pattern->base.filter = CAIRO_FILTER_BEST; + break; + default: + goto fail; + } + + return TRUE; + +fail: + _cairo_pattern_fini (&pattern->base); + return FALSE; +} + +static cairo_bool_t +_render_operator (CARD8 render_op, cairo_operator_t *op) +{ + switch (render_op) { + case PictOpClear: *op = CAIRO_OPERATOR_CLEAR; break; + case PictOpSrc: *op = CAIRO_OPERATOR_SOURCE; break; + case PictOpOver: *op = CAIRO_OPERATOR_OVER; break; + case PictOpIn: *op = CAIRO_OPERATOR_IN; break; + case PictOpOut: *op = CAIRO_OPERATOR_OUT; break; + case PictOpAtop: *op = CAIRO_OPERATOR_ATOP; break; + case PictOpDst: *op = CAIRO_OPERATOR_DEST; break; + case PictOpOverReverse: *op = CAIRO_OPERATOR_DEST_OVER; break; + case PictOpInReverse: *op = CAIRO_OPERATOR_DEST_IN; break; + case PictOpOutReverse: *op = CAIRO_OPERATOR_DEST_OUT; break; + case PictOpAtopReverse: *op = CAIRO_OPERATOR_DEST_ATOP; break; + case PictOpXor: *op = CAIRO_OPERATOR_XOR; break; + case PictOpAdd: *op = CAIRO_OPERATOR_ADD; break; + case PictOpSaturate: *op = CAIRO_OPERATOR_SATURATE; break; + case PictOpMultiply: *op = CAIRO_OPERATOR_MULTIPLY; break; + case PictOpScreen: *op = CAIRO_OPERATOR_SCREEN; break; + case PictOpOverlay: *op = CAIRO_OPERATOR_OVERLAY; break; + case PictOpDarken: *op = CAIRO_OPERATOR_DARKEN; break; + case PictOpLighten: *op = CAIRO_OPERATOR_LIGHTEN; break; + case PictOpColorDodge: *op = CAIRO_OPERATOR_COLOR_DODGE; break; + case PictOpColorBurn: *op = CAIRO_OPERATOR_COLOR_BURN; break; + case PictOpHardLight: *op = CAIRO_OPERATOR_HARD_LIGHT; break; + case PictOpSoftLight: *op = CAIRO_OPERATOR_SOFT_LIGHT; break; + case PictOpDifference: *op = CAIRO_OPERATOR_DIFFERENCE; break; + case PictOpExclusion: *op = CAIRO_OPERATOR_EXCLUSION; break; + case PictOpHSLHue: *op = CAIRO_OPERATOR_HSL_HUE; break; + case PictOpHSLSaturation: *op = CAIRO_OPERATOR_HSL_SATURATION; break; + case PictOpHSLColor: *op = CAIRO_OPERATOR_HSL_COLOR; break; + case PictOpHSLLuminosity: *op = CAIRO_OPERATOR_HSL_LUMINOSITY; break; + + default: return FALSE; + } + + return TRUE; +} + +static void +xr_picture_get_clip (PicturePtr picture, + cairo_clip_t *clip) +{ + cairo_status_t status; + + _cairo_clip_init (clip); + + if (picture->pCompositeClip) { + cairo_path_fixed_t path; + BoxPtr pbox; + int nbox; + + nbox = REGION_NUM_RECTS (picture->pCompositeClip); + pbox = REGION_RECTS (picture->pCompositeClip); + _cairo_path_fixed_init (&path); + while (nbox--) { + if (_cairo_path_fixed_move_to (&path, + _cairo_fixed_from_int (pbox->x1), + _cairo_fixed_from_int (pbox->y1)) || + _cairo_path_fixed_line_to (&path, + _cairo_fixed_from_int (pbox->x2), + _cairo_fixed_from_int (pbox->y1)) || + _cairo_path_fixed_line_to (&path, + _cairo_fixed_from_int (pbox->x2), + _cairo_fixed_from_int (pbox->y2)) || + _cairo_path_fixed_line_to (&path, + _cairo_fixed_from_int (pbox->x1), + _cairo_fixed_from_int (pbox->y2)) || + _cairo_path_fixed_close_path (&path)) + { + goto err_path; + } + } + + status = _cairo_clip_clip (clip, + &path, + CAIRO_FILL_RULE_WINDING, + 1.0, + CAIRO_ANTIALIAS_DEFAULT); + +err_path: + _cairo_path_fixed_fini (&path); + } + + (void) status; +} + +static void +xr_composite (CARD8 render_op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, INT16 ySrc, + INT16 xMask, INT16 yMask, + INT16 xDst, INT16 yDst, + CARD16 width, CARD16 height) +{ + cairo_pattern_union_t source, mask; + cairo_operator_t op; + cairo_surface_t *surface; + cairo_clip_t clip; + cairo_rectangle_int_t rect; + cairo_bool_t mask_is_clipped = FALSE, source_is_clipped = FALSE; + cairo_status_t status; + + if (! _render_operator (render_op, &op)) + goto fallback; + + if (! xr_pattern_init_for_picture (&source, pSrc)) + goto fallback; + + cairo_matrix_translate (&source.base.matrix, + xSrc - xDst, ySrc - yDst); + + if (pMask) { + if (! xr_pattern_init_for_picture (&mask, pMask)) { + _cairo_pattern_fini (&source.base); + goto fallback; + } + + cairo_matrix_translate (&mask.base.matrix, + xMask - xDst, yMask - yDst); + } + + xr_picture_get_clip (pDst, &clip); + rect.x = xDst; + rect.y = yDst; + rect.width = width; + rect.height = height; + status = _cairo_clip_rectangle (&clip, &rect); + +#if 0 + { + cairo_clip_t clip_source; + + xr_picture_get_clip (pSrc, &clip_source); + if (clip_source.path != NULL) { + _cairo_clip_apply_clip (&clip, &clip_source); + source_is_clipped = TRUE; + } + _cairo_clip_fini (&clip_source); + } + if (pMask) { + cairo_clip_t clip_mask; + + xr_picture_get_clip (pMask, &clip_mask); + if (clip_mask.path != NULL) { + _cairo_clip_apply_clip (&clip, &clip_mask); + mask_is_clipped = TRUE; + } + _cairo_clip_fini (&clip_mask); + } +#endif + + surface = xr_drawable_get_surface (pDst->pDrawable); + if (! clip.all_clipped) { + if (pMask) { + status = _cairo_surface_mask (surface, op, + &source.base, + &mask.base, + &clip); + } else { + status = _cairo_surface_paint (surface, op, + &source.base, + &clip); + } + } + +#if 0 + if (source_is_clipped) { + /* clear areas in dst where source was clipped */ + cairo_surface_t *surface; + cairo_clip_t clip_source; + + if (pMask) { + cairo_clip_t clip_mask; + + xr_picture_get_clip (pMask, &clip_mask); + if (clip_mask.path != NULL) { + _cairo_clip_apply_clip (&local_clip, &clip_mask); + mask_is_clipped = TRUE; + } + _cairo_clip_fini (&clip_mask); + } + + xr_picture_get_inverse_clip (pSrc, &clip_source); + _cairo_clip_apply_clip (&clip_source, &clip); + + if (pMask) { + status = _cairo_surface_mask (surface, + CAIRO_OPERATOR_CLEAR, + &_cairo_pattern_clear.base, + &mask.base, + &clip_source); + } else { + status = _cairo_surface_paint (surface, + CAIRO_OPERATOR_CLEAR, + &_cairo_pattern_clear.base, + &clip_source); + } + _cairo_clip_fini (&clip_source); + } + + if (mask_is_clipped && ! _cairo_operator_bounded_by_mask (op)) { + /* clear areas in dst where mask was clipped */ + cairo_surface_t *surface; + cairo_clip_t clip_mask; + + xr_picture_get_inverse_clip (pMask, &clip_mask); + _cairo_clip_apply_clip (&clip, &clip_mask); + _cairo_clip_fini (&clip_mask); + + status = _cairo_surface_paint (surface, + CAIRO_OPERATOR_CLEAR, + &_cairo_pattern_clear.base, + &clip); + } +#endif + + cairo_surface_destroy (surface); + _cairo_clip_fini (&clip); + + if (pMask) + _cairo_pattern_fini (&mask.base); + _cairo_pattern_fini (&source.base); + + return; + +fallback: + { + cairo_surface_t *dst_image, *src_image, *mask_image; + //ErrorF ("fallback: %s\n", __FUNCTION__); + if (xr_prepare_access (pDst->pDrawable, &dst_image)) { + if (pSrc->pDrawable == NULL || + xr_prepare_access (pSrc->pDrawable, &src_image)) + { + if (pMask == NULL || pMask->pDrawable == NULL || + xr_prepare_access (pMask->pDrawable, &mask_image)) + { + fbComposite (op, pSrc, pMask, pDst, + xSrc, ySrc, + xMask, yMask, + xDst, yDst, + width, height); + if (pMask && pMask->pDrawable) + xr_finish_access (pMask->pDrawable, mask_image); + } + if (pSrc->pDrawable) + xr_finish_access (pSrc->pDrawable, src_image); + } + xr_finish_access (pDst->pDrawable, dst_image); + } + } +} + +static void +xr_glyphs (CARD8 op, + PicturePtr pSrc, + PicturePtr pDst, + PictFormatPtr maskFormat, + INT16 xSrc, INT16 ySrc, + int nlist, + GlyphListPtr list, + GlyphPtr *glyphs) +{ +} + +static cairo_bool_t +xr_do_fill (cairo_operator_t op, + PicturePtr pSrc, + PicturePtr pDst, + int src_x, + int src_y, + cairo_path_fixed_t *path) +{ + cairo_pattern_union_t source; + cairo_clip_t clip; + cairo_surface_t *surface; + cairo_status_t status; + + if (! xr_pattern_init_for_picture (&source, pSrc)) + return FALSE; + + cairo_matrix_translate (&source.base.matrix, src_x, src_y); + + surface = xr_drawable_get_surface (pDst->pDrawable); + xr_picture_get_clip (pDst, &clip); + status = _cairo_surface_fill (surface, op, &source.base, path, + CAIRO_FILL_RULE_WINDING, + pDst->polyEdge == PolyEdgeSharp ? CAIRO_ANTIALIAS_NONE : CAIRO_ANTIALIAS_DEFAULT, + CAIRO_GSTATE_TOLERANCE_DEFAULT, + clip.path ? &clip : NULL); + _cairo_clip_fini (&clip); + cairo_surface_destroy (surface); + _cairo_pattern_fini (&source.base); + + return TRUE; +} + +static void +xr_composite_rects (CARD8 render_op, + PicturePtr picture, + xRenderColor *xColor, + int nrect, + xRectangle *rect) +{ + cairo_operator_t op; + cairo_clip_t clip; + cairo_surface_t *surface; + cairo_status_t status; + + if (! _render_operator (render_op, &op)) + goto fallback; + + surface = xr_drawable_get_surface (picture->pDrawable); + xr_picture_get_clip (picture, &clip); + if (clip.path == NULL && nrect == 1 && + rect->x <= 0 && + rect->y <= 0 && + rect->width >= picture->pDrawable->width && + rect->height >= picture->pDrawable->height && + (op == CAIRO_OPERATOR_CLEAR || (op == CAIRO_OPERATOR_SOURCE && xColor->alpha <= 0x00ff))) + { + status = _cairo_surface_paint (surface, + CAIRO_OPERATOR_CLEAR, + &_cairo_pattern_clear.base, + NULL); + } + else + { + cairo_path_fixed_t path; + cairo_fixed_t x_off, y_off; + cairo_solid_pattern_t pattern; + cairo_color_t color; + int n; + + x_off = _cairo_fixed_from_int (picture->pDrawable->x); + y_off = _cairo_fixed_from_int (picture->pDrawable->y); + _cairo_path_fixed_init (&path); + for (n = 0; n < nrect; n++) { + cairo_fixed_t x1 = x_off + _cairo_fixed_from_int (rect[n].x); + cairo_fixed_t x2 = x1 + _cairo_fixed_from_int (rect[n].width); + cairo_fixed_t y1 = y_off + _cairo_fixed_from_int (rect[n].y); + cairo_fixed_t y2 = y1 + _cairo_fixed_from_int (rect[n].height); + + if (_cairo_path_fixed_move_to (&path, x1, y1) || + _cairo_path_fixed_line_to (&path, x2, y1) || + _cairo_path_fixed_line_to (&path, x2, y2) || + _cairo_path_fixed_line_to (&path, x1, y2) || + _cairo_path_fixed_close_path (&path)) + { + goto err_path; + } + } + + color.red_short = xColor->red; + color.green_short = xColor->green; + color.blue_short = xColor->blue; + color.alpha_short = xColor->alpha; + if (color.alpha_short <= 0x00ff) { + color.red_short = color.green_short = color.blue_short = 0; + color.alpha = color.red = color.green = color.blue = 0.; + } else { + color.alpha = color.alpha_short / (double) 0xffff; + color.red = color.red_short / (double) 0xffff / color.alpha; + color.green = color.green_short / (double) 0xffff / color.alpha; + color.blue = color.blue_short / (double) 0xffff / color.alpha; + } + _cairo_pattern_init_solid (&pattern, &color, CAIRO_CONTENT_COLOR); + + status = _cairo_surface_fill (surface, op, + &pattern.base, + &path, + CAIRO_FILL_RULE_WINDING, + 1., + CAIRO_ANTIALIAS_DEFAULT, + clip.path ? &clip : NULL); +err_path: + _cairo_path_fixed_fini (&path); + } + + cairo_surface_destroy (surface); + _cairo_clip_fini (&clip); + + (void) status; + return; + +fallback: + //ErrorF ("fallback: %s\n", __FUNCTION__); +#if 0 + { + cairo_surface_t *dst_image, *src_image; + if (xr_prepare_access (pDst->pDrawable, &dst_image)) { + if (pSrc->pDrawable == NULL || + xr_prepare_access (pSrc->pDrawable, &src_image)) + { + fbTrapezoids (op, pSrc, pDst, + maskFormat, + xSrc, ySrc, + ntrap, traps); + if (pSrc->pDrawable) + xr_finish_access (pSrc->pDrawable, src_image); + } + xr_finish_access (pDst->pDrawable, dst_image); + } + } +#endif + return; +} + +static void +xr_trapezoids (CARD8 render_op, + PicturePtr pSrc, + PicturePtr pDst, + PictFormatPtr maskFormat, + INT16 xSrc, + INT16 ySrc, + int ntrap, + xTrapezoid *traps) +{ + cairo_path_fixed_t path; + cairo_operator_t op; + int src_x, src_y; + + if (! _render_operator (render_op, &op)) + goto fallback; + + src_x = xSrc - (traps->left.p1.x >> 16); + src_y = ySrc - (traps->left.p1.y >> 16); + + _cairo_path_fixed_init (&path); + while (ntrap--) { + if (traps->bottom > traps->top) { + cairo_fixed_t x1, x2; + cairo_fixed_t y1, y2; + + if (traps->left.p1.y != traps->top) { + double x; + + x = _cairo_fixed_16_16_to_double (traps->left.p1.x) + + _cairo_fixed_16_16_to_double (traps->left.p1.x - traps->left.p2.x) * + _cairo_fixed_16_16_to_double (traps->top - traps->left.p2.y) / + _cairo_fixed_16_16_to_double (traps->left.p1.y - traps->left.p2.y); + + x1 = _cairo_fixed_from_double (x); + } else { + x1 = _cairo_fixed_from_16_16 (traps->left.p1.x); + } + + if (traps->right.p1.y != traps->top) { + double x; + + x = _cairo_fixed_16_16_to_double (traps->right.p1.x) + + _cairo_fixed_16_16_to_double (traps->right.p1.x - traps->right.p2.x) * + _cairo_fixed_16_16_to_double (traps->top - traps->right.p2.y) / + _cairo_fixed_16_16_to_double (traps->right.p1.y - traps->right.p2.y); + + x2 = _cairo_fixed_from_double (x); + } else { + x2 = _cairo_fixed_from_16_16 (traps->left.p2.x); + } + + y1 = _cairo_fixed_from_16_16 (traps->top); + y2 = _cairo_fixed_from_16_16 (traps->bottom); + + if (_cairo_path_fixed_move_to (&path, x1, y1) || + _cairo_path_fixed_line_to (&path, x2, y1) || + _cairo_path_fixed_line_to (&path, x2, y2) || + _cairo_path_fixed_line_to (&path, x1, y2) || + _cairo_path_fixed_close_path (&path)) + { + goto err_path; + } + } + + traps++; + } + + if (! xr_do_fill (op, pSrc, pDst, src_x, src_y, &path)) { + _cairo_path_fixed_fini (&path); + goto fallback; + } + +err_path: + _cairo_path_fixed_fini (&path); + + return; + +fallback: + //ErrorF ("fallback: %s\n", __FUNCTION__); +#if 0 + { + cairo_surface_t *dst_image, *src_image; + if (xr_prepare_access (pDst->pDrawable, &dst_image)) { + if (pSrc->pDrawable == NULL || + xr_prepare_access (pSrc->pDrawable, &src_image)) + { + fbTrapezoids (op, pSrc, pDst, + maskFormat, + xSrc, ySrc, + ntrap, traps); + if (pSrc->pDrawable) + xr_finish_access (pSrc->pDrawable, src_image); + } + xr_finish_access (pDst->pDrawable, dst_image); + } + } +#endif + return; +} + +static void +xr_triangles (CARD8 render_op, + PicturePtr pSrc, + PicturePtr pDst, + PictFormatPtr maskFormat, + INT16 xSrc, + INT16 ySrc, + int ntriangles, + xTriangle *triangles) +{ + cairo_path_fixed_t path; + cairo_operator_t op; + int src_x, src_y; + + if (! _render_operator (render_op, &op)) + goto fallback; + + src_x = xSrc - (triangles->p1.x >> 16); + src_y = ySrc - (triangles->p1.y >> 16); + + _cairo_path_fixed_init (&path); + while (ntriangles--) { + if (_cairo_path_fixed_move_to (&path, + _cairo_fixed_from_16_16 (triangles->p1.x), + _cairo_fixed_from_16_16 (triangles->p1.y)) || + _cairo_path_fixed_line_to (&path, + _cairo_fixed_from_16_16 (triangles->p2.x), + _cairo_fixed_from_16_16 (triangles->p2.y)) || + _cairo_path_fixed_line_to (&path, + _cairo_fixed_from_16_16 (triangles->p3.x), + _cairo_fixed_from_16_16 (triangles->p3.y)) || + _cairo_path_fixed_close_path (&path)) + { + goto err_path; + } + + triangles++; + } + + if (! xr_do_fill (op, pSrc, pDst, src_x, src_y, &path)) { + _cairo_path_fixed_fini (&path); + goto fallback; + } + +err_path: + _cairo_path_fixed_fini (&path); + + return; + +fallback: + //ErrorF ("fallback: %s\n", __FUNCTION__); +#if 0 + { + cairo_surface_t *dst_image, *src_image; + if (xr_prepare_access (pDst->pDrawable, &dst_image)) { + if (pSrc->pDrawable == NULL || + xr_prepare_access (pSrc->pDrawable, &src_image)) + { + fbTriangles (op, pSrc, pDst, + maskFormat, + xSrc, ySrc, + ntriangles, triangles); + if (pSrc->pDrawable) + xr_finish_access (pSrc->pDrawable, src_image); + } + xr_finish_access (pDst->pDrawable, dst_image); + } + } +#endif + return; +} + +static void +xr_tristrip (CARD8 op, + PicturePtr pSrc, + PicturePtr pDst, + PictFormatPtr maskFormat, + INT16 xSrc, + INT16 ySrc, + int npoints, + xPointFixed *points) +{ + //ErrorF ("fallback: %s\n", __FUNCTION__); +#if 0 + { + cairo_surface_t *dst_image, *src_image; + if (xr_prepare_access (pDst->pDrawable, &dst_image)) { + if (pSrc->pDrawable == NULL || + xr_prepare_access (pSrc->pDrawable, &src_image)) + { + fbTriStrip (op, pSrc, pDst, + maskFormat, + xSrc, ySrc, + npoints, points); + if (pSrc->pDrawable) + xr_finish_access (pSrc->pDrawable, src_image); + } + xr_finish_access (pDst->pDrawable, dst_image); + } + } +#endif +} + +static void +xr_trifan (CARD8 render_op, + PicturePtr pSrc, + PicturePtr pDst, + PictFormatPtr maskFormat, + INT16 xSrc, + INT16 ySrc, + int npoints, + xPointFixed *points) +{ + cairo_path_fixed_t path; + cairo_operator_t op; + int src_x, src_y; + + if (! _render_operator (render_op, &op)) + goto fallback; + + src_x = xSrc - (points->x >> 16); + src_y = ySrc - (points->y >> 16); + + _cairo_path_fixed_init (&path); + points++; + while (--npoints) { + if (_cairo_path_fixed_line_to (&path, + _cairo_fixed_from_16_16 (points->x), + _cairo_fixed_from_16_16 (points->y))) + { + goto err_path; + } + + points++; + } + if (_cairo_path_fixed_close_path (&path)) + goto err_path; + + if (! xr_do_fill (op, pSrc, pDst, src_x, src_y, &path)) { + _cairo_path_fixed_fini (&path); + goto fallback; + } + +err_path: + _cairo_path_fixed_fini (&path); + + return; + +fallback: + //ErrorF ("fallback: %s\n", __FUNCTION__); +#if 0 + { + cairo_surface_t *dst_image, *src_image; + if (xr_prepare_access (pDst->pDrawable, &dst_image)) { + if (pSrc->pDrawable == NULL || + xr_prepare_access (pSrc->pDrawable, &src_image)) + { + fbTriFan (op, pSrc, pDst, + maskFormat, + xSrc, ySrc, + npoints, points); + if (pSrc->pDrawable) + xr_finish_access (pSrc->pDrawable, src_image); + } + xr_finish_access (pDst->pDrawable, dst_image); + } + } +#endif + return; +} + +static void +xr_add_triangles (PicturePtr picture, + INT16 x_off, INT16 y_off, + int ntriangle, xTriangle *triangles) +{ + cairo_path_fixed_t path; + cairo_clip_t clip; + cairo_surface_t *surface; + cairo_status_t status; + int x, y; + + x = _cairo_fixed_from_int (x_off); + y = _cairo_fixed_from_int (y_off); + + _cairo_path_fixed_init (&path); + while (ntriangle--) { + if (_cairo_path_fixed_move_to (&path, + x + _cairo_fixed_from_16_16 (triangles->p1.x), + y + _cairo_fixed_from_16_16 (triangles->p1.y)) || + _cairo_path_fixed_line_to (&path, + x + _cairo_fixed_from_16_16 (triangles->p2.x), + y + _cairo_fixed_from_16_16 (triangles->p2.y)) || + _cairo_path_fixed_line_to (&path, + x + _cairo_fixed_from_16_16 (triangles->p3.x), + y + _cairo_fixed_from_16_16 (triangles->p3.y)) || + _cairo_path_fixed_close_path (&path)) + { + goto err_path; + } + + triangles++; + } + + surface = xr_drawable_get_surface (picture->pDrawable); + xr_picture_get_clip (picture, &clip); + status = _cairo_surface_fill (surface, + CAIRO_OPERATOR_ADD, + &_cairo_pattern_white.base, + &path, + CAIRO_FILL_RULE_WINDING, + picture->polyEdge == PolyEdgeSharp ? CAIRO_ANTIALIAS_NONE : CAIRO_ANTIALIAS_DEFAULT, + CAIRO_GSTATE_TOLERANCE_DEFAULT, + clip.path ? &clip : NULL); + _cairo_clip_fini (&clip); + cairo_surface_destroy (surface); + +err_path: + _cairo_path_fixed_fini (&path); +} + +static void +xr_add_traps (PicturePtr picture, + INT16 x_off, INT16 y_off, + int ntrap, xTrap * traps) +{ + cairo_path_fixed_t path; + cairo_clip_t clip; + cairo_surface_t *surface; + cairo_status_t status; + int x, y; + + x = _cairo_fixed_from_int (x_off); + y = _cairo_fixed_from_int (y_off); + + _cairo_path_fixed_init (&path); + while (ntrap--) { + if (_cairo_path_fixed_move_to (&path, + x + _cairo_fixed_from_16_16 (traps->top.l), + y + _cairo_fixed_from_16_16 (traps->top.y)) || + _cairo_path_fixed_line_to (&path, + x + _cairo_fixed_from_16_16 (traps->top.r), + y + _cairo_fixed_from_16_16 (traps->top.y)) || + _cairo_path_fixed_line_to (&path, + x + _cairo_fixed_from_16_16 (traps->bot.r), + y + _cairo_fixed_from_16_16 (traps->bot.y)) || + _cairo_path_fixed_move_to (&path, + x + _cairo_fixed_from_16_16 (traps->bot.l), + y + _cairo_fixed_from_16_16 (traps->bot.y)) || + _cairo_path_fixed_close_path (&path)) + { + goto err_path; + } + + traps++; + } + + surface = xr_drawable_get_surface (picture->pDrawable); + xr_picture_get_clip (picture, &clip); + status = _cairo_surface_fill (surface, + CAIRO_OPERATOR_ADD, + &_cairo_pattern_white.base, + &path, + CAIRO_FILL_RULE_WINDING, + picture->polyEdge == PolyEdgeSharp ? CAIRO_ANTIALIAS_NONE : CAIRO_ANTIALIAS_DEFAULT, + CAIRO_GSTATE_TOLERANCE_DEFAULT, + clip.path ? &clip : NULL); + _cairo_clip_fini (&clip); + cairo_surface_destroy (surface); + +err_path: + _cairo_path_fixed_fini (&path); +} + +static Bool +xr_realize_glyph (ScreenPtr screen, GlyphPtr glyph) +{ + return TRUE; +} + +static void +xr_unrealize_glyph (ScreenPtr screen, GlyphPtr glyph) +{ +} + +static PixmapPtr +xr_create_pixmap (ScreenPtr screen, + int w, int h, int depth, + unsigned usage) +{ + xr_screen_t *xr = xr_get_screen (screen); + PixmapPtr pixmap; + + if (w > 32767 || h > 32767) + return NullPixmap; + + if (usage == CREATE_PIXMAP_USAGE_GLYPH_PICTURE) + return fbCreatePixmap (screen, w, h, depth, usage); + + if (w && h) { + cairo_surface_t *surface; + cairo_format_t format; + + format = xr_format_for_depth (depth); + surface = cairo_drm_surface_create (xr->device, format, w, h); + if (unlikely (surface->status)) + goto fallback; + + pixmap = fbCreatePixmap (screen, 0, 0, depth, usage); + screen->ModifyPixmapHeader (pixmap, w, h, 0, 0, + cairo_drm_surface_get_stride (surface), + NULL); + dixSetPrivate (&pixmap->devPrivates, &xr_pixmap_index, surface); + } else { +fallback: + pixmap = fbCreatePixmap (screen, w, h, depth, usage); + } + + return pixmap; +} + +static Bool +xr_destroy_pixmap (PixmapPtr pixmap) +{ + if (pixmap->refcnt == 1) + cairo_surface_destroy (&xr_pixmap_get_drm_surface (pixmap)->base); + + fbDestroyPixmap(pixmap); + return TRUE; +} + +static Bool +xr_close_screen (int i, ScreenPtr screen) +{ + xr_screen_t *xr = xr_get_screen(screen); + + screen->CreateGC = xr->SavedCreateGC; + screen->CloseScreen = xr->SavedCloseScreen; + screen->GetImage = xr->SavedGetImage; + screen->GetSpans = xr->SavedGetSpans; + screen->CreatePixmap = xr->SavedCreatePixmap; + screen->DestroyPixmap = xr->SavedDestroyPixmap; + screen->CopyWindow = xr->SavedCopyWindow; + screen->ChangeWindowAttributes = + xr->SavedChangeWindowAttributes; + screen->BitmapToRegion = xr->SavedBitmapToRegion; +#ifdef RENDER + { + PictureScreenPtr ps = GetPictureScreenIfSet(screen); + if (ps) { + ps->Composite = xr->SavedComposite; + ps->Glyphs = xr->SavedGlyphs; + ps->CompositeRects = xr->SavedCompositeRects; + ps->Trapezoids = xr->SavedTrapezoids; + ps->Triangles = xr->SavedTriangles; + ps->TriStrip = xr->SavedTriStrip; + ps->TriFan = xr->SavedTriFan; + ps->AddTriangles = xr->SavedAddTriangles; + ps->AddTraps = xr->SavedAddTraps; + ps->RealizeGlyph = xr->SavedRealizeGlyph; + ps->UnrealizeGlyph = xr->SavedUnrealizeGlyph; + } + } +#endif + + cairo_device_destroy (xr->device); + xfree (xr); + + return screen->CloseScreen (i, screen); +} + +static void +xr_block_handler (void *data, OSTimePtr timeout, void *last_select_mask) +{ + xr_screen_t *xr = data; + + cairo_device_flush (xr->device); + cairo_drm_device_throttle (xr->device); +} + +static void +xr_wakeup_handler (void *data, int result, void *last_select_mask) +{ +} + +xr_screen_t * +cairo_drm_xr_enable (ScreenPtr screen, int fd) +{ + xr_screen_t *xr; + cairo_device_t *device; + + device = cairo_drm_device_get_for_fd (fd); + if (device == NULL) + return NULL; + + xr = malloc (sizeof (*xr)); + if (unlikely (xr == NULL)) + goto cleanup_device; + + xr->device = device; + dixSetPrivate (&screen->devPrivates, + &xr_screen_index, + xr); + + if (! dixRequestPrivate(&xr_pixmap_index, 0)) + goto cleanup_driver; + + if (! RegisterBlockAndWakeupHandlers (xr_block_handler, + xr_wakeup_handler, + xr)) + { + goto cleanup_driver; + } + + /* wrap the screen interfaces */ + xr->SavedCloseScreen = screen->CloseScreen; + screen->CloseScreen = xr_close_screen; + + xr->SavedCreateGC = screen->CreateGC; + screen->CreateGC = xr_create_gc; + + xr->SavedGetImage = screen->GetImage; + screen->GetImage = xr_get_image; + + xr->SavedGetSpans = screen->GetSpans; + screen->GetSpans = xr_get_spans; + + xr->SavedCopyWindow = screen->CopyWindow; + screen->CopyWindow = xr_copy_window; + + xr->SavedChangeWindowAttributes = + screen->ChangeWindowAttributes; + screen->ChangeWindowAttributes = xr_change_window_attributes; + + xr->SavedBitmapToRegion = screen->BitmapToRegion; + screen->BitmapToRegion = xr_bitmap_to_region; + +#ifdef RENDER + { + PictureScreenPtr ps = GetPictureScreenIfSet(screen); + if (ps) { + xr->SavedComposite = ps->Composite; + ps->Composite = xr_composite; + + xr->SavedGlyphs = ps->Glyphs; + ps->Glyphs = xr_glyphs; + + xr->SavedCompositeRects = ps->CompositeRects; + ps->CompositeRects = xr_composite_rects; + + xr->SavedTrapezoids = ps->Trapezoids; + ps->Trapezoids = xr_trapezoids; + + xr->SavedTriangles = ps->Triangles; + ps->Triangles = xr_triangles; + + xr->SavedTriStrip = ps->TriStrip; + ps->TriStrip = xr_tristrip; + + xr->SavedTriFan = ps->TriFan; + ps->TriFan = xr_trifan; + + xr->SavedAddTriangles = ps->AddTriangles; + ps->AddTriangles = xr_add_triangles; + + xr->SavedAddTraps = ps->AddTraps; + ps->AddTraps = xr_add_traps; + + xr->SavedRealizeGlyph = ps->RealizeGlyph; + ps->RealizeGlyph = xr_realize_glyph; + + xr->SavedUnrealizeGlyph = ps->UnrealizeGlyph; + ps->UnrealizeGlyph = xr_unrealize_glyph; + } + } +#endif + +#ifdef MITSHM +#if 0 + /* Re-register with the MI funcs, which don't allow shared pixmaps. + * Shared pixmaps are almost always a performance loss for us, but this + * still allows for SHM PutImage. + */ + { + static ShmFuncs xr_shm_funcs = { NULL, NULL }; + ShmRegisterFuncs (screen, &xr_shm_funcs); + } +#endif +#endif + + screen->CreatePixmap = xr_create_pixmap; + screen->DestroyPixmap = xr_destroy_pixmap; + + LogMessage (X_INFO, + "XR(%d): Driver registered support.\n", screen->myNum); + + return xr; + +cleanup_driver: + free (xr); +cleanup_device: + cairo_device_destroy (device); + return NULL; +} + +void +cairo_drm_xr_pixmap_link_bo (xr_screen_t *xr, + PixmapPtr pixmap, + uint32_t name, + cairo_format_t format, + int width, + int height, + int stride) +{ + cairo_surface_t *surface; + + cairo_surface_destroy (dixLookupPrivate (&pixmap->devPrivates, + &xr_pixmap_index)); + + surface = cairo_drm_surface_create_for_name (xr->device, name, format, + width, height, stride); + dixSetPrivate (&pixmap->devPrivates, &xr_pixmap_index, surface); +} + +void +cairo_drm_xr_pixmap_unlink_bo (xr_screen_t *xr, + PixmapPtr pixmap) +{ + cairo_surface_destroy (dixLookupPrivate (&pixmap->devPrivates, + &xr_pixmap_index)); + + dixSetPrivate (&pixmap->devPrivates, &xr_pixmap_index, NULL); +} |