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 {
210 cairo_list_t surfaces;
216 static inline cairo_bool_t
217 seqno_passed (unsigned long a, unsigned long b)
219 return (long)(b - a) > 0;
222 static inline cairo_status_t
223 _pqueue_init (struct pqueue *pq)
228 pq->elements = _cairo_malloc_ab (pq->max_size,
229 sizeof (cairo_xlib_shm_info_t *));
230 if (unlikely (pq->elements == NULL))
231 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
234 return CAIRO_STATUS_SUCCESS;
238 _pqueue_fini (struct pqueue *pq)
243 static cairo_status_t
244 _pqueue_grow (struct pqueue *pq)
246 cairo_xlib_shm_info_t **new_elements;
248 new_elements = _cairo_realloc_ab (pq->elements,
250 sizeof (cairo_xlib_shm_info_t *));
251 if (unlikely (new_elements == NULL))
252 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
254 pq->elements = new_elements;
256 return CAIRO_STATUS_SUCCESS;
260 _pqueue_shrink (struct pqueue *pq, int min_size)
262 cairo_xlib_shm_info_t **new_elements;
264 if (min_size > pq->max_size)
267 new_elements = _cairo_realloc_ab (pq->elements,
269 sizeof (cairo_xlib_shm_info_t *));
270 if (unlikely (new_elements == NULL))
273 pq->elements = new_elements;
274 pq->max_size = min_size;
277 static inline cairo_status_t
278 _pqueue_push (struct pqueue *pq, cairo_xlib_shm_info_t *info)
280 cairo_xlib_shm_info_t **elements;
283 if (unlikely (pq->size + 1 == pq->max_size)) {
284 cairo_status_t status;
286 status = _pqueue_grow (pq);
287 if (unlikely (status))
291 elements = pq->elements;
294 i != PQ_FIRST_ENTRY &&
295 info->last_request < elements[parent = PQ_PARENT_INDEX (i)]->last_request;
298 elements[i] = elements[parent];
303 return CAIRO_STATUS_SUCCESS;
307 _pqueue_pop (struct pqueue *pq)
309 cairo_xlib_shm_info_t **elements = pq->elements;
310 cairo_xlib_shm_info_t *tail;
313 tail = elements[pq->size--];
315 elements[PQ_FIRST_ENTRY] = NULL;
316 _pqueue_shrink (pq, 32);
320 for (i = PQ_FIRST_ENTRY;
321 (child = PQ_LEFT_CHILD_INDEX (i)) <= pq->size;
324 if (child != pq->size &&
325 elements[child+1]->last_request < elements[child]->last_request)
330 if (elements[child]->last_request >= tail->last_request)
333 elements[i] = elements[child];
338 static cairo_bool_t _x_error_occurred;
341 _check_error_handler (Display *display,
344 _x_error_occurred = TRUE;
345 return False; /* ignored */
349 can_use_shm (Display *dpy, int *has_pixmap)
352 int (*old_handler) (Display *display, XErrorEvent *event);
356 if (! XShmQueryExtension (dpy))
359 XShmQueryVersion (dpy, &major, &minor, has_pixmap);
361 shm.shmid = shmget (IPC_PRIVATE, 0x1000, IPC_CREAT | 0600);
365 shm.readOnly = FALSE;
366 shm.shmaddr = shmat (shm.shmid, NULL, 0);
367 if (shm.shmaddr == (char *) -1) {
368 shmctl (shm.shmid, IPC_RMID, NULL);
372 assert (CAIRO_MUTEX_IS_LOCKED (_cairo_xlib_display_mutex));
373 _x_error_occurred = FALSE;
377 old_handler = XSetErrorHandler (_check_error_handler);
379 success = XShmAttach (dpy, &shm);
381 XShmDetach (dpy, &shm);
384 XSetErrorHandler (old_handler);
385 XUnlockDisplay (dpy);
387 shmctl (shm.shmid, IPC_RMID, NULL);
390 return success && ! _x_error_occurred;
393 static inline Display *
394 peek_display (cairo_device_t *device)
396 return ((cairo_xlib_display_t *)device)->display;
399 static inline unsigned long
400 peek_processed (cairo_device_t *device)
402 return LastKnownRequestProcessed (peek_display(device));
405 static unsigned next_request (cairo_device_t *device)
407 return NextRequest (peek_display (device));
411 _cairo_xlib_display_shm_pool_destroy (cairo_xlib_display_t *display,
412 cairo_xlib_shm_t *pool)
414 shmdt (pool->shm.shmaddr);
415 if (display->display) /* may be called after CloseDisplay */
416 XShmDetach (display->display, &pool->shm);
418 _cairo_mempool_fini (&pool->mem);
420 cairo_list_del (&pool->link);
425 _cairo_xlib_shm_info_cleanup (cairo_xlib_display_t *display)
427 cairo_xlib_shm_info_t *info;
428 Display *dpy = display->display;
429 struct pqueue *pq = &display->shm->info;
430 unsigned long processed;
432 if (PQ_TOP(pq) == NULL)
435 XEventsQueued (dpy, QueuedAfterReading);
436 processed = LastKnownRequestProcessed (dpy);
440 if (! seqno_passed (info->last_request, processed))
443 _cairo_mempool_free (&info->pool->mem, info->mem);
444 _pqueue_pop (&display->shm->info);
446 } while ((info = PQ_TOP(pq)));
449 static cairo_xlib_shm_info_t *
450 _cairo_xlib_shm_info_find (cairo_xlib_display_t *display,
451 size_t size, unsigned long *last_request)
453 cairo_xlib_shm_info_t *info;
454 struct pqueue *pq = &display->shm->info;
456 if (PQ_TOP(pq) == NULL)
461 _pqueue_pop (&display->shm->info);
463 if (info->size >= size && size <= 2*info->size)
466 *last_request = info->last_request;
467 _cairo_mempool_free (&info->pool->mem, info->mem);
469 } while ((info = PQ_TOP(pq)));
474 static cairo_xlib_shm_t *
475 _cairo_xlib_shm_pool_find (cairo_xlib_display_t *display,
479 cairo_xlib_shm_t *pool;
481 cairo_list_foreach_entry (pool, cairo_xlib_shm_t, &display->shm->pool, link) {
482 if (pool->mem.free_bytes >= size) {
483 void *mem = _cairo_mempool_alloc (&pool->mem, size);
495 _cairo_xlib_shm_pool_cleanup (cairo_xlib_display_t *display)
497 cairo_xlib_shm_t *pool, *next;
498 unsigned long processed;
500 processed = LastKnownRequestProcessed (display->display);
502 cairo_list_foreach_entry_safe (pool, next, cairo_xlib_shm_t,
503 &display->shm->pool, link) {
504 if (! seqno_passed (pool->attached, processed))
507 if (pool->mem.free_bytes == pool->mem.max_bytes)
508 _cairo_xlib_display_shm_pool_destroy (display, pool);
512 static cairo_xlib_shm_t *
513 _cairo_xlib_shm_pool_create(cairo_xlib_display_t *display,
514 size_t size, void **ptr)
516 Display *dpy = display->display;
517 cairo_xlib_shm_t *pool;
518 size_t bytes, maxbits = 16, minbits = MIN_BITS;
521 pool = malloc (sizeof (cairo_xlib_shm_t));
525 bytes = 1 << maxbits;
526 while (bytes <= size)
527 bytes <<= 1, maxbits++;
530 minbits += (maxbits - 16) / 2;
532 pool->shm.shmid = shmget (IPC_PRIVATE, bytes, IPC_CREAT | 0600);
533 while (pool->shm.shmid == -1 && bytes >= 2*size) {
535 pool->shm.shmid = shmget (IPC_PRIVATE, bytes, IPC_CREAT | 0600);
537 if (pool->shm.shmid == -1)
540 pool->shm.readOnly = FALSE;
541 pool->shm.shmaddr = shmat (pool->shm.shmid, NULL, 0);
542 if (pool->shm.shmaddr == (char *) -1) {
543 shmctl (pool->shm.shmid, IPC_RMID, NULL);
547 pool->attached = NextRequest (dpy);
548 success = XShmAttach (dpy, &pool->shm);
549 #if !IPC_RMID_DEFERRED_RELEASE
552 shmctl (pool->shm.shmid, IPC_RMID, NULL);
557 if (_cairo_mempool_init (&pool->mem, pool->shm.shmaddr, bytes,
558 minbits, maxbits - minbits + 1))
561 cairo_list_add (&pool->link, &display->shm->pool);
563 *ptr = _cairo_mempool_alloc (&pool->mem, size);
564 assert (*ptr != NULL);
568 XShmDetach (dpy, &pool->shm);
570 shmdt (pool->shm.shmaddr);
576 static cairo_xlib_shm_info_t *
577 _cairo_xlib_shm_info_create (cairo_xlib_display_t *display,
578 size_t size, cairo_bool_t will_sync)
580 cairo_xlib_shm_info_t *info;
581 cairo_xlib_shm_t *pool;
582 unsigned long last_request = 0;
586 info = _cairo_xlib_shm_info_find (display, size, &last_request);
591 _cairo_xlib_shm_info_cleanup (display);
592 pool = _cairo_xlib_shm_pool_find (display, size, &mem);
593 _cairo_xlib_shm_pool_cleanup (display);
595 pool = _cairo_xlib_shm_pool_create (display, size, &mem);
599 assert (mem != NULL);
601 info = malloc (sizeof (*info));
603 _cairo_mempool_free (&pool->mem, mem);
610 info->last_request = last_request;
615 static cairo_status_t
616 _cairo_xlib_shm_surface_flush (void *abstract_surface, unsigned flags)
618 cairo_xlib_shm_surface_t *shm = abstract_surface;
619 cairo_xlib_display_t *display;
620 cairo_status_t status;
622 if (shm->active == 0)
623 return CAIRO_STATUS_SUCCESS;
625 if (shm->image.base._finishing)
626 return CAIRO_STATUS_SUCCESS;
628 if (seqno_passed (shm->active, peek_processed (shm->image.base.device))) {
630 return CAIRO_STATUS_SUCCESS;
633 status = _cairo_xlib_display_acquire (shm->image.base.device, &display);
634 if (unlikely (status))
637 XEventsQueued (display->display, QueuedAfterReading);
638 if (!seqno_passed (shm->active,
639 LastKnownRequestProcessed (display->display)))
640 XSync (display->display, False);
642 cairo_device_release (&display->base);
645 return CAIRO_STATUS_SUCCESS;
648 static inline cairo_bool_t
649 active (cairo_xlib_shm_surface_t *shm, Display *dpy)
651 return (shm->active &&
652 !seqno_passed (shm->active, LastKnownRequestProcessed (dpy)));
655 static cairo_status_t
656 _cairo_xlib_shm_surface_finish (void *abstract_surface)
658 cairo_xlib_shm_surface_t *shm = abstract_surface;
659 cairo_xlib_display_t *display;
660 cairo_status_t status;
662 status = _cairo_xlib_display_acquire (shm->image.base.device, &display);
663 if (unlikely (status))
667 XFreePixmap (display->display, shm->pixmap);
669 if (active (shm, display->display)) {
670 shm->info->last_request = shm->active;
671 _pqueue_push (&display->shm->info, shm->info);
673 _cairo_mempool_free (&shm->info->pool->mem, shm->info->mem);
676 _cairo_xlib_shm_pool_cleanup (display);
679 cairo_list_del (&shm->link);
681 cairo_device_release (&display->base);
682 return CAIRO_STATUS_SUCCESS;
685 static const cairo_surface_backend_t cairo_xlib_shm_surface_backend = {
686 CAIRO_SURFACE_TYPE_IMAGE,
687 _cairo_xlib_shm_surface_finish,
689 _cairo_default_context_create,
691 _cairo_image_surface_create_similar,
692 NULL, /* create similar image */
693 _cairo_image_surface_map_to_image,
694 _cairo_image_surface_unmap_image,
696 _cairo_image_surface_source,
697 _cairo_image_surface_acquire_source_image,
698 _cairo_image_surface_release_source_image,
699 _cairo_image_surface_snapshot,
701 NULL, /* copy_page */
702 NULL, /* show_page */
704 _cairo_image_surface_get_extents,
705 _cairo_image_surface_get_font_options,
707 _cairo_xlib_shm_surface_flush,
710 _cairo_image_surface_paint,
711 _cairo_image_surface_mask,
712 _cairo_image_surface_stroke,
713 _cairo_image_surface_fill,
714 NULL, /* fill-stroke */
715 _cairo_image_surface_glyphs,
719 has_shm (cairo_xlib_surface_t *surface)
721 cairo_xlib_display_t *display = (cairo_xlib_display_t *)surface->base.device;
722 return display->shm != NULL;
726 has_shm_pixmaps (cairo_xlib_surface_t *surface)
728 cairo_xlib_display_t *display = (cairo_xlib_display_t *)surface->base.device;
732 return display->shm->has_pixmaps;
735 static cairo_xlib_shm_surface_t *
736 _cairo_xlib_shm_surface_create (cairo_xlib_surface_t *other,
737 pixman_format_code_t format,
738 int width, int height,
739 cairo_bool_t will_sync,
742 cairo_xlib_shm_surface_t *shm;
743 cairo_xlib_display_t *display;
744 pixman_image_t *image;
747 stride = CAIRO_STRIDE_FOR_WIDTH_BPP (width, PIXMAN_FORMAT_BPP(format));
748 size = stride * height;
752 shm = malloc (sizeof (*shm));
753 if (unlikely (shm == NULL))
754 return (cairo_xlib_shm_surface_t *)_cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
756 _cairo_surface_init (&shm->image.base,
757 &cairo_xlib_shm_surface_backend,
759 _cairo_content_from_pixman_format (format));
761 if (_cairo_xlib_display_acquire (other->base.device, &display))
764 shm->info = _cairo_xlib_shm_info_create (display, size, will_sync);
765 if (shm->info == NULL)
766 goto cleanup_display;
768 image = pixman_image_create_bits (format, width, height,
769 (uint32_t *) shm->info->mem, stride);
773 _cairo_image_surface_init (&shm->image, image, format);
776 if (create_pixmap && size >= create_pixmap) {
777 shm->pixmap = XShmCreatePixmap (display->display,
780 &shm->info->pool->shm,
785 shm->active = shm->info->last_request;
788 assert (shm->active == 0 || will_sync);
790 cairo_list_add (&shm->link, &display->shm->surfaces);
792 cairo_device_release (&display->base);
797 _cairo_mempool_free (&shm->info->pool->mem, shm->info->mem);
800 cairo_device_release (&display->base);
807 _cairo_xlib_surface_update_shm (cairo_xlib_surface_t *surface)
809 cairo_xlib_shm_surface_t *shm = (cairo_xlib_shm_surface_t *)surface->shm;
810 cairo_xlib_display_t *display;
811 cairo_damage_t *damage;
814 damage = _cairo_damage_reduce (surface->base.damage);
815 surface->base.damage = _cairo_damage_create();
817 if (_cairo_xlib_display_acquire (surface->base.device, &display))
820 if (_cairo_xlib_surface_get_gc (display, surface, &gc))
821 goto cleanup_display;
823 if (! surface->owns_pixmap) {
826 gcv.subwindow_mode = IncludeInferiors;
827 XChangeGC (display->display, gc, GCSubwindowMode, &gcv);
830 if (damage->region) {
831 XRectangle stack_rects[CAIRO_STACK_ARRAY_LENGTH (sizeof (XRectangle))];
832 XRectangle *rects = stack_rects;
833 cairo_rectangle_int_t r;
836 n_rects = cairo_region_num_rectangles (damage->region);
838 } else if (n_rects == 1) {
839 cairo_region_get_rectangle (damage->region, 0, &r);
840 XCopyArea (display->display,
841 surface->drawable, shm->pixmap, gc,
846 if (n_rects > ARRAY_LENGTH (stack_rects)) {
847 rects = _cairo_malloc_ab (n_rects, sizeof (XRectangle));
848 if (unlikely (rects == NULL)) {
850 n_rects = ARRAY_LENGTH (stack_rects);
853 for (i = 0; i < n_rects; i++) {
854 cairo_region_get_rectangle (damage->region, i, &r);
858 rects[i].width = r.width;
859 rects[i].height = r.height;
861 XSetClipRectangles (display->display, gc, 0, 0, rects, i, YXBanded);
863 XCopyArea (display->display,
864 surface->drawable, shm->pixmap, gc,
866 shm->image.width, shm->image.height,
869 if (damage->status == CAIRO_STATUS_SUCCESS && damage->region)
870 XSetClipMask (display->display, gc, None);
873 XCopyArea (display->display,
874 surface->drawable, shm->pixmap, gc,
876 shm->image.width, shm->image.height,
880 if (! surface->owns_pixmap) {
883 gcv.subwindow_mode = ClipByChildren;
884 XChangeGC (display->display, gc, GCSubwindowMode, &gcv);
887 XSync (display->display, False);
891 _cairo_xlib_surface_put_gc (display, surface, gc);
893 cairo_device_release (&display->base);
895 _cairo_damage_destroy (damage);
899 _cairo_xlib_surface_clear_shm (cairo_xlib_surface_t *surface)
901 cairo_xlib_shm_surface_t *shm = (cairo_xlib_shm_surface_t *)surface->shm;
903 assert (shm->active == 0);
905 _cairo_damage_destroy (surface->base.damage);
906 surface->base.damage = _cairo_damage_create();
908 memset (shm->image.data, 0, shm->image.stride * shm->image.height);
909 shm->image.base.is_clear = TRUE;
912 static void inc_idle (cairo_surface_t *surface)
914 cairo_xlib_shm_surface_t *shm = (cairo_xlib_shm_surface_t *)surface;
918 static void dec_idle (cairo_surface_t *surface)
920 cairo_xlib_shm_surface_t *shm = (cairo_xlib_shm_surface_t *)surface;
925 _cairo_xlib_surface_get_shm (cairo_xlib_surface_t *surface,
926 cairo_bool_t overwrite)
928 if (surface->fallback) {
929 assert (surface->base.damage);
930 assert (surface->shm);
931 assert (surface->shm->damage);
935 if (surface->shm == NULL) {
936 pixman_format_code_t pixman_format;
937 cairo_bool_t will_sync;
939 if (! has_shm_pixmaps (surface))
942 if ((surface->width | surface->height) < 32)
945 pixman_format = _pixman_format_for_xlib_surface (surface);
946 if (pixman_format == 0)
949 will_sync = !surface->base.is_clear && !overwrite;
952 &_cairo_xlib_shm_surface_create (surface, pixman_format,
953 surface->width, surface->height,
954 will_sync, 1)->image.base;
955 if (surface->shm == NULL)
958 assert (surface->base.damage == NULL);
959 if (surface->base.serial || !surface->owns_pixmap) {
960 cairo_rectangle_int_t rect;
963 rect.width = surface->width;
964 rect.height = surface->height;
966 surface->base.damage =
967 _cairo_damage_add_rectangle (NULL, &rect);
969 surface->base.damage = _cairo_damage_create ();
971 surface->shm->damage = _cairo_damage_create ();
975 _cairo_damage_destroy (surface->base.damage);
976 surface->base.damage = _cairo_damage_create ();
979 if (!surface->base.is_clear && surface->base.damage->dirty)
980 _cairo_xlib_surface_update_shm (surface);
982 _cairo_xlib_shm_surface_flush (surface->shm, 1);
984 if (surface->base.is_clear && surface->base.damage->dirty)
985 _cairo_xlib_surface_clear_shm (surface);
988 dec_idle(surface->shm);
993 _cairo_xlib_surface_put_shm (cairo_xlib_surface_t *surface)
995 cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS;
997 if (!surface->fallback) {
999 inc_idle (surface->shm);
1000 return CAIRO_INT_STATUS_SUCCESS;
1003 if (surface->shm->damage->dirty) {
1004 cairo_xlib_shm_surface_t *shm = (cairo_xlib_shm_surface_t *) surface->shm;
1005 cairo_xlib_display_t *display;
1006 cairo_damage_t *damage;
1009 status = _cairo_xlib_display_acquire (surface->base.device, &display);
1010 if (unlikely (status))
1013 damage = _cairo_damage_reduce (shm->image.base.damage);
1014 shm->image.base.damage = _cairo_damage_create ();
1016 status = _cairo_xlib_surface_get_gc (display, surface, &gc);
1017 if (unlikely (status))
1020 TRACE ((stderr, "%s: flushing damage x %d\n", __FUNCTION__,
1021 damage->region ? cairo_region_num_rectangles (damage->region) : 0));
1022 if (damage->status == CAIRO_STATUS_SUCCESS && damage->region) {
1023 XRectangle stack_rects[CAIRO_STACK_ARRAY_LENGTH (sizeof (XRectangle))];
1024 XRectangle *rects = stack_rects;
1025 cairo_rectangle_int_t r;
1028 n_rects = cairo_region_num_rectangles (damage->region);
1030 } else if (n_rects == 1) {
1031 cairo_region_get_rectangle (damage->region, 0, &r);
1032 XCopyArea (display->display,
1033 shm->pixmap, surface->drawable, gc,
1038 if (n_rects > ARRAY_LENGTH (stack_rects)) {
1039 rects = _cairo_malloc_ab (n_rects, sizeof (XRectangle));
1040 if (unlikely (rects == NULL)) {
1041 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
1045 for (i = 0; i < n_rects; i++) {
1046 cairo_region_get_rectangle (damage->region, i, &r);
1050 rects[i].width = r.width;
1051 rects[i].height = r.height;
1053 XSetClipRectangles (display->display, gc, 0, 0, rects, i, YXBanded);
1055 XCopyArea (display->display,
1056 shm->pixmap, surface->drawable, gc,
1058 shm->image.width, shm->image.height,
1061 if (damage->status == CAIRO_STATUS_SUCCESS && damage->region)
1062 XSetClipMask (display->display, gc, None);
1065 _cairo_damage_destroy (damage);
1067 _cairo_xlib_shm_surface_mark_active (surface->shm);
1068 _cairo_xlib_surface_put_gc (display, surface, gc);
1070 cairo_device_release (&display->base);
1077 _cairo_xlib_surface_create_shm (cairo_xlib_surface_t *other,
1078 pixman_format_code_t format,
1079 int width, int height)
1081 cairo_surface_t *surface;
1084 if (has_shm (other))
1085 surface = &_cairo_xlib_shm_surface_create (other, format,
1086 width, height, FALSE,
1087 has_shm_pixmaps (other))->image.base;
1093 _cairo_xlib_surface_create_shm__image (cairo_xlib_surface_t *surface,
1094 pixman_format_code_t format,
1095 int width, int height)
1097 if (! has_shm(surface))
1100 return &_cairo_xlib_shm_surface_create (surface, format,
1101 surface->width, surface->height,
1102 TRUE, 0)->image.base;
1106 _cairo_xlib_surface_create_similar_shm (void *other,
1107 cairo_format_t format,
1108 int width, int height)
1110 cairo_surface_t *surface;
1112 surface = _cairo_xlib_surface_create_shm (other,
1113 _cairo_format_to_pixman_format_code (format),
1116 if (! surface->is_clear) {
1117 cairo_xlib_shm_surface_t *shm = (cairo_xlib_shm_surface_t *) surface;
1118 assert (shm->active == 0);
1119 memset (shm->image.data, 0, shm->image.stride * shm->image.height);
1120 shm->image.base.is_clear = TRUE;
1123 surface = cairo_image_surface_create (format, width, height);
1129 _cairo_xlib_shm_surface_mark_active (cairo_surface_t *_shm)
1131 cairo_xlib_shm_surface_t *shm = (cairo_xlib_shm_surface_t *) _shm;
1132 cairo_xlib_display_t *display = (cairo_xlib_display_t *) _shm->device;
1133 XShmCompletionEvent ev;
1135 ev.type = display->shm->event;
1136 ev.drawable = display->shm->window;
1137 ev.major_code = display->shm->opcode;
1138 ev.minor_code = X_ShmPutImage;
1139 ev.shmseg = shm->info->pool->shm.shmid;
1140 ev.offset = (char *)shm->info->mem - (char *)shm->info->pool->shm.shmaddr;
1142 shm->active = NextRequest (display->display);
1143 XSendEvent (display->display, ev.drawable, False, 0, (XEvent *)&ev);
1147 _cairo_xlib_shm_surface_get_ximage (cairo_surface_t *surface,
1150 cairo_xlib_shm_surface_t *shm = (cairo_xlib_shm_surface_t *) surface;
1151 int native_byte_order = _cairo_is_little_endian () ? LSBFirst : MSBFirst;
1152 cairo_format_masks_t image_masks;
1155 ret = _pixman_format_to_masks (shm->image.pixman_format, &image_masks);
1158 ximage->width = shm->image.width;
1159 ximage->height = shm->image.height;
1160 ximage->format = ZPixmap;
1161 ximage->data = (char *) shm->image.data;
1162 ximage->obdata = (char *)&shm->info->pool->shm;
1163 ximage->byte_order = native_byte_order;
1164 ximage->bitmap_unit = 32; /* always for libpixman */
1165 ximage->bitmap_bit_order = native_byte_order;
1166 ximage->bitmap_pad = 32; /* always for libpixman */
1167 ximage->depth = shm->image.depth;
1168 ximage->bytes_per_line = shm->image.stride;
1169 ximage->bits_per_pixel = image_masks.bpp;
1170 ximage->red_mask = image_masks.red_mask;
1171 ximage->green_mask = image_masks.green_mask;
1172 ximage->blue_mask = image_masks.blue_mask;
1173 ximage->xoffset = 0;
1175 ret = XInitImage (ximage);
1180 _cairo_xlib_shm_surface_get_obdata (cairo_surface_t *surface)
1182 cairo_xlib_shm_surface_t *shm;
1184 shm = (cairo_xlib_shm_surface_t *) surface;
1185 shm->active = next_request (surface->device);
1186 return &shm->info->pool->shm;
1190 _cairo_xlib_shm_surface_get_pixmap (cairo_surface_t *surface)
1192 cairo_xlib_shm_surface_t *shm;
1194 shm = (cairo_xlib_shm_surface_t *) surface;
1199 _cairo_xlib_shm_surface_get_xrender_format (cairo_surface_t *surface)
1201 cairo_xlib_shm_surface_t *shm;
1203 shm = (cairo_xlib_shm_surface_t *) surface;
1204 if (shm->image.format != CAIRO_FORMAT_INVALID)
1205 return _cairo_xlib_display_get_xrender_format ((cairo_xlib_display_t *)surface->device,
1208 return _cairo_xlib_display_get_xrender_format_for_pixman((cairo_xlib_display_t *)surface->device,
1209 shm->image.pixman_format);
1213 _cairo_xlib_shm_surface_is_active (cairo_surface_t *surface)
1215 cairo_xlib_shm_surface_t *shm;
1217 shm = (cairo_xlib_shm_surface_t *) surface;
1218 if (shm->active == 0)
1221 if (seqno_passed (shm->active, peek_processed (shm->image.base.device))) {
1230 _cairo_xlib_shm_surface_is_idle (cairo_surface_t *surface)
1232 cairo_xlib_shm_surface_t *shm;
1234 shm = (cairo_xlib_shm_surface_t *) surface;
1235 return shm->idle > 0;
1238 #define XORG_VERSION_ENCODE(major,minor,patch,snap) \
1239 (((major) * 10000000) + ((minor) * 100000) + ((patch) * 1000) + snap)
1242 has_broken_send_shm_event (cairo_xlib_display_t *display,
1243 cairo_xlib_shm_display_t *shm)
1245 Display *dpy = display->display;
1246 int (*old_handler) (Display *display, XErrorEvent *event);
1247 XShmCompletionEvent ev;
1248 XShmSegmentInfo info;
1250 info.shmid = shmget (IPC_PRIVATE, 0x1000, IPC_CREAT | 0600);
1251 if (info.shmid == -1)
1254 info.readOnly = FALSE;
1255 info.shmaddr = shmat (info.shmid, NULL, 0);
1256 if (info.shmaddr == (char *) -1) {
1257 shmctl (info.shmid, IPC_RMID, NULL);
1261 ev.type = shm->event;
1262 ev.drawable = shm->window;
1263 ev.major_code = shm->opcode;
1264 ev.minor_code = X_ShmPutImage;
1266 ev.shmseg = info.shmid;
1269 assert (CAIRO_MUTEX_IS_LOCKED (_cairo_xlib_display_mutex));
1270 _x_error_occurred = FALSE;
1274 old_handler = XSetErrorHandler (_check_error_handler);
1276 XShmAttach (dpy, &info);
1277 XSendEvent (dpy, ev.drawable, False, 0, (XEvent *)&ev);
1278 XShmDetach (dpy, &info);
1281 XSetErrorHandler (old_handler);
1282 XUnlockDisplay (dpy);
1284 shmctl (info.shmid, IPC_RMID, NULL);
1285 shmdt (info.shmaddr);
1287 return _x_error_occurred;
1291 xorg_has_buggy_send_shm_completion_event(cairo_xlib_display_t *display,
1292 cairo_xlib_shm_display_t *shm)
1294 Display *dpy = display->display;
1296 /* As libXext sets the SEND_EVENT bit in the ShmCompletionEvent,
1297 * the Xserver may crash if it does not take care when processing
1298 * the event type. For instance versions of Xorg prior to 1.11.1
1299 * exhibited this bug, and was fixed by:
1301 * commit 2d2dce558d24eeea0eb011ec9ebaa6c5c2273c39
1302 * Author: Sam Spilsbury <sam.spilsbury@canonical.com>
1303 * Date: Wed Sep 14 09:58:34 2011 +0800
1305 * Remove the SendEvent bit (0x80) before doing range checks on event type.
1307 if (_cairo_xlib_vendor_is_xorg (dpy) &&
1308 VendorRelease (dpy) < XORG_VERSION_ENCODE(1,11,0,1))
1311 /* For everyone else check that no error is generated */
1312 return has_broken_send_shm_event (display, shm);
1316 _cairo_xlib_display_init_shm (cairo_xlib_display_t *display)
1318 cairo_xlib_shm_display_t *shm;
1319 XSetWindowAttributes attr;
1321 int has_pixmap, scr;
1323 display->shm = NULL;
1325 if (!can_use_shm (display->display, &has_pixmap))
1328 shm = malloc (sizeof (*shm));
1329 if (unlikely (shm == NULL))
1332 codes = XInitExtension (display->display, SHMNAME);
1333 if (codes == NULL) {
1338 shm->opcode = codes ->major_opcode;
1339 shm->event = codes->first_event;
1341 if (unlikely (_pqueue_init (&shm->info))) {
1346 scr = DefaultScreen (display->display);
1347 attr.override_redirect = 1;
1348 shm->window = XCreateWindow (display->display,
1349 DefaultRootWindow (display->display), -1, -1,
1351 DefaultDepth (display->display, scr),
1353 DefaultVisual (display->display, scr),
1354 CWOverrideRedirect, &attr);
1356 if (xorg_has_buggy_send_shm_completion_event(display, shm))
1359 shm->has_pixmaps = has_pixmap ? MIN_PIXMAP_SIZE : 0;
1360 cairo_list_init (&shm->pool);
1362 cairo_list_init (&shm->surfaces);
1368 _cairo_xlib_display_fini_shm (cairo_xlib_display_t *display)
1370 cairo_xlib_shm_display_t *shm = display->shm;
1375 while (!cairo_list_is_empty (&shm->surfaces))
1376 cairo_surface_finish (&cairo_list_first_entry (&shm->surfaces,
1377 cairo_xlib_shm_surface_t,
1380 _pqueue_fini (&shm->info);
1382 while (!cairo_list_is_empty (&shm->pool)) {
1383 cairo_xlib_shm_t *pool;
1385 pool = cairo_list_first_entry (&shm->pool, cairo_xlib_shm_t, link);
1386 _cairo_xlib_display_shm_pool_destroy (display, pool);
1389 if (display->display)
1390 XDestroyWindow (display->display, shm->window);
1393 display->shm = NULL;