[Intel-gfx] [PATCH] drm/i915: delay fb unpins from sprites to the next vblank

Jesse Barnes jbarnes at virtuousgeek.org
Mon Feb 27 22:53:09 CET 2012


Mutiple calls per frame are allowed, but we mustn't unpin the active fb
until the next vblank or we may end up displaying garbage or someone
else's buffer.

So use the page flip unpin work handler to delay unpin of the buffer to
a later time.

This adds a new field to the unpin struct so we can track which pipe we
need to wait for.  It also separates out the flip related work based on
the pending_flip object presence (refcounting happens differently for
flip objects).

Signed-off-by: Jesse Barnes <jbarnes at virtuousgeek.org>
---
 drivers/gpu/drm/i915/intel_display.c |   11 ++++++++---
 drivers/gpu/drm/i915/intel_drv.h     |    3 +++
 drivers/gpu/drm/i915/intel_sprite.c  |   24 ++++++++++++++++++++++--
 3 files changed, 33 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index cdcf99b..2fb9c01 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -7165,15 +7165,19 @@ static void intel_crtc_destroy(struct drm_crtc *crtc)
 	kfree(intel_crtc);
 }
 
-static void intel_unpin_work_fn(struct work_struct *__work)
+void intel_unpin_work_fn(struct work_struct *__work)
 {
 	struct intel_unpin_work *work =
 		container_of(__work, struct intel_unpin_work, work);
 
+	if (work->pipe >= 0)
+		intel_wait_for_vblank(work->dev, work->pipe);
 	mutex_lock(&work->dev->struct_mutex);
 	intel_unpin_fb_obj(work->old_fb_obj);
-	drm_gem_object_unreference(&work->pending_flip_obj->base);
-	drm_gem_object_unreference(&work->old_fb_obj->base);
+	if (work->pending_flip_obj) {
+		drm_gem_object_unreference(&work->pending_flip_obj->base);
+		drm_gem_object_unreference(&work->old_fb_obj->base);
+	}
 
 	intel_update_fbc(work->dev);
 	mutex_unlock(&work->dev->struct_mutex);
@@ -7494,6 +7498,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
 	if (work == NULL)
 		return -ENOMEM;
 
+	work->pipe = -1;
 	work->event = event;
 	work->dev = crtc->dev;
 	intel_fb = to_intel_framebuffer(crtc->fb);
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 9cec6c3..51c55bf 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -275,8 +275,11 @@ struct intel_unpin_work {
 	struct drm_pending_vblank_event *event;
 	int pending;
 	bool enable_stall_check;
+	int pipe;
 };
 
+extern void intel_unpin_work_fn(struct work_struct *__work);
+
 struct intel_fbc_work {
 	struct delayed_work work;
 	struct drm_crtc *crtc;
diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c
index dbdc5c0..3f1956d 100644
--- a/drivers/gpu/drm/i915/intel_sprite.c
+++ b/drivers/gpu/drm/i915/intel_sprite.c
@@ -387,6 +387,26 @@ snb_get_colorkey(struct drm_plane *plane, struct drm_intel_sprite_colorkey *key)
 		key->flags = I915_SET_COLORKEY_NONE;
 }
 
+static void
+intel_queue_unpin(struct drm_i915_gem_object *obj, int pipe)
+{
+	struct intel_unpin_work *work;
+
+	work = kzalloc(sizeof *work, GFP_KERNEL);
+	if (!work) {
+		/* Avoids a memory leak, but may result in a corrupt frame */
+		intel_unpin_fb_obj(obj);
+		return;
+	}
+
+	INIT_WORK(&work->work, intel_unpin_work_fn);
+	work->old_fb_obj = obj;
+	work->dev = obj->base.dev;
+	work->pipe = pipe;
+
+	schedule_work(&work->work);
+}
+
 static int
 intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
 		   struct drm_framebuffer *fb, int crtc_x, int crtc_y,
@@ -490,7 +510,7 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
 
 	/* Unpin old obj after new one is active to avoid ugliness */
 	if (old_obj)
-		intel_unpin_fb_obj(old_obj);
+		intel_queue_unpin(old_obj, pipe);
 
 out_unlock:
 	mutex_unlock(&dev->struct_mutex);
@@ -516,7 +536,7 @@ intel_disable_plane(struct drm_plane *plane)
 		goto out;
 
 	mutex_lock(&dev->struct_mutex);
-	intel_unpin_fb_obj(intel_plane->obj);
+	intel_queue_unpin(intel_plane->obj, intel_plane->pipe);
 	intel_plane->obj = NULL;
 	mutex_unlock(&dev->struct_mutex);
 out:
-- 
1.7.4.1




More information about the Intel-gfx mailing list