From patchwork Wed Jul 9 08:19:08 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Chris Wilson X-Patchwork-Id: 4512401 Return-Path: X-Original-To: patchwork-dri-devel@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork2.web.kernel.org (Postfix) with ESMTP id CF1D2BEEAA for ; Wed, 9 Jul 2014 08:19:29 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id A544E202E5 for ; Wed, 9 Jul 2014 08:19:28 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) by mail.kernel.org (Postfix) with ESMTP id 5B413202B4 for ; Wed, 9 Jul 2014 08:19:27 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 936526E56D; Wed, 9 Jul 2014 01:19:26 -0700 (PDT) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from fireflyinternet.com (mail.fireflyinternet.com [87.106.93.118]) by gabe.freedesktop.org (Postfix) with ESMTP id D0B8A72055 for ; Wed, 9 Jul 2014 01:19:24 -0700 (PDT) X-Default-Received-SPF: pass (skip=forwardok (res=PASS)) x-ip-name=78.156.65.138; Received: from cantiga.alporthouse.com (unverified [78.156.65.138]) by fireflyinternet.com (Firefly Internet (M1)) with ESMTP id 27411225-1500048 for multiple; Wed, 09 Jul 2014 09:19:34 +0100 Received: by cantiga.alporthouse.com (sSMTP sendmail emulation); Wed, 09 Jul 2014 09:19:11 +0100 From: Chris Wilson To: dri-devel@lists.freedesktop.org, xorg-devel@lists.x.org Subject: [PATCH] modesetting: Support native primary plane rotation Date: Wed, 9 Jul 2014 09:19:08 +0100 Message-Id: <1404893948-18819-1-git-send-email-chris@chris-wilson.co.uk> X-Mailer: git-send-email 2.0.1 In-Reply-To: <1404889221-6549-1-git-send-email-chris@chris-wilson.co.uk> References: <1404889221-6549-1-git-send-email-chris@chris-wilson.co.uk> X-Originating-IP: 78.156.65.138 X-Country: code=GB country="United Kingdom" ip=78.156.65.138 Cc: Pekka Paalanen , walter harms X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" X-Spam-Status: No, score=-4.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP With the advent of universal drm planes and the introduction of generic plane properties for rotations, we can query and program the hardware for native rotation support. NOTE: this depends upon the next release of libdrm to remove one opencoded define. v2: Use enum to determine primary plane, suggested by Pekka Paalanen. Use libobj for replacement ffs(), suggested by walter harms Signed-off-by: Chris Wilson Cc: Pekka Paalanen Cc: walter harms --- configure.ac | 5 +- libobj/ffs.c | 14 ++++ src/drmmode_display.c | 216 ++++++++++++++++++++++++++++++++++++++++++-------- src/drmmode_display.h | 10 ++- 4 files changed, 212 insertions(+), 33 deletions(-) create mode 100644 libobj/ffs.c diff --git a/configure.ac b/configure.ac index 1c1a36d..1694465 100644 --- a/configure.ac +++ b/configure.ac @@ -74,10 +74,13 @@ AM_CONDITIONAL(HAVE_XEXTPROTO_71, [ test "$HAVE_XEXTPROTO_71" = "yes" ]) # Checks for header files. AC_HEADER_STDC -PKG_CHECK_MODULES(DRM, [libdrm >= 2.4.46]) +PKG_CHECK_MODULES(DRM, [libdrm >= 2.4.47]) PKG_CHECK_MODULES([PCIACCESS], [pciaccess >= 0.10]) AM_CONDITIONAL(DRM, test "x$DRM" = xyes) +AC_CONFIG_LIBOBJ_DIR(libobj) +AC_REPLACE_FUNCS(ffs) + PKG_CHECK_MODULES(UDEV, [libudev], [udev=yes], [udev=no]) if test x"$udev" = xyes; then AC_DEFINE(HAVE_UDEV,1,[Enable udev-based monitor hotplug detection]) diff --git a/libobj/ffs.c b/libobj/ffs.c new file mode 100644 index 0000000..2d44dcc --- /dev/null +++ b/libobj/ffs.c @@ -0,0 +1,14 @@ +extern int ffs(unsigned int value); + +int ffs(unsigned int value) +{ + int bit; + + if (value == 0) + return 0; + + bit = 0; + while ((value & (1 << bit++)) == 0) + ; + return bit; +} diff --git a/src/drmmode_display.c b/src/drmmode_display.c index c533324..e854502 100644 --- a/src/drmmode_display.c +++ b/src/drmmode_display.c @@ -56,6 +56,8 @@ #include "driver.h" +#define DRM_CLIENT_CAP_UNIVERSAL_PLANES 2 /* from libdrm 2.4.55 */ + static struct dumb_bo *dumb_bo_create(int fd, const unsigned width, const unsigned height, const unsigned bpp) @@ -300,6 +302,132 @@ create_pixmap_for_fbcon(drmmode_ptr drmmode, #endif +static unsigned +rotation_index(unsigned rotation) +{ + return ffs(rotation) - 1; +} + +static void +rotation_init(xf86CrtcPtr crtc) +{ + drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; + drmmode_ptr drmmode = drmmode_crtc->drmmode; + drmModePlaneRes *plane_resources; + int i, j, k; + + drmSetClientCap(drmmode->fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1); + + plane_resources = drmModeGetPlaneResources(drmmode->fd); + if (plane_resources == NULL) + return; + + for (i = 0; drmmode_crtc->primary_plane_id == 0 && i < plane_resources->count_planes; i++) { + drmModePlane *drm_plane; + drmModeObjectPropertiesPtr proplist; + int is_primary = -1; + + drm_plane = drmModeGetPlane(drmmode->fd, + plane_resources->planes[i]); + if (drm_plane == NULL) + continue; + + if (!(drm_plane->possible_crtcs & (1 << drmmode_crtc->index))) + goto free_plane; + + proplist = drmModeObjectGetProperties(drmmode->fd, + drm_plane->plane_id, + DRM_MODE_OBJECT_PLANE); + if (proplist == NULL) + goto free_plane; + + for (j = 0; is_primary == -1 && j < proplist->count_props; j++) { + drmModePropertyPtr prop; + + prop = drmModeGetProperty(drmmode->fd, proplist->props[j]); + if (!prop) + continue; + + if (strcmp(prop->name, "type") == 0) { + for (k = 0; k < prop->count_enums; k++) { + if (prop->enums[k].value != proplist->prop_values[j]) + continue; + + is_primary = strcmp(prop->enums[k].name, "Primary") == 0; + break; + } + } + + drmModeFreeProperty(prop); + } + + if (is_primary) { + drmmode_crtc->primary_plane_id = drm_plane->plane_id; + + for (j = 0; drmmode_crtc->rotation_prop_id == 0 && j < proplist->count_props; j++) { + drmModePropertyPtr prop; + + prop = drmModeGetProperty(drmmode->fd, proplist->props[j]); + if (!prop) + continue; + + if (strcmp(prop->name, "rotation") == 0) { + drmmode_crtc->rotation_prop_id = proplist->props[j]; + drmmode_crtc->current_rotation = proplist->prop_values[j]; + for (k = 0; k < prop->count_enums; k++) { + int rr = -1; + if (strcmp(prop->enums[k].name, "rotate-0") == 0) + rr = RR_Rotate_0; + else if (strcmp(prop->enums[k].name, "rotate-90") == 0) + rr = RR_Rotate_90; + else if (strcmp(prop->enums[k].name, "rotate-180") == 0) + rr = RR_Rotate_180; + else if (strcmp(prop->enums[k].name, "rotate-270") == 0) + rr = RR_Rotate_270; + else if (strcmp(prop->enums[k].name, "reflect-x") == 0) + rr = RR_Reflect_X; + else if (strcmp(prop->enums[k].name, "reflect-y") == 0) + rr = RR_Reflect_Y; + if (rr != -1) { + drmmode_crtc->map_rotations[rotation_index(rr)] = 1 << prop->enums[k].value; + drmmode_crtc->supported_rotations |= rr; + } + } + } + + drmModeFreeProperty(prop); + } + } + + drmModeFreeObjectProperties(proplist); +free_plane: + drmModeFreePlane(drm_plane); + } +} + +static Bool +rotation_set(xf86CrtcPtr crtc, unsigned rotation) +{ + drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; + drmmode_ptr drmmode = drmmode_crtc->drmmode; + + if (drmmode_crtc->current_rotation == rotation) + return TRUE; + + if ((drmmode_crtc->supported_rotations & rotation) == 0) + return FALSE; + + if (drmModeObjectSetProperty(drmmode->fd, + drmmode_crtc->primary_plane_id, + DRM_MODE_OBJECT_PLANE, + drmmode_crtc->rotation_prop_id, + drmmode_crtc->map_rotations[rotation_index(rotation)])) + return FALSE; + + drmmode_crtc->current_rotation = rotation; + return TRUE; +} + static Bool drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode, Rotation rotation, int x, int y) @@ -307,13 +435,14 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode, ScrnInfoPtr pScrn = crtc->scrn; xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn); drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; + unsigned supported_rotations = drmmode_crtc->supported_rotations; 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 ret; int i; uint32_t fb_id; drmModeModeInfo kmode; @@ -324,15 +453,16 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode, if (drmmode->fb_id == 0) { ret = drmModeAddFB(drmmode->fd, pScrn->virtualX, height, - pScrn->depth, pScrn->bitsPerPixel, + pScrn->depth, pScrn->bitsPerPixel, drmmode->front_bo->pitch, drmmode->front_bo->handle, - &drmmode->fb_id); - if (ret < 0) { - ErrorF("failed to add fb %d\n", ret); - return FALSE; - } - } + &drmmode->fb_id); + if (ret) { + xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR, + "failed to create framebuffer: %s\n", strerror(-ret)); + return FALSE; + } + } saved_mode = crtc->mode; saved_x = crtc->x; @@ -350,10 +480,8 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode, } output_ids = calloc(sizeof(uint32_t), xf86_config->num_output); - if (!output_ids) { - ret = FALSE; - goto done; - } + if (!output_ids) + goto err; if (mode) { for (i = 0; i < xf86_config->num_output; i++) { @@ -368,9 +496,16 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode, output_count++; } - if (!xf86CrtcRotate(crtc)) { - goto done; - } + rotation_set(crtc, RR_Rotate_0); + +again: + crtc->driverIsPerformingTransform = FALSE; + if (rotation & supported_rotations && !crtc->transformPresent) + crtc->driverIsPerformingTransform = TRUE; + + if (!xf86CrtcRotate(crtc)) + goto err; + #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); @@ -392,11 +527,20 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode, } ret = drmModeSetCrtc(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, fb_id, x, y, output_ids, output_count, &kmode); - if (ret) + if (ret) { xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR, - "failed to set mode: %s", strerror(-ret)); - else - ret = TRUE; + "failed to set mode: %s\n", strerror(-ret)); + goto err; + } + + if (crtc->driverIsPerformingTransform) { + if (!rotation_set(crtc, crtc->rotation)) { + xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR, + "failed to set rotation: %s\n", strerror(errno)); + supported_rotations &= ~crtc->rotation; + goto again; + } + } if (crtc->scrn->pScreen) xf86CrtcSetScreenSubpixelOrder(crtc->scrn->pScreen); @@ -409,26 +553,33 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode, output->funcs->dpms(output, DPMSModeOn); } + } else { + ret = drmModeSetCrtc(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, + 0, 0, 0, NULL, 0, NULL) == 0; + if (ret) { + xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR, + "failed to set mode: %s\n", strerror(-ret)); + goto err; + } } +#if defined(XF86_CRTC_VERSION) && XF86_CRTC_VERSION >= 3 + crtc->active = mode != NULL; +#endif + #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 TRUE; - return ret; +err: + crtc->x = saved_x; + crtc->y = saved_y; + crtc->rotation = saved_rotation; + crtc->mode = saved_mode; + return FALSE; } static void @@ -610,7 +761,10 @@ drmmode_crtc_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int num) 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; + drmmode_crtc->index = num; crtc->driver_private = drmmode_crtc; + + rotation_init(crtc); } static xf86OutputStatus diff --git a/src/drmmode_display.h b/src/drmmode_display.h index 745c484..73fabfd 100644 --- a/src/drmmode_display.h +++ b/src/drmmode_display.h @@ -75,8 +75,13 @@ typedef struct { typedef struct { drmmode_ptr drmmode; drmModeCrtcPtr mode_crtc; - int hw_id; + int index; struct dumb_bo *cursor_bo; + unsigned primary_plane_id; + unsigned rotation_prop_id; + unsigned supported_rotations; + unsigned map_rotations[6]; + unsigned current_rotation; unsigned rotate_fb_id; uint16_t lut_r[256], lut_g[256], lut_b[256]; DamagePtr slave_damage; @@ -145,5 +150,8 @@ void drmmode_get_default_bpp(ScrnInfoPtr pScrn, drmmode_ptr drmmmode, int *depth #define MS_ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) +#ifndef HAVE_FFS +extern int ffs(unsigned int value); +#endif #endif