ReactOS  0.4.13-dev-257-gfabbd7c
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 1999-2005
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 along
18  with this program; if not, write to the Free Software Foundation, Inc.,
19  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 */
21 
22 #include "rdesktop.h"
23 
24 #undef IS_SET // !!!FIXME!!!
25 
26 /* BITMAP CACHE */
27 #define NUM_ELEMENTS(array) (sizeof(array) / sizeof(array[0]))
28 #define IS_PERSISTENT(id) (This->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 therby reducing the need to load bitmaps from disk.
37  * (Jeroen)
38  */
39 #define BUMP_COUNT 40
40 
41 /* Setup the bitmap cache lru/mru linked list */
42 void
44 {
45  int n = count, c = 0;
46  sint16 n_idx;
47 
48  /* find top, skip evicted bitmaps */
49  while (--n >= 0 && This->cache.bmpcache[id][idx[n]].bitmap == NULL);
50  if (n < 0)
51  {
52  This->cache.bmpcache_mru[id] = This->cache.bmpcache_lru[id] = NOT_SET;
53  return;
54  }
55 
56  This->cache.bmpcache_mru[id] = idx[n];
57  This->cache.bmpcache[id][idx[n]].next = NOT_SET;
58  n_idx = idx[n];
59  c++;
60 
61  /* link list */
62  while (n >= 0)
63  {
64  /* skip evicted bitmaps */
65  while (--n >= 0 && This->cache.bmpcache[id][idx[n]].bitmap == NULL);
66 
67  if (n < 0)
68  break;
69 
70  This->cache.bmpcache[id][n_idx].previous = idx[n];
71  This->cache.bmpcache[id][idx[n]].next = n_idx;
72  n_idx = idx[n];
73  c++;
74  }
75 
76  This->cache.bmpcache[id][n_idx].previous = NOT_SET;
77  This->cache.bmpcache_lru[id] = n_idx;
78 
79  if (c != This->cache.bmpcache_count[id])
80  {
81  error("Oops. %d in bitmap cache linked list, %d in ui cache...\n", c,
82  This->cache.bmpcache_count[id]);
83  exit(1);
84  }
85 }
86 
87 /* Move a bitmap to a new position in the linked list. */
88 void
90 {
91  int p_idx, n_idx, n;
92 
93  if (!IS_PERSISTENT(id))
94  return;
95 
96  if (This->cache.bmpcache_mru[id] == idx)
97  return;
98 
99  DEBUG_RDP5(("bump bitmap: id=%d, idx=%d, bump=%d\n", id, idx, bump));
100 
101  n_idx = This->cache.bmpcache[id][idx].next;
102  p_idx = This->cache.bmpcache[id][idx].previous;
103 
104  if (IS_SET(n_idx))
105  {
106  /* remove */
107  --This->cache.bmpcache_count[id];
108  if (IS_SET(p_idx))
109  This->cache.bmpcache[id][p_idx].next = n_idx;
110  else
111  This->cache.bmpcache_lru[id] = n_idx;
112  if (IS_SET(n_idx))
113  This->cache.bmpcache[id][n_idx].previous = p_idx;
114  else
115  This->cache.bmpcache_mru[id] = p_idx;
116  }
117  else
118  {
119  p_idx = NOT_SET;
120  n_idx = This->cache.bmpcache_lru[id];
121  }
122 
123  if (bump >= 0)
124  {
125  for (n = 0; n < bump && IS_SET(n_idx); n++)
126  {
127  p_idx = n_idx;
128  n_idx = This->cache.bmpcache[id][p_idx].next;
129  }
130  }
131  else
132  {
133  p_idx = This->cache.bmpcache_mru[id];
134  n_idx = NOT_SET;
135  }
136 
137  /* insert */
138  ++This->cache.bmpcache_count[id];
139  This->cache.bmpcache[id][idx].previous = p_idx;
140  This->cache.bmpcache[id][idx].next = n_idx;
141 
142  if (p_idx >= 0)
143  This->cache.bmpcache[id][p_idx].next = idx;
144  else
145  This->cache.bmpcache_lru[id] = idx;
146 
147  if (n_idx >= 0)
148  This->cache.bmpcache[id][n_idx].previous = idx;
149  else
150  This->cache.bmpcache_mru[id] = idx;
151 }
152 
153 /* Evict the least-recently used bitmap from the cache */
154 void
156 {
157  uint16 idx;
158  int n_idx;
159 
160  if (!IS_PERSISTENT(id))
161  return;
162 
163  idx = This->cache.bmpcache_lru[id];
164  n_idx = This->cache.bmpcache[id][idx].next;
165  DEBUG_RDP5(("evict bitmap: id=%d idx=%d n_idx=%d bmp=0x%x\n", id, idx, n_idx,
166  This->cache.bmpcache[id][idx].bitmap));
167 
168  ui_destroy_bitmap(This, This->cache.bmpcache[id][idx].bitmap);
169  --This->cache.bmpcache_count[id];
170  This->cache.bmpcache[id][idx].bitmap = 0;
171 
172  This->cache.bmpcache_lru[id] = n_idx;
173  This->cache.bmpcache[id][n_idx].previous = NOT_SET;
174 
175  pstcache_touch_bitmap(This, id, idx, 0);
176 }
177 
178 /* Retrieve a bitmap from the cache */
179 HBITMAP
181 {
182  if ((id < NUM_ELEMENTS(This->cache.bmpcache)) && (idx < NUM_ELEMENTS(This->cache.bmpcache[0])))
183  {
184  if (This->cache.bmpcache[id][idx].bitmap || pstcache_load_bitmap(This, id, idx))
185  {
186  if (IS_PERSISTENT(id))
188 
189  return This->cache.bmpcache[id][idx].bitmap;
190  }
191  }
192  else if ((id < NUM_ELEMENTS(This->cache.volatile_bc)) && (idx == 0x7fff))
193  {
194  return This->cache.volatile_bc[id];
195  }
196 
197  error("get bitmap %d:%d\n", id, idx);
198  return NULL;
199 }
200 
201 /* Store a bitmap in the cache */
202 void
204 {
205  HBITMAP old;
206 
207  if ((id < NUM_ELEMENTS(This->cache.bmpcache)) && (idx < NUM_ELEMENTS(This->cache.bmpcache[0])))
208  {
209  old = This->cache.bmpcache[id][idx].bitmap;
210  if (old != NULL)
211  ui_destroy_bitmap(This, old);
212  This->cache.bmpcache[id][idx].bitmap = bitmap;
213 
214  if (IS_PERSISTENT(id))
215  {
216  if (old == NULL)
217  This->cache.bmpcache[id][idx].previous = This->cache.bmpcache[id][idx].next = NOT_SET;
218 
220  if (This->cache.bmpcache_count[id] > BMPCACHE2_C2_CELLS)
222  }
223  }
224  else if ((id < NUM_ELEMENTS(This->cache.volatile_bc)) && (idx == 0x7fff))
225  {
226  old = This->cache.volatile_bc[id];
227  if (old != NULL)
228  ui_destroy_bitmap(This, old);
229  This->cache.volatile_bc[id] = bitmap;
230  }
231  else
232  {
233  error("put bitmap %d:%d\n", id, idx);
234  }
235 }
236 
237 /* Updates the persistent bitmap cache MRU information on exit */
238 void
240 {
241  uint32 id = 0, t = 0;
242  int idx;
243 
244  for (id = 0; id < NUM_ELEMENTS(This->cache.bmpcache); id++)
245  if (IS_PERSISTENT(id))
246  {
247  DEBUG_RDP5(("Saving cache state for bitmap cache %d...", id));
248  idx = This->cache.bmpcache_lru[id];
249  while (idx >= 0)
250  {
251  pstcache_touch_bitmap(This, id, idx, ++t);
252  idx = This->cache.bmpcache[id][idx].next;
253  }
254  DEBUG_RDP5((" %d stamps written.\n", t));
255  }
256 }
257 
258 
259 /* FONT CACHE */
260 /* Retrieve a glyph from the font cache */
261 FONTGLYPH *
263 {
264  FONTGLYPH *glyph;
265 
266  if ((font < NUM_ELEMENTS(This->cache.fontcache)) && (character < NUM_ELEMENTS(This->cache.fontcache[0])))
267  {
268  glyph = &This->cache.fontcache[font][character];
269  if (glyph->pixmap != NULL)
270  return glyph;
271  }
272 
273  error("get font %d:%d\n", font, character);
274  return NULL;
275 }
276 
277 /* Store a glyph in the font cache */
278 void
280  uint16 baseline, uint16 width, uint16 height, HGLYPH pixmap)
281 {
282  FONTGLYPH *glyph;
283 
284  if ((font < NUM_ELEMENTS(This->cache.fontcache)) && (character < NUM_ELEMENTS(This->cache.fontcache[0])))
285  {
286  glyph = &This->cache.fontcache[font][character];
287  if (glyph->pixmap != NULL)
288  ui_destroy_glyph(This, glyph->pixmap);
289 
290  glyph->offset = offset;
291  glyph->baseline = baseline;
292  glyph->width = width;
293  glyph->height = height;
294  glyph->pixmap = pixmap;
295  }
296  else
297  {
298  error("put font %d:%d\n", font, character);
299  }
300 }
301 
302 
303 /* TEXT CACHE */
304 /* Retrieve a text item from the cache */
305 DATABLOB *
307 {
308  DATABLOB *text;
309 
310  text = &This->cache.textcache[cache_id];
311  return text;
312 }
313 
314 /* Store a text item in the cache */
315 void
316 cache_put_text(RDPCLIENT * This, uint8 cache_id, void *data, int length)
317 {
318  DATABLOB *text;
319  void * p = malloc(length);
320 
321  if(p == NULL)
322  return;
323 
324  text = &This->cache.textcache[cache_id];
325  if (text->data != NULL)
326  free(text->data);
327  text->data = p;
328  text->size = length;
329  memcpy(text->data, data, length);
330 }
331 
332 
333 /* DESKTOP CACHE */
334 /* Retrieve desktop data from the cache */
335 uint8 *
336 cache_get_desktop(RDPCLIENT * This, uint32 offset, int cx, int cy, int bytes_per_pixel)
337 {
338  int length = cx * cy * bytes_per_pixel;
339 
340  if (offset > sizeof(This->cache.deskcache))
341  offset = 0;
342 
343  if ((offset + length) <= sizeof(This->cache.deskcache))
344  {
345  return &This->cache.deskcache[offset];
346  }
347 
348  error("get desktop %d:%d\n", offset, length);
349  return NULL;
350 }
351 
352 /* Store desktop data in the cache */
353 void
354 cache_put_desktop(RDPCLIENT * This, uint32 offset, int cx, int cy, int scanline, int bytes_per_pixel, uint8 * data)
355 {
356  int length = cx * cy * bytes_per_pixel;
357 
358  if (offset > sizeof(This->cache.deskcache))
359  offset = 0;
360 
361  if ((offset + length) <= sizeof(This->cache.deskcache))
362  {
363  cx *= bytes_per_pixel;
364  while (cy--)
365  {
366  memcpy(&This->cache.deskcache[offset], data, cx);
367  data += scanline;
368  offset += cx;
369  }
370  }
371  else
372  {
373  error("put desktop %d:%d\n", offset, length);
374  }
375 }
376 
377 
378 /* CURSOR CACHE */
379 /* Retrieve cursor from cache */
380 HCURSOR
382 {
383  HCURSOR cursor;
384 
385  if (cache_idx < NUM_ELEMENTS(This->cache.cursorcache))
386  {
387  cursor = This->cache.cursorcache[cache_idx];
388  if (cursor != NULL)
389  return cursor;
390  }
391 
392  error("get cursor %d\n", cache_idx);
393  return NULL;
394 }
395 
396 /* Store cursor in cache */
397 void
399 {
400  HCURSOR old;
401 
402  if (cache_idx < NUM_ELEMENTS(This->cache.cursorcache))
403  {
404  old = This->cache.cursorcache[cache_idx];
405  if (old != NULL)
406  ui_destroy_cursor(This, old);
407 
408  This->cache.cursorcache[cache_idx] = cursor;
409  }
410  else
411  {
412  error("put cursor %d\n", cache_idx);
413  }
414 }
RD_BOOL pstcache_load_bitmap(uint8 cache_id, uint16 cache_idx)
Definition: pstcache.c:53
GLint GLint GLsizei width
Definition: gl.h:1546
#define BMPCACHE2_C2_CELLS
Definition: constants.h:284
void cache_bump_bitmap(uint8 id, uint16 idx, int bump)
Definition: cache.c:104
#define error(str)
Definition: mkdosfs.c:1605
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
#define free
Definition: debug_ros.c:5
uint16 height
Definition: types.h:115
GLintptr offset
Definition: glext.h:5920
GLdouble n
Definition: glext.h:7729
GLdouble GLdouble t
Definition: gl.h:2047
sint16 baseline
Definition: types.h:113
HICON HCURSOR
Definition: windef.h:284
#define TO_TOP
Definition: cache.c:29
#define NUM_ELEMENTS(array)
Definition: cache.c:27
FONTGLYPH * cache_get_font(uint8 font, uint16 character)
Definition: cache.c:279
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
#define IS_SET(idx)
Definition: cache.c:31
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
#define NOT_SET
Definition: cache.c:30
#define IS_PERSISTENT(id)
Definition: cache.c:28
GLenum GLuint GLenum GLsizei length
Definition: glext.h:5579
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
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: gl.h:1950
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
signed short sint16
Definition: types.h:31
void cache_evict_bitmap(uint8 id)
Definition: cache.c:170
GLint GLint GLsizei GLsizei height
Definition: gl.h:1546
uint16 width
Definition: types.h:114
sint16 offset
Definition: types.h:112
#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
#define BUMP_COUNT
Definition: cache.c:39
unsigned short uint16
Definition: types.h:30
_Out_opt_ int * cx
Definition: commctrl.h:570
GLenum GLuint id
Definition: glext.h:5579
#define malloc
Definition: debug_ros.c:4
static HBITMAP bitmap
Definition: clipboard.c:1344
DATABLOB * cache_get_text(uint8 cache_id)
Definition: cache.c:325
static HBITMAP
Definition: button.c:44
void exit(int exitcode)
Definition: _exit.c:33
GLfloat GLfloat p
Definition: glext.h:8902
RD_HBITMAP pixmap
Definition: types.h:116
void ui_destroy_glyph(RD_HGLYPH glyph)
Definition: qtewin.cpp:1424
void ui_destroy_cursor(RD_HCURSOR cursor)