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 | 2 ++ drivers/gpu/drm/i915/intel_display.c | 2 +- drivers/gpu/drm/i915/intel_drv.h | 3 ++ drivers/gpu/drm/i915/intel_sprite.c | 69 ++++++++++++++++++++++++------------ 4 files changed, 53 insertions(+), 23 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 72e5693..74a3f01 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -3411,6 +3411,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) @@ -3487,6 +3488,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 SPROFFSET(pipe) _PIPE(pipe, _SPRA_OFFSET, _SPRB_OFFSET) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 4b50d5f..dc4bf49 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2270,7 +2270,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 19df4ec..e6dda01 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -383,6 +383,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 { @@ -648,6 +649,8 @@ extern int intel_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode, int x, int y, struct drm_framebuffer *old_fb); extern void intel_modeset_disable(struct drm_device *dev); extern void intel_crtc_restore_mode(struct drm_crtc *crtc); +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_crtc_update_dpms(struct drm_crtc *crtc); extern void intel_encoder_destroy(struct drm_encoder *encoder); diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index 9d95589..d129282 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -397,6 +397,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, @@ -602,6 +612,35 @@ format_is_yuv(uint32_t format) } } +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) != i915_gem_obj_ggtt_offset(obj)) { + 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, @@ -830,20 +869,8 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, intel_disable_primary(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); @@ -861,16 +888,12 @@ intel_disable_plane(struct drm_plane *plane) intel_enable_primary(plane->crtc); intel_plane->disable_plane(plane); - if (!intel_plane->obj) - goto out; - - intel_wait_for_vblank(dev, intel_plane->pipe); - 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; } @@ -1029,6 +1052,7 @@ intel_plane_init(struct drm_device *dev, enum pipe pipe, int plane) 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; @@ -1061,6 +1085,7 @@ intel_plane_init(struct drm_device *dev, enum pipe pipe, int plane) 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.8.3.2