1/* 2 * Copyright 2009 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#ifdef HAVE_CONFIG_H 24#include "config.h" 25#endif 26 27#include <stdarg.h> 28#include <errno.h> 29#include <time.h> 30#include <unistd.h> 31 32#include "qxl.h" 33#include "mspace.h" 34 35#include "qxl_surface.h" 36#ifdef DEBUG_QXL_MEM 37#include <valgrind/memcheck.h> 38#endif 39 40#define QXL_BO_DATA 1 41#define QXL_BO_SURF 2 42#define QXL_BO_CMD 4 43#define QXL_BO_SURF_PRIMARY 8 44 45#define QXL_BO_FLAG_FAIL 1 46 47 48struct qxl_mem 49{ 50 mspace space; 51 void * base; 52 unsigned long n_bytes; 53#ifdef DEBUG_QXL_MEM 54 size_t used_initial; 55 int unverifiable; 56 int missing; 57#endif 58}; 59 60#ifdef DEBUG_QXL_MEM 61void 62qxl_mem_unverifiable(struct qxl_mem *mem) 63{ 64 mem->unverifiable = 1; 65} 66#endif 67 68static void __attribute__ ((format (gnu_printf, 2, 3))) 69errout (void *data, const char *format, ...) 70{ 71 va_list va; 72 73 va_start (va, format); 74 75 VErrorF (format, va); 76 77 va_end (va); 78} 79 80static void __attribute__ ((__noreturn__)) 81qxl_mspace_abort_func (void *user_data) 82{ 83 abort (); 84} 85 86void 87qxl_mem_init(void) 88{ 89 mspace_set_print_func (errout); 90 mspace_set_abort_func (qxl_mspace_abort_func); 91} 92 93struct qxl_mem * 94qxl_mem_create (void *base, 95 unsigned long n_bytes) 96{ 97 struct qxl_mem *mem; 98 99 mem = calloc (sizeof (*mem), 1); 100 if (!mem) 101 goto out; 102 103 ErrorF ("memory space from %p to %p\n", base, (char *)base + n_bytes); 104 105 106 mem->space = create_mspace_with_base (base, n_bytes, 0, NULL); 107 108 mem->base = base; 109 mem->n_bytes = n_bytes; 110 111#ifdef DEBUG_QXL_MEM 112 { 113 size_t used; 114 115 mspace_malloc_stats_return(mem->space, NULL, NULL, &used); 116 mem->used_initial = used; 117 mem->unverifiable = 0; 118 mem->missing = 0; 119 } 120#endif 121 122out: 123 return mem; 124 125} 126 127void 128qxl_mem_dump_stats (struct qxl_mem *mem, 129 const char *header) 130{ 131 ErrorF ("%s\n", header); 132 133 mspace_malloc_stats (mem->space); 134} 135 136static void * 137qxl_alloc (struct qxl_mem *mem, 138 unsigned long n_bytes, 139 const char *name) 140{ 141 void *addr = mspace_malloc (mem->space, n_bytes); 142 143#ifdef DEBUG_QXL_MEM 144 VALGRIND_MALLOCLIKE_BLOCK(addr, n_bytes, 0, 0); 145#ifdef DEBUG_QXL_MEM_VERBOSE 146 fprintf(stderr, "alloc %p: %ld (%s)\n", addr, n_bytes, name); 147#endif 148#endif 149 return addr; 150} 151 152static void 153qxl_free (struct qxl_mem *mem, 154 void *d, 155 const char * name) 156{ 157#if 0 158 ErrorF ("%p <= free %s\n", d, name); 159#endif 160 mspace_free (mem->space, d); 161#ifdef DEBUG_QXL_MEM 162#ifdef DEBUG_QXL_MEM_VERBOSE 163 fprintf(stderr, "free %p %s\n", d, name); 164#endif 165 VALGRIND_FREELIKE_BLOCK(d, 0); 166#endif 167} 168 169void 170qxl_mem_free_all (struct qxl_mem *mem) 171{ 172#ifdef DEBUG_QXL_MEM 173 size_t maxfp, fp, used; 174 175 if (mem->space) 176 { 177 mspace_malloc_stats_return(mem->space, &maxfp, &fp, &used); 178 mem->missing = used - mem->used_initial; 179 ErrorF ("untracked %zd bytes (%s)", used - mem->used_initial, 180 mem->unverifiable ? "marked unverifiable" : "oops"); 181 } 182#endif 183 mem->space = create_mspace_with_base (mem->base, mem->n_bytes, 0, NULL); 184} 185 186static uint8_t 187setup_slot (qxl_screen_t *qxl, uint8_t slot_index_offset, 188 unsigned long start_phys_addr, unsigned long end_phys_addr, 189 uint64_t start_virt_addr, uint64_t end_virt_addr) 190{ 191 uint64_t high_bits; 192 qxl_memslot_t *slot; 193 uint8_t slot_index; 194 struct QXLRam *ram_header; 195 196 ram_header = (void *)((unsigned long)qxl->ram + (unsigned long)qxl->rom->ram_header_offset); 197 198 slot_index = qxl->rom->slots_start + slot_index_offset; 199 slot = &qxl->mem_slots[slot_index]; 200 slot->start_phys_addr = start_phys_addr; 201 slot->end_phys_addr = end_phys_addr; 202 slot->start_virt_addr = start_virt_addr; 203 slot->end_virt_addr = end_virt_addr; 204 205 ram_header->mem_slot.mem_start = slot->start_phys_addr; 206 ram_header->mem_slot.mem_end = slot->end_phys_addr; 207 208 qxl_io_memslot_add (qxl, slot_index); 209 210 slot->generation = qxl->rom->slot_generation; 211 212 high_bits = slot_index << qxl->slot_gen_bits; 213 high_bits |= slot->generation; 214 high_bits <<= (64 - (qxl->slot_gen_bits + qxl->slot_id_bits)); 215 slot->high_bits = high_bits; 216 217 return slot_index; 218} 219 220void 221qxl_reset_and_create_mem_slots (qxl_screen_t *qxl) 222{ 223 ioport_write (qxl, QXL_IO_RESET, 0); 224 qxl->device_primary = QXL_DEVICE_PRIMARY_NONE; 225 /* Mem slots */ 226 ErrorF ("slots start: %d, slots end: %d\n", 227 qxl->rom->slots_start, 228 qxl->rom->slots_end); 229 230 /* Main slot */ 231 qxl->n_mem_slots = qxl->rom->slots_end; 232 qxl->slot_gen_bits = qxl->rom->slot_gen_bits; 233 qxl->slot_id_bits = qxl->rom->slot_id_bits; 234 qxl->va_slot_mask = (~(uint64_t)0) >> (qxl->slot_id_bits + qxl->slot_gen_bits); 235 236 qxl->mem_slots = xnfalloc (qxl->n_mem_slots * sizeof (qxl_memslot_t)); 237 238#ifdef XSPICE 239 qxl->main_mem_slot = qxl->vram_mem_slot = setup_slot (qxl, 0, 0, ~0, 0, ~0); 240#else /* QXL */ 241 qxl->main_mem_slot = setup_slot (qxl, 0, 242 (unsigned long)qxl->ram_physical, 243 (unsigned long)qxl->ram_physical + qxl->surface0_size + 244 (unsigned long)qxl->rom->num_pages * getpagesize (), 245 (uint64_t)(uintptr_t)qxl->ram, 246 (uint64_t)(uintptr_t)qxl->ram + qxl->surface0_size + 247 (unsigned long)qxl->rom->num_pages * getpagesize () 248 ); 249 qxl->vram_mem_slot = setup_slot (qxl, 1, 250 (unsigned long)qxl->vram_physical, 251 (unsigned long)qxl->vram_physical + (unsigned long)qxl->vram_size, 252 (uint64_t)(uintptr_t)qxl->vram, 253 (uint64_t)(uintptr_t)qxl->vram + (uint64_t)qxl->vram_size); 254#endif 255 256 qxl_allocate_monitors_config(qxl); 257} 258 259void 260qxl_mark_mem_unverifiable (qxl_screen_t *qxl) 261{ 262 qxl_mem_unverifiable (qxl->mem); 263 qxl_mem_unverifiable (qxl->surf_mem); 264} 265 266 267static uint64_t 268qxl_garbage_collect_internal (qxl_screen_t *qxl, uint64_t id) 269{ 270 /* We assume that there the two low bits of a pointer are 271 * available. If the low one is set, then the command in 272 * question is a cursor command 273 */ 274#define POINTER_MASK ((1 << 2) - 1) 275 276 struct qxl_bo *info_bo = (struct qxl_bo *)u64_to_pointer(id & ~POINTER_MASK); 277 union QXLReleaseInfo *info = qxl->bo_funcs->bo_map(info_bo); 278 struct QXLCursorCmd *cmd = (struct QXLCursorCmd *)info; 279 struct QXLDrawable *drawable = (struct QXLDrawable *)info; 280 struct QXLSurfaceCmd *surface_cmd = (struct QXLSurfaceCmd *)info; 281 int is_cursor = FALSE; 282 int is_surface = FALSE; 283 int is_drawable = FALSE; 284 struct qxl_bo *to_free; 285 286 if ((id & POINTER_MASK) == 1) 287 is_cursor = TRUE; 288 else if ((id & POINTER_MASK) == 2) 289 is_surface = TRUE; 290 else 291 is_drawable = TRUE; 292 293 if (is_cursor && cmd->type == QXL_CURSOR_SET) 294 { 295 to_free = qxl_ums_lookup_phy_addr(qxl, cmd->u.set.shape); 296 qxl->bo_funcs->bo_decref (qxl, to_free); 297 } 298 else if (is_drawable && drawable->type == QXL_DRAW_COPY) 299 { 300 struct QXLImage *image; 301 302 to_free = qxl_ums_lookup_phy_addr(qxl, drawable->u.copy.src_bitmap); 303 image = qxl->bo_funcs->bo_map(to_free); 304 305 if (image->descriptor.type == SPICE_IMAGE_TYPE_SURFACE) 306 { 307 qxl_surface_unref (qxl->surface_cache, image->surface_image.surface_id); 308 qxl_surface_cache_sanity_check (qxl->surface_cache); 309 qxl->bo_funcs->bo_unmap(to_free); 310 qxl->bo_funcs->bo_decref (qxl, to_free); 311 } 312 else 313 { 314 qxl->bo_funcs->bo_unmap(to_free); 315 qxl_image_destroy (qxl, to_free); 316 } 317 } 318 else if (is_drawable && drawable->type == QXL_DRAW_COMPOSITE) 319 { 320 struct qxl_bo *bo; 321 struct QXLComposite *composite = &drawable->u.composite; 322 323 /* Source */ 324 bo = qxl_ums_lookup_phy_addr(qxl, drawable->u.composite.src); 325 qxl->bo_funcs->bo_decref (qxl, bo); 326 327 if (composite->src_transform) 328 { 329 bo = qxl_ums_lookup_phy_addr(qxl, composite->src_transform); 330 qxl->bo_funcs->bo_decref (qxl, bo); 331 } 332 333 /* Mask */ 334 if (drawable->u.composite.mask) 335 { 336 if (drawable->u.composite.mask_transform) 337 { 338 bo = qxl_ums_lookup_phy_addr(qxl, drawable->u.composite.mask_transform); 339 qxl->bo_funcs->bo_decref (qxl, bo); 340 } 341 bo = qxl_ums_lookup_phy_addr(qxl, drawable->u.composite.mask); 342 qxl->bo_funcs->bo_decref (qxl, bo); 343 } 344 } 345 else if (is_surface && surface_cmd->type == QXL_SURFACE_CMD_DESTROY) 346 { 347 qxl_surface_recycle (qxl->surface_cache, surface_cmd->surface_id); 348 qxl_surface_cache_sanity_check (qxl->surface_cache); 349 } 350 351 id = info->next; 352 353 qxl->bo_funcs->bo_unmap(info_bo); 354 qxl->bo_funcs->bo_decref(qxl, info_bo); 355 356 return id; 357} 358 359int 360qxl_garbage_collect (qxl_screen_t *qxl) 361{ 362 uint64_t id; 363 int i = 0; 364 365 while (qxl_ring_pop (qxl->release_ring, &id)) 366 { 367 while (id) 368 { 369 id = qxl_garbage_collect_internal (qxl, id); 370 371 i++; 372 } 373 } 374 375 return i; 376} 377 378static void 379qxl_usleep (int useconds) 380{ 381 struct timespec t; 382 383 t.tv_sec = useconds / 1000000; 384 t.tv_nsec = (useconds - (t.tv_sec * 1000000)) * 1000; 385 386 errno = 0; 387 while (nanosleep (&t, &t) == -1 && errno == EINTR) 388 ; 389} 390 391int 392qxl_handle_oom (qxl_screen_t *qxl) 393{ 394 qxl_io_notify_oom (qxl); 395 396#if 0 397 ErrorF ("."); 398 qxl_usleep (10000); 399#endif 400 401 if (!(qxl_garbage_collect (qxl))) 402 qxl_usleep (10000); 403 404 return qxl_garbage_collect (qxl); 405} 406 407static void * 408qxl_allocnf (qxl_screen_t *qxl, unsigned long size, const char *name) 409{ 410 void *result; 411 int n_attempts = 0; 412 413#if 0 414 static int nth_oom = 1; 415#endif 416 417 qxl_garbage_collect (qxl); 418 419 while (!(result = qxl_alloc (qxl->mem, size, name))) 420 { 421#if 0 422 ErrorF ("eliminated memory (%d)\n", nth_oom++); 423#endif 424 if (!qxl_garbage_collect (qxl)) 425 { 426 if (qxl_handle_oom (qxl)) 427 { 428 n_attempts = 0; 429 } 430 else if (++n_attempts == 1000) 431 { 432 ErrorF ("Out of memory allocating %ld bytes\n", size); 433 qxl_mem_dump_stats (qxl->mem, "Out of mem - stats\n"); 434 fprintf (stderr, "Out of memory\n"); 435 exit (1); 436 } 437 } 438 } 439 440 return result; 441} 442 443struct qxl_ums_bo { 444 void *virt_addr; 445 const char *name; 446 int type; 447 uint32_t size; 448 void *internal_virt_addr; 449 int refcnt; 450 qxl_screen_t *qxl; 451 xorg_list_t bos; 452}; 453 454static struct qxl_bo *qxl_bo_alloc_internal(qxl_screen_t *qxl, int type, int flags, unsigned long size, const char *name) 455{ 456 struct qxl_ums_bo *bo; 457 struct qxl_mem *mptr; 458 459 bo = calloc(1, sizeof(struct qxl_ums_bo)); 460 if (!bo) 461 return NULL; 462 463 bo->size = size; 464 bo->name = name; 465 bo->type = type; 466 bo->qxl = qxl; 467 bo->refcnt = 1; 468 if (type == QXL_BO_SURF) 469 mptr = qxl->surf_mem; 470 else 471 mptr = qxl->mem; 472 473 if (flags & QXL_BO_FLAG_FAIL) { 474 bo->internal_virt_addr = qxl_alloc(mptr, size, name); 475 if (!bo->internal_virt_addr) { 476 free(bo); 477 return NULL; 478 } 479 } else 480 bo->internal_virt_addr = qxl_allocnf(qxl, size, name); 481 482 if (type != QXL_BO_SURF) { 483 xorg_list_add(&bo->bos, &qxl->ums_bos); 484 } 485 return (struct qxl_bo *)bo; 486} 487 488static struct qxl_bo *qxl_bo_alloc(qxl_screen_t *qxl, unsigned long size, const char *name) 489{ 490 return qxl_bo_alloc_internal(qxl, QXL_BO_DATA, 0, size, name); 491} 492 493static struct qxl_bo *qxl_cmd_alloc(qxl_screen_t *qxl, unsigned long size, const char *name) 494{ 495 return qxl_bo_alloc_internal(qxl, QXL_BO_CMD, 0, size, name); 496} 497 498static void *qxl_bo_map(struct qxl_bo *_bo) 499{ 500 struct qxl_ums_bo *bo = (struct qxl_ums_bo *)_bo; 501 if (bo->virt_addr) 502 ErrorF("recursive map %p\n", bo); 503 bo->virt_addr = bo->internal_virt_addr; 504 return bo->virt_addr; 505} 506 507static void qxl_bo_unmap(struct qxl_bo *_bo) 508{ 509 struct qxl_ums_bo *bo = (struct qxl_ums_bo *)_bo; 510 if (!bo->virt_addr) 511 ErrorF("unbalanced unmap %p\n", bo); 512 bo->virt_addr = NULL; 513} 514 515static void qxl_bo_output_bo_reloc(qxl_screen_t *qxl, uint32_t dst_offset, 516 struct qxl_bo *_dst_bo, 517 struct qxl_bo *_src_bo) 518{ 519 struct qxl_ums_bo *src_bo = (struct qxl_ums_bo *)_src_bo; 520 struct qxl_ums_bo *dst_bo = (struct qxl_ums_bo *)_dst_bo; 521 uint8_t slot_id; 522 uint64_t value; 523 524 /* take a reference on the bo */ 525 src_bo->refcnt++; 526 527 slot_id = src_bo->type == QXL_BO_SURF ? qxl->vram_mem_slot : qxl->main_mem_slot; 528 value = physical_address(qxl, src_bo->internal_virt_addr, slot_id); 529 530 *(uint64_t *)((char *)dst_bo->internal_virt_addr + dst_offset) = value; 531} 532 533static void qxl_bo_output_cmd_reloc(qxl_screen_t *qxl, QXLCommand *command, 534 struct qxl_bo *_src_bo) 535{ 536 struct qxl_ums_bo *src_bo = (struct qxl_ums_bo *)_src_bo; 537 uint64_t value; 538 uint8_t slot_id; 539 540 src_bo->refcnt++; 541 542 slot_id = src_bo->type == QXL_BO_SURF ? qxl->vram_mem_slot : qxl->main_mem_slot; 543 value = physical_address(qxl, src_bo->internal_virt_addr, slot_id); 544 545 command->data = value; 546} 547 548struct qxl_bo *qxl_ums_lookup_phy_addr(qxl_screen_t *qxl, uint64_t phy_addr) 549{ 550 struct qxl_ums_bo *bo, *found = NULL; 551 uint8_t slot_id; 552 void *virt_addr; 553 554 slot_id = qxl->main_mem_slot; 555 virt_addr = (void *)virtual_address(qxl, u64_to_pointer(phy_addr), slot_id); 556 557 xorg_list_for_each_entry(bo, &qxl->ums_bos, bos) { 558 if (bo->internal_virt_addr == virt_addr && bo->type == QXL_BO_DATA) { 559 found = bo; 560 break; 561 } 562 } 563 return (struct qxl_bo *)found; 564} 565 566static void qxl_bo_incref(qxl_screen_t *qxl, struct qxl_bo *_bo) 567{ 568 struct qxl_ums_bo *bo = (struct qxl_ums_bo *)_bo; 569 bo->refcnt++; 570} 571 572static void qxl_bo_decref(qxl_screen_t *qxl, struct qxl_bo *_bo) 573{ 574 struct qxl_ums_bo *bo = (struct qxl_ums_bo *)_bo; 575 struct qxl_mem *mptr; 576 577 bo->refcnt--; 578 579 if (bo->refcnt > 0) 580 return; 581 582 if (bo->type == QXL_BO_SURF_PRIMARY) 583 goto out_free; 584 585 if (bo->type == QXL_BO_SURF) 586 mptr = qxl->surf_mem; 587 else 588 mptr = qxl->mem; 589 590 qxl_free(mptr, bo->internal_virt_addr, bo->name); 591 if (bo->type != QXL_BO_SURF) 592 xorg_list_del(&bo->bos); 593out_free: 594 free(bo); 595} 596 597static void qxl_bo_write_command(qxl_screen_t *qxl, uint32_t cmd_type, struct qxl_bo *bo) 598{ 599 struct QXLCommand cmd; 600 601 /* When someone runs "init 3", the device will be 602 * switched into VGA mode and there is nothing we 603 * can do about it. We get no notification. 604 * 605 * However, if commands are submitted when the device 606 * is in VGA mode, they will be queued up, and then 607 * the next time a mode set set, an assertion in the 608 * device will take down the entire virtual machine. 609 * 610 * For surface commands this is not relevant, we send 611 * them regardless. 612 */ 613 614 if (!qxl->pScrn->vtSema && cmd_type != QXL_CMD_SURFACE) 615 return; 616 617 cmd.type = cmd_type; 618 qxl_bo_output_cmd_reloc(qxl, &cmd, bo); 619 620 if (cmd_type == QXL_CMD_CURSOR) 621 qxl_ring_push (qxl->cursor_ring, &cmd); 622 else 623 qxl_ring_push (qxl->command_ring, &cmd); 624 625 qxl_bo_decref(qxl, bo); 626} 627 628static void qxl_bo_update_area(qxl_surface_t *surf, int x1, int y1, int x2, int y2) 629{ 630 struct QXLRam *ram_header = get_ram_header(surf->qxl); 631 632 ram_header->update_area.top = y1; 633 ram_header->update_area.bottom = y2; 634 ram_header->update_area.left = x1; 635 ram_header->update_area.right = x2; 636 637 ram_header->update_surface = surf->id; 638 639 qxl_update_area(surf->qxl); 640} 641 642/* create a fake bo for the primary */ 643static struct qxl_bo *qxl_bo_create_primary(qxl_screen_t *qxl, uint32_t width, uint32_t height, int32_t stride, uint32_t format) 644{ 645 struct qxl_ums_bo *bo; 646 struct QXLRam *ram_header = 647 (void *)((unsigned long)qxl->ram + qxl->rom->ram_header_offset); 648 649 struct QXLSurfaceCreate *create = &(ram_header->create_surface); 650 651 create->width = width; 652 create->height = height; 653 create->stride = - stride; 654 create->format = format; 655 create->position = 0; /* What is this? The Windows driver doesn't use it */ 656 create->flags = 0; 657 create->type = QXL_SURF_TYPE_PRIMARY; 658 create->mem = physical_address (qxl, qxl->ram, qxl->main_mem_slot); 659 660 qxl_io_create_primary(qxl); 661 662 bo = calloc(1, sizeof(struct qxl_ums_bo)); 663 if (!bo) 664 return NULL; 665 666 bo->size = stride * height; 667 bo->name = "primary"; 668 bo->type = QXL_BO_SURF_PRIMARY; 669 bo->qxl = qxl; 670 bo->refcnt = 1; 671 bo->internal_virt_addr = (uint8_t *)qxl->ram + stride * (height - 1); 672 673 qxl->primary_bo = (struct qxl_bo *)bo; 674 return (struct qxl_bo *)bo; 675} 676 677static void qxl_bo_destroy_primary(qxl_screen_t *qxl, struct qxl_bo *bo) 678{ 679 free(bo); 680 qxl->primary_bo = NULL; 681 682 qxl_io_destroy_primary (qxl); 683} 684 685static void qxl_bo_output_surf_reloc(qxl_screen_t *qxl, uint32_t dst_offset, 686 struct qxl_bo *_dst_bo, qxl_surface_t *surf) 687{ 688 struct qxl_ums_bo *dst_bo = (struct qxl_ums_bo *)_dst_bo; 689 690 *(uint32_t *)((char *)dst_bo->internal_virt_addr + dst_offset) = surf->id; 691} 692 693static struct qxl_bo_funcs qxl_ums_bo_funcs = { 694 qxl_bo_alloc, 695 qxl_cmd_alloc, 696 qxl_bo_map, 697 qxl_bo_unmap, 698 qxl_bo_decref, 699 qxl_bo_incref, 700 qxl_bo_output_bo_reloc, 701 qxl_bo_write_command, 702 qxl_bo_update_area, 703 qxl_bo_create_primary, 704 qxl_bo_destroy_primary, 705 qxl_surface_create, 706 qxl_surface_kill, 707 qxl_bo_output_surf_reloc, 708}; 709 710void qxl_ums_setup_funcs(qxl_screen_t *qxl) 711{ 712 qxl->bo_funcs = &qxl_ums_bo_funcs; 713} 714 715struct qxl_bo *qxl_ums_surf_mem_alloc(qxl_screen_t *qxl, uint32_t size) 716{ 717 struct qxl_bo *bo; 718 bo = qxl_bo_alloc_internal (qxl, QXL_BO_SURF, QXL_BO_FLAG_FAIL, size, "surface memory"); 719 return bo; 720} 721