1 /* -*- c-basic-offset: 8 -*-
2 rdesktop: A Remote Desktop Protocol client.
4 Copyright (C) Matthew Chapman 1999-2005
5 Copyright (C) Jeroen Meijer 2005
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.
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.
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.
25 extern int g_pstcache_fd
[];
27 #define NUM_ELEMENTS(array) (sizeof(array) / sizeof(array[0]))
28 //#define IS_PERSISTENT(id) (g_pstcache_fd[id] > 0)
31 #define IS_SET(idx) (idx >= 0)
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.
48 static struct bmpcache_entry g_bmpcache
[3][0xa00];
49 static RD_HBITMAP g_volatile_bc
[3];
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 static int g_bmpcache_count
[3];
55 /* Setup the bitmap cache lru/mru linked list */
57 cache_rebuild_bmpcache_linked_list(uint8 id
, sint16
* idx
, int count
)
62 /* find top, skip evicted bitmaps */
63 while (--n
>= 0 && g_bmpcache
[id
][idx
[n
]].bitmap
== NULL
);
66 g_bmpcache_mru
[id
] = g_bmpcache_lru
[id
] = NOT_SET
;
70 g_bmpcache_mru
[id
] = idx
[n
];
71 g_bmpcache
[id
][idx
[n
]].next
= NOT_SET
;
78 /* skip evicted bitmaps */
79 while (--n
>= 0 && g_bmpcache
[id
][idx
[n
]].bitmap
== NULL
);
84 g_bmpcache
[id
][n_idx
].previous
= idx
[n
];
85 g_bmpcache
[id
][idx
[n
]].next
= n_idx
;
90 g_bmpcache
[id
][n_idx
].previous
= NOT_SET
;
91 g_bmpcache_lru
[id
] = n_idx
;
93 if (c
!= g_bmpcache_count
[id
])
95 error("Oops. %d in bitmap cache linked list, %d in ui cache...\n", c
,
96 g_bmpcache_count
[id
]);
101 /* Move a bitmap to a new position in the linked list. */
103 cache_bump_bitmap(uint8 id
, uint16 idx
, int bump
)
107 if (!IS_PERSISTENT(id
))
110 if (g_bmpcache_mru
[id
] == idx
)
113 DEBUG_RDP5(("bump bitmap: id=%d, idx=%d, bump=%d\n", id
, idx
, bump
));
115 n_idx
= g_bmpcache
[id
][idx
].next
;
116 p_idx
= g_bmpcache
[id
][idx
].previous
;
121 --g_bmpcache_count
[id
];
123 g_bmpcache
[id
][p_idx
].next
= n_idx
;
125 g_bmpcache_lru
[id
] = n_idx
;
127 g_bmpcache
[id
][n_idx
].previous
= p_idx
;
129 g_bmpcache_mru
[id
] = p_idx
;
134 n_idx
= g_bmpcache_lru
[id
];
139 for (n
= 0; n
< bump
&& IS_SET(n_idx
); n
++)
142 n_idx
= g_bmpcache
[id
][p_idx
].next
;
147 p_idx
= g_bmpcache_mru
[id
];
152 ++g_bmpcache_count
[id
];
153 g_bmpcache
[id
][idx
].previous
= p_idx
;
154 g_bmpcache
[id
][idx
].next
= n_idx
;
157 g_bmpcache
[id
][p_idx
].next
= idx
;
159 g_bmpcache_lru
[id
] = idx
;
162 g_bmpcache
[id
][n_idx
].previous
= idx
;
164 g_bmpcache_mru
[id
] = idx
;
167 /* Evict the least-recently used bitmap from the cache */
169 cache_evict_bitmap(uint8 id
)
174 if (!IS_PERSISTENT(id
))
177 idx
= g_bmpcache_lru
[id
];
178 n_idx
= g_bmpcache
[id
][idx
].next
;
179 DEBUG_RDP5(("evict bitmap: id=%d idx=%d n_idx=%d bmp=0x%x\n", id
, idx
, n_idx
,
180 g_bmpcache
[id
][idx
].bitmap
));
182 ui_destroy_bitmap(g_bmpcache
[id
][idx
].bitmap
);
183 --g_bmpcache_count
[id
];
184 g_bmpcache
[id
][idx
].bitmap
= 0;
186 g_bmpcache_lru
[id
] = n_idx
;
187 g_bmpcache
[id
][n_idx
].previous
= NOT_SET
;
189 pstcache_touch_bitmap(id
, idx
, 0);
192 /* Retrieve a bitmap from the cache */
194 cache_get_bitmap(uint8 id
, uint16 idx
)
196 if ((id
< NUM_ELEMENTS(g_bmpcache
)) && (idx
< NUM_ELEMENTS(g_bmpcache
[0])))
198 if (g_bmpcache
[id
][idx
].bitmap
|| pstcache_load_bitmap(id
, idx
))
200 if (IS_PERSISTENT(id
))
201 cache_bump_bitmap(id
, idx
, BUMP_COUNT
);
203 return g_bmpcache
[id
][idx
].bitmap
;
206 else if ((id
< NUM_ELEMENTS(g_volatile_bc
)) && (idx
== 0x7fff))
208 return g_volatile_bc
[id
];
211 error("get bitmap %d:%d\n", id
, idx
);
215 /* Store a bitmap in the cache */
217 cache_put_bitmap(uint8 id
, uint16 idx
, RD_HBITMAP bitmap
)
221 if ((id
< NUM_ELEMENTS(g_bmpcache
)) && (idx
< NUM_ELEMENTS(g_bmpcache
[0])))
223 old
= g_bmpcache
[id
][idx
].bitmap
;
225 ui_destroy_bitmap(old
);
226 g_bmpcache
[id
][idx
].bitmap
= bitmap
;
228 if (IS_PERSISTENT(id
))
231 g_bmpcache
[id
][idx
].previous
= g_bmpcache
[id
][idx
].next
= NOT_SET
;
233 cache_bump_bitmap(id
, idx
, TO_TOP
);
234 if (g_bmpcache_count
[id
] > BMPCACHE2_C2_CELLS
)
235 cache_evict_bitmap(id
);
238 else if ((id
< NUM_ELEMENTS(g_volatile_bc
)) && (idx
== 0x7fff))
240 old
= g_volatile_bc
[id
];
242 ui_destroy_bitmap(old
);
243 g_volatile_bc
[id
] = bitmap
;
247 error("put bitmap %d:%d\n", id
, idx
);
251 /* Updates the persistent bitmap cache MRU information on exit */
253 cache_save_state(void)
255 uint32 id
= 0, t
= 0;
258 for (id
= 0; id
< NUM_ELEMENTS(g_bmpcache
); id
++)
259 if (IS_PERSISTENT(id
))
261 DEBUG_RDP5(("Saving cache state for bitmap cache %d...", id
));
262 idx
= g_bmpcache_lru
[id
];
265 pstcache_touch_bitmap((uint8
) id
, (uint16
) idx
, ++t
);
266 idx
= g_bmpcache
[id
][idx
].next
;
268 DEBUG_RDP5((" %d stamps written.\n", t
));
274 static FONTGLYPH g_fontcache
[12][256];
276 /* Retrieve a glyph from the font cache */
278 cache_get_font(uint8 font
, uint16 character
)
282 if ((font
< NUM_ELEMENTS(g_fontcache
)) && (character
< NUM_ELEMENTS(g_fontcache
[0])))
284 glyph
= &g_fontcache
[font
][character
];
285 if (glyph
->pixmap
!= NULL
)
289 error("get font %d:%d\n", font
, character
);
293 /* Store a glyph in the font cache */
295 cache_put_font(uint8 font
, uint16 character
, uint16 offset
,
296 uint16 baseline
, uint16 width
, uint16 height
, RD_HGLYPH pixmap
)
300 if ((font
< NUM_ELEMENTS(g_fontcache
)) && (character
< NUM_ELEMENTS(g_fontcache
[0])))
302 glyph
= &g_fontcache
[font
][character
];
303 if (glyph
->pixmap
!= NULL
)
304 ui_destroy_glyph(glyph
->pixmap
);
306 glyph
->offset
= offset
;
307 glyph
->baseline
= baseline
;
308 glyph
->width
= width
;
309 glyph
->height
= height
;
310 glyph
->pixmap
= pixmap
;
314 error("put font %d:%d\n", font
, character
);
320 static DATABLOB g_textcache
[256];
322 /* Retrieve a text item from the cache */
324 cache_get_text(uint8 cache_id
)
328 text
= &g_textcache
[cache_id
];
332 /* Store a text item in the cache */
334 cache_put_text(uint8 cache_id
, void *data
, int length
)
338 text
= &g_textcache
[cache_id
];
339 if (text
->data
!= NULL
)
341 text
->data
= xmalloc(length
);
343 memcpy(text
->data
, data
, length
);
348 static uint8 g_deskcache
[0x38400 * 4];
350 /* Retrieve desktop data from the cache */
352 cache_get_desktop(uint32 offset
, int cx
, int cy
, int bytes_per_pixel
)
354 int length
= cx
* cy
* bytes_per_pixel
;
356 if (offset
> sizeof(g_deskcache
))
359 if ((offset
+ length
) <= sizeof(g_deskcache
))
361 return &g_deskcache
[offset
];
364 error("get desktop %d:%d\n", offset
, length
);
368 /* Store desktop data in the cache */
370 cache_put_desktop(uint32 offset
, int cx
, int cy
, int scanline
, int bytes_per_pixel
, uint8
* data
)
372 int length
= cx
* cy
* bytes_per_pixel
;
374 if (offset
> sizeof(g_deskcache
))
377 if ((offset
+ length
) <= sizeof(g_deskcache
))
379 cx
*= bytes_per_pixel
;
382 memcpy(&g_deskcache
[offset
], data
, cx
);
389 error("put desktop %d:%d\n", offset
, length
);
395 static RD_HCURSOR g_cursorcache
[0x20];
397 /* Retrieve cursor from cache */
399 cache_get_cursor(uint16 cache_idx
)
403 if (cache_idx
< NUM_ELEMENTS(g_cursorcache
))
405 cursor
= g_cursorcache
[cache_idx
];
410 error("get cursor %d\n", cache_idx
);
414 /* Store cursor in cache */
416 cache_put_cursor(uint16 cache_idx
, RD_HCURSOR cursor
)
420 if (cache_idx
< NUM_ELEMENTS(g_cursorcache
))
422 old
= g_cursorcache
[cache_idx
];
424 ui_destroy_cursor(old
);
426 g_cursorcache
[cache_idx
] = cursor
;
430 error("put cursor %d\n", cache_idx
);