drm_hwcomposer: Disable unused planes

Right before queuing up a composition, go through the
list of unused planes and add disable markers such
that they don't remain active when the new frame is
posted.

BUG=chrome-os-parter:42311
TEST=Tested on smaug, turned on/off bunch of times, no dup icons

Change-Id: Ic2e5e210873efb6dc41fd43682fe00db33c2a28e
Signed-off-by: Sean Paul <seanpaul@chromium.org>
diff --git a/drmcomposition.cpp b/drmcomposition.cpp
index 3f5f356..805fd26 100644
--- a/drmcomposition.cpp
+++ b/drmcomposition.cpp
@@ -126,4 +126,49 @@
     int display) {
   return std::move(composition_map_[display]);
 }
+
+int DrmComposition::DisableUnusedPlanes() {
+  for (DrmResources::ConnectorIter iter = drm_->begin_connectors();
+       iter != drm_->end_connectors(); ++iter) {
+    int display = (*iter)->display();
+    DrmDisplayComposition *comp = GetDisplayComposition(display);
+
+    /*
+     * Leave empty compositions alone
+     * TODO: re-visit this and potentially disable leftover planes after the
+     *       active compositions have gobbled up all they can
+     */
+    if (comp->type() == DRM_COMPOSITION_TYPE_EMPTY)
+      continue;
+
+    DrmCrtc *crtc = drm_->GetCrtcForDisplay(display);
+    if (!crtc) {
+      ALOGE("Failed to find crtc for display %d", display);
+      continue;
+    }
+
+    for (std::vector<DrmPlane *>::iterator iter = primary_planes_.begin();
+         iter != primary_planes_.end(); ++iter) {
+      if ((*iter)->GetCrtcSupported(*crtc)) {
+        comp->AddPlaneDisable(*iter);
+        primary_planes_.erase(iter);
+        break;
+      }
+    }
+    for (std::vector<DrmPlane *>::iterator iter = overlay_planes_.begin();
+         iter != overlay_planes_.end();) {
+      if ((*iter)->GetCrtcSupported(*crtc)) {
+        comp->AddPlaneDisable(*iter);
+        iter = overlay_planes_.erase(iter);
+      } else {
+        iter++;
+      }
+    }
+  }
+  return 0;
+}
+
+DrmDisplayComposition *DrmComposition::GetDisplayComposition(int display) {
+  return composition_map_[display].get();
+}
 }
diff --git a/drmcomposition.h b/drmcomposition.h
index 902d7c7..06af71d 100644
--- a/drmcomposition.h
+++ b/drmcomposition.h
@@ -43,7 +43,10 @@
   virtual int AddLayer(int display, hwc_layer_1_t *layer, hwc_drm_bo_t *bo);
   int AddDpmsMode(int display, uint32_t dpms_mode);
 
+  int DisableUnusedPlanes();
+
   std::unique_ptr<DrmDisplayComposition> TakeDisplayComposition(int display);
+  DrmDisplayComposition *GetDisplayComposition(int display);
 
  private:
   DrmComposition(const DrmComposition &) = delete;
diff --git a/drmcompositor.cpp b/drmcompositor.cpp
index 9ade368..3bab93f 100644
--- a/drmcompositor.cpp
+++ b/drmcompositor.cpp
@@ -64,6 +64,13 @@
 
 int DrmCompositor::QueueComposition(Composition *composition) {
   DrmComposition *drm_composition = (DrmComposition *)composition;
+
+  int ret = drm_composition->DisableUnusedPlanes();
+  if (ret) {
+    ALOGE("Failed to disable unused planes %d", ret);
+    return ret;
+  }
+
   for (DrmResources::ConnectorIter iter = drm_->begin_connectors();
        iter != drm_->end_connectors(); ++iter) {
     int display = (*iter)->display();
diff --git a/drmdisplaycomposition.cpp b/drmdisplaycomposition.cpp
index 2f8d651..364a64e 100644
--- a/drmdisplaycomposition.cpp
+++ b/drmdisplaycomposition.cpp
@@ -51,7 +51,7 @@
 DrmDisplayComposition::~DrmDisplayComposition() {
   for (DrmCompositionLayerVector_t::iterator iter = layers_.begin();
        iter != layers_.end(); ++iter) {
-    if (importer_)
+    if (importer_ && iter->bo.fb_id)
       importer_->ReleaseBuffer(&iter->bo);
 
     if (iter->layer.acquireFenceFd >= 0)
@@ -119,6 +119,14 @@
   return 0;
 }
 
+int DrmDisplayComposition::AddPlaneDisable(DrmPlane *plane) {
+  DrmCompositionLayer_t c_layer;
+  c_layer.crtc = NULL;
+  c_layer.plane = plane;
+  layers_.push_back(c_layer);
+  return 0;
+}
+
 int DrmDisplayComposition::FinishComposition() {
   int ret = sw_sync_timeline_inc(timeline_fd_, timeline_);
   if (ret)
diff --git a/drmdisplaycomposition.h b/drmdisplaycomposition.h
index 2ae696f..09ad3ff 100644
--- a/drmdisplaycomposition.h
+++ b/drmdisplaycomposition.h
@@ -56,6 +56,7 @@
 
   int AddLayer(hwc_layer_1_t *layer, hwc_drm_bo_t *bo, DrmCrtc *crtc,
                DrmPlane *plane);
+  int AddPlaneDisable(DrmPlane *plane);
   int AddDpmsMode(uint32_t dpms_mode);
 
   int FinishComposition();
diff --git a/drmdisplaycompositor.cpp b/drmdisplaycompositor.cpp
index 80b71f5..8168e1a 100644
--- a/drmdisplaycompositor.cpp
+++ b/drmdisplaycompositor.cpp
@@ -157,9 +157,25 @@
     }
 
     DrmPlane *plane = iter->plane;
+    DrmCrtc *crtc = iter->crtc;
+
+    // Disable the plane if there's no crtc
+    if (!crtc) {
+      ret =
+          drmModePropertySetAdd(pset, plane->id(), plane->crtc_property().id(),
+                                0) ||
+          drmModePropertySetAdd(pset, plane->id(), plane->fb_property().id(),
+                                0);
+      if (ret) {
+        ALOGE("Failed to add plane %d disable to pset", plane->id());
+        break;
+      }
+      continue;
+    }
+
     ret =
         drmModePropertySetAdd(pset, plane->id(), plane->crtc_property().id(),
-                              iter->crtc->id()) ||
+                              crtc->id()) ||
         drmModePropertySetAdd(pset, plane->id(), plane->fb_property().id(),
                               iter->bo.fb_id) ||
         drmModePropertySetAdd(pset, plane->id(), plane->crtc_x_property().id(),