ReactOS 0.4.16-dev-92-g0c2cdca
cache.c
Go to the documentation of this file.
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#include "precomp.h"
23
24/* BITMAP CACHE */
25extern int g_pstcache_fd[];
26
27#define NUM_ELEMENTS(array) (sizeof(array) / sizeof(array[0]))
28//#define IS_PERSISTENT(id) (g_pstcache_fd[id] > 0)
29#define TO_TOP -1
30#define NOT_SET -1
31#define IS_SET(idx) (idx >= 0)
32
33/*
34 * TODO: Test for optimal value of BUMP_COUNT. TO_TOP gives lowest cpu utilisation but using
35 * a positive value will hopefully result in less frequently used bitmaps having a greater chance
36 * of being evicted from the cache, and thereby reducing the need to load bitmaps from disk.
37 * (Jeroen)
38 */
39#define BUMP_COUNT 40
40
42{
46};
47
48static struct bmpcache_entry g_bmpcache[3][0xa00];
50
51static int g_bmpcache_lru[3] = { NOT_SET, NOT_SET, NOT_SET };
52static int g_bmpcache_mru[3] = { NOT_SET, NOT_SET, NOT_SET };
53
54static int g_bmpcache_count[3];
55
56/* Setup the bitmap cache lru/mru linked list */
57void
59{
60 int n = count, c = 0;
61 sint16 n_idx;
62
63 /* find top, skip evicted bitmaps */
64 while (--n >= 0 && g_bmpcache[id][idx[n]].bitmap == NULL);
65 if (n < 0)
66 {
68 return;
69 }
70
72 g_bmpcache[id][idx[n]].next = NOT_SET;
73 n_idx = idx[n];
74 c++;
75
76 /* link list */
77 while (n >= 0)
78 {
79 /* skip evicted bitmaps */
80 while (--n >= 0 && g_bmpcache[id][idx[n]].bitmap == NULL);
81
82 if (n < 0)
83 break;
84
85 g_bmpcache[id][n_idx].previous = idx[n];
86 g_bmpcache[id][idx[n]].next = n_idx;
87 n_idx = idx[n];
88 c++;
89 }
90
91 g_bmpcache[id][n_idx].previous = NOT_SET;
92 g_bmpcache_lru[id] = n_idx;
93
94 if (c != g_bmpcache_count[id])
95 {
96 error("Oops. %d in bitmap cache linked list, %d in ui cache...\n", c,
99 }
100}
101
102/* Move a bitmap to a new position in the linked list. */
103void
105{
106 int p_idx, n_idx, n;
107
108 if (!IS_PERSISTENT(id))
109 return;
110
111 if (g_bmpcache_mru[id] == idx)
112 return;
113
114 DEBUG_RDP5(("bump bitmap: id=%d, idx=%d, bump=%d\n", id, idx, bump));
115
116 n_idx = g_bmpcache[id][idx].next;
117 p_idx = g_bmpcache[id][idx].previous;
118
119 if (IS_SET(n_idx))
120 {
121 /* remove */
123 if (IS_SET(p_idx))
124 g_bmpcache[id][p_idx].next = n_idx;
125 else
126 g_bmpcache_lru[id] = n_idx;
127 if (IS_SET(n_idx))
128 g_bmpcache[id][n_idx].previous = p_idx;
129 else
130 g_bmpcache_mru[id] = p_idx;
131 }
132 else
133 {
134 p_idx = NOT_SET;
135 n_idx = g_bmpcache_lru[id];
136 }
137
138 if (bump >= 0)
139 {
140 for (n = 0; n < bump && IS_SET(n_idx); n++)
141 {
142 p_idx = n_idx;
143 n_idx = g_bmpcache[id][p_idx].next;
144 }
145 }
146 else
147 {
148 p_idx = g_bmpcache_mru[id];
149 n_idx = NOT_SET;
150 }
151
152 /* insert */
154 g_bmpcache[id][idx].previous = p_idx;
155 g_bmpcache[id][idx].next = n_idx;
156
157 if (p_idx >= 0)
158 g_bmpcache[id][p_idx].next = idx;
159 else
161
162 if (n_idx >= 0)
163 g_bmpcache[id][n_idx].previous = idx;
164 else
166}
167
168/* Evict the least-recently used bitmap from the cache */
169void
171{
172 uint16 idx;
173 int n_idx;
174
175 if (!IS_PERSISTENT(id))
176 return;
177
179 n_idx = g_bmpcache[id][idx].next;
180 DEBUG_RDP5(("evict bitmap: id=%d idx=%d n_idx=%d bmp=%p\n", id, idx, n_idx,
181 g_bmpcache[id][idx].bitmap));
182
185 g_bmpcache[id][idx].bitmap = 0;
186
187 g_bmpcache_lru[id] = n_idx;
188 g_bmpcache[id][n_idx].previous = NOT_SET;
189
191}
192
193/* Retrieve a bitmap from the cache */
196{
197 if ((id < NUM_ELEMENTS(g_bmpcache)) && (idx < NUM_ELEMENTS(g_bmpcache[0])))
198 {
200 {
201 if (IS_PERSISTENT(id))
203
204 return g_bmpcache[id][idx].bitmap;
205 }
206 }
207 else if ((id < NUM_ELEMENTS(g_volatile_bc)) && (idx == 0x7fff))
208 {
209 return g_volatile_bc[id];
210 }
211
212 error("get bitmap %d:%d\n", id, idx);
213 return NULL;
214}
215
216/* Store a bitmap in the cache */
217void
219{
220 RD_HBITMAP old;
221
222 if ((id < NUM_ELEMENTS(g_bmpcache)) && (idx < NUM_ELEMENTS(g_bmpcache[0])))
223 {
224 old = g_bmpcache[id][idx].bitmap;
225 if (old != NULL)
227 g_bmpcache[id][idx].bitmap = bitmap;
228
229 if (IS_PERSISTENT(id))
230 {
231 if (old == NULL)
232 g_bmpcache[id][idx].previous = g_bmpcache[id][idx].next = NOT_SET;
233
237 }
238 }
239 else if ((id < NUM_ELEMENTS(g_volatile_bc)) && (idx == 0x7fff))
240 {
241 old = g_volatile_bc[id];
242 if (old != NULL)
245 }
246 else
247 {
248 error("put bitmap %d:%d\n", id, idx);
249 }
250}
251
252/* Updates the persistent bitmap cache MRU information on exit */
253void
255{
256 uint32 id = 0, t = 0;
257 int idx;
258
259 for (id = 0; id < NUM_ELEMENTS(g_bmpcache); id++)
260 if (IS_PERSISTENT(id))
261 {
262 DEBUG_RDP5(("Saving cache state for bitmap cache %d...", id));
264 while (idx >= 0)
265 {
267 idx = g_bmpcache[id][idx].next;
268 }
269 DEBUG_RDP5((" %d stamps written.\n", t));
270 }
271}
272
273
274/* FONT CACHE */
275static FONTGLYPH g_fontcache[12][256];
276
277/* Retrieve a glyph from the font cache */
278FONTGLYPH *
280{
281 FONTGLYPH *glyph;
282
283 if ((font < NUM_ELEMENTS(g_fontcache)) && (character < NUM_ELEMENTS(g_fontcache[0])))
284 {
285 glyph = &g_fontcache[font][character];
286 if (glyph->pixmap != NULL)
287 return glyph;
288 }
289
290 error("get font %d:%d\n", font, character);
291 return NULL;
292}
293
294/* Store a glyph in the font cache */
295void
297 uint16 baseline, uint16 width, uint16 height, RD_HGLYPH pixmap)
298{
299 FONTGLYPH *glyph;
300
301 if ((font < NUM_ELEMENTS(g_fontcache)) && (character < NUM_ELEMENTS(g_fontcache[0])))
302 {
303 glyph = &g_fontcache[font][character];
304 if (glyph->pixmap != NULL)
305 ui_destroy_glyph(glyph->pixmap);
306
307 glyph->offset = offset;
308 glyph->baseline = baseline;
309 glyph->width = width;
310 glyph->height = height;
311 glyph->pixmap = pixmap;
312 }
313 else
314 {
315 error("put font %d:%d\n", font, character);
316 }
317}
318
319
320/* TEXT CACHE */
322
323/* Retrieve a text item from the cache */
324DATABLOB *
326{
327 DATABLOB *text;
328
329 text = &g_textcache[cache_id];
330 return text;
331}
332
333/* Store a text item in the cache */
334void
335cache_put_text(uint8 cache_id, void *data, int length)
336{
337 DATABLOB *text;
338
339 text = &g_textcache[cache_id];
340 if (text->data != NULL)
341 xfree(text->data);
342 text->data = xmalloc(length);
343 text->size = length;
344 memcpy(text->data, data, length);
345}
346
347
348/* DESKTOP CACHE */
349static uint8 g_deskcache[0x38400 * 4];
350
351/* Retrieve desktop data from the cache */
352uint8 *
353cache_get_desktop(uint32 offset, int cx, int cy, int bytes_per_pixel)
354{
355 int length = cx * cy * bytes_per_pixel;
356
357 if (offset > sizeof(g_deskcache))
358 offset = 0;
359
360 if ((offset + length) <= sizeof(g_deskcache))
361 {
362 return &g_deskcache[offset];
363 }
364
365 error("get desktop %d:%d\n", offset, length);
366 return NULL;
367}
368
369/* Store desktop data in the cache */
370void
371cache_put_desktop(uint32 offset, int cx, int cy, int scanline, int bytes_per_pixel, uint8 * data)
372{
373 int length = cx * cy * bytes_per_pixel;
374
375 if (offset > sizeof(g_deskcache))
376 offset = 0;
377
378 if ((offset + length) <= sizeof(g_deskcache))
379 {
380 cx *= bytes_per_pixel;
381 while (cy--)
382 {
384 data += scanline;
385 offset += cx;
386 }
387 }
388 else
389 {
390 error("put desktop %d:%d\n", offset, length);
391 }
392}
393
394
395/* CURSOR CACHE */
397
398/* Retrieve cursor from cache */
401{
403
404 if (cache_idx < NUM_ELEMENTS(g_cursorcache))
405 {
406 cursor = g_cursorcache[cache_idx];
407 if (cursor != NULL)
408 return cursor;
409 }
410
411 error("get cursor %d\n", cache_idx);
412 return NULL;
413}
414
415/* Store cursor in cache */
416void
418{
419 RD_HCURSOR old;
420
421 if (cache_idx < NUM_ELEMENTS(g_cursorcache))
422 {
423 old = g_cursorcache[cache_idx];
424 if (old != NULL)
426
427 g_cursorcache[cache_idx] = cursor;
428 }
429 else
430 {
431 error("put cursor %d\n", cache_idx);
432 }
433}
434
435/* BRUSH CACHE */
436/* index 0 is 2 colour brush, index 1 is muti colour brush */
438
439/* Retrieve brush from cache */
440BRUSHDATA *
442{
443 colour_code = colour_code == 1 ? 0 : 1;
444 if (idx < NUM_ELEMENTS(g_brushcache[0]))
445 {
446 return &g_brushcache[colour_code][idx];
447 }
448 error("get brush %d %d\n", colour_code, idx);
449 return NULL;
450}
451
452/* Store brush in cache */
453/* this function takes over the data pointer in struct, eg, caller gives it up */
454void
455cache_put_brush_data(uint8 colour_code, uint8 idx, BRUSHDATA * brush_data)
456{
457 BRUSHDATA *bd;
458
459 colour_code = colour_code == 1 ? 0 : 1;
460 if (idx < NUM_ELEMENTS(g_brushcache[0]))
461 {
462 bd = &g_brushcache[colour_code][idx];
463 if (bd->data != 0)
464 {
465 xfree(bd->data);
466 }
467 memcpy(bd, brush_data, sizeof(BRUSHDATA));
468 }
469 else
470 {
471 error("put brush %d %d\n", colour_code, idx);
472 }
473}
#define IS_SET(idx)
Definition: cache.c:31
static struct bmpcache_entry g_bmpcache[3][0xa00]
Definition: cache.c:48
void cache_put_font(uint8 font, uint16 character, uint16 offset, uint16 baseline, uint16 width, uint16 height, RD_HGLYPH pixmap)
Definition: cache.c:296
static uint8 g_deskcache[0x38400 *4]
Definition: cache.c:349
BRUSHDATA * cache_get_brush_data(uint8 colour_code, uint8 idx)
Definition: cache.c:441
#define BUMP_COUNT
Definition: cache.c:39
RD_HCURSOR cache_get_cursor(uint16 cache_idx)
Definition: cache.c:400
void cache_put_text(uint8 cache_id, void *data, int length)
Definition: cache.c:335
static BRUSHDATA g_brushcache[2][64]
Definition: cache.c:437
static RD_HCURSOR g_cursorcache[0x20]
Definition: cache.c:396
#define NOT_SET
Definition: cache.c:30
RD_HBITMAP cache_get_bitmap(uint8 id, uint16 idx)
Definition: cache.c:195
static FONTGLYPH g_fontcache[12][256]
Definition: cache.c:275
int g_pstcache_fd[]
Definition: pstcache.c:31
FONTGLYPH * cache_get_font(uint8 font, uint16 character)
Definition: cache.c:279
static int g_bmpcache_count[3]
Definition: cache.c:54
void cache_put_desktop(uint32 offset, int cx, int cy, int scanline, int bytes_per_pixel, uint8 *data)
Definition: cache.c:371
void cache_put_cursor(uint16 cache_idx, RD_HCURSOR cursor)
Definition: cache.c:417
static int g_bmpcache_mru[3]
Definition: cache.c:52
static int g_bmpcache_lru[3]
Definition: cache.c:51
static RD_HBITMAP g_volatile_bc[3]
Definition: cache.c:49
#define TO_TOP
Definition: cache.c:29
void cache_bump_bitmap(uint8 id, uint16 idx, int bump)
Definition: cache.c:104
#define NUM_ELEMENTS(array)
Definition: cache.c:27
static DATABLOB g_textcache[256]
Definition: cache.c:321
void cache_put_bitmap(uint8 id, uint16 idx, RD_HBITMAP bitmap)
Definition: cache.c:218
DATABLOB * cache_get_text(uint8 cache_id)
Definition: cache.c:325
void cache_put_brush_data(uint8 colour_code, uint8 idx, BRUSHDATA *brush_data)
Definition: cache.c:455
void cache_rebuild_bmpcache_linked_list(uint8 id, sint16 *idx, int count)
Definition: cache.c:58
void cache_evict_bitmap(uint8 id)
Definition: cache.c:170
void cache_save_state(void)
Definition: cache.c:254
uint8 * cache_get_desktop(uint32 offset, int cx, int cy, int bytes_per_pixel)
Definition: cache.c:353
#define BMPCACHE2_C2_CELLS
Definition: constants.h:284
#define IS_PERSISTENT(id)
Definition: precomp.h:26
void xfree(void *mem)
Definition: uimain.c:758
void ui_destroy_bitmap(RD_HBITMAP bmp)
void pstcache_touch_bitmap(uint8 cache_id, uint16 cache_idx, uint32 stamp)
Definition: pstcache.c:39
RD_BOOL pstcache_load_bitmap(uint8 cache_id, uint16 cache_idx)
Definition: pstcache.c:53
void ui_destroy_cursor(RD_HCURSOR cursor)
void ui_destroy_glyph(RD_HGLYPH glyph)
Definition: qtewin.cpp:1424
void * xmalloc(int size)
Definition: uimain.c:747
#define DEBUG_RDP5(args)
Definition: rdesktop.h:141
#define EX_SOFTWARE
Definition: rdesktop.h:70
unsigned short uint16
Definition: types.h:30
unsigned int uint32
Definition: types.h:32
signed short sint16
Definition: types.h:31
unsigned char uint8
Definition: types.h:28
#define NULL
Definition: types.h:112
unsigned int idx
Definition: utils.c:41
const WCHAR * text
Definition: package.c:1794
GLuint GLuint GLsizei count
Definition: gl.h:1545
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: gl.h:1950
GLint GLint GLsizei GLsizei height
Definition: gl.h:1546
GLdouble GLdouble t
Definition: gl.h:2047
GLint GLint GLsizei width
Definition: gl.h:1546
GLdouble n
Definition: glext.h:7729
const GLubyte * c
Definition: glext.h:8905
GLuint GLsizei GLsizei * length
Definition: glext.h:6040
GLuint id
Definition: glext.h:5910
GLintptr offset
Definition: glext.h:5920
const char cursor[]
Definition: icontest.c:13
#define error(str)
Definition: mkdosfs.c:1605
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
Definition: mk_font.cpp:20
_Out_opt_ int _Out_opt_ int * cy
Definition: commctrl.h:586
_Out_opt_ int * cx
Definition: commctrl.h:585
#define exit(n)
Definition: config.h:202
uint8 * data
Definition: types.h:96
uint16 width
Definition: types.h:114
sint16 baseline
Definition: types.h:113
uint16 height
Definition: types.h:115
sint16 offset
Definition: types.h:112
RD_HBITMAP pixmap
Definition: types.h:116
Definition: uimain.c:89
Definition: cache.c:42
sint16 next
Definition: cache.c:45
RD_HBITMAP bitmap
Definition: cache.c:43
sint16 previous
Definition: cache.c:44