aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKristian Høgsberg <krh@bitplanet.net>2009-11-17 12:43:55 -0500
committerDave Airlie <airlied@redhat.com>2009-11-17 19:05:47 -0500
commitd91d8a3f88059d93e34ac70d059153ec69a9ffc7 (patch)
tree13810c8dbc35522d930b5fc17db35570f3d1e821
parentdad07ca71719598bc990dbdbeda763d15a10e98b (diff)
drm/kms: add page flipping ioctl
This adds a page flipping ioctl to the KMS API. The ioctl takes an fb ID and a ctrc ID and flips the crtc to the given fb at the next vblank. The ioctl returns immediately but the flip doesn't happen until after any rendering that's currently queued up against the new framebuffer is done. After submitting a page flip, any execbuffer involving the old front buffer will block until the flip is completed. Optionally, a vblank event can be generated when the swap eventually happens. Signed-off-by: Kristian Høgsberg <krh@bitplanet.net> Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk> Signed-off-by: Dave Airlie <airlied@redhat.com>
-rw-r--r--drivers/gpu/drm/drm_crtc.c69
-rw-r--r--drivers/gpu/drm/drm_drv.c1
-rw-r--r--include/drm/drm.h1
-rw-r--r--include/drm/drm_crtc.h16
-rw-r--r--include/drm/drm_mode.h33
5 files changed, 120 insertions, 0 deletions
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 5cae0b3eee9b..32756e67dd56 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -2478,3 +2478,72 @@ out:
2478 mutex_unlock(&dev->mode_config.mutex); 2478 mutex_unlock(&dev->mode_config.mutex);
2479 return ret; 2479 return ret;
2480} 2480}
2481
2482int drm_mode_page_flip_ioctl(struct drm_device *dev,
2483 void *data, struct drm_file *file_priv)
2484{
2485 struct drm_mode_crtc_page_flip *page_flip = data;
2486 struct drm_mode_object *obj;
2487 struct drm_crtc *crtc;
2488 struct drm_framebuffer *fb;
2489 struct drm_pending_vblank_event *e = NULL;
2490 unsigned long flags;
2491 int ret = -EINVAL;
2492
2493 if (page_flip->flags & ~DRM_MODE_PAGE_FLIP_FLAGS ||
2494 page_flip->reserved != 0)
2495 return -EINVAL;
2496
2497 mutex_lock(&dev->mode_config.mutex);
2498 obj = drm_mode_object_find(dev, page_flip->crtc_id, DRM_MODE_OBJECT_CRTC);
2499 if (!obj)
2500 goto out;
2501 crtc = obj_to_crtc(obj);
2502
2503 if (crtc->funcs->page_flip == NULL)
2504 goto out;
2505
2506 obj = drm_mode_object_find(dev, page_flip->fb_id, DRM_MODE_OBJECT_FB);
2507 if (!obj)
2508 goto out;
2509 fb = obj_to_fb(obj);
2510
2511 if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) {
2512 ret = -ENOMEM;
2513 spin_lock_irqsave(&dev->event_lock, flags);
2514 if (file_priv->event_space < sizeof e->event) {
2515 spin_unlock_irqrestore(&dev->event_lock, flags);
2516 goto out;
2517 }
2518 file_priv->event_space -= sizeof e->event;
2519 spin_unlock_irqrestore(&dev->event_lock, flags);
2520
2521 e = kzalloc(sizeof *e, GFP_KERNEL);
2522 if (e == NULL) {
2523 spin_lock_irqsave(&dev->event_lock, flags);
2524 file_priv->event_space += sizeof e->event;
2525 spin_unlock_irqrestore(&dev->event_lock, flags);
2526 goto out;
2527 }
2528
2529 e->event.base.type = DRM_EVENT_VBLANK;
2530 e->event.base.length = sizeof e->event;
2531 e->event.user_data = page_flip->user_data;
2532 e->base.event = &e->event.base;
2533 e->base.file_priv = file_priv;
2534 e->base.destroy =
2535 (void (*) (struct drm_pending_event *)) kfree;
2536 }
2537
2538 ret = crtc->funcs->page_flip(crtc, fb, e);
2539 if (ret) {
2540 spin_lock_irqsave(&dev->event_lock, flags);
2541 file_priv->event_space += sizeof e->event;
2542 spin_unlock_irqrestore(&dev->event_lock, flags);
2543 kfree(e);
2544 }
2545
2546out:
2547 mutex_unlock(&dev->mode_config.mutex);
2548 return ret;
2549}
diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c
index 5bd3f9461e2d..bfaf59b02bda 100644
--- a/drivers/gpu/drm/drm_drv.c
+++ b/drivers/gpu/drm/drm_drv.c
@@ -145,6 +145,7 @@ static struct drm_ioctl_desc drm_ioctls[] = {
145 DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETFB, drm_mode_getfb, DRM_MASTER|DRM_CONTROL_ALLOW), 145 DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETFB, drm_mode_getfb, DRM_MASTER|DRM_CONTROL_ALLOW),
146 DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB, drm_mode_addfb, DRM_MASTER|DRM_CONTROL_ALLOW), 146 DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB, drm_mode_addfb, DRM_MASTER|DRM_CONTROL_ALLOW),
147 DRM_IOCTL_DEF(DRM_IOCTL_MODE_RMFB, drm_mode_rmfb, DRM_MASTER|DRM_CONTROL_ALLOW), 147 DRM_IOCTL_DEF(DRM_IOCTL_MODE_RMFB, drm_mode_rmfb, DRM_MASTER|DRM_CONTROL_ALLOW),
148 DRM_IOCTL_DEF(DRM_IOCTL_MODE_PAGE_FLIP, drm_mode_page_flip_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW),
148}; 149};
149 150
150#define DRM_CORE_IOCTL_COUNT ARRAY_SIZE( drm_ioctls ) 151#define DRM_CORE_IOCTL_COUNT ARRAY_SIZE( drm_ioctls )
diff --git a/include/drm/drm.h b/include/drm/drm.h
index fa6d9155873d..3919a4f792ae 100644
--- a/include/drm/drm.h
+++ b/include/drm/drm.h
@@ -687,6 +687,7 @@ struct drm_gem_open {
687#define DRM_IOCTL_MODE_GETFB DRM_IOWR(0xAD, struct drm_mode_fb_cmd) 687#define DRM_IOCTL_MODE_GETFB DRM_IOWR(0xAD, struct drm_mode_fb_cmd)
688#define DRM_IOCTL_MODE_ADDFB DRM_IOWR(0xAE, struct drm_mode_fb_cmd) 688#define DRM_IOCTL_MODE_ADDFB DRM_IOWR(0xAE, struct drm_mode_fb_cmd)
689#define DRM_IOCTL_MODE_RMFB DRM_IOWR(0xAF, unsigned int) 689#define DRM_IOCTL_MODE_RMFB DRM_IOWR(0xAF, unsigned int)
690#define DRM_IOCTL_MODE_PAGE_FLIP DRM_IOWR(0xB0, struct drm_mode_crtc_page_flip)
690 691
691/** 692/**
692 * Device specific ioctls should only be in their respective headers 693 * Device specific ioctls should only be in their respective headers
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index b69347b8904f..4cc8a32dc4cf 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -290,6 +290,7 @@ struct drm_property {
290struct drm_crtc; 290struct drm_crtc;
291struct drm_connector; 291struct drm_connector;
292struct drm_encoder; 292struct drm_encoder;
293struct drm_pending_vblank_event;
293 294
294/** 295/**
295 * drm_crtc_funcs - control CRTCs for a given device 296 * drm_crtc_funcs - control CRTCs for a given device
@@ -333,6 +334,19 @@ struct drm_crtc_funcs {
333 void (*destroy)(struct drm_crtc *crtc); 334 void (*destroy)(struct drm_crtc *crtc);
334 335
335 int (*set_config)(struct drm_mode_set *set); 336 int (*set_config)(struct drm_mode_set *set);
337
338 /*
339 * Flip to the given framebuffer. This implements the page
340 * flip ioctl descibed in drm_mode.h, specifically, the
341 * implementation must return immediately and block all
342 * rendering to the current fb until the flip has completed.
343 * If userspace set the event flag in the ioctl, the event
344 * argument will point to an event to send back when the flip
345 * completes, otherwise it will be NULL.
346 */
347 int (*page_flip)(struct drm_crtc *crtc,
348 struct drm_framebuffer *fb,
349 struct drm_pending_vblank_event *event);
336}; 350};
337 351
338/** 352/**
@@ -756,6 +770,8 @@ extern int drm_mode_gamma_get_ioctl(struct drm_device *dev,
756extern int drm_mode_gamma_set_ioctl(struct drm_device *dev, 770extern int drm_mode_gamma_set_ioctl(struct drm_device *dev,
757 void *data, struct drm_file *file_priv); 771 void *data, struct drm_file *file_priv);
758extern bool drm_detect_hdmi_monitor(struct edid *edid); 772extern bool drm_detect_hdmi_monitor(struct edid *edid);
773extern int drm_mode_page_flip_ioctl(struct drm_device *dev,
774 void *data, struct drm_file *file_priv);
759extern struct drm_display_mode *drm_cvt_mode(struct drm_device *dev, 775extern struct drm_display_mode *drm_cvt_mode(struct drm_device *dev,
760 int hdisplay, int vdisplay, int vrefresh, 776 int hdisplay, int vdisplay, int vrefresh,
761 bool reduced, bool interlaced, bool margins); 777 bool reduced, bool interlaced, bool margins);
diff --git a/include/drm/drm_mode.h b/include/drm/drm_mode.h
index 1f908416aedb..68ddc6175ae7 100644
--- a/include/drm/drm_mode.h
+++ b/include/drm/drm_mode.h
@@ -268,4 +268,37 @@ struct drm_mode_crtc_lut {
268 __u64 blue; 268 __u64 blue;
269}; 269};
270 270
271#define DRM_MODE_PAGE_FLIP_EVENT 0x01
272#define DRM_MODE_PAGE_FLIP_FLAGS DRM_MODE_PAGE_FLIP_EVENT
273
274/*
275 * Request a page flip on the specified crtc.
276 *
277 * This ioctl will ask KMS to schedule a page flip for the specified
278 * crtc. Once any pending rendering targeting the specified fb (as of
279 * ioctl time) has completed, the crtc will be reprogrammed to display
280 * that fb after the next vertical refresh. The ioctl returns
281 * immediately, but subsequent rendering to the current fb will block
282 * in the execbuffer ioctl until the page flip happens. If a page
283 * flip is already pending as the ioctl is called, EBUSY will be
284 * returned.
285 *
286 * The ioctl supports one flag, DRM_MODE_PAGE_FLIP_EVENT, which will
287 * request that drm sends back a vblank event (see drm.h: struct
288 * drm_event_vblank) when the page flip is done. The user_data field
289 * passed in with this ioctl will be returned as the user_data field
290 * in the vblank event struct.
291 *
292 * The reserved field must be zero until we figure out something
293 * clever to use it for.
294 */
295
296struct drm_mode_crtc_page_flip {
297 __u32 crtc_id;
298 __u32 fb_id;
299 __u32 flags;
300 __u32 reserved;
301 __u64 user_data;
302};
303
271#endif 304#endif