Queue the unpinning of the current plane object to after the next vblank. For special case benchmarks and others apps that may call set_plane at a high frequency, we can unpin their objects directly unless they are "live". Signed-off-by: Jesse Barnes <jbarnes at virtuousgeek.org> Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk> --- drivers/gpu/drm/i915/i915_reg.h | 4 ++ drivers/gpu/drm/i915/intel_display.c | 2 +- drivers/gpu/drm/i915/intel_drv.h | 3 ++ drivers/gpu/drm/i915/intel_sprite.c | 67 ++++++++++++++++++++++++---------- 4 files changed, 55 insertions(+), 21 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 5ac9837..a4c801e 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -2988,6 +2988,7 @@ #define DVSSTRIDE(pipe) _PIPE(pipe, _DVSASTRIDE, _DVSBSTRIDE) #define DVSPOS(pipe) _PIPE(pipe, _DVSAPOS, _DVSBPOS) #define DVSSURF(pipe) _PIPE(pipe, _DVSASURF, _DVSBSURF) +#define DVSSURFLIVE(pipe) _PIPE(pipe, _DVSASURFLIVE, _DVSBSURFLIVE) #define DVSKEYMAX(pipe) _PIPE(pipe, _DVSAKEYMAXVAL, _DVSBKEYMAXVAL) #define DVSSIZE(pipe) _PIPE(pipe, _DVSASIZE, _DVSBSIZE) #define DVSSCALE(pipe) _PIPE(pipe, _DVSASCALE, _DVSBSCALE) @@ -3028,6 +3029,7 @@ #define _SPRA_SURF 0x7029c #define _SPRA_KEYMAX 0x702a0 #define _SPRA_TILEOFF 0x702a4 +#define _SPRA_SURFLIVE 0x702ac #define _SPRA_SCALE 0x70304 #define SPRITE_SCALE_ENABLE (1<<31) #define SPRITE_FILTER_MASK (3<<29) @@ -3048,6 +3050,7 @@ #define _SPRB_SURF 0x7129c #define _SPRB_KEYMAX 0x712a0 #define _SPRB_TILEOFF 0x712a4 +#define _SPRB_SURFLIVE 0x712ac #define _SPRB_SCALE 0x71304 #define _SPRB_GAMC 0x71400 @@ -3059,6 +3062,7 @@ #define SPRKEYVAL(pipe) _PIPE(pipe, _SPRA_KEYVAL, _SPRB_KEYVAL) #define SPRKEYMSK(pipe) _PIPE(pipe, _SPRA_KEYMSK, _SPRB_KEYMSK) #define SPRSURF(pipe) _PIPE(pipe, _SPRA_SURF, _SPRB_SURF) +#define SPRSURFLIVE(pipe) _PIPE(pipe, _SPRA_SURFLIVE, _SPRB_SURFLIVE) #define SPRKEYMAX(pipe) _PIPE(pipe, _SPRA_KEYMAX, _SPRB_KEYMAX) #define SPRTILEOFF(pipe) _PIPE(pipe, _SPRA_TILEOFF, _SPRB_TILEOFF) #define SPRSCALE(pipe) _PIPE(pipe, _SPRA_SCALE, _SPRB_SCALE) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 03e5d86..edc5c9b 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1959,7 +1959,7 @@ static void intel_crtc_unpin_work_fn(struct intel_crtc *crtc, void *obj) mutex_unlock(&dev->struct_mutex); } -static void +void intel_crtc_queue_unpin(struct intel_crtc *crtc, struct drm_i915_gem_object *obj) { diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 5ca07e0..e839a67 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -210,6 +210,7 @@ struct intel_plane { struct drm_intel_sprite_colorkey *key); void (*get_colorkey)(struct drm_plane *plane, struct drm_intel_sprite_colorkey *key); + u32 (*current_surface)(struct drm_plane *plane); }; struct intel_watermark_params { @@ -364,6 +365,8 @@ extern void intel_panel_disable_backlight(struct drm_device *dev); extern void intel_panel_destroy_backlight(struct drm_device *dev); extern enum drm_connector_status intel_panel_detect(struct drm_device *dev); +extern void intel_crtc_queue_unpin(struct intel_crtc *crtc, + struct drm_i915_gem_object *obj); extern void intel_crtc_load_lut(struct drm_crtc *crtc); extern void intel_encoder_prepare(struct drm_encoder *encoder); extern void intel_encoder_commit(struct drm_encoder *encoder); diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index fbf03b9..11545ca 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -207,6 +207,16 @@ ivb_get_colorkey(struct drm_plane *plane, struct drm_intel_sprite_colorkey *key) key->flags = I915_SET_COLORKEY_NONE; } +static u32 +ivb_current_surface(struct drm_plane *plane) +{ + struct intel_plane *intel_plane; + + intel_plane = to_intel_plane(plane); + + return SPRSURFLIVE(intel_plane->pipe); +} + static void ilk_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb, struct drm_i915_gem_object *obj, int crtc_x, int crtc_y, @@ -387,6 +397,35 @@ ilk_get_colorkey(struct drm_plane *plane, struct drm_intel_sprite_colorkey *key) key->flags = I915_SET_COLORKEY_NONE; } +static u32 +ilk_current_surface(struct drm_plane *plane) +{ + struct intel_plane *intel_plane; + + intel_plane = to_intel_plane(plane); + + return DVSSURFLIVE(intel_plane->pipe); +} + +static void +intel_plane_queue_unpin(struct intel_plane *plane, + struct drm_i915_gem_object *obj) +{ + /* + * If the surface is currently being scanned out, we need to + * wait until the next vblank event latches in the new base address + * before we unpin it, or we may end up displaying the wrong data. + * However, if the old object isn't currently 'live', we can just + * unpin right away. + */ + if (plane->current_surface(&plane->base) != obj->gtt_offset) { + intel_unpin_fb_obj(obj); + return; + } + + intel_crtc_queue_unpin(to_intel_crtc(plane->base.crtc), obj); +} + static int intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, struct drm_framebuffer *fb, int crtc_x, int crtc_y, @@ -492,20 +531,8 @@ 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) { - /* - * It's fairly common to simply update the position of - * an existing object. In that case, we don't need to - * wait for vblank to avoid ugliness, we only need to - * do the pin & ref bookkeeping. - */ - if (old_obj != obj) { - mutex_unlock(&dev->struct_mutex); - intel_wait_for_vblank(dev, to_intel_crtc(crtc)->pipe); - mutex_lock(&dev->struct_mutex); - } - intel_unpin_fb_obj(old_obj); - } + if (old_obj) + intel_plane_queue_unpin(intel_plane, old_obj); out_unlock: mutex_unlock(&dev->struct_mutex); @@ -527,14 +554,12 @@ intel_disable_plane(struct drm_plane *plane) intel_plane->disable_plane(plane); - if (!intel_plane->obj) - goto out; - mutex_lock(&dev->struct_mutex); - intel_unpin_fb_obj(intel_plane->obj); - intel_plane->obj = NULL; + if (intel_plane->obj) { + intel_plane_queue_unpin(intel_plane, intel_plane->obj); + intel_plane->obj = NULL; + } mutex_unlock(&dev->struct_mutex); -out: return ret; } @@ -658,6 +683,7 @@ intel_plane_init(struct drm_device *dev, enum pipe pipe) intel_plane->disable_plane = ilk_disable_plane; intel_plane->update_colorkey = ilk_update_colorkey; intel_plane->get_colorkey = ilk_get_colorkey; + intel_plane->current_surface = ilk_current_surface; if (IS_GEN6(dev)) { plane_formats = snb_plane_formats; @@ -674,6 +700,7 @@ intel_plane_init(struct drm_device *dev, enum pipe pipe) intel_plane->disable_plane = ivb_disable_plane; intel_plane->update_colorkey = ivb_update_colorkey; intel_plane->get_colorkey = ivb_get_colorkey; + intel_plane->current_surface = ivb_current_surface; plane_formats = snb_plane_formats; num_plane_formats = ARRAY_SIZE(snb_plane_formats); -- 1.7.10