drm/i915: Fix the overlay frontbuffer tracking
authorVille Syrjälä <ville.syrjala@linux.intel.com>
Wed, 7 Dec 2016 17:28:06 +0000 (19:28 +0200)
committerVille Syrjälä <ville.syrjala@linux.intel.com>
Thu, 22 Dec 2016 19:29:34 +0000 (21:29 +0200)
Do the overlay frontbuffer tracking properly so that it matches
the state of the overlay on/off/continue requests.

One slight problem is that intel_frontbuffer_flip_complete()
may get delayed by an arbitrarily liong time due to the fact that
the overlay code likes to bail out when a signal occurs. So the
flip may not get completed until the ioctl is restarted. But fixing
that would require bigger surgery, so I decided to ignore it for now.

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1481131693-27993-5-git-send-email-ville.syrjala@linux.intel.com
Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>
drivers/gpu/drm/i915/intel_overlay.c

index 94f9e468e07048840c69eb25a2d28e8ddcad5ee5..a618511a32ef9566b2eadc12a4f41786f9468501 100644 (file)
@@ -272,8 +272,30 @@ static int intel_overlay_on(struct intel_overlay *overlay)
        return intel_overlay_do_wait_request(overlay, req, NULL);
 }
 
+static void intel_overlay_flip_prepare(struct intel_overlay *overlay,
+                                      struct i915_vma *vma)
+{
+       enum pipe pipe = overlay->crtc->pipe;
+
+       WARN_ON(overlay->old_vma);
+
+       i915_gem_track_fb(overlay->vma ? overlay->vma->obj : NULL,
+                         vma ? vma->obj : NULL,
+                         INTEL_FRONTBUFFER_OVERLAY(pipe));
+
+       intel_frontbuffer_flip_prepare(overlay->i915,
+                                      INTEL_FRONTBUFFER_OVERLAY(pipe));
+
+       overlay->old_vma = overlay->vma;
+       if (vma)
+               overlay->vma = i915_vma_get(vma);
+       else
+               overlay->vma = NULL;
+}
+
 /* overlay needs to be enabled in OCMD reg */
 static int intel_overlay_continue(struct intel_overlay *overlay,
+                                 struct i915_vma *vma,
                                  bool load_polyphase_filter)
 {
        struct drm_i915_private *dev_priv = overlay->i915;
@@ -308,43 +330,44 @@ static int intel_overlay_continue(struct intel_overlay *overlay,
        intel_ring_emit(ring, flip_addr);
        intel_ring_advance(ring);
 
+       intel_overlay_flip_prepare(overlay, vma);
+
        intel_overlay_submit_request(overlay, req, NULL);
 
        return 0;
 }
 
-static void intel_overlay_release_old_vid_tail(struct i915_gem_active *active,
-                                              struct drm_i915_gem_request *req)
+static void intel_overlay_release_old_vma(struct intel_overlay *overlay)
 {
-       struct intel_overlay *overlay =
-               container_of(active, typeof(*overlay), last_flip);
        struct i915_vma *vma;
 
        vma = fetch_and_zero(&overlay->old_vma);
        if (WARN_ON(!vma))
                return;
 
-       i915_gem_track_fb(vma->obj, NULL,
-                         INTEL_FRONTBUFFER_OVERLAY(overlay->crtc->pipe));
+       intel_frontbuffer_flip_complete(overlay->i915,
+                                       INTEL_FRONTBUFFER_OVERLAY(overlay->crtc->pipe));
 
        i915_gem_object_unpin_from_display_plane(vma);
        i915_vma_put(vma);
 }
 
+static void intel_overlay_release_old_vid_tail(struct i915_gem_active *active,
+                                              struct drm_i915_gem_request *req)
+{
+       struct intel_overlay *overlay =
+               container_of(active, typeof(*overlay), last_flip);
+
+       intel_overlay_release_old_vma(overlay);
+}
+
 static void intel_overlay_off_tail(struct i915_gem_active *active,
                                   struct drm_i915_gem_request *req)
 {
        struct intel_overlay *overlay =
                container_of(active, typeof(*overlay), last_flip);
-       struct i915_vma *vma;
 
-       /* never have the overlay hw on without showing a frame */
-       vma = fetch_and_zero(&overlay->vma);
-       if (WARN_ON(!vma))
-               return;
-
-       i915_gem_object_unpin_from_display_plane(vma);
-       i915_vma_put(vma);
+       intel_overlay_release_old_vma(overlay);
 
        overlay->crtc->overlay = NULL;
        overlay->crtc = NULL;
@@ -398,6 +421,8 @@ static int intel_overlay_off(struct intel_overlay *overlay)
        }
        intel_ring_advance(ring);
 
+       intel_overlay_flip_prepare(overlay, NULL);
+
        return intel_overlay_do_wait_request(overlay, req,
                                             intel_overlay_off_tail);
 }
@@ -836,18 +861,10 @@ static int intel_overlay_do_put_image(struct intel_overlay *overlay,
 
        intel_overlay_unmap_regs(overlay, regs);
 
-       ret = intel_overlay_continue(overlay, scale_changed);
+       ret = intel_overlay_continue(overlay, vma, scale_changed);
        if (ret)
                goto out_unpin;
 
-       i915_gem_track_fb(overlay->vma ? overlay->vma->obj : NULL,
-                         vma->obj, INTEL_FRONTBUFFER_OVERLAY(pipe));
-
-       overlay->old_vma = overlay->vma;
-       overlay->vma = vma;
-
-       intel_frontbuffer_flip(dev_priv, INTEL_FRONTBUFFER_OVERLAY(pipe));
-
        return 0;
 
 out_unpin:
@@ -1215,6 +1232,7 @@ int intel_overlay_put_image_ioctl(struct drm_device *dev, void *data,
 
        mutex_unlock(&dev->struct_mutex);
        drm_modeset_unlock_all(dev);
+       i915_gem_object_put(new_bo);
 
        kfree(params);