Home | History | Annotate | Line # | Download | only in src
      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 
     35 Bool 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
     48 static 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 
     63 static 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 
    123 static Bool
    124 qxl_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 
    139 Bool 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 
    208 static Bool
    209 qxl_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 
    242 static Bool
    243 qxl_blank_screen (ScreenPtr pScreen, int mode)
    244 {
    245     return TRUE;
    246 }
    247 
    248 Bool
    249 qxl_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 
    275 void
    276 qxl_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 
    298 Bool 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 
    379 struct 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 
    390 static 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 
    421 static 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 
    443 static 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 
    479 static void qxl_bo_unmap(struct qxl_bo *_bo)
    480 {
    481 }
    482 
    483 static 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 
    489 static 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 
    516 static 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 
    540 static 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 
    574 static 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 
    593 static 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, &param);
    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 
    625 static 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 
    633 static qxl_surface_t *
    634 qxl_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, &param);
    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 
    717 static 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 
    732 static 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 
    754 static 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 
    771 void qxl_kms_setup_funcs(qxl_screen_t *qxl)
    772 {
    773     qxl->bo_funcs = &qxl_kms_bo_funcs;
    774 }
    775 
    776 uint32_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