1 /* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
2 /* cairo - a vector graphics library with display and print output
4 * Copyright © 2012 Intel Corporation
6 * This library is free software; you can redistribute it and/or
7 * modify it either under the terms of the GNU Lesser General Public
8 * License version 2.1 as published by the Free Software Foundation
9 * (the "LGPL") or, at your option, under the terms of the Mozilla
10 * Public License Version 1.1 (the "MPL"). If you do not alter this
11 * notice, a recipient may use your version of this file under either
12 * the MPL or the LGPL.
14 * You should have received a copy of the LGPL along with this library
15 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
17 * You should have received a copy of the MPL along with this library
18 * in the file COPYING-MPL-1.1
20 * The contents of this file are subject to the Mozilla Public License
21 * Version 1.1 (the "License"); you may not use this file except in
22 * compliance with the License. You may obtain a copy of the License at
23 * http://www.mozilla.org/MPL/
25 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
26 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
27 * the specific language governing rights and limitations.
29 * The Original Code is the cairo graphics library.
31 * The Initial Developer of the Original Code is University of Southern
35 * Chris Wilson <chris@chris-wilson.co.uk>
40 #if !CAIRO_HAS_XLIB_XCB_FUNCTIONS
42 #include "cairo-xlib-private.h"
43 #include "cairo-xlib-surface-private.h"
45 #if !HAVE_X11_EXTENSIONS_XSHM_H || !(HAVE_X11_EXTENSIONS_SHMPROTO_H || HAVE_X11_EXTENSIONS_SHMSTR_H)
46 void _cairo_xlib_display_init_shm (cairo_xlib_display_t
*display
) {}
49 _cairo_xlib_surface_get_shm (cairo_xlib_surface_t
*surface
,
50 cairo_bool_t overwrite
)
56 _cairo_xlib_surface_put_shm (cairo_xlib_surface_t
*surface
)
58 assert (!surface
->fallback
);
59 return CAIRO_INT_STATUS_SUCCESS
;
63 _cairo_xlib_surface_create_shm (cairo_xlib_surface_t
*other
,
64 pixman_format_code_t format
,
65 int width
, int height
)
71 _cairo_xlib_surface_create_shm__image (cairo_xlib_surface_t
*surface
,
72 pixman_format_code_t format
,
73 int width
, int height
)
79 _cairo_xlib_surface_create_similar_shm (void *other
,
80 cairo_format_t format
,
81 int width
, int height
)
83 return cairo_image_surface_create (format
, width
, height
);
87 _cairo_xlib_shm_surface_mark_active (cairo_surface_t
*_shm
)
93 _cairo_xlib_shm_surface_get_ximage (cairo_surface_t
*surface
,
100 _cairo_xlib_shm_surface_get_obdata (cairo_surface_t
*surface
)
107 _cairo_xlib_shm_surface_get_pixmap (cairo_surface_t
*surface
)
114 _cairo_xlib_shm_surface_get_xrender_format (cairo_surface_t
*surface
)
121 _cairo_xlib_shm_surface_is_active (cairo_surface_t
*surface
)
128 _cairo_xlib_shm_surface_is_idle (cairo_surface_t
*surface
)
134 void _cairo_xlib_display_fini_shm (cairo_xlib_display_t
*display
) {}
138 #include "cairo-damage-private.h"
139 #include "cairo-default-context-private.h"
140 #include "cairo-image-surface-private.h"
141 #include "cairo-list-inline.h"
142 #include "cairo-mempool-private.h"
144 #include <X11/Xlibint.h>
145 #include <X11/Xproto.h>
146 #include <X11/extensions/XShm.h>
147 #if HAVE_X11_EXTENSIONS_SHMPROTO_H
148 #include <X11/extensions/shmproto.h>
149 #elif HAVE_X11_EXTENSIONS_SHMSTR_H
150 #include <X11/extensions/shmstr.h>
155 #define MIN_PIXMAP_SIZE 4096
158 #define MIN_SIZE (1<<(MIN_BITS-1))
160 typedef struct _cairo_xlib_shm cairo_xlib_shm_t
;
161 typedef struct _cairo_xlib_shm_info cairo_xlib_shm_info_t
;
162 typedef struct _cairo_xlib_shm_surface cairo_xlib_shm_surface_t
;
164 struct _cairo_xlib_shm
{
168 unsigned long attached
;
172 struct _cairo_xlib_shm_info
{
173 unsigned long last_request
;
176 cairo_xlib_shm_t
*pool
;
179 struct _cairo_xlib_shm_surface
{
180 cairo_image_surface_t image
;
183 cairo_xlib_shm_info_t
*info
;
185 unsigned long active
;
189 /* the parent is always given by index/2 */
190 #define PQ_PARENT_INDEX(i) ((i) >> 1)
191 #define PQ_FIRST_ENTRY 1
193 /* left and right children are index * 2 and (index * 2) +1 respectively */
194 #define PQ_LEFT_CHILD_INDEX(i) ((i) << 1)
196 #define PQ_TOP(pq) ((pq)->elements[PQ_FIRST_ENTRY])
200 cairo_xlib_shm_info_t
**elements
;
203 struct _cairo_xlib_shm_display
{
209 unsigned long last_request
;
210 unsigned long last_event
;
212 cairo_list_t surfaces
;
218 static inline cairo_bool_t
219 seqno_passed (unsigned long a
, unsigned long b
)
221 return (long)(b
- a
) >= 0;
224 static inline cairo_bool_t
225 seqno_before (unsigned long a
, unsigned long b
)
227 return (long)(b
- a
) > 0;
230 static inline cairo_bool_t
231 seqno_after (unsigned long a
, unsigned long b
)
233 return (long)(a
- b
) > 0;
236 static inline cairo_status_t
237 _pqueue_init (struct pqueue
*pq
)
242 pq
->elements
= _cairo_malloc_ab (pq
->max_size
,
243 sizeof (cairo_xlib_shm_info_t
*));
244 if (unlikely (pq
->elements
== NULL
))
245 return _cairo_error (CAIRO_STATUS_NO_MEMORY
);
248 return CAIRO_STATUS_SUCCESS
;
252 _pqueue_fini (struct pqueue
*pq
)
257 static cairo_status_t
258 _pqueue_grow (struct pqueue
*pq
)
260 cairo_xlib_shm_info_t
**new_elements
;
262 new_elements
= _cairo_realloc_ab (pq
->elements
,
264 sizeof (cairo_xlib_shm_info_t
*));
265 if (unlikely (new_elements
== NULL
))
266 return _cairo_error (CAIRO_STATUS_NO_MEMORY
);
268 pq
->elements
= new_elements
;
270 return CAIRO_STATUS_SUCCESS
;
274 _pqueue_shrink (struct pqueue
*pq
, int min_size
)
276 cairo_xlib_shm_info_t
**new_elements
;
278 if (min_size
> pq
->max_size
)
281 new_elements
= _cairo_realloc_ab (pq
->elements
,
283 sizeof (cairo_xlib_shm_info_t
*));
284 if (unlikely (new_elements
== NULL
))
287 pq
->elements
= new_elements
;
288 pq
->max_size
= min_size
;
291 static inline cairo_status_t
292 _pqueue_push (struct pqueue
*pq
, cairo_xlib_shm_info_t
*info
)
294 cairo_xlib_shm_info_t
**elements
;
297 if (unlikely (pq
->size
+ 1 == pq
->max_size
)) {
298 cairo_status_t status
;
300 status
= _pqueue_grow (pq
);
301 if (unlikely (status
))
305 elements
= pq
->elements
;
308 i
!= PQ_FIRST_ENTRY
&&
309 info
->last_request
< elements
[parent
= PQ_PARENT_INDEX (i
)]->last_request
;
312 elements
[i
] = elements
[parent
];
317 return CAIRO_STATUS_SUCCESS
;
321 _pqueue_pop (struct pqueue
*pq
)
323 cairo_xlib_shm_info_t
**elements
= pq
->elements
;
324 cairo_xlib_shm_info_t
*tail
;
327 tail
= elements
[pq
->size
--];
329 elements
[PQ_FIRST_ENTRY
] = NULL
;
330 _pqueue_shrink (pq
, 32);
334 for (i
= PQ_FIRST_ENTRY
;
335 (child
= PQ_LEFT_CHILD_INDEX (i
)) <= pq
->size
;
338 if (child
!= pq
->size
&&
339 elements
[child
+1]->last_request
< elements
[child
]->last_request
)
344 if (elements
[child
]->last_request
>= tail
->last_request
)
347 elements
[i
] = elements
[child
];
352 static cairo_bool_t _x_error_occurred
;
355 _check_error_handler (Display
*display
,
358 _x_error_occurred
= TRUE
;
359 return False
; /* ignored */
363 can_use_shm (Display
*dpy
, int *has_pixmap
)
366 int (*old_handler
) (Display
*display
, XErrorEvent
*event
);
370 if (! XShmQueryExtension (dpy
))
373 XShmQueryVersion (dpy
, &major
, &minor
, has_pixmap
);
375 shm
.shmid
= shmget (IPC_PRIVATE
, 0x1000, IPC_CREAT
| 0600);
379 shm
.readOnly
= FALSE
;
380 shm
.shmaddr
= shmat (shm
.shmid
, NULL
, 0);
381 if (shm
.shmaddr
== (char *) -1) {
382 shmctl (shm
.shmid
, IPC_RMID
, NULL
);
386 assert (CAIRO_MUTEX_IS_LOCKED (_cairo_xlib_display_mutex
));
387 _x_error_occurred
= FALSE
;
391 old_handler
= XSetErrorHandler (_check_error_handler
);
393 success
= XShmAttach (dpy
, &shm
);
395 XShmDetach (dpy
, &shm
);
398 XSetErrorHandler (old_handler
);
399 XUnlockDisplay (dpy
);
401 shmctl (shm
.shmid
, IPC_RMID
, NULL
);
404 return success
&& ! _x_error_occurred
;
407 static inline Display
*
408 peek_display (cairo_device_t
*device
)
410 return ((cairo_xlib_display_t
*)device
)->display
;
413 static inline unsigned long
414 peek_processed (cairo_device_t
*device
)
416 return LastKnownRequestProcessed (peek_display(device
));
420 _cairo_xlib_display_shm_pool_destroy (cairo_xlib_display_t
*display
,
421 cairo_xlib_shm_t
*pool
)
423 shmdt (pool
->shm
.shmaddr
);
424 if (display
->display
) /* may be called after CloseDisplay */
425 XShmDetach (display
->display
, &pool
->shm
);
427 _cairo_mempool_fini (&pool
->mem
);
429 cairo_list_del (&pool
->link
);
433 static void send_event(cairo_xlib_display_t
*display
,
434 cairo_xlib_shm_info_t
*info
,
437 XShmCompletionEvent ev
;
439 if (! seqno_after (seqno
, display
->shm
->last_event
))
442 ev
.type
= display
->shm
->event
;
443 ev
.send_event
= 1; /* XXX or lie? */
444 ev
.serial
= NextRequest (display
->display
);
445 ev
.drawable
= display
->shm
->window
;
446 ev
.major_code
= display
->shm
->opcode
;
447 ev
.minor_code
= X_ShmPutImage
;
448 ev
.shmseg
= info
->pool
->shm
.shmid
;
449 ev
.offset
= (char *)info
->mem
- (char *)info
->pool
->shm
.shmaddr
;
451 XSendEvent (display
->display
, ev
.drawable
, False
, 0, (XEvent
*)&ev
);
453 display
->shm
->last_event
= ev
.serial
;
456 static void _cairo_xlib_display_sync (cairo_xlib_display_t
*display
)
458 cairo_xlib_shm_info_t
*info
;
459 struct pqueue
*pq
= &display
->shm
->info
;
461 XSync (display
->display
, False
);
463 while ((info
= PQ_TOP(pq
))) {
464 _cairo_mempool_free (&info
->pool
->mem
, info
->mem
);
465 _pqueue_pop (&display
->shm
->info
);
471 _cairo_xlib_shm_info_cleanup (cairo_xlib_display_t
*display
)
473 cairo_xlib_shm_info_t
*info
;
474 Display
*dpy
= display
->display
;
475 struct pqueue
*pq
= &display
->shm
->info
;
476 unsigned long processed
;
478 if (PQ_TOP(pq
) == NULL
)
481 XEventsQueued (dpy
, QueuedAfterReading
);
482 processed
= LastKnownRequestProcessed (dpy
);
486 if (! seqno_passed (info
->last_request
, processed
)) {
487 send_event (display
, info
, display
->shm
->last_request
);
491 _cairo_mempool_free (&info
->pool
->mem
, info
->mem
);
492 _pqueue_pop (&display
->shm
->info
);
494 } while ((info
= PQ_TOP(pq
)));
497 static cairo_xlib_shm_t
*
498 _cairo_xlib_shm_info_find (cairo_xlib_display_t
*display
, size_t size
,
499 void **ptr
, unsigned long *last_request
)
501 cairo_xlib_shm_info_t
*info
;
502 struct pqueue
*pq
= &display
->shm
->info
;
504 if (PQ_TOP(pq
) == NULL
)
509 cairo_xlib_shm_t
*pool
= info
->pool
;
511 *last_request
= info
->last_request
;
513 _pqueue_pop (&display
->shm
->info
);
514 _cairo_mempool_free (&pool
->mem
, info
->mem
);
517 if (pool
->mem
.free_bytes
>= size
) {
518 void *mem
= _cairo_mempool_alloc (&pool
->mem
, size
);
524 } while ((info
= PQ_TOP(pq
)));
529 static cairo_xlib_shm_t
*
530 _cairo_xlib_shm_pool_find (cairo_xlib_display_t
*display
,
534 cairo_xlib_shm_t
*pool
;
536 cairo_list_foreach_entry (pool
, cairo_xlib_shm_t
, &display
->shm
->pool
, link
) {
537 if (pool
->mem
.free_bytes
>= size
) {
538 void *mem
= _cairo_mempool_alloc (&pool
->mem
, size
);
550 _cairo_xlib_shm_pool_cleanup (cairo_xlib_display_t
*display
)
552 cairo_xlib_shm_t
*pool
, *next
;
553 unsigned long processed
;
555 processed
= LastKnownRequestProcessed (display
->display
);
557 cairo_list_foreach_entry_safe (pool
, next
, cairo_xlib_shm_t
,
558 &display
->shm
->pool
, link
) {
559 if (! seqno_passed (pool
->attached
, processed
))
562 if (pool
->mem
.free_bytes
== pool
->mem
.max_bytes
)
563 _cairo_xlib_display_shm_pool_destroy (display
, pool
);
567 static cairo_xlib_shm_t
*
568 _cairo_xlib_shm_pool_create(cairo_xlib_display_t
*display
,
569 size_t size
, void **ptr
)
571 Display
*dpy
= display
->display
;
572 cairo_xlib_shm_t
*pool
;
573 size_t bytes
, maxbits
= 16, minbits
= MIN_BITS
;
576 pool
= malloc (sizeof (cairo_xlib_shm_t
));
580 bytes
= 1 << maxbits
;
581 while (bytes
<= size
)
582 bytes
<<= 1, maxbits
++;
585 minbits
+= (maxbits
- 16) / 2;
587 pool
->shm
.shmid
= shmget (IPC_PRIVATE
, bytes
, IPC_CREAT
| 0600);
588 while (pool
->shm
.shmid
== -1 && bytes
>= 2*size
) {
590 pool
->shm
.shmid
= shmget (IPC_PRIVATE
, bytes
, IPC_CREAT
| 0600);
592 if (pool
->shm
.shmid
== -1)
595 pool
->shm
.readOnly
= FALSE
;
596 pool
->shm
.shmaddr
= shmat (pool
->shm
.shmid
, NULL
, 0);
597 if (pool
->shm
.shmaddr
== (char *) -1) {
598 shmctl (pool
->shm
.shmid
, IPC_RMID
, NULL
);
602 pool
->attached
= NextRequest (dpy
);
603 success
= XShmAttach (dpy
, &pool
->shm
);
604 #if !IPC_RMID_DEFERRED_RELEASE
607 shmctl (pool
->shm
.shmid
, IPC_RMID
, NULL
);
612 if (_cairo_mempool_init (&pool
->mem
, pool
->shm
.shmaddr
, bytes
,
613 minbits
, maxbits
- minbits
+ 1))
616 cairo_list_add (&pool
->link
, &display
->shm
->pool
);
618 *ptr
= _cairo_mempool_alloc (&pool
->mem
, size
);
619 assert (*ptr
!= NULL
);
623 XShmDetach (dpy
, &pool
->shm
);
625 shmdt (pool
->shm
.shmaddr
);
631 static cairo_xlib_shm_info_t
*
632 _cairo_xlib_shm_info_create (cairo_xlib_display_t
*display
,
633 size_t size
, cairo_bool_t will_sync
)
635 cairo_xlib_shm_info_t
*info
;
636 cairo_xlib_shm_t
*pool
;
637 unsigned long last_request
= 0;
640 _cairo_xlib_shm_info_cleanup (display
);
641 pool
= _cairo_xlib_shm_pool_find (display
, size
, &mem
);
642 _cairo_xlib_shm_pool_cleanup (display
);
644 if (pool
== NULL
&& will_sync
)
645 pool
= _cairo_xlib_shm_info_find (display
, size
, &mem
, &last_request
);
647 pool
= _cairo_xlib_shm_pool_create (display
, size
, &mem
);
651 assert (mem
!= NULL
);
653 info
= malloc (sizeof (*info
));
655 _cairo_mempool_free (&pool
->mem
, mem
);
662 info
->last_request
= last_request
;
667 static cairo_status_t
668 _cairo_xlib_shm_surface_flush (void *abstract_surface
, unsigned flags
)
670 cairo_xlib_shm_surface_t
*shm
= abstract_surface
;
671 cairo_xlib_display_t
*display
;
673 cairo_status_t status
;
675 if (shm
->active
== 0)
676 return CAIRO_STATUS_SUCCESS
;
678 if (shm
->image
.base
._finishing
)
679 return CAIRO_STATUS_SUCCESS
;
681 if (seqno_passed (shm
->active
, peek_processed (shm
->image
.base
.device
))) {
683 return CAIRO_STATUS_SUCCESS
;
686 status
= _cairo_xlib_display_acquire (shm
->image
.base
.device
, &display
);
687 if (unlikely (status
))
690 send_event (display
, shm
->info
, shm
->active
);
692 dpy
= display
->display
;
693 XEventsQueued (dpy
, QueuedAfterReading
);
694 while (! seqno_passed (shm
->active
, LastKnownRequestProcessed (dpy
))) {
700 cairo_device_release (&display
->base
);
703 return CAIRO_STATUS_SUCCESS
;
706 static inline cairo_bool_t
707 active (cairo_xlib_shm_surface_t
*shm
, Display
*dpy
)
709 return (shm
->active
&&
710 ! seqno_passed (shm
->active
, LastKnownRequestProcessed (dpy
)));
713 static cairo_status_t
714 _cairo_xlib_shm_surface_finish (void *abstract_surface
)
716 cairo_xlib_shm_surface_t
*shm
= abstract_surface
;
717 cairo_xlib_display_t
*display
;
718 cairo_status_t status
;
720 if (shm
->image
.base
.damage
) {
721 _cairo_damage_destroy (shm
->image
.base
.damage
);
722 shm
->image
.base
.damage
= _cairo_damage_create_in_error (CAIRO_STATUS_SURFACE_FINISHED
);
725 status
= _cairo_xlib_display_acquire (shm
->image
.base
.device
, &display
);
726 if (unlikely (status
))
730 XFreePixmap (display
->display
, shm
->pixmap
);
732 if (active (shm
, display
->display
)) {
733 shm
->info
->last_request
= shm
->active
;
734 _pqueue_push (&display
->shm
->info
, shm
->info
);
735 if (seqno_before (display
->shm
->last_request
, shm
->active
))
736 display
->shm
->last_request
= shm
->active
;
738 _cairo_mempool_free (&shm
->info
->pool
->mem
, shm
->info
->mem
);
741 _cairo_xlib_shm_pool_cleanup (display
);
744 cairo_list_del (&shm
->link
);
746 cairo_device_release (&display
->base
);
747 return _cairo_image_surface_finish (abstract_surface
);
750 static const cairo_surface_backend_t cairo_xlib_shm_surface_backend
= {
751 CAIRO_SURFACE_TYPE_IMAGE
,
752 _cairo_xlib_shm_surface_finish
,
754 _cairo_default_context_create
,
756 _cairo_image_surface_create_similar
,
757 NULL
, /* create similar image */
758 _cairo_image_surface_map_to_image
,
759 _cairo_image_surface_unmap_image
,
761 _cairo_image_surface_source
,
762 _cairo_image_surface_acquire_source_image
,
763 _cairo_image_surface_release_source_image
,
764 _cairo_image_surface_snapshot
,
766 NULL
, /* copy_page */
767 NULL
, /* show_page */
769 _cairo_image_surface_get_extents
,
770 _cairo_image_surface_get_font_options
,
772 _cairo_xlib_shm_surface_flush
,
775 _cairo_image_surface_paint
,
776 _cairo_image_surface_mask
,
777 _cairo_image_surface_stroke
,
778 _cairo_image_surface_fill
,
779 NULL
, /* fill-stroke */
780 _cairo_image_surface_glyphs
,
784 has_shm (cairo_xlib_surface_t
*surface
)
786 cairo_xlib_display_t
*display
= (cairo_xlib_display_t
*)surface
->base
.device
;
787 return display
->shm
!= NULL
;
791 has_shm_pixmaps (cairo_xlib_surface_t
*surface
)
793 cairo_xlib_display_t
*display
= (cairo_xlib_display_t
*)surface
->base
.device
;
797 return display
->shm
->has_pixmaps
;
800 static cairo_xlib_shm_surface_t
*
801 _cairo_xlib_shm_surface_create (cairo_xlib_surface_t
*other
,
802 pixman_format_code_t format
,
803 int width
, int height
,
804 cairo_bool_t will_sync
,
807 cairo_xlib_shm_surface_t
*shm
;
808 cairo_xlib_display_t
*display
;
809 pixman_image_t
*image
;
812 stride
= CAIRO_STRIDE_FOR_WIDTH_BPP (width
, PIXMAN_FORMAT_BPP(format
));
813 size
= stride
* height
;
817 shm
= malloc (sizeof (*shm
));
818 if (unlikely (shm
== NULL
))
819 return (cairo_xlib_shm_surface_t
*)_cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY
);
821 _cairo_surface_init (&shm
->image
.base
,
822 &cairo_xlib_shm_surface_backend
,
824 _cairo_content_from_pixman_format (format
));
826 if (_cairo_xlib_display_acquire (other
->base
.device
, &display
))
829 shm
->info
= _cairo_xlib_shm_info_create (display
, size
, will_sync
);
830 if (shm
->info
== NULL
)
831 goto cleanup_display
;
833 image
= pixman_image_create_bits (format
, width
, height
,
834 (uint32_t *) shm
->info
->mem
, stride
);
838 _cairo_image_surface_init (&shm
->image
, image
, format
);
841 if (create_pixmap
&& size
>= create_pixmap
) {
842 shm
->pixmap
= XShmCreatePixmap (display
->display
,
845 &shm
->info
->pool
->shm
,
850 shm
->active
= shm
->info
->last_request
;
853 assert (shm
->active
== 0 || will_sync
);
855 cairo_list_add (&shm
->link
, &display
->shm
->surfaces
);
857 cairo_device_release (&display
->base
);
862 _cairo_mempool_free (&shm
->info
->pool
->mem
, shm
->info
->mem
);
865 cairo_device_release (&display
->base
);
872 _cairo_xlib_surface_update_shm (cairo_xlib_surface_t
*surface
)
874 cairo_xlib_shm_surface_t
*shm
= (cairo_xlib_shm_surface_t
*)surface
->shm
;
875 cairo_xlib_display_t
*display
;
876 cairo_damage_t
*damage
;
879 damage
= _cairo_damage_reduce (surface
->base
.damage
);
880 surface
->base
.damage
= _cairo_damage_create();
882 if (_cairo_xlib_display_acquire (surface
->base
.device
, &display
))
885 if (_cairo_xlib_surface_get_gc (display
, surface
, &gc
))
886 goto cleanup_display
;
888 if (! surface
->owns_pixmap
) {
891 gcv
.subwindow_mode
= IncludeInferiors
;
892 XChangeGC (display
->display
, gc
, GCSubwindowMode
, &gcv
);
895 if (damage
->region
) {
896 XRectangle stack_rects
[CAIRO_STACK_ARRAY_LENGTH (XRectangle
)];
897 XRectangle
*rects
= stack_rects
;
898 cairo_rectangle_int_t r
;
901 n_rects
= cairo_region_num_rectangles (damage
->region
);
903 } else if (n_rects
== 1) {
904 cairo_region_get_rectangle (damage
->region
, 0, &r
);
905 XCopyArea (display
->display
,
906 surface
->drawable
, shm
->pixmap
, gc
,
911 if (n_rects
> ARRAY_LENGTH (stack_rects
)) {
912 rects
= _cairo_malloc_ab (n_rects
, sizeof (XRectangle
));
913 if (unlikely (rects
== NULL
)) {
915 n_rects
= ARRAY_LENGTH (stack_rects
);
918 for (i
= 0; i
< n_rects
; i
++) {
919 cairo_region_get_rectangle (damage
->region
, i
, &r
);
923 rects
[i
].width
= r
.width
;
924 rects
[i
].height
= r
.height
;
926 XSetClipRectangles (display
->display
, gc
, 0, 0, rects
, i
, YXBanded
);
928 XCopyArea (display
->display
,
929 surface
->drawable
, shm
->pixmap
, gc
,
931 shm
->image
.width
, shm
->image
.height
,
934 if (damage
->status
== CAIRO_STATUS_SUCCESS
&& damage
->region
)
935 XSetClipMask (display
->display
, gc
, None
);
938 XCopyArea (display
->display
,
939 surface
->drawable
, shm
->pixmap
, gc
,
941 shm
->image
.width
, shm
->image
.height
,
945 if (! surface
->owns_pixmap
) {
948 gcv
.subwindow_mode
= ClipByChildren
;
949 XChangeGC (display
->display
, gc
, GCSubwindowMode
, &gcv
);
952 _cairo_xlib_display_sync (display
);
956 _cairo_xlib_surface_put_gc (display
, surface
, gc
);
958 cairo_device_release (&display
->base
);
960 _cairo_damage_destroy (damage
);
964 _cairo_xlib_surface_clear_shm (cairo_xlib_surface_t
*surface
)
966 cairo_xlib_shm_surface_t
*shm
= (cairo_xlib_shm_surface_t
*)surface
->shm
;
968 assert (shm
->active
== 0);
970 _cairo_damage_destroy (surface
->base
.damage
);
971 surface
->base
.damage
= _cairo_damage_create();
973 memset (shm
->image
.data
, 0, shm
->image
.stride
* shm
->image
.height
);
974 shm
->image
.base
.is_clear
= TRUE
;
977 static void inc_idle (cairo_surface_t
*surface
)
979 cairo_xlib_shm_surface_t
*shm
= (cairo_xlib_shm_surface_t
*)surface
;
983 static void dec_idle (cairo_surface_t
*surface
)
985 cairo_xlib_shm_surface_t
*shm
= (cairo_xlib_shm_surface_t
*)surface
;
990 _cairo_xlib_surface_get_shm (cairo_xlib_surface_t
*surface
,
991 cairo_bool_t overwrite
)
993 if (surface
->fallback
) {
994 assert (surface
->base
.damage
);
995 assert (surface
->shm
);
996 assert (surface
->shm
->damage
);
1000 if (surface
->shm
== NULL
) {
1001 pixman_format_code_t pixman_format
;
1002 cairo_bool_t will_sync
;
1004 if (! has_shm_pixmaps (surface
))
1007 if ((surface
->width
| surface
->height
) < 32)
1010 pixman_format
= _pixman_format_for_xlib_surface (surface
);
1011 if (pixman_format
== 0)
1014 will_sync
= !surface
->base
.is_clear
&& !overwrite
;
1017 &_cairo_xlib_shm_surface_create (surface
, pixman_format
,
1018 surface
->width
, surface
->height
,
1019 will_sync
, 1)->image
.base
;
1020 if (surface
->shm
== NULL
)
1023 assert (surface
->base
.damage
== NULL
);
1024 if (surface
->base
.serial
|| !surface
->owns_pixmap
) {
1025 cairo_rectangle_int_t rect
;
1027 rect
.x
= rect
.y
= 0;
1028 rect
.width
= surface
->width
;
1029 rect
.height
= surface
->height
;
1031 surface
->base
.damage
=
1032 _cairo_damage_add_rectangle (NULL
, &rect
);
1034 surface
->base
.damage
= _cairo_damage_create ();
1036 surface
->shm
->damage
= _cairo_damage_create ();
1040 _cairo_damage_destroy (surface
->base
.damage
);
1041 surface
->base
.damage
= _cairo_damage_create ();
1044 if (!surface
->base
.is_clear
&& surface
->base
.damage
->dirty
)
1045 _cairo_xlib_surface_update_shm (surface
);
1047 _cairo_xlib_shm_surface_flush (surface
->shm
, 1);
1049 if (surface
->base
.is_clear
&& surface
->base
.damage
->dirty
)
1050 _cairo_xlib_surface_clear_shm (surface
);
1053 dec_idle(surface
->shm
);
1054 return surface
->shm
;
1058 _cairo_xlib_surface_put_shm (cairo_xlib_surface_t
*surface
)
1060 cairo_int_status_t status
= CAIRO_INT_STATUS_SUCCESS
;
1062 if (!surface
->fallback
) {
1064 inc_idle (surface
->shm
);
1065 return CAIRO_INT_STATUS_SUCCESS
;
1068 if (surface
->shm
->damage
->dirty
) {
1069 cairo_xlib_shm_surface_t
*shm
= (cairo_xlib_shm_surface_t
*) surface
->shm
;
1070 cairo_xlib_display_t
*display
;
1071 cairo_damage_t
*damage
;
1074 status
= _cairo_xlib_display_acquire (surface
->base
.device
, &display
);
1075 if (unlikely (status
))
1078 damage
= _cairo_damage_reduce (shm
->image
.base
.damage
);
1079 shm
->image
.base
.damage
= _cairo_damage_create ();
1081 TRACE ((stderr
, "%s: flushing damage x %d\n", __FUNCTION__
,
1082 damage
->region
? cairo_region_num_rectangles (damage
->region
) : 0));
1083 if (damage
->status
== CAIRO_STATUS_SUCCESS
&& damage
->region
) {
1084 XRectangle stack_rects
[CAIRO_STACK_ARRAY_LENGTH (XRectangle
)];
1085 XRectangle
*rects
= stack_rects
;
1086 cairo_rectangle_int_t r
;
1089 n_rects
= cairo_region_num_rectangles (damage
->region
);
1093 status
= _cairo_xlib_surface_get_gc (display
, surface
, &gc
);
1094 if (unlikely (status
))
1098 cairo_region_get_rectangle (damage
->region
, 0, &r
);
1099 _cairo_xlib_shm_surface_mark_active (surface
->shm
);
1100 XCopyArea (display
->display
,
1101 shm
->pixmap
, surface
->drawable
, gc
,
1106 if (n_rects
> ARRAY_LENGTH (stack_rects
)) {
1107 rects
= _cairo_malloc_ab (n_rects
, sizeof (XRectangle
));
1108 if (unlikely (rects
== NULL
)) {
1109 status
= _cairo_error (CAIRO_STATUS_NO_MEMORY
);
1110 _cairo_xlib_surface_put_gc (display
, surface
, gc
);
1114 for (i
= 0; i
< n_rects
; i
++) {
1115 cairo_region_get_rectangle (damage
->region
, i
, &r
);
1119 rects
[i
].width
= r
.width
;
1120 rects
[i
].height
= r
.height
;
1122 XSetClipRectangles (display
->display
, gc
, 0, 0, rects
, i
, YXBanded
);
1124 _cairo_xlib_shm_surface_mark_active (surface
->shm
);
1125 XCopyArea (display
->display
,
1126 shm
->pixmap
, surface
->drawable
, gc
,
1128 shm
->image
.width
, shm
->image
.height
,
1131 if (damage
->status
== CAIRO_STATUS_SUCCESS
&& damage
->region
)
1132 XSetClipMask (display
->display
, gc
, None
);
1135 _cairo_xlib_surface_put_gc (display
, surface
, gc
);
1139 _cairo_damage_destroy (damage
);
1140 cairo_device_release (&display
->base
);
1147 _cairo_xlib_surface_create_shm (cairo_xlib_surface_t
*other
,
1148 pixman_format_code_t format
,
1149 int width
, int height
)
1151 cairo_surface_t
*surface
;
1154 if (has_shm (other
))
1155 surface
= &_cairo_xlib_shm_surface_create (other
, format
, width
, height
,
1156 FALSE
, has_shm_pixmaps (other
))->image
.base
;
1162 _cairo_xlib_surface_create_shm__image (cairo_xlib_surface_t
*surface
,
1163 pixman_format_code_t format
,
1164 int width
, int height
)
1166 if (! has_shm(surface
))
1169 return &_cairo_xlib_shm_surface_create (surface
, format
, width
, height
,
1170 FALSE
, 0)->image
.base
;
1174 _cairo_xlib_surface_create_similar_shm (void *other
,
1175 cairo_format_t format
,
1176 int width
, int height
)
1178 cairo_surface_t
*surface
;
1180 surface
= _cairo_xlib_surface_create_shm (other
,
1181 _cairo_format_to_pixman_format_code (format
),
1184 if (! surface
->is_clear
) {
1185 cairo_xlib_shm_surface_t
*shm
= (cairo_xlib_shm_surface_t
*) surface
;
1186 assert (shm
->active
== 0);
1187 memset (shm
->image
.data
, 0, shm
->image
.stride
* shm
->image
.height
);
1188 shm
->image
.base
.is_clear
= TRUE
;
1191 surface
= cairo_image_surface_create (format
, width
, height
);
1197 _cairo_xlib_shm_surface_mark_active (cairo_surface_t
*_shm
)
1199 cairo_xlib_shm_surface_t
*shm
= (cairo_xlib_shm_surface_t
*) _shm
;
1200 cairo_xlib_display_t
*display
= (cairo_xlib_display_t
*) _shm
->device
;
1202 shm
->active
= NextRequest (display
->display
);
1206 _cairo_xlib_shm_surface_get_ximage (cairo_surface_t
*surface
,
1209 cairo_xlib_shm_surface_t
*shm
= (cairo_xlib_shm_surface_t
*) surface
;
1210 int native_byte_order
= _cairo_is_little_endian () ? LSBFirst
: MSBFirst
;
1211 cairo_format_masks_t image_masks
;
1214 ret
= _pixman_format_to_masks (shm
->image
.pixman_format
, &image_masks
);
1217 ximage
->width
= shm
->image
.width
;
1218 ximage
->height
= shm
->image
.height
;
1219 ximage
->format
= ZPixmap
;
1220 ximage
->data
= (char *) shm
->image
.data
;
1221 ximage
->obdata
= (char *)&shm
->info
->pool
->shm
;
1222 ximage
->byte_order
= native_byte_order
;
1223 ximage
->bitmap_unit
= 32; /* always for libpixman */
1224 ximage
->bitmap_bit_order
= native_byte_order
;
1225 ximage
->bitmap_pad
= 32; /* always for libpixman */
1226 ximage
->depth
= shm
->image
.depth
;
1227 ximage
->bytes_per_line
= shm
->image
.stride
;
1228 ximage
->bits_per_pixel
= image_masks
.bpp
;
1229 ximage
->red_mask
= image_masks
.red_mask
;
1230 ximage
->green_mask
= image_masks
.green_mask
;
1231 ximage
->blue_mask
= image_masks
.blue_mask
;
1232 ximage
->xoffset
= 0;
1234 ret
= XInitImage (ximage
);
1239 _cairo_xlib_shm_surface_get_obdata (cairo_surface_t
*surface
)
1241 cairo_xlib_display_t
*display
= (cairo_xlib_display_t
*) surface
->device
;
1242 cairo_xlib_shm_surface_t
*shm
= (cairo_xlib_shm_surface_t
*) surface
;
1244 display
->shm
->last_event
= shm
->active
= NextRequest (display
->display
);
1245 return &shm
->info
->pool
->shm
;
1249 _cairo_xlib_shm_surface_get_pixmap (cairo_surface_t
*surface
)
1251 cairo_xlib_shm_surface_t
*shm
;
1253 shm
= (cairo_xlib_shm_surface_t
*) surface
;
1258 _cairo_xlib_shm_surface_get_xrender_format (cairo_surface_t
*surface
)
1260 cairo_xlib_shm_surface_t
*shm
;
1262 shm
= (cairo_xlib_shm_surface_t
*) surface
;
1263 if (shm
->image
.format
!= CAIRO_FORMAT_INVALID
)
1264 return _cairo_xlib_display_get_xrender_format ((cairo_xlib_display_t
*)surface
->device
,
1267 return _cairo_xlib_display_get_xrender_format_for_pixman((cairo_xlib_display_t
*)surface
->device
,
1268 shm
->image
.pixman_format
);
1272 _cairo_xlib_shm_surface_is_active (cairo_surface_t
*surface
)
1274 cairo_xlib_shm_surface_t
*shm
;
1276 shm
= (cairo_xlib_shm_surface_t
*) surface
;
1277 if (shm
->active
== 0)
1280 if (seqno_passed (shm
->active
, peek_processed (shm
->image
.base
.device
))) {
1289 _cairo_xlib_shm_surface_is_idle (cairo_surface_t
*surface
)
1291 cairo_xlib_shm_surface_t
*shm
;
1293 shm
= (cairo_xlib_shm_surface_t
*) surface
;
1294 return shm
->idle
> 0;
1297 #define XORG_VERSION_ENCODE(major,minor,patch,snap) \
1298 (((major) * 10000000) + ((minor) * 100000) + ((patch) * 1000) + snap)
1301 has_broken_send_shm_event (cairo_xlib_display_t
*display
,
1302 cairo_xlib_shm_display_t
*shm
)
1304 Display
*dpy
= display
->display
;
1305 int (*old_handler
) (Display
*display
, XErrorEvent
*event
);
1306 XShmCompletionEvent ev
;
1307 XShmSegmentInfo info
;
1309 info
.shmid
= shmget (IPC_PRIVATE
, 0x1000, IPC_CREAT
| 0600);
1310 if (info
.shmid
== -1)
1313 info
.readOnly
= FALSE
;
1314 info
.shmaddr
= shmat (info
.shmid
, NULL
, 0);
1315 if (info
.shmaddr
== (char *) -1) {
1316 shmctl (info
.shmid
, IPC_RMID
, NULL
);
1320 ev
.type
= shm
->event
;
1323 ev
.drawable
= shm
->window
;
1324 ev
.major_code
= shm
->opcode
;
1325 ev
.minor_code
= X_ShmPutImage
;
1327 ev
.shmseg
= info
.shmid
;
1330 assert (CAIRO_MUTEX_IS_LOCKED (_cairo_xlib_display_mutex
));
1331 _x_error_occurred
= FALSE
;
1335 old_handler
= XSetErrorHandler (_check_error_handler
);
1337 XShmAttach (dpy
, &info
);
1338 XSendEvent (dpy
, ev
.drawable
, False
, 0, (XEvent
*)&ev
);
1339 XShmDetach (dpy
, &info
);
1342 XSetErrorHandler (old_handler
);
1343 XUnlockDisplay (dpy
);
1345 shmctl (info
.shmid
, IPC_RMID
, NULL
);
1346 shmdt (info
.shmaddr
);
1348 return _x_error_occurred
;
1352 xorg_has_buggy_send_shm_completion_event(cairo_xlib_display_t
*display
,
1353 cairo_xlib_shm_display_t
*shm
)
1355 Display
*dpy
= display
->display
;
1357 /* As libXext sets the SEND_EVENT bit in the ShmCompletionEvent,
1358 * the Xserver may crash if it does not take care when processing
1359 * the event type. For instance versions of Xorg prior to 1.11.1
1360 * exhibited this bug, and was fixed by:
1362 * commit 2d2dce558d24eeea0eb011ec9ebaa6c5c2273c39
1363 * Author: Sam Spilsbury <sam.spilsbury@canonical.com>
1364 * Date: Wed Sep 14 09:58:34 2011 +0800
1366 * Remove the SendEvent bit (0x80) before doing range checks on event type.
1368 if (_cairo_xlib_vendor_is_xorg (dpy
) &&
1369 VendorRelease (dpy
) < XORG_VERSION_ENCODE(1,11,0,1))
1372 /* For everyone else check that no error is generated */
1373 return has_broken_send_shm_event (display
, shm
);
1377 _cairo_xlib_display_init_shm (cairo_xlib_display_t
*display
)
1379 cairo_xlib_shm_display_t
*shm
;
1380 XSetWindowAttributes attr
;
1382 int has_pixmap
, scr
;
1384 display
->shm
= NULL
;
1386 if (!can_use_shm (display
->display
, &has_pixmap
))
1389 shm
= malloc (sizeof (*shm
));
1390 if (unlikely (shm
== NULL
))
1393 codes
= XInitExtension (display
->display
, SHMNAME
);
1394 if (codes
== NULL
) {
1399 shm
->opcode
= codes
->major_opcode
;
1400 shm
->event
= codes
->first_event
;
1402 if (unlikely (_pqueue_init (&shm
->info
))) {
1407 scr
= DefaultScreen (display
->display
);
1408 attr
.override_redirect
= 1;
1409 shm
->window
= XCreateWindow (display
->display
,
1410 DefaultRootWindow (display
->display
), -1, -1,
1412 DefaultDepth (display
->display
, scr
),
1414 DefaultVisual (display
->display
, scr
),
1415 CWOverrideRedirect
, &attr
);
1416 shm
->last_event
= 0;
1417 shm
->last_request
= 0;
1419 if (xorg_has_buggy_send_shm_completion_event(display
, shm
))
1422 shm
->has_pixmaps
= has_pixmap
? MIN_PIXMAP_SIZE
: 0;
1423 cairo_list_init (&shm
->pool
);
1425 cairo_list_init (&shm
->surfaces
);
1431 _cairo_xlib_display_fini_shm (cairo_xlib_display_t
*display
)
1433 cairo_xlib_shm_display_t
*shm
= display
->shm
;
1438 while (!cairo_list_is_empty (&shm
->surfaces
))
1439 cairo_surface_finish (&cairo_list_first_entry (&shm
->surfaces
,
1440 cairo_xlib_shm_surface_t
,
1443 _pqueue_fini (&shm
->info
);
1445 while (!cairo_list_is_empty (&shm
->pool
)) {
1446 cairo_xlib_shm_t
*pool
;
1448 pool
= cairo_list_first_entry (&shm
->pool
, cairo_xlib_shm_t
, link
);
1449 _cairo_xlib_display_shm_pool_destroy (display
, pool
);
1452 if (display
->display
)
1453 XDestroyWindow (display
->display
, shm
->window
);
1456 display
->shm
= NULL
;