From 7c80e128429d639742043f8fbdd7f1551c940ea3 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Tue, 4 Sep 2012 16:35:56 +0000 Subject: [PATCH] drm: support for rotated scanout MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For drivers that can support rotated scanout, the extra parameter checking in drm-core, while nice, tends to get confused. To solve this drivers can set the crtc or plane invert_dimensions field so that the dimension checking takes into account the rotation that the driver is performing. v1: original v2: remove invert_dimensions from plane, at Ville's suggestion. Userspace can give rotated src coordinates, so invert_dimensions is not required for planes. Signed-off-by: Rob Clark Reviewed-by: Ville Syrjälä Signed-off-by: Dave Airlie --- drivers/gpu/drm/drm_crtc.c | 46 +++++++++++++++++++++++++------------- include/drm/drm_crtc.h | 5 +++++ 2 files changed, 35 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 39afe13a5fa2..9c346a50379f 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -437,6 +437,7 @@ int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc, crtc->dev = dev; crtc->funcs = funcs; + crtc->invert_dimensions = false; mutex_lock(&dev->mode_config.mutex); @@ -1912,6 +1913,7 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data, DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id); if (crtc_req->mode_valid) { + int hdisplay, vdisplay; /* If we have a mode we need a framebuffer. */ /* If we pass -1, set the mode with the currently bound fb */ if (crtc_req->fb_id == -1) { @@ -1947,14 +1949,20 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data, drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V); - if (mode->hdisplay > fb->width || - mode->vdisplay > fb->height || - crtc_req->x > fb->width - mode->hdisplay || - crtc_req->y > fb->height - mode->vdisplay) { - DRM_DEBUG_KMS("Invalid CRTC viewport %ux%u+%u+%u for fb size %ux%u.\n", - mode->hdisplay, mode->vdisplay, - crtc_req->x, crtc_req->y, - fb->width, fb->height); + hdisplay = mode->hdisplay; + vdisplay = mode->vdisplay; + + if (crtc->invert_dimensions) + swap(hdisplay, vdisplay); + + if (hdisplay > fb->width || + vdisplay > fb->height || + crtc_req->x > fb->width - hdisplay || + crtc_req->y > fb->height - vdisplay) { + DRM_DEBUG_KMS("Invalid fb size %ux%u for CRTC viewport %ux%u+%d+%d%s.\n", + fb->width, fb->height, + hdisplay, vdisplay, crtc_req->x, crtc_req->y, + crtc->invert_dimensions ? " (inverted)" : ""); ret = -ENOSPC; goto out; } @@ -3546,6 +3554,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev, struct drm_framebuffer *fb; struct drm_pending_vblank_event *e = NULL; unsigned long flags; + int hdisplay, vdisplay; int ret = -EINVAL; if (page_flip->flags & ~DRM_MODE_PAGE_FLIP_FLAGS || @@ -3575,14 +3584,19 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev, goto out; fb = obj_to_fb(obj); - if (crtc->mode.hdisplay > fb->width || - crtc->mode.vdisplay > fb->height || - crtc->x > fb->width - crtc->mode.hdisplay || - crtc->y > fb->height - crtc->mode.vdisplay) { - DRM_DEBUG_KMS("Invalid fb size %ux%u for CRTC viewport %ux%u+%d+%d.\n", - fb->width, fb->height, - crtc->mode.hdisplay, crtc->mode.vdisplay, - crtc->x, crtc->y); + hdisplay = crtc->mode.hdisplay; + vdisplay = crtc->mode.vdisplay; + + if (crtc->invert_dimensions) + swap(hdisplay, vdisplay); + + if (hdisplay > fb->width || + vdisplay > fb->height || + crtc->x > fb->width - hdisplay || + crtc->y > fb->height - vdisplay) { + DRM_DEBUG_KMS("Invalid fb size %ux%u for CRTC viewport %ux%u+%d+%d%s.\n", + fb->width, fb->height, hdisplay, vdisplay, crtc->x, crtc->y, + crtc->invert_dimensions ? " (inverted)" : ""); ret = -ENOSPC; goto out; } diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 68fdb299e39f..8e405b82707d 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -368,6 +368,9 @@ struct drm_crtc_funcs { * @enabled: is this CRTC enabled? * @mode: current mode timings * @hwmode: mode timings as programmed to hw regs + * @invert_dimensions: for purposes of error checking crtc vs fb sizes, + * invert the width/height of the crtc. This is used if the driver + * is performing 90 or 270 degree rotated scanout * @x: x position on screen * @y: y position on screen * @funcs: CRTC control functions @@ -401,6 +404,8 @@ struct drm_crtc { */ struct drm_display_mode hwmode; + bool invert_dimensions; + int x, y; const struct drm_crtc_funcs *funcs;