On Wed, 29 Apr 2009 18:02:59 -0700
Jesse Barnes <jbar...@virtuousgeek.org> wrote:
> On Wed, 29 Apr 2009 15:09:33 -0700
> Jesse Barnes <jbar...@virtuousgeek.org> wrote:
> > I'm still working through mutlihead issues on the kernel side; the
> > flip waits should wait for *both* vblank events before completing
> > the flip. But other than that, I'm pretty happy with things.
>
> This incremental set fixes up the multihead handling and adds swap
> interval support as a bonus. It's nice to see flipping & no tearing
> on two heads at once!
Here's an update that makes all the code generic. Jakob suggested that
we do the mode_set_base call out of the caller's context so we don't
block the caller waiting for the GTT domain transition (effectively
waiting until rendering finishes). I definitely want to do this, but
I'll have to add a way to communicate the necessary flip data from the
ioctl to the new work function.
--
Jesse Barnes, Intel Open Source Technology Center
diff --git a/libdrm/xf86drmMode.c b/libdrm/xf86drmMode.c
index ea11207..ada5690 100644
--- a/libdrm/xf86drmMode.c
+++ b/libdrm/xf86drmMode.c
@@ -664,3 +664,16 @@ int drmModeCrtcSetGamma(int fd, uint32_t crtc_id, uint32_t size,
return 0;
}
+
+int drmModePageFlip(int fd, uint32_t *crtc_ids, uint32_t crtc_count,
+ uint32_t fb_id)
+{
+ struct drm_gem_page_flip flip;
+
+ flip.fb_id = fb_id;
+ flip.crtc_ids_ptr = (uint64_t)crtc_ids;
+ flip.crtc_count = (uint32_t)crtc_count;
+ flip.flags = 0;
+
+ return drmIoctl(fd, DRM_IOCTL_GEM_PAGE_FLIP, &flip);
+}
diff --git a/libdrm/xf86drmMode.h b/libdrm/xf86drmMode.h
index 62304bb..2406e2f 100644
--- a/libdrm/xf86drmMode.h
+++ b/libdrm/xf86drmMode.h
@@ -259,8 +259,6 @@ typedef struct _drmModeConnector {
uint32_t *encoders; /**< List of encoder ids */
} drmModeConnector, *drmModeConnectorPtr;
-
-
extern void drmModeFreeModeInfo( drmModeModeInfoPtr ptr );
extern void drmModeFreeResources( drmModeResPtr ptr );
extern void drmModeFreeFB( drmModeFBPtr ptr );
@@ -362,3 +360,5 @@ extern int drmModeCrtcSetGamma(int fd, uint32_t crtc_id, uint32_t size,
uint16_t *red, uint16_t *green, uint16_t *blue);
extern int drmModeCrtcGetGamma(int fd, uint32_t crtc_id, uint32_t size,
uint16_t *red, uint16_t *green, uint16_t *blue);
+extern int drmModePageFlip(int fd, uint32_t *crtc_ids, uint32_t crtc_count,
+ uint32_t fb_id);
diff --git a/shared-core/drm.h b/shared-core/drm.h
index b97ba09..2353ac4 100644
--- a/shared-core/drm.h
+++ b/shared-core/drm.h
@@ -1107,7 +1107,7 @@ struct drm_gem_open {
#define DRM_IOCTL_MODE_GETFB DRM_IOWR(0xAD, struct drm_mode_fb_cmd)
#define DRM_IOCTL_MODE_ADDFB DRM_IOWR(0xAE, struct drm_mode_fb_cmd)
#define DRM_IOCTL_MODE_RMFB DRM_IOWR(0xAF, uint32_t)
-#define DRM_IOCTL_MODE_REPLACEFB DRM_IOWR(0xB0, struct drm_mode_fb_cmd)
+#define DRM_IOCTL_GEM_PAGE_FLIP DRM_IOW( 0xB0, struct drm_gem_page_flip)
/*...@}*/
diff --git a/shared-core/drm_mode.h b/shared-core/drm_mode.h
index 9b92733..2354f77 100644
--- a/shared-core/drm_mode.h
+++ b/shared-core/drm_mode.h
@@ -270,4 +270,23 @@ struct drm_mode_crtc_lut {
uint64_t blue;
};
+#define DRM_PAGE_FLIP_WAIT (1<<0) /* block on previous page flip */
+#define DRM_PAGE_FLIP_FLAGS_MASK (DRM_PAGE_FLIP_WAIT)
+
+struct drm_gem_page_flip {
+ /** Handle of new front buffer */
+ uint32_t fb_id;
+
+ /**
+ * crtcs to flip
+ */
+ uint32_t crtc_count;
+ uint64_t crtc_ids_ptr;
+
+ /**
+ * page flip flags (wait on flip only for now)
+ */
+ uint32_t flags;
+};
+
#endif
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 94a7688..4c39350 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -352,11 +352,12 @@ EXPORT_SYMBOL(drm_framebuffer_cleanup);
*
* Inits a new object created as base part of an driver crtc object.
*/
-void drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
+void drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc, int pipe,
const struct drm_crtc_funcs *funcs)
{
crtc->dev = dev;
crtc->funcs = funcs;
+ crtc->pipe = pipe;
mutex_lock(&dev->mode_config.mutex);
drm_mode_object_get(dev, &crtc->base, DRM_MODE_OBJECT_CRTC);
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c
index a04639d..7b9bc80 100644
--- a/drivers/gpu/drm/drm_crtc_helper.c
+++ b/drivers/gpu/drm/drm_crtc_helper.c
@@ -593,8 +593,10 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
if (drm_mode_equal(&saved_mode, &crtc->mode)) {
if (saved_x != crtc->x || saved_y != crtc->y ||
depth_changed || bpp_changed) {
+ mutex_lock(&dev->struct_mutex);
ret = !crtc_funcs->mode_set_base(crtc, crtc->x, crtc->y,
old_fb);
+ mutex_unlock(&dev->struct_mutex);
goto done;
}
}
@@ -864,8 +866,10 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
old_fb = set->crtc->fb;
if (set->crtc->fb != set->fb)
set->crtc->fb = set->fb;
+ mutex_lock(&dev->struct_mutex);
ret = crtc_funcs->mode_set_base(set->crtc,
set->x, set->y, old_fb);
+ mutex_unlock(&dev->struct_mutex);
if (ret != 0)
goto fail_set_mode;
}
@@ -1007,3 +1011,140 @@ int drm_helper_resume_force_mode(struct drm_device *dev)
return 0;
}
EXPORT_SYMBOL(drm_helper_resume_force_mode);
+
+/**
+ * drm_gem_page_flip - page flip ioctl
+ * @dev: DRM device
+ * @data: ioctl args
+ * @file_priv: file private data
+ *
+ * The page flip ioctl replaces the current front buffer with a new one,
+ * using the CRTC's mode_set_base function, which should just update
+ * the front buffer base pointer. It's up to mode_set_base to make
+ * sure the update doesn't result in tearing (on some hardware the base
+ * register is double buffered, so this is easy).
+ *
+ * Note that this covers just the simple case of flipping the front
+ * buffer immediately. Interval handling and interlaced modes have to
+ * be handled by userspace, or with new ioctls.
+ */
+int drm_gem_page_flip(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
+{
+ struct drm_gem_page_flip *flip_data = data;
+ struct drm_mode_object *drm_obj, *fb_obj;
+ struct drm_crtc *crtc;
+ struct drm_framebuffer *old_fb;
+ struct drm_gem_object *obj = NULL;
+ unsigned long flags;
+ u32 frame, crtc_ids[2];
+ int i, ret = 0;
+ struct drm_crtc_helper_funcs *crtc_funcs;
+
+ if (!(drm_core_check_feature(dev, DRIVER_MODESET)))
+ return -ENODEV;
+
+ /*
+ * Reject unknown flags so future userspace knows what we (don't)
+ * support
+ */
+ if (flip_data->flags & (~DRM_PAGE_FLIP_FLAGS_MASK)) {
+ DRM_DEBUG("bad page flip flags\n");
+ return -EINVAL;
+ }
+
+ if (flip_data->crtc_count > dev->num_crtcs) {
+ DRM_DEBUG("bad crtc count\n");
+ return -EINVAL;
+ }
+
+ ret = copy_from_user(crtc_ids, (u32 __user *)flip_data->crtc_ids_ptr,
+ sizeof(u32) * flip_data->crtc_count);
+ if (ret)
+ return -EFAULT;
+
+ mutex_lock(&dev->struct_mutex);
+
+ fb_obj = drm_mode_object_find(dev, flip_data->fb_id,
+ DRM_MODE_OBJECT_FB);
+ if (!fb_obj) {
+ DRM_DEBUG("unknown fb %d\n", flip_data->fb_id);
+ ret = -ENOENT;
+ goto out_unlock;
+ }
+
+ for (i = 0; i < flip_data->crtc_count; i++) {
+ drm_obj = drm_mode_object_find(dev, crtc_ids[i],
+ DRM_MODE_OBJECT_CRTC);
+ if (!drm_obj) {
+ DRM_DEBUG("unknown crtc %d\n", crtc_ids[i]);
+ ret = -ENOENT;
+ goto out_unlock;
+ }
+ crtc = obj_to_crtc(drm_obj);
+ if (!crtc->enabled) {
+ DRM_DEBUG("crtc %d not enabled\n", crtc_ids[i]);
+ ret = -EINVAL;
+ goto out_unlock;
+ }
+ old_fb = crtc->fb;
+ crtc_funcs = crtc->helper_private;
+
+ /* Get vblank ref for completion handling */
+ ret = drm_vblank_get(dev, crtc->pipe);
+ if (ret) {
+ DRM_DEBUG("failed to take vblank ref\n");
+ goto out_unlock;
+ }
+
+ crtc->fb = obj_to_fb(fb_obj);
+ obj = crtc_funcs->framebuffer_to_obj(crtc->fb);
+
+ /*
+ * This prevents two threads from queueing a flip on
+ * the same buffer and clobbering one another. We could
+ * also just do a wait_for_completion here, but that
+ * could cause any thread who loses the race to the mutex
+ * to clobber the previous flip.
+ */
+ retry:
+ if (atomic_read(&obj->flips_pending)) {
+ mutex_unlock(&dev->struct_mutex);
+ wait_for_completion(&obj->flip);
+ mutex_lock(&dev->struct_mutex);
+ goto retry;
+ }
+
+ spin_lock_irqsave(&dev->flip_lock, flags);
+
+ /* Should be in the clear at this point, check */
+ WARN(atomic_read(&obj->flips_pending),
+ "object already queued for flip\n");
+
+ frame = drm_vblank_count(dev, crtc->pipe);
+ obj->flip_frame[crtc->pipe] = frame + 1;
+ /* Only need to add it once */
+ if (list_empty(&obj->flip_head))
+ list_add_tail(&obj->flip_head, &dev->flip_list);
+ atomic_inc(&obj->flips_pending);
+ spin_unlock_irqrestore(&dev->flip_lock, flags);
+
+ ret = crtc_funcs->mode_set_base(crtc, 0, 0, old_fb);
+ if (ret) {
+ DRM_ERROR("mode_set_base failed: %d\n", ret);
+ goto out_unlock;
+ }
+ }
+
+ mutex_unlock(&dev->struct_mutex);
+
+ if (obj && atomic_read(&obj->flips_pending))
+ wait_for_completion(&obj->flip);
+
+ return 0;
+
+out_unlock:
+ mutex_unlock(&dev->struct_mutex);
+
+ return ret;
+}
diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c
index c4ada8b..b71c53f 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[] = {
DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETFB, drm_mode_getfb, DRM_MASTER|DRM_CONTROL_ALLOW),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB, drm_mode_addfb, DRM_MASTER|DRM_CONTROL_ALLOW),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_RMFB, drm_mode_rmfb, DRM_MASTER|DRM_CONTROL_ALLOW),
+ DRM_IOCTL_DEF(DRM_IOCTL_GEM_PAGE_FLIP, drm_gem_page_flip, DRM_AUTH|DRM_MASTER),
};
#define DRM_CORE_IOCTL_COUNT ARRAY_SIZE( drm_ioctls )
diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c
index 4984aa8..cb8b202 100644
--- a/drivers/gpu/drm/drm_gem.c
+++ b/drivers/gpu/drm/drm_gem.c
@@ -88,6 +88,8 @@ drm_gem_init(struct drm_device *dev)
atomic_set(&dev->pin_memory, 0);
atomic_set(&dev->gtt_count, 0);
atomic_set(&dev->gtt_memory, 0);
+ INIT_LIST_HEAD(&dev->flip_list);
+ spin_lock_init(&dev->flip_lock);
mm = drm_calloc(1, sizeof(struct drm_gem_mm), DRM_MEM_MM);
if (!mm) {
@@ -144,6 +146,16 @@ drm_gem_object_alloc(struct drm_device *dev, size_t size)
kref_init(&obj->refcount);
kref_init(&obj->handlecount);
+
+ INIT_LIST_HEAD(&obj->flip_head);
+ obj->flip_frame = kcalloc(1, sizeof(u32) * dev->num_crtcs, GFP_KERNEL);
+ if (!obj->flip_frame) {
+ kfree(obj);
+ return NULL;
+ }
+ init_completion(&obj->flip);
+ atomic_set(&obj->flips_pending, 0);
+
obj->size = size;
if (dev->driver->gem_init_object != NULL &&
dev->driver->gem_init_object(obj) != 0) {
diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c
index 93e677a..d3aa656 100644
--- a/drivers/gpu/drm/drm_irq.c
+++ b/drivers/gpu/drm/drm_irq.c
@@ -71,6 +71,44 @@ int drm_irq_by_busid(struct drm_device *dev, void *data,
return 0;
}
+#define vblank_after(a,b) ((long)(b) - (long)(a) < 0)
+
+static void drm_handle_flip_locked(struct drm_device *dev,
+ struct drm_gem_object *obj,
+ int pipe)
+{
+ if (vblank_after(drm_vblank_count(dev, pipe), obj->flip_frame[pipe])) {
+ atomic_dec(&obj->flips_pending);
+ drm_vblank_put(dev, pipe);
+ /*
+ * If all the vblanks for this object have completed,
+ * we can wake up any waiters.
+ */
+ if (!atomic_read(&obj->flips_pending)) {
+ list_del_init(&obj->flip_head);
+ complete(&obj->flip);
+ }
+ }
+}
+
+static void drm_flip_work_func(struct work_struct *work)
+{
+ struct drm_device *dev = container_of(work, struct drm_device,
+ flip_complete_work);
+ struct drm_gem_object *obj, *tmp;
+ unsigned long irqflags;
+ int pipe;
+
+ mutex_lock(&dev->struct_mutex);
+ spin_lock_irqsave(&dev->flip_lock, irqflags);
+ for (pipe = 0; pipe < dev->num_crtcs; pipe++) {
+ list_for_each_entry_safe(obj, tmp, &dev->flip_list, flip_head)
+ drm_handle_flip_locked(dev, obj, pipe);
+ }
+ spin_unlock_irqrestore(&dev->flip_lock, irqflags);
+ mutex_unlock(&dev->struct_mutex);
+}
+
static void vblank_disable_fn(unsigned long arg)
{
struct drm_device *dev = (struct drm_device *)arg;
@@ -173,6 +211,9 @@ int drm_vblank_init(struct drm_device *dev, int num_crtcs)
atomic_set(&dev->vblank_refcount[i], 0);
}
+ spin_lock_init(&dev->flip_lock);
+// INIT_WORK(&dev->flip_work, );
+ INIT_WORK(&dev->flip_complete_work, drm_flip_work_func);
dev->vblank_disable_allowed = 0;
return 0;
@@ -632,5 +673,7 @@ void drm_handle_vblank(struct drm_device *dev, int crtc)
{
atomic_inc(&dev->_vblank_count[crtc]);
DRM_WAKEUP(&dev->vbl_queue[crtc]);
+ schedule_work(&dev->flip_complete_work);
}
EXPORT_SYMBOL(drm_handle_vblank);
+
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 4642115..ff1f452 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -3232,6 +3232,22 @@ i915_gem_execbuffer(struct drm_device *dev, void *data,
if (ret != 0)
goto pre_mutex_err;
+ /* Look up object handles */
+ for (i = 0; i < args->buffer_count; i++) {
+ object_list[i] = drm_gem_object_lookup(dev, file_priv,
+ exec_list[i].handle);
+ if (object_list[i] == NULL) {
+ DRM_ERROR("Invalid object handle %d at index %d\n",
+ exec_list[i].handle, i);
+ ret = -EBADF;
+ mutex_lock(&dev->struct_mutex);
+ goto err;
+ }
+
+ if (atomic_read(&object_list[i]->flips_pending))
+ wait_for_completion(&object_list[i]->flip);
+ }
+
mutex_lock(&dev->struct_mutex);
i915_verify_inactive(dev, __FILE__, __LINE__);
@@ -3250,17 +3266,8 @@ i915_gem_execbuffer(struct drm_device *dev, void *data,
goto pre_mutex_err;
}
- /* Look up object handles */
+ /* Sanity check list for double entries */
for (i = 0; i < args->buffer_count; i++) {
- object_list[i] = drm_gem_object_lookup(dev, file_priv,
- exec_list[i].handle);
- if (object_list[i] == NULL) {
- DRM_ERROR("Invalid object handle %d at index %d\n",
- exec_list[i].handle, i);
- ret = -EBADF;
- goto err;
- }
-
obj_priv = object_list[i]->driver_private;
if (obj_priv->in_execbuffer) {
DRM_ERROR("Object %p appears more than once in object list\n",
@@ -3773,9 +3780,13 @@ i915_gem_idle(struct drm_device *dev)
*/
dev_priv->mm.suspended = 1;
+ mutex_unlock(&dev->struct_mutex);
+
+ /* Wait for any outstanding flips */
+ /* FIXME */
+
/* Cancel the retire work handler, wait for it to finish if running
*/
- mutex_unlock(&dev->struct_mutex);
cancel_delayed_work_sync(&dev_priv->mm.retire_work);
mutex_lock(&dev->struct_mutex);
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index bdcda36..f2c144a 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -641,6 +641,15 @@ intel_wait_for_vblank(struct drm_device *dev)
mdelay(20);
}
+struct drm_gem_object *intel_framebuffer_to_obj(struct drm_framebuffer *fb)
+{
+ struct intel_framebuffer *intel_fb;
+
+ intel_fb = to_intel_framebuffer(fb);
+
+ return intel_fb->obj;
+}
+
static int
intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
struct drm_framebuffer *old_fb)
@@ -662,6 +671,8 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
u32 dspcntr, alignment;
int ret;
+ BUG_ON(!mutex_is_locked(&dev->struct_mutex));
+
/* no fb bound */
if (!crtc->fb) {
DRM_DEBUG("No FB bound\n");
@@ -697,17 +708,14 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
BUG();
}
- mutex_lock(&dev->struct_mutex);
ret = i915_gem_object_pin(intel_fb->obj, alignment);
if (ret != 0) {
- mutex_unlock(&dev->struct_mutex);
return ret;
}
ret = i915_gem_object_set_to_gtt_domain(intel_fb->obj, 1);
if (ret != 0) {
i915_gem_object_unpin(intel_fb->obj);
- mutex_unlock(&dev->struct_mutex);
return ret;
}
@@ -731,7 +739,6 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
default:
DRM_ERROR("Unknown color depth\n");
i915_gem_object_unpin(intel_fb->obj);
- mutex_unlock(&dev->struct_mutex);
return -EINVAL;
}
if (IS_I965G(dev)) {
@@ -765,7 +772,6 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
intel_fb = to_intel_framebuffer(old_fb);
i915_gem_object_unpin(intel_fb->obj);
}
- mutex_unlock(&dev->struct_mutex);
if (!dev->primary->master)
return 0;
@@ -1314,7 +1320,9 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
I915_WRITE(dspcntr_reg, dspcntr);
/* Flush the plane changes */
+ mutex_lock(&dev->struct_mutex);
ret = intel_pipe_set_base(crtc, x, y, old_fb);
+ mutex_unlock(&dev->struct_mutex);
if (ret != 0)
return ret;
@@ -1757,6 +1765,7 @@ static const struct drm_crtc_helper_funcs intel_helper_funcs = {
.mode_fixup = intel_crtc_mode_fixup,
.mode_set = intel_crtc_mode_set,
.mode_set_base = intel_pipe_set_base,
+ .framebuffer_to_obj = intel_framebuffer_to_obj,
.prepare = intel_crtc_prepare,
.commit = intel_crtc_commit,
};
@@ -1779,7 +1788,7 @@ static void intel_crtc_init(struct drm_device *dev, int pipe)
if (intel_crtc == NULL)
return;
- drm_crtc_init(dev, &intel_crtc->base, &intel_crtc_funcs);
+ drm_crtc_init(dev, &intel_crtc->base, pipe, &intel_crtc_funcs);
drm_mode_crtc_set_gamma_size(&intel_crtc->base, 256);
intel_crtc->pipe = pipe;
diff --git a/include/drm/drm.h b/include/drm/drm.h
index 7cb50bd..fca0728 100644
--- a/include/drm/drm.h
+++ b/include/drm/drm.h
@@ -686,6 +686,7 @@ struct drm_gem_open {
#define DRM_IOCTL_MODE_GETFB DRM_IOWR(0xAD, struct drm_mode_fb_cmd)
#define DRM_IOCTL_MODE_ADDFB DRM_IOWR(0xAE, struct drm_mode_fb_cmd)
#define DRM_IOCTL_MODE_RMFB DRM_IOWR(0xAF, unsigned int)
+#define DRM_IOCTL_GEM_PAGE_FLIP DRM_IOW( 0xB0, struct drm_gem_page_flip)
/**
* Device specific ioctls should only be in their respective headers
diff --git a/include/drm/drmP.h b/include/drm/drmP.h
index c8c4221..7ba8781 100644
--- a/include/drm/drmP.h
+++ b/include/drm/drmP.h
@@ -617,6 +617,14 @@ struct drm_gem_object {
*/
int name;
+ /** Object's place on the flip lists (protected by vblank_lock) */
+ struct list_head flip_head;
+ /** frame to wait for (both of these are per-pipe values) */
+ u32 *flip_frame;
+ /** for page flips */
+ struct completion flip;
+ atomic_t flips_pending;
+
/**
* Memory domains. These monitor which caches contain read/write data
* related to the object. When transitioning from one set of domains
@@ -968,6 +976,16 @@ struct drm_device {
u32 max_vblank_count; /**< size of vblank counter register */
+ /** Protects flip list */
+ spinlock_t flip_lock;
+ struct work_struct flip_work;
+ struct work_struct flip_complete_work;
+
+ /**
+ * List of objects waiting on flip completion
+ */
+ struct list_head flip_list;
+
/*...@} */
cycles_t ctx_start;
cycles_t lck_start;
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 3c1924c..f352f6f 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -336,6 +336,7 @@ struct drm_crtc_funcs {
/**
* drm_crtc - central CRTC control structure
* @enabled: is this CRTC enabled?
+ * @pipe: pipe number (as seen by DRM vblank functions)
* @x: x position on screen
* @y: y position on screen
* @desired_mode: new desired mode
@@ -359,6 +360,7 @@ struct drm_crtc {
struct drm_display_mode mode;
+ int pipe;
int x, y;
struct drm_display_mode *desired_mode;
int desired_x, desired_y;
@@ -586,6 +588,7 @@ struct drm_mode_config {
extern void drm_crtc_init(struct drm_device *dev,
struct drm_crtc *crtc,
+ int pipe,
const struct drm_crtc_funcs *funcs);
extern void drm_crtc_cleanup(struct drm_crtc *crtc);
@@ -733,4 +736,6 @@ extern int drm_mode_gamma_get_ioctl(struct drm_device *dev,
extern int drm_mode_gamma_set_ioctl(struct drm_device *dev,
void *data, struct drm_file *file_priv);
extern bool drm_detect_hdmi_monitor(struct edid *edid);
+extern int drm_gem_page_flip(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
#endif /* __DRM_CRTC_H__ */
diff --git a/include/drm/drm_crtc_helper.h b/include/drm/drm_crtc_helper.h
index ec073d8..1d2335c 100644
--- a/include/drm/drm_crtc_helper.h
+++ b/include/drm/drm_crtc_helper.h
@@ -60,6 +60,8 @@ struct drm_crtc_helper_funcs {
/* Move the crtc on the current fb to the given position *optional* */
int (*mode_set_base)(struct drm_crtc *crtc, int x, int y,
struct drm_framebuffer *old_fb);
+
+ struct drm_gem_object *(*framebuffer_to_obj)(struct drm_framebuffer *fb);
};
struct drm_encoder_helper_funcs {
diff --git a/include/drm/drm_mode.h b/include/drm/drm_mode.h
index ae304cc..f4f030e 100644
--- a/include/drm/drm_mode.h
+++ b/include/drm/drm_mode.h
@@ -265,4 +265,23 @@ struct drm_mode_crtc_lut {
__u64 blue;
};
+#define DRM_PAGE_FLIP_WAIT (1<<0) /* block on previous page flip */
+#define DRM_PAGE_FLIP_FLAGS_MASK (DRM_PAGE_FLIP_WAIT)
+
+struct drm_gem_page_flip {
+ /** Handle of new front buffer */
+ uint32_t fb_id;
+
+ /**
+ * crtcs to flip
+ */
+ uint32_t crtc_count;
+ uint64_t crtc_ids_ptr;
+
+ /**
+ * page flip flags (wait on flip only for now)
+ */
+ uint32_t flags;
+};
+
#endif
------------------------------------------------------------------------------
Register Now & Save for Velocity, the Web Performance & Operations
Conference from O'Reilly Media. Velocity features a full day of
expert-led, hands-on workshops and two days of sessions from industry
leaders in dedicated Performance & Operations tracks. Use code vel09scf
and Save an extra 15% before 5/3. http://p.sf.net/sfu/velocityconf
--
_______________________________________________
Dri-devel mailing list
Dri-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/dri-devel