drm/i915/fbc: choose the new FBC CRTC during atomic check
authorPaulo Zanoni <paulo.r.zanoni@intel.com>
Tue, 19 Jan 2016 13:35:50 +0000 (11:35 -0200)
committerPaulo Zanoni <paulo.r.zanoni@intel.com>
Fri, 29 Jan 2016 20:16:45 +0000 (18:16 -0200)
This opens the possibility of implementing nicer schemes to choose the
CRTC, such as checking the amount of stolen memory available, or
choosing the best pipe on platforms that don't die FBC to pipe or
plane A.

This code was written for another refactor that I ended up discarding,
so I don't actually need it, but I figured this patch would be an
improvement on its own so I kept it on the series.

Reviewed-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Signed-off-by: Paulo Zanoni <paulo.r.zanoni@intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1453210558-7875-18-git-send-email-paulo.r.zanoni@intel.com
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_drv.h
drivers/gpu/drm/i915/intel_fbc.c

index 189367cea993bc138f5fb9b5ee2515d7ee339bf4..cd57613176fc1610d2d0657dd6e2218ccf3dcb23 100644 (file)
@@ -13402,6 +13402,7 @@ static int intel_atomic_check(struct drm_device *dev,
        if (ret)
                return ret;
 
+       intel_fbc_choose_crtc(dev_priv, state);
        calc_watermark_data(state);
 
        return 0;
index 00a835990bdb9f63f3572f788f0797ee902ad696..93ba14a3bb7691d0298341dac58a7e09e7205d7d 100644 (file)
@@ -492,6 +492,8 @@ struct intel_crtc_state {
 
        bool ips_enabled;
 
+       bool enable_fbc;
+
        bool double_wide;
 
        bool dp_encoder_is_mst;
@@ -1329,6 +1331,8 @@ static inline void intel_fbdev_restore_mode(struct drm_device *dev)
 #endif
 
 /* intel_fbc.c */
+void intel_fbc_choose_crtc(struct drm_i915_private *dev_priv,
+                          struct drm_atomic_state *state);
 bool intel_fbc_is_active(struct drm_i915_private *dev_priv);
 void intel_fbc_pre_update(struct intel_crtc *crtc);
 void intel_fbc_post_update(struct intel_crtc *crtc);
index c2ef400a959962c9a900a9948410a069ed24b902..5bf7f844d82753a388c627cd54579aee00c238cf 100644 (file)
@@ -826,7 +826,7 @@ static bool intel_fbc_can_activate(struct intel_crtc *crtc)
        return true;
 }
 
-static bool intel_fbc_can_enable(struct intel_crtc *crtc)
+static bool intel_fbc_can_choose(struct intel_crtc *crtc)
 {
        struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
 
@@ -1014,12 +1014,77 @@ void intel_fbc_flush(struct drm_i915_private *dev_priv,
        mutex_unlock(&fbc->lock);
 }
 
+/**
+ * intel_fbc_choose_crtc - select a CRTC to enable FBC on
+ * @dev_priv: i915 device instance
+ * @state: the atomic state structure
+ *
+ * This function looks at the proposed state for CRTCs and planes, then chooses
+ * which pipe is going to have FBC by setting intel_crtc_state->enable_fbc to
+ * true.
+ *
+ * Later, intel_fbc_enable is going to look for state->enable_fbc and then maybe
+ * enable FBC for the chosen CRTC. If it does, it will set dev_priv->fbc.crtc.
+ */
+void intel_fbc_choose_crtc(struct drm_i915_private *dev_priv,
+                          struct drm_atomic_state *state)
+{
+       struct intel_fbc *fbc = &dev_priv->fbc;
+       struct drm_crtc *crtc;
+       struct drm_crtc_state *crtc_state;
+       struct drm_plane *plane;
+       struct drm_plane_state *plane_state;
+       bool fbc_crtc_present = false;
+       int i, j;
+
+       mutex_lock(&fbc->lock);
+
+       for_each_crtc_in_state(state, crtc, crtc_state, i) {
+               if (fbc->crtc == to_intel_crtc(crtc)) {
+                       fbc_crtc_present = true;
+                       break;
+               }
+       }
+       /* This atomic commit doesn't involve the CRTC currently tied to FBC. */
+       if (!fbc_crtc_present && fbc->crtc != NULL)
+               goto out;
+
+       /* Simply choose the first CRTC that is compatible and has a visible
+        * plane. We could go for fancier schemes such as checking the plane
+        * size, but this would just affect the few platforms that don't tie FBC
+        * to pipe or plane A. */
+       for_each_plane_in_state(state, plane, plane_state, i) {
+               struct intel_plane_state *intel_plane_state =
+                       to_intel_plane_state(plane_state);
+
+               if (!intel_plane_state->visible)
+                       continue;
+
+               for_each_crtc_in_state(state, crtc, crtc_state, j) {
+                       struct intel_crtc_state *intel_crtc_state =
+                               to_intel_crtc_state(crtc_state);
+
+                       if (plane_state->crtc != crtc)
+                               continue;
+
+                       if (!intel_fbc_can_choose(to_intel_crtc(crtc)))
+                               break;
+
+                       intel_crtc_state->enable_fbc = true;
+                       goto out;
+               }
+       }
+
+out:
+       mutex_unlock(&fbc->lock);
+}
+
 /**
  * intel_fbc_enable: tries to enable FBC on the CRTC
  * @crtc: the CRTC
  *
- * This function checks if it's possible to enable FBC on the following CRTC,
- * then enables it. Notice that it doesn't activate FBC.
+ * This function checks if the given CRTC was chosen for FBC, then enables it if
+ * possible. Notice that it doesn't activate FBC.
  */
 void intel_fbc_enable(struct intel_crtc *crtc)
 {
@@ -1036,12 +1101,12 @@ void intel_fbc_enable(struct intel_crtc *crtc)
                goto out;
        }
 
+       if (!crtc->config->enable_fbc)
+               goto out;
+
        WARN_ON(fbc->active);
        WARN_ON(fbc->crtc != NULL);
 
-       if (!intel_fbc_can_enable(crtc))
-               goto out;
-
        intel_fbc_update_state_cache(crtc);
        if (intel_fbc_alloc_cfb(crtc)) {
                set_no_fbc_reason(dev_priv, "not enough stolen memory");