summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--boilerplate/Makefile.win32.features18
-rw-r--r--boilerplate/cairo-boilerplate-drm.c12
-rw-r--r--build/Makefile.win32.features1
-rw-r--r--build/Makefile.win32.features-h4
-rw-r--r--build/configure.ac.features1
-rw-r--r--configure.ac13
-rw-r--r--src/Makefile.sources7
-rw-r--r--src/Makefile.win32.features22
-rw-r--r--src/cairo-boxes-private.h4
-rw-r--r--src/cairo-boxes.c31
-rw-r--r--src/cairo-composite-rectangles.c7
-rw-r--r--src/cairo-drm-xr.h66
-rw-r--r--src/cairo-drm.h4
-rw-r--r--src/cairo-fixed-private.h18
-rw-r--r--src/cairo-freelist-private.h1
-rw-r--r--src/cairo-freelist.c7
-rw-r--r--src/cairo-image-surface.c2
-rw-r--r--src/cairo-list-private.h31
-rw-r--r--src/cairoint.h7
-rw-r--r--src/drm/cairo-drm-i915-glyphs.c82
-rw-r--r--src/drm/cairo-drm-i915-private.h153
-rw-r--r--src/drm/cairo-drm-i915-shader.c866
-rw-r--r--src/drm/cairo-drm-i915-spans.c146
-rw-r--r--src/drm/cairo-drm-i915-surface.c1698
-rw-r--r--src/drm/cairo-drm-i965-glyphs.c36
-rw-r--r--src/drm/cairo-drm-i965-private.h2
-rw-r--r--src/drm/cairo-drm-i965-shader.c11
-rw-r--r--src/drm/cairo-drm-i965-spans.c16
-rw-r--r--src/drm/cairo-drm-i965-surface.c146
-rw-r--r--src/drm/cairo-drm-intel-debug.c1
-rw-r--r--src/drm/cairo-drm-intel-ioctl-private.h25
-rw-r--r--src/drm/cairo-drm-intel-private.h92
-rw-r--r--src/drm/cairo-drm-intel-surface.c90
-rw-r--r--src/drm/cairo-drm-intel.c530
-rw-r--r--src/drm/cairo-drm-private.h10
-rw-r--r--src/drm/cairo-drm-radeon-surface.c60
-rw-r--r--src/drm/cairo-drm-surface.c37
-rw-r--r--src/drm/cairo-drm-xr.c2377
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);
+}