Commit | Line | Data |
---|---|---|
a09e091a JB |
1 | /* |
2 | * Copyright © 2003 Anders Carlsson | |
3 | * | |
4 | * Permission to use, copy, modify, distribute, and sell this software and its | |
5 | * documentation for any purpose is hereby granted without fee, provided that | |
6 | * the above copyright notice appear in all copies and that both that | |
7 | * copyright notice and this permission notice appear in supporting | |
8 | * documentation, and that the name of Anders Carlsson not be used in | |
9 | * advertising or publicity pertaining to distribution of the software without | |
10 | * specific, written prior permission. Anders Carlsson makes no | |
11 | * representations about the suitability of this software for any purpose. It | |
12 | * is provided "as is" without express or implied warranty. | |
13 | * | |
14 | * ANDERS CARLSSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, | |
15 | * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO | |
16 | * EVENT SHALL ANDERS CARLSSON BE LIABLE FOR ANY SPECIAL, INDIRECT OR | |
17 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, | |
18 | * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER | |
19 | * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR | |
20 | * PERFORMANCE OF THIS SOFTWARE. | |
21 | */ | |
22 | ||
23 | /** @file | |
24 | * This allocator allocates blocks of memory by maintaining a list of areas. | |
25 | * When allocating, the contiguous block of areas with the minimum eviction | |
26 | * cost is found and evicted in order to make room for the new allocation. | |
27 | */ | |
28 | ||
29 | #include "exa_priv.h" | |
30 | ||
31 | #include <limits.h> | |
32 | #include <assert.h> | |
33 | #include <stdlib.h> | |
34 | ||
35 | #if DEBUG_OFFSCREEN | |
36 | #define DBG_OFFSCREEN(a) ErrorF a | |
37 | #else | |
38 | #define DBG_OFFSCREEN(a) | |
39 | #endif | |
40 | ||
41 | #if DEBUG_OFFSCREEN | |
42 | static void | |
43 | ExaOffscreenValidate(ScreenPtr pScreen) | |
44 | { | |
45 | ExaScreenPriv(pScreen); | |
46 | ExaOffscreenArea *prev = 0, *area; | |
47 | ||
48 | assert(pExaScr->info->offScreenAreas->base_offset == | |
49 | pExaScr->info->offScreenBase); | |
50 | for (area = pExaScr->info->offScreenAreas; area; area = area->next) { | |
51 | assert(area->offset >= area->base_offset && | |
52 | area->offset < (area->base_offset + area->size)); | |
53 | if (prev) | |
54 | assert(prev->base_offset + prev->size == area->base_offset); | |
55 | prev = area; | |
56 | } | |
57 | assert(prev->base_offset + prev->size == pExaScr->info->memorySize); | |
58 | } | |
59 | #else | |
60 | #define ExaOffscreenValidate(s) | |
61 | #endif | |
62 | ||
63 | static ExaOffscreenArea * | |
64 | ExaOffscreenKickOut(ScreenPtr pScreen, ExaOffscreenArea * area) | |
65 | { | |
66 | if (area->save) | |
67 | (*area->save) (pScreen, area); | |
68 | return exaOffscreenFree(pScreen, area); | |
69 | } | |
70 | ||
71 | static void | |
72 | exaUpdateEvictionCost(ExaOffscreenArea * area, unsigned offScreenCounter) | |
73 | { | |
74 | unsigned age; | |
75 | ||
76 | if (area->state == ExaOffscreenAvail) | |
77 | return; | |
78 | ||
79 | age = offScreenCounter - area->last_use; | |
80 | ||
81 | /* This is unlikely to happen, but could result in a division by zero... */ | |
82 | if (age > (UINT_MAX / 2)) { | |
83 | age = UINT_MAX / 2; | |
84 | area->last_use = offScreenCounter - age; | |
85 | } | |
86 | ||
87 | area->eviction_cost = area->size / age; | |
88 | } | |
89 | ||
90 | static ExaOffscreenArea * | |
91 | exaFindAreaToEvict(ExaScreenPrivPtr pExaScr, int size, int align) | |
92 | { | |
93 | ExaOffscreenArea *begin, *end, *best; | |
94 | unsigned cost, best_cost; | |
95 | int avail, real_size; | |
96 | ||
97 | best_cost = UINT_MAX; | |
98 | begin = end = pExaScr->info->offScreenAreas; | |
99 | avail = 0; | |
100 | cost = 0; | |
101 | best = 0; | |
102 | ||
103 | while (end != NULL) { | |
104 | restart: | |
105 | while (begin != NULL && begin->state == ExaOffscreenLocked) | |
106 | begin = end = begin->next; | |
107 | ||
108 | if (begin == NULL) | |
109 | break; | |
110 | ||
111 | /* adjust size needed to account for alignment loss for this area */ | |
112 | real_size = size + (begin->base_offset + begin->size - size) % align; | |
113 | ||
114 | while (avail < real_size && end != NULL) { | |
115 | if (end->state == ExaOffscreenLocked) { | |
116 | /* Can't more room here, restart after this locked area */ | |
117 | avail = 0; | |
118 | cost = 0; | |
119 | begin = end; | |
120 | goto restart; | |
121 | } | |
122 | avail += end->size; | |
123 | exaUpdateEvictionCost(end, pExaScr->offScreenCounter); | |
124 | cost += end->eviction_cost; | |
125 | end = end->next; | |
126 | } | |
127 | ||
128 | /* Check the cost, update best */ | |
129 | if (avail >= real_size && cost < best_cost) { | |
130 | best = begin; | |
131 | best_cost = cost; | |
132 | } | |
133 | ||
134 | avail -= begin->size; | |
135 | cost -= begin->eviction_cost; | |
136 | begin = begin->next; | |
137 | } | |
138 | ||
139 | return best; | |
140 | } | |
141 | ||
142 | /** | |
143 | * exaOffscreenAlloc allocates offscreen memory | |
144 | * | |
145 | * @param pScreen current screen | |
146 | * @param size size in bytes of the allocation | |
147 | * @param align byte alignment requirement for the offset of the allocated area | |
148 | * @param locked whether the allocated area is locked and can't be kicked out | |
149 | * @param save callback for when the area is evicted from memory | |
150 | * @param privdata private data for the save callback. | |
151 | * | |
152 | * Allocates offscreen memory from the device associated with pScreen. size | |
153 | * and align deteremine where and how large the allocated area is, and locked | |
154 | * will mark whether it should be held in card memory. privdata may be any | |
155 | * pointer for the save callback when the area is removed. | |
156 | * | |
157 | * Note that locked areas do get evicted on VT switch unless the driver | |
158 | * requested version 2.1 or newer behavior. In that case, the save callback is | |
159 | * still called. | |
160 | */ | |
161 | ExaOffscreenArea * | |
162 | exaOffscreenAlloc(ScreenPtr pScreen, int size, int align, | |
163 | Bool locked, ExaOffscreenSaveProc save, pointer privData) | |
164 | { | |
165 | ExaOffscreenArea *area; | |
166 | ||
167 | ExaScreenPriv(pScreen); | |
168 | int real_size = 0, largest_avail = 0; | |
169 | ||
170 | #if DEBUG_OFFSCREEN | |
171 | static int number = 0; | |
172 | ||
173 | ErrorF("================= ============ allocating a new pixmap %d\n", | |
174 | ++number); | |
175 | #endif | |
176 | ||
177 | ExaOffscreenValidate(pScreen); | |
178 | if (!align) | |
179 | align = 1; | |
180 | ||
181 | if (!size) { | |
182 | DBG_OFFSCREEN(("Alloc 0x%x -> EMPTY\n", size)); | |
183 | return NULL; | |
184 | } | |
185 | ||
186 | /* throw out requests that cannot fit */ | |
187 | if (size > (pExaScr->info->memorySize - pExaScr->info->offScreenBase)) { | |
188 | DBG_OFFSCREEN(("Alloc 0x%x vs (0x%lx) -> TOBIG\n", size, | |
189 | pExaScr->info->memorySize - | |
190 | pExaScr->info->offScreenBase)); | |
191 | return NULL; | |
192 | } | |
193 | ||
194 | /* Try to find a free space that'll fit. */ | |
195 | for (area = pExaScr->info->offScreenAreas; area; area = area->next) { | |
196 | /* skip allocated areas */ | |
197 | if (area->state != ExaOffscreenAvail) | |
198 | continue; | |
199 | ||
200 | /* adjust size to match alignment requirement */ | |
201 | real_size = size + (area->base_offset + area->size - size) % align; | |
202 | ||
203 | /* does it fit? */ | |
204 | if (real_size <= area->size) | |
205 | break; | |
206 | ||
207 | if (area->size > largest_avail) | |
208 | largest_avail = area->size; | |
209 | } | |
210 | ||
211 | if (!area) { | |
212 | area = exaFindAreaToEvict(pExaScr, size, align); | |
213 | ||
214 | if (!area) { | |
215 | DBG_OFFSCREEN(("Alloc 0x%x -> NOSPACE\n", size)); | |
216 | /* Could not allocate memory */ | |
217 | ExaOffscreenValidate(pScreen); | |
218 | return NULL; | |
219 | } | |
220 | ||
221 | /* adjust size needed to account for alignment loss for this area */ | |
222 | real_size = size + (area->base_offset + area->size - size) % align; | |
223 | ||
224 | /* | |
225 | * Kick out first area if in use | |
226 | */ | |
227 | if (area->state != ExaOffscreenAvail) | |
228 | area = ExaOffscreenKickOut(pScreen, area); | |
229 | /* | |
230 | * Now get the system to merge the other needed areas together | |
231 | */ | |
232 | while (area->size < real_size) { | |
233 | assert(area->next && area->next->state == ExaOffscreenRemovable); | |
234 | (void) ExaOffscreenKickOut(pScreen, area->next); | |
235 | } | |
236 | } | |
237 | ||
238 | /* save extra space in new area */ | |
239 | if (real_size < area->size) { | |
240 | ExaOffscreenArea *new_area = malloc(sizeof(ExaOffscreenArea)); | |
241 | ||
242 | if (!new_area) | |
243 | return NULL; | |
244 | new_area->base_offset = area->base_offset; | |
245 | ||
246 | new_area->offset = new_area->base_offset; | |
247 | new_area->align = 0; | |
248 | new_area->size = area->size - real_size; | |
249 | new_area->state = ExaOffscreenAvail; | |
250 | new_area->save = NULL; | |
251 | new_area->last_use = 0; | |
252 | new_area->eviction_cost = 0; | |
253 | new_area->next = area; | |
254 | new_area->prev = area->prev; | |
255 | if (area->prev->next) | |
256 | area->prev->next = new_area; | |
257 | else | |
258 | pExaScr->info->offScreenAreas = new_area; | |
259 | area->prev = new_area; | |
260 | area->base_offset = new_area->base_offset + new_area->size; | |
261 | area->size = real_size; | |
262 | } | |
263 | else | |
264 | pExaScr->numOffscreenAvailable--; | |
265 | ||
266 | /* | |
267 | * Mark this area as in use | |
268 | */ | |
269 | if (locked) | |
270 | area->state = ExaOffscreenLocked; | |
271 | else | |
272 | area->state = ExaOffscreenRemovable; | |
273 | area->privData = privData; | |
274 | area->save = save; | |
275 | area->last_use = pExaScr->offScreenCounter++; | |
276 | area->offset = (area->base_offset + align - 1); | |
277 | area->offset -= area->offset % align; | |
278 | area->align = align; | |
279 | ||
280 | ExaOffscreenValidate(pScreen); | |
281 | ||
282 | DBG_OFFSCREEN(("Alloc 0x%x -> 0x%x (0x%x)\n", size, | |
283 | area->base_offset, area->offset)); | |
284 | return area; | |
285 | } | |
286 | ||
287 | /** | |
288 | * Ejects all offscreen areas, and uninitializes the offscreen memory manager. | |
289 | */ | |
290 | void | |
291 | ExaOffscreenSwapOut(ScreenPtr pScreen) | |
292 | { | |
293 | ExaScreenPriv(pScreen); | |
294 | ||
295 | ExaOffscreenValidate(pScreen); | |
296 | /* loop until a single free area spans the space */ | |
297 | for (;;) { | |
298 | ExaOffscreenArea *area = pExaScr->info->offScreenAreas; | |
299 | ||
300 | if (!area) | |
301 | break; | |
302 | if (area->state == ExaOffscreenAvail) { | |
303 | area = area->next; | |
304 | if (!area) | |
305 | break; | |
306 | } | |
307 | assert(area->state != ExaOffscreenAvail); | |
308 | (void) ExaOffscreenKickOut(pScreen, area); | |
309 | ExaOffscreenValidate(pScreen); | |
310 | } | |
311 | ExaOffscreenValidate(pScreen); | |
312 | ExaOffscreenFini(pScreen); | |
313 | } | |
314 | ||
315 | /** Ejects all pixmaps managed by EXA. */ | |
316 | static void | |
317 | ExaOffscreenEjectPixmaps(ScreenPtr pScreen) | |
318 | { | |
319 | ExaScreenPriv(pScreen); | |
320 | ||
321 | ExaOffscreenValidate(pScreen); | |
322 | /* loop until a single free area spans the space */ | |
323 | for (;;) { | |
324 | ExaOffscreenArea *area; | |
325 | ||
326 | for (area = pExaScr->info->offScreenAreas; area != NULL; | |
327 | area = area->next) { | |
328 | if (area->state == ExaOffscreenRemovable && | |
329 | area->save == exaPixmapSave) { | |
330 | (void) ExaOffscreenKickOut(pScreen, area); | |
331 | ExaOffscreenValidate(pScreen); | |
332 | break; | |
333 | } | |
334 | } | |
335 | if (area == NULL) | |
336 | break; | |
337 | } | |
338 | ExaOffscreenValidate(pScreen); | |
339 | } | |
340 | ||
341 | void | |
342 | ExaOffscreenSwapIn(ScreenPtr pScreen) | |
343 | { | |
344 | exaOffscreenInit(pScreen); | |
345 | } | |
346 | ||
347 | /** | |
348 | * Prepares EXA for disabling of FB access, or restoring it. | |
349 | * | |
350 | * In version 2.1, the disabling results in pixmaps being ejected, while other | |
351 | * allocations remain. With this plus the prevention of migration while | |
352 | * swappedOut is set, EXA by itself should not cause any access of the | |
353 | * framebuffer to occur while swapped out. Any remaining issues are the | |
354 | * responsibility of the driver. | |
355 | * | |
356 | * Prior to version 2.1, all allocations, including locked ones, are ejected | |
357 | * when access is disabled, and the allocator is torn down while swappedOut | |
358 | * is set. This is more drastic, and caused implementation difficulties for | |
359 | * many drivers that could otherwise handle the lack of FB access while | |
360 | * swapped out. | |
361 | */ | |
362 | void | |
363 | exaEnableDisableFBAccess(ScreenPtr pScreen, Bool enable) | |
364 | { | |
365 | ExaScreenPriv(pScreen); | |
366 | ||
367 | if (pExaScr->info->flags & EXA_HANDLES_PIXMAPS) | |
368 | return; | |
369 | ||
370 | if (!enable && pExaScr->disableFbCount++ == 0) { | |
371 | if (pExaScr->info->exa_minor < 1) | |
372 | ExaOffscreenSwapOut(pScreen); | |
373 | else | |
374 | ExaOffscreenEjectPixmaps(pScreen); | |
375 | pExaScr->swappedOut = TRUE; | |
376 | } | |
377 | ||
378 | if (enable && --pExaScr->disableFbCount == 0) { | |
379 | if (pExaScr->info->exa_minor < 1) | |
380 | ExaOffscreenSwapIn(pScreen); | |
381 | pExaScr->swappedOut = FALSE; | |
382 | } | |
383 | } | |
384 | ||
385 | /* merge the next free area into this one */ | |
386 | static void | |
387 | ExaOffscreenMerge(ExaScreenPrivPtr pExaScr, ExaOffscreenArea * area) | |
388 | { | |
389 | ExaOffscreenArea *next = area->next; | |
390 | ||
391 | /* account for space */ | |
392 | area->size += next->size; | |
393 | /* frob pointer */ | |
394 | area->next = next->next; | |
395 | if (area->next) | |
396 | area->next->prev = area; | |
397 | else | |
398 | pExaScr->info->offScreenAreas->prev = area; | |
399 | free(next); | |
400 | ||
401 | pExaScr->numOffscreenAvailable--; | |
402 | } | |
403 | ||
404 | /** | |
405 | * exaOffscreenFree frees an allocation. | |
406 | * | |
407 | * @param pScreen current screen | |
408 | * @param area offscreen area to free | |
409 | * | |
410 | * exaOffscreenFree frees an allocation created by exaOffscreenAlloc. Note that | |
411 | * the save callback of the area is not called, and it is up to the driver to | |
412 | * do any cleanup necessary as a result. | |
413 | * | |
414 | * @return pointer to the newly freed area. This behavior should not be relied | |
415 | * on. | |
416 | */ | |
417 | ExaOffscreenArea * | |
418 | exaOffscreenFree(ScreenPtr pScreen, ExaOffscreenArea * area) | |
419 | { | |
420 | ExaScreenPriv(pScreen); | |
421 | ExaOffscreenArea *next = area->next; | |
422 | ExaOffscreenArea *prev; | |
423 | ||
424 | DBG_OFFSCREEN(("Free 0x%x -> 0x%x (0x%x)\n", area->size, | |
425 | area->base_offset, area->offset)); | |
426 | ExaOffscreenValidate(pScreen); | |
427 | ||
428 | area->state = ExaOffscreenAvail; | |
429 | area->save = NULL; | |
430 | area->last_use = 0; | |
431 | area->eviction_cost = 0; | |
432 | /* | |
433 | * Find previous area | |
434 | */ | |
435 | if (area == pExaScr->info->offScreenAreas) | |
436 | prev = NULL; | |
437 | else | |
438 | prev = area->prev; | |
439 | ||
440 | pExaScr->numOffscreenAvailable++; | |
441 | ||
442 | /* link with next area if free */ | |
443 | if (next && next->state == ExaOffscreenAvail) | |
444 | ExaOffscreenMerge(pExaScr, area); | |
445 | ||
446 | /* link with prev area if free */ | |
447 | if (prev && prev->state == ExaOffscreenAvail) { | |
448 | area = prev; | |
449 | ExaOffscreenMerge(pExaScr, area); | |
450 | } | |
451 | ||
452 | ExaOffscreenValidate(pScreen); | |
453 | DBG_OFFSCREEN(("\tdone freeing\n")); | |
454 | return area; | |
455 | } | |
456 | ||
457 | void | |
458 | ExaOffscreenMarkUsed(PixmapPtr pPixmap) | |
459 | { | |
460 | ExaPixmapPriv(pPixmap); | |
461 | ExaScreenPriv(pPixmap->drawable.pScreen); | |
462 | ||
463 | if (!pExaPixmap || !pExaPixmap->area) | |
464 | return; | |
465 | ||
466 | pExaPixmap->area->last_use = pExaScr->offScreenCounter++; | |
467 | } | |
468 | ||
469 | /** | |
470 | * Defragment offscreen memory by compacting allocated areas at the end of it, | |
471 | * leaving the total amount of memory available as a single area at the | |
472 | * beginning (when there are no pinned allocations). | |
473 | */ | |
474 | _X_HIDDEN ExaOffscreenArea * | |
475 | ExaOffscreenDefragment(ScreenPtr pScreen) | |
476 | { | |
477 | ExaScreenPriv(pScreen); | |
478 | ExaOffscreenArea *area, *largest_available = NULL; | |
479 | int largest_size = 0; | |
480 | PixmapPtr pDstPix; | |
481 | ExaPixmapPrivPtr pExaDstPix; | |
482 | ||
483 | pDstPix = (*pScreen->CreatePixmap) (pScreen, 0, 0, 0, 0); | |
484 | ||
485 | if (!pDstPix) | |
486 | return NULL; | |
487 | ||
488 | pExaDstPix = ExaGetPixmapPriv(pDstPix); | |
489 | pExaDstPix->use_gpu_copy = TRUE; | |
490 | ||
491 | for (area = pExaScr->info->offScreenAreas->prev; | |
492 | area != pExaScr->info->offScreenAreas;) { | |
493 | ExaOffscreenArea *prev = area->prev; | |
494 | PixmapPtr pSrcPix; | |
495 | ExaPixmapPrivPtr pExaSrcPix; | |
496 | Bool save_use_gpu_copy; | |
497 | int save_pitch; | |
498 | ||
499 | if (area->state != ExaOffscreenAvail || | |
500 | prev->state == ExaOffscreenLocked || | |
501 | (prev->state == ExaOffscreenRemovable && | |
502 | prev->save != exaPixmapSave)) { | |
503 | area = prev; | |
504 | continue; | |
505 | } | |
506 | ||
507 | if (prev->state == ExaOffscreenAvail) { | |
508 | if (area == largest_available) { | |
509 | largest_available = prev; | |
510 | largest_size += prev->size; | |
511 | } | |
512 | area = prev; | |
513 | ExaOffscreenMerge(pExaScr, area); | |
514 | continue; | |
515 | } | |
516 | ||
517 | if (area->size > largest_size) { | |
518 | largest_available = area; | |
519 | largest_size = area->size; | |
520 | } | |
521 | ||
522 | pSrcPix = prev->privData; | |
523 | pExaSrcPix = ExaGetPixmapPriv(pSrcPix); | |
524 | ||
525 | pExaDstPix->fb_ptr = pExaScr->info->memoryBase + | |
526 | area->base_offset + area->size - prev->size + prev->base_offset - | |
527 | prev->offset; | |
528 | pExaDstPix->fb_ptr -= (unsigned long) pExaDstPix->fb_ptr % prev->align; | |
529 | ||
530 | if (pExaDstPix->fb_ptr <= pExaSrcPix->fb_ptr) { | |
531 | area = prev; | |
532 | continue; | |
533 | } | |
534 | ||
535 | if (!(pExaScr->info->flags & EXA_SUPPORTS_OFFSCREEN_OVERLAPS) && | |
536 | (pExaSrcPix->fb_ptr + prev->size) > pExaDstPix->fb_ptr) { | |
537 | area = prev; | |
538 | continue; | |
539 | } | |
540 | ||
541 | save_use_gpu_copy = pExaSrcPix->use_gpu_copy; | |
542 | save_pitch = pSrcPix->devKind; | |
543 | ||
544 | pExaSrcPix->use_gpu_copy = TRUE; | |
545 | pSrcPix->devKind = pExaSrcPix->fb_pitch; | |
546 | ||
547 | pDstPix->drawable.width = pSrcPix->drawable.width; | |
548 | pDstPix->devKind = pSrcPix->devKind; | |
549 | pDstPix->drawable.height = pSrcPix->drawable.height; | |
550 | pDstPix->drawable.depth = pSrcPix->drawable.depth; | |
551 | pDstPix->drawable.bitsPerPixel = pSrcPix->drawable.bitsPerPixel; | |
552 | ||
553 | if (!pExaScr->info->PrepareCopy(pSrcPix, pDstPix, -1, -1, GXcopy, ~0)) { | |
554 | pExaSrcPix->use_gpu_copy = save_use_gpu_copy; | |
555 | pSrcPix->devKind = save_pitch; | |
556 | area = prev; | |
557 | continue; | |
558 | } | |
559 | ||
560 | pExaScr->info->Copy(pDstPix, 0, 0, 0, 0, pDstPix->drawable.width, | |
561 | pDstPix->drawable.height); | |
562 | pExaScr->info->DoneCopy(pDstPix); | |
563 | exaMarkSync(pScreen); | |
564 | ||
565 | DBG_OFFSCREEN(("Before swap: prev=0x%08x-0x%08x-0x%08x area=0x%08x-0x%08x-0x%08x\n", prev->base_offset, prev->offset, prev->base_offset + prev->size, area->base_offset, area->offset, area->base_offset + area->size)); | |
566 | ||
567 | /* Calculate swapped area offsets and sizes */ | |
568 | area->base_offset = prev->base_offset; | |
569 | area->offset = area->base_offset; | |
570 | prev->offset += pExaDstPix->fb_ptr - pExaSrcPix->fb_ptr; | |
571 | assert(prev->offset >= pExaScr->info->offScreenBase && | |
572 | prev->offset < pExaScr->info->memorySize); | |
573 | prev->base_offset = prev->offset; | |
574 | if (area->next) | |
575 | prev->size = area->next->base_offset - prev->base_offset; | |
576 | else | |
577 | prev->size = pExaScr->info->memorySize - prev->base_offset; | |
578 | area->size = prev->base_offset - area->base_offset; | |
579 | ||
580 | DBG_OFFSCREEN(("After swap: area=0x%08x-0x%08x-0x%08x prev=0x%08x-0x%08x-0x%08x\n", area->base_offset, area->offset, area->base_offset + area->size, prev->base_offset, prev->offset, prev->base_offset + prev->size)); | |
581 | ||
582 | /* Swap areas in list */ | |
583 | if (area->next) | |
584 | area->next->prev = prev; | |
585 | else | |
586 | pExaScr->info->offScreenAreas->prev = prev; | |
587 | if (prev->prev->next) | |
588 | prev->prev->next = area; | |
589 | else | |
590 | pExaScr->info->offScreenAreas = area; | |
591 | prev->next = area->next; | |
592 | area->next = prev; | |
593 | area->prev = prev->prev; | |
594 | prev->prev = area; | |
595 | if (!area->prev->next) | |
596 | pExaScr->info->offScreenAreas = area; | |
597 | ||
598 | #if DEBUG_OFFSCREEN | |
599 | if (prev->prev == prev || prev->next == prev) | |
600 | ErrorF("Whoops, prev points to itself!\n"); | |
601 | ||
602 | if (area->prev == area || area->next == area) | |
603 | ErrorF("Whoops, area points to itself!\n"); | |
604 | #endif | |
605 | ||
606 | pExaSrcPix->fb_ptr = pExaDstPix->fb_ptr; | |
607 | pExaSrcPix->use_gpu_copy = save_use_gpu_copy; | |
608 | pSrcPix->devKind = save_pitch; | |
609 | } | |
610 | ||
611 | pDstPix->drawable.width = 0; | |
612 | pDstPix->drawable.height = 0; | |
613 | pDstPix->drawable.depth = 0; | |
614 | pDstPix->drawable.bitsPerPixel = 0; | |
615 | ||
616 | (*pScreen->DestroyPixmap) (pDstPix); | |
617 | ||
618 | if (area->state == ExaOffscreenAvail && area->size > largest_size) | |
619 | return area; | |
620 | ||
621 | return largest_available; | |
622 | } | |
623 | ||
624 | /** | |
625 | * exaOffscreenInit initializes the offscreen memory manager. | |
626 | * | |
627 | * @param pScreen current screen | |
628 | * | |
629 | * exaOffscreenInit is called by exaDriverInit to set up the memory manager for | |
630 | * the screen, if any offscreen memory is available. | |
631 | */ | |
632 | Bool | |
633 | exaOffscreenInit(ScreenPtr pScreen) | |
634 | { | |
635 | ExaScreenPriv(pScreen); | |
636 | ExaOffscreenArea *area; | |
637 | ||
638 | /* Allocate a big free area */ | |
639 | area = malloc(sizeof(ExaOffscreenArea)); | |
640 | ||
641 | if (!area) | |
642 | return FALSE; | |
643 | ||
644 | area->state = ExaOffscreenAvail; | |
645 | area->base_offset = pExaScr->info->offScreenBase; | |
646 | area->offset = area->base_offset; | |
647 | area->align = 0; | |
648 | area->size = pExaScr->info->memorySize - area->base_offset; | |
649 | area->save = NULL; | |
650 | area->next = NULL; | |
651 | area->prev = area; | |
652 | area->last_use = 0; | |
653 | area->eviction_cost = 0; | |
654 | ||
655 | /* Add it to the free areas */ | |
656 | pExaScr->info->offScreenAreas = area; | |
657 | pExaScr->offScreenCounter = 1; | |
658 | pExaScr->numOffscreenAvailable = 1; | |
659 | ||
660 | ExaOffscreenValidate(pScreen); | |
661 | ||
662 | return TRUE; | |
663 | } | |
664 | ||
665 | void | |
666 | ExaOffscreenFini(ScreenPtr pScreen) | |
667 | { | |
668 | ExaScreenPriv(pScreen); | |
669 | ExaOffscreenArea *area; | |
670 | ||
671 | /* just free all of the area records */ | |
672 | while ((area = pExaScr->info->offScreenAreas)) { | |
673 | pExaScr->info->offScreenAreas = area->next; | |
674 | free(area); | |
675 | } | |
676 | } |