All of lore.kernel.org
 help / color / mirror / Atom feed
From: Chris Wilson <chris@chris-wilson.co.uk>
To: intel-gfx@lists.freedesktop.org
Subject: [PATCH 4/5] drm/i915: Track modifications to the frontbuffer
Date: Thu, 20 Jun 2013 18:18:31 +0100	[thread overview]
Message-ID: <1371748712-26072-5-git-send-email-chris@chris-wilson.co.uk> (raw)
In-Reply-To: <1371748712-26072-1-git-send-email-chris@chris-wilson.co.uk>

The frontbuffer (active framebuffer being used as the scanout) often
requires addition work to flush any modifications to the display engine
and to the displays. So in order to do so, we need to detect whenever we
begin to write to the frontbuffer and mark it for a flush. The flush
then is performed after a slight delay, in order to coalesce several
small updates into a single flush.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
---
 drivers/gpu/drm/i915/i915_debugfs.c        |   2 +
 drivers/gpu/drm/i915/i915_drv.h            |   4 +
 drivers/gpu/drm/i915/i915_gem.c            |   4 +
 drivers/gpu/drm/i915/i915_gem_execbuffer.c |   2 +-
 drivers/gpu/drm/i915/intel_display.c       | 122 ++++++++++++++++++++++++++---
 drivers/gpu/drm/i915/intel_drv.h           |   5 ++
 include/uapi/drm/i915_drm.h                |   1 +
 7 files changed, 130 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index d8deb3b..db9af99 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -138,6 +138,8 @@ describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj)
 	}
 	if (obj->ring != NULL)
 		seq_printf(m, " (%s)", obj->ring->name);
+	if (!list_empty(&obj->fb_list))
+		seq_printf(m, " (framebuffer)");
 }
 
 static int i915_gem_object_list_info(struct seq_file *m, void *data)
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 01901b5..1257e0e 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -1064,6 +1064,8 @@ typedef struct drm_i915_private {
 	u32 hpd_event_bits;
 	struct timer_list hotplug_reenable_timer;
 
+	struct delayed_work display_refresh_work;
+
 	int num_plane;
 
 	unsigned long cfb_size;
@@ -1308,6 +1310,8 @@ struct drm_i915_gem_object {
 	unsigned int has_global_gtt_mapping:1;
 	unsigned int has_dma_mapping:1;
 
+	struct list_head fb_list;
+
 	struct sg_table *pages;
 	int pages_pin_count;
 
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 030b742..6661adb 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -3321,6 +3321,9 @@ i915_gem_object_set_to_gtt_domain(struct drm_i915_gem_object *obj, bool write)
 		obj->base.read_domains = I915_GEM_DOMAIN_GTT;
 		obj->base.write_domain = I915_GEM_DOMAIN_GTT;
 		obj->dirty = 1;
+
+		if (obj->pin_count && !list_empty(&obj->fb_list))
+			intel_mark_fb_busy(obj, NULL);
 	}
 
 	trace_i915_gem_object_change_domain(obj,
@@ -3890,6 +3893,7 @@ unlock:
 void i915_gem_object_init(struct drm_i915_gem_object *obj,
 			  const struct drm_i915_gem_object_ops *ops)
 {
+	INIT_LIST_HEAD(&obj->fb_list);
 	INIT_LIST_HEAD(&obj->mm_list);
 	INIT_LIST_HEAD(&obj->global_list);
 	INIT_LIST_HEAD(&obj->ring_list);
diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
index 73974fa..dabd9af 100644
--- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c
+++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
@@ -785,7 +785,7 @@ i915_gem_execbuffer_move_to_active(struct list_head *objects,
 		if (obj->base.write_domain) {
 			obj->dirty = 1;
 			obj->last_write_seqno = intel_ring_get_seqno(ring);
-			if (obj->pin_count) /* check for potential scanout */
+			if (obj->pin_count && !list_empty(&obj->fb_list))
 				intel_mark_fb_busy(obj, ring);
 		}
 
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 821a52d..be60f12 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -6663,7 +6663,9 @@ intel_framebuffer_create(struct drm_device *dev,
 		return ERR_PTR(-ENOMEM);
 	}
 
+	mutex_lock(&dev->struct_mutex);
 	ret = intel_framebuffer_init(dev, intel_fb, mode_cmd, obj);
+	mutex_unlock(&dev->struct_mutex);
 	if (ret) {
 		drm_gem_object_unreference_unlocked(&obj->base);
 		kfree(intel_fb);
@@ -7084,25 +7086,94 @@ void intel_mark_idle(struct drm_device *dev)
 	}
 }
 
-void intel_mark_fb_busy(struct drm_i915_gem_object *obj,
-			struct intel_ring_buffer *ring)
+static void intel_display_refresh(struct work_struct *work)
 {
-	struct drm_device *dev = obj->base.dev;
+	struct drm_i915_private *dev_priv =
+		container_of(work, struct drm_i915_private, display_refresh_work.work);
+	struct drm_device *dev = dev_priv->dev;
 	struct drm_crtc *crtc;
+	u32 rings = 0;
+	u32 flush = 0;
 
-	if (!i915_powersave)
-		return;
+	mutex_lock(&dev->struct_mutex);
 
 	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+		struct intel_framebuffer *fb = to_intel_framebuffer(crtc->fb);
+
 		if (!crtc->fb)
 			continue;
 
-		if (to_intel_framebuffer(crtc->fb)->obj != obj)
+		/* kick PSR/FBC/GFDT etc */
+
+		if (!fb->refresh_pending)
+			continue;
+
+		if (fb->refresh_mode == REFRESH_NONE)
+			i915_gem_release_mmap(fb->obj);
+		fb->obj->base.write_domain &= ~I915_GEM_DOMAIN_GTT;
+		fb->refresh_pending = false;
+	}
+
+	if (flush) {
+		struct intel_ring_buffer *ring;
+		int i;
+
+		if (rings == 0)
+			rings = 1 << BCS;
+
+		for_each_ring(ring, dev_priv, i)
+			if (rings & (1 << i))
+				(void)intel_ring_flush_internal(ring, flush);
+	}
+
+	mutex_unlock(&dev->struct_mutex);
+}
+
+static void __intel_mark_fb_busy(struct intel_framebuffer *fb,
+				 struct intel_ring_buffer *ring)
+{
+	struct drm_device *dev = fb->base.dev;
+	struct drm_crtc *crtc;
+	bool refresh = false;
+
+	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+		if (crtc->fb != &fb->base)
 			continue;
 
 		intel_increase_pllclock(crtc);
-		if (ring && intel_fbc_enabled(dev))
-			ring->fbc_dirty = true;
+		refresh = true;
+	}
+
+	if (!refresh || fb->refresh_pending)
+		return;
+
+	refresh = false;
+
+	if (ring && intel_fbc_enabled(dev)) {
+		ring->fbc_dirty = true;
+		refresh = true;
+	}
+
+	if (refresh) {
+		struct drm_i915_private *dev_priv = dev->dev_private;
+
+		fb->refresh_pending = true;
+		queue_delayed_work(dev_priv->wq,
+				   &dev_priv->display_refresh_work,
+				   msecs_to_jiffies(20));
+	}
+}
+
+void intel_mark_fb_busy(struct drm_i915_gem_object *obj,
+			struct intel_ring_buffer *ring)
+{
+	struct intel_framebuffer *fb;
+
+	list_for_each_entry(fb, &obj->fb_list, obj_list) {
+		if (fb->refresh_mode == REFRESH_USER)
+			continue;
+
+		__intel_mark_fb_busy(fb, NULL);
 	}
 }
 
@@ -9071,12 +9142,31 @@ static void intel_setup_outputs(struct drm_device *dev)
 	drm_helper_move_panel_connectors_to_head(dev);
 }
 
+static int intel_user_framebuffer_dirty(struct drm_framebuffer *fb,
+					struct drm_file *file,
+					unsigned flags, unsigned color,
+					struct drm_clip_rect *clips,
+					unsigned num_clips)
+{
+	struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
+
+	if (intel_fb->refresh_mode == REFRESH_USER)
+		__intel_mark_fb_busy(intel_fb, NULL);
+
+	return 0;
+}
+
 static void intel_user_framebuffer_destroy(struct drm_framebuffer *fb)
 {
 	struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
+	struct drm_device *dev = fb->dev;
 
 	drm_framebuffer_cleanup(fb);
-	drm_gem_object_unreference_unlocked(&intel_fb->obj->base);
+
+	mutex_lock(&dev->struct_mutex);
+	list_del(&intel_fb->obj_list);
+	drm_gem_object_unreference(&intel_fb->obj->base);
+	mutex_unlock(&dev->struct_mutex);
 
 	kfree(intel_fb);
 }
@@ -9094,6 +9184,7 @@ static int intel_user_framebuffer_create_handle(struct drm_framebuffer *fb,
 static const struct drm_framebuffer_funcs intel_fb_funcs = {
 	.destroy = intel_user_framebuffer_destroy,
 	.create_handle = intel_user_framebuffer_create_handle,
+	.dirty = intel_user_framebuffer_dirty,
 };
 
 int intel_framebuffer_init(struct drm_device *dev,
@@ -9174,6 +9265,8 @@ int intel_framebuffer_init(struct drm_device *dev,
 	drm_helper_mode_fill_fb_struct(&intel_fb->base, mode_cmd);
 	intel_fb->obj = obj;
 	intel_fb->powersave = true;
+	intel_fb->refresh_mode = REFRESH_NONE;
+	intel_fb->refresh_pending = false;
 
 	ret = drm_framebuffer_init(dev, &intel_fb->base, &intel_fb_funcs);
 	if (ret) {
@@ -9181,6 +9274,8 @@ int intel_framebuffer_init(struct drm_device *dev,
 		return ret;
 	}
 
+	list_add(&intel_fb->obj_list, &obj->fb_list);
+
 	return 0;
 }
 
@@ -9207,6 +9302,9 @@ __intel_user_framebuffer_getparam(struct intel_framebuffer *fb,
 	case INTEL_FRAMEBUFFER_PARAM_POWERSAVE:
 		*value = fb->powersave;
 		return 0;
+	case INTEL_FRAMEBUFFER_PARAM_REFRESH:
+		*value = fb->refresh_mode;
+		return 0;
 	default:
 		return -EINVAL;
 	}
@@ -9243,6 +9341,9 @@ __intel_user_framebuffer_setparam(struct intel_framebuffer *fb,
 	case INTEL_FRAMEBUFFER_PARAM_POWERSAVE:
 		fb->powersave = value;
 		return 0;
+	case INTEL_FRAMEBUFFER_PARAM_REFRESH:
+		fb->refresh_mode = value;
+		return 0;
 	default:
 		return -EINVAL;
 	}
@@ -9616,6 +9717,9 @@ void intel_modeset_init(struct drm_device *dev)
 
 	/* Just in case the BIOS is doing something questionable. */
 	intel_disable_fbc(dev);
+
+	INIT_DELAYED_WORK(&dev_priv->display_refresh_work,
+			  intel_display_refresh);
 }
 
 static void
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 4cddefb..9f32949 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -103,6 +103,11 @@ struct intel_framebuffer {
 	struct drm_framebuffer base;
 	struct drm_i915_gem_object *obj;
 	unsigned powersave:1;
+	unsigned refresh_mode:1;
+#define REFRESH_NONE 0
+#define REFRESH_USER 1
+	unsigned refresh_pending:1;
+	struct list_head obj_list;
 };
 
 struct intel_fbdev {
diff --git a/include/uapi/drm/i915_drm.h b/include/uapi/drm/i915_drm.h
index 74c34c2..609fc0c 100644
--- a/include/uapi/drm/i915_drm.h
+++ b/include/uapi/drm/i915_drm.h
@@ -1006,6 +1006,7 @@ struct intel_framebuffer_param {
 	__u32 fb_id;
 	__u32 param;
 #define INTEL_FRAMEBUFFER_PARAM_POWERSAVE 1
+#define INTEL_FRAMEBUFFER_PARAM_REFRESH 2
 	__u64 value;
 };
 
-- 
1.8.3.1

  parent reply	other threads:[~2013-06-20 17:18 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-06-20 17:18 RFC frontbuffer write tracking Chris Wilson
2013-06-20 17:18 ` [PATCH 1/5] drm/i915: Amalgamate the parameters to ring flush Chris Wilson
2013-06-20 17:18 ` [PATCH 2/5] drm/i915: Expose framebuffer parameters Chris Wilson
2013-06-20 17:18 ` [PATCH 3/5] drm/i915: Add a powersave framebuffer parameter Chris Wilson
2013-06-20 17:18 ` Chris Wilson [this message]
2013-06-20 17:18 ` [PATCH 5/5] drm/i915: Defer the FBC w/a invalidation Chris Wilson
2013-07-18  7:40 ` RFC frontbuffer write tracking Daniel Vetter

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1371748712-26072-5-git-send-email-chris@chris-wilson.co.uk \
    --to=chris@chris-wilson.co.uk \
    --cc=intel-gfx@lists.freedesktop.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.