~ubuntu-branches/ubuntu/wily/freerdp/wily-proposed

« back to all changes in this revision

Viewing changes to libfreerdp/cache.c

  • Committer: Package Import Robot
  • Author(s): Martin Pitt, Jeremy Bicha, Jean-Louis Dupond, Martin Pitt
  • Date: 2012-01-31 10:02:14 UTC
  • mfrom: (1.1.6)
  • Revision ID: package-import@ubuntu.com-20120131100214-jaok3uwvni7sqxth
Tags: 1.0.0-0git1
Upload current Debian packaging git to get this rolling for precise.

[ Jeremy Bicha ]
* New upstream release. Closes: #647498.
* Updated symbols and bumped soname
* debian/control:
  - Added new build dependencies
  - Bump Standards-Version to 3.9.2
* debian/source/format: Set to 3.0 (quilt)
* debian/rules: Turn on strict symbols checking
* debian/watch: Watch github

[ Jean-Louis Dupond ]
* debian/control: Updated homepage
* debian/copyright: Reflect upstream switch to the Apache license

[ Martin Pitt ]
* debian/libfreerdp0.symbols: Fix version number, should
  be 1.0~beta5, not 1.0-beta5.
* debian/control: Add libavcodec-dev build dependency, upstream build system
  checks for that. Thanks Jean-Louis Dupond!

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* -*- c-basic-offset: 8 -*-
2
 
   rdesktop: A Remote Desktop Protocol client.
3
 
   Cache routines
4
 
   Copyright (C) Matthew Chapman 1999-2008
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
18
 
   along with this program; if not, write to the Free Software
19
 
   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20
 
*/
21
 
 
22
 
#include "frdp.h"
23
 
#include "cache.h"
24
 
#include "rdp.h"
25
 
#include "pstcache.h"
26
 
#include "mem.h"
27
 
#include "debug.h"
28
 
 
29
 
#define NUM_ELEMENTS(array) (sizeof(array) / sizeof(array[0]))
30
 
#define IS_PERSISTENT(id) (cache->rdp->pcache->pstcache_fd[id] > 0)
31
 
#define TO_TOP -1
32
 
#define NOT_SET -1
33
 
#define IS_SET(idx) (idx >= 0)
34
 
 
35
 
/*
36
 
 * TODO: Test for optimal value of BUMP_COUNT. TO_TOP gives lowest cpu utilisation but using
37
 
 * a positive value will hopefully result in less frequently used bitmaps having a greater chance
38
 
 * of being evicted from the cache, and therby reducing the need to load bitmaps from disk.
39
 
 * (Jeroen)
40
 
 */
41
 
#define BUMP_COUNT 40
42
 
 
43
 
/* Setup the bitmap cache lru/mru linked list */
44
 
void
45
 
cache_rebuild_bmpcache_linked_list(rdpCache * cache, uint8 id, sint16 * idx, int count)
46
 
{
47
 
        int n = count, c = 0;
48
 
        sint16 n_idx;
49
 
 
50
 
        /* find top, skip evicted bitmaps */
51
 
        while (--n >= 0 && cache->bmpcache[id][idx[n]].bitmap == NULL);
52
 
        if (n < 0)
53
 
        {
54
 
                cache->bmpcache_mru[id] = cache->bmpcache_lru[id] = NOT_SET;
55
 
                return;
56
 
        }
57
 
 
58
 
        cache->bmpcache_mru[id] = idx[n];
59
 
        cache->bmpcache[id][idx[n]].next = NOT_SET;
60
 
        n_idx = idx[n];
61
 
        c++;
62
 
 
63
 
        /* link list */
64
 
        while (n >= 0)
65
 
        {
66
 
                /* skip evicted bitmaps */
67
 
                while (--n >= 0 && cache->bmpcache[id][idx[n]].bitmap == NULL);
68
 
 
69
 
                if (n < 0)
70
 
                        break;
71
 
 
72
 
                cache->bmpcache[id][n_idx].previous = idx[n];
73
 
                cache->bmpcache[id][idx[n]].next = n_idx;
74
 
                n_idx = idx[n];
75
 
                c++;
76
 
        }
77
 
 
78
 
        cache->bmpcache[id][n_idx].previous = NOT_SET;
79
 
        cache->bmpcache_lru[id] = n_idx;
80
 
 
81
 
        if (c != cache->bmpcache_count[id])
82
 
        {
83
 
                ui_error(cache->rdp->inst, "Oops. %d in bitmap cache linked list, %d in ui "
84
 
                         "cache...\n", c, cache->bmpcache_count[id]);
85
 
                exit(1);
86
 
        }
87
 
}
88
 
 
89
 
/* Move a bitmap to a new position in the linked list. */
90
 
void
91
 
cache_bump_bitmap(rdpCache * cache, uint8 id, uint16 idx, int bump)
92
 
{
93
 
        int p_idx, n_idx, n;
94
 
 
95
 
        if (!IS_PERSISTENT(id))
96
 
                return;
97
 
 
98
 
        if (cache->bmpcache_mru[id] == idx)
99
 
                return;
100
 
 
101
 
        DEBUG_RDP5("bump bitmap: id=%d, idx=%d, bump=%d\n", id, idx, bump);
102
 
 
103
 
        n_idx = cache->bmpcache[id][idx].next;
104
 
        p_idx = cache->bmpcache[id][idx].previous;
105
 
 
106
 
        if (IS_SET(n_idx))
107
 
        {
108
 
                /* remove */
109
 
                --(cache->bmpcache_count[id]);
110
 
                if (IS_SET(p_idx))
111
 
                        cache->bmpcache[id][p_idx].next = n_idx;
112
 
                else
113
 
                        cache->bmpcache_lru[id] = n_idx;
114
 
                if (IS_SET(n_idx))
115
 
                        cache->bmpcache[id][n_idx].previous = p_idx;
116
 
                else
117
 
                        cache->bmpcache_mru[id] = p_idx;
118
 
        }
119
 
        else
120
 
        {
121
 
                p_idx = NOT_SET;
122
 
                n_idx = cache->bmpcache_lru[id];
123
 
        }
124
 
 
125
 
        if (bump >= 0)
126
 
        {
127
 
                for (n = 0; n < bump && IS_SET(n_idx); n++)
128
 
                {
129
 
                        p_idx = n_idx;
130
 
                        n_idx = cache->bmpcache[id][p_idx].next;
131
 
                }
132
 
        }
133
 
        else
134
 
        {
135
 
                p_idx = cache->bmpcache_mru[id];
136
 
                n_idx = NOT_SET;
137
 
        }
138
 
 
139
 
        /* insert */
140
 
        ++(cache->bmpcache_count[id]);
141
 
        cache->bmpcache[id][idx].previous = p_idx;
142
 
        cache->bmpcache[id][idx].next = n_idx;
143
 
 
144
 
        if (p_idx >= 0)
145
 
                cache->bmpcache[id][p_idx].next = idx;
146
 
        else
147
 
                cache->bmpcache_lru[id] = idx;
148
 
 
149
 
        if (n_idx >= 0)
150
 
                cache->bmpcache[id][n_idx].previous = idx;
151
 
        else
152
 
                cache->bmpcache_mru[id] = idx;
153
 
}
154
 
 
155
 
/* Evict the least-recently used bitmap from the cache */
156
 
void
157
 
cache_evict_bitmap(rdpCache * cache, uint8 id)
158
 
{
159
 
        uint16 idx;
160
 
        int n_idx;
161
 
 
162
 
        if (!IS_PERSISTENT(id))
163
 
                return;
164
 
 
165
 
        idx = cache->bmpcache_lru[id];
166
 
        n_idx = cache->bmpcache[id][idx].next;
167
 
/*      DEBUG_RDP5("evict bitmap: id=%d idx=%d n_idx=%d bmp=0x%x\n", id, idx, n_idx,
168
 
                    cache->bmpcache[id][idx].bitmap); */
169
 
 
170
 
        ui_destroy_bitmap(cache->rdp->inst, cache->bmpcache[id][idx].bitmap);
171
 
        --(cache->bmpcache_count[id]);
172
 
        cache->bmpcache[id][idx].bitmap = 0;
173
 
 
174
 
        cache->bmpcache_lru[id] = n_idx;
175
 
        cache->bmpcache[id][n_idx].previous = NOT_SET;
176
 
 
177
 
        pstcache_touch_bitmap(cache->rdp->pcache, id, idx, 0);
178
 
}
179
 
 
180
 
/* Retrieve a bitmap from the cache */
181
 
RD_HBITMAP
182
 
cache_get_bitmap(rdpCache * cache, uint8 id, uint16 idx)
183
 
{
184
 
        if ((id < NUM_ELEMENTS(cache->bmpcache)) && (idx < NUM_ELEMENTS(cache->bmpcache[0])))
185
 
        {
186
 
                if (cache->bmpcache[id][idx].bitmap ||
187
 
                    pstcache_load_bitmap(cache->rdp->pcache, id, idx))
188
 
                {
189
 
                        if (IS_PERSISTENT(id))
190
 
                                cache_bump_bitmap(cache, id, idx, BUMP_COUNT);
191
 
 
192
 
                        return cache->bmpcache[id][idx].bitmap;
193
 
                }
194
 
        }
195
 
        else if ((id < NUM_ELEMENTS(cache->volatile_bc)) && (idx == 0x7fff))
196
 
        {
197
 
                return cache->volatile_bc[id];
198
 
        }
199
 
        else if ((id == 255) && (idx < NUM_ELEMENTS(cache->drawing_surface)))
200
 
        {
201
 
                return cache->drawing_surface[idx];
202
 
        }
203
 
        ui_error(cache->rdp->inst, "get bitmap %d:%d\n", id, idx);
204
 
        return NULL;
205
 
}
206
 
 
207
 
/* Store a bitmap in the cache */
208
 
void
209
 
cache_put_bitmap(rdpCache * cache, uint8 id, uint16 idx, RD_HBITMAP bitmap)
210
 
{
211
 
        RD_HBITMAP old;
212
 
 
213
 
        if ((id < NUM_ELEMENTS(cache->bmpcache)) && (idx < NUM_ELEMENTS(cache->bmpcache[0])))
214
 
        {
215
 
                old = cache->bmpcache[id][idx].bitmap;
216
 
                if (old != NULL)
217
 
                        ui_destroy_bitmap(cache->rdp->inst, old);
218
 
                cache->bmpcache[id][idx].bitmap = bitmap;
219
 
 
220
 
                if (IS_PERSISTENT(id))
221
 
                {
222
 
                        if (old == NULL)
223
 
                                cache->bmpcache[id][idx].previous =
224
 
                                cache->bmpcache[id][idx].next = NOT_SET;
225
 
 
226
 
                        cache_bump_bitmap(cache, id, idx, TO_TOP);
227
 
                        if (cache->bmpcache_count[id] > BMPCACHE2_C2_CELLS)
228
 
                                cache_evict_bitmap(cache, id);
229
 
                }
230
 
        }
231
 
        else if ((id < NUM_ELEMENTS(cache->volatile_bc)) && (idx == 0x7fff))
232
 
        {
233
 
                old = cache->volatile_bc[id];
234
 
                if (old != NULL)
235
 
                        ui_destroy_bitmap(cache->rdp->inst, old);
236
 
                cache->volatile_bc[id] = bitmap;
237
 
        }
238
 
        else if ((id == 255) && (idx < NUM_ELEMENTS(cache->drawing_surface)))
239
 
        {
240
 
                cache->drawing_surface[idx] = bitmap;
241
 
        }
242
 
        else
243
 
        {
244
 
                ui_error(cache->rdp->inst, "put bitmap %d:%d\n", id, idx);
245
 
        }
246
 
}
247
 
 
248
 
/* Updates the persistent bitmap cache MRU information on exit */
249
 
void
250
 
cache_save_state(rdpCache * cache)
251
 
{
252
 
        uint32 id = 0, t = 0;
253
 
        int idx;
254
 
 
255
 
        for (id = 0; id < NUM_ELEMENTS(cache->bmpcache); id++)
256
 
                if (IS_PERSISTENT(id))
257
 
                {
258
 
                        DEBUG_RDP5("Saving cache state for bitmap cache %d...", id);
259
 
                        idx = cache->bmpcache_lru[id];
260
 
                        while (idx >= 0)
261
 
                        {
262
 
                                pstcache_touch_bitmap(cache->rdp->pcache, id, idx, ++t);
263
 
                                idx = cache->bmpcache[id][idx].next;
264
 
                        }
265
 
                        DEBUG_RDP5(" %d stamps written.\n", t);
266
 
                }
267
 
}
268
 
 
269
 
/* Retrieve a glyph from the font cache */
270
 
FONTGLYPH *
271
 
cache_get_font(rdpCache * cache, uint8 font, uint16 character)
272
 
{
273
 
        FONTGLYPH *glyph;
274
 
 
275
 
        if ((font < NUM_ELEMENTS(cache->fontcache)) && (character < NUM_ELEMENTS(cache->fontcache[0])))
276
 
        {
277
 
                glyph = &(cache->fontcache[font][character]);
278
 
                if (glyph->pixmap != NULL)
279
 
                        return glyph;
280
 
        }
281
 
 
282
 
        ui_error(cache->rdp->inst, "get font %d:%d\n", font, character);
283
 
        return NULL;
284
 
}
285
 
 
286
 
/* Store a glyph in the font cache */
287
 
void
288
 
cache_put_font(rdpCache * cache, uint8 font, uint16 character, uint16 offset,
289
 
               uint16 baseline, uint16 width, uint16 height, RD_HGLYPH pixmap)
290
 
{
291
 
        FONTGLYPH *glyph;
292
 
 
293
 
        if ((font < NUM_ELEMENTS(cache->fontcache)) && (character < NUM_ELEMENTS(cache->fontcache[0])))
294
 
        {
295
 
                glyph = &(cache->fontcache[font][character]);
296
 
                if (glyph->pixmap != NULL)
297
 
                        ui_destroy_glyph(cache->rdp->inst, glyph->pixmap);
298
 
 
299
 
                glyph->offset = offset;
300
 
                glyph->baseline = baseline;
301
 
                glyph->width = width;
302
 
                glyph->height = height;
303
 
                glyph->pixmap = pixmap;
304
 
        }
305
 
        else
306
 
        {
307
 
                ui_error(cache->rdp->inst, "put font %d:%d\n", font, character);
308
 
        }
309
 
}
310
 
 
311
 
/* Retrieve a text item from the cache */
312
 
DATABLOB *
313
 
cache_get_text(rdpCache * cache, uint8 cache_id)
314
 
{
315
 
        DATABLOB *text;
316
 
 
317
 
        text = &(cache->textcache[cache_id]);
318
 
        return text;
319
 
}
320
 
 
321
 
/* Store a text item in the cache */
322
 
void
323
 
cache_put_text(rdpCache * cache, uint8 cache_id, void *data, int length)
324
 
{
325
 
        DATABLOB *text;
326
 
 
327
 
        text = &(cache->textcache[cache_id]);
328
 
        if (text->data != NULL)
329
 
                xfree(text->data);
330
 
        text->data = xmalloc(length);
331
 
        text->size = length;
332
 
        memcpy(text->data, data, length);
333
 
}
334
 
 
335
 
/* Retrieve cursor from cache */
336
 
RD_HCURSOR
337
 
cache_get_cursor(rdpCache * cache, uint16 cache_idx)
338
 
{
339
 
        RD_HCURSOR cursor;
340
 
 
341
 
        if (cache_idx < NUM_ELEMENTS(cache->cursorcache))
342
 
        {
343
 
                cursor = cache->cursorcache[cache_idx];
344
 
                if (cursor != NULL)
345
 
                        return cursor;
346
 
        }
347
 
 
348
 
        ui_error(cache->rdp->inst, "get cursor %d\n", cache_idx);
349
 
        return NULL;
350
 
}
351
 
 
352
 
/* Store cursor in cache */
353
 
void
354
 
cache_put_cursor(rdpCache * cache, uint16 cache_idx, RD_HCURSOR cursor)
355
 
{
356
 
        RD_HCURSOR old;
357
 
 
358
 
        if (cache_idx < NUM_ELEMENTS(cache->cursorcache))
359
 
        {
360
 
                old = cache->cursorcache[cache_idx];
361
 
                if (old != NULL)
362
 
                        ui_destroy_cursor(cache->rdp->inst, old);
363
 
 
364
 
                cache->cursorcache[cache_idx] = cursor;
365
 
        }
366
 
        else
367
 
        {
368
 
                ui_error(cache->rdp->inst, "put cursor %d\n", cache_idx);
369
 
        }
370
 
}
371
 
 
372
 
/* Retrieve brush from cache */
373
 
RD_BRUSHDATA *
374
 
cache_get_brush_data(rdpCache * cache, uint8 color_code, uint8 idx)
375
 
{
376
 
        color_code = color_code == 1 ? 0 : 1;
377
 
        if (idx < NUM_ELEMENTS(cache->brushcache[0]))
378
 
        {
379
 
                return &(cache->brushcache[color_code][idx]);
380
 
        }
381
 
        ui_error(cache->rdp->inst, "get brush %d %d\n", color_code, idx);
382
 
        return NULL;
383
 
}
384
 
 
385
 
/* Store brush in cache */
386
 
/* this function takes over the data pointer in struct, eg, caller gives it up */
387
 
void
388
 
cache_put_brush_data(rdpCache * cache, uint8 color_code, uint8 idx, RD_BRUSHDATA * brush_data)
389
 
{
390
 
        RD_BRUSHDATA *bd;
391
 
 
392
 
        color_code = color_code == 1 ? 0 : 1;
393
 
        if (idx < NUM_ELEMENTS(cache->brushcache[0]))
394
 
        {
395
 
                bd = &(cache->brushcache[color_code][idx]);
396
 
                if (bd->data != NULL)
397
 
                {
398
 
                        xfree(bd->data);
399
 
                }
400
 
                memcpy(bd, brush_data, sizeof(RD_BRUSHDATA));
401
 
        }
402
 
        else
403
 
        {
404
 
                ui_error(cache->rdp->inst, "put brush %d %d\n", color_code, idx);
405
 
        }
406
 
}
407
 
 
408
 
rdpCache *
409
 
cache_new(struct rdp_rdp * rdp)
410
 
{
411
 
        rdpCache * self;
412
 
 
413
 
        self = (rdpCache *) xmalloc(sizeof(rdpCache));
414
 
        if (self != NULL)
415
 
        {
416
 
                memset(self, 0, sizeof(rdpCache));
417
 
                self->rdp = rdp;
418
 
                self->bmpcache_lru[0] = NOT_SET;
419
 
                self->bmpcache_lru[1] = NOT_SET;
420
 
                self->bmpcache_lru[2] = NOT_SET;
421
 
                self->bmpcache_mru[0] = NOT_SET;
422
 
                self->bmpcache_mru[1] = NOT_SET;
423
 
                self->bmpcache_mru[2] = NOT_SET;
424
 
        }
425
 
        return self;
426
 
}
427
 
 
428
 
void
429
 
cache_free(rdpCache * cache)
430
 
{
431
 
        if (cache != NULL)
432
 
        {
433
 
                {
434
 
                        int color_code, idx;
435
 
                        RD_BRUSHDATA * bd;
436
 
 
437
 
                        for (color_code = 0; color_code < NUM_ELEMENTS(cache->brushcache); color_code++)
438
 
                        {
439
 
                                for(idx = 0; idx < NUM_ELEMENTS(cache->brushcache[color_code]); idx++)
440
 
                                {
441
 
                                        bd = &(cache->brushcache[color_code][idx]);
442
 
                                        if (bd->data != NULL)
443
 
                                        {
444
 
                                                xfree(bd->data);
445
 
                                        }
446
 
                                }
447
 
                        }
448
 
                }
449
 
 
450
 
                {
451
 
                        int cache_id;
452
 
                        DATABLOB * text;
453
 
 
454
 
                        for (cache_id = 0; cache_id < NUM_ELEMENTS(cache->textcache); cache_id++)
455
 
                        {
456
 
                                text = &(cache->textcache[cache_id]);
457
 
                                if (text->data != NULL)
458
 
                                        xfree(text->data);
459
 
                        }
460
 
                }
461
 
 
462
 
                {
463
 
                        int cache_id;
464
 
                        int cache_idx;
465
 
                        RD_HBITMAP * bmp;
466
 
 
467
 
                        for (cache_id = 0; cache_id < NUM_ELEMENTS(cache->bmpcache); cache_id++)
468
 
                        {
469
 
                                for (cache_idx = 0; cache_idx < NUM_ELEMENTS(cache->bmpcache[0]); cache_idx++)
470
 
                                {
471
 
                                        bmp = cache->bmpcache[cache_id][cache_idx].bitmap;
472
 
                                        if (bmp != NULL)
473
 
                                                ui_destroy_bitmap(cache->rdp->inst, bmp);
474
 
                                }
475
 
                        }
476
 
                        for (cache_id = 0; cache_id < NUM_ELEMENTS(cache->drawing_surface); cache_id++)
477
 
                        {
478
 
                                bmp = cache->drawing_surface[cache_id];
479
 
                                if (bmp)
480
 
                                        ui_destroy_surface(cache->rdp->inst, bmp);
481
 
                        }
482
 
                }
483
 
 
484
 
                {
485
 
                        int cache_id;
486
 
                        RD_HCURSOR cursor;
487
 
 
488
 
                        for (cache_id = 0; cache_id < NUM_ELEMENTS(cache->cursorcache); cache_id++)
489
 
                        {
490
 
                                cursor = cache->cursorcache[cache_id];
491
 
                                if (cursor)
492
 
                                        ui_destroy_cursor(cache->rdp->inst, cursor);
493
 
                        }
494
 
                }
495
 
 
496
 
                {
497
 
                        int cache_id;
498
 
                        int cache_idx;
499
 
                        RD_HGLYPH * glyph;
500
 
 
501
 
                        for (cache_id = 0; cache_id < NUM_ELEMENTS(cache->fontcache); cache_id++)
502
 
                        {
503
 
                                for (cache_idx = 0; cache_idx < NUM_ELEMENTS(cache->fontcache[0]); cache_idx++)
504
 
                                {
505
 
                                        glyph = cache->fontcache[cache_id][cache_idx].pixmap;
506
 
                                        if (glyph != NULL)
507
 
                                                ui_destroy_glyph(cache->rdp->inst, glyph);
508
 
                                }
509
 
                        }
510
 
                }
511
 
 
512
 
                xfree(cache);
513
 
        }
514
 
}