1 /* cairo - a vector graphics library with display and print output
2 *
3 * Copyright © 2009 Intel Corporation
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it either under the terms of the GNU Lesser General Public
7 * License version 2.1 as published by the Free Software Foundation
8 * (the "LGPL") or, at your option, under the terms of the Mozilla
9 * Public License Version 1.1 (the "MPL"). If you do not alter this
10 * notice, a recipient may use your version of this file under either
11 * the MPL or the LGPL.
12 *
13 * You should have received a copy of the LGPL along with this library
14 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
15 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
16 * You should have received a copy of the MPL along with this library
17 * in the file COPYING-MPL-1.1
18 *
19 * The contents of this file are subject to the Mozilla Public License
20 * Version 1.1 (the "License"); you may not use this file except in
21 * compliance with the License. You may obtain a copy of the License at
22 * http://www.mozilla.org/MPL/
23 *
24 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
25 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
26 * the specific language governing rights and limitations.
27 *
28 * Contributor(s):
29 * Chris Wilson <chris@chris-wilson.co.uk>
30 */
31
32 #include "cairoint.h"
33
34 #include "cairo-xcb-private.h"
35
36 #include <xcb/xcbext.h>
37
38 xcb_pixmap_t
_cairo_xcb_connection_create_pixmap(cairo_xcb_connection_t * connection,uint8_t depth,xcb_drawable_t drawable,uint16_t width,uint16_t height)39 _cairo_xcb_connection_create_pixmap (cairo_xcb_connection_t *connection,
40 uint8_t depth,
41 xcb_drawable_t drawable,
42 uint16_t width,
43 uint16_t height)
44 {
45 xcb_pixmap_t pixmap = _cairo_xcb_connection_get_xid (connection);
46
47 assert (width > 0);
48 assert (height > 0);
49 xcb_create_pixmap (connection->xcb_connection,
50 depth, pixmap, drawable,
51 width, height);
52 return pixmap;
53 }
54
55 void
_cairo_xcb_connection_free_pixmap(cairo_xcb_connection_t * connection,xcb_pixmap_t pixmap)56 _cairo_xcb_connection_free_pixmap (cairo_xcb_connection_t *connection,
57 xcb_pixmap_t pixmap)
58 {
59 xcb_free_pixmap (connection->xcb_connection, pixmap);
60 _cairo_xcb_connection_put_xid (connection, pixmap);
61 }
62
63 xcb_gcontext_t
_cairo_xcb_connection_create_gc(cairo_xcb_connection_t * connection,xcb_drawable_t drawable,uint32_t value_mask,uint32_t * values)64 _cairo_xcb_connection_create_gc (cairo_xcb_connection_t *connection,
65 xcb_drawable_t drawable,
66 uint32_t value_mask,
67 uint32_t *values)
68 {
69 xcb_gcontext_t gc = _cairo_xcb_connection_get_xid (connection);
70 xcb_create_gc (connection->xcb_connection, gc, drawable,
71 value_mask, values);
72 return gc;
73 }
74
75 void
_cairo_xcb_connection_free_gc(cairo_xcb_connection_t * connection,xcb_gcontext_t gc)76 _cairo_xcb_connection_free_gc (cairo_xcb_connection_t *connection,
77 xcb_gcontext_t gc)
78 {
79 xcb_free_gc (connection->xcb_connection, gc);
80 _cairo_xcb_connection_put_xid (connection, gc);
81 }
82
83 void
_cairo_xcb_connection_change_gc(cairo_xcb_connection_t * connection,xcb_gcontext_t gc,uint32_t value_mask,uint32_t * values)84 _cairo_xcb_connection_change_gc (cairo_xcb_connection_t *connection,
85 xcb_gcontext_t gc,
86 uint32_t value_mask,
87 uint32_t *values)
88 {
89 xcb_change_gc (connection->xcb_connection, gc,
90 value_mask, values);
91 }
92
93 void
_cairo_xcb_connection_copy_area(cairo_xcb_connection_t * connection,xcb_drawable_t src,xcb_drawable_t dst,xcb_gcontext_t gc,int16_t src_x,int16_t src_y,int16_t dst_x,int16_t dst_y,uint16_t width,uint16_t height)94 _cairo_xcb_connection_copy_area (cairo_xcb_connection_t *connection,
95 xcb_drawable_t src,
96 xcb_drawable_t dst,
97 xcb_gcontext_t gc,
98 int16_t src_x,
99 int16_t src_y,
100 int16_t dst_x,
101 int16_t dst_y,
102 uint16_t width,
103 uint16_t height)
104 {
105 xcb_copy_area (connection->xcb_connection, src, dst, gc,
106 src_x, src_y, dst_x, dst_y, width, height);
107 }
108
109 void
_cairo_xcb_connection_poly_fill_rectangle(cairo_xcb_connection_t * connection,xcb_drawable_t dst,xcb_gcontext_t gc,uint32_t num_rectangles,xcb_rectangle_t * rectangles)110 _cairo_xcb_connection_poly_fill_rectangle (cairo_xcb_connection_t *connection,
111 xcb_drawable_t dst,
112 xcb_gcontext_t gc,
113 uint32_t num_rectangles,
114 xcb_rectangle_t *rectangles)
115 {
116 xcb_poly_fill_rectangle (connection->xcb_connection, dst, gc,
117 num_rectangles, rectangles);
118 }
119
120 void
_cairo_xcb_connection_put_image(cairo_xcb_connection_t * connection,xcb_drawable_t dst,xcb_gcontext_t gc,uint16_t width,uint16_t height,int16_t dst_x,int16_t dst_y,uint8_t depth,uint32_t stride,void * data)121 _cairo_xcb_connection_put_image (cairo_xcb_connection_t *connection,
122 xcb_drawable_t dst,
123 xcb_gcontext_t gc,
124 uint16_t width,
125 uint16_t height,
126 int16_t dst_x,
127 int16_t dst_y,
128 uint8_t depth,
129 uint32_t stride,
130 void *data)
131 {
132 const uint32_t req_size = 18;
133 uint32_t length = height * stride;
134 uint32_t len = (req_size + length) >> 2;
135
136 if (len < connection->maximum_request_length) {
137 xcb_put_image (connection->xcb_connection, XCB_IMAGE_FORMAT_Z_PIXMAP,
138 dst, gc, width, height, dst_x, dst_y, 0, depth,
139 length, data);
140 } else {
141 int rows = (connection->maximum_request_length - req_size - 4) / stride;
142 if (rows > 0) {
143 do {
144 if (rows > height)
145 rows = height;
146
147 length = rows * stride;
148
149 xcb_put_image (connection->xcb_connection, XCB_IMAGE_FORMAT_Z_PIXMAP,
150 dst, gc, width, rows, dst_x, dst_y, 0, depth, length, data);
151
152 height -= rows;
153 dst_y += rows;
154 data = (char *) data + length;
155 } while (height);
156 } else {
157 ASSERT_NOT_REACHED;
158 }
159 }
160 }
161
162 static void
_cairo_xcb_connection_do_put_subimage(cairo_xcb_connection_t * connection,xcb_drawable_t dst,xcb_gcontext_t gc,int16_t src_x,int16_t src_y,uint16_t width,uint16_t height,uint16_t cpp,int stride,int16_t dst_x,int16_t dst_y,uint8_t depth,void * _data)163 _cairo_xcb_connection_do_put_subimage (cairo_xcb_connection_t *connection,
164 xcb_drawable_t dst,
165 xcb_gcontext_t gc,
166 int16_t src_x,
167 int16_t src_y,
168 uint16_t width,
169 uint16_t height,
170 uint16_t cpp,
171 int stride,
172 int16_t dst_x,
173 int16_t dst_y,
174 uint8_t depth,
175 void *_data)
176 {
177 xcb_protocol_request_t xcb_req = {
178 0 /* count */,
179 0 /* ext */,
180 XCB_PUT_IMAGE /* opcode */,
181 1 /* isvoid (doesn't cause a reply) */
182 };
183 xcb_put_image_request_t req;
184 struct iovec vec_stack[CAIRO_STACK_ARRAY_LENGTH (struct iovec)];
185 struct iovec *vec = vec_stack;
186 uint32_t len = 0;
187 uint8_t *data = _data;
188 int n = 3;
189 /* Two extra entries are needed for xcb, two for us */
190 int entries_needed = height + 2 + 2;
191
192 req.format = XCB_IMAGE_FORMAT_Z_PIXMAP;
193 req.drawable = dst;
194 req.gc = gc;
195 req.width = width;
196 req.height = height;
197 req.dst_x = dst_x;
198 req.dst_y = dst_y;
199 req.left_pad = 0;
200 req.depth = depth;
201 req.pad0[0] = 0;
202 req.pad0[1] = 0;
203
204 if (entries_needed > ARRAY_LENGTH (vec_stack)) {
205 vec = _cairo_malloc_ab (entries_needed, sizeof (struct iovec));
206 if (unlikely (vec == NULL)) {
207 /* XXX loop over ARRAY_LENGTH (vec_stack) */
208 return;
209 }
210 }
211
212 data += src_y * stride + src_x * cpp;
213 /* vec[1] will be used in XCB if it has to use BigRequests or insert a sync,
214 * vec[0] is used if the internal queue needs to be flushed. */
215 vec[2].iov_base = (char *) &req;
216 vec[2].iov_len = sizeof (req);
217
218 /* Now comes the actual data */
219 while (height--) {
220 vec[n].iov_base = data;
221 vec[n].iov_len = cpp * width;
222 len += cpp * width;
223 data += stride;
224 n++;
225 }
226
227 /* And again some padding */
228 vec[n].iov_base = 0;
229 vec[n].iov_len = -len & 3;
230 n++;
231
232 /* For efficiency reasons, this functions writes the request "directly" to
233 * the xcb connection to avoid having to copy the data around. */
234 assert (n == entries_needed);
235 xcb_req.count = n - 2;
236 xcb_send_request (connection->xcb_connection, 0, &vec[2], &xcb_req);
237
238 if (vec != vec_stack)
239 free (vec);
240 }
241
242 void
_cairo_xcb_connection_put_subimage(cairo_xcb_connection_t * connection,xcb_drawable_t dst,xcb_gcontext_t gc,int16_t src_x,int16_t src_y,uint16_t width,uint16_t height,uint16_t cpp,int stride,int16_t dst_x,int16_t dst_y,uint8_t depth,void * _data)243 _cairo_xcb_connection_put_subimage (cairo_xcb_connection_t *connection,
244 xcb_drawable_t dst,
245 xcb_gcontext_t gc,
246 int16_t src_x,
247 int16_t src_y,
248 uint16_t width,
249 uint16_t height,
250 uint16_t cpp,
251 int stride,
252 int16_t dst_x,
253 int16_t dst_y,
254 uint8_t depth,
255 void *_data)
256 {
257 const uint32_t req_size = sizeof(xcb_put_image_request_t);
258 uint32_t length = height * cpp * width;
259 uint32_t len = (req_size + length) >> 2;
260
261 if (len < connection->maximum_request_length) {
262 _cairo_xcb_connection_do_put_subimage (connection, dst, gc, src_x, src_y,
263 width, height, cpp, stride, dst_x, dst_y, depth, _data);
264 } else {
265 int rows = (connection->maximum_request_length - req_size - 4) / (cpp * width);
266 if (rows > 0) {
267 do {
268 if (rows > height)
269 rows = height;
270
271 _cairo_xcb_connection_do_put_subimage (connection, dst, gc, src_x, src_y,
272 width, rows, cpp, stride, dst_x, dst_y, depth, _data);
273
274 height -= rows;
275 dst_y += rows;
276 _data = (char *) _data + stride * rows;
277 } while (height);
278 } else {
279 ASSERT_NOT_REACHED;
280 }
281 }
282 }
283
284 xcb_get_image_reply_t *
_cairo_xcb_connection_get_image(cairo_xcb_connection_t * connection,xcb_drawable_t src,int16_t src_x,int16_t src_y,uint16_t width,uint16_t height)285 _cairo_xcb_connection_get_image (cairo_xcb_connection_t *connection,
286 xcb_drawable_t src,
287 int16_t src_x,
288 int16_t src_y,
289 uint16_t width,
290 uint16_t height)
291 {
292 return xcb_get_image_reply (connection->xcb_connection,
293 xcb_get_image (connection->xcb_connection,
294 XCB_IMAGE_FORMAT_Z_PIXMAP,
295 src,
296 src_x, src_y,
297 width, height,
298 (uint32_t) -1),
299 NULL);
300 }
301