am 1abf5c3f: (-s ours) drm_hwcomposer: Add composition type to DrmComposition

* commit '1abf5c3fd61c1698e1ef7f9794cac5e22609a58c':
  drm_hwcomposer: Add composition type to DrmComposition
diff --git a/compositor.h b/compositor.h
index e148416..b424b37 100644
--- a/compositor.h
+++ b/compositor.h
@@ -90,6 +90,8 @@
   // Starts a fresh composition.
   virtual Composition *CreateComposition(Importer *importer) = 0;
 
+  // Transfers ownership of composition to the Compositor (whether or not this
+  // call returns success) for compositing.
   // On success returns a syncpoint fd that will be signaled when composition is
   // complete or -1 if compositing was completed by this method's return. On
   // error returns an integer less than -1. The composition is invalid after
diff --git a/drmcomposition.cpp b/drmcomposition.cpp
index 37e3bad..805fd26 100644
--- a/drmcomposition.cpp
+++ b/drmcomposition.cpp
@@ -77,7 +77,7 @@
     if ((*iter)->GetCrtcSupported(*crtc))
       ++num_planes;
   }
-  for (std::deque<DrmPlane *>::const_iterator iter = overlay_planes_.begin();
+  for (std::vector<DrmPlane *>::const_iterator iter = overlay_planes_.begin();
        iter != overlay_planes_.end(); ++iter) {
     if ((*iter)->GetCrtcSupported(*crtc))
       ++num_planes;
@@ -103,7 +103,7 @@
       break;
     }
   }
-  for (std::deque<DrmPlane *>::iterator iter = overlay_planes_.begin();
+  for (std::vector<DrmPlane *>::iterator iter = overlay_planes_.begin();
        !plane && iter != overlay_planes_.end(); ++iter) {
     if ((*iter)->GetCrtcSupported(*crtc)) {
       plane = *iter;
@@ -118,8 +118,57 @@
   return composition_map_[display]->AddLayer(layer, bo, crtc, plane);
 }
 
+int DrmComposition::AddDpmsMode(int display, uint32_t dpms_mode) {
+  return composition_map_[display]->AddDpmsMode(dpms_mode);
+}
+
 std::unique_ptr<DrmDisplayComposition> DrmComposition::TakeDisplayComposition(
     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 a8f9836..06af71d 100644
--- a/drmcomposition.h
+++ b/drmcomposition.h
@@ -41,8 +41,12 @@
 
   virtual unsigned GetRemainingLayers(int display, unsigned num_needed) const;
   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;
@@ -51,7 +55,7 @@
   Importer *importer_;
 
   std::vector<DrmPlane *> primary_planes_;
-  std::deque<DrmPlane *> overlay_planes_;
+  std::vector<DrmPlane *> overlay_planes_;
 
   /*
    * This _must_ be read-only after it's passed to QueueComposition. Otherwise
diff --git a/drmcompositor.cpp b/drmcompositor.cpp
index 4268ab5..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();
@@ -71,6 +78,7 @@
         drm_composition->TakeDisplayComposition(display));
     if (ret) {
       ALOGE("Failed to queue composition for display %d", display);
+      delete composition;
       return ret;
     }
   }
diff --git a/drmdisplaycomposition.cpp b/drmdisplaycomposition.cpp
index f049f2d..364a64e 100644
--- a/drmdisplaycomposition.cpp
+++ b/drmdisplaycomposition.cpp
@@ -26,6 +26,7 @@
 #include <cutils/log.h>
 #include <sw_sync.h>
 #include <sync/sync.h>
+#include <xf86drmMode.h>
 
 namespace android {
 
@@ -43,13 +44,14 @@
       importer_(NULL),
       type_(DRM_COMPOSITION_TYPE_EMPTY),
       timeline_fd_(-1),
-      timeline_(0) {
+      timeline_(0),
+      dpms_mode_(DRM_MODE_DPMS_ON) {
 }
 
 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)
@@ -109,6 +111,22 @@
   return 0;
 }
 
+int DrmDisplayComposition::AddDpmsMode(uint32_t dpms_mode) {
+  if (!validate_composition_type(DRM_COMPOSITION_TYPE_DPMS))
+    return -EINVAL;
+  dpms_mode_ = dpms_mode;
+  type_ = DRM_COMPOSITION_TYPE_DPMS;
+  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)
@@ -120,4 +138,8 @@
 DrmCompositionLayerVector_t *DrmDisplayComposition::GetCompositionLayers() {
   return &layers_;
 }
+
+uint32_t DrmDisplayComposition::dpms_mode() const {
+  return dpms_mode_;
+}
 }
diff --git a/drmdisplaycomposition.h b/drmdisplaycomposition.h
index bc8cf2e..09ad3ff 100644
--- a/drmdisplaycomposition.h
+++ b/drmdisplaycomposition.h
@@ -31,6 +31,7 @@
 enum DrmCompositionType {
   DRM_COMPOSITION_TYPE_EMPTY,
   DRM_COMPOSITION_TYPE_FRAME,
+  DRM_COMPOSITION_TYPE_DPMS,
 };
 
 typedef struct DrmCompositionLayer {
@@ -55,10 +56,13 @@
 
   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();
 
   DrmCompositionLayerVector_t *GetCompositionLayers();
+  uint32_t dpms_mode() const;
 
  private:
   DrmDisplayComposition(const DrmDisplayComposition &) = delete;
@@ -74,6 +78,7 @@
   int timeline_;
 
   DrmCompositionLayerVector_t layers_;
+  uint32_t dpms_mode_;
 };
 }
 
diff --git a/drmdisplaycompositor.cpp b/drmdisplaycompositor.cpp
index 2a11ee7..8168e1a 100644
--- a/drmdisplaycompositor.cpp
+++ b/drmdisplaycompositor.cpp
@@ -40,6 +40,7 @@
       worker_(this),
       frame_no_(0),
       initialized_(false),
+      active_(false),
       dump_frames_composited_(0),
       dump_last_timestamp_ns_(0) {
   struct timespec ts;
@@ -95,6 +96,15 @@
     std::unique_ptr<DrmDisplayComposition> composition) {
   switch (composition->type()) {
   case DRM_COMPOSITION_TYPE_FRAME:
+    if (!active_)
+      return -ENODEV;
+    break;
+  case DRM_COMPOSITION_TYPE_DPMS:
+    /*
+     * Update the state as soon as we get it so we can start/stop queuing
+     * frames asap.
+     */
+    active_ = (composition->dpms_mode() == DRM_MODE_DPMS_ON);
     break;
   case DRM_COMPOSITION_TYPE_EMPTY:
     return 0;
@@ -147,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(),
@@ -189,6 +215,23 @@
   return ret;
 }
 
+int DrmDisplayCompositor::ApplyDpms(DrmDisplayComposition *display_comp) {
+  DrmConnector *conn = drm_->GetConnectorForDisplay(display_);
+  if (!conn) {
+    ALOGE("Failed to get DrmConnector for display %d", display_);
+    return -ENODEV;
+  }
+
+  const DrmProperty &prop = conn->dpms_property();
+  int ret = drmModeConnectorSetProperty(drm_->fd(), conn->id(), prop.id(),
+                                        display_comp->dpms_mode());
+  if (ret) {
+    ALOGE("Failed to set DPMS property for connector %d", conn->id());
+    return ret;
+  }
+  return 0;
+}
+
 int DrmDisplayCompositor::Composite() {
   ATRACE_CALL();
   int ret = pthread_mutex_lock(&lock_);
@@ -222,6 +265,11 @@
     }
     ++dump_frames_composited_;
     break;
+  case DRM_COMPOSITION_TYPE_DPMS:
+    ret = ApplyDpms(composition.get());
+    if (ret)
+      ALOGE("Failed to apply dpms for display %d", display_);
+    return ret;
   default:
     ALOGE("Unknown composition type %d", composition->type());
     return -EINVAL;
diff --git a/drmdisplaycompositor.h b/drmdisplaycompositor.h
index 928ce46..9f50664 100644
--- a/drmdisplaycompositor.h
+++ b/drmdisplaycompositor.h
@@ -47,6 +47,7 @@
   DrmDisplayCompositor(const DrmDisplayCompositor &) = delete;
 
   int ApplyFrame(DrmDisplayComposition *display_comp);
+  int ApplyDpms(DrmDisplayComposition *display_comp);
 
   DrmResources *drm_;
   int display_;
@@ -59,6 +60,7 @@
   uint64_t frame_no_;
 
   bool initialized_;
+  bool active_;
 
   // mutable since we need to acquire in HaveQueuedComposites
   mutable pthread_mutex_t lock_;
diff --git a/drmresources.cpp b/drmresources.cpp
index 2cda217..9be990f 100644
--- a/drmresources.cpp
+++ b/drmresources.cpp
@@ -467,19 +467,22 @@
     return -EINVAL;
   }
 
-  DrmConnector *c = GetConnectorForDisplay(display);
-  if (!c) {
-    ALOGE("Failed to get DrmConnector for display %d", display);
-    return -ENODEV;
+  DrmComposition *comp = (DrmComposition *)compositor_.CreateComposition(NULL);
+  if (!comp) {
+    ALOGE("Failed to create composition for dpms on %d", display);
+    return -ENOMEM;
   }
-
-  const DrmProperty &prop = c->dpms_property();
-  int ret = drmModeConnectorSetProperty(fd_, c->id(), prop.id(), mode);
+  int ret = comp->AddDpmsMode(display, mode);
   if (ret) {
-    ALOGE("Failed to set DPMS property for connector %d", c->id());
+    ALOGE("Failed to add dpms %ld to composition on %d %d", mode, display, ret);
+    delete comp;
     return ret;
   }
-
+  ret = compositor_.QueueComposition((Composition *)comp);
+  if (ret) {
+    ALOGE("Failed to queue dpms composition on %d %d", display, ret);
+    return ret;
+  }
   return 0;
 }
 
diff --git a/hwcomposer.cpp b/hwcomposer.cpp
index 02c13af..b4fb340 100644
--- a/hwcomposer.cpp
+++ b/hwcomposer.cpp
@@ -407,9 +407,10 @@
   }
 
   ret = ctx->drm.compositor()->QueueComposition(composition);
+  composition = NULL;
   if (ret) {
     ALOGE("Failed to queue the composition");
-    hwc_set_cleanup(num_displays, display_contents, composition);
+    hwc_set_cleanup(num_displays, display_contents, NULL);
     return ret;
   }
   hwc_set_cleanup(num_displays, display_contents, NULL);