ReactOS  0.4.12-dev-43-g63b00d8
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 */
25 extern 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 
48 static struct bmpcache_entry g_bmpcache[3][0xa00];
50 
51 static int g_bmpcache_lru[3] = { NOT_SET, NOT_SET, NOT_SET };
52 static int g_bmpcache_mru[3] = { NOT_SET, NOT_SET, NOT_SET };
53 
54 static int g_bmpcache_count[3];
55 
56 /* Setup the bitmap cache lru/mru linked list */
57 void
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 
71  g_bmpcache_mru[id] = idx[n];
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,
97  g_bmpcache_count[id]);
99  }
100 }
101 
102 /* Move a bitmap to a new position in the linked list. */
103 void
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 */
122  --g_bmpcache_count[id];
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 */
153  ++g_bmpcache_count[id];
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
160  g_bmpcache_lru[id] = idx;
161 
162  if (n_idx >= 0)
163  g_bmpcache[id][n_idx].previous = idx;
164  else
165  g_bmpcache_mru[id] = idx;
166 }
167 
168 /* Evict the least-recently used bitmap from the cache */
169 void
171 {
172  uint16 idx;
173  int n_idx;
174 
175  if (!IS_PERSISTENT(id))
176  return;
177 
178  idx = g_bmpcache_lru[id];
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 
183  ui_destroy_bitmap(g_bmpcache[id][idx].bitmap);
184  --g_bmpcache_count[id];
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 
190  pstcache_touch_bitmap(id, idx, 0);
191 }
192 
193 /* Retrieve a bitmap from the cache */
196 {
197  if ((id < NUM_ELEMENTS(g_bmpcache)) && (idx < NUM_ELEMENTS(g_bmpcache[0])))
198  {
199  if (g_bmpcache[id][idx].bitmap || pstcache_load_bitmap(id, idx))
200  {
201  if (IS_PERSISTENT(id))
202  cache_bump_bitmap(id, idx, BUMP_COUNT);
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 */
217 void
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)
226  ui_destroy_bitmap(old);
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 
234  cache_bump_bitmap(id, idx, TO_TOP);
236  cache_evict_bitmap(id);
237  }
238  }
239  else if ((id < NUM_ELEMENTS(g_volatile_bc)) && (idx == 0x7fff))
240  {
241  old = g_volatile_bc[id];
242  if (old != NULL)
243  ui_destroy_bitmap(old);
244  g_volatile_bc[id] = bitmap;
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 */
253 void
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));
263  idx = g_bmpcache_lru[id];
264  while (idx >= 0)
265  {
266  pstcache_touch_bitmap(id, idx, ++t);
267  idx = g_bmpcache[id][idx].next;
268  }
269  DEBUG_RDP5((" %d stamps written.\n", t));
270  }
271 }
272 
273 
274 /* FONT CACHE */
275 static FONTGLYPH g_fontcache[12][256];
276 
277 /* Retrieve a glyph from the font cache */
278 FONTGLYPH *
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 */
295 void
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 */
321 static DATABLOB g_textcache[256];
322 
323 /* Retrieve a text item from the cache */
324 DATABLOB *
326 {
327  DATABLOB *text;
328 
329  text = &g_textcache[cache_id];
330  return text;
331 }
332 
333 /* Store a text item in the cache */
334 void
335 cache_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 */
349 static uint8 g_deskcache[0x38400 * 4];
350 
351 /* Retrieve desktop data from the cache */
352 uint8 *
353 cache_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 */
370 void
371 cache_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  {
383  memcpy(&g_deskcache[offset], data, cx);
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 */
416 void
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)
425  ui_destroy_cursor(old);
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 */
437 static BRUSHDATA g_brushcache[2][64];
438 
439 /* Retrieve brush from cache */
440 BRUSHDATA *
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 */
454 void
455 cache_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 }
RD_BOOL pstcache_load_bitmap(uint8 cache_id, uint16 cache_idx)
Definition: pstcache.c:53
#define TO_TOP
Definition: cache.c:29
GLint GLint GLsizei width
Definition: gl.h:1546
#define BMPCACHE2_C2_CELLS
Definition: constants.h:284
sint16 next
Definition: cache.c:45
#define IS_SET(idx)
Definition: cache.c:31
void cache_bump_bitmap(uint8 id, uint16 idx, int bump)
Definition: cache.c:104
#define error(str)
Definition: mkdosfs.c:1605
int size
Definition: types.h:124
static int g_bmpcache_lru[3]
Definition: cache.c:51
void cache_put_brush_data(uint8 colour_code, uint8 idx, BRUSHDATA *brush_data)
Definition: cache.c:455
Definition: mk_font.cpp:20
const WCHAR * text
Definition: package.c:1827
GLuint GLuint GLsizei count
Definition: gl.h:1545
unsigned int uint32
Definition: types.h:32
uint16 height
Definition: types.h:115
static int g_bmpcache_count[3]
Definition: cache.c:54
GLintptr offset
Definition: glext.h:5920
static int g_bmpcache_mru[3]
Definition: cache.c:52
GLdouble GLdouble t
Definition: gl.h:2047
sint16 baseline
Definition: types.h:113
Definition: cache.c:41
GLuint n
Definition: s_context.h:57
sint16 previous
Definition: cache.c:44
FONTGLYPH * cache_get_font(uint8 font, uint16 character)
Definition: cache.c:279
void * xmalloc(int size)
Definition: uimain.c:747
RD_HBITMAP cache_get_bitmap(uint8 id, uint16 idx)
Definition: cache.c:195
unsigned int idx
Definition: utils.c:41
_Out_opt_ int _Out_opt_ int * cy
Definition: commctrl.h:570
uint8 * cache_get_desktop(uint32 offset, int cx, int cy, int bytes_per_pixel)
Definition: cache.c:353
void cache_put_text(uint8 cache_id, void *data, int length)
Definition: cache.c:335
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_bitmap(uint8 id, uint16 idx, RD_HBITMAP bitmap)
Definition: cache.c:218
smooth NULL
Definition: ftsmooth.c:416
static RD_HBITMAP g_volatile_bc[3]
Definition: cache.c:49
void pstcache_touch_bitmap(uint8 cache_id, uint16 cache_idx, uint32 stamp)
Definition: pstcache.c:39
void cache_save_state(void)
Definition: cache.c:254
RD_HCURSOR cache_get_cursor(uint16 cache_idx)
Definition: cache.c:400
Definition: uimain.c:88
void xfree(void *mem)
Definition: uimain.c:758
static DATABLOB g_textcache[256]
Definition: cache.c:321
static uint8 g_deskcache[0x38400 *4]
Definition: cache.c:349
#define IS_PERSISTENT(id)
Definition: cache.c:28
GLenum GLuint GLenum GLsizei length
Definition: glext.h:5579
#define NUM_ELEMENTS(array)
Definition: cache.c:27
RD_HBITMAP bitmap
Definition: cache.c:43
const GLubyte * c
Definition: glext.h:8905
void cache_put_cursor(uint16 cache_idx, RD_HCURSOR cursor)
Definition: cache.c:417
void cache_rebuild_bmpcache_linked_list(uint8 id, sint16 *idx, int count)
Definition: cache.c:58
unsigned char uint8
Definition: types.h:28
uint8 * data
Definition: types.h:96
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: gl.h:1950
#define EX_SOFTWARE
Definition: rdesktop.h:70
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
int g_pstcache_fd[]
Definition: pstcache.c:31
void * data
Definition: types.h:123
signed short sint16
Definition: types.h:31
void cache_evict_bitmap(uint8 id)
Definition: cache.c:170
static FONTGLYPH g_fontcache[12][256]
Definition: cache.c:275
void ui_destroy_cursor(HCURSOR)
Definition: qtewin.cpp:1502
GLint GLint GLsizei GLsizei height
Definition: gl.h:1546
uint16 width
Definition: types.h:114
sint16 offset
Definition: types.h:112
static BRUSHDATA g_brushcache[2][64]
Definition: cache.c:437
#define NOT_SET
Definition: cache.c:30
#define DEBUG_RDP5(args)
Definition: rdesktop.h:141
void ui_destroy_bitmap(RD_HBITMAP bmp)
const char cursor[]
Definition: icontest.c:13
void cache_put_font(uint8 font, uint16 character, uint16 offset, uint16 baseline, uint16 width, uint16 height, RD_HGLYPH pixmap)
Definition: cache.c:296
unsigned short uint16
Definition: types.h:30
static struct bmpcache_entry g_bmpcache[3][0xa00]
Definition: cache.c:48
_Out_opt_ int * cx
Definition: commctrl.h:570
GLenum GLuint id
Definition: glext.h:5579
DATABLOB * cache_get_text(uint8 cache_id)
Definition: cache.c:325
#define BUMP_COUNT
Definition: cache.c:39
BRUSHDATA * cache_get_brush_data(uint8 colour_code, uint8 idx)
Definition: cache.c:441
void exit(int exitcode)
Definition: _exit.c:33
RD_HBITMAP pixmap
Definition: types.h:116
void ui_destroy_glyph(RD_HGLYPH glyph)
Definition: qtewin.cpp:1424
static RD_HCURSOR g_cursorcache[0x20]
Definition: cache.c:396