summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDave Airlie <airlied@gmail.com>2013-03-06 14:26:07 +1000
committerDave Airlie <airlied@redhat.com>2013-03-12 10:42:31 +1000
commit4897efe095c80fe5fa2f6e33b3d9c64542a4be20 (patch)
tree9261454dfc0a18812b031aa1937e65a3cbc7e58c
parent7a7b12762904eea329f678987565d89db56421b6 (diff)
qxl: add KMS support v1.2qxl-kms
Avoid DRI create busid symbol for now. fix warnings.
-rw-r--r--configure.ac26
-rw-r--r--src/Makefile.am5
-rw-r--r--src/qxl.h41
-rw-r--r--src/qxl_driver.c104
-rw-r--r--src/qxl_drmmode.c882
-rw-r--r--src/qxl_drmmode.h83
-rw-r--r--src/qxl_kms.c763
-rw-r--r--src/qxl_surface.c87
-rw-r--r--src/qxl_surface.h1
-rw-r--r--src/qxl_surface_ums.c36
-rw-r--r--src/qxl_uxa.c20
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
diff --git a/src/qxl.h b/src/qxl.h
index 017eab5..0c8277a 100644
--- a/src/qxl.h
+++ b/src/qxl.h
@@ -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, &param);
+ 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, &param);
+ 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 &&