1/* 2 * Copyright 2010 Red Hat, Inc. 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * on the rights to use, copy, modify, merge, publish, distribute, sub 8 * license, and/or sell copies of the Software, and to permit persons to whom 9 * the Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 */ 22 23/* The life cycle of surfaces 24 * 25 * free => live => dead => destroyed => free 26 * 27 * A 'free' surface is one that is not allocated on the device. These 28 * are stored on the 'free_surfaces' list. 29 * 30 * A 'live' surface is one that the X server is using for something. It 31 * has an associated pixmap. It is allocated in the device. These are stored on 32 * the "live_surfaces" list. 33 * 34 * A 'dead' surface is one that the X server is no using any more, but 35 * is still allocated in the device. These surfaces may be stored in the 36 * cache, from where they can be resurrected. The cache holds a ref on the 37 * surfaces. 38 * 39 * A 'destroyed' surface is one whose ref count has reached 0. It is no 40 * longer being referenced by either the server or the device or the cache. 41 * When a surface enters this state, the associated pixman images are freed, and 42 * a destroy command is sent. This will eventually trigger a 'recycle' call, 43 * which puts the surface into the 'free' state. 44 * 45 */ 46#ifdef HAVE_CONFIG_H 47#include "config.h" 48#endif 49 50#include "qxl.h" 51#include "qxl_surface.h" 52#ifdef DEBUG_SURFACE_LIFECYCLE 53#include <stdio.h> 54 55static FILE* surface_log; 56#endif 57 58typedef struct evacuated_surface_t evacuated_surface_t; 59 60struct evacuated_surface_t 61{ 62 pixman_image_t *image; 63 PixmapPtr pixmap; 64 int bpp; 65 66 evacuated_surface_t *prev; 67 evacuated_surface_t *next; 68}; 69 70#define N_CACHED_SURFACES 64 71 72/* 73 * Surface cache 74 */ 75struct surface_cache_t 76{ 77 qxl_screen_t *qxl; 78 79 /* Array of surfaces (not a linked list). 80 * All surfaces, excluding the primary one, indexed by surface id. 81 */ 82 qxl_surface_t *all_surfaces; 83 84 /* All surfaces that the driver is currently using (linked through next/prev) */ 85 qxl_surface_t *live_surfaces; 86 87 /* All surfaces that need to be allocated (linked through next, but not prev) */ 88 qxl_surface_t *free_surfaces; 89 90 /* Surfaces that are already allocated, but not in used by the driver, 91 * linked through next 92 */ 93 qxl_surface_t *cached_surfaces[N_CACHED_SURFACES]; 94}; 95 96#ifdef DEBUG_SURFACE_LIFECYCLE 97static void debug_surface_open(void) 98{ 99 if (surface_log) 100 return; 101 surface_log = fopen("/tmp/xf86-video-qxl.surface.log", "w+"); 102 if (!surface_log) 103 { 104 fprintf(stderr, "error creating surface log file (DEBUG_SURFACE_LIFECYCLE)\n"); 105 exit(-1); 106 } 107} 108 109static int surface_count(qxl_surface_t *surface) 110{ 111 int i; 112 113 for (i = 0; surface ;++i, surface = surface->next); 114 return i; 115} 116 117static void debug_surface_log(surface_cache_t *cache) 118{ 119 int live_n, free_n; 120 121 debug_surface_open(); 122 live_n = surface_count(cache->live_surfaces); 123 free_n = surface_count(cache->free_surfaces); 124 fprintf(surface_log, "live,free,sum = %d, %d, %d\n", live_n, free_n, 125 live_n + free_n); 126 fflush(surface_log); 127} 128 129#else 130#define debug_surface_log(cache) 131#endif 132 133 134static Bool 135surface_cache_init (surface_cache_t *cache, qxl_screen_t *qxl) 136{ 137 int n_surfaces = qxl->rom->n_surfaces; 138 int i; 139 140 if (!cache->all_surfaces) 141 { 142 /* all_surfaces is not freed when evacuating, since surfaces are still 143 * tied to pixmaps that may be destroyed after evacuation before 144 * recreation */ 145 cache->all_surfaces = calloc (n_surfaces, sizeof (qxl_surface_t)); 146 if (!cache->all_surfaces) 147 return FALSE; 148 } 149 150 memset (cache->all_surfaces, 0, n_surfaces * sizeof (qxl_surface_t)); 151 memset (cache->cached_surfaces, 0, N_CACHED_SURFACES * sizeof (qxl_surface_t *)); 152 153 cache->free_surfaces = NULL; 154 cache->live_surfaces = NULL; 155 156 for (i = 0; i < n_surfaces; ++i) 157 { 158 cache->all_surfaces[i].id = i; 159 cache->all_surfaces[i].cache = cache; 160 cache->all_surfaces[i].qxl = qxl; 161 cache->all_surfaces[i].dev_image = NULL; 162 cache->all_surfaces[i].host_image = NULL; 163 cache->all_surfaces[i].evacuated = NULL; 164 165 REGION_INIT ( 166 NULL, &(cache->all_surfaces[i].access_region), (BoxPtr)NULL, 0); 167 cache->all_surfaces[i].access_type = UXA_ACCESS_RO; 168 169 if (i) /* surface 0 is the primary surface */ 170 { 171 cache->all_surfaces[i].next = cache->free_surfaces; 172 cache->free_surfaces = &(cache->all_surfaces[i]); 173 cache->all_surfaces[i].in_use = FALSE; 174 } 175 } 176 177 return TRUE; 178} 179 180surface_cache_t * 181qxl_surface_cache_create (qxl_screen_t *qxl) 182{ 183 surface_cache_t *cache = malloc (sizeof *cache); 184 185 if (!cache) 186 return NULL; 187 188 memset(cache, 0, sizeof(*cache)); 189 cache->qxl = qxl; 190 if (!surface_cache_init (cache, qxl)) 191 { 192 free (cache); 193 return NULL; 194 } 195 196 return cache; 197} 198 199void 200qxl_surface_cache_sanity_check (surface_cache_t *qxl) 201{ 202#if 0 203 qxl_surface_t *s; 204 205 for (s = qxl->live_surfaces; s != NULL; s = s->next) 206 { 207 PixmapPtr pixmap = s->pixmap; 208 209 if (! (get_surface (pixmap) == s) ) 210 { 211 ErrorF ("Surface %p has pixmap %p, but pixmap %p has surface %p\n", 212 s, pixmap, pixmap, get_surface (pixmap)); 213 214 assert (0); 215 } 216 } 217#endif 218} 219 220static void 221print_cache_info (surface_cache_t *cache) 222{ 223 int i; 224 int n_surfaces = 0; 225 226 ErrorF ("Cache contents: "); 227 for (i = 0; i < N_CACHED_SURFACES; ++i) 228 { 229 if (cache->cached_surfaces[i]) 230 { 231 ErrorF ("%4d ", cache->cached_surfaces[i]->id); 232 n_surfaces++; 233 } 234 else 235 ErrorF ("null "); 236 } 237 238 ErrorF (" total: %d\n", n_surfaces); 239} 240 241static qxl_surface_t * 242surface_get_from_cache (surface_cache_t *cache, int width, int height, int bpp) 243{ 244 int i; 245 246 for (i = 0; i < N_CACHED_SURFACES; ++i) 247 { 248 qxl_surface_t *s = cache->cached_surfaces[i]; 249 250 if (s && bpp == s->bpp) 251 { 252 int w = pixman_image_get_width (s->host_image); 253 int h = pixman_image_get_height (s->host_image); 254 255 if (width <= w && width * 4 > w && height <= h && height * 4 > h) 256 { 257 cache->cached_surfaces[i] = NULL; 258 259 return s; 260 } 261 } 262 } 263 264 return NULL; 265} 266 267static int n_live; 268 269void 270qxl_surface_recycle (surface_cache_t *cache, uint32_t id) 271{ 272 qxl_surface_t *surface = cache->all_surfaces + id; 273 274 n_live--; 275 if (surface->bo) 276 cache->qxl->bo_funcs->bo_decref (cache->qxl, surface->bo); 277 surface->bo = NULL; 278 surface->next = cache->free_surfaces; 279 cache->free_surfaces = surface; 280} 281 282/* 283 * mode is used for the whole virtual screen, not for a specific head. 284 * For a single head where virtual size is equal to the head size, they are 285 * equal. For multiple heads this mode will not match any existing heads and 286 * will be the containing virtual size. 287 */ 288qxl_surface_t * 289qxl_surface_cache_create_primary (qxl_screen_t *qxl, 290 struct QXLMode *mode) 291{ 292 pixman_format_code_t format; 293 uint8_t *dev_addr; 294 pixman_image_t *dev_image, *host_image; 295 qxl_surface_t *surface; 296 surface_cache_t *cache = qxl->surface_cache; 297 struct qxl_bo *bo; 298 299 if (mode->bits == 16) 300 { 301 format = PIXMAN_x1r5g5b5; 302 } 303 else if (mode->bits == 32) 304 { 305 format = PIXMAN_x8r8g8b8; 306 } 307 else 308 { 309 xf86DrvMsg (qxl->pScrn->scrnIndex, X_ERROR, 310 "Unknown bit depth %d\n", mode->bits); 311 return NULL; 312 } 313 314 bo = qxl->bo_funcs->create_primary(qxl, mode->x_res, mode->y_res, mode->stride, mode->bits); 315 316 dev_addr = qxl->bo_funcs->bo_map(bo); 317 dev_image = pixman_image_create_bits (format, mode->x_res, mode->y_res, 318 (uint32_t *)dev_addr, (qxl->kms_enabled ? mode->stride : -mode->stride)); 319 320 host_image = pixman_image_create_bits (format, 321 qxl->virtual_x, qxl->virtual_y, 322 NULL, mode->stride); 323#if 0 324 xf86DrvMsg(cache->qxl->pScrn->scrnIndex, X_ERROR, 325 "testing dev_image memory (%d x %d)\n", 326 mode->x_res, mode->y_res); 327 memset(qxl->ram, 0, mode->stride * mode->y_res); 328 xf86DrvMsg(cache->qxl->pScrn->scrnIndex, X_ERROR, 329 "testing host_image memory\n"); 330 memset(qxl->fb, 0, mode->stride * mode->y_res); 331#endif 332 333 surface = malloc (sizeof *surface); 334 surface->id = 0; 335 surface->dev_image = dev_image; 336 surface->host_image = host_image; 337 surface->cache = cache; 338 surface->qxl = qxl; 339 surface->bpp = mode->bits; 340 surface->next = NULL; 341 surface->prev = NULL; 342 surface->evacuated = NULL; 343 surface->bo = bo; 344 surface->image_bo = NULL; 345 346 REGION_INIT (NULL, &(surface->access_region), (BoxPtr)NULL, 0); 347 surface->access_type = UXA_ACCESS_RO; 348 349 return surface; 350} 351 352void * 353qxl_surface_get_host_bits(qxl_surface_t *surface) 354{ 355 if (!surface) 356 return NULL; 357 return (void *) pixman_image_get_data(surface->host_image); 358} 359 360 361 362 363static struct qxl_bo * 364make_surface_cmd (surface_cache_t *cache, uint32_t id, QXLSurfaceCmdType type) 365{ 366 struct qxl_bo *cmd_bo; 367 struct QXLSurfaceCmd *cmd; 368 qxl_screen_t *qxl = cache->qxl; 369 370 cmd_bo = qxl->bo_funcs->cmd_alloc (qxl, sizeof *cmd, "surface command"); 371 cmd = qxl->bo_funcs->bo_map(cmd_bo); 372 373 cmd->release_info.id = pointer_to_u64 (cmd_bo) | 2; 374 cmd->type = type; 375 cmd->flags = 0; 376 cmd->surface_id = id; 377 378 qxl->bo_funcs->bo_unmap(cmd_bo); 379 return cmd_bo; 380} 381 382static void 383push_surface_cmd (surface_cache_t *cache, struct qxl_bo *cmd_bo) 384{ 385 qxl_screen_t *qxl = cache->qxl; 386 387 qxl->bo_funcs->write_command (qxl, QXL_CMD_SURFACE, cmd_bo); 388} 389 390 391static qxl_surface_t * 392surface_get_from_free_list (surface_cache_t *cache) 393{ 394 qxl_surface_t *result = NULL; 395 396 if (cache->free_surfaces) 397 { 398 qxl_surface_t *s; 399 400 result = cache->free_surfaces; 401 cache->free_surfaces = cache->free_surfaces->next; 402 403 result->next = NULL; 404 result->in_use = TRUE; 405 result->ref_count = 1; 406 result->pixmap = NULL; 407 408 for (s = cache->free_surfaces; s; s = s->next) 409 { 410 if (s->id == result->id) 411 ErrorF ("huh: %d to be returned, but %d is in list\n", 412 s->id, result->id); 413 414 assert (s->id != result->id); 415 } 416 } 417 418 return result; 419} 420 421static int 422align (int x) 423{ 424 return x; 425} 426 427static qxl_surface_t * 428surface_send_create (surface_cache_t *cache, 429 int width, 430 int height, 431 int bpp) 432{ 433 SpiceSurfaceFmt format; 434 pixman_format_code_t pformat; 435 struct QXLSurfaceCmd *cmd; 436 int stride; 437 uint32_t *dev_addr; 438 int n_attempts = 0; 439 qxl_screen_t *qxl = cache->qxl; 440 qxl_surface_t *surface; 441 struct qxl_bo *bo, *cmd_bo; 442 void *dev_ptr; 443 qxl_get_formats (bpp, &format, &pformat); 444 445 width = align (width); 446 height = align (height); 447 448 stride = width * PIXMAN_FORMAT_BPP (pformat) / 8; 449 stride = (stride + 3) & ~3; 450 451 /* the final + stride is to work around a bug where the device apparently 452 * scribbles after the end of the image 453 */ 454 qxl_garbage_collect (qxl); 455retry2: 456 bo = qxl_ums_surf_mem_alloc(qxl, stride * height + stride); 457 458 if (!bo) 459 { 460 ErrorF ("- %dth attempt\n", n_attempts++); 461 462 if (qxl_garbage_collect (qxl)) 463 goto retry2; 464 465 ErrorF ("- OOM at %d %d %d (= %d bytes)\n", width, height, bpp, width * height * (bpp / 8)); 466 print_cache_info (cache); 467 468 if (qxl_handle_oom (qxl)) 469 { 470 while (qxl_garbage_collect (qxl)) 471 ; 472 goto retry2; 473 } 474 475 ErrorF ("Out of video memory: Could not allocate %d bytes\n", 476 stride * height + stride); 477 478 return NULL; 479 } 480 481retry: 482 surface = surface_get_from_free_list (cache); 483 if (!surface) 484 { 485 if (!qxl_handle_oom (cache->qxl)) 486 { 487 ErrorF (" Out of surfaces\n"); 488 qxl->bo_funcs->bo_decref (qxl, bo); 489 return NULL; 490 } 491 else 492 goto retry; 493 } 494 495 surface->bo = bo; 496 497 cmd_bo = make_surface_cmd (cache, surface->id, QXL_SURFACE_CMD_CREATE); 498 499 cmd = qxl->bo_funcs->bo_map(cmd_bo); 500 cmd->u.surface_create.format = format; 501 cmd->u.surface_create.width = width; 502 cmd->u.surface_create.height = height; 503 cmd->u.surface_create.stride = - stride; 504 qxl->bo_funcs->bo_unmap(cmd_bo); 505 506 qxl->bo_funcs->bo_output_bo_reloc(qxl, offsetof(struct QXLSurfaceCmd, u.surface_create.data), cmd_bo, surface->bo); 507 508 push_surface_cmd (cache, cmd_bo); 509 510 dev_ptr = qxl->bo_funcs->bo_map(surface->bo); 511 dev_addr 512 = (uint32_t *)((uint8_t *)dev_ptr + stride * (height - 1)); 513 514 surface->dev_image = pixman_image_create_bits ( 515 pformat, width, height, dev_addr, - stride); 516 517 surface->host_image = pixman_image_create_bits ( 518 pformat, width, height, NULL, -1); 519 520 qxl->bo_funcs->bo_unmap(surface->bo); 521 surface->bpp = bpp; 522 523 n_live++; 524 525 return surface; 526} 527 528qxl_surface_t * 529qxl_surface_create (qxl_screen_t *qxl, 530 int width, 531 int height, 532 int bpp) 533{ 534 qxl_surface_t *surface; 535 surface_cache_t *cache = qxl->surface_cache; 536 537 if (!qxl->enable_surfaces) 538 return NULL; 539 540 if ((bpp & 3) != 0) 541 { 542 ErrorF ("%s: Bad bpp: %d (%d)\n", __FUNCTION__, bpp, bpp & 7); 543 return NULL; 544 } 545 546#if 0 547 if (bpp == 8) 548 { 549 static int warned; 550 if (!warned) 551 { 552 warned = 1; 553 ErrorF ("bpp == 8 triggers bugs in spice apparently\n"); 554 } 555 556 return NULL; 557 } 558#endif 559 560 if (bpp != 8 && bpp != 16 && bpp != 32 && bpp != 24) 561 { 562 ErrorF ("%s: Unknown bpp\n", __FUNCTION__); 563 return NULL; 564 } 565 566 if (width == 0 || height == 0) 567 { 568 ErrorF ("%s: Zero width or height\n", __FUNCTION__); 569 return NULL; 570 } 571 572 if (!(surface = surface_get_from_cache (cache, width, height, bpp))) 573 if (!(surface = surface_send_create (cache, width, height, bpp))) 574 return NULL; 575 576 surface->next = cache->live_surfaces; 577 surface->prev = NULL; 578 if (cache->live_surfaces) 579 cache->live_surfaces->prev = surface; 580 cache->live_surfaces = surface; 581 582 return surface; 583} 584 585void 586qxl_surface_set_pixmap (qxl_surface_t *surface, PixmapPtr pixmap) 587{ 588 surface->pixmap = pixmap; 589 590 assert (get_surface (pixmap) == surface); 591} 592 593static void 594unlink_surface (qxl_surface_t *surface) 595{ 596 if (surface->id != 0) 597 { 598 if (surface->prev) 599 surface->prev->next = surface->next; 600 else 601 surface->cache->live_surfaces = surface->next; 602 } 603 604 debug_surface_log(surface->cache); 605 606 if (surface->next) 607 surface->next->prev = surface->prev; 608 609 surface->pixmap = NULL; 610 611 surface->prev = NULL; 612 surface->next = NULL; 613} 614 615static void 616surface_destroy (qxl_surface_t *surface) 617{ 618 struct qxl_bo *cmd_bo; 619 620 if (surface->dev_image) 621 pixman_image_unref (surface->dev_image); 622 if (surface->host_image) 623 pixman_image_unref (surface->host_image); 624 625#if 0 626 ErrorF("destroy %ld\n", (long int)surface->end - (long int)surface->address); 627#endif 628 cmd_bo = make_surface_cmd (surface->cache, surface->id, QXL_SURFACE_CMD_DESTROY); 629 630 push_surface_cmd (surface->cache, cmd_bo); 631 632 surface->cache->qxl->bo_funcs->bo_decref(surface->cache->qxl, surface->bo); 633} 634 635static void 636surface_add_to_cache (qxl_surface_t *surface) 637{ 638 surface_cache_t *cache = surface->cache; 639 int oldest = -1; 640 int n_surfaces = 0; 641 int i, delta; 642 int destroy_id = -1; 643 qxl_surface_t *destroy_surface = NULL; 644 645 surface->ref_count++; 646 647 for (i = 0; i < N_CACHED_SURFACES; ++i) 648 { 649 if (cache->cached_surfaces[i]) 650 { 651 oldest = i; 652 n_surfaces++; 653 } 654 } 655 656 if (n_surfaces == N_CACHED_SURFACES) 657 { 658 destroy_id = cache->cached_surfaces[oldest]->id; 659 660 destroy_surface = cache->cached_surfaces[oldest]; 661 662 cache->cached_surfaces[oldest] = NULL; 663 664 for (i = 0; i < N_CACHED_SURFACES; ++i) 665 assert (!cache->cached_surfaces[i] || 666 cache->cached_surfaces[i]->id != destroy_id); 667 } 668 669 delta = 0; 670 for (i = N_CACHED_SURFACES - 1; i >= 0; i--) 671 { 672 if (cache->cached_surfaces[i]) 673 { 674 if (delta > 0) 675 { 676 cache->cached_surfaces[i + delta] = 677 cache->cached_surfaces[i]; 678 679 assert (cache->cached_surfaces[i + delta]->id != destroy_id); 680 681 cache->cached_surfaces[i] = NULL; 682 } 683 } 684 else 685 { 686 delta++; 687 } 688 } 689 690 assert (delta > 0); 691 692 cache->cached_surfaces[i + delta] = surface; 693 694 for (i = 0; i < N_CACHED_SURFACES; ++i) 695 assert (!cache->cached_surfaces[i] || cache->cached_surfaces[i]->id != destroy_id); 696 697 /* Note that sending a destroy command can trigger callbacks into 698 * this function (due to memory management), so we have to 699 * do this after updating the cache 700 */ 701 if (destroy_surface) 702 qxl_surface_unref (destroy_surface->cache, destroy_surface->id); 703} 704 705void 706qxl_surface_unref (surface_cache_t *cache, uint32_t id) 707{ 708 if (id != 0) 709 { 710 qxl_surface_t *surface = cache->all_surfaces + id; 711 712 if (--surface->ref_count == 0) 713 surface_destroy (surface); 714 } 715} 716 717void 718qxl_surface_kill (qxl_surface_t *surface) 719{ 720 struct evacuated_surface_t *ev = surface->evacuated; 721 722 if (ev) 723 { 724 /* server side surface is already destroyed (via reset), don't 725 * resend a destroy. Just mark surface as not to be recreated */ 726 ev->pixmap = NULL; 727 if (ev->image) 728 pixman_image_unref (ev->image); 729 if (ev->next) 730 ev->next->prev = ev->prev; 731 if (ev->prev) 732 ev->prev->next = ev->next; 733 free(ev); 734 surface->evacuated = NULL; 735 return; 736 } 737 738 unlink_surface (surface); 739 740 if (!surface->cache->all_surfaces) { 741 return; 742 } 743 744 if (surface->id != 0 && 745 surface->host_image && 746 pixman_image_get_width (surface->host_image) >= 128 && 747 pixman_image_get_height (surface->host_image) >= 128) 748 { 749 surface_add_to_cache (surface); 750 } 751 752 qxl_surface_unref (surface->cache, surface->id); 753} 754 755 756void * 757qxl_surface_cache_evacuate_all (surface_cache_t *cache) 758{ 759 evacuated_surface_t *evacuated_surfaces = NULL; 760 qxl_surface_t *s; 761 int i; 762 763 for (i = 0; i < N_CACHED_SURFACES; ++i) 764 { 765 if (cache->cached_surfaces[i]) 766 { 767 surface_destroy (cache->cached_surfaces[i]); 768 cache->cached_surfaces[i] = NULL; 769 } 770 } 771 772 s = cache->live_surfaces; 773 while (s != NULL) 774 { 775 qxl_surface_t *next = s->next; 776 evacuated_surface_t *evacuated = malloc (sizeof (evacuated_surface_t)); 777 int width, height; 778 779 width = pixman_image_get_width (s->host_image); 780 height = pixman_image_get_height (s->host_image); 781 782 qxl_download_box (s, 0, 0, width, height); 783 784 evacuated->image = s->host_image; 785 evacuated->pixmap = s->pixmap; 786 787 assert (get_surface (evacuated->pixmap) == s); 788 789 evacuated->bpp = s->bpp; 790 791 s->host_image = NULL; 792 793 unlink_surface (s); 794 795 evacuated->prev = NULL; 796 evacuated->next = evacuated_surfaces; 797 if (evacuated_surfaces) 798 evacuated_surfaces->prev = evacuated; 799 evacuated_surfaces = evacuated; 800 s->evacuated = evacuated; 801 802 s = next; 803 } 804 805 cache->live_surfaces = NULL; 806 cache->free_surfaces = NULL; 807 808 return evacuated_surfaces; 809} 810 811void 812qxl_surface_cache_replace_all (surface_cache_t *cache, void *data) 813{ 814 evacuated_surface_t *ev; 815 816 if (!surface_cache_init (cache, cache->qxl)) 817 { 818 /* FIXME: report the error */ 819 return; 820 } 821 822 ev = data; 823 while (ev != NULL) 824 { 825 evacuated_surface_t *next = ev->next; 826 int width = pixman_image_get_width (ev->image); 827 int height = pixman_image_get_height (ev->image); 828 qxl_surface_t *surface; 829 830 surface = qxl_surface_create (cache->qxl, width, height, ev->bpp); 831 832 assert (surface->host_image); 833 assert (surface->dev_image); 834 835 pixman_image_unref (surface->host_image); 836 surface->host_image = ev->image; 837 838 qxl_upload_box (surface, 0, 0, width, height); 839 840 set_surface (ev->pixmap, surface); 841 842 qxl_surface_set_pixmap (surface, ev->pixmap); 843 844 free (ev); 845 846 ev = next; 847 } 848 849 qxl_surface_cache_sanity_check (cache); 850 851} 852