VirtualBox

source: vbox/trunk/src/VBox/RDP/client/cache.c@ 14833

Last change on this file since 14833 was 11982, checked in by vboxsync, 16 years ago

All: license header changes for 2.0 (OSE headers, add Sun GPL/LGPL disclaimer)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 9.5 KB
Line 
1/* -*- c-basic-offset: 8 -*-
2 rdesktop: A Remote Desktop Protocol client.
3 Cache routines
4 Copyright (C) Matthew Chapman 1999-2007
5 Copyright (C) Jeroen Meijer 2005
6
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.
11
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.
16
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.
20*/
21
22/*
23 * Sun GPL Disclaimer: For the avoidance of doubt, except that if any license choice
24 * other than GPL or LGPL is available it will apply instead, Sun elects to use only
25 * the General Public License version 2 (GPLv2) at this time for any software where
26 * a choice of GPL license versions is made available with the language indicating
27 * that GPLv2 or any later version may be used, or where a choice of which version
28 * of the GPL is applied is otherwise unspecified.
29 */
30
31#include "rdesktop.h"
32
33/* BITMAP CACHE */
34extern int g_pstcache_fd[];
35
36#define NUM_ELEMENTS(array) (sizeof(array) / sizeof(array[0]))
37#define IS_PERSISTENT(id) (g_pstcache_fd[id] > 0)
38#define TO_TOP -1
39#define NOT_SET -1
40#define IS_SET(idx) (idx >= 0)
41
42/*
43 * TODO: Test for optimal value of BUMP_COUNT. TO_TOP gives lowest cpu utilisation but using
44 * a positive value will hopefully result in less frequently used bitmaps having a greater chance
45 * of being evicted from the cache, and therby reducing the need to load bitmaps from disk.
46 * (Jeroen)
47 */
48#define BUMP_COUNT 40
49
50struct bmpcache_entry
51{
52 RD_HBITMAP bitmap;
53 sint16 previous;
54 sint16 next;
55};
56
57static struct bmpcache_entry g_bmpcache[3][0xa00];
58static RD_HBITMAP g_volatile_bc[3];
59
60static int g_bmpcache_lru[3] = { NOT_SET, NOT_SET, NOT_SET };
61static int g_bmpcache_mru[3] = { NOT_SET, NOT_SET, NOT_SET };
62static int g_bmpcache_count[3];
63
64/* Setup the bitmap cache lru/mru linked list */
65void
66cache_rebuild_bmpcache_linked_list(uint8 id, sint16 * idx, int count)
67{
68 int n = count, c = 0;
69 sint16 n_idx;
70
71 /* find top, skip evicted bitmaps */
72 while (--n >= 0 && g_bmpcache[id][idx[n]].bitmap == NULL);
73 if (n < 0)
74 {
75 g_bmpcache_mru[id] = g_bmpcache_lru[id] = NOT_SET;
76 return;
77 }
78
79 g_bmpcache_mru[id] = idx[n];
80 g_bmpcache[id][idx[n]].next = NOT_SET;
81 n_idx = idx[n];
82 c++;
83
84 /* link list */
85 while (n >= 0)
86 {
87 /* skip evicted bitmaps */
88 while (--n >= 0 && g_bmpcache[id][idx[n]].bitmap == NULL);
89
90 if (n < 0)
91 break;
92
93 g_bmpcache[id][n_idx].previous = idx[n];
94 g_bmpcache[id][idx[n]].next = n_idx;
95 n_idx = idx[n];
96 c++;
97 }
98
99 g_bmpcache[id][n_idx].previous = NOT_SET;
100 g_bmpcache_lru[id] = n_idx;
101
102 if (c != g_bmpcache_count[id])
103 {
104 error("Oops. %d in bitmap cache linked list, %d in ui cache...\n", c,
105 g_bmpcache_count[id]);
106 exit(1);
107 }
108}
109
110/* Move a bitmap to a new position in the linked list. */
111void
112cache_bump_bitmap(uint8 id, uint16 idx, int bump)
113{
114 int p_idx, n_idx, n;
115
116 if (!IS_PERSISTENT(id))
117 return;
118
119 if (g_bmpcache_mru[id] == idx)
120 return;
121
122 DEBUG_RDP5(("bump bitmap: id=%d, idx=%d, bump=%d\n", id, idx, bump));
123
124 n_idx = g_bmpcache[id][idx].next;
125 p_idx = g_bmpcache[id][idx].previous;
126
127 if (IS_SET(n_idx))
128 {
129 /* remove */
130 --g_bmpcache_count[id];
131 if (IS_SET(p_idx))
132 g_bmpcache[id][p_idx].next = n_idx;
133 else
134 g_bmpcache_lru[id] = n_idx;
135 if (IS_SET(n_idx))
136 g_bmpcache[id][n_idx].previous = p_idx;
137 else
138 g_bmpcache_mru[id] = p_idx;
139 }
140 else
141 {
142 p_idx = NOT_SET;
143 n_idx = g_bmpcache_lru[id];
144 }
145
146 if (bump >= 0)
147 {
148 for (n = 0; n < bump && IS_SET(n_idx); n++)
149 {
150 p_idx = n_idx;
151 n_idx = g_bmpcache[id][p_idx].next;
152 }
153 }
154 else
155 {
156 p_idx = g_bmpcache_mru[id];
157 n_idx = NOT_SET;
158 }
159
160 /* insert */
161 ++g_bmpcache_count[id];
162 g_bmpcache[id][idx].previous = p_idx;
163 g_bmpcache[id][idx].next = n_idx;
164
165 if (p_idx >= 0)
166 g_bmpcache[id][p_idx].next = idx;
167 else
168 g_bmpcache_lru[id] = idx;
169
170 if (n_idx >= 0)
171 g_bmpcache[id][n_idx].previous = idx;
172 else
173 g_bmpcache_mru[id] = idx;
174}
175
176/* Evict the least-recently used bitmap from the cache */
177void
178cache_evict_bitmap(uint8 id)
179{
180 uint16 idx;
181 int n_idx;
182
183 if (!IS_PERSISTENT(id))
184 return;
185
186 idx = g_bmpcache_lru[id];
187 n_idx = g_bmpcache[id][idx].next;
188 DEBUG_RDP5(("evict bitmap: id=%d idx=%d n_idx=%d bmp=0x%x\n", id, idx, n_idx,
189 g_bmpcache[id][idx].bitmap));
190
191 ui_destroy_bitmap(g_bmpcache[id][idx].bitmap);
192 --g_bmpcache_count[id];
193 g_bmpcache[id][idx].bitmap = 0;
194
195 g_bmpcache_lru[id] = n_idx;
196 g_bmpcache[id][n_idx].previous = NOT_SET;
197
198 pstcache_touch_bitmap(id, idx, 0);
199}
200
201/* Retrieve a bitmap from the cache */
202RD_HBITMAP
203cache_get_bitmap(uint8 id, uint16 idx)
204{
205 if ((id < NUM_ELEMENTS(g_bmpcache)) && (idx < NUM_ELEMENTS(g_bmpcache[0])))
206 {
207 if (g_bmpcache[id][idx].bitmap || pstcache_load_bitmap(id, idx))
208 {
209 if (IS_PERSISTENT(id))
210 cache_bump_bitmap(id, idx, BUMP_COUNT);
211
212 return g_bmpcache[id][idx].bitmap;
213 }
214 }
215 else if ((id < NUM_ELEMENTS(g_volatile_bc)) && (idx == 0x7fff))
216 {
217 return g_volatile_bc[id];
218 }
219
220 error("get bitmap %d:%d\n", id, idx);
221 return NULL;
222}
223
224/* Store a bitmap in the cache */
225void
226cache_put_bitmap(uint8 id, uint16 idx, RD_HBITMAP bitmap)
227{
228 RD_HBITMAP old;
229
230 if ((id < NUM_ELEMENTS(g_bmpcache)) && (idx < NUM_ELEMENTS(g_bmpcache[0])))
231 {
232 old = g_bmpcache[id][idx].bitmap;
233 if (old != NULL)
234 ui_destroy_bitmap(old);
235 g_bmpcache[id][idx].bitmap = bitmap;
236
237 if (IS_PERSISTENT(id))
238 {
239 if (old == NULL)
240 g_bmpcache[id][idx].previous = g_bmpcache[id][idx].next = NOT_SET;
241
242 cache_bump_bitmap(id, idx, TO_TOP);
243 if (g_bmpcache_count[id] > BMPCACHE2_C2_CELLS)
244 cache_evict_bitmap(id);
245 }
246 }
247 else if ((id < NUM_ELEMENTS(g_volatile_bc)) && (idx == 0x7fff))
248 {
249 old = g_volatile_bc[id];
250 if (old != NULL)
251 ui_destroy_bitmap(old);
252 g_volatile_bc[id] = bitmap;
253 }
254 else
255 {
256 error("put bitmap %d:%d\n", id, idx);
257 }
258}
259
260/* Updates the persistent bitmap cache MRU information on exit */
261void
262cache_save_state(void)
263{
264 uint32 id = 0, t = 0;
265 int idx;
266
267 for (id = 0; id < NUM_ELEMENTS(g_bmpcache); id++)
268 if (IS_PERSISTENT(id))
269 {
270 DEBUG_RDP5(("Saving cache state for bitmap cache %d...", id));
271 idx = g_bmpcache_lru[id];
272 while (idx >= 0)
273 {
274 pstcache_touch_bitmap(id, idx, ++t);
275 idx = g_bmpcache[id][idx].next;
276 }
277 DEBUG_RDP5((" %d stamps written.\n", t));
278 }
279}
280
281
282/* FONT CACHE */
283static FONTGLYPH g_fontcache[12][256];
284
285/* Retrieve a glyph from the font cache */
286FONTGLYPH *
287cache_get_font(uint8 font, uint16 character)
288{
289 FONTGLYPH *glyph;
290
291 if ((font < NUM_ELEMENTS(g_fontcache)) && (character < NUM_ELEMENTS(g_fontcache[0])))
292 {
293 glyph = &g_fontcache[font][character];
294 if (glyph->pixmap != NULL)
295 return glyph;
296 }
297
298 error("get font %d:%d\n", font, character);
299 return NULL;
300}
301
302/* Store a glyph in the font cache */
303void
304cache_put_font(uint8 font, uint16 character, uint16 offset,
305 uint16 baseline, uint16 width, uint16 height, RD_HGLYPH pixmap)
306{
307 FONTGLYPH *glyph;
308
309 if ((font < NUM_ELEMENTS(g_fontcache)) && (character < NUM_ELEMENTS(g_fontcache[0])))
310 {
311 glyph = &g_fontcache[font][character];
312 if (glyph->pixmap != NULL)
313 ui_destroy_glyph(glyph->pixmap);
314
315 glyph->offset = offset;
316 glyph->baseline = baseline;
317 glyph->width = width;
318 glyph->height = height;
319 glyph->pixmap = pixmap;
320 }
321 else
322 {
323 error("put font %d:%d\n", font, character);
324 }
325}
326
327
328/* TEXT CACHE */
329static DATABLOB g_textcache[256];
330
331/* Retrieve a text item from the cache */
332DATABLOB *
333cache_get_text(uint8 cache_id)
334{
335 DATABLOB *text;
336
337 text = &g_textcache[cache_id];
338 return text;
339}
340
341/* Store a text item in the cache */
342void
343cache_put_text(uint8 cache_id, void *data, int length)
344{
345 DATABLOB *text;
346
347 text = &g_textcache[cache_id];
348 if (text->data != NULL)
349 xfree(text->data);
350 text->data = xmalloc(length);
351 text->size = length;
352 memcpy(text->data, data, length);
353}
354
355
356/* DESKTOP CACHE */
357static uint8 g_deskcache[0x38400 * 4];
358
359/* Retrieve desktop data from the cache */
360uint8 *
361cache_get_desktop(uint32 offset, int cx, int cy, int bytes_per_pixel)
362{
363 int length = cx * cy * bytes_per_pixel;
364
365 if (offset > sizeof(g_deskcache))
366 offset = 0;
367
368 if ((offset + length) <= sizeof(g_deskcache))
369 {
370 return &g_deskcache[offset];
371 }
372
373 error("get desktop %d:%d\n", offset, length);
374 return NULL;
375}
376
377/* Store desktop data in the cache */
378void
379cache_put_desktop(uint32 offset, int cx, int cy, int scanline, int bytes_per_pixel, uint8 * data)
380{
381 int length = cx * cy * bytes_per_pixel;
382
383 if (offset > sizeof(g_deskcache))
384 offset = 0;
385
386 if ((offset + length) <= sizeof(g_deskcache))
387 {
388 cx *= bytes_per_pixel;
389 while (cy--)
390 {
391 memcpy(&g_deskcache[offset], data, cx);
392 data += scanline;
393 offset += cx;
394 }
395 }
396 else
397 {
398 error("put desktop %d:%d\n", offset, length);
399 }
400}
401
402
403/* CURSOR CACHE */
404static RD_HCURSOR g_cursorcache[0x20];
405
406/* Retrieve cursor from cache */
407RD_HCURSOR
408cache_get_cursor(uint16 cache_idx)
409{
410 RD_HCURSOR cursor;
411
412 if (cache_idx < NUM_ELEMENTS(g_cursorcache))
413 {
414 cursor = g_cursorcache[cache_idx];
415 if (cursor != NULL)
416 return cursor;
417 }
418
419 error("get cursor %d\n", cache_idx);
420 return NULL;
421}
422
423/* Store cursor in cache */
424void
425cache_put_cursor(uint16 cache_idx, RD_HCURSOR cursor)
426{
427 RD_HCURSOR old;
428
429 if (cache_idx < NUM_ELEMENTS(g_cursorcache))
430 {
431 old = g_cursorcache[cache_idx];
432 if (old != NULL)
433 ui_destroy_cursor(old);
434
435 g_cursorcache[cache_idx] = cursor;
436 }
437 else
438 {
439 error("put cursor %d\n", cache_idx);
440 }
441}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette