~ubuntu-branches/ubuntu/intrepid/xserver-xgl/intrepid

« back to all changes in this revision

Viewing changes to hw/kdrive/src/koffscreen.c

  • Committer: Bazaar Package Importer
  • Author(s): Matthew Garrett
  • Date: 2006-02-13 14:21:43 UTC
  • Revision ID: james.westby@ubuntu.com-20060213142143-mad6z9xzem7hzxz9
Tags: upstream-7.0.0
ImportĀ upstreamĀ versionĀ 7.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * $Id: koffscreen.c,v 1.19 2005/12/27 08:29:48 ajax Exp $
 
3
 *
 
4
 * Copyright Ā© 2003 Anders Carlsson
 
5
 *
 
6
 * Permission to use, copy, modify, distribute, and sell this software and its
 
7
 * documentation for any purpose is hereby granted without fee, provided that
 
8
 * the above copyright notice appear in all copies and that both that
 
9
 * copyright notice and this permission notice appear in supporting
 
10
 * documentation, and that the name of Anders Carlsson not be used in
 
11
 * advertising or publicity pertaining to distribution of the software without
 
12
 * specific, written prior permission.  Anders Carlsson makes no
 
13
 * representations about the suitability of this software for any purpose.  It
 
14
 * is provided "as is" without express or implied warranty.
 
15
 *
 
16
 * ANDERS CARLSSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 
17
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
 
18
 * EVENT SHALL ANDERS CARLSSON BE LIABLE FOR ANY SPECIAL, INDIRECT OR
 
19
 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
 
20
 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
 
21
 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 
22
 * PERFORMANCE OF THIS SOFTWARE.
 
23
 */
 
24
 
 
25
#ifdef HAVE_CONFIG_H
 
26
#include <kdrive-config.h>
 
27
#endif
 
28
#include "kdrive.h"
 
29
#include "kaa.h"
 
30
 
 
31
#define DEBUG_OFFSCREEN 0
 
32
#if DEBUG_OFFSCREEN
 
33
#define DBG_OFFSCREEN(a) ErrorF a
 
34
#else
 
35
#define DBG_OFFSCREEN(a)
 
36
#endif
 
37
 
 
38
#if DEBUG_OFFSCREEN
 
39
static void
 
40
KdOffscreenValidate (ScreenPtr pScreen)
 
41
{
 
42
    KdScreenPriv (pScreen);
 
43
    KdOffscreenArea *prev = 0, *area;
 
44
 
 
45
    assert (pScreenPriv->screen->off_screen_areas->area.offset == 0);
 
46
    for (area = pScreenPriv->off_screen_areas; area; area = area->next)
 
47
    {
 
48
        if (prev)
 
49
            assert (prev->offset + prev->size == area->offset);
 
50
            
 
51
        prev = area;
 
52
    }
 
53
    assert (prev->offset + prev->size == pScreenPriv->screen->memory_size);
 
54
}
 
55
#else
 
56
#define KdOffscreenValidate(s)
 
57
#endif
 
58
 
 
59
static KdOffscreenArea *
 
60
KdOffscreenKickOut (ScreenPtr pScreen, KdOffscreenArea *area)
 
61
{
 
62
    if (area->save)
 
63
        (*area->save) (pScreen, area);
 
64
    return KdOffscreenFree (pScreen, area);
 
65
}
 
66
 
 
67
KdOffscreenArea *
 
68
KdOffscreenAlloc (ScreenPtr pScreen, int size, int align,
 
69
                  Bool locked,
 
70
                  KdOffscreenSaveProc save,
 
71
                  pointer privData)
 
72
{
 
73
    KdOffscreenArea *area, *begin, *best;
 
74
    KdScreenPriv (pScreen);
 
75
    int tmp, real_size = 0, best_score;
 
76
 
 
77
    KdOffscreenValidate (pScreen);
 
78
    if (!align)
 
79
        align = 1;
 
80
 
 
81
    if (!size)
 
82
    {
 
83
        DBG_OFFSCREEN (("Alloc 0x%x -> EMPTY\n", size));
 
84
        return NULL;
 
85
    }
 
86
 
 
87
    /* throw out requests that cannot fit */
 
88
    if (size > (pScreenPriv->screen->memory_size - pScreenPriv->screen->off_screen_base))
 
89
    {
 
90
        DBG_OFFSCREEN (("Alloc 0x%x -> TOBIG\n", size));
 
91
        return NULL;
 
92
    }
 
93
    
 
94
    /* Try to find a free space that'll fit. */
 
95
    for (area = pScreenPriv->off_screen_areas; area; area = area->next)
 
96
    {
 
97
        /* skip allocated areas */
 
98
        if (area->state != KdOffscreenAvail)
 
99
            continue;
 
100
 
 
101
        /* adjust size to match alignment requirement */
 
102
        real_size = size;
 
103
        tmp = area->offset % align;
 
104
        if (tmp)
 
105
            real_size += (align - tmp);
 
106
        
 
107
        /* does it fit? */
 
108
        if (real_size <= area->size)
 
109
            break;
 
110
    }
 
111
    
 
112
    if (!area)
 
113
    {
 
114
        /* 
 
115
         * Kick out existing users to make space.
 
116
         *
 
117
         * First, locate a region which can hold the desired object.
 
118
         */
 
119
        
 
120
        /* prev points at the first object to boot */
 
121
        best = NULL;
 
122
        best_score = MAXINT;
 
123
        for (begin = pScreenPriv->off_screen_areas; begin != NULL;
 
124
             begin = begin->next)
 
125
        {
 
126
            int avail, score;
 
127
            KdOffscreenArea *scan;
 
128
 
 
129
            if (begin->state == KdOffscreenLocked)
 
130
                continue;
 
131
 
 
132
            /* adjust size to match alignment requirement */
 
133
            real_size = size;
 
134
            tmp = begin->offset % align;
 
135
            if (tmp)
 
136
                real_size += (align - tmp);
 
137
            
 
138
            avail = 0;
 
139
            score = 0;
 
140
            /* now see if we can make room here, and how "costly" it'll be. */
 
141
            for (scan = begin; scan != NULL; scan = scan->next)
 
142
            {
 
143
                if (scan->state == KdOffscreenLocked) {
 
144
                    /* Can't make room here, start after this locked area. */
 
145
                    begin = scan->next;
 
146
                    break;
 
147
                }
 
148
                /* Score should only be non-zero for KdOffscreenRemovable */
 
149
                score += scan->score;
 
150
                avail += scan->size;
 
151
                if (avail >= real_size)
 
152
                    break;
 
153
            }
 
154
            /* Is it the best option we've found so far? */
 
155
            if (avail >= real_size && score < best_score) {
 
156
                best = begin;
 
157
                best_score = score;
 
158
            }
 
159
        }
 
160
        area = best;
 
161
        if (!area)
 
162
        {
 
163
            DBG_OFFSCREEN (("Alloc 0x%x -> NOSPACE\n", size));
 
164
            /* Could not allocate memory */
 
165
            KdOffscreenValidate (pScreen);
 
166
            return NULL;
 
167
        }
 
168
 
 
169
        /* adjust size to match alignment requirement */
 
170
        real_size = size;
 
171
        tmp = begin->offset % align;
 
172
        if (tmp)
 
173
            real_size += (align - tmp);
 
174
 
 
175
        /*
 
176
         * Kick out first area if in use
 
177
         */
 
178
        if (area->state != KdOffscreenAvail)
 
179
            area = KdOffscreenKickOut (pScreen, area);
 
180
        /*
 
181
         * Now get the system to merge the other needed areas together
 
182
         */
 
183
        while (area->size < real_size)
 
184
        {
 
185
            assert (area->next && area->next->state == KdOffscreenRemovable);
 
186
            (void) KdOffscreenKickOut (pScreen, area->next);
 
187
        }
 
188
    }
 
189
    
 
190
    /* save extra space in new area */
 
191
    if (real_size < area->size)
 
192
    {
 
193
        KdOffscreenArea   *new_area = xalloc (sizeof (KdOffscreenArea));
 
194
        if (!new_area)
 
195
            return NULL;
 
196
        new_area->offset = area->offset + real_size;
 
197
        new_area->size = area->size - real_size;
 
198
        new_area->state = KdOffscreenAvail;
 
199
        new_area->save = 0;
 
200
        new_area->score = 0;
 
201
        new_area->next = area->next;
 
202
        area->next = new_area;
 
203
        area->size = real_size;
 
204
    }
 
205
    /*
 
206
     * Mark this area as in use
 
207
     */
 
208
    if (locked)
 
209
        area->state = KdOffscreenLocked;
 
210
    else
 
211
        area->state = KdOffscreenRemovable;
 
212
    area->privData = privData;
 
213
    area->save = save;
 
214
    area->score = 0;
 
215
 
 
216
    area->save_offset = area->offset;
 
217
    {
 
218
        int tmp = area->offset % align;
 
219
        if (tmp)
 
220
            area->offset += (align - tmp);
 
221
    }
 
222
 
 
223
    KdOffscreenValidate (pScreen);
 
224
    
 
225
    DBG_OFFSCREEN (("Alloc 0x%x -> 0x%x\n", size, area->offset));
 
226
    return area;
 
227
}
 
228
 
 
229
void
 
230
KdOffscreenSwapOut (ScreenPtr pScreen)
 
231
{
 
232
    KdScreenPriv (pScreen);
 
233
 
 
234
    KdOffscreenValidate (pScreen);
 
235
    /* loop until a single free area spans the space */
 
236
    for (;;)
 
237
    {
 
238
        KdOffscreenArea *area = pScreenPriv->off_screen_areas;
 
239
        
 
240
        if (!area)
 
241
            break;
 
242
        if (area->state == KdOffscreenAvail)
 
243
        {
 
244
            area = area->next;
 
245
            if (!area)
 
246
                break;
 
247
        }
 
248
        assert (area->state != KdOffscreenAvail);
 
249
        (void) KdOffscreenKickOut (pScreen, area);
 
250
        KdOffscreenValidate (pScreen);
 
251
    }    
 
252
    KdOffscreenValidate (pScreen);
 
253
    KdOffscreenFini (pScreen);
 
254
}
 
255
 
 
256
void
 
257
KdOffscreenSwapIn (ScreenPtr pScreen)
 
258
{
 
259
    KdOffscreenInit (pScreen);
 
260
}
 
261
 
 
262
/* merge the next free area into this one */
 
263
static void
 
264
KdOffscreenMerge (KdOffscreenArea *area)
 
265
{
 
266
    KdOffscreenArea     *next = area->next;
 
267
 
 
268
    /* account for space */
 
269
    area->size += next->size;
 
270
    /* frob pointer */
 
271
    area->next = next->next;
 
272
    xfree (next);
 
273
}
 
274
 
 
275
KdOffscreenArea *
 
276
KdOffscreenFree (ScreenPtr pScreen, KdOffscreenArea *area)
 
277
{
 
278
    KdScreenPriv(pScreen);
 
279
    KdOffscreenArea     *next = area->next;
 
280
    KdOffscreenArea     *prev;
 
281
    
 
282
    DBG_OFFSCREEN (("Free 0x%x -> 0x%x\n", area->size, area->offset));
 
283
    KdOffscreenValidate (pScreen);
 
284
 
 
285
    area->state = KdOffscreenAvail;
 
286
    area->save = 0;
 
287
    area->offset = area->save_offset;
 
288
    area->score = 0;
 
289
 
 
290
    /*
 
291
     * Find previous area
 
292
     */
 
293
    if (area == pScreenPriv->off_screen_areas)
 
294
        prev = 0;
 
295
    else
 
296
        for (prev = pScreenPriv->off_screen_areas; prev; prev = prev->next)
 
297
            if (prev->next == area)
 
298
                break;
 
299
    
 
300
    /* link with next area if free */
 
301
    if (next && next->state == KdOffscreenAvail)
 
302
        KdOffscreenMerge (area);
 
303
    
 
304
    /* link with prev area if free */
 
305
    if (prev && prev->state == KdOffscreenAvail)
 
306
    {
 
307
        area = prev;
 
308
        KdOffscreenMerge (area);
 
309
    }
 
310
 
 
311
    KdOffscreenValidate (pScreen);
 
312
    return area;
 
313
}
 
314
 
 
315
void
 
316
KdOffscreenMarkUsed (PixmapPtr pPixmap)
 
317
{
 
318
    KaaPixmapPriv (pPixmap);
 
319
    KdScreenPriv (pPixmap->drawable.pScreen);
 
320
    static int iter = 0;
 
321
 
 
322
    if (!pKaaPixmap->area)
 
323
        return;
 
324
 
 
325
    /* The numbers here are arbitrary.  We may want to tune these. */
 
326
    pKaaPixmap->area->score += 100;
 
327
    if (++iter == 10) {
 
328
        KdOffscreenArea *area;
 
329
        for (area = pScreenPriv->off_screen_areas; area != NULL;
 
330
             area = area->next)
 
331
        {
 
332
            if (area->state == KdOffscreenRemovable)
 
333
                area->score = (area->score * 7) / 8;
 
334
        }
 
335
    }
 
336
}
 
337
 
 
338
Bool
 
339
KdOffscreenInit (ScreenPtr pScreen)
 
340
{
 
341
    KdScreenPriv (pScreen);
 
342
    KdOffscreenArea *area;
 
343
 
 
344
    /* Allocate a big free area */
 
345
    area = xalloc (sizeof (KdOffscreenArea));
 
346
 
 
347
    if (!area)
 
348
        return FALSE;
 
349
 
 
350
    area->state = KdOffscreenAvail;
 
351
    area->offset = pScreenPriv->screen->off_screen_base;
 
352
    area->size = pScreenPriv->screen->memory_size - area->offset;
 
353
    area->save = 0;
 
354
    area->next = NULL;
 
355
    area->score = 0;
 
356
    
 
357
    /* Add it to the free areas */
 
358
    pScreenPriv->off_screen_areas = area;
 
359
    
 
360
    KdOffscreenValidate (pScreen);
 
361
 
 
362
    return TRUE;
 
363
}
 
364
 
 
365
void
 
366
KdOffscreenFini (ScreenPtr pScreen)
 
367
{
 
368
    KdScreenPriv (pScreen);
 
369
    KdOffscreenArea *area;
 
370
    
 
371
    /* just free all of the area records */
 
372
    while ((area = pScreenPriv->off_screen_areas))
 
373
    {
 
374
        pScreenPriv->off_screen_areas = area->next;
 
375
        xfree (area);
 
376
    }
 
377
}