summaryrefslogtreecommitdiff
path: root/src/cairo-xcb-connection-core.c
diff options
context:
space:
mode:
authorUli Schlachter <psychon@znc.in>2010-12-04 16:36:28 +0100
committerChris Wilson <chris@chris-wilson.co.uk>2010-12-25 09:50:34 +0000
commit109fcb39502239ff87c70cc99f2baea6e46b36a5 (patch)
tree1763e250a56c4ed126b4be27ff65c81c43568be8 /src/cairo-xcb-connection-core.c
parentcf0a4ed862d93b7e6d7d26942cfe98a50beccd4c (diff)
downloadcairo-109fcb39502239ff87c70cc99f2baea6e46b36a5.tar.gz
XCB: Stop taking the xcb socket
This makes the xcb backend use the auto-generated xcb API instead of hand-writing each request. This should also improve parallelism with non-cairo threads that use the same xcb connection. Big thanks to Andrea Canciani for taking a look at this and finding lots of good improvements (especially finding xcb_send_request was great). cairo-perf-trace and cairo-perf-diff-files between master (6732dbf2992891be4b1f08b14a5c449fd08b637c) and this change: $ ./cairo-perf-diff-files ../master_perf ../xcb_no_socket_perf old: master_perf new: xcb_no_socket_perf Speedups ======== xcb-rgba evolution-0 23558.86 (23558.86 0.00%) -> 19338.78 (19338.78 0.00%): 1.22x speedup ▎ xcb-rgba poppler-bug-12266-0 98.43 (98.43 0.00%) -> 82.36 (82.36 0.00%): 1.20x speedup ▎ xcb-rgba gnome-terminal-vim-0 5518.08 (5518.08 0.00%) -> 4905.92 (4905.92 0.00%): 1.12x speedup ▏ xcb-rgba gnome-terminal-20090601-0 45648.46 (45648.46 0.00%) -> 41231.25 (41231.25 0.00%): 1.11x speedup ▏ xcb-rgba evolution-20090607-0 71643.69 (71643.69 0.00%) -> 66314.95 (66314.95 0.00%): 1.08x speedup ▏ xcb-rgba poppler-0 3501.69 (3501.69 0.00%) -> 3322.26 (3322.26 0.00%): 1.05x speedup Slowdowns ========= xcb-rgba gnome-system-monitor-0 7500.01 (7500.01 0.00%) -> 7923.70 (7923.70 0.00%): 1.06x slowdown xcb-rgba swfdec-youtube-full-0 26409.89 (26409.89 0.00%) -> 28430.76 (28430.76 0.00%): 1.08x slowdown ▏ xcb-rgba gnome-system-monitor-20090821-0 34801.61 (34801.61 0.00%) -> 37891.14 (37891.14 0.00%): 1.09x slowdown Signed-off-by: Uli Schlachter <psychon@znc.in>
Diffstat (limited to 'src/cairo-xcb-connection-core.c')
-rw-r--r--src/cairo-xcb-connection-core.c336
1 files changed, 61 insertions, 275 deletions
diff --git a/src/cairo-xcb-connection-core.c b/src/cairo-xcb-connection-core.c
index 5b16c1994..089cc4e6b 100644
--- a/src/cairo-xcb-connection-core.c
+++ b/src/cairo-xcb-connection-core.c
@@ -42,53 +42,18 @@ _cairo_xcb_connection_create_pixmap (cairo_xcb_connection_t *connection,
uint16_t width,
uint16_t height)
{
- struct {
- uint8_t req;
- uint8_t depth;
- uint16_t len;
- uint32_t pixmap;
- uint32_t drawable;
- uint16_t width, height;
- } req;
- struct iovec vec[1];
-
- req.req = 53;
- req.depth = depth;
- req.len = sizeof (req) >> 2;
-
- req.pixmap = _cairo_xcb_connection_get_xid (connection);
- req.drawable = drawable;
- req.width = width;
- req.height = height;
-
- vec[0].iov_base = &req;
- vec[0].iov_len = sizeof (req);
-
- _cairo_xcb_connection_write (connection, vec, 1);
-
- return req.pixmap;
+ xcb_pixmap_t pixmap = _cairo_xcb_connection_get_xid (connection);
+ xcb_create_pixmap (connection->xcb_connection,
+ depth, pixmap, drawable,
+ width, height);
+ return pixmap;
}
void
_cairo_xcb_connection_free_pixmap (cairo_xcb_connection_t *connection,
xcb_pixmap_t pixmap)
{
- struct {
- uint8_t req;
- uint8_t pad;
- uint16_t len;
- uint32_t pixmap;
- } req;
- struct iovec vec[1];
-
- req.req = 54;
- req.len = sizeof (req) >> 2;
- req.pixmap = pixmap;
-
- vec[0].iov_base = &req;
- vec[0].iov_len = sizeof (req);
-
- _cairo_xcb_connection_write (connection, vec, 1);
+ xcb_free_pixmap (connection->xcb_connection, pixmap);
_cairo_xcb_connection_put_xid (connection, pixmap);
}
@@ -98,53 +63,17 @@ _cairo_xcb_connection_create_gc (cairo_xcb_connection_t *connection,
uint32_t value_mask,
uint32_t *values)
{
- struct {
- uint8_t req;
- uint8_t pad;
- uint16_t len;
- uint32_t gc;
- uint32_t drawable;
- uint32_t mask;
- } req;
- struct iovec vec[2];
- int len = _cairo_popcount (value_mask) * 4;
-
- req.req = 55;
- req.len = (sizeof (req) + len) >> 2;
- req.gc = _cairo_xcb_connection_get_xid (connection);
- req.drawable = drawable;
- req.mask = value_mask;
-
- vec[0].iov_base = &req;
- vec[0].iov_len = sizeof (req);
- vec[1].iov_base = values;
- vec[1].iov_len = len;
-
- _cairo_xcb_connection_write (connection, vec, 2);
-
- return req.gc;
+ xcb_gcontext_t gc = _cairo_xcb_connection_get_xid (connection);
+ xcb_create_gc (connection->xcb_connection, gc, drawable,
+ value_mask, values);
+ return gc;
}
void
_cairo_xcb_connection_free_gc (cairo_xcb_connection_t *connection,
xcb_gcontext_t gc)
{
- struct {
- uint8_t req;
- uint8_t pad;
- uint16_t len;
- uint32_t gc;
- } req;
- struct iovec vec[1];
-
- req.req = 60;
- req.len = sizeof (req) >> 2;
- req.gc = gc;
-
- vec[0].iov_base = &req;
- vec[0].iov_len = sizeof (req);
-
- _cairo_xcb_connection_write (connection, vec, 1);
+ xcb_free_gc (connection->xcb_connection, gc);
_cairo_xcb_connection_put_xid (connection, gc);
}
@@ -154,27 +83,8 @@ _cairo_xcb_connection_change_gc (cairo_xcb_connection_t *connection,
uint32_t value_mask,
uint32_t *values)
{
- struct {
- uint8_t req;
- uint8_t pad;
- uint16_t len;
- uint32_t gc;
- uint32_t mask;
- } req;
- struct iovec vec[2];
- int len = _cairo_popcount (value_mask) * 4;
-
- req.req = 56;
- req.len = (sizeof (req) + len) >> 2;
- req.gc = gc;
- req.mask = value_mask;
-
- vec[0].iov_base = &req;
- vec[0].iov_len = sizeof (req);
- vec[1].iov_base = values;
- vec[1].iov_len = len;
-
- _cairo_xcb_connection_write (connection, vec, 2);
+ xcb_change_gc (connection->xcb_connection, gc,
+ value_mask, values);
}
void
@@ -189,38 +99,8 @@ _cairo_xcb_connection_copy_area (cairo_xcb_connection_t *connection,
uint16_t width,
uint16_t height)
{
- struct {
- uint8_t req;
- uint8_t pad;
- uint16_t len;
- uint32_t src;
- uint32_t dst;
- uint32_t gc;
- int16_t src_x;
- int16_t src_y;
- int16_t dst_x;
- int16_t dst_y;
- uint16_t width;
- uint16_t height;
- } req;
- struct iovec vec[1];
-
- req.req = 62;
- req.len = sizeof (req) >> 2;
- req.src = src;
- req.dst = dst;
- req.gc = gc;
- req.src_x = src_x;
- req.src_y = src_y;
- req.dst_x = dst_x;
- req.dst_y = dst_y;
- req.width = width;
- req.height = height;
-
- vec[0].iov_base = &req;
- vec[0].iov_len = sizeof (req);
-
- _cairo_xcb_connection_write (connection, vec, 1);
+ xcb_copy_area (connection->xcb_connection, src, dst, gc,
+ src_x, src_y, dst_x, dst_y, width, height);
}
void
@@ -230,26 +110,8 @@ _cairo_xcb_connection_poly_fill_rectangle (cairo_xcb_connection_t *connection,
uint32_t num_rectangles,
xcb_rectangle_t *rectangles)
{
- struct {
- uint8_t req;
- uint8_t pad;
- uint16_t len;
- uint32_t dst;
- uint32_t gc;
- } req;
- struct iovec vec[2];
-
- req.req = 70;
- req.len = (sizeof (req) + num_rectangles * sizeof (xcb_rectangle_t)) >> 2;
- req.dst = dst;
- req.gc = gc;
-
- vec[0].iov_base = &req;
- vec[0].iov_len = sizeof (req);
- vec[1].iov_base = rectangles;
- vec[1].iov_len = num_rectangles * sizeof (xcb_rectangle_t);
-
- _cairo_xcb_connection_write (connection, vec, 2);
+ xcb_poly_fill_rectangle (connection->xcb_connection, dst, gc,
+ num_rectangles, rectangles);
}
void
@@ -264,86 +126,28 @@ _cairo_xcb_connection_put_image (cairo_xcb_connection_t *connection,
uint32_t stride,
void *data)
{
- struct {
- uint8_t req;
- uint8_t format;
- uint16_t len;
- uint32_t dst;
- uint32_t gc;
- uint16_t width;
- uint16_t height;
- int16_t dst_x;
- int16_t dst_y;
- uint8_t left;
- uint8_t depth;
- uint16_t pad;
- } req;
- struct iovec vec[3];
- uint32_t prefix[2];
+ const uint32_t req_size = 18;
uint32_t length = height * stride;
- uint32_t len = (sizeof (req) + length) >> 2;
-
- req.req = 72;
- req.format = XCB_IMAGE_FORMAT_Z_PIXMAP;
- req.len = 0;
- req.dst = dst;
- req.gc = gc;
- req.width = width;
- req.height = height;
- req.dst_x = dst_x;
- req.dst_y = dst_y;
- req.left = 0;
- req.depth = depth;
-
- if (len < connection->root->maximum_request_length) {
- req.len = len;
-
- vec[0].iov_base = &req;
- vec[0].iov_len = sizeof (req);
- vec[1].iov_base = data;
- vec[1].iov_len = length;
-
- _cairo_xcb_connection_write (connection, vec, 2);
- } else if (len < connection->maximum_request_length) {
- prefix[0] = *(uint32_t *) &req;
- prefix[1] = len + 1;
- vec[0].iov_base = prefix;
- vec[0].iov_len = sizeof (prefix);
- vec[1].iov_base = (uint32_t *) &req + 1;
- vec[1].iov_len = sizeof (req) - 4;
- vec[2].iov_base = data;
- vec[2].iov_len = length;
+ uint32_t len = (req_size + length) >> 2;
- _cairo_xcb_connection_write (connection, vec, 3);
+ if (len < connection->maximum_request_length) {
+ xcb_put_image (connection->xcb_connection, XCB_IMAGE_FORMAT_Z_PIXMAP,
+ dst, gc, width, height, dst_x, dst_y, 0, depth,
+ length, data);
} else {
- int rows;
-
- rows = (connection->maximum_request_length - sizeof (req) - 4) / stride;
+ int rows = (connection->maximum_request_length - req_size - 4) / stride;
if (rows > 0) {
do {
if (rows > height)
rows = height;
length = rows * stride;
- len = (sizeof (req) + 4 + length) >> 2;
-
- req.height = rows;
-
- prefix[0] = *(uint32_t *) &req;
- prefix[1] = len;
-
- vec[0].iov_base = prefix;
- vec[0].iov_len = sizeof (prefix);
- vec[1].iov_base = (uint32_t *) &req + 1;
- vec[1].iov_len = sizeof (req) - 4;
- vec[2].iov_base = data;
- vec[2].iov_len = length;
- /* note may modify vec */
- _cairo_xcb_connection_write (connection, vec, 3);
+ xcb_put_image (connection->xcb_connection, XCB_IMAGE_FORMAT_Z_PIXMAP,
+ dst, gc, width, rows, dst_x, dst_y, 0, depth, length, data);
height -= rows;
- req.dst_y += rows;
+ dst_y += rows;
data = (char *) data + length;
} while (height);
} else {
@@ -367,41 +171,35 @@ _cairo_xcb_connection_put_subimage (cairo_xcb_connection_t *connection,
uint8_t depth,
void *_data)
{
- struct {
- uint8_t req;
- uint8_t format;
- uint16_t len;
- uint32_t dst;
- uint32_t gc;
- uint16_t width;
- uint16_t height;
- int16_t dst_x;
- int16_t dst_y;
- uint8_t left;
- uint8_t depth;
- uint16_t pad;
- } req;
+ xcb_protocol_request_t xcb_req = {
+ 0 /* count */,
+ 0 /* ext */,
+ XCB_PUT_IMAGE /* opcode */,
+ 1 /* isvoid (doesn't cause a reply) */
+ };
+ xcb_put_image_request_t req;
struct iovec vec_stack[CAIRO_STACK_ARRAY_LENGTH (struct iovec)];
struct iovec *vec = vec_stack;
- uint32_t prefix[2];
- uint32_t len = (sizeof (req) + cpp*width*height) >> 2;
+ uint32_t len = 0;
uint8_t *data = _data;
- int n;
+ int n = 3;
+ /* Two extra entries are needed for xcb, two for us */
+ int entries_needed = height + 2 + 2;
- req.req = 72;
req.format = XCB_IMAGE_FORMAT_Z_PIXMAP;
- req.len = 0;
- req.dst = dst;
+ req.drawable = dst;
req.gc = gc;
req.width = width;
req.height = height;
req.dst_x = dst_x;
req.dst_y = dst_y;
- req.left = 0;
+ req.left_pad = 0;
req.depth = depth;
+ req.pad0[0] = 0;
+ req.pad0[1] = 0;
- if (height + 2 > ARRAY_LENGTH (vec_stack)) {
- vec = _cairo_malloc_ab (height+2, sizeof (struct iovec));
+ if (entries_needed > ARRAY_LENGTH (vec_stack)) {
+ vec = _cairo_malloc_ab (entries_needed, sizeof (struct iovec));
if (unlikely (vec == NULL)) {
/* XXX loop over ARRAY_LENGTH (vec_stack) */
return;
@@ -409,34 +207,30 @@ _cairo_xcb_connection_put_subimage (cairo_xcb_connection_t *connection,
}
data += src_y * stride + src_x * cpp;
- if (len < connection->root->maximum_request_length) {
- req.len = len;
-
- vec[0].iov_base = &req;
- vec[0].iov_len = sizeof (req);
-
- n = 1;
- } else if (len < connection->maximum_request_length) {
- prefix[0] = *(uint32_t *) &req;
- prefix[1] = len + 1;
- vec[0].iov_base = prefix;
- vec[0].iov_len = sizeof (prefix);
- vec[1].iov_base = (uint32_t *) &req + 1;
- vec[1].iov_len = sizeof (req) - 4;
-
- n = 2;
- } else {
- ASSERT_NOT_REACHED;
- }
+ /* vec[1] will be used in XCB if it has to use BigRequests or insert a sync,
+ * vec[0] is used if the internal queue needs to be flushed. */
+ vec[2].iov_base = (char *) &req;
+ vec[2].iov_len = sizeof (req);
+ /* Now comes the actual data */
while (height--) {
vec[n].iov_base = data;
vec[n].iov_len = cpp * width;
+ len += cpp * width;
data += stride;
n++;
}
- _cairo_xcb_connection_write (connection, vec, n);
+ /* And again some padding */
+ vec[n].iov_base = 0;
+ vec[n].iov_len = -len & 3;
+ n++;
+
+ /* For efficiency reasons, this functions writes the request "directly" to
+ * the xcb connection to avoid having to copy the data around. */
+ assert (n == entries_needed);
+ xcb_req.count = n - 2;
+ xcb_send_request (connection->xcb_connection, 0, &vec[2], &xcb_req);
if (vec != vec_stack)
free (vec);
@@ -452,7 +246,6 @@ _cairo_xcb_connection_get_image (cairo_xcb_connection_t *connection,
xcb_get_image_reply_t **reply)
{
xcb_generic_error_t *error;
- cairo_status_t status;
*reply = xcb_get_image_reply (connection->xcb_connection,
xcb_get_image (connection->xcb_connection,
@@ -471,12 +264,5 @@ _cairo_xcb_connection_get_image (cairo_xcb_connection_t *connection,
*reply = NULL;
}
- status = _cairo_xcb_connection_take_socket (connection);
- if (unlikely (status)) {
- if (*reply)
- free (*reply);
- *reply = NULL;
- }
-
- return status;
+ return CAIRO_STATUS_SUCCESS;
}