Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /* Cairo - a vector graphics library with display and print output
  2.  *
  3.  * Copyright © 2008 Chris Wilson
  4.  * Copyright © 2009 Intel Corporation
  5.  *
  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.
  13.  *
  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
  19.  *
  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/
  24.  *
  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.
  28.  *
  29.  * Authors:
  30.  *    Chris Wilson <chris@chris-wilson.co.uk>
  31.  */
  32.  
  33. #include "cairoint.h"
  34.  
  35. #include "cairo-xcb-private.h"
  36. #include "cairo-list-inline.h"
  37.  
  38. struct pattern_cache_entry {
  39.     cairo_cache_entry_t key;
  40.     cairo_xcb_screen_t *screen;
  41.     cairo_pattern_union_t pattern;
  42.     cairo_surface_t *picture;
  43. };
  44.  
  45. void
  46. _cairo_xcb_screen_finish (cairo_xcb_screen_t *screen)
  47. {
  48.     int i;
  49.  
  50.     CAIRO_MUTEX_LOCK (screen->connection->screens_mutex);
  51.     cairo_list_del (&screen->link);
  52.     CAIRO_MUTEX_UNLOCK (screen->connection->screens_mutex);
  53.  
  54.     while (! cairo_list_is_empty (&screen->surfaces)) {
  55.         cairo_surface_t *surface;
  56.  
  57.         surface = &cairo_list_first_entry (&screen->surfaces,
  58.                                            cairo_xcb_surface_t,
  59.                                            link)->base;
  60.  
  61.         cairo_surface_finish (surface);
  62.     }
  63.  
  64.     while (! cairo_list_is_empty (&screen->pictures)) {
  65.         cairo_surface_t *surface;
  66.  
  67.         surface = &cairo_list_first_entry (&screen->pictures,
  68.                                            cairo_xcb_picture_t,
  69.                                            link)->base;
  70.  
  71.         cairo_surface_finish (surface);
  72.     }
  73.  
  74.     for (i = 0; i < screen->solid_cache_size; i++)
  75.         cairo_surface_destroy (screen->solid_cache[i].picture);
  76.  
  77.     for (i = 0; i < ARRAY_LENGTH (screen->stock_colors); i++)
  78.         cairo_surface_destroy (screen->stock_colors[i]);
  79.  
  80.     for (i = 0; i < ARRAY_LENGTH (screen->gc); i++) {
  81.         if (screen->gc_depths[i] != 0)
  82.             _cairo_xcb_connection_free_gc (screen->connection, screen->gc[i]);
  83.     }
  84.  
  85.     _cairo_cache_fini (&screen->linear_pattern_cache);
  86.     _cairo_cache_fini (&screen->radial_pattern_cache);
  87.     _cairo_freelist_fini (&screen->pattern_cache_entry_freelist);
  88.  
  89.     free (screen);
  90. }
  91.  
  92. static cairo_bool_t
  93. _linear_pattern_cache_entry_equal (const void *A, const void *B)
  94. {
  95.     const struct pattern_cache_entry *a = A, *b = B;
  96.  
  97.     return _cairo_linear_pattern_equal (&a->pattern.gradient.linear,
  98.                                         &b->pattern.gradient.linear);
  99. }
  100.  
  101. static cairo_bool_t
  102. _radial_pattern_cache_entry_equal (const void *A, const void *B)
  103. {
  104.     const struct pattern_cache_entry *a = A, *b = B;
  105.  
  106.     return _cairo_radial_pattern_equal (&a->pattern.gradient.radial,
  107.                                         &b->pattern.gradient.radial);
  108. }
  109.  
  110. static void
  111. _pattern_cache_entry_destroy (void *closure)
  112. {
  113.     struct pattern_cache_entry *entry = closure;
  114.  
  115.     _cairo_pattern_fini (&entry->pattern.base);
  116.     cairo_surface_destroy (entry->picture);
  117.     _cairo_freelist_free (&entry->screen->pattern_cache_entry_freelist, entry);
  118. }
  119.  
  120. cairo_xcb_screen_t *
  121. _cairo_xcb_screen_get (xcb_connection_t *xcb_connection,
  122.                        xcb_screen_t *xcb_screen)
  123. {
  124.     cairo_xcb_connection_t *connection;
  125.     cairo_xcb_screen_t *screen;
  126.     cairo_status_t status;
  127.     int i;
  128.  
  129.     connection = _cairo_xcb_connection_get (xcb_connection);
  130.     if (unlikely (connection == NULL))
  131.         return NULL;
  132.  
  133.     CAIRO_MUTEX_LOCK (connection->screens_mutex);
  134.  
  135.     cairo_list_foreach_entry (screen,
  136.                               cairo_xcb_screen_t,
  137.                               &connection->screens,
  138.                               link)
  139.     {
  140.         if (screen->xcb_screen == xcb_screen) {
  141.             /* Maintain list in MRU order */
  142.             if (&screen->link != connection->screens.next)
  143.                 cairo_list_move (&screen->link, &connection->screens);
  144.  
  145.             goto unlock;
  146.         }
  147.     }
  148.  
  149.     screen = malloc (sizeof (cairo_xcb_screen_t));
  150.     if (unlikely (screen == NULL))
  151.         goto unlock;
  152.  
  153.     screen->connection = connection;
  154.     screen->xcb_screen = xcb_screen;
  155.  
  156.     _cairo_freelist_init (&screen->pattern_cache_entry_freelist,
  157.                           sizeof (struct pattern_cache_entry));
  158.     cairo_list_init (&screen->link);
  159.     cairo_list_init (&screen->surfaces);
  160.     cairo_list_init (&screen->pictures);
  161.  
  162.     memset (screen->gc_depths, 0, sizeof (screen->gc_depths));
  163.     memset (screen->gc, 0, sizeof (screen->gc));
  164.  
  165.     screen->solid_cache_size = 0;
  166.     for (i = 0; i < ARRAY_LENGTH (screen->stock_colors); i++)
  167.         screen->stock_colors[i] = NULL;
  168.  
  169.     status = _cairo_cache_init (&screen->linear_pattern_cache,
  170.                                 _linear_pattern_cache_entry_equal,
  171.                                 NULL,
  172.                                 _pattern_cache_entry_destroy,
  173.                                 16);
  174.     if (unlikely (status))
  175.         goto error_screen;
  176.  
  177.     status = _cairo_cache_init (&screen->radial_pattern_cache,
  178.                                 _radial_pattern_cache_entry_equal,
  179.                                 NULL,
  180.                                 _pattern_cache_entry_destroy,
  181.                                 4);
  182.     if (unlikely (status))
  183.         goto error_linear;
  184.  
  185.     cairo_list_add (&screen->link, &connection->screens);
  186.  
  187. unlock:
  188.     CAIRO_MUTEX_UNLOCK (connection->screens_mutex);
  189.  
  190.     return screen;
  191.  
  192. error_linear:
  193.     _cairo_cache_fini (&screen->linear_pattern_cache);
  194. error_screen:
  195.     CAIRO_MUTEX_UNLOCK (connection->screens_mutex);
  196.     free (screen);
  197.  
  198.     return NULL;
  199. }
  200.  
  201. static xcb_gcontext_t
  202. _create_gc (cairo_xcb_screen_t *screen,
  203.             xcb_drawable_t drawable)
  204. {
  205.     uint32_t values[] = { 0 };
  206.  
  207.     return _cairo_xcb_connection_create_gc (screen->connection, drawable,
  208.                                             XCB_GC_GRAPHICS_EXPOSURES,
  209.                                             values);
  210. }
  211.  
  212. xcb_gcontext_t
  213. _cairo_xcb_screen_get_gc (cairo_xcb_screen_t *screen,
  214.                           xcb_drawable_t drawable,
  215.                           int depth)
  216. {
  217.     int i;
  218.  
  219.     assert (CAIRO_MUTEX_IS_LOCKED (screen->connection->device.mutex));
  220.  
  221.     for (i = 0; i < ARRAY_LENGTH (screen->gc); i++) {
  222.         if (screen->gc_depths[i] == depth) {
  223.             screen->gc_depths[i] = 0;
  224.             return screen->gc[i];
  225.         }
  226.     }
  227.  
  228.     return _create_gc (screen, drawable);
  229. }
  230.  
  231. void
  232. _cairo_xcb_screen_put_gc (cairo_xcb_screen_t *screen, int depth, xcb_gcontext_t gc)
  233. {
  234.     int i;
  235.  
  236.     assert (CAIRO_MUTEX_IS_LOCKED (screen->connection->device.mutex));
  237.  
  238.     for (i = 0; i < ARRAY_LENGTH (screen->gc); i++) {
  239.         if (screen->gc_depths[i] == 0)
  240.             break;
  241.     }
  242.  
  243.     if (i == ARRAY_LENGTH (screen->gc)) {
  244.         /* perform random substitution to ensure fair caching over depths */
  245.         i = rand () % ARRAY_LENGTH (screen->gc);
  246.         _cairo_xcb_connection_free_gc (screen->connection, screen->gc[i]);
  247.     }
  248.  
  249.     screen->gc[i] = gc;
  250.     screen->gc_depths[i] = depth;
  251. }
  252.  
  253. cairo_status_t
  254. _cairo_xcb_screen_store_linear_picture (cairo_xcb_screen_t *screen,
  255.                                         const cairo_linear_pattern_t *linear,
  256.                                         cairo_surface_t *picture)
  257. {
  258.     struct pattern_cache_entry *entry;
  259.     cairo_status_t status;
  260.  
  261.     assert (CAIRO_MUTEX_IS_LOCKED (screen->connection->device.mutex));
  262.  
  263.     entry = _cairo_freelist_alloc (&screen->pattern_cache_entry_freelist);
  264.     if (unlikely (entry == NULL))
  265.         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
  266.  
  267.     entry->key.hash = _cairo_linear_pattern_hash (_CAIRO_HASH_INIT_VALUE, linear);
  268.     entry->key.size = 1;
  269.  
  270.     status = _cairo_pattern_init_copy (&entry->pattern.base, &linear->base.base);
  271.     if (unlikely (status)) {
  272.         _cairo_freelist_free (&screen->pattern_cache_entry_freelist, entry);
  273.         return status;
  274.     }
  275.  
  276.     entry->picture = cairo_surface_reference (picture);
  277.     entry->screen = screen;
  278.  
  279.     status = _cairo_cache_insert (&screen->linear_pattern_cache,
  280.                                   &entry->key);
  281.     if (unlikely (status)) {
  282.         cairo_surface_destroy (picture);
  283.         _cairo_freelist_free (&screen->pattern_cache_entry_freelist, entry);
  284.         return status;
  285.     }
  286.  
  287.     return CAIRO_STATUS_SUCCESS;
  288. }
  289.  
  290. cairo_surface_t *
  291. _cairo_xcb_screen_lookup_linear_picture (cairo_xcb_screen_t *screen,
  292.                                          const cairo_linear_pattern_t *linear)
  293. {
  294.     cairo_surface_t *picture = NULL;
  295.     struct pattern_cache_entry tmpl;
  296.     struct pattern_cache_entry *entry;
  297.  
  298.     assert (CAIRO_MUTEX_IS_LOCKED (screen->connection->device.mutex));
  299.  
  300.     tmpl.key.hash = _cairo_linear_pattern_hash (_CAIRO_HASH_INIT_VALUE, linear);
  301.     _cairo_pattern_init_static_copy (&tmpl.pattern.base, &linear->base.base);
  302.  
  303.     entry = _cairo_cache_lookup (&screen->linear_pattern_cache, &tmpl.key);
  304.     if (entry != NULL)
  305.         picture = cairo_surface_reference (entry->picture);
  306.  
  307.     return picture;
  308. }
  309.  
  310. cairo_status_t
  311. _cairo_xcb_screen_store_radial_picture (cairo_xcb_screen_t *screen,
  312.                                         const cairo_radial_pattern_t *radial,
  313.                                         cairo_surface_t *picture)
  314. {
  315.     struct pattern_cache_entry *entry;
  316.     cairo_status_t status;
  317.  
  318.     assert (CAIRO_MUTEX_IS_LOCKED (screen->connection->device.mutex));
  319.  
  320.     entry = _cairo_freelist_alloc (&screen->pattern_cache_entry_freelist);
  321.     if (unlikely (entry == NULL))
  322.         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
  323.  
  324.     entry->key.hash = _cairo_radial_pattern_hash (_CAIRO_HASH_INIT_VALUE, radial);
  325.     entry->key.size = 1;
  326.  
  327.     status = _cairo_pattern_init_copy (&entry->pattern.base, &radial->base.base);
  328.     if (unlikely (status)) {
  329.         _cairo_freelist_free (&screen->pattern_cache_entry_freelist, entry);
  330.         return status;
  331.     }
  332.  
  333.     entry->picture = cairo_surface_reference (picture);
  334.     entry->screen = screen;
  335.  
  336.     status = _cairo_cache_insert (&screen->radial_pattern_cache, &entry->key);
  337.     if (unlikely (status)) {
  338.         cairo_surface_destroy (picture);
  339.         _cairo_freelist_free (&screen->pattern_cache_entry_freelist, entry);
  340.         return status;
  341.     }
  342.  
  343.     return CAIRO_STATUS_SUCCESS;
  344. }
  345.  
  346. cairo_surface_t *
  347. _cairo_xcb_screen_lookup_radial_picture (cairo_xcb_screen_t *screen,
  348.                                          const cairo_radial_pattern_t *radial)
  349. {
  350.     cairo_surface_t *picture = NULL;
  351.     struct pattern_cache_entry tmpl;
  352.     struct pattern_cache_entry *entry;
  353.  
  354.     assert (CAIRO_MUTEX_IS_LOCKED (screen->connection->device.mutex));
  355.  
  356.     tmpl.key.hash = _cairo_radial_pattern_hash (_CAIRO_HASH_INIT_VALUE, radial);
  357.     _cairo_pattern_init_static_copy (&tmpl.pattern.base, &radial->base.base);
  358.  
  359.     entry = _cairo_cache_lookup (&screen->radial_pattern_cache, &tmpl.key);
  360.     if (entry != NULL)
  361.         picture = cairo_surface_reference (entry->picture);
  362.  
  363.     return picture;
  364. }
  365.