comparison src/xgccache.c @ 185:3d6bfa290dbd r20-3b19

Import from CVS: tag r20-3b19
author cvs
date Mon, 13 Aug 2007 09:55:28 +0200
parents 376386a54a3c
children c5d627a313b1
comparison
equal deleted inserted replaced
184:bcd2674570bf 185:3d6bfa290dbd
24 /* Emacs uses a lot of different display attributes; for example, assume 24 /* Emacs uses a lot of different display attributes; for example, assume
25 that only four fonts are in use (normal, bold, italic, and bold-italic). 25 that only four fonts are in use (normal, bold, italic, and bold-italic).
26 Then assume that one stipple or background is used for text selections, 26 Then assume that one stipple or background is used for text selections,
27 and another is used for highlighting mousable regions. That makes 16 27 and another is used for highlighting mousable regions. That makes 16
28 GCs already. Add in the fact that another GC may be needed to display 28 GCs already. Add in the fact that another GC may be needed to display
29 the text cursor in any of those regions, and you've got 32. Add in 29 the text cursor in any of those regions, and you've got 32. Add in
30 more fonts, and it keeps increasing exponentially. 30 more fonts, and it keeps increasing exponentially.
31 31
32 We used to keep these GCs in a cache of merged (fully qualified) faces. 32 We used to keep these GCs in a cache of merged (fully qualified) faces.
33 However, a lot of other code in xterm.c used XChangeGC of existing GCs, 33 However, a lot of other code in xterm.c used XChangeGC of existing GCs,
34 which is kind of slow and kind of random. Also, managing the face cache 34 which is kind of slow and kind of random. Also, managing the face cache
35 was tricky because it was hard to know when a face was no longer visible 35 was tricky because it was hard to know when a face was no longer visible
36 on the frame -- we had to mark all frames as garbaged whenever a face 36 on the frame -- we had to mark all frames as garbaged whenever a face
37 was changed, which caused an unpleasant amount of flicker (since faces are 37 was changed, which caused an unpleasant amount of flicker (since faces are
38 created/destroyed (= changed) whenever a frame is created/destroyed. 38 created/destroyed (= changed) whenever a frame is created/destroyed.
39 39
40 So this code maintains a cache at the GC level instead of at the face 40 So this code maintains a cache at the GC level instead of at the face
41 level. There is an upper limit on the size of the cache, after which we 41 level. There is an upper limit on the size of the cache, after which we
42 will stop creating GCs and start reusing them (reusing the least-recently- 42 will stop creating GCs and start reusing them (reusing the least-recently-
43 used ones first). So if faces get changed, their GCs will eventually be 43 used ones first). So if faces get changed, their GCs will eventually be
44 recycled. Also more sharing of GCs is possible. 44 recycled. Also more sharing of GCs is possible.
45 45
90 int create_count; 90 int create_count;
91 int delete_count; 91 int delete_count;
92 }; 92 };
93 93
94 #ifdef GCCACHE_HASH 94 #ifdef GCCACHE_HASH
95 static unsigned long 95 static unsigned long
96 gc_cache_hash (CONST void *arg) 96 gc_cache_hash (CONST void *arg)
97 { 97 {
98 CONST struct gcv_and_mask *gcvm = (CONST struct gcv_and_mask *) arg; 98 CONST struct gcv_and_mask *gcvm = (CONST struct gcv_and_mask *) arg;
99 unsigned long *longs = (unsigned long *) &gcvm->gcv; 99 unsigned long *longs = (unsigned long *) &gcvm->gcv;
100 unsigned long hash = gcvm->mask; 100 unsigned long hash = gcvm->mask;
109 return hash; 109 return hash;
110 } 110 }
111 111
112 #endif /* GCCACHE_HASH */ 112 #endif /* GCCACHE_HASH */
113 113
114 static int 114 static int
115 gc_cache_eql (CONST void *arg1, CONST void *arg2) 115 gc_cache_eql (CONST void *arg1, CONST void *arg2)
116 { 116 {
117 /* See comment in gc_cache_hash */ 117 /* See comment in gc_cache_hash */
118 return (!memcmp (arg1, arg2, sizeof (struct gcv_and_mask))); 118 return !memcmp (arg1, arg2, sizeof (struct gcv_and_mask));
119 } 119 }
120 120
121 struct gc_cache * 121 struct gc_cache *
122 make_gc_cache (Display *dpy, Window window) 122 make_gc_cache (Display *dpy, Window window)
123 { 123 {
124 struct gc_cache *cache = 124 struct gc_cache *cache = xnew (struct gc_cache);
125 (struct gc_cache *) xmalloc (sizeof (struct gc_cache));
126 cache->dpy = dpy; 125 cache->dpy = dpy;
127 cache->window = window; 126 cache->window = window;
128 cache->size = 0; 127 cache->size = 0;
129 cache->head = cache->tail = 0; 128 cache->head = cache->tail = 0;
130 cache->create_count = cache->delete_count = 0; 129 cache->create_count = cache->delete_count = 0;
165 gcvm.mask = mask; 164 gcvm.mask = mask;
166 gcvm.gcv = *gcv; /* this copies... */ 165 gcvm.gcv = *gcv; /* this copies... */
167 166
168 #ifdef GCCACHE_HASH 167 #ifdef GCCACHE_HASH
169 168
170 if (gethash (&gcvm, cache->table, (void *) &cell)) 169 if (gethash (&gcvm, cache->table, (void **) &cell))
171 170
172 #else /* !GCCACHE_HASH */ 171 #else /* !GCCACHE_HASH */
173 172
174 cell = cache->tail; /* start at the end (most recently used) */ 173 cell = cache->tail; /* start at the end (most recently used) */
175 while (cell) 174 while (cell)
233 } 232 }
234 else if (cache->size > GC_CACHE_SIZE) 233 else if (cache->size > GC_CACHE_SIZE)
235 abort (); 234 abort ();
236 else 235 else
237 { 236 {
238 /* Allocate a new cell (don't put it in the list or table yet). 237 /* Allocate a new cell (don't put it in the list or table yet). */
239 */ 238 cell = xnew (struct gc_cache_cell);
240 cell = (struct gc_cache_cell *) xmalloc (sizeof (struct gc_cache_cell));
241 cache->size++; 239 cache->size++;
242 } 240 }
243 241
244 /* Now we've got a cell (new or reused). Fill it in. */ 242 /* Now we've got a cell (new or reused). Fill it in. */
245 memcpy (&cell->gcvm.gcv, gcv, sizeof (XGCValues)); 243 memcpy (&cell->gcvm.gcv, gcv, sizeof (XGCValues));