diff options
author | Dave Airlie <airlied@gmail.com> | 2013-03-06 14:26:07 +1000 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2013-03-12 10:42:31 +1000 |
commit | 4897efe095c80fe5fa2f6e33b3d9c64542a4be20 (patch) | |
tree | 9261454dfc0a18812b031aa1937e65a3cbc7e58c | |
parent | 7a7b12762904eea329f678987565d89db56421b6 (diff) |
qxl: add KMS support v1.2qxl-kms
Avoid DRI create busid symbol for now.
fix warnings.
-rw-r--r-- | configure.ac | 26 | ||||
-rw-r--r-- | src/Makefile.am | 5 | ||||
-rw-r--r-- | src/qxl.h | 41 | ||||
-rw-r--r-- | src/qxl_driver.c | 104 | ||||
-rw-r--r-- | src/qxl_drmmode.c | 882 | ||||
-rw-r--r-- | src/qxl_drmmode.h | 83 | ||||
-rw-r--r-- | src/qxl_kms.c | 763 | ||||
-rw-r--r-- | src/qxl_surface.c | 87 | ||||
-rw-r--r-- | src/qxl_surface.h | 1 | ||||
-rw-r--r-- | src/qxl_surface_ums.c | 36 | ||||
-rw-r--r-- | src/qxl_uxa.c | 20 |
11 files changed, 1966 insertions, 82 deletions
diff --git a/configure.ac b/configure.ac index 48904a2..9ebdbd9 100644 --- a/configure.ac +++ b/configure.ac @@ -62,6 +62,7 @@ XORG_DRIVER_CHECK_EXT(XFreeXDGA, xf86dgaproto) # Obtain compiler/linker options for the driver dependencies PKG_CHECK_MODULES(XORG, [xorg-server >= 1.0.99.901] xproto fontsproto $REQUIRED_MODULES) + save_CFLAGS="$CFLAGS" CFLAGS="$XORG_CFLAGS" AC_CHECK_DECL(XSERVER_LIBPCIACCESS, @@ -69,12 +70,31 @@ AC_CHECK_DECL(XSERVER_LIBPCIACCESS, [#include "xorg-server.h"]) CFLAGS="$save_CFLAGS" +# Checks for libraries. +PKG_CHECK_MODULES(DRM, [libdrm >= 2.4.42]) + +AC_ARG_ENABLE(kms, + AS_HELP_STRING([--disable-kms], + [Disable KMS support [[default=enabled]]]), [DRM_MODE="$enableval"], + [DRM_MODE=yes]) + if test "x$XSERVER_LIBPCIACCESS" = xyes; then PKG_CHECK_MODULES([PCIACCESS], [pciaccess >= 0.10]) fi AM_CONDITIONAL(XSERVER_LIBPCIACCESS, test "x$XSERVER_LIBPCIACCESS" = xyes) - -# Checks for libraries. +save_CFLAGS="$CFLAGS" +CFLAGS="$DRM_CFLAGS $CFLAGS" +if test "x$DRM_MODE" = xyes; then + AC_CHECK_HEADER(xf86drmMode.h,[DRM_MODE=yes],[DRM_MODE=no],[#include <stdint.h> +#include <stdlib.h>]) + if test "x$DRM_MODE" = xyes; then + AC_DEFINE(XF86DRM_MODE,1,[DRM kernel modesetting]) + else + DRM_MODE=no + fi +fi +CFLAGS="$save_CFLAGS" +AM_CONDITIONAL(DRM_MODE, test x$DRM_MODE = xyes) enable_qxl=yes AC_ARG_ENABLE(xspice, @@ -134,6 +154,8 @@ echo " prefix: ${prefix} c compiler: ${CC} + drm: ${DRM_CFLAGS} + KMS: ${DRM_MODE} Build qxl: ${enable_qxl} Build xspice: ${enable_xspice} " diff --git a/src/Makefile.am b/src/Makefile.am index f9557da..8a4c5f7 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -27,7 +27,7 @@ SUBDIRS=uxa -AM_CFLAGS = $(SPICE_PROTOCOL_CFLAGS) $(XORG_CFLAGS) $(PCIACCESS_CFLAGS) $(CWARNFLAGS) +AM_CFLAGS = $(SPICE_PROTOCOL_CFLAGS) $(XORG_CFLAGS) $(PCIACCESS_CFLAGS) $(CWARNFLAGS) $(DRM_CFLAGS) if BUILD_QXL qxl_drv_la_LTLIBRARIES = qxl_drv.la @@ -56,6 +56,9 @@ qxl_drv_la_SOURCES = \ qxl_uxa.c \ qxl_ums_mode.c \ qxl_io.c \ + qxl_kms.c \ + qxl_drmmode.c \ + qxl_drmmode.h \ compat-api.h endif @@ -54,6 +54,8 @@ #include "vgaHW.h" #endif /* XSPICE */ +#include "qxl_drmmode.h" + #include "compat-api.h" #define hidden _X_HIDDEN @@ -171,11 +173,24 @@ struct qxl_bo_funcs { }; void qxl_ums_setup_funcs(qxl_screen_t *qxl); +void qxl_kms_setup_funcs(qxl_screen_t *qxl); /* ums specific functions */ struct qxl_bo *qxl_ums_surf_mem_alloc(qxl_screen_t *qxl, uint32_t size); struct qxl_bo *qxl_ums_lookup_phy_addr(qxl_screen_t *qxl, uint64_t phy_addr); +#ifdef XF86DRM_MODE +#define MAX_RELOCS 96 +#include "qxl_drm.h" + +struct qxl_cmd_stream { + struct qxl_bo *reloc_bo[MAX_RELOCS]; + int n_reloc_bos; + struct drm_qxl_reloc relocs[MAX_RELOCS]; + int n_relocs; +}; +#endif + struct _qxl_screen_t { /* These are the names QXL uses */ @@ -308,6 +323,14 @@ struct _qxl_screen_t struct xorg_list ums_bos; struct qxl_bo_funcs *bo_funcs; + + Bool kms_enabled; +#ifdef XF86DRM_MODE + drmmode_rec drmmode; + int drm_fd; + struct qxl_cmd_stream cmds; +#endif + }; typedef struct qxl_output_private { @@ -558,6 +581,24 @@ void qxl_io_flush_release (qxl_screen_t *qxl); */ Bool qxl_output_edid_set(xf86OutputPtr output, int head, DisplayModePtr mode); +Bool qxl_pre_init_common(ScrnInfoPtr pScrn); +Bool qxl_fb_init (qxl_screen_t *qxl, ScreenPtr pScreen); +Bool qxl_screen_init_kms(SCREEN_INIT_ARGS_DECL); +Bool qxl_enter_vt_kms (VT_FUNC_ARGS_DECL); +void qxl_leave_vt_kms (VT_FUNC_ARGS_DECL); +void qxl_set_screen_pixmap_header (ScreenPtr pScreen); +Bool qxl_resize_primary_to_virtual (qxl_screen_t *qxl); +void qxl_get_formats (int bpp, SpiceBitmapFmt *format, pixman_format_code_t *pformat); + +#ifdef XF86DRM_MODE +Bool qxl_pre_init_kms(ScrnInfoPtr pScrn, int flags); +Bool qxl_kms_check_cap(qxl_screen_t *qxl, int cap); +uint32_t qxl_kms_bo_get_handle(struct qxl_bo *_bo); +#else +static inline Bool qxl_pre_init_kms(ScrnInfoPtr pScrn, int flags) { return FALSE; } +static inline Bool qxl_kms_check_cap(qxl_screen_t *qxl, int cap) { return FALSE; } +#endif + #ifdef XSPICE /* device to spice-server, now xspice to spice-server */ void ioport_write(qxl_screen_t *qxl, uint32_t io_port, uint32_t val); diff --git a/src/qxl_driver.c b/src/qxl_driver.c index 7b59b2c..f52cb3d 100644 --- a/src/qxl_driver.c +++ b/src/qxl_driver.c @@ -453,8 +453,8 @@ qxl_close_screen (CLOSE_SCREEN_ARGS_DECL) return result; } -static void -set_screen_pixmap_header (ScreenPtr pScreen) +void +qxl_set_screen_pixmap_header (ScreenPtr pScreen) { ScrnInfoPtr pScrn = xf86ScreenToScrn (pScreen); qxl_screen_t *qxl = pScrn->driverPrivate; @@ -492,7 +492,7 @@ qxl_create_primary(qxl_screen_t *qxl) return qxl_surface_cache_create_primary (qxl, &qxl->primary_mode); } -static Bool +Bool qxl_resize_primary_to_virtual (qxl_screen_t *qxl) { ScreenPtr pScreen; @@ -506,16 +506,18 @@ qxl_resize_primary_to_virtual (qxl_screen_t *qxl) } ErrorF ("resizing primary to %dx%d\n", qxl->virtual_x, qxl->virtual_y); + + if (!qxl->kms_enabled) { + new_surface0_size = + qxl->virtual_x * qxl->pScrn->bitsPerPixel / 8 * qxl->virtual_y; - new_surface0_size = - qxl->virtual_x * qxl->pScrn->bitsPerPixel / 8 * qxl->virtual_y; - - if (new_surface0_size > qxl->surface0_size) - { - if (!qxl_resize_surface0 (qxl, new_surface0_size)) + if (new_surface0_size > qxl->surface0_size) { - ErrorF ("not resizing primary to virtual, leaving old virtual\n"); - return FALSE; + if (!qxl_resize_surface0 (qxl, new_surface0_size)) + { + ErrorF ("not resizing primary to virtual, leaving old virtual\n"); + return FALSE; + } } } @@ -546,7 +548,7 @@ qxl_resize_primary_to_virtual (qxl_screen_t *qxl) set_surface (root, qxl->primary); } - set_screen_pixmap_header (pScreen); + qxl_set_screen_pixmap_header (pScreen); } ErrorF ("primary is %p\n", qxl->primary); @@ -602,7 +604,7 @@ qxl_create_screen_resources (ScreenPtr pScreen) if (qxl->deferred_fps <= 0) #endif { - set_screen_pixmap_header (pScreen); + qxl_set_screen_pixmap_header (pScreen); if ((surf = get_surface (pPixmap))) qxl_surface_kill (surf); @@ -652,7 +654,7 @@ spiceqxl_screen_init (ScrnInfoPtr pScrn, qxl_screen_t *qxl) #endif -static Bool +Bool qxl_fb_init (qxl_screen_t *qxl, ScreenPtr pScreen) { ScrnInfoPtr pScrn = qxl->pScrn; @@ -955,7 +957,7 @@ qxl_check_device (ScrnInfoPtr pScrn, qxl_screen_t *qxl) #endif /* !XSPICE */ -static Bool +Bool qxl_pre_init_common(ScrnInfoPtr pScrn) { int scrnIndex = pScrn->scrnIndex; @@ -1033,7 +1035,7 @@ qxl_pre_init (ScrnInfoPtr pScrn, int flags) qxl->pScrn = pScrn; qxl->x_modes = NULL; qxl->entity = xf86GetEntityInfo (pScrn->entityList[0]); - + qxl->kms_enabled = FALSE; xorg_list_init(&qxl->ums_bos); #ifndef XSPICE @@ -1189,19 +1191,62 @@ qxl_identify (int flags) } static void -qxl_init_scrn (ScrnInfoPtr pScrn) +qxl_init_scrn (ScrnInfoPtr pScrn, Bool kms) { pScrn->driverVersion = 0; pScrn->driverName = QXL_DRIVER_NAME; pScrn->name = QXL_DRIVER_NAME; - pScrn->PreInit = qxl_pre_init; - pScrn->ScreenInit = qxl_screen_init; - pScrn->SwitchMode = qxl_switch_mode; - pScrn->ValidMode = NULL, + + if (kms) { + pScrn->PreInit = qxl_pre_init_kms; + pScrn->ScreenInit = qxl_screen_init_kms; + pScrn->EnterVT = qxl_enter_vt_kms; + pScrn->LeaveVT = qxl_leave_vt_kms; + } else { + pScrn->PreInit = qxl_pre_init; + pScrn->ScreenInit = qxl_screen_init; pScrn->EnterVT = qxl_enter_vt; - pScrn->LeaveVT = qxl_leave_vt; + pScrn->LeaveVT = qxl_leave_vt; + } + pScrn->SwitchMode = qxl_switch_mode; + pScrn->ValidMode = NULL; } +#ifdef XF86DRM_MODE +static char * +CreatePCIBusID(const struct pci_device *dev) +{ + char *busID; + + if (asprintf(&busID, "pci:%04x:%02x:%02x.%d", + dev->domain, dev->bus, dev->dev, dev->func) == -1) + return NULL; + + return busID; +} + +static Bool qxl_kernel_mode_enabled(ScrnInfoPtr pScrn, struct pci_device *pci_dev) +{ + char *busIdString; + int ret; + + busIdString = CreatePCIBusID(pci_dev); + ret = drmCheckModesettingSupported(busIdString); + free(busIdString); + if (ret) { + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 0, + "[KMS] drm report modesetting isn't supported.\n"); + return FALSE; + } + + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 0, + "[KMS] Kernel modesetting enabled.\n"); + return TRUE; +} +#else +#define radeon_kernel_mode_enabled(x, y) FALSE +#endif + #ifdef XSPICE static Bool qxl_probe (struct _DriverRec *drv, int flags) @@ -1215,7 +1260,7 @@ qxl_probe (struct _DriverRec *drv, int flags) return TRUE; pScrn = xf86AllocateScreen (drv, flags); - qxl_init_scrn (pScrn); + qxl_init_scrn (pScrn, FALSE); xf86MatchDevice (QXL_DRIVER_NAME, &device); entityIndex = xf86ClaimNoSlot (drv, 0, device[0], TRUE); @@ -1273,7 +1318,7 @@ qxl_probe (DriverPtr drv, int flags) ScrnInfoPtr pScrn = NULL; if ((pScrn = xf86ConfigPciEntity (pScrn, 0, usedChips[i], qxlPciChips, 0, 0, 0, 0, 0))) - qxl_init_scrn (pScrn); + qxl_init_scrn (pScrn, FALSE); } xfree (usedChips); @@ -1288,16 +1333,23 @@ qxl_pci_probe (DriverPtr drv, int entity, struct pci_device *dev, intptr_t match qxl_screen_t *qxl; ScrnInfoPtr pScrn = xf86ConfigPciEntity (NULL, 0, entity, NULL, NULL, NULL, NULL, NULL, NULL); + Bool kms = FALSE; if (!pScrn) return FALSE; - + + if (dev) { + if (qxl_kernel_mode_enabled(pScrn, dev)) { + kms = TRUE; + } + } + if (!pScrn->driverPrivate) pScrn->driverPrivate = xnfcalloc (sizeof (qxl_screen_t), 1); qxl = pScrn->driverPrivate; qxl->pci = dev; - qxl_init_scrn (pScrn); + qxl_init_scrn (pScrn, kms); return TRUE; } diff --git a/src/qxl_drmmode.c b/src/qxl_drmmode.c new file mode 100644 index 0000000..c248b64 --- /dev/null +++ b/src/qxl_drmmode.c @@ -0,0 +1,882 @@ +/* + * Copyright © 2007 Red Hat, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Authors: + * Dave Airlie <airlied@redhat.com> + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <errno.h> +#ifdef XF86DRM_MODE + +#include <sys/ioctl.h> +#include "qxl_drmmode.h" +#include "X11/Xatom.h" +#include "xf86DDC.h" +/* DPMS */ +#ifdef HAVE_XEXTPROTO_71 +#include <X11/extensions/dpmsconst.h> +#else +#define DPMS_SERVER +#include <X11/extensions/dpms.h> +#endif + +#include "qxl.h" +#include "qxl_surface.h" +static void +drmmode_ConvertFromKMode(ScrnInfoPtr scrn, + drmModeModeInfo *kmode, + DisplayModePtr mode) +{ + memset(mode, 0, sizeof(DisplayModeRec)); + mode->status = MODE_OK; + + mode->Clock = kmode->clock; + + mode->HDisplay = kmode->hdisplay; + mode->HSyncStart = kmode->hsync_start; + mode->HSyncEnd = kmode->hsync_end; + mode->HTotal = kmode->htotal; + mode->HSkew = kmode->hskew; + + mode->VDisplay = kmode->vdisplay; + mode->VSyncStart = kmode->vsync_start; + mode->VSyncEnd = kmode->vsync_end; + mode->VTotal = kmode->vtotal; + mode->VScan = kmode->vscan; + + mode->Flags = kmode->flags; //& FLAG_BITS; + mode->name = strdup(kmode->name); + + if (kmode->type & DRM_MODE_TYPE_DRIVER) + mode->type = M_T_DRIVER; + if (kmode->type & DRM_MODE_TYPE_PREFERRED) + mode->type |= M_T_PREFERRED; + xf86SetModeCrtc (mode, scrn->adjustFlags); +} + +static void +drmmode_ConvertToKMode(ScrnInfoPtr scrn, + drmModeModeInfo *kmode, + DisplayModePtr mode) +{ + memset(kmode, 0, sizeof(*kmode)); + + kmode->clock = mode->Clock; + kmode->hdisplay = mode->HDisplay; + kmode->hsync_start = mode->HSyncStart; + kmode->hsync_end = mode->HSyncEnd; + kmode->htotal = mode->HTotal; + kmode->hskew = mode->HSkew; + + kmode->vdisplay = mode->VDisplay; + kmode->vsync_start = mode->VSyncStart; + kmode->vsync_end = mode->VSyncEnd; + kmode->vtotal = mode->VTotal; + kmode->vscan = mode->VScan; + + kmode->flags = mode->Flags; //& FLAG_BITS; + if (mode->name) + strncpy(kmode->name, mode->name, DRM_DISPLAY_MODE_LEN); + kmode->name[DRM_DISPLAY_MODE_LEN-1] = 0; + +} + + +static void +drmmode_crtc_dpms(xf86CrtcPtr crtc, int mode) +{ + drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; +// drmmode_ptr drmmode = drmmode_crtc->drmmode; + + drmmode_crtc->dpms_mode = mode; + +#if 0 + /* bonghits in the randr 1.2 - uses dpms to disable crtc - bad buzz */ + if (mode == DPMSModeOff) { +// drmModeSetCrtc(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, +// 0, 0, 0, NULL, 0, NULL); + } +#endif +} + +static Bool +drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode, + Rotation rotation, int x, int y) +{ + ScrnInfoPtr pScrn = crtc->scrn; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn); + drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; + drmmode_ptr drmmode = drmmode_crtc->drmmode; + int saved_x, saved_y; + Rotation saved_rotation; + DisplayModeRec saved_mode; + uint32_t *output_ids; + int output_count = 0; + Bool ret = TRUE; + int i; + int fb_id; + drmModeModeInfo kmode; + int pitch; + int height; + qxl_screen_t *qxl = crtc->scrn->driverPrivate; + + pitch = pScrn->displayWidth * ((pScrn->bitsPerPixel + 7) >> 3); + height = pScrn->virtualY; + if (drmmode->fb_id == 0) { + ret = drmModeAddFB(drmmode->fd, + pScrn->virtualX, height, + pScrn->depth, pScrn->bitsPerPixel, + pitch, + qxl_kms_bo_get_handle(qxl->primary->bo), + &drmmode->fb_id); + if (ret < 0) { + ErrorF("failed to add fb\n"); + return FALSE; + } + } + + saved_mode = crtc->mode; + saved_x = crtc->x; + saved_y = crtc->y; + saved_rotation = crtc->rotation; + + if (mode) { + crtc->mode = *mode; + crtc->x = x; + crtc->y = y; + crtc->rotation = rotation; +#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,5,99,0,0) + crtc->transformPresent = FALSE; +#endif + } + + output_ids = calloc(sizeof(uint32_t), xf86_config->num_output); + if (!output_ids) { + ret = FALSE; + goto done; + } + + if (mode) { + for (i = 0; i < xf86_config->num_output; i++) { + xf86OutputPtr output = xf86_config->output[i]; + drmmode_output_private_ptr drmmode_output; + + if (output->crtc != crtc) + continue; + + drmmode_output = output->driver_private; + output_ids[output_count] = drmmode_output->mode_output->connector_id; + output_count++; + } + + if (!xf86CrtcRotate(crtc)) { + goto done; + } +#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,7,0,0,0) + crtc->funcs->gamma_set(crtc, crtc->gamma_red, crtc->gamma_green, + crtc->gamma_blue, crtc->gamma_size); +#endif + + drmmode_ConvertToKMode(crtc->scrn, &kmode, mode); + + fb_id = drmmode->fb_id; + if (drmmode_crtc->rotate_fb_id) { + fb_id = drmmode_crtc->rotate_fb_id; + x = y = 0; + } + ret = drmModeSetCrtc(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, + fb_id, x, y, output_ids, output_count, &kmode); + if (ret) + xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR, + "failed to set mode: %s", strerror(-ret)); + else + ret = TRUE; + + if (crtc->scrn->pScreen) + xf86CrtcSetScreenSubpixelOrder(crtc->scrn->pScreen); + /* go through all the outputs and force DPMS them back on? */ + for (i = 0; i < xf86_config->num_output; i++) { + xf86OutputPtr output = xf86_config->output[i]; + + if (output->crtc != crtc) + continue; + + output->funcs->dpms(output, DPMSModeOn); + } + } + +#if 0 + if (pScrn->pScreen && + !xf86ReturnOptValBool(info->Options, OPTION_SW_CURSOR, FALSE)) + xf86_reload_cursors(pScrn->pScreen); +#endif + +done: + if (!ret) { + crtc->x = saved_x; + crtc->y = saved_y; + crtc->rotation = saved_rotation; + crtc->mode = saved_mode; + } +#if defined(XF86_CRTC_VERSION) && XF86_CRTC_VERSION >= 3 + else + crtc->active = TRUE; +#endif + + return ret; +} + +static void +drmmode_set_cursor_colors (xf86CrtcPtr crtc, int bg, int fg) +{ + +} + +static void +drmmode_set_cursor_position (xf86CrtcPtr crtc, int x, int y) +{ + drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; + drmmode_ptr drmmode = drmmode_crtc->drmmode; + + drmModeMoveCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, x, y); +} + +static void +drmmode_show_cursor (xf86CrtcPtr crtc) +{ + drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; + drmmode_ptr drmmode = drmmode_crtc->drmmode; + uint32_t handle = qxl_kms_bo_get_handle(drmmode_crtc->cursor_bo); + + drmModeSetCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, handle, 64, 64); +} + +static void +drmmode_load_cursor_argb (xf86CrtcPtr crtc, CARD32 *image) +{ + drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; + drmmode_ptr drmmode = drmmode_crtc->drmmode; + int i; + uint32_t *ptr; + + /* cursor should be mapped already */ + ptr = (uint32_t *)(drmmode_crtc->cursor_ptr); + + for (i = 0; i < 64 * 64; i++) + ptr[i] = image[i]; + + drmmode_show_cursor(crtc); +} + +static void +drmmode_hide_cursor (xf86CrtcPtr crtc) +{ + drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; + drmmode_ptr drmmode = drmmode_crtc->drmmode; + int ret; + + drmModeSetCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, 0, 64, 64); +} + +static void +drmmode_crtc_gamma_set(xf86CrtcPtr crtc, uint16_t *red, uint16_t *green, + uint16_t *blue, int size) +{ + drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; + drmmode_ptr drmmode = drmmode_crtc->drmmode; + + drmModeCrtcSetGamma(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, + size, red, green, blue); +} +static const xf86CrtcFuncsRec drmmode_crtc_funcs = { + .dpms = drmmode_crtc_dpms, + .set_mode_major = drmmode_set_mode_major, + .set_cursor_colors = drmmode_set_cursor_colors, + .set_cursor_position = drmmode_set_cursor_position, + .show_cursor = drmmode_show_cursor, + .hide_cursor = drmmode_hide_cursor, + .load_cursor_argb = drmmode_load_cursor_argb, + + .gamma_set = drmmode_crtc_gamma_set, + .destroy = NULL, /* XXX */ +}; + +static void +drmmode_crtc_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int num) +{ + qxl_screen_t *qxl = pScrn->driverPrivate; + xf86CrtcPtr crtc; + drmmode_crtc_private_ptr drmmode_crtc; + + crtc = xf86CrtcCreate(pScrn, &drmmode_crtc_funcs); + if (crtc == NULL) + return; + + drmmode_crtc = xnfcalloc(sizeof(drmmode_crtc_private_rec), 1); + drmmode_crtc->mode_crtc = drmModeGetCrtc(drmmode->fd, drmmode->mode_res->crtcs[num]); + drmmode_crtc->drmmode = drmmode; + crtc->driver_private = drmmode_crtc; + + { + int cursor_size = 64*4*64; + + drmmode_crtc->cursor_bo = qxl->bo_funcs->bo_alloc(qxl, cursor_size, "cursor"); + if (!drmmode_crtc->cursor_bo) { + ErrorF("failed to allocate cursor buffer\n"); + return; + } + + drmmode_crtc->cursor_ptr = qxl->bo_funcs->bo_map(drmmode_crtc->cursor_bo); + } + + return; +} + + +static xf86OutputStatus +drmmode_output_detect(xf86OutputPtr output) +{ + /* go to the hw and retrieve a new output struct */ + drmmode_output_private_ptr drmmode_output = output->driver_private; + drmmode_ptr drmmode = drmmode_output->drmmode; + xf86OutputStatus status; + drmModeFreeConnector(drmmode_output->mode_output); + + drmmode_output->mode_output = drmModeGetConnector(drmmode->fd, drmmode_output->output_id); + + switch (drmmode_output->mode_output->connection) { + case DRM_MODE_CONNECTED: + status = XF86OutputStatusConnected; + break; + case DRM_MODE_DISCONNECTED: + status = XF86OutputStatusDisconnected; + break; + default: + case DRM_MODE_UNKNOWNCONNECTION: + status = XF86OutputStatusUnknown; + break; + } + return status; +} + +static Bool +drmmode_output_mode_valid(xf86OutputPtr output, DisplayModePtr pModes) +{ + return MODE_OK; +} + +static DisplayModePtr +drmmode_output_get_modes(xf86OutputPtr output) +{ + drmmode_output_private_ptr drmmode_output = output->driver_private; + drmModeConnectorPtr koutput = drmmode_output->mode_output; + drmmode_ptr drmmode = drmmode_output->drmmode; + int i; + DisplayModePtr Modes = NULL, Mode; + drmModePropertyPtr props; + xf86MonPtr mon = NULL; + + /* look for an EDID property */ + for (i = 0; i < koutput->count_props; i++) { + props = drmModeGetProperty(drmmode->fd, koutput->props[i]); + if (props && (props->flags & DRM_MODE_PROP_BLOB)) { + if (!strcmp(props->name, "EDID")) { + if (drmmode_output->edid_blob) + drmModeFreePropertyBlob(drmmode_output->edid_blob); + drmmode_output->edid_blob = drmModeGetPropertyBlob(drmmode->fd, koutput->prop_values[i]); + } + drmModeFreeProperty(props); + } + } + + if (drmmode_output->edid_blob) { + mon = xf86InterpretEDID(output->scrn->scrnIndex, + drmmode_output->edid_blob->data); + if (mon && drmmode_output->edid_blob->length > 128) + mon->flags |= MONITOR_EDID_COMPLETE_RAWDATA; + } + xf86OutputSetEDID(output, mon); + + /* modes should already be available */ + for (i = 0; i < koutput->count_modes; i++) { + Mode = xnfalloc(sizeof(DisplayModeRec)); + + drmmode_ConvertFromKMode(output->scrn, &koutput->modes[i], Mode); + Modes = xf86ModesAdd(Modes, Mode); + + } + return Modes; +} + +static void +drmmode_output_destroy(xf86OutputPtr output) +{ + drmmode_output_private_ptr drmmode_output = output->driver_private; + int i; + + if (drmmode_output->edid_blob) + drmModeFreePropertyBlob(drmmode_output->edid_blob); + for (i = 0; i < drmmode_output->num_props; i++) { + drmModeFreeProperty(drmmode_output->props[i].mode_prop); + free(drmmode_output->props[i].atoms); + } + for (i = 0; i < drmmode_output->mode_output->count_encoders; i++) { + drmModeFreeEncoder(drmmode_output->mode_encoders[i]); + free(drmmode_output->mode_encoders); + } + free(drmmode_output->props); + drmModeFreeConnector(drmmode_output->mode_output); + free(drmmode_output); + output->driver_private = NULL; +} + +static void +drmmode_output_dpms(xf86OutputPtr output, int mode) +{ + drmmode_output_private_ptr drmmode_output = output->driver_private; + drmModeConnectorPtr koutput = drmmode_output->mode_output; + drmmode_ptr drmmode = drmmode_output->drmmode; + + drmModeConnectorSetProperty(drmmode->fd, koutput->connector_id, + drmmode_output->dpms_enum_id, mode); + return; +} + + +static Bool +drmmode_property_ignore(drmModePropertyPtr prop) +{ + if (!prop) + return TRUE; + /* ignore blob prop */ + if (prop->flags & DRM_MODE_PROP_BLOB) + return TRUE; + /* ignore standard property */ + if (!strcmp(prop->name, "EDID") || + !strcmp(prop->name, "DPMS")) + return TRUE; + + return FALSE; +} + +static void +drmmode_output_create_resources(xf86OutputPtr output) +{ + drmmode_output_private_ptr drmmode_output = output->driver_private; + drmModeConnectorPtr mode_output = drmmode_output->mode_output; + drmmode_ptr drmmode = drmmode_output->drmmode; + drmModePropertyPtr drmmode_prop; + int i, j, err; + + drmmode_output->props = calloc(mode_output->count_props, sizeof(drmmode_prop_rec)); + if (!drmmode_output->props) + return; + + drmmode_output->num_props = 0; + for (i = 0, j = 0; i < mode_output->count_props; i++) { + drmmode_prop = drmModeGetProperty(drmmode->fd, mode_output->props[i]); + if (drmmode_property_ignore(drmmode_prop)) { + drmModeFreeProperty(drmmode_prop); + continue; + } + drmmode_output->props[j].mode_prop = drmmode_prop; + drmmode_output->props[j].value = mode_output->prop_values[i]; + drmmode_output->num_props++; + j++; + } + + for (i = 0; i < drmmode_output->num_props; i++) { + drmmode_prop_ptr p = &drmmode_output->props[i]; + drmmode_prop = p->mode_prop; + + if (drmmode_prop->flags & DRM_MODE_PROP_RANGE) { + INT32 range[2]; + INT32 value = p->value; + + p->num_atoms = 1; + p->atoms = calloc(p->num_atoms, sizeof(Atom)); + if (!p->atoms) + continue; + p->atoms[0] = MakeAtom(drmmode_prop->name, strlen(drmmode_prop->name), TRUE); + range[0] = drmmode_prop->values[0]; + range[1] = drmmode_prop->values[1]; + err = RRConfigureOutputProperty(output->randr_output, p->atoms[0], + FALSE, TRUE, + drmmode_prop->flags & DRM_MODE_PROP_IMMUTABLE ? TRUE : FALSE, + 2, range); + if (err != 0) { + xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, + "RRConfigureOutputProperty error, %d\n", err); + } + err = RRChangeOutputProperty(output->randr_output, p->atoms[0], + XA_INTEGER, 32, PropModeReplace, 1, &value, FALSE, TRUE); + if (err != 0) { + xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, + "RRChangeOutputProperty error, %d\n", err); + } + } else if (drmmode_prop->flags & DRM_MODE_PROP_ENUM) { + p->num_atoms = drmmode_prop->count_enums + 1; + p->atoms = calloc(p->num_atoms, sizeof(Atom)); + if (!p->atoms) + continue; + p->atoms[0] = MakeAtom(drmmode_prop->name, strlen(drmmode_prop->name), TRUE); + for (j = 1; j <= drmmode_prop->count_enums; j++) { + struct drm_mode_property_enum *e = &drmmode_prop->enums[j-1]; + p->atoms[j] = MakeAtom(e->name, strlen(e->name), TRUE); + } + err = RRConfigureOutputProperty(output->randr_output, p->atoms[0], + FALSE, FALSE, + drmmode_prop->flags & DRM_MODE_PROP_IMMUTABLE ? TRUE : FALSE, + p->num_atoms - 1, (INT32 *)&p->atoms[1]); + if (err != 0) { + xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, + "RRConfigureOutputProperty error, %d\n", err); + } + for (j = 0; j < drmmode_prop->count_enums; j++) + if (drmmode_prop->enums[j].value == p->value) + break; + /* there's always a matching value */ + err = RRChangeOutputProperty(output->randr_output, p->atoms[0], + XA_ATOM, 32, PropModeReplace, 1, &p->atoms[j+1], FALSE, TRUE); + if (err != 0) { + xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, + "RRChangeOutputProperty error, %d\n", err); + } + } + } +} + +static Bool +drmmode_output_set_property(xf86OutputPtr output, Atom property, + RRPropertyValuePtr value) +{ + drmmode_output_private_ptr drmmode_output = output->driver_private; + drmmode_ptr drmmode = drmmode_output->drmmode; + int i; + + for (i = 0; i < drmmode_output->num_props; i++) { + drmmode_prop_ptr p = &drmmode_output->props[i]; + + if (p->atoms[0] != property) + continue; + + if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) { + uint32_t val; + + if (value->type != XA_INTEGER || value->format != 32 || + value->size != 1) + return FALSE; + val = *(uint32_t *)value->data; + + drmModeConnectorSetProperty(drmmode->fd, drmmode_output->output_id, + p->mode_prop->prop_id, (uint64_t)val); + return TRUE; + } else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) { + Atom atom; + const char *name; + int j; + + if (value->type != XA_ATOM || value->format != 32 || value->size != 1) + return FALSE; + memcpy(&atom, value->data, 4); + name = NameForAtom(atom); + + /* search for matching name string, then set its value down */ + for (j = 0; j < p->mode_prop->count_enums; j++) { + if (!strcmp(p->mode_prop->enums[j].name, name)) { + drmModeConnectorSetProperty(drmmode->fd, drmmode_output->output_id, + p->mode_prop->prop_id, p->mode_prop->enums[j].value); + return TRUE; + } + } + } + } + + return TRUE; +} + +static Bool +drmmode_output_get_property(xf86OutputPtr output, Atom property) +{ + return TRUE; +} + +static const xf86OutputFuncsRec drmmode_output_funcs = { + .dpms = drmmode_output_dpms, + .create_resources = drmmode_output_create_resources, +#ifdef RANDR_12_INTERFACE + .set_property = drmmode_output_set_property, + .get_property = drmmode_output_get_property, +#endif +#if 0 + + .save = drmmode_crt_save, + .restore = drmmode_crt_restore, + .mode_fixup = drmmode_crt_mode_fixup, + .prepare = drmmode_output_prepare, + .mode_set = drmmode_crt_mode_set, + .commit = drmmode_output_commit, +#endif + .detect = drmmode_output_detect, + .mode_valid = drmmode_output_mode_valid, + + .get_modes = drmmode_output_get_modes, + .destroy = drmmode_output_destroy +}; + +static int subpixel_conv_table[7] = { 0, SubPixelUnknown, + SubPixelHorizontalRGB, + SubPixelHorizontalBGR, + SubPixelVerticalRGB, + SubPixelVerticalBGR, + SubPixelNone }; + +const char *output_names[] = { "None", + "VGA", + "DVI", + "DVI", + "DVI", + "Composite", + "S-video", + "LVDS", + "CTV", + "DIN", + "DisplayPort", + "HDMI", + "HDMI", + "TV", + "eDP", + "Virtual" +}; + +static void +drmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int num) +{ + xf86OutputPtr output; + drmModeConnectorPtr koutput; + drmModeEncoderPtr *kencoders = NULL; + drmmode_output_private_ptr drmmode_output; + drmModePropertyPtr props; + char name[32]; + int i; + const char *s; + + koutput = drmModeGetConnector(drmmode->fd, drmmode->mode_res->connectors[num]); + if (!koutput) + return; + + kencoders = calloc(sizeof(drmModeEncoderPtr), koutput->count_encoders); + if (!kencoders) { + goto out_free_encoders; + } + + for (i = 0; i < koutput->count_encoders; i++) { + kencoders[i] = drmModeGetEncoder(drmmode->fd, koutput->encoders[i]); + if (!kencoders[i]) { + goto out_free_encoders; + } + } + + /* need to do smart conversion here for compat with non-kms ATI driver */ + snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], koutput->connector_type_id - 1); + + + output = xf86OutputCreate (pScrn, &drmmode_output_funcs, name); + if (!output) { + goto out_free_encoders; + } + + drmmode_output = calloc(sizeof(drmmode_output_private_rec), 1); + if (!drmmode_output) { + xf86OutputDestroy(output); + goto out_free_encoders; + } + + drmmode_output->output_id = drmmode->mode_res->connectors[num]; + drmmode_output->mode_output = koutput; + drmmode_output->mode_encoders = kencoders; + drmmode_output->drmmode = drmmode; + output->mm_width = koutput->mmWidth; + output->mm_height = koutput->mmHeight; + + output->subpixel_order = subpixel_conv_table[koutput->subpixel]; + output->interlaceAllowed = TRUE; + output->doubleScanAllowed = TRUE; + output->driver_private = drmmode_output; + + output->possible_crtcs = 0xffffffff; + for (i = 0; i < koutput->count_encoders; i++) { + output->possible_crtcs &= kencoders[i]->possible_crtcs; + } + /* work out the possible clones later */ + output->possible_clones = 0; + + for (i = 0; i < koutput->count_props; i++) { + props = drmModeGetProperty(drmmode->fd, koutput->props[i]); + if (props && (props->flags & DRM_MODE_PROP_ENUM)) { + if (!strcmp(props->name, "DPMS")) { + drmmode_output->dpms_enum_id = koutput->props[i]; + drmModeFreeProperty(props); + break; + } + drmModeFreeProperty(props); + } + } + + return; +out_free_encoders: + if (kencoders){ + for (i = 0; i < koutput->count_encoders; i++) + drmModeFreeEncoder(kencoders[i]); + free(kencoders); + } + drmModeFreeConnector(koutput); + +} + +static Bool +drmmode_xf86crtc_resize (ScrnInfoPtr scrn, int width, int height) +{ + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); + drmmode_crtc_private_ptr + drmmode_crtc = xf86_config->crtc[0]->driver_private; + drmmode_ptr drmmode = drmmode_crtc->drmmode; + ScreenPtr screen = xf86ScrnToScreen(scrn); + PixmapPtr ppix = screen->GetScreenPixmap(screen); + struct qxl_bo *old_front = NULL; + struct qxl_bo *front_bo; + qxl_screen_t *qxl = scrn->driverPrivate; + int cpp = (scrn->bitsPerPixel + 7) / 8; + int32_t pitch, old_pitch; + int ret, i; + uint32_t old_width, old_height, old_stride, old_fb_id; + if (scrn->virtualX == width && scrn->virtualY == height) + return TRUE; + + xf86DrvMsg(scrn->scrnIndex, X_INFO, + "Allocate new frame buffer %dx%d stride\n", + width, height); + + front_bo = qxl->primary->bo; + + pitch = width * cpp; + old_width = scrn->virtualX; + old_height = scrn->virtualY; + old_pitch = scrn->displayWidth; + old_fb_id = drmmode->fb_id; + old_front = front_bo; + + scrn->virtualX = width; + scrn->virtualY = height; + scrn->displayWidth = pitch / cpp; + + qxl->primary->bo = qxl->bo_funcs->create_primary(qxl, width, height, pitch, SPICE_SURFACE_FMT_32_xRGB); + if (!qxl->primary->bo) + goto fail; + + ret = drmModeAddFB(drmmode->fd, + width, height, + scrn->depth, scrn->bitsPerPixel, + pitch, + qxl_kms_bo_get_handle(qxl->primary->bo), + &drmmode->fb_id); + if (ret) + goto fail; + + for (i = 0; i < xf86_config->num_crtc; i++) { + xf86CrtcPtr crtc = xf86_config->crtc[i]; + if (!crtc->enabled) + continue; + drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation, + crtc->x, crtc->y); + } + + { + void *dev_ptr = qxl->bo_funcs->bo_map(qxl->primary->bo); + uint32_t *dev_addr; + int format = scrn->bitsPerPixel == 16 ? PIXMAN_x1r5g5b5 : PIXMAN_x8r8g8b8; + dev_addr + = (uint32_t *)((uint8_t *)dev_ptr + pitch * (height - 1)); + pixman_image_unref(qxl->primary->dev_image); + pixman_image_unref (qxl->primary->host_image); + + qxl->primary->dev_image = pixman_image_create_bits (format, + width, + height, + (uint32_t *)dev_addr, pitch); + + } + + /* fixup the surfaces */ + + if (old_fb_id) + drmModeRmFB(drmmode->fd, old_fb_id); + if (old_front) + qxl->bo_funcs->bo_decref(qxl, old_front); + + return TRUE; +fail: + qxl->primary->bo = old_front; + scrn->virtualX = old_width; + scrn->virtualY = old_height; + scrn->displayWidth = old_pitch; + drmmode->fb_id = old_fb_id; + return FALSE; +} + + +static const xf86CrtcConfigFuncsRec drmmode_xf86crtc_config_funcs = { + drmmode_xf86crtc_resize, +}; + +Bool drmmode_pre_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int cpp) +{ + xf86CrtcConfigPtr xf86_config; + int i; + + xf86CrtcConfigInit(pScrn, &drmmode_xf86crtc_config_funcs); + xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); + + drmmode->scrn = pScrn; + drmmode->cpp = cpp; + drmmode->mode_res = drmModeGetResources(drmmode->fd); + if (!drmmode->mode_res) + return FALSE; + + xf86CrtcSetSizeRange(pScrn, 320, 200, drmmode->mode_res->max_width, drmmode->mode_res->max_height); + for (i = 0; i < drmmode->mode_res->count_crtcs; i++) + drmmode_crtc_init(pScrn, drmmode, i); + + for (i = 0; i < drmmode->mode_res->count_connectors; i++) + drmmode_output_init(pScrn, drmmode, i); + + xf86InitialConfiguration(pScrn, TRUE); + + return TRUE; +} + +#endif diff --git a/src/qxl_drmmode.h b/src/qxl_drmmode.h new file mode 100644 index 0000000..df076c7 --- /dev/null +++ b/src/qxl_drmmode.h @@ -0,0 +1,83 @@ +/* + * Copyright © 2007 Red Hat, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Authors: + * Dave Airlie <airlied@redhat.com> + * + */ +#ifndef DRMMODE_DISPLAY_H +#define DRMMODE_DISPLAY_H + +#ifdef XF86DRM_MODE + +#include "xf86drm.h" +#include "xf86drmMode.h" +#include "xf86str.h" +#include "randrstr.h" +#include "xf86Crtc.h" + +typedef struct { + int fd; + unsigned fb_id; + drmModeResPtr mode_res; + drmModeFBPtr mode_fb; + int cpp; + ScrnInfoPtr scrn; +} drmmode_rec, *drmmode_ptr; + +typedef struct { + drmmode_ptr drmmode; + drmModeCrtcPtr mode_crtc; + int hw_id; + struct qxl_bo *cursor_bo; + void *cursor_ptr; + // struct radeon_bo *rotate_bo; + unsigned rotate_fb_id; + int dpms_mode; + uint16_t lut_r[256], lut_g[256], lut_b[256]; +} drmmode_crtc_private_rec, *drmmode_crtc_private_ptr; + + +typedef struct { + drmModePropertyPtr mode_prop; + uint64_t value; + int num_atoms; /* if range prop, num_atoms == 1; if enum prop, num_atoms == num_enums + 1 */ + Atom *atoms; +} drmmode_prop_rec, *drmmode_prop_ptr; + +typedef struct { + drmmode_ptr drmmode; + int output_id; + drmModeConnectorPtr mode_output; + drmModeEncoderPtr *mode_encoders; + drmModePropertyBlobPtr edid_blob; + int dpms_enum_id; + int num_props; + drmmode_prop_ptr props; + int enc_mask; + int enc_clone_mask; +} drmmode_output_private_rec, *drmmode_output_private_ptr; + +extern Bool drmmode_pre_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int cpp); +#endif + +#endif diff --git a/src/qxl_kms.c b/src/qxl_kms.c new file mode 100644 index 0000000..b673294 --- /dev/null +++ b/src/qxl_kms.c @@ -0,0 +1,763 @@ +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#ifdef XF86DRM_MODE +#include <fcntl.h> +#include <sys/mman.h> +#include <errno.h> +#include "qxl.h" + +#include "qxl_surface.h" + +Bool qxl_kms_check_cap(qxl_screen_t *qxl, int idx) +{ + int ret; + struct drm_qxl_clientcap cap; + + cap.index = idx; + ret = drmIoctl(qxl->drm_fd, DRM_IOCTL_QXL_CLIENTCAP, &cap); + if (ret == 0) + return TRUE; + return FALSE; +} + +#if 0 +static Bool qxl_kms_getparam(qxl_screen_t *qxl, uint64_t param, uint64_t *value) +{ + int ret; + struct drm_qxl_getparam args = {0}; + + args.param = param; + ret = drmIoctl(qxl->drm_fd, DRM_IOCTL_QXL_GETPARAM, &args); + if (ret != 0) + return FALSE; + + *value = args.value; + return TRUE; +} +#endif + +static Bool qxl_open_drm_master(ScrnInfoPtr pScrn) +{ + qxl_screen_t *qxl = pScrn->driverPrivate; + struct pci_device *dev = qxl->pci; + char *busid; + drmSetVersion sv; + int err; + +#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,9,99,901,0) + XNFasprintf(&busid, "pci:%04x:%02x:%02x.%d", + dev->domain, dev->bus, dev->dev, dev->func); +#else + busid = XNFprintf("pci:%04x:%02x:%02x.%d", + dev->domain, dev->bus, dev->dev, dev->func); +#endif + + qxl->drm_fd = drmOpen("qxl", busid); + if (qxl->drm_fd == -1) { + + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "[drm] Failed to open DRM device for %s: %s\n", + busid, strerror(errno)); + free(busid); + return FALSE; + } + free(busid); + + /* Check that what we opened was a master or a master-capable FD, + * by setting the version of the interface we'll use to talk to it. + * (see DRIOpenDRMMaster() in DRI1) + */ + sv.drm_di_major = 1; + sv.drm_di_minor = 1; + sv.drm_dd_major = -1; + sv.drm_dd_minor = -1; + err = drmSetInterfaceVersion(qxl->drm_fd, &sv); + if (err != 0) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "[drm] failed to set drm interface version.\n"); + drmClose(qxl->drm_fd); + qxl->drm_fd = -1; + + return FALSE; + } + + out: + qxl->drmmode.fd = qxl->drm_fd; + return TRUE; +} + +static Bool +qxl_close_screen_kms (CLOSE_SCREEN_ARGS_DECL) +{ + ScrnInfoPtr pScrn = xf86ScreenToScrn (pScreen); + qxl_screen_t *qxl = pScrn->driverPrivate; + Bool result; + + pScreen->CloseScreen = qxl->close_screen; + + result = pScreen->CloseScreen (CLOSE_SCREEN_ARGS); + + return result; +} + + +Bool qxl_pre_init_kms(ScrnInfoPtr pScrn, int flags) +{ + int scrnIndex = pScrn->scrnIndex; + qxl_screen_t *qxl = NULL; + + if (!pScrn->confScreen) + return FALSE; + + /* zaphod mode is for suckers and i choose not to implement it */ + if (xf86IsEntityShared (pScrn->entityList[0])) + { + xf86DrvMsg (scrnIndex, X_ERROR, "No Zaphod mode for you\n"); + return FALSE; + } + + if (!pScrn->driverPrivate) + pScrn->driverPrivate = xnfcalloc (sizeof (qxl_screen_t), 1); + + qxl = pScrn->driverPrivate; + qxl->device_primary = QXL_DEVICE_PRIMARY_UNDEFINED; + qxl->pScrn = pScrn; + qxl->x_modes = NULL; + qxl->entity = xf86GetEntityInfo (pScrn->entityList[0]); + qxl->kms_enabled = TRUE; + xorg_list_init(&qxl->ums_bos); + + qxl_kms_setup_funcs(qxl); + qxl->pci = xf86GetPciInfoForEntity (qxl->entity->index); + + pScrn->monitor = pScrn->confScreen->monitor; + + if (qxl_open_drm_master(pScrn) == FALSE) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Kernel modesetting setup failed\n"); + goto out; + } + + if (!qxl_pre_init_common(pScrn)) + goto out; + + xf86SetDpi (pScrn, 0, 0); + + if (!xf86LoadSubModule (pScrn, "fb")) + goto out; + + if (!xf86LoadSubModule (pScrn, "ramdac")) + goto out; + + if (drmmode_pre_init(pScrn, &qxl->drmmode, pScrn->bitsPerPixel / 8) == FALSE) + goto out; + + qxl->virtual_x = 1024; + qxl->virtual_y = 768; + + pScrn->display->virtualX = qxl->virtual_x; + pScrn->display->virtualY = qxl->virtual_y; + + xf86DrvMsg (scrnIndex, X_INFO, "PreInit complete\n"); +#ifdef GIT_VERSION + xf86DrvMsg (scrnIndex, X_INFO, "git commit %s\n", GIT_VERSION); +#endif + + return TRUE; + + out: + if (qxl) + free(qxl); + return FALSE; +} + +static Bool +qxl_create_screen_resources_kms(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86ScreenToScrn (pScreen); + qxl_screen_t * qxl = pScrn->driverPrivate; + Bool ret; + PixmapPtr pPixmap; + qxl_surface_t *surf; + int i; + + pScreen->CreateScreenResources = qxl->create_screen_resources; + ret = pScreen->CreateScreenResources (pScreen); + pScreen->CreateScreenResources = qxl_create_screen_resources_kms; + + if (!ret) + return FALSE; + + pPixmap = pScreen->GetScreenPixmap (pScreen); + + qxl_set_screen_pixmap_header (pScreen); + + if ((surf = get_surface (pPixmap))) + qxl->bo_funcs->destroy_surface(surf); + + set_surface (pPixmap, qxl->primary); + + if (!uxa_resources_init (pScreen)) + return FALSE; + + return TRUE; +} + +static Bool +qxl_blank_screen (ScreenPtr pScreen, int mode) +{ + return TRUE; +} + +Bool +qxl_enter_vt_kms (VT_FUNC_ARGS_DECL) +{ + SCRN_INFO_PTR (arg); + qxl_screen_t *qxl = pScrn->driverPrivate; + int ret; + + ret = drmSetMaster(qxl->drm_fd); + if (ret) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "drmSetMaster failed: %s\n", + strerror(errno)); + } + + if (!xf86SetDesiredModes(pScrn)) + return FALSE; + + // pScrn->EnableDisableFBAccess (XF86_SCRN_ARG (pScrn), TRUE); + return TRUE; +} + +void +qxl_leave_vt_kms (VT_FUNC_ARGS_DECL) +{ + SCRN_INFO_PTR (arg); + int ret; + qxl_screen_t *qxl = pScrn->driverPrivate; + xf86_hide_cursors (pScrn); + // pScrn->EnableDisableFBAccess (XF86_SCRN_ARG (pScrn), FALSE); + + ret = drmDropMaster(qxl->drm_fd); + if (ret) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "drmDropMaster failed: %s\n", + strerror(errno)); + } +} + + +Bool qxl_screen_init_kms(SCREEN_INIT_ARGS_DECL) +{ + ScrnInfoPtr pScrn = xf86ScreenToScrn (pScreen); + qxl_screen_t * qxl = pScrn->driverPrivate; + VisualPtr visual; + uint64_t n_surf; + + miClearVisualTypes (); + if (!miSetVisualTypes (pScrn->depth, miGetDefaultVisualMask (pScrn->depth), + pScrn->rgbBits, pScrn->defaultVisual)) + goto out; + if (!miSetPixmapDepths ()) + goto out; + pScrn->displayWidth = pScrn->virtualX; + + pScrn->virtualX = pScrn->currentMode->HDisplay; + pScrn->virtualY = pScrn->currentMode->VDisplay; + if (!qxl_fb_init (qxl, pScreen)) + goto out; + + visual = pScreen->visuals + pScreen->numVisuals; + while (--visual >= pScreen->visuals) + { + if ((visual->class | DynamicClass) == DirectColor) + { + visual->offsetRed = pScrn->offset.red; + visual->offsetGreen = pScrn->offset.green; + visual->offsetBlue = pScrn->offset.blue; + visual->redMask = pScrn->mask.red; + visual->greenMask = pScrn->mask.green; + visual->blueMask = pScrn->mask.blue; + } + } + + qxl->uxa = uxa_driver_alloc (); + +// GETPARAM + /* no surface cache for kms surfaces for now */ +#if 0 + if (!qxl_kms_getparam(qxl, QXL_PARAM_NUM_SURFACES, &n_surf)) + n_surf = 1024; + qxl->surface_cache = qxl_surface_cache_create (qxl, n_surf); +#endif + pScreen->SaveScreen = qxl_blank_screen; + + qxl_uxa_init (qxl, pScreen); + + DamageSetup (pScreen); + + miDCInitialize (pScreen, xf86GetPointerScreenFuncs()); + + xf86_cursors_init (pScreen, 64, 64, + (HARDWARE_CURSOR_TRUECOLOR_AT_8BPP | + HARDWARE_CURSOR_AND_SOURCE_WITH_MASK | + HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_1 | + HARDWARE_CURSOR_UPDATE_UNHIDDEN | + HARDWARE_CURSOR_ARGB)); + + if (!miCreateDefColormap (pScreen)) + goto out; + + if (!xf86CrtcScreenInit (pScreen)) + return FALSE; + + if (!qxl_resize_primary_to_virtual (qxl)) + return FALSE; + + qxl->create_screen_resources = pScreen->CreateScreenResources; + pScreen->CreateScreenResources = qxl_create_screen_resources_kms; + + qxl->close_screen = pScreen->CloseScreen; + pScreen->CloseScreen = qxl_close_screen_kms; + + return qxl_enter_vt_kms(VT_FUNC_ARGS); + out: + return FALSE; + +} + +#define QXL_BO_DATA 1 +#define QXL_BO_SURF 2 +#define QXL_BO_CMD 4 +#define QXL_BO_SURF_PRIMARY 8 + +struct qxl_kms_bo { + uint32_t handle; + const char *name; + uint32_t size; + int type; + struct xorg_list bos; + void *mapping; + qxl_screen_t *qxl; + int refcnt; +}; + +static struct qxl_bo *qxl_bo_alloc(qxl_screen_t *qxl, + unsigned long size, const char *name) +{ + struct qxl_kms_bo *bo; + struct drm_qxl_alloc alloc; + int ret; + + bo = calloc(1, sizeof(struct qxl_kms_bo)); + if (!bo) + return NULL; + + alloc.size = size; + alloc.handle = 0; + + ret = drmIoctl(qxl->drm_fd, DRM_IOCTL_QXL_ALLOC, &alloc); + if (ret) { + xf86DrvMsg(qxl->pScrn->scrnIndex, X_ERROR, + "error doing QXL_ALLOC\n"); + free(bo); + return NULL; // an invalid handle + } + + out: + bo->name = name; + bo->size = size; + bo->type = QXL_BO_DATA; + bo->handle = alloc.handle; + bo->qxl = qxl; + bo->refcnt = 1; + return (struct qxl_bo *)bo; +} + +static struct qxl_bo *qxl_cmd_alloc(qxl_screen_t *qxl, + unsigned long size, const char *name) +{ + struct qxl_kms_bo *bo; + struct drm_qxl_alloc alloc; + int ret; + + bo = calloc(1, sizeof(struct qxl_kms_bo)); + if (!bo) + return NULL; + bo->mapping = malloc(size); + if (!bo->mapping) { + free(bo); + return NULL; + } + bo->name = name; + bo->size = size; + bo->type = QXL_BO_CMD; + bo->handle = 0; + bo->qxl = qxl; + bo->refcnt = 1; + return (struct qxl_bo *)bo; +} + +static void *qxl_bo_map(struct qxl_bo *_bo) +{ + struct qxl_kms_bo *bo = (struct qxl_kms_bo *)_bo; + void *map; + struct drm_qxl_map qxl_map; + qxl_screen_t *qxl; + + if (!bo) + return NULL; + + qxl = bo->qxl; + if (bo->mapping) + return bo->mapping; + + memset(&qxl_map, 0, sizeof(qxl_map)); + + qxl_map.handle = bo->handle; + + if (drmIoctl(qxl->drm_fd, DRM_IOCTL_QXL_MAP, &qxl_map)) { + xf86DrvMsg(qxl->pScrn->scrnIndex, X_ERROR, + "error doing QXL_MAP: %s\n", strerror(errno)); + return NULL; + } + + map = mmap(0, bo->size, PROT_READ | PROT_WRITE, MAP_SHARED, qxl->drm_fd, + qxl_map.offset); + if (map == MAP_FAILED) { + xf86DrvMsg(qxl->pScrn->scrnIndex, X_ERROR, + "mmap failure: %s\n", strerror(errno)); + return NULL; + } + + bo->mapping = map; + return bo->mapping; +} + +static void qxl_bo_unmap(struct qxl_bo *_bo) +{ +} + +static void qxl_bo_incref(qxl_screen_t *qxl, struct qxl_bo *_bo) +{ + struct qxl_kms_bo *bo = (struct qxl_kms_bo *)_bo; + bo->refcnt++; +} + +static void qxl_bo_decref(qxl_screen_t *qxl, struct qxl_bo *_bo) +{ + struct qxl_kms_bo *bo = (struct qxl_kms_bo *)_bo; + struct drm_gem_close args; + int ret; + + bo->refcnt--; + if (bo->refcnt > 0) + return; + + if (bo->type == QXL_BO_CMD) { + free(bo->mapping); + goto out; + } else if (bo->mapping) + munmap(bo->mapping, bo->size); + + /* just close the handle */ + args.handle = bo->handle; + ret = drmIoctl(qxl->drm_fd, DRM_IOCTL_GEM_CLOSE, &args); + if (ret) { + xf86DrvMsg(qxl->pScrn->scrnIndex, X_ERROR, + "error doing QXL_DECREF\n"); + } + out: + free(bo); +} + +static void qxl_bo_output_bo_reloc(qxl_screen_t *qxl, uint32_t dst_offset, + struct qxl_bo *_dst_bo, + struct qxl_bo *_src_bo) +{ + struct qxl_kms_bo *dst_bo = (struct qxl_kms_bo *)_dst_bo; + struct qxl_kms_bo *src_bo = (struct qxl_kms_bo *)_src_bo; + struct drm_qxl_reloc *r = &qxl->cmds.relocs[qxl->cmds.n_relocs]; + + if (qxl->cmds.n_reloc_bos >= MAX_RELOCS || qxl->cmds.n_relocs >= MAX_RELOCS) + assert(0); + + qxl->cmds.reloc_bo[qxl->cmds.n_reloc_bos] = _src_bo; + qxl->cmds.n_reloc_bos++; + src_bo->refcnt++; + + /* fix the kernel names */ + r->reloc_type = QXL_RELOC_TYPE_BO; + r->dst_handle = dst_bo->handle; + r->src_handle = src_bo->handle; + r->dst_offset = dst_offset; + r->src_offset = 0; + qxl->cmds.n_relocs++; +} + +static void qxl_bo_output_cmd_reloc(qxl_screen_t *qxl, QXLCommand *command, + struct qxl_bo *_src_bo) +{ + struct qxl_kms_bo *src_bo = (struct qxl_kms_bo *)_src_bo; + struct drm_qxl_reloc *r = &qxl->cmds.relocs[qxl->cmds.n_relocs]; + + if (qxl->cmds.n_reloc_bos >= MAX_RELOCS || qxl->cmds.n_relocs >= MAX_RELOCS) + assert(0); + + qxl->cmds.reloc_bo[qxl->cmds.n_reloc_bos] = _src_bo; + qxl->cmds.n_reloc_bos++; + src_bo->refcnt++; + /* fix the kernel names */ + r->reloc_type = QXL_RELOC_TYPE_BO; + r->dst_handle = 0; + r->src_handle = src_bo->handle; + r->dst_offset = 0; + r->src_offset = 0; + qxl->cmds.n_relocs++; +} + +static void qxl_bo_write_command(qxl_screen_t *qxl, uint32_t cmd_type, struct qxl_bo *_bo) +{ + struct qxl_kms_bo *bo = (struct qxl_kms_bo *)_bo; + struct drm_qxl_execbuffer eb; + struct drm_qxl_command c; + int ret; + int i; + + c.type = cmd_type; + c.command_size = bo->size - sizeof(union QXLReleaseInfo); + c.command = pointer_to_u64(((uint8_t *)bo->mapping + sizeof(union QXLReleaseInfo))); + if (qxl->cmds.n_relocs) { + c.relocs_num = qxl->cmds.n_relocs; + c.relocs = pointer_to_u64(qxl->cmds.relocs); + } else { + c.relocs_num = 0; + c.relocs = 0; + } + eb.flags = 0; + eb.commands_num = 1; + eb.commands = pointer_to_u64(&c); + ret = drmIoctl(qxl->drm_fd, DRM_IOCTL_QXL_EXECBUFFER, &eb); + if (ret) { + xf86DrvMsg(qxl->pScrn->scrnIndex, X_ERROR, + "EXECBUFFER failed\n"); + } + qxl->cmds.n_relocs = 0; + qxl->bo_funcs->bo_decref(qxl, _bo); + + for (i = 0; i < qxl->cmds.n_reloc_bos; i++) + qxl->bo_funcs->bo_decref(qxl, qxl->cmds.reloc_bo[i]); + qxl->cmds.n_reloc_bos = 0; +} + +static void qxl_bo_update_area(qxl_surface_t *surf, int x1, int y1, int x2, int y2) +{ + int ret; + struct qxl_kms_bo *bo = (struct qxl_kms_bo *)surf->bo; + struct drm_qxl_update_area update_area = { + .handle = bo->handle, + .left = x1, + .top = y1, + .right = x2, + .bottom = y2 + }; + + ret = drmIoctl(surf->qxl->drm_fd, + DRM_IOCTL_QXL_UPDATE_AREA, &update_area); + if (ret) { + fprintf(stderr, "error doing QXL_UPDATE_AREA %d %d %d\n", ret, errno, surf->id); + } +} + +static struct qxl_bo *qxl_bo_create_primary(qxl_screen_t *qxl, uint32_t width, uint32_t height, int32_t stride, uint32_t format) +{ + struct qxl_kms_bo *bo; + struct drm_qxl_alloc_surf param; + int ret; + + bo = calloc(1, sizeof(struct qxl_kms_bo)); + if (!bo) + return NULL; + + param.format = SPICE_SURFACE_FMT_32_xRGB; + param.width = width; + param.height = height; + param.stride = stride; + param.handle = 0; + ret = drmIoctl(qxl->drm_fd, + DRM_IOCTL_QXL_ALLOC_SURF, ¶m); + if (ret) + return NULL; + + bo->name = "surface memory"; + bo->size = stride * param.height; + bo->type = QXL_BO_SURF_PRIMARY; + bo->handle = param.handle; + bo->qxl = qxl; + bo->refcnt = 1; + + qxl->primary_bo = (struct qxl_bo *)bo; + qxl->device_primary = QXL_DEVICE_PRIMARY_CREATED; + return (struct qxl_bo *)bo; +} + +static void qxl_bo_destroy_primary(qxl_screen_t *qxl, struct qxl_bo *bo) +{ + qxl_bo_decref(qxl, bo); + + qxl->primary_bo = NULL; + qxl->device_primary = QXL_DEVICE_PRIMARY_NONE; +} + +static qxl_surface_t * +qxl_kms_surface_create(qxl_screen_t *qxl, + int width, + int height, + int bpp) +{ + SpiceBitmapFmt format; + qxl_surface_t *surface; + int stride; + struct qxl_kms_bo *bo; + pixman_format_code_t pformat; + void *dev_ptr; + int ret; + uint32_t *dev_addr; + + struct drm_qxl_alloc_surf param; + if (!qxl->enable_surfaces) + return NULL; + + if ((bpp & 3) != 0) + { + ErrorF ("%s: Bad bpp: %d (%d)\n", __FUNCTION__, bpp, bpp & 7); + return NULL; + } + + if (bpp != 8 && bpp != 16 && bpp != 32 && bpp != 24) + { + ErrorF ("%s: Unknown bpp\n", __FUNCTION__); + return NULL; + } + + if (width == 0 || height == 0) + { + ErrorF ("%s: Zero width or height\n", __FUNCTION__); + return NULL; + } + + qxl_get_formats (bpp, &format, &pformat); + stride = width * PIXMAN_FORMAT_BPP (pformat) / 8; + stride = (stride + 3) & ~3; + + bo = calloc(1, sizeof(struct qxl_kms_bo)); + if (!bo) + return NULL; + + param.format = format; + param.width = width; + param.height = height; + param.stride = -stride; + param.handle = 0; + ret = drmIoctl(qxl->drm_fd, + DRM_IOCTL_QXL_ALLOC_SURF, ¶m); + if (ret) + return NULL; + + bo->name = "surface memory"; + bo->size = stride * height + stride; + bo->type = QXL_BO_SURF; + bo->handle = param.handle; + bo->qxl = qxl; + bo->refcnt = 1; + + /* then fill out the driver surface */ + surface = calloc(1, sizeof *surface); + surface->bo = (struct qxl_bo *)bo; + surface->qxl = qxl; + surface->id = bo->handle; + surface->image_bo = NULL; + dev_ptr = qxl->bo_funcs->bo_map(surface->bo); + dev_addr + = (uint32_t *)((uint8_t *)dev_ptr + stride * (height - 1)); + surface->dev_image = pixman_image_create_bits ( + pformat, width, height, dev_addr, - stride); + + surface->host_image = pixman_image_create_bits ( + pformat, width, height, NULL, -1); + REGION_INIT (NULL, &(surface->access_region), (BoxPtr)NULL, 0); + qxl->bo_funcs->bo_unmap(surface->bo); + surface->access_type = UXA_ACCESS_RO; + surface->bpp = bpp; + + return surface; +} + +static void qxl_kms_surface_destroy(qxl_surface_t *surf) +{ + qxl_screen_t *qxl = surf->qxl; + + if (surf->dev_image) + pixman_image_unref (surf->dev_image); + if (surf->host_image) + pixman_image_unref (surf->host_image); + + if (surf->image_bo) + qxl->bo_funcs->bo_decref(qxl, surf->image_bo); + qxl->bo_funcs->bo_decref(qxl, surf->bo); + free(surf); +} + +static void qxl_bo_output_surf_reloc(qxl_screen_t *qxl, uint32_t dst_offset, + struct qxl_bo *_dst_bo, qxl_surface_t *surf) +{ + struct qxl_kms_bo *dst_bo = (struct qxl_kms_bo *)_dst_bo; + struct drm_qxl_reloc *r = &qxl->cmds.relocs[qxl->cmds.n_relocs]; + struct qxl_kms_bo *bo = (struct qxl_kms_bo *)surf->bo; + if (qxl->cmds.n_reloc_bos >= MAX_RELOCS || qxl->cmds.n_relocs >= MAX_RELOCS) + assert(0); + + qxl->cmds.reloc_bo[qxl->cmds.n_reloc_bos] = surf->bo; + qxl->cmds.n_reloc_bos++; + bo->refcnt++; + + /* fix the kernel names */ + r->reloc_type = QXL_RELOC_TYPE_SURF; + r->dst_handle = dst_bo->handle; + r->src_handle = bo->handle; + r->dst_offset = dst_offset; + r->src_offset = 0; + qxl->cmds.n_relocs++; +} + +struct qxl_bo_funcs qxl_kms_bo_funcs = { + qxl_bo_alloc, + qxl_cmd_alloc, + qxl_bo_map, + qxl_bo_unmap, + qxl_bo_decref, + qxl_bo_incref, + qxl_bo_output_bo_reloc, + qxl_bo_write_command, + qxl_bo_update_area, + qxl_bo_create_primary, + qxl_bo_destroy_primary, + qxl_kms_surface_create, + qxl_kms_surface_destroy, + qxl_bo_output_surf_reloc, +}; + +void qxl_kms_setup_funcs(qxl_screen_t *qxl) +{ + qxl->bo_funcs = &qxl_kms_bo_funcs; +} + +uint32_t qxl_kms_bo_get_handle(struct qxl_bo *_bo) +{ + struct qxl_kms_bo *bo = (struct qxl_kms_bo *)_bo; + + return bo->handle; +} +#endif diff --git a/src/qxl_surface.c b/src/qxl_surface.c index fc1bdf9..5a69fb7 100644 --- a/src/qxl_surface.c +++ b/src/qxl_surface.c @@ -84,7 +84,8 @@ make_drawable (qxl_screen_t *qxl, qxl_surface_t *surf, uint8_t type, if (rect) drawable->bbox = *rect; - drawable->mm_time = qxl->rom->mm_clock; + if (!qxl->kms_enabled) + drawable->mm_time = qxl->rom->mm_clock; qxl->bo_funcs->bo_unmap(draw_bo); return draw_bo; @@ -454,6 +455,35 @@ qxl_surface_prepare_copy (qxl_surface_t *dest, return TRUE; } + +static struct qxl_bo * +image_from_surface_internal(qxl_screen_t *qxl, + qxl_surface_t *surface) +{ + struct qxl_bo *image_bo = qxl->bo_funcs->bo_alloc (qxl, sizeof(struct QXLImage), "image struct for surface"); + struct QXLImage *image = qxl->bo_funcs->bo_map(image_bo); + + image->descriptor.id = 0; + image->descriptor.type = SPICE_IMAGE_TYPE_SURFACE; + image->descriptor.width = 0; + image->descriptor.height = 0; + qxl->bo_funcs->bo_unmap(image_bo); + return image_bo; +} + +struct qxl_bo *image_from_surface(qxl_screen_t *qxl, qxl_surface_t *dest) +{ + struct QXLImage *image_bo; + + if (!dest->image_bo) + dest->image_bo = image_from_surface_internal(qxl, dest); + + qxl->bo_funcs->bo_incref(qxl, dest->image_bo); + qxl->bo_funcs->bo_output_surf_reloc(qxl, offsetof(struct QXLImage, surface_image.surface_id), dest->image_bo, dest); + + return dest->image_bo; +} + void qxl_surface_copy (qxl_surface_t *dest, int src_x1, int src_y1, @@ -493,14 +523,8 @@ qxl_surface_copy (qxl_surface_t *dest, struct QXLImage *image; dest->u.copy_src->ref_count++; - image_bo = qxl->bo_funcs->bo_alloc (qxl, sizeof(struct QXLImage), "image struct for surface"); - image = qxl->bo_funcs->bo_map(image_bo); - image->descriptor.id = 0; - image->descriptor.type = SPICE_IMAGE_TYPE_SURFACE; - image->descriptor.width = 0; - image->descriptor.height = 0; - image->surface_image.surface_id = dest->u.copy_src->id; - qxl->bo_funcs->bo_unmap(image_bo); + + image_bo = image_from_surface(qxl, dest->u.copy_src); drawable_bo = make_drawable (qxl, dest, QXL_DRAW_COPY, &qrect); @@ -566,22 +590,14 @@ image_from_picture (qxl_screen_t *qxl, qxl_surface_t *surface, int *force_opaque) { - struct qxl_bo *image_bo = qxl->bo_funcs->bo_alloc (qxl, sizeof(struct QXLImage), "image struct for surface"); - struct QXLImage *image = qxl->bo_funcs->bo_map(image_bo); - - image->descriptor.id = 0; - image->descriptor.type = SPICE_IMAGE_TYPE_SURFACE; - image->descriptor.width = 0; - image->descriptor.height = 0; - image->surface_image.surface_id = surface->id; + struct qxl_bo *image_bo; - qxl->bo_funcs->bo_unmap(image_bo); if (picture->format == PICT_x8r8g8b8) *force_opaque = TRUE; else *force_opaque = FALSE; - - return image_bo; + + return image_from_surface(qxl, surface); } static struct qxl_bo * @@ -791,3 +807,34 @@ qxl_surface_put_image (qxl_surface_t *dest, qxl->bo_funcs->bo_decref(qxl, image_bo); return TRUE; } + +void +qxl_get_formats (int bpp, SpiceBitmapFmt *format, pixman_format_code_t *pformat) +{ + switch (bpp) + { + case 8: + *format = SPICE_SURFACE_FMT_8_A; + *pformat = PIXMAN_a8; + break; + + case 16: + *format = SPICE_SURFACE_FMT_16_565; + *pformat = PIXMAN_r5g6b5; + break; + + case 24: + *format = SPICE_SURFACE_FMT_32_xRGB; + *pformat = PIXMAN_a8r8g8b8; + break; + + case 32: + *format = SPICE_SURFACE_FMT_32_ARGB; + *pformat = PIXMAN_a8r8g8b8; + break; + + default: + *format = *pformat = -1; + break; + } +} diff --git a/src/qxl_surface.h b/src/qxl_surface.h index a3655a3..888bb0b 100644 --- a/src/qxl_surface.h +++ b/src/qxl_surface.h @@ -46,6 +46,7 @@ struct qxl_surface_t struct qxl_surface_t *dest; } composite; } u; + struct qxl_bo *image_bo; }; void qxl_download_box (qxl_surface_t *surface, int x1, int y1, int x2, int y2); diff --git a/src/qxl_surface_ums.c b/src/qxl_surface_ums.c index 96e7454..6839372 100644 --- a/src/qxl_surface_ums.c +++ b/src/qxl_surface_ums.c @@ -238,37 +238,6 @@ print_cache_info (surface_cache_t *cache) ErrorF (" total: %d\n", n_surfaces); } -static void -get_formats (int bpp, SpiceBitmapFmt *format, pixman_format_code_t *pformat) -{ - switch (bpp) - { - case 8: - *format = SPICE_SURFACE_FMT_8_A; - *pformat = PIXMAN_a8; - break; - - case 16: - *format = SPICE_SURFACE_FMT_16_565; - *pformat = PIXMAN_r5g6b5; - break; - - case 24: - *format = SPICE_SURFACE_FMT_32_xRGB; - *pformat = PIXMAN_a8r8g8b8; - break; - - case 32: - *format = SPICE_SURFACE_FMT_32_ARGB; - *pformat = PIXMAN_a8r8g8b8; - break; - - default: - *format = *pformat = -1; - break; - } -} - static qxl_surface_t * surface_get_from_cache (surface_cache_t *cache, int width, int height, int bpp) { @@ -346,7 +315,7 @@ qxl_surface_cache_create_primary (qxl_screen_t *qxl, dev_addr = qxl->bo_funcs->bo_map(bo); dev_image = pixman_image_create_bits (format, mode->x_res, mode->y_res, - (uint32_t *)dev_addr, -mode->stride); + (uint32_t *)dev_addr, (qxl->kms_enabled ? mode->stride : -mode->stride)); host_image = pixman_image_create_bits (format, qxl->virtual_x, qxl->virtual_y, @@ -372,6 +341,7 @@ qxl_surface_cache_create_primary (qxl_screen_t *qxl, surface->prev = NULL; surface->evacuated = NULL; surface->bo = bo; + surface->image_bo = NULL; REGION_INIT (NULL, &(surface->access_region), (BoxPtr)NULL, 0); surface->access_type = UXA_ACCESS_RO; @@ -470,7 +440,7 @@ surface_send_create (surface_cache_t *cache, qxl_surface_t *surface; struct qxl_bo *bo, *cmd_bo; void *dev_ptr; - get_formats (bpp, &format, &pformat); + qxl_get_formats (bpp, &format, &pformat); width = align (width); height = align (height); diff --git a/src/qxl_uxa.c b/src/qxl_uxa.c index 1810181..584a863 100644 --- a/src/qxl_uxa.c +++ b/src/qxl_uxa.c @@ -198,6 +198,16 @@ can_accelerate_picture (PicturePtr pict) static Bool qxl_has_composite (qxl_screen_t *qxl) { +#ifdef XF86DRM_MODE + if (qxl->kms_enabled) { + static Bool result, checked; + if (!checked) { + result = qxl_kms_check_cap(qxl, SPICE_DISPLAY_CAP_COMPOSITE); + checked = TRUE; + } + return result; + } +#endif #ifndef XSPICE return qxl->pci->revision >= 4 && @@ -211,6 +221,16 @@ qxl_has_composite (qxl_screen_t *qxl) static Bool qxl_has_a8_surfaces (qxl_screen_t *qxl) { +#ifdef XF86DRM_MODE + if (qxl->kms_enabled) { + static Bool result, checked; + if (!checked) { + result = qxl_kms_check_cap(qxl, SPICE_DISPLAY_CAP_A8_SURFACE); + checked = TRUE; + } + return result; + } +#endif #ifndef XSPICE return qxl->pci->revision >= 4 && |