Hook into the frontbuffer write and delayed flush mechanism to avoid
having to send the FBC w/a on every batch, and instead just send the
w/a whenever we update the scanout.

Signed-off-by: Chris Wilson <ch...@chris-wilson.co.uk>
---
 drivers/gpu/drm/i915/i915_drv.h            |  1 +
 drivers/gpu/drm/i915/i915_gem.c            |  2 +-
 drivers/gpu/drm/i915/i915_gem_execbuffer.c |  2 +-
 drivers/gpu/drm/i915/intel_display.c       | 30 ++++++++++++++++++------------
 drivers/gpu/drm/i915/intel_drv.h           |  4 ++--
 drivers/gpu/drm/i915/intel_pm.c            |  2 ++
 drivers/gpu/drm/i915/intel_ringbuffer.c    |  9 +++------
 drivers/gpu/drm/i915/intel_ringbuffer.h    |  2 +-
 8 files changed, 29 insertions(+), 23 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 1257e0e..7dc76bf 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -1070,6 +1070,7 @@ typedef struct drm_i915_private {
 
        unsigned long cfb_size;
        unsigned int cfb_fb;
+       bool cfb_enabled;
        enum plane cfb_plane;
        int cfb_y;
        struct intel_fbc_work *fbc_work;
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 6661adb..707a55e 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -3323,7 +3323,7 @@ i915_gem_object_set_to_gtt_domain(struct 
drm_i915_gem_object *obj, bool write)
                obj->dirty = 1;
 
                if (obj->pin_count && !list_empty(&obj->fb_list))
-                       intel_mark_fb_busy(obj, NULL);
+                       intel_mark_fb_busy(obj);
        }
 
        trace_i915_gem_object_change_domain(obj,
diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c 
b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
index dabd9af..c6a02d7 100644
--- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c
+++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
@@ -786,7 +786,7 @@ i915_gem_execbuffer_move_to_active(struct list_head 
*objects,
                        obj->dirty = 1;
                        obj->last_write_seqno = intel_ring_get_seqno(ring);
                        if (obj->pin_count && !list_empty(&obj->fb_list))
-                               intel_mark_fb_busy(obj, ring);
+                               intel_mark_fb_busy(obj);
                }
 
                trace_i915_gem_object_change_domain(obj, old_read, old_write);
diff --git a/drivers/gpu/drm/i915/intel_display.c 
b/drivers/gpu/drm/i915/intel_display.c
index be60f12..9a90aa5 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -7108,6 +7108,14 @@ static void intel_display_refresh(struct work_struct 
*work)
                if (!fb->refresh_pending)
                        continue;
 
+               if (fb->fbc_dirty) {
+                       flush |= RING_FBC;
+                       if (fb->obj->ring)
+                               rings |= 1 << fb->obj->ring->id;
+                       intel_update_fbc(dev);
+                       fb->fbc_dirty = false;
+               }
+
                if (fb->refresh_mode == REFRESH_NONE)
                        i915_gem_release_mmap(fb->obj);
                fb->obj->base.write_domain &= ~I915_GEM_DOMAIN_GTT;
@@ -7129,10 +7137,10 @@ static void intel_display_refresh(struct work_struct 
*work)
        mutex_unlock(&dev->struct_mutex);
 }
 
-static void __intel_mark_fb_busy(struct intel_framebuffer *fb,
-                                struct intel_ring_buffer *ring)
+static void __intel_mark_fb_busy(struct intel_framebuffer *fb)
 {
        struct drm_device *dev = fb->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_crtc *crtc;
        bool refresh = false;
 
@@ -7149,14 +7157,13 @@ static void __intel_mark_fb_busy(struct 
intel_framebuffer *fb,
 
        refresh = false;
 
-       if (ring && intel_fbc_enabled(dev)) {
-               ring->fbc_dirty = true;
+       if (dev_priv->cfb_enabled) {
+               intel_disable_fbc(dev);
+               fb->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,
@@ -7164,8 +7171,7 @@ static void __intel_mark_fb_busy(struct intel_framebuffer 
*fb,
        }
 }
 
-void intel_mark_fb_busy(struct drm_i915_gem_object *obj,
-                       struct intel_ring_buffer *ring)
+void intel_mark_fb_busy(struct drm_i915_gem_object *obj)
 {
        struct intel_framebuffer *fb;
 
@@ -7173,7 +7179,7 @@ void intel_mark_fb_busy(struct drm_i915_gem_object *obj,
                if (fb->refresh_mode == REFRESH_USER)
                        continue;
 
-               __intel_mark_fb_busy(fb, NULL);
+               __intel_mark_fb_busy(fb);
        }
 }
 
@@ -7622,8 +7628,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
        if (ret)
                goto cleanup_pending;
 
-       intel_disable_fbc(dev);
-       intel_mark_fb_busy(obj, NULL);
+       intel_mark_fb_busy(obj);
        mutex_unlock(&dev->struct_mutex);
 
        trace_i915_flip_request(intel_crtc->plane, obj);
@@ -9151,7 +9156,7 @@ static int intel_user_framebuffer_dirty(struct 
drm_framebuffer *fb,
        struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
 
        if (intel_fb->refresh_mode == REFRESH_USER)
-               __intel_mark_fb_busy(intel_fb, NULL);
+               __intel_mark_fb_busy(intel_fb);
 
        return 0;
 }
@@ -9267,6 +9272,7 @@ int intel_framebuffer_init(struct drm_device *dev,
        intel_fb->powersave = true;
        intel_fb->refresh_mode = REFRESH_NONE;
        intel_fb->refresh_pending = false;
+       intel_fb->fbc_dirty = false;
 
        ret = drm_framebuffer_init(dev, &intel_fb->base, &intel_fb_funcs);
        if (ret) {
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 9f32949..01957bf 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -107,6 +107,7 @@ struct intel_framebuffer {
 #define REFRESH_NONE 0
 #define REFRESH_USER 1
        unsigned refresh_pending:1;
+       unsigned fbc_dirty:1;
        struct list_head obj_list;
 };
 
@@ -585,8 +586,7 @@ extern bool intel_sdvo_init(struct drm_device *dev, 
uint32_t sdvo_reg,
 extern void intel_dvo_init(struct drm_device *dev);
 extern void intel_tv_init(struct drm_device *dev);
 extern void intel_mark_busy(struct drm_device *dev);
-extern void intel_mark_fb_busy(struct drm_i915_gem_object *obj,
-                              struct intel_ring_buffer *ring);
+extern void intel_mark_fb_busy(struct drm_i915_gem_object *obj);
 extern void intel_mark_idle(struct drm_device *dev);
 extern void intel_lvds_init(struct drm_device *dev);
 extern bool intel_is_dual_link_lvds(struct drm_device *dev);
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index 2f6150b..711cdd0 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -347,6 +347,7 @@ static void intel_fbc_work_fn(struct work_struct *__work)
 
 static void intel_cancel_fbc_work(struct drm_i915_private *dev_priv)
 {
+       dev_priv->cfb_enabled = false;
        if (dev_priv->fbc_work == NULL)
                return;
 
@@ -379,6 +380,7 @@ void intel_enable_fbc(struct drm_crtc *crtc, unsigned long 
interval)
 
        intel_cancel_fbc_work(dev_priv);
 
+       dev_priv->cfb_enabled = true;
        work = kzalloc(sizeof *work, GFP_KERNEL);
        if (work == NULL) {
                DRM_ERROR("Failed to allocate FBC work structure\n");
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c 
b/drivers/gpu/drm/i915/intel_ringbuffer.c
index 601e1eb..1383267 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.c
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.c
@@ -278,12 +278,10 @@ static int gen7_ring_fbc_flush(struct intel_ring_buffer 
*ring, u32 value)
 {
        int ret;
 
-       if (!ring->fbc_dirty)
-               return 0;
-
        ret = intel_ring_begin(ring, 4);
        if (ret)
                return ret;
+
        intel_ring_emit(ring, MI_NOOP);
        /* WaFbcNukeOn3DBlt:ivb/hsw */
        intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(1));
@@ -291,7 +289,6 @@ static int gen7_ring_fbc_flush(struct intel_ring_buffer 
*ring, u32 value)
        intel_ring_emit(ring, value);
        intel_ring_advance(ring);
 
-       ring->fbc_dirty = false;
        return 0;
 }
 
@@ -353,7 +350,7 @@ gen7_render_ring_flush(struct intel_ring_buffer *ring, u32 
action)
                intel_ring_advance(ring);
        }
 
-       if (action & RING_FLUSH)
+       if (action & RING_FBC)
                return gen7_ring_fbc_flush(ring, FBC_REND_NUKE);
 
        return 0;
@@ -1737,7 +1734,7 @@ static int gen6_ring_flush(struct intel_ring_buffer 
*ring, u32 action)
                intel_ring_advance(ring);
        }
 
-       if (IS_GEN7(dev) && action & RING_FLUSH)
+       if (IS_GEN7(dev) && action & RING_FBC)
                return gen7_ring_fbc_flush(ring, FBC_REND_CACHE_CLEAN);
 
        return 0;
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h 
b/drivers/gpu/drm/i915/intel_ringbuffer.h
index 5066b3b..c91a4b1 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.h
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.h
@@ -96,6 +96,7 @@ struct  intel_ring_buffer {
                                  u32 action);
 #define RING_FLUSH     0x1
 #define RING_INVALIDATE 0x2
+#define RING_FBC       0x4
 
        int             (*add_request)(struct intel_ring_buffer *ring);
        /* Some chipsets are not quite as coherent as advertised and need
@@ -146,7 +147,6 @@ struct  intel_ring_buffer {
         */
        u32 outstanding_lazy_request;
        bool gpu_caches_dirty;
-       bool fbc_dirty;
 
        wait_queue_head_t irq_queue;
 
-- 
1.8.3.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

Reply via email to