1
/* -*- c-basic-offset: 8 -*-
2
rdesktop: A Remote Desktop Protocol client.
4
Copyright (C) Matthew Chapman 1999-2008
5
Copyright (C) Jeroen Meijer 2005
7
This program is free software; you can redistribute it and/or modify
8
it under the terms of the GNU General Public License as published by
9
the Free Software Foundation; either version 2 of the License, or
10
(at your option) any later version.
12
This program is distributed in the hope that it will be useful,
13
but WITHOUT ANY WARRANTY; without even the implied warranty of
14
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
GNU General Public License for more details.
17
You should have received a copy of the GNU General Public License
18
along with this program; if not, write to the Free Software
19
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
29
#define NUM_ELEMENTS(array) (sizeof(array) / sizeof(array[0]))
30
#define IS_PERSISTENT(id) (cache->rdp->pcache->pstcache_fd[id] > 0)
33
#define IS_SET(idx) (idx >= 0)
36
* TODO: Test for optimal value of BUMP_COUNT. TO_TOP gives lowest cpu utilisation but using
37
* a positive value will hopefully result in less frequently used bitmaps having a greater chance
38
* of being evicted from the cache, and therby reducing the need to load bitmaps from disk.
43
/* Setup the bitmap cache lru/mru linked list */
45
cache_rebuild_bmpcache_linked_list(rdpCache * cache, uint8 id, sint16 * idx, int count)
50
/* find top, skip evicted bitmaps */
51
while (--n >= 0 && cache->bmpcache[id][idx[n]].bitmap == NULL);
54
cache->bmpcache_mru[id] = cache->bmpcache_lru[id] = NOT_SET;
58
cache->bmpcache_mru[id] = idx[n];
59
cache->bmpcache[id][idx[n]].next = NOT_SET;
66
/* skip evicted bitmaps */
67
while (--n >= 0 && cache->bmpcache[id][idx[n]].bitmap == NULL);
72
cache->bmpcache[id][n_idx].previous = idx[n];
73
cache->bmpcache[id][idx[n]].next = n_idx;
78
cache->bmpcache[id][n_idx].previous = NOT_SET;
79
cache->bmpcache_lru[id] = n_idx;
81
if (c != cache->bmpcache_count[id])
83
ui_error(cache->rdp->inst, "Oops. %d in bitmap cache linked list, %d in ui "
84
"cache...\n", c, cache->bmpcache_count[id]);
89
/* Move a bitmap to a new position in the linked list. */
91
cache_bump_bitmap(rdpCache * cache, uint8 id, uint16 idx, int bump)
95
if (!IS_PERSISTENT(id))
98
if (cache->bmpcache_mru[id] == idx)
101
DEBUG_RDP5("bump bitmap: id=%d, idx=%d, bump=%d\n", id, idx, bump);
103
n_idx = cache->bmpcache[id][idx].next;
104
p_idx = cache->bmpcache[id][idx].previous;
109
--(cache->bmpcache_count[id]);
111
cache->bmpcache[id][p_idx].next = n_idx;
113
cache->bmpcache_lru[id] = n_idx;
115
cache->bmpcache[id][n_idx].previous = p_idx;
117
cache->bmpcache_mru[id] = p_idx;
122
n_idx = cache->bmpcache_lru[id];
127
for (n = 0; n < bump && IS_SET(n_idx); n++)
130
n_idx = cache->bmpcache[id][p_idx].next;
135
p_idx = cache->bmpcache_mru[id];
140
++(cache->bmpcache_count[id]);
141
cache->bmpcache[id][idx].previous = p_idx;
142
cache->bmpcache[id][idx].next = n_idx;
145
cache->bmpcache[id][p_idx].next = idx;
147
cache->bmpcache_lru[id] = idx;
150
cache->bmpcache[id][n_idx].previous = idx;
152
cache->bmpcache_mru[id] = idx;
155
/* Evict the least-recently used bitmap from the cache */
157
cache_evict_bitmap(rdpCache * cache, uint8 id)
162
if (!IS_PERSISTENT(id))
165
idx = cache->bmpcache_lru[id];
166
n_idx = cache->bmpcache[id][idx].next;
167
/* DEBUG_RDP5("evict bitmap: id=%d idx=%d n_idx=%d bmp=0x%x\n", id, idx, n_idx,
168
cache->bmpcache[id][idx].bitmap); */
170
ui_destroy_bitmap(cache->rdp->inst, cache->bmpcache[id][idx].bitmap);
171
--(cache->bmpcache_count[id]);
172
cache->bmpcache[id][idx].bitmap = 0;
174
cache->bmpcache_lru[id] = n_idx;
175
cache->bmpcache[id][n_idx].previous = NOT_SET;
177
pstcache_touch_bitmap(cache->rdp->pcache, id, idx, 0);
180
/* Retrieve a bitmap from the cache */
182
cache_get_bitmap(rdpCache * cache, uint8 id, uint16 idx)
184
if ((id < NUM_ELEMENTS(cache->bmpcache)) && (idx < NUM_ELEMENTS(cache->bmpcache[0])))
186
if (cache->bmpcache[id][idx].bitmap ||
187
pstcache_load_bitmap(cache->rdp->pcache, id, idx))
189
if (IS_PERSISTENT(id))
190
cache_bump_bitmap(cache, id, idx, BUMP_COUNT);
192
return cache->bmpcache[id][idx].bitmap;
195
else if ((id < NUM_ELEMENTS(cache->volatile_bc)) && (idx == 0x7fff))
197
return cache->volatile_bc[id];
199
else if ((id == 255) && (idx < NUM_ELEMENTS(cache->drawing_surface)))
201
return cache->drawing_surface[idx];
203
ui_error(cache->rdp->inst, "get bitmap %d:%d\n", id, idx);
207
/* Store a bitmap in the cache */
209
cache_put_bitmap(rdpCache * cache, uint8 id, uint16 idx, RD_HBITMAP bitmap)
213
if ((id < NUM_ELEMENTS(cache->bmpcache)) && (idx < NUM_ELEMENTS(cache->bmpcache[0])))
215
old = cache->bmpcache[id][idx].bitmap;
217
ui_destroy_bitmap(cache->rdp->inst, old);
218
cache->bmpcache[id][idx].bitmap = bitmap;
220
if (IS_PERSISTENT(id))
223
cache->bmpcache[id][idx].previous =
224
cache->bmpcache[id][idx].next = NOT_SET;
226
cache_bump_bitmap(cache, id, idx, TO_TOP);
227
if (cache->bmpcache_count[id] > BMPCACHE2_C2_CELLS)
228
cache_evict_bitmap(cache, id);
231
else if ((id < NUM_ELEMENTS(cache->volatile_bc)) && (idx == 0x7fff))
233
old = cache->volatile_bc[id];
235
ui_destroy_bitmap(cache->rdp->inst, old);
236
cache->volatile_bc[id] = bitmap;
238
else if ((id == 255) && (idx < NUM_ELEMENTS(cache->drawing_surface)))
240
cache->drawing_surface[idx] = bitmap;
244
ui_error(cache->rdp->inst, "put bitmap %d:%d\n", id, idx);
248
/* Updates the persistent bitmap cache MRU information on exit */
250
cache_save_state(rdpCache * cache)
252
uint32 id = 0, t = 0;
255
for (id = 0; id < NUM_ELEMENTS(cache->bmpcache); id++)
256
if (IS_PERSISTENT(id))
258
DEBUG_RDP5("Saving cache state for bitmap cache %d...", id);
259
idx = cache->bmpcache_lru[id];
262
pstcache_touch_bitmap(cache->rdp->pcache, id, idx, ++t);
263
idx = cache->bmpcache[id][idx].next;
265
DEBUG_RDP5(" %d stamps written.\n", t);
269
/* Retrieve a glyph from the font cache */
271
cache_get_font(rdpCache * cache, uint8 font, uint16 character)
275
if ((font < NUM_ELEMENTS(cache->fontcache)) && (character < NUM_ELEMENTS(cache->fontcache[0])))
277
glyph = &(cache->fontcache[font][character]);
278
if (glyph->pixmap != NULL)
282
ui_error(cache->rdp->inst, "get font %d:%d\n", font, character);
286
/* Store a glyph in the font cache */
288
cache_put_font(rdpCache * cache, uint8 font, uint16 character, uint16 offset,
289
uint16 baseline, uint16 width, uint16 height, RD_HGLYPH pixmap)
293
if ((font < NUM_ELEMENTS(cache->fontcache)) && (character < NUM_ELEMENTS(cache->fontcache[0])))
295
glyph = &(cache->fontcache[font][character]);
296
if (glyph->pixmap != NULL)
297
ui_destroy_glyph(cache->rdp->inst, glyph->pixmap);
299
glyph->offset = offset;
300
glyph->baseline = baseline;
301
glyph->width = width;
302
glyph->height = height;
303
glyph->pixmap = pixmap;
307
ui_error(cache->rdp->inst, "put font %d:%d\n", font, character);
311
/* Retrieve a text item from the cache */
313
cache_get_text(rdpCache * cache, uint8 cache_id)
317
text = &(cache->textcache[cache_id]);
321
/* Store a text item in the cache */
323
cache_put_text(rdpCache * cache, uint8 cache_id, void *data, int length)
327
text = &(cache->textcache[cache_id]);
328
if (text->data != NULL)
330
text->data = xmalloc(length);
332
memcpy(text->data, data, length);
335
/* Retrieve cursor from cache */
337
cache_get_cursor(rdpCache * cache, uint16 cache_idx)
341
if (cache_idx < NUM_ELEMENTS(cache->cursorcache))
343
cursor = cache->cursorcache[cache_idx];
348
ui_error(cache->rdp->inst, "get cursor %d\n", cache_idx);
352
/* Store cursor in cache */
354
cache_put_cursor(rdpCache * cache, uint16 cache_idx, RD_HCURSOR cursor)
358
if (cache_idx < NUM_ELEMENTS(cache->cursorcache))
360
old = cache->cursorcache[cache_idx];
362
ui_destroy_cursor(cache->rdp->inst, old);
364
cache->cursorcache[cache_idx] = cursor;
368
ui_error(cache->rdp->inst, "put cursor %d\n", cache_idx);
372
/* Retrieve brush from cache */
374
cache_get_brush_data(rdpCache * cache, uint8 color_code, uint8 idx)
376
color_code = color_code == 1 ? 0 : 1;
377
if (idx < NUM_ELEMENTS(cache->brushcache[0]))
379
return &(cache->brushcache[color_code][idx]);
381
ui_error(cache->rdp->inst, "get brush %d %d\n", color_code, idx);
385
/* Store brush in cache */
386
/* this function takes over the data pointer in struct, eg, caller gives it up */
388
cache_put_brush_data(rdpCache * cache, uint8 color_code, uint8 idx, RD_BRUSHDATA * brush_data)
392
color_code = color_code == 1 ? 0 : 1;
393
if (idx < NUM_ELEMENTS(cache->brushcache[0]))
395
bd = &(cache->brushcache[color_code][idx]);
396
if (bd->data != NULL)
400
memcpy(bd, brush_data, sizeof(RD_BRUSHDATA));
404
ui_error(cache->rdp->inst, "put brush %d %d\n", color_code, idx);
409
cache_new(struct rdp_rdp * rdp)
413
self = (rdpCache *) xmalloc(sizeof(rdpCache));
416
memset(self, 0, sizeof(rdpCache));
418
self->bmpcache_lru[0] = NOT_SET;
419
self->bmpcache_lru[1] = NOT_SET;
420
self->bmpcache_lru[2] = NOT_SET;
421
self->bmpcache_mru[0] = NOT_SET;
422
self->bmpcache_mru[1] = NOT_SET;
423
self->bmpcache_mru[2] = NOT_SET;
429
cache_free(rdpCache * cache)
437
for (color_code = 0; color_code < NUM_ELEMENTS(cache->brushcache); color_code++)
439
for(idx = 0; idx < NUM_ELEMENTS(cache->brushcache[color_code]); idx++)
441
bd = &(cache->brushcache[color_code][idx]);
442
if (bd->data != NULL)
454
for (cache_id = 0; cache_id < NUM_ELEMENTS(cache->textcache); cache_id++)
456
text = &(cache->textcache[cache_id]);
457
if (text->data != NULL)
467
for (cache_id = 0; cache_id < NUM_ELEMENTS(cache->bmpcache); cache_id++)
469
for (cache_idx = 0; cache_idx < NUM_ELEMENTS(cache->bmpcache[0]); cache_idx++)
471
bmp = cache->bmpcache[cache_id][cache_idx].bitmap;
473
ui_destroy_bitmap(cache->rdp->inst, bmp);
476
for (cache_id = 0; cache_id < NUM_ELEMENTS(cache->drawing_surface); cache_id++)
478
bmp = cache->drawing_surface[cache_id];
480
ui_destroy_surface(cache->rdp->inst, bmp);
488
for (cache_id = 0; cache_id < NUM_ELEMENTS(cache->cursorcache); cache_id++)
490
cursor = cache->cursorcache[cache_id];
492
ui_destroy_cursor(cache->rdp->inst, cursor);
501
for (cache_id = 0; cache_id < NUM_ELEMENTS(cache->fontcache); cache_id++)
503
for (cache_idx = 0; cache_idx < NUM_ELEMENTS(cache->fontcache[0]); cache_idx++)
505
glyph = cache->fontcache[cache_id][cache_idx].pixmap;
507
ui_destroy_glyph(cache->rdp->inst, glyph);