diff options
author | Uli Schlachter <psychon@znc.in> | 2010-12-04 16:36:28 +0100 |
---|---|---|
committer | Chris Wilson <chris@chris-wilson.co.uk> | 2010-12-25 09:50:34 +0000 |
commit | 109fcb39502239ff87c70cc99f2baea6e46b36a5 (patch) | |
tree | 1763e250a56c4ed126b4be27ff65c81c43568be8 /src/cairo-xcb-connection-core.c | |
parent | cf0a4ed862d93b7e6d7d26942cfe98a50beccd4c (diff) | |
download | cairo-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.c | 336 |
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; } |