2
* $Id: koffscreen.c,v 1.19 2005/12/27 08:29:48 ajax Exp $
4
* Copyright Ā© 2003 Anders Carlsson
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.
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.
26
#include <kdrive-config.h>
31
#define DEBUG_OFFSCREEN 0
33
#define DBG_OFFSCREEN(a) ErrorF a
35
#define DBG_OFFSCREEN(a)
40
KdOffscreenValidate (ScreenPtr pScreen)
42
KdScreenPriv (pScreen);
43
KdOffscreenArea *prev = 0, *area;
45
assert (pScreenPriv->screen->off_screen_areas->area.offset == 0);
46
for (area = pScreenPriv->off_screen_areas; area; area = area->next)
49
assert (prev->offset + prev->size == area->offset);
53
assert (prev->offset + prev->size == pScreenPriv->screen->memory_size);
56
#define KdOffscreenValidate(s)
59
static KdOffscreenArea *
60
KdOffscreenKickOut (ScreenPtr pScreen, KdOffscreenArea *area)
63
(*area->save) (pScreen, area);
64
return KdOffscreenFree (pScreen, area);
68
KdOffscreenAlloc (ScreenPtr pScreen, int size, int align,
70
KdOffscreenSaveProc save,
73
KdOffscreenArea *area, *begin, *best;
74
KdScreenPriv (pScreen);
75
int tmp, real_size = 0, best_score;
77
KdOffscreenValidate (pScreen);
83
DBG_OFFSCREEN (("Alloc 0x%x -> EMPTY\n", size));
87
/* throw out requests that cannot fit */
88
if (size > (pScreenPriv->screen->memory_size - pScreenPriv->screen->off_screen_base))
90
DBG_OFFSCREEN (("Alloc 0x%x -> TOBIG\n", size));
94
/* Try to find a free space that'll fit. */
95
for (area = pScreenPriv->off_screen_areas; area; area = area->next)
97
/* skip allocated areas */
98
if (area->state != KdOffscreenAvail)
101
/* adjust size to match alignment requirement */
103
tmp = area->offset % align;
105
real_size += (align - tmp);
108
if (real_size <= area->size)
115
* Kick out existing users to make space.
117
* First, locate a region which can hold the desired object.
120
/* prev points at the first object to boot */
123
for (begin = pScreenPriv->off_screen_areas; begin != NULL;
127
KdOffscreenArea *scan;
129
if (begin->state == KdOffscreenLocked)
132
/* adjust size to match alignment requirement */
134
tmp = begin->offset % align;
136
real_size += (align - tmp);
140
/* now see if we can make room here, and how "costly" it'll be. */
141
for (scan = begin; scan != NULL; scan = scan->next)
143
if (scan->state == KdOffscreenLocked) {
144
/* Can't make room here, start after this locked area. */
148
/* Score should only be non-zero for KdOffscreenRemovable */
149
score += scan->score;
151
if (avail >= real_size)
154
/* Is it the best option we've found so far? */
155
if (avail >= real_size && score < best_score) {
163
DBG_OFFSCREEN (("Alloc 0x%x -> NOSPACE\n", size));
164
/* Could not allocate memory */
165
KdOffscreenValidate (pScreen);
169
/* adjust size to match alignment requirement */
171
tmp = begin->offset % align;
173
real_size += (align - tmp);
176
* Kick out first area if in use
178
if (area->state != KdOffscreenAvail)
179
area = KdOffscreenKickOut (pScreen, area);
181
* Now get the system to merge the other needed areas together
183
while (area->size < real_size)
185
assert (area->next && area->next->state == KdOffscreenRemovable);
186
(void) KdOffscreenKickOut (pScreen, area->next);
190
/* save extra space in new area */
191
if (real_size < area->size)
193
KdOffscreenArea *new_area = xalloc (sizeof (KdOffscreenArea));
196
new_area->offset = area->offset + real_size;
197
new_area->size = area->size - real_size;
198
new_area->state = KdOffscreenAvail;
201
new_area->next = area->next;
202
area->next = new_area;
203
area->size = real_size;
206
* Mark this area as in use
209
area->state = KdOffscreenLocked;
211
area->state = KdOffscreenRemovable;
212
area->privData = privData;
216
area->save_offset = area->offset;
218
int tmp = area->offset % align;
220
area->offset += (align - tmp);
223
KdOffscreenValidate (pScreen);
225
DBG_OFFSCREEN (("Alloc 0x%x -> 0x%x\n", size, area->offset));
230
KdOffscreenSwapOut (ScreenPtr pScreen)
232
KdScreenPriv (pScreen);
234
KdOffscreenValidate (pScreen);
235
/* loop until a single free area spans the space */
238
KdOffscreenArea *area = pScreenPriv->off_screen_areas;
242
if (area->state == KdOffscreenAvail)
248
assert (area->state != KdOffscreenAvail);
249
(void) KdOffscreenKickOut (pScreen, area);
250
KdOffscreenValidate (pScreen);
252
KdOffscreenValidate (pScreen);
253
KdOffscreenFini (pScreen);
257
KdOffscreenSwapIn (ScreenPtr pScreen)
259
KdOffscreenInit (pScreen);
262
/* merge the next free area into this one */
264
KdOffscreenMerge (KdOffscreenArea *area)
266
KdOffscreenArea *next = area->next;
268
/* account for space */
269
area->size += next->size;
271
area->next = next->next;
276
KdOffscreenFree (ScreenPtr pScreen, KdOffscreenArea *area)
278
KdScreenPriv(pScreen);
279
KdOffscreenArea *next = area->next;
280
KdOffscreenArea *prev;
282
DBG_OFFSCREEN (("Free 0x%x -> 0x%x\n", area->size, area->offset));
283
KdOffscreenValidate (pScreen);
285
area->state = KdOffscreenAvail;
287
area->offset = area->save_offset;
293
if (area == pScreenPriv->off_screen_areas)
296
for (prev = pScreenPriv->off_screen_areas; prev; prev = prev->next)
297
if (prev->next == area)
300
/* link with next area if free */
301
if (next && next->state == KdOffscreenAvail)
302
KdOffscreenMerge (area);
304
/* link with prev area if free */
305
if (prev && prev->state == KdOffscreenAvail)
308
KdOffscreenMerge (area);
311
KdOffscreenValidate (pScreen);
316
KdOffscreenMarkUsed (PixmapPtr pPixmap)
318
KaaPixmapPriv (pPixmap);
319
KdScreenPriv (pPixmap->drawable.pScreen);
322
if (!pKaaPixmap->area)
325
/* The numbers here are arbitrary. We may want to tune these. */
326
pKaaPixmap->area->score += 100;
328
KdOffscreenArea *area;
329
for (area = pScreenPriv->off_screen_areas; area != NULL;
332
if (area->state == KdOffscreenRemovable)
333
area->score = (area->score * 7) / 8;
339
KdOffscreenInit (ScreenPtr pScreen)
341
KdScreenPriv (pScreen);
342
KdOffscreenArea *area;
344
/* Allocate a big free area */
345
area = xalloc (sizeof (KdOffscreenArea));
350
area->state = KdOffscreenAvail;
351
area->offset = pScreenPriv->screen->off_screen_base;
352
area->size = pScreenPriv->screen->memory_size - area->offset;
357
/* Add it to the free areas */
358
pScreenPriv->off_screen_areas = area;
360
KdOffscreenValidate (pScreen);
366
KdOffscreenFini (ScreenPtr pScreen)
368
KdScreenPriv (pScreen);
369
KdOffscreenArea *area;
371
/* just free all of the area records */
372
while ((area = pScreenPriv->off_screen_areas))
374
pScreenPriv->off_screen_areas = area->next;