qxl_kms.c revision d514b0f3
1/* 2 * Copyright 2013-2014 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#ifdef XF86DRM_MODE 28#include <fcntl.h> 29#include <sys/mman.h> 30#include <errno.h> 31#include "qxl.h" 32 33#include "qxl_surface.h" 34 35Bool qxl_kms_check_cap(qxl_screen_t *qxl, int idx) 36{ 37 int ret; 38 struct drm_qxl_clientcap cap; 39 40 cap.index = idx; 41 ret = drmIoctl(qxl->drm_fd, DRM_IOCTL_QXL_CLIENTCAP, &cap); 42 if (ret == 0) 43 return TRUE; 44 return FALSE; 45} 46 47#if 0 48static Bool qxl_kms_getparam(qxl_screen_t *qxl, uint64_t param, uint64_t *value) 49{ 50 int ret; 51 struct drm_qxl_getparam args = {0}; 52 53 args.param = param; 54 ret = drmIoctl(qxl->drm_fd, DRM_IOCTL_QXL_GETPARAM, &args); 55 if (ret != 0) 56 return FALSE; 57 58 *value = args.value; 59 return TRUE; 60} 61#endif 62 63static Bool qxl_open_drm_master(ScrnInfoPtr pScrn) 64{ 65 qxl_screen_t *qxl = pScrn->driverPrivate; 66 struct pci_device *dev = qxl->pci; 67 char *busid; 68 drmSetVersion sv; 69 int err; 70 71#if defined(ODEV_ATTRIB_FD) 72 if (qxl->platform_dev) { 73 qxl->drm_fd = xf86_get_platform_device_int_attrib(qxl->platform_dev, 74 ODEV_ATTRIB_FD, -1); 75 if (qxl->drm_fd != -1) { 76 qxl->drmmode.fd = qxl->drm_fd; 77 return TRUE; 78 } 79 } 80#endif 81 82#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,9,99,901,0) 83 XNFasprintf(&busid, "pci:%04x:%02x:%02x.%d", 84 dev->domain, dev->bus, dev->dev, dev->func); 85#else 86 busid = XNFprintf("pci:%04x:%02x:%02x.%d", 87 dev->domain, dev->bus, dev->dev, dev->func); 88#endif 89 90 qxl->drm_fd = drmOpen("qxl", busid); 91 if (qxl->drm_fd == -1) { 92 93 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 94 "[drm] Failed to open DRM device for %s: %s\n", 95 busid, strerror(errno)); 96 free(busid); 97 return FALSE; 98 } 99 free(busid); 100 101 /* Check that what we opened was a master or a master-capable FD, 102 * by setting the version of the interface we'll use to talk to it. 103 * (see DRIOpenDRMMaster() in DRI1) 104 */ 105 sv.drm_di_major = 1; 106 sv.drm_di_minor = 1; 107 sv.drm_dd_major = -1; 108 sv.drm_dd_minor = -1; 109 err = drmSetInterfaceVersion(qxl->drm_fd, &sv); 110 if (err != 0) { 111 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 112 "[drm] failed to set drm interface version.\n"); 113 drmClose(qxl->drm_fd); 114 qxl->drm_fd = -1; 115 116 return FALSE; 117 } 118 119 qxl->drmmode.fd = qxl->drm_fd; 120 return TRUE; 121} 122 123static Bool 124qxl_close_screen_kms (CLOSE_SCREEN_ARGS_DECL) 125{ 126 ScrnInfoPtr pScrn = xf86ScreenToScrn (pScreen); 127 qxl_screen_t *qxl = pScrn->driverPrivate; 128 Bool result; 129 130 qxl_drmmode_uevent_fini(pScrn, &qxl->drmmode); 131 pScreen->CloseScreen = qxl->close_screen; 132 133 result = pScreen->CloseScreen (CLOSE_SCREEN_ARGS); 134 135 return result; 136} 137 138 139Bool qxl_pre_init_kms(ScrnInfoPtr pScrn, int flags) 140{ 141 int scrnIndex = pScrn->scrnIndex; 142 qxl_screen_t *qxl = NULL; 143 144 if (!pScrn->confScreen) 145 return FALSE; 146 147 /* zaphod mode is for suckers and i choose not to implement it */ 148 if (xf86IsEntityShared (pScrn->entityList[0])) 149 { 150 xf86DrvMsg (scrnIndex, X_ERROR, "No Zaphod mode for you\n"); 151 return FALSE; 152 } 153 154 if (!pScrn->driverPrivate) 155 pScrn->driverPrivate = xnfcalloc (sizeof (qxl_screen_t), 1); 156 157 qxl = pScrn->driverPrivate; 158 qxl->device_primary = QXL_DEVICE_PRIMARY_UNDEFINED; 159 qxl->pScrn = pScrn; 160 qxl->x_modes = NULL; 161 qxl->entity = xf86GetEntityInfo (pScrn->entityList[0]); 162 qxl->kms_enabled = TRUE; 163 xorg_list_init(&qxl->ums_bos); 164 165 qxl_kms_setup_funcs(qxl); 166 qxl->pci = xf86GetPciInfoForEntity (qxl->entity->index); 167 168 pScrn->monitor = pScrn->confScreen->monitor; 169 170 if (qxl_open_drm_master(pScrn) == FALSE) { 171 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Kernel modesetting setup failed\n"); 172 goto out; 173 } 174 175 if (!qxl_pre_init_common(pScrn)) 176 goto out; 177 178 xf86SetDpi (pScrn, 0, 0); 179 180 if (!xf86LoadSubModule (pScrn, "fb")) 181 goto out; 182 183 if (!xf86LoadSubModule (pScrn, "ramdac")) 184 goto out; 185 186 if (drmmode_pre_init(pScrn, &qxl->drmmode, pScrn->bitsPerPixel / 8) == FALSE) 187 goto out; 188 189 qxl->virtual_x = pScrn->virtualX; 190 qxl->virtual_y = pScrn->virtualY; 191 192 pScrn->display->virtualX = qxl->virtual_x; 193 pScrn->display->virtualY = qxl->virtual_y; 194 195 xf86DrvMsg (scrnIndex, X_INFO, "PreInit complete\n"); 196#ifdef GIT_VERSION 197 xf86DrvMsg (scrnIndex, X_INFO, "git commit %s\n", GIT_VERSION); 198#endif 199 200 return TRUE; 201 202 out: 203 if (qxl) 204 free(qxl); 205 return FALSE; 206} 207 208static Bool 209qxl_create_screen_resources_kms(ScreenPtr pScreen) 210{ 211 ScrnInfoPtr pScrn = xf86ScreenToScrn (pScreen); 212 qxl_screen_t * qxl = pScrn->driverPrivate; 213 Bool ret; 214 PixmapPtr pPixmap; 215 qxl_surface_t *surf; 216 217 pScreen->CreateScreenResources = qxl->create_screen_resources; 218 ret = pScreen->CreateScreenResources (pScreen); 219 pScreen->CreateScreenResources = qxl_create_screen_resources_kms; 220 221 if (!ret) 222 return FALSE; 223 224 pPixmap = pScreen->GetScreenPixmap (pScreen); 225 226 qxl_set_screen_pixmap_header (pScreen); 227 228 if ((surf = get_surface (pPixmap))) 229 qxl->bo_funcs->destroy_surface(surf); 230 231 set_surface (pPixmap, qxl->primary); 232 233 qxl_drmmode_uevent_init(pScrn, &qxl->drmmode); 234 235 if (!uxa_resources_init (pScreen)) 236 return FALSE; 237 238 qxl->screen_resources_created = TRUE; 239 return TRUE; 240} 241 242static Bool 243qxl_blank_screen (ScreenPtr pScreen, int mode) 244{ 245 return TRUE; 246} 247 248Bool 249qxl_enter_vt_kms (VT_FUNC_ARGS_DECL) 250{ 251 SCRN_INFO_PTR (arg); 252 qxl_screen_t *qxl = pScrn->driverPrivate; 253 int ret; 254 255#ifdef XF86_PDEV_SERVER_FD 256 if (!(qxl->platform_dev && 257 (qxl->platform_dev->flags & XF86_PDEV_SERVER_FD))) 258#endif 259 { 260 ret = drmSetMaster(qxl->drm_fd); 261 if (ret) { 262 xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 263 "drmSetMaster failed: %s\n", 264 strerror(errno)); 265 } 266 } 267 268 if (!xf86SetDesiredModes(pScrn)) 269 return FALSE; 270 271 // pScrn->EnableDisableFBAccess (XF86_SCRN_ARG (pScrn), TRUE); 272 return TRUE; 273} 274 275void 276qxl_leave_vt_kms (VT_FUNC_ARGS_DECL) 277{ 278 SCRN_INFO_PTR (arg); 279 int ret; 280 qxl_screen_t *qxl = pScrn->driverPrivate; 281 xf86_hide_cursors (pScrn); 282 // pScrn->EnableDisableFBAccess (XF86_SCRN_ARG (pScrn), FALSE); 283 284#ifdef XF86_PDEV_SERVER_FD 285 if (qxl->platform_dev && (qxl->platform_dev->flags & XF86_PDEV_SERVER_FD)) 286 return; 287#endif 288 289 ret = drmDropMaster(qxl->drm_fd); 290 if (ret) { 291 xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 292 "drmDropMaster failed: %s\n", 293 strerror(errno)); 294 } 295} 296 297 298Bool qxl_screen_init_kms(SCREEN_INIT_ARGS_DECL) 299{ 300 ScrnInfoPtr pScrn = xf86ScreenToScrn (pScreen); 301 qxl_screen_t * qxl = pScrn->driverPrivate; 302 VisualPtr visual; 303 304 miClearVisualTypes (); 305 if (!miSetVisualTypes (pScrn->depth, miGetDefaultVisualMask (pScrn->depth), 306 pScrn->rgbBits, pScrn->defaultVisual)) 307 goto out; 308 if (!miSetPixmapDepths ()) 309 goto out; 310 pScrn->displayWidth = pScrn->virtualX; 311 312 if (!qxl_fb_init (qxl, pScreen)) 313 goto out; 314 315 visual = pScreen->visuals + pScreen->numVisuals; 316 while (--visual >= pScreen->visuals) 317 { 318 if ((visual->class | DynamicClass) == DirectColor) 319 { 320 visual->offsetRed = pScrn->offset.red; 321 visual->offsetGreen = pScrn->offset.green; 322 visual->offsetBlue = pScrn->offset.blue; 323 visual->redMask = pScrn->mask.red; 324 visual->greenMask = pScrn->mask.green; 325 visual->blueMask = pScrn->mask.blue; 326 } 327 } 328 329 qxl->uxa = uxa_driver_alloc (); 330 331// GETPARAM 332 /* no surface cache for kms surfaces for now */ 333#if 0 334 if (!qxl_kms_getparam(qxl, QXL_PARAM_NUM_SURFACES, &n_surf)) 335 n_surf = 1024; 336 qxl->surface_cache = qxl_surface_cache_create (qxl, n_surf); 337#endif 338 pScreen->SaveScreen = qxl_blank_screen; 339 340 qxl_uxa_init (qxl, pScreen); 341 342 DamageSetup (pScreen); 343 344 miDCInitialize (pScreen, xf86GetPointerScreenFuncs()); 345 346 xf86_cursors_init (pScreen, 64, 64, 347 (HARDWARE_CURSOR_TRUECOLOR_AT_8BPP | 348 HARDWARE_CURSOR_AND_SOURCE_WITH_MASK | 349 HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_1 | 350 HARDWARE_CURSOR_UPDATE_UNHIDDEN | 351 HARDWARE_CURSOR_ARGB)); 352 353 if (!miCreateDefColormap (pScreen)) 354 goto out; 355 356 if (!xf86CrtcScreenInit (pScreen)) 357 return FALSE; 358 359 if (!qxl_resize_primary_to_virtual (qxl)) 360 return FALSE; 361 362 qxl->create_screen_resources = pScreen->CreateScreenResources; 363 pScreen->CreateScreenResources = qxl_create_screen_resources_kms; 364 365 qxl->close_screen = pScreen->CloseScreen; 366 pScreen->CloseScreen = qxl_close_screen_kms; 367 368 return qxl_enter_vt_kms(VT_FUNC_ARGS); 369 out: 370 return FALSE; 371 372} 373 374#define QXL_BO_DATA 1 375#define QXL_BO_SURF 2 376#define QXL_BO_CMD 4 377#define QXL_BO_SURF_PRIMARY 8 378 379struct qxl_kms_bo { 380 uint32_t handle; 381 const char *name; 382 uint32_t size; 383 int type; 384 xorg_list_t bos; 385 void *mapping; 386 qxl_screen_t *qxl; 387 int refcnt; 388}; 389 390static struct qxl_bo *qxl_bo_alloc(qxl_screen_t *qxl, 391 unsigned long size, const char *name) 392{ 393 struct qxl_kms_bo *bo; 394 struct drm_qxl_alloc alloc; 395 int ret; 396 397 bo = calloc(1, sizeof(struct qxl_kms_bo)); 398 if (!bo) 399 return NULL; 400 401 alloc.size = size; 402 alloc.handle = 0; 403 404 ret = drmIoctl(qxl->drm_fd, DRM_IOCTL_QXL_ALLOC, &alloc); 405 if (ret) { 406 xf86DrvMsg(qxl->pScrn->scrnIndex, X_ERROR, 407 "error doing QXL_ALLOC\n"); 408 free(bo); 409 return NULL; // an invalid handle 410 } 411 412 bo->name = name; 413 bo->size = size; 414 bo->type = QXL_BO_DATA; 415 bo->handle = alloc.handle; 416 bo->qxl = qxl; 417 bo->refcnt = 1; 418 return (struct qxl_bo *)bo; 419} 420 421static struct qxl_bo *qxl_cmd_alloc(qxl_screen_t *qxl, 422 unsigned long size, const char *name) 423{ 424 struct qxl_kms_bo *bo; 425 426 bo = calloc(1, sizeof(struct qxl_kms_bo)); 427 if (!bo) 428 return NULL; 429 bo->mapping = malloc(size); 430 if (!bo->mapping) { 431 free(bo); 432 return NULL; 433 } 434 bo->name = name; 435 bo->size = size; 436 bo->type = QXL_BO_CMD; 437 bo->handle = 0; 438 bo->qxl = qxl; 439 bo->refcnt = 1; 440 return (struct qxl_bo *)bo; 441} 442 443static void *qxl_bo_map(struct qxl_bo *_bo) 444{ 445 struct qxl_kms_bo *bo = (struct qxl_kms_bo *)_bo; 446 void *map; 447 struct drm_qxl_map qxl_map; 448 qxl_screen_t *qxl; 449 450 if (!bo) 451 return NULL; 452 453 qxl = bo->qxl; 454 if (bo->mapping) 455 return bo->mapping; 456 457 memset(&qxl_map, 0, sizeof(qxl_map)); 458 459 qxl_map.handle = bo->handle; 460 461 if (drmIoctl(qxl->drm_fd, DRM_IOCTL_QXL_MAP, &qxl_map)) { 462 xf86DrvMsg(qxl->pScrn->scrnIndex, X_ERROR, 463 "error doing QXL_MAP: %s\n", strerror(errno)); 464 return NULL; 465 } 466 467 map = mmap(0, bo->size, PROT_READ | PROT_WRITE, MAP_SHARED, qxl->drm_fd, 468 qxl_map.offset); 469 if (map == MAP_FAILED) { 470 xf86DrvMsg(qxl->pScrn->scrnIndex, X_ERROR, 471 "mmap failure: %s\n", strerror(errno)); 472 return NULL; 473 } 474 475 bo->mapping = map; 476 return bo->mapping; 477} 478 479static void qxl_bo_unmap(struct qxl_bo *_bo) 480{ 481} 482 483static void qxl_bo_incref(qxl_screen_t *qxl, struct qxl_bo *_bo) 484{ 485 struct qxl_kms_bo *bo = (struct qxl_kms_bo *)_bo; 486 bo->refcnt++; 487} 488 489static void qxl_bo_decref(qxl_screen_t *qxl, struct qxl_bo *_bo) 490{ 491 struct qxl_kms_bo *bo = (struct qxl_kms_bo *)_bo; 492 struct drm_gem_close args; 493 int ret; 494 495 bo->refcnt--; 496 if (bo->refcnt > 0) 497 return; 498 499 if (bo->type == QXL_BO_CMD) { 500 free(bo->mapping); 501 goto out; 502 } else if (bo->mapping) 503 munmap(bo->mapping, bo->size); 504 505 /* just close the handle */ 506 args.handle = bo->handle; 507 ret = drmIoctl(qxl->drm_fd, DRM_IOCTL_GEM_CLOSE, &args); 508 if (ret) { 509 xf86DrvMsg(qxl->pScrn->scrnIndex, X_ERROR, 510 "error doing QXL_DECREF\n"); 511 } 512 out: 513 free(bo); 514} 515 516static void qxl_bo_output_bo_reloc(qxl_screen_t *qxl, uint32_t dst_offset, 517 struct qxl_bo *_dst_bo, 518 struct qxl_bo *_src_bo) 519{ 520 struct qxl_kms_bo *dst_bo = (struct qxl_kms_bo *)_dst_bo; 521 struct qxl_kms_bo *src_bo = (struct qxl_kms_bo *)_src_bo; 522 struct drm_qxl_reloc *r = &qxl->cmds.relocs[qxl->cmds.n_relocs]; 523 524 if (qxl->cmds.n_reloc_bos >= MAX_RELOCS || qxl->cmds.n_relocs >= MAX_RELOCS) 525 assert(0); 526 527 qxl->cmds.reloc_bo[qxl->cmds.n_reloc_bos] = _src_bo; 528 qxl->cmds.n_reloc_bos++; 529 src_bo->refcnt++; 530 531 /* fix the kernel names */ 532 r->reloc_type = QXL_RELOC_TYPE_BO; 533 r->dst_handle = dst_bo->handle; 534 r->src_handle = src_bo->handle; 535 r->dst_offset = dst_offset; 536 r->src_offset = 0; 537 qxl->cmds.n_relocs++; 538} 539 540static void qxl_bo_write_command(qxl_screen_t *qxl, uint32_t cmd_type, struct qxl_bo *_bo) 541{ 542 struct qxl_kms_bo *bo = (struct qxl_kms_bo *)_bo; 543 struct drm_qxl_execbuffer eb; 544 struct drm_qxl_command c; 545 int ret; 546 int i; 547 548 c.type = cmd_type; 549 c.command_size = bo->size - sizeof(union QXLReleaseInfo); 550 c.command = pointer_to_u64(((uint8_t *)bo->mapping + sizeof(union QXLReleaseInfo))); 551 if (qxl->cmds.n_relocs) { 552 c.relocs_num = qxl->cmds.n_relocs; 553 c.relocs = pointer_to_u64(qxl->cmds.relocs); 554 } else { 555 c.relocs_num = 0; 556 c.relocs = 0; 557 } 558 eb.flags = 0; 559 eb.commands_num = 1; 560 eb.commands = pointer_to_u64(&c); 561 ret = drmIoctl(qxl->drm_fd, DRM_IOCTL_QXL_EXECBUFFER, &eb); 562 if (ret) { 563 xf86DrvMsg(qxl->pScrn->scrnIndex, X_ERROR, 564 "EXECBUFFER failed\n"); 565 } 566 qxl->cmds.n_relocs = 0; 567 qxl->bo_funcs->bo_decref(qxl, _bo); 568 569 for (i = 0; i < qxl->cmds.n_reloc_bos; i++) 570 qxl->bo_funcs->bo_decref(qxl, qxl->cmds.reloc_bo[i]); 571 qxl->cmds.n_reloc_bos = 0; 572} 573 574static void qxl_bo_update_area(qxl_surface_t *surf, int x1, int y1, int x2, int y2) 575{ 576 int ret; 577 struct qxl_kms_bo *bo = (struct qxl_kms_bo *)surf->bo; 578 struct drm_qxl_update_area update_area = { 579 .handle = bo->handle, 580 .left = x1, 581 .top = y1, 582 .right = x2, 583 .bottom = y2 584 }; 585 586 ret = drmIoctl(surf->qxl->drm_fd, 587 DRM_IOCTL_QXL_UPDATE_AREA, &update_area); 588 if (ret) { 589 fprintf(stderr, "error doing QXL_UPDATE_AREA %d %d %d\n", ret, errno, surf->id); 590 } 591} 592 593static struct qxl_bo *qxl_bo_create_primary(qxl_screen_t *qxl, uint32_t width, uint32_t height, int32_t stride, uint32_t format) 594{ 595 struct qxl_kms_bo *bo; 596 struct drm_qxl_alloc_surf param; 597 int ret; 598 599 bo = calloc(1, sizeof(struct qxl_kms_bo)); 600 if (!bo) 601 return NULL; 602 603 param.format = SPICE_SURFACE_FMT_32_xRGB; 604 param.width = width; 605 param.height = height; 606 param.stride = stride; 607 param.handle = 0; 608 ret = drmIoctl(qxl->drm_fd, 609 DRM_IOCTL_QXL_ALLOC_SURF, ¶m); 610 if (ret) 611 return NULL; 612 613 bo->name = "surface memory"; 614 bo->size = stride * param.height; 615 bo->type = QXL_BO_SURF_PRIMARY; 616 bo->handle = param.handle; 617 bo->qxl = qxl; 618 bo->refcnt = 1; 619 620 qxl->primary_bo = (struct qxl_bo *)bo; 621 qxl->device_primary = QXL_DEVICE_PRIMARY_CREATED; 622 return (struct qxl_bo *)bo; 623} 624 625static void qxl_bo_destroy_primary(qxl_screen_t *qxl, struct qxl_bo *bo) 626{ 627 qxl_bo_decref(qxl, bo); 628 629 qxl->primary_bo = NULL; 630 qxl->device_primary = QXL_DEVICE_PRIMARY_NONE; 631} 632 633static qxl_surface_t * 634qxl_kms_surface_create(qxl_screen_t *qxl, 635 int width, 636 int height, 637 int bpp) 638{ 639 SpiceSurfaceFmt format; 640 qxl_surface_t *surface; 641 int stride; 642 struct qxl_kms_bo *bo; 643 pixman_format_code_t pformat; 644 void *dev_ptr; 645 int ret; 646 uint32_t *dev_addr; 647 648 struct drm_qxl_alloc_surf param; 649 if (!qxl->enable_surfaces) 650 return NULL; 651 652 if ((bpp & 3) != 0) 653 { 654 ErrorF ("%s: Bad bpp: %d (%d)\n", __FUNCTION__, bpp, bpp & 7); 655 return NULL; 656 } 657 658 if (bpp != 8 && bpp != 16 && bpp != 32 && bpp != 24) 659 { 660 ErrorF ("%s: Unknown bpp\n", __FUNCTION__); 661 return NULL; 662 } 663 664 if (width == 0 || height == 0) 665 { 666 ErrorF ("%s: Zero width or height\n", __FUNCTION__); 667 return NULL; 668 } 669 670 qxl_get_formats (bpp, &format, &pformat); 671 stride = width * PIXMAN_FORMAT_BPP (pformat) / 8; 672 stride = (stride + 3) & ~3; 673 674 bo = calloc(1, sizeof(struct qxl_kms_bo)); 675 if (!bo) 676 return NULL; 677 678 param.format = format; 679 param.width = width; 680 param.height = height; 681 param.stride = -stride; 682 param.handle = 0; 683 ret = drmIoctl(qxl->drm_fd, 684 DRM_IOCTL_QXL_ALLOC_SURF, ¶m); 685 if (ret) 686 return NULL; 687 688 bo->name = "surface memory"; 689 bo->size = stride * height + stride; 690 bo->type = QXL_BO_SURF; 691 bo->handle = param.handle; 692 bo->qxl = qxl; 693 bo->refcnt = 1; 694 695 /* then fill out the driver surface */ 696 surface = calloc(1, sizeof *surface); 697 surface->bo = (struct qxl_bo *)bo; 698 surface->qxl = qxl; 699 surface->id = bo->handle; 700 surface->image_bo = NULL; 701 dev_ptr = qxl->bo_funcs->bo_map(surface->bo); 702 dev_addr 703 = (uint32_t *)((uint8_t *)dev_ptr + stride * (height - 1)); 704 surface->dev_image = pixman_image_create_bits ( 705 pformat, width, height, dev_addr, - stride); 706 707 surface->host_image = pixman_image_create_bits ( 708 pformat, width, height, NULL, -1); 709 REGION_INIT (NULL, &(surface->access_region), (BoxPtr)NULL, 0); 710 qxl->bo_funcs->bo_unmap(surface->bo); 711 surface->access_type = UXA_ACCESS_RO; 712 surface->bpp = bpp; 713 714 return surface; 715} 716 717static void qxl_kms_surface_destroy(qxl_surface_t *surf) 718{ 719 qxl_screen_t *qxl = surf->qxl; 720 721 if (surf->dev_image) 722 pixman_image_unref (surf->dev_image); 723 if (surf->host_image) 724 pixman_image_unref (surf->host_image); 725 726 if (surf->image_bo) 727 qxl->bo_funcs->bo_decref(qxl, surf->image_bo); 728 qxl->bo_funcs->bo_decref(qxl, surf->bo); 729 free(surf); 730} 731 732static void qxl_bo_output_surf_reloc(qxl_screen_t *qxl, uint32_t dst_offset, 733 struct qxl_bo *_dst_bo, qxl_surface_t *surf) 734{ 735 struct qxl_kms_bo *dst_bo = (struct qxl_kms_bo *)_dst_bo; 736 struct drm_qxl_reloc *r = &qxl->cmds.relocs[qxl->cmds.n_relocs]; 737 struct qxl_kms_bo *bo = (struct qxl_kms_bo *)surf->bo; 738 if (qxl->cmds.n_reloc_bos >= MAX_RELOCS || qxl->cmds.n_relocs >= MAX_RELOCS) 739 assert(0); 740 741 qxl->cmds.reloc_bo[qxl->cmds.n_reloc_bos] = surf->bo; 742 qxl->cmds.n_reloc_bos++; 743 bo->refcnt++; 744 745 /* fix the kernel names */ 746 r->reloc_type = QXL_RELOC_TYPE_SURF; 747 r->dst_handle = dst_bo->handle; 748 r->src_handle = bo->handle; 749 r->dst_offset = dst_offset; 750 r->src_offset = 0; 751 qxl->cmds.n_relocs++; 752} 753 754static struct qxl_bo_funcs qxl_kms_bo_funcs = { 755 qxl_bo_alloc, 756 qxl_cmd_alloc, 757 qxl_bo_map, 758 qxl_bo_unmap, 759 qxl_bo_decref, 760 qxl_bo_incref, 761 qxl_bo_output_bo_reloc, 762 qxl_bo_write_command, 763 qxl_bo_update_area, 764 qxl_bo_create_primary, 765 qxl_bo_destroy_primary, 766 qxl_kms_surface_create, 767 qxl_kms_surface_destroy, 768 qxl_bo_output_surf_reloc, 769}; 770 771void qxl_kms_setup_funcs(qxl_screen_t *qxl) 772{ 773 qxl->bo_funcs = &qxl_kms_bo_funcs; 774} 775 776uint32_t qxl_kms_bo_get_handle(struct qxl_bo *_bo) 777{ 778 struct qxl_kms_bo *bo = (struct qxl_kms_bo *)_bo; 779 780 return bo->handle; 781} 782#endif 783