VirtualBox

source: vbox/trunk/src/VBox/RDP/client-1.8.4/cache.c@ 94377

Last change on this file since 94377 was 55123, checked in by vboxsync, 10 years ago

rdesktop 1.8.3 modified for VBox

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 10.5 KB
Line 
1/* -*- c-basic-offset: 8 -*-
2 rdesktop: A Remote Desktop Protocol client.
3 Cache routines
4 Copyright (C) Matthew Chapman <matthewc.unsw.edu.au> 1999-2008
5 Copyright (C) Jeroen Meijer <jeroen@oldambt7.com> 2005
6 Copyright 2003-2011 Peter Astrand <astrand@cendio.se> for Cendio AB
7
8 This program is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
20*/
21
22/*
23 * Oracle 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, Oracle 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 };
62
63static int g_bmpcache_count[3];
64
65/* Setup the bitmap cache lru/mru linked list */
66void
67cache_rebuild_bmpcache_linked_list(uint8 id, sint16 * idx, int count)
68{
69 int n = count, c = 0;
70 sint16 n_idx;
71
72 /* find top, skip evicted bitmaps */
73 while (--n >= 0 && g_bmpcache[id][idx[n]].bitmap == NULL);
74 if (n < 0)
75 {
76 g_bmpcache_mru[id] = g_bmpcache_lru[id] = NOT_SET;
77 return;
78 }
79
80 g_bmpcache_mru[id] = idx[n];
81 g_bmpcache[id][idx[n]].next = NOT_SET;
82 n_idx = idx[n];
83 c++;
84
85 /* link list */
86 while (n >= 0)
87 {
88 /* skip evicted bitmaps */
89 while (--n >= 0 && g_bmpcache[id][idx[n]].bitmap == NULL);
90
91 if (n < 0)
92 break;
93
94 g_bmpcache[id][n_idx].previous = idx[n];
95 g_bmpcache[id][idx[n]].next = n_idx;
96 n_idx = idx[n];
97 c++;
98 }
99
100 g_bmpcache[id][n_idx].previous = NOT_SET;
101 g_bmpcache_lru[id] = n_idx;
102
103 if (c != g_bmpcache_count[id])
104 {
105 error("Oops. %d in bitmap cache linked list, %d in ui cache...\n", c,
106 g_bmpcache_count[id]);
107 exit(EX_SOFTWARE);
108 }
109}
110
111/* Move a bitmap to a new position in the linked list. */
112void
113cache_bump_bitmap(uint8 id, uint16 idx, int bump)
114{
115 int p_idx, n_idx, n;
116
117 if (!IS_PERSISTENT(id))
118 return;
119
120 if (g_bmpcache_mru[id] == idx)
121 return;
122
123 DEBUG_RDP5(("bump bitmap: id=%d, idx=%d, bump=%d\n", id, idx, bump));
124
125 n_idx = g_bmpcache[id][idx].next;
126 p_idx = g_bmpcache[id][idx].previous;
127
128 if (IS_SET(n_idx))
129 {
130 /* remove */
131 --g_bmpcache_count[id];
132 if (IS_SET(p_idx))
133 g_bmpcache[id][p_idx].next = n_idx;
134 else
135 g_bmpcache_lru[id] = n_idx;
136 if (IS_SET(n_idx))
137 g_bmpcache[id][n_idx].previous = p_idx;
138 else
139 g_bmpcache_mru[id] = p_idx;
140 }
141 else
142 {
143 p_idx = NOT_SET;
144 n_idx = g_bmpcache_lru[id];
145 }
146
147 if (bump >= 0)
148 {
149 for (n = 0; n < bump && IS_SET(n_idx); n++)
150 {
151 p_idx = n_idx;
152 n_idx = g_bmpcache[id][p_idx].next;
153 }
154 }
155 else
156 {
157 p_idx = g_bmpcache_mru[id];
158 n_idx = NOT_SET;
159 }
160
161 /* insert */
162 ++g_bmpcache_count[id];
163 g_bmpcache[id][idx].previous = p_idx;
164 g_bmpcache[id][idx].next = n_idx;
165
166 if (p_idx >= 0)
167 g_bmpcache[id][p_idx].next = idx;
168 else
169 g_bmpcache_lru[id] = idx;
170
171 if (n_idx >= 0)
172 g_bmpcache[id][n_idx].previous = idx;
173 else
174 g_bmpcache_mru[id] = idx;
175}
176
177/* Evict the least-recently used bitmap from the cache */
178void
179cache_evict_bitmap(uint8 id)
180{
181 uint16 idx;
182 int n_idx;
183
184 if (!IS_PERSISTENT(id))
185 return;
186
187 idx = g_bmpcache_lru[id];
188 n_idx = g_bmpcache[id][idx].next;
189 DEBUG_RDP5(("evict bitmap: id=%d idx=%d n_idx=%d bmp=%p\n", id, idx, n_idx,
190 g_bmpcache[id][idx].bitmap));
191
192 ui_destroy_bitmap(g_bmpcache[id][idx].bitmap);
193 --g_bmpcache_count[id];
194 g_bmpcache[id][idx].bitmap = 0;
195
196 g_bmpcache_lru[id] = n_idx;
197 g_bmpcache[id][n_idx].previous = NOT_SET;
198
199 pstcache_touch_bitmap(id, idx, 0);
200}
201
202/* Retrieve a bitmap from the cache */
203RD_HBITMAP
204cache_get_bitmap(uint8 id, uint16 idx)
205{
206 if ((id < NUM_ELEMENTS(g_bmpcache)) && (idx < NUM_ELEMENTS(g_bmpcache[0])))
207 {
208 if (g_bmpcache[id][idx].bitmap || pstcache_load_bitmap(id, idx))
209 {
210 if (IS_PERSISTENT(id))
211 cache_bump_bitmap(id, idx, BUMP_COUNT);
212
213 return g_bmpcache[id][idx].bitmap;
214 }
215 }
216 else if ((id < NUM_ELEMENTS(g_volatile_bc)) && (idx == 0x7fff))
217 {
218 return g_volatile_bc[id];
219 }
220
221 error("get bitmap %d:%d\n", id, idx);
222 return NULL;
223}
224
225/* Store a bitmap in the cache */
226void
227cache_put_bitmap(uint8 id, uint16 idx, RD_HBITMAP bitmap)
228{
229 RD_HBITMAP old;
230
231 if ((id < NUM_ELEMENTS(g_bmpcache)) && (idx < NUM_ELEMENTS(g_bmpcache[0])))
232 {
233 old = g_bmpcache[id][idx].bitmap;
234 if (old != NULL)
235 ui_destroy_bitmap(old);
236 g_bmpcache[id][idx].bitmap = bitmap;
237
238 if (IS_PERSISTENT(id))
239 {
240 if (old == NULL)
241 g_bmpcache[id][idx].previous = g_bmpcache[id][idx].next = NOT_SET;
242
243 cache_bump_bitmap(id, idx, TO_TOP);
244 if (g_bmpcache_count[id] > BMPCACHE2_C2_CELLS)
245 cache_evict_bitmap(id);
246 }
247 }
248 else if ((id < NUM_ELEMENTS(g_volatile_bc)) && (idx == 0x7fff))
249 {
250 old = g_volatile_bc[id];
251 if (old != NULL)
252 ui_destroy_bitmap(old);
253 g_volatile_bc[id] = bitmap;
254 }
255 else
256 {
257 error("put bitmap %d:%d\n", id, idx);
258 }
259}
260
261/* Updates the persistent bitmap cache MRU information on exit */
262void
263cache_save_state(void)
264{
265 uint32 id = 0, t = 0;
266 int idx;
267
268 for (id = 0; id < NUM_ELEMENTS(g_bmpcache); id++)
269 if (IS_PERSISTENT(id))
270 {
271 DEBUG_RDP5(("Saving cache state for bitmap cache %d...", id));
272 idx = g_bmpcache_lru[id];
273 while (idx >= 0)
274 {
275 pstcache_touch_bitmap(id, idx, ++t);
276 idx = g_bmpcache[id][idx].next;
277 }
278 DEBUG_RDP5((" %d stamps written.\n", t));
279 }
280}
281
282
283/* FONT CACHE */
284static FONTGLYPH g_fontcache[12][256];
285
286/* Retrieve a glyph from the font cache */
287FONTGLYPH *
288cache_get_font(uint8 font, uint16 character)
289{
290 FONTGLYPH *glyph;
291
292 if ((font < NUM_ELEMENTS(g_fontcache)) && (character < NUM_ELEMENTS(g_fontcache[0])))
293 {
294 glyph = &g_fontcache[font][character];
295 if (glyph->pixmap != NULL)
296 return glyph;
297 }
298
299 error("get font %d:%d\n", font, character);
300 return NULL;
301}
302
303/* Store a glyph in the font cache */
304void
305cache_put_font(uint8 font, uint16 character, uint16 offset,
306 uint16 baseline, uint16 width, uint16 height, RD_HGLYPH pixmap)
307{
308 FONTGLYPH *glyph;
309
310 if ((font < NUM_ELEMENTS(g_fontcache)) && (character < NUM_ELEMENTS(g_fontcache[0])))
311 {
312 glyph = &g_fontcache[font][character];
313 if (glyph->pixmap != NULL)
314 ui_destroy_glyph(glyph->pixmap);
315
316 glyph->offset = offset;
317 glyph->baseline = baseline;
318 glyph->width = width;
319 glyph->height = height;
320 glyph->pixmap = pixmap;
321 }
322 else
323 {
324 error("put font %d:%d\n", font, character);
325 }
326}
327
328
329/* TEXT CACHE */
330static DATABLOB g_textcache[256];
331
332/* Retrieve a text item from the cache */
333DATABLOB *
334cache_get_text(uint8 cache_id)
335{
336 DATABLOB *text;
337
338 text = &g_textcache[cache_id];
339 return text;
340}
341
342/* Store a text item in the cache */
343void
344cache_put_text(uint8 cache_id, void *data, int length)
345{
346 DATABLOB *text;
347
348 text = &g_textcache[cache_id];
349 if (text->data != NULL)
350 xfree(text->data);
351 text->data = xmalloc(length);
352 text->size = length;
353 memcpy(text->data, data, length);
354}
355
356
357/* DESKTOP CACHE */
358static uint8 g_deskcache[0x38400 * 4];
359
360/* Retrieve desktop data from the cache */
361uint8 *
362cache_get_desktop(uint32 offset, int cx, int cy, int bytes_per_pixel)
363{
364 int length = cx * cy * bytes_per_pixel;
365
366 if (offset > sizeof(g_deskcache))
367 offset = 0;
368
369 if ((offset + length) <= sizeof(g_deskcache))
370 {
371 return &g_deskcache[offset];
372 }
373
374 error("get desktop %d:%d\n", offset, length);
375 return NULL;
376}
377
378/* Store desktop data in the cache */
379void
380cache_put_desktop(uint32 offset, int cx, int cy, int scanline, int bytes_per_pixel, uint8 * data)
381{
382 int length = cx * cy * bytes_per_pixel;
383
384 if (offset > sizeof(g_deskcache))
385 offset = 0;
386
387 if ((offset + length) <= sizeof(g_deskcache))
388 {
389 cx *= bytes_per_pixel;
390 while (cy--)
391 {
392 memcpy(&g_deskcache[offset], data, cx);
393 data += scanline;
394 offset += cx;
395 }
396 }
397 else
398 {
399 error("put desktop %d:%d\n", offset, length);
400 }
401}
402
403
404/* CURSOR CACHE */
405static RD_HCURSOR g_cursorcache[0x20];
406
407/* Retrieve cursor from cache */
408RD_HCURSOR
409cache_get_cursor(uint16 cache_idx)
410{
411 RD_HCURSOR cursor;
412
413 if (cache_idx < NUM_ELEMENTS(g_cursorcache))
414 {
415 cursor = g_cursorcache[cache_idx];
416 if (cursor != NULL)
417 return cursor;
418 }
419
420 error("get cursor %d\n", cache_idx);
421 return NULL;
422}
423
424/* Store cursor in cache */
425void
426cache_put_cursor(uint16 cache_idx, RD_HCURSOR cursor)
427{
428 RD_HCURSOR old;
429
430 if (cache_idx < NUM_ELEMENTS(g_cursorcache))
431 {
432 old = g_cursorcache[cache_idx];
433 if (old != NULL)
434 ui_destroy_cursor(old);
435
436 g_cursorcache[cache_idx] = cursor;
437 }
438 else
439 {
440 error("put cursor %d\n", cache_idx);
441 }
442}
443
444/* BRUSH CACHE */
445/* index 0 is 2 colour brush, index 1 is muti colour brush */
446static BRUSHDATA g_brushcache[2][64];
447
448/* Retrieve brush from cache */
449BRUSHDATA *
450cache_get_brush_data(uint8 colour_code, uint8 idx)
451{
452 colour_code = colour_code == 1 ? 0 : 1;
453 if (idx < NUM_ELEMENTS(g_brushcache[0]))
454 {
455 return &g_brushcache[colour_code][idx];
456 }
457 error("get brush %d %d\n", colour_code, idx);
458 return NULL;
459}
460
461/* Store brush in cache */
462/* this function takes over the data pointer in struct, eg, caller gives it up */
463void
464cache_put_brush_data(uint8 colour_code, uint8 idx, BRUSHDATA * brush_data)
465{
466 BRUSHDATA *bd;
467
468 colour_code = colour_code == 1 ? 0 : 1;
469 if (idx < NUM_ELEMENTS(g_brushcache[0]))
470 {
471 bd = &g_brushcache[colour_code][idx];
472 if (bd->data != 0)
473 {
474 xfree(bd->data);
475 }
476 memcpy(bd, brush_data, sizeof(BRUSHDATA));
477 }
478 else
479 {
480 error("put brush %d %d\n", colour_code, idx);
481 }
482}
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