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 <chris at 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