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, &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
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, &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
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