merge in mnc-release history after reset to mnc-dev
diff --git a/Android.mk b/Android.mk
index e20615e..eadfe2b 100644
--- a/Android.mk
+++ b/Android.mk
@@ -44,6 +44,8 @@
         drmcompositorworker.cpp \
 	drmconnector.cpp \
 	drmcrtc.cpp \
+        drmdisplaycomposition.cpp \
+        drmdisplaycompositor.cpp \
 	drmencoder.cpp \
 	drmmode.cpp \
 	drmplane.cpp \
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 07e08da..7a50601 100644
--- a/drmcomposition.cpp
+++ b/drmcomposition.cpp
@@ -31,22 +31,8 @@
 
 static const bool kUseOverlayPlanes = true;
 
-DrmCompositionLayer::DrmCompositionLayer() : crtc(NULL), plane(NULL) {
-  memset(&layer, 0, sizeof(layer));
-  layer.acquireFenceFd = -1;
-  memset(&bo, 0, sizeof(bo));
-}
-
-DrmCompositionLayer::~DrmCompositionLayer() {
-}
-
-DrmComposition::DrmComposition(DrmResources *drm, Importer *importer,
-                               uint64_t frame_no)
-    : drm_(drm),
-      importer_(importer),
-      frame_no_(frame_no),
-      timeline_fd_(-1),
-      timeline_(0) {
+DrmComposition::DrmComposition(DrmResources *drm, Importer *importer)
+    : drm_(drm), importer_(importer) {
   for (DrmResources::PlaneIter iter = drm_->begin_planes();
        iter != drm_->end_planes(); ++iter) {
     if ((*iter)->type() == DRM_PLANE_TYPE_PRIMARY)
@@ -57,25 +43,23 @@
 }
 
 DrmComposition::~DrmComposition() {
-  for (DrmCompositionLayerMap_t::iterator iter = composition_map_.begin();
-       iter != composition_map_.end(); ++iter) {
-    importer_->ReleaseBuffer(&iter->second.bo);
-
-    if (iter->second.layer.acquireFenceFd >= 0)
-      close(iter->second.layer.acquireFenceFd);
-  }
-
-  if (timeline_fd_ >= 0)
-    close(timeline_fd_);
 }
 
 int DrmComposition::Init() {
-  int ret = sw_sync_timeline_create();
-  if (ret < 0) {
-    ALOGE("Failed to create sw sync timeline %d", ret);
-    return ret;
+  for (DrmResources::ConnectorIter iter = drm_->begin_connectors();
+       iter != drm_->end_connectors(); ++iter) {
+    int display = (*iter)->display();
+    composition_map_[display].reset(new DrmDisplayComposition());
+    if (!composition_map_[display]) {
+      ALOGE("Failed to allocate new display composition\n");
+      return -ENOMEM;
+    }
+    int ret = composition_map_[(*iter)->display()]->Init(drm_, importer_);
+    if (ret) {
+      ALOGE("Failed to init display composition for %d", (*iter)->display());
+      return ret;
+    }
   }
-  timeline_fd_ = ret;
   return 0;
 }
 
@@ -83,7 +67,7 @@
                                             unsigned num_needed) const {
   DrmCrtc *crtc = drm_->GetCrtcForDisplay(display);
   if (!crtc) {
-    ALOGW("Failed to find crtc for display %d", display);
+    ALOGE("Failed to find crtc for display %d", display);
     return 0;
   }
 
@@ -103,65 +87,43 @@
 
 int DrmComposition::AddLayer(int display, hwc_layer_1_t *layer,
                              hwc_drm_bo *bo) {
-  if (layer->transform != 0)
-    return -EINVAL;
-
   DrmCrtc *crtc = drm_->GetCrtcForDisplay(display);
   if (!crtc) {
-    ALOGE("Could not find crtc for display %d", display);
+    ALOGE("Failed to find crtc for display %d", display);
     return -ENODEV;
   }
 
-  ++timeline_;
-  layer->releaseFenceFd =
-      sw_sync_fence_create(timeline_fd_, "drm_fence", timeline_);
-  if (layer->releaseFenceFd < 0) {
-    ALOGE("Could not create release fence %d", layer->releaseFenceFd);
-    return layer->releaseFenceFd;
-  }
-
-  DrmCompositionLayer_t c_layer;
-  c_layer.layer = *layer;
-  c_layer.bo = *bo;
-  c_layer.crtc = crtc;
-
-  // First try to find a primary plane for the layer, then fallback on overlays
+  // Find a plane for the layer
+  DrmPlane *plane = NULL;
   for (std::vector<DrmPlane *>::iterator iter = primary_planes_.begin();
        iter != primary_planes_.end(); ++iter) {
     if ((*iter)->GetCrtcSupported(*crtc)) {
-      c_layer.plane = (*iter);
+      plane = *iter;
       primary_planes_.erase(iter);
       break;
     }
   }
   for (std::deque<DrmPlane *>::iterator iter = overlay_planes_.begin();
-       !c_layer.plane && iter != overlay_planes_.end(); ++iter) {
+       !plane && iter != overlay_planes_.end(); ++iter) {
     if ((*iter)->GetCrtcSupported(*crtc)) {
-      c_layer.plane = (*iter);
+      plane = *iter;
       overlay_planes_.erase(iter);
       break;
     }
   }
-  if (!c_layer.plane) {
-    close(layer->releaseFenceFd);
-    layer->releaseFenceFd = -1;
+  if (!plane) {
+    ALOGE("Failed to find plane for display %d", display);
     return -ENOENT;
   }
-
-  layer->acquireFenceFd = -1;  // We own this now
-  composition_map_.insert(DrmCompositionLayerPair_t(display, c_layer));
-  return 0;
+  return composition_map_[display]->AddLayer(layer, bo, crtc, plane);
 }
 
-int DrmComposition::FinishComposition() {
-  int ret = sw_sync_timeline_inc(timeline_fd_, timeline_);
-  if (ret)
-    ALOGE("Failed to increment sync timeline %d", ret);
-
-  return ret;
+int DrmComposition::AddDpmsMode(int display, uint32_t dpms_mode) {
+  return composition_map_[display]->AddDpmsMode(dpms_mode);
 }
 
-DrmCompositionLayerMap_t *DrmComposition::GetCompositionMap() {
-  return &composition_map_;
+std::unique_ptr<DrmDisplayComposition> DrmComposition::TakeDisplayComposition(
+    int display) {
+  return std::move(composition_map_[display]);
 }
 }
diff --git a/drmcomposition.h b/drmcomposition.h
index 5c47fbf..e490811 100644
--- a/drmcomposition.h
+++ b/drmcomposition.h
@@ -19,6 +19,7 @@
 
 #include "compositor.h"
 #include "drm_hwcomposer.h"
+#include "drmdisplaycomposition.h"
 #include "drmplane.h"
 #include "importer.h"
 
@@ -31,46 +32,35 @@
 
 namespace android {
 
-typedef struct DrmCompositionLayer {
-  DrmCompositionLayer();
-  ~DrmCompositionLayer();
-
-  hwc_layer_1_t layer;
-  hwc_drm_bo_t bo;
-  DrmCrtc *crtc;
-  DrmPlane *plane;
-} DrmCompositionLayer_t;
-
-typedef std::multimap<int, DrmCompositionLayer> DrmCompositionLayerMap_t;
-typedef std::pair<int, DrmCompositionLayer> DrmCompositionLayerPair_t;
-
 class DrmComposition : public Composition {
  public:
-  DrmComposition(DrmResources *drm, Importer *importer, uint64_t frame_no);
+  DrmComposition(DrmResources *drm, Importer *importer);
   ~DrmComposition();
 
   virtual int Init();
 
   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 FinishComposition();
-
-  DrmCompositionLayerMap_t *GetCompositionMap();
+  std::unique_ptr<DrmDisplayComposition> TakeDisplayComposition(int display);
 
  private:
+  DrmComposition(const DrmComposition &) = delete;
+
   DrmResources *drm_;
   Importer *importer_;
 
-  uint64_t frame_no_;
-
-  int timeline_fd_;
-  int timeline_;
-
   std::vector<DrmPlane *> primary_planes_;
   std::deque<DrmPlane *> overlay_planes_;
-  DrmCompositionLayerMap_t composition_map_;
+
+  /*
+   * This _must_ be read-only after it's passed to QueueComposition. Otherwise
+   * locking is required to maintain consistency across the compositor threads.
+   */
+  std::map<int, std::unique_ptr<DrmDisplayComposition>> composition_map_;
 };
+
 }
 
 #endif  // ANDROID_DRM_COMPOSITION_H_
diff --git a/drmcompositor.cpp b/drmcompositor.cpp
index 0c6d445..9ade368 100644
--- a/drmcompositor.cpp
+++ b/drmcompositor.cpp
@@ -14,63 +14,41 @@
  * limitations under the License.
  */
 
-#define ATRACE_TAG ATRACE_TAG_GRAPHICS
 #define LOG_TAG "hwc-drm-compositor"
 
 #include "drmcompositor.h"
-#include "drmcrtc.h"
-#include "drmplane.h"
+#include "drmdisplaycompositor.h"
 #include "drmresources.h"
 
-#include <pthread.h>
 #include <sstream>
 #include <stdlib.h>
-#include <time.h>
-#include <utils/Trace.h>
 
 #include <cutils/log.h>
-#include <sync/sync.h>
 
 namespace android {
 
-DrmCompositor::DrmCompositor(DrmResources *drm)
-    : drm_(drm),
-      worker_(this),
-      active_composition_(NULL),
-      frame_no_(0),
-      initialized_(false),
-      dump_frames_composited_(0),
-      dump_last_timestamp_ns_(0) {
-  struct timespec ts;
-  if (clock_gettime(CLOCK_MONOTONIC, &ts))
-    return;
-  dump_last_timestamp_ns_ = ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec;
+DrmCompositor::DrmCompositor(DrmResources *drm) : drm_(drm) {
 }
 
 DrmCompositor::~DrmCompositor() {
-  if (initialized_)
-    pthread_mutex_destroy(&lock_);
 }
 
 int DrmCompositor::Init() {
-  int ret = pthread_mutex_init(&lock_, NULL);
-  if (ret) {
-    ALOGE("Failed to initialize drm compositor lock %d\n", ret);
-    return ret;
-  }
-  ret = worker_.Init();
-  if (ret) {
-    pthread_mutex_destroy(&lock_);
-    ALOGE("Failed to initialize compositor worker %d\n", ret);
-    return ret;
+  for (DrmResources::ConnectorIter iter = drm_->begin_connectors();
+       iter != drm_->end_connectors(); ++iter) {
+    int display = (*iter)->display();
+    int ret = compositor_map_[display].Init(drm_, display);
+    if (ret) {
+      ALOGE("Failed to initialize display compositor for %d", display);
+      return ret;
+    }
   }
 
-  initialized_ = true;
   return 0;
 }
 
 Composition *DrmCompositor::CreateComposition(Importer *importer) {
-  DrmComposition *composition = new DrmComposition(drm_, importer, frame_no_++);
+  DrmComposition *composition = new DrmComposition(drm_, importer);
   if (!composition) {
     ALOGE("Failed to allocate drm composition");
     return NULL;
@@ -85,187 +63,35 @@
 }
 
 int DrmCompositor::QueueComposition(Composition *composition) {
-  int ret = pthread_mutex_lock(&lock_);
-  if (ret) {
-    ALOGE("Failed to acquire compositor lock %d", ret);
-    return ret;
-  }
-
-  composite_queue_.push((DrmComposition *)composition);
-
-  ret = pthread_mutex_unlock(&lock_);
-  if (ret) {
-    ALOGE("Failed to release compositor lock %d", ret);
-    return ret;
-  }
-
-  worker_.Signal();
-  return 0;
-}
-
-int DrmCompositor::CompositeDisplay(DrmCompositionLayerMap_t::iterator begin,
-                                    DrmCompositionLayerMap_t::iterator end) {
-  int ret = 0;
-  // Wait for all acquire fences to signal
-  for (DrmCompositionLayerMap_t::iterator iter = begin; iter != end; ++iter) {
-    hwc_layer_1_t *layer = &iter->second.layer;
-
-    if (layer->acquireFenceFd < 0)
-      continue;
-
-    ret = sync_wait(layer->acquireFenceFd, -1);
-    if (ret) {
-      ALOGE("Failed to wait for acquire %d/%d", layer->acquireFenceFd, ret);
-      return ret;
-    }
-    close(layer->acquireFenceFd);
-    layer->acquireFenceFd = -1;
-  }
-
-  drmModePropertySetPtr pset = drmModePropertySetAlloc();
-  if (!pset) {
-    ALOGE("Failed to allocate property set");
-    return -ENOMEM;
-  }
-
-  for (DrmCompositionLayerMap_t::iterator iter = begin; iter != end; ++iter) {
-    DrmCompositionLayer_t *comp = &iter->second;
-    hwc_layer_1_t *layer = &comp->layer;
-    DrmPlane *plane = comp->plane;
-
-    ret =
-        drmModePropertySetAdd(pset, plane->id(), plane->crtc_property().id(),
-                              begin->second.crtc->id()) ||
-        drmModePropertySetAdd(pset, plane->id(), plane->fb_property().id(),
-                              comp->bo.fb_id) ||
-        drmModePropertySetAdd(pset, plane->id(), plane->crtc_x_property().id(),
-                              layer->displayFrame.left) ||
-        drmModePropertySetAdd(pset, plane->id(), plane->crtc_y_property().id(),
-                              layer->displayFrame.top) ||
-        drmModePropertySetAdd(
-            pset, plane->id(), plane->crtc_w_property().id(),
-            layer->displayFrame.right - layer->displayFrame.left) ||
-        drmModePropertySetAdd(
-            pset, plane->id(), plane->crtc_h_property().id(),
-            layer->displayFrame.bottom - layer->displayFrame.top) ||
-        drmModePropertySetAdd(pset, plane->id(), plane->src_x_property().id(),
-                              layer->sourceCropf.left) ||
-        drmModePropertySetAdd(pset, plane->id(), plane->src_y_property().id(),
-                              layer->sourceCropf.top) ||
-        drmModePropertySetAdd(
-            pset, plane->id(), plane->src_w_property().id(),
-            (int)(layer->sourceCropf.right - layer->sourceCropf.left) << 16) ||
-        drmModePropertySetAdd(
-            pset, plane->id(), plane->src_h_property().id(),
-            (int)(layer->sourceCropf.bottom - layer->sourceCropf.top) << 16);
-    if (ret) {
-      ALOGE("Failed to add plane %d to set", plane->id());
-      break;
-    }
-  }
-
-  if (!ret) {
-    ret = drmModePropertySetCommit(drm_->fd(), 0, drm_, pset);
-    if (ret)
-      ALOGE("Failed to commit pset ret=%d\n", ret);
-  }
-  if (pset)
-    drmModePropertySetFree(pset);
-
-  return ret;
-}
-
-int DrmCompositor::Composite() {
-  ATRACE_CALL();
-  int ret = pthread_mutex_lock(&lock_);
-  if (ret) {
-    ALOGE("Failed to acquire compositor lock %d", ret);
-    return ret;
-  }
-  if (composite_queue_.empty()) {
-    ret = pthread_mutex_unlock(&lock_);
-    if (ret)
-      ALOGE("Failed to release compositor lock %d", ret);
-    return ret;
-  }
-
-  DrmComposition *composition = composite_queue_.front();
-  composite_queue_.pop();
-  ++dump_frames_composited_;
-
-  ret = pthread_mutex_unlock(&lock_);
-  if (ret) {
-    ALOGE("Failed to release compositor lock %d", ret);
-    return ret;
-  }
-
-  DrmCompositionLayerMap_t *map = composition->GetCompositionMap();
+  DrmComposition *drm_composition = (DrmComposition *)composition;
   for (DrmResources::ConnectorIter iter = drm_->begin_connectors();
        iter != drm_->end_connectors(); ++iter) {
     int display = (*iter)->display();
-    std::pair<DrmCompositionLayerMap_t::iterator,
-              DrmCompositionLayerMap_t::iterator> layer_iters =
-        map->equal_range(display);
-
-    if (layer_iters.first != layer_iters.second) {
-      ret = CompositeDisplay(layer_iters.first, layer_iters.second);
-      if (ret) {
-        ALOGE("Composite failed for display %d:", display);
-        break;
-      }
+    int ret = compositor_map_[display].QueueComposition(
+        drm_composition->TakeDisplayComposition(display));
+    if (ret) {
+      ALOGE("Failed to queue composition for display %d", display);
+      delete composition;
+      return ret;
     }
   }
 
-  if (active_composition_) {
-    active_composition_->FinishComposition();
-    delete active_composition_;
-  }
-  active_composition_ = composition;
-  return ret;
+  return 0;
 }
 
-bool DrmCompositor::HaveQueuedComposites() const {
-  int ret = pthread_mutex_lock(&lock_);
-  if (ret) {
-    ALOGE("Failed to acquire compositor lock %d", ret);
-    return false;
-  }
-
-  bool empty_ret = !composite_queue_.empty();
-
-  ret = pthread_mutex_unlock(&lock_);
-  if (ret) {
-    ALOGE("Failed to release compositor lock %d", ret);
-    return false;
-  }
-
-  return empty_ret;
+int DrmCompositor::Composite() {
+  /*
+   * This shouldn't be called, we should be calling Composite() on the display
+   * compositors directly.
+   */
+  ALOGE("Calling base drm compositor Composite() function");
+  return -EINVAL;
 }
 
 void DrmCompositor::Dump(std::ostringstream *out) const {
-  uint64_t cur_ts;
-
-  int ret = pthread_mutex_lock(&lock_);
-  if (ret)
-    return;
-
-  uint64_t num_frames = dump_frames_composited_;
-  dump_frames_composited_ = 0;
-
-  struct timespec ts;
-  ret = clock_gettime(CLOCK_MONOTONIC, &ts);
-
-  ret |= pthread_mutex_unlock(&lock_);
-  if (ret)
-    return;
-
-  cur_ts = ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec;
-  uint64_t num_ms = (cur_ts - dump_last_timestamp_ns_) / (1000 * 1000);
-  unsigned fps = num_ms ? (num_frames * 1000) / (num_ms) : 0;
-
-  *out << "DrmCompositor: num_frames=" << num_frames << " num_ms=" << num_ms <<
-          " fps=" << fps << "\n";
-
-  dump_last_timestamp_ns_ = cur_ts;
+  *out << "DrmCompositor stats:\n";
+  for (DrmResources::ConnectorIter iter = drm_->begin_connectors();
+       iter != drm_->end_connectors(); ++iter)
+    compositor_map_[(*iter)->display()].Dump(out);
 }
 }
diff --git a/drmcompositor.h b/drmcompositor.h
index 2d4eb69..5f47034 100644
--- a/drmcompositor.h
+++ b/drmcompositor.h
@@ -18,23 +18,14 @@
 #define ANDROID_DRM_COMPOSITOR_H_
 
 #include "compositor.h"
-#include "drm_hwcomposer.h"
-#include "drmcomposition.h"
-#include "drmcompositorworker.h"
-#include "drmplane.h"
+#include "drmdisplaycompositor.h"
 #include "importer.h"
 
-#include <pthread.h>
-#include <queue>
+#include <map>
 #include <sstream>
 
-#include <hardware/hardware.h>
-#include <hardware/hwcomposer.h>
-
 namespace android {
 
-class Drm;
-
 class DrmCompositor : public Compositor {
  public:
   DrmCompositor(DrmResources *drm);
@@ -52,32 +43,13 @@
   virtual int Composite();
   virtual void Dump(std::ostringstream *out) const;
 
-  bool HaveQueuedComposites() const;
-
  private:
-  DrmCompositor(const DrmCompositor &);
-
-  int CompositeDisplay(DrmCompositionLayerMap_t::iterator begin,
-                       DrmCompositionLayerMap_t::iterator end);
+  DrmCompositor(const DrmCompositor &) = delete;
 
   DrmResources *drm_;
 
-  DrmCompositorWorker worker_;
-
-  std::queue<DrmComposition *> composite_queue_;
-  DrmComposition *active_composition_;
-
-  uint64_t frame_no_;
-
-  bool initialized_;
-
-  // mutable since we need to acquire in HaveQueuedComposites
-  mutable pthread_mutex_t lock_;
-
-  // State tracking progress since our last Dump(). These are mutable since
-  // we need to reset them on every Dump() call.
-  mutable uint64_t dump_frames_composited_;
-  mutable uint64_t dump_last_timestamp_ns_;
+  // mutable for Dump() propagation
+  mutable std::map<int, DrmDisplayCompositor> compositor_map_;
 };
 }
 
diff --git a/drmcompositorworker.cpp b/drmcompositorworker.cpp
index 9406194..c8eae5f 100644
--- a/drmcompositorworker.cpp
+++ b/drmcompositorworker.cpp
@@ -16,7 +16,7 @@
 
 #define LOG_TAG "hwc-drm-compositor-worker"
 
-#include "drmcompositor.h"
+#include "drmdisplaycompositor.h"
 #include "drmcompositorworker.h"
 #include "worker.h"
 
@@ -27,7 +27,7 @@
 
 namespace android {
 
-DrmCompositorWorker::DrmCompositorWorker(DrmCompositor *compositor)
+DrmCompositorWorker::DrmCompositorWorker(DrmDisplayCompositor *compositor)
     : Worker("drm-compositor", HAL_PRIORITY_URGENT_DISPLAY),
       compositor_(compositor) {
 }
diff --git a/drmcompositorworker.h b/drmcompositorworker.h
index 8b485bf..9f74fb6 100644
--- a/drmcompositorworker.h
+++ b/drmcompositorworker.h
@@ -21,11 +21,11 @@
 
 namespace android {
 
-class DrmCompositor;
+class DrmDisplayCompositor;
 
 class DrmCompositorWorker : public Worker {
  public:
-  DrmCompositorWorker(DrmCompositor *compositor);
+  DrmCompositorWorker(DrmDisplayCompositor *compositor);
   ~DrmCompositorWorker();
 
   int Init();
@@ -33,7 +33,7 @@
  protected:
   virtual void Routine();
 
-  DrmCompositor *compositor_;
+  DrmDisplayCompositor *compositor_;
 };
 }
 
diff --git a/drmdisplaycomposition.cpp b/drmdisplaycomposition.cpp
new file mode 100644
index 0000000..2f8d651
--- /dev/null
+++ b/drmdisplaycomposition.cpp
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "hwc-drm-display-composition"
+
+#include "drmdisplaycomposition.h"
+#include "drmcrtc.h"
+#include "drmplane.h"
+#include "drmresources.h"
+
+#include <stdlib.h>
+
+#include <cutils/log.h>
+#include <sw_sync.h>
+#include <sync/sync.h>
+#include <xf86drmMode.h>
+
+namespace android {
+
+DrmCompositionLayer::DrmCompositionLayer() : crtc(NULL), plane(NULL) {
+  memset(&layer, 0, sizeof(layer));
+  layer.acquireFenceFd = -1;
+  memset(&bo, 0, sizeof(bo));
+}
+
+DrmCompositionLayer::~DrmCompositionLayer() {
+}
+
+DrmDisplayComposition::DrmDisplayComposition()
+    : drm_(NULL),
+      importer_(NULL),
+      type_(DRM_COMPOSITION_TYPE_EMPTY),
+      timeline_fd_(-1),
+      timeline_(0),
+      dpms_mode_(DRM_MODE_DPMS_ON) {
+}
+
+DrmDisplayComposition::~DrmDisplayComposition() {
+  for (DrmCompositionLayerVector_t::iterator iter = layers_.begin();
+       iter != layers_.end(); ++iter) {
+    if (importer_)
+      importer_->ReleaseBuffer(&iter->bo);
+
+    if (iter->layer.acquireFenceFd >= 0)
+      close(iter->layer.acquireFenceFd);
+  }
+
+  if (timeline_fd_ >= 0)
+    close(timeline_fd_);
+}
+
+int DrmDisplayComposition::Init(DrmResources *drm, Importer *importer) {
+  drm_ = drm;
+  importer_ = importer;
+
+  int ret = sw_sync_timeline_create();
+  if (ret < 0) {
+    ALOGE("Failed to create sw sync timeline %d", ret);
+    return ret;
+  }
+  timeline_fd_ = ret;
+  return 0;
+}
+
+DrmCompositionType DrmDisplayComposition::type() const {
+  return type_;
+}
+
+bool DrmDisplayComposition::validate_composition_type(DrmCompositionType des) {
+  return type_ == DRM_COMPOSITION_TYPE_EMPTY || type_ == des;
+}
+
+int DrmDisplayComposition::AddLayer(hwc_layer_1_t *layer, hwc_drm_bo_t *bo,
+                                    DrmCrtc *crtc, DrmPlane *plane) {
+  if (layer->transform != 0)
+    return -EINVAL;
+
+  if (!validate_composition_type(DRM_COMPOSITION_TYPE_FRAME))
+    return -EINVAL;
+
+  ++timeline_;
+  layer->releaseFenceFd =
+      sw_sync_fence_create(timeline_fd_, "drm_fence", timeline_);
+  if (layer->releaseFenceFd < 0) {
+    ALOGE("Could not create release fence %d", layer->releaseFenceFd);
+    return layer->releaseFenceFd;
+  }
+
+  DrmCompositionLayer_t c_layer;
+  c_layer.layer = *layer;
+  c_layer.bo = *bo;
+  c_layer.crtc = crtc;
+  c_layer.plane = plane;
+
+  layer->acquireFenceFd = -1;  // We own this now
+  layers_.push_back(c_layer);
+  type_ = DRM_COMPOSITION_TYPE_FRAME;
+  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::FinishComposition() {
+  int ret = sw_sync_timeline_inc(timeline_fd_, timeline_);
+  if (ret)
+    ALOGE("Failed to increment sync timeline %d", ret);
+
+  return ret;
+}
+
+DrmCompositionLayerVector_t *DrmDisplayComposition::GetCompositionLayers() {
+  return &layers_;
+}
+
+uint32_t DrmDisplayComposition::dpms_mode() const {
+  return dpms_mode_;
+}
+}
diff --git a/drmdisplaycomposition.h b/drmdisplaycomposition.h
new file mode 100644
index 0000000..2ae696f
--- /dev/null
+++ b/drmdisplaycomposition.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_DRM_DISPLAY_COMPOSITION_H_
+#define ANDROID_DRM_DISPLAY_COMPOSITION_H_
+
+#include "drm_hwcomposer.h"
+#include "drmplane.h"
+#include "importer.h"
+
+#include <vector>
+
+#include <hardware/hardware.h>
+#include <hardware/hwcomposer.h>
+
+namespace android {
+
+enum DrmCompositionType {
+  DRM_COMPOSITION_TYPE_EMPTY,
+  DRM_COMPOSITION_TYPE_FRAME,
+  DRM_COMPOSITION_TYPE_DPMS,
+};
+
+typedef struct DrmCompositionLayer {
+  DrmCompositionLayer();
+  ~DrmCompositionLayer();
+
+  hwc_layer_1_t layer;
+  hwc_drm_bo_t bo;
+  DrmCrtc *crtc;
+  DrmPlane *plane;
+} DrmCompositionLayer_t;
+typedef std::vector<DrmCompositionLayer_t> DrmCompositionLayerVector_t;
+
+class DrmDisplayComposition {
+ public:
+  DrmDisplayComposition();
+  ~DrmDisplayComposition();
+
+  int Init(DrmResources *drm, Importer *importer);
+
+  DrmCompositionType type() const;
+
+  int AddLayer(hwc_layer_1_t *layer, hwc_drm_bo_t *bo, DrmCrtc *crtc,
+               DrmPlane *plane);
+  int AddDpmsMode(uint32_t dpms_mode);
+
+  int FinishComposition();
+
+  DrmCompositionLayerVector_t *GetCompositionLayers();
+  uint32_t dpms_mode() const;
+
+ private:
+  DrmDisplayComposition(const DrmDisplayComposition &) = delete;
+
+  bool validate_composition_type(DrmCompositionType desired);
+
+  DrmResources *drm_;
+  Importer *importer_;
+
+  DrmCompositionType type_;
+
+  int timeline_fd_;
+  int timeline_;
+
+  DrmCompositionLayerVector_t layers_;
+  uint32_t dpms_mode_;
+};
+}
+
+#endif  // ANDROID_DRM_DISPLAY_COMPOSITION_H_
diff --git a/drmdisplaycompositor.cpp b/drmdisplaycompositor.cpp
new file mode 100644
index 0000000..80b71f5
--- /dev/null
+++ b/drmdisplaycompositor.cpp
@@ -0,0 +1,314 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+#define LOG_TAG "hwc-drm-display-compositor"
+
+#include "drmdisplaycompositor.h"
+#include "drmcrtc.h"
+#include "drmplane.h"
+#include "drmresources.h"
+
+#include <pthread.h>
+#include <sstream>
+#include <stdlib.h>
+#include <time.h>
+#include <vector>
+
+#include <cutils/log.h>
+#include <sync/sync.h>
+#include <utils/Trace.h>
+
+namespace android {
+
+DrmDisplayCompositor::DrmDisplayCompositor()
+    : drm_(NULL),
+      display_(-1),
+      worker_(this),
+      frame_no_(0),
+      initialized_(false),
+      active_(false),
+      dump_frames_composited_(0),
+      dump_last_timestamp_ns_(0) {
+  struct timespec ts;
+  if (clock_gettime(CLOCK_MONOTONIC, &ts))
+    return;
+  dump_last_timestamp_ns_ = ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec;
+}
+
+DrmDisplayCompositor::~DrmDisplayCompositor() {
+  if (!initialized_)
+    return;
+
+  worker_.Exit();
+
+  int ret = pthread_mutex_lock(&lock_);
+  if (ret)
+    ALOGE("Failed to acquire compositor lock %d", ret);
+
+  while (!composite_queue_.empty()) {
+    composite_queue_.front().reset();
+    composite_queue_.pop();
+  }
+  active_composition_.reset();
+
+  ret = pthread_mutex_unlock(&lock_);
+  if (ret)
+    ALOGE("Failed to acquire compositor lock %d", ret);
+
+  pthread_mutex_destroy(&lock_);
+}
+
+int DrmDisplayCompositor::Init(DrmResources *drm, int display) {
+  drm_ = drm;
+  display_ = display;
+
+  int ret = pthread_mutex_init(&lock_, NULL);
+  if (ret) {
+    ALOGE("Failed to initialize drm compositor lock %d\n", ret);
+    return ret;
+  }
+  ret = worker_.Init();
+  if (ret) {
+    pthread_mutex_destroy(&lock_);
+    ALOGE("Failed to initialize compositor worker %d\n", ret);
+    return ret;
+  }
+
+  initialized_ = true;
+  return 0;
+}
+
+int DrmDisplayCompositor::QueueComposition(
+    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;
+  default:
+    ALOGE("Unknown composition type %d/%d", composition->type(), display_);
+    return -ENOENT;
+  }
+
+  int ret = pthread_mutex_lock(&lock_);
+  if (ret) {
+    ALOGE("Failed to acquire compositor lock %d", ret);
+    return ret;
+  }
+
+  composite_queue_.push(std::move(composition));
+
+  ret = pthread_mutex_unlock(&lock_);
+  if (ret) {
+    ALOGE("Failed to release compositor lock %d", ret);
+    return ret;
+  }
+
+  worker_.Signal();
+  return 0;
+}
+
+int DrmDisplayCompositor::ApplyFrame(DrmDisplayComposition *display_comp) {
+  int ret = 0;
+
+  drmModePropertySetPtr pset = drmModePropertySetAlloc();
+  if (!pset) {
+    ALOGE("Failed to allocate property set");
+    return -ENOMEM;
+  }
+
+  DrmCompositionLayerVector_t *layers = display_comp->GetCompositionLayers();
+  for (DrmCompositionLayerVector_t::iterator iter = layers->begin();
+       iter != layers->end(); ++iter) {
+    hwc_layer_1_t *layer = &iter->layer;
+
+    if (layer->acquireFenceFd >= 0) {
+      ret = sync_wait(layer->acquireFenceFd, -1);
+      if (ret) {
+        ALOGE("Failed to wait for acquire %d/%d", layer->acquireFenceFd, ret);
+        drmModePropertySetFree(pset);
+        return ret;
+      }
+      close(layer->acquireFenceFd);
+      layer->acquireFenceFd = -1;
+    }
+
+    DrmPlane *plane = iter->plane;
+    ret =
+        drmModePropertySetAdd(pset, plane->id(), plane->crtc_property().id(),
+                              iter->crtc->id()) ||
+        drmModePropertySetAdd(pset, plane->id(), plane->fb_property().id(),
+                              iter->bo.fb_id) ||
+        drmModePropertySetAdd(pset, plane->id(), plane->crtc_x_property().id(),
+                              layer->displayFrame.left) ||
+        drmModePropertySetAdd(pset, plane->id(), plane->crtc_y_property().id(),
+                              layer->displayFrame.top) ||
+        drmModePropertySetAdd(
+            pset, plane->id(), plane->crtc_w_property().id(),
+            layer->displayFrame.right - layer->displayFrame.left) ||
+        drmModePropertySetAdd(
+            pset, plane->id(), plane->crtc_h_property().id(),
+            layer->displayFrame.bottom - layer->displayFrame.top) ||
+        drmModePropertySetAdd(pset, plane->id(), plane->src_x_property().id(),
+                              layer->sourceCropf.left) ||
+        drmModePropertySetAdd(pset, plane->id(), plane->src_y_property().id(),
+                              layer->sourceCropf.top) ||
+        drmModePropertySetAdd(
+            pset, plane->id(), plane->src_w_property().id(),
+            (int)(layer->sourceCropf.right - layer->sourceCropf.left) << 16) ||
+        drmModePropertySetAdd(
+            pset, plane->id(), plane->src_h_property().id(),
+            (int)(layer->sourceCropf.bottom - layer->sourceCropf.top) << 16);
+    if (ret) {
+      ALOGE("Failed to add plane %d to set", plane->id());
+      break;
+    }
+  }
+
+  if (!ret) {
+    ret = drmModePropertySetCommit(drm_->fd(), 0, drm_, pset);
+    if (ret)
+      ALOGE("Failed to commit pset ret=%d\n", ret);
+  }
+  if (pset)
+    drmModePropertySetFree(pset);
+
+  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_);
+  if (ret) {
+    ALOGE("Failed to acquire compositor lock %d", ret);
+    return ret;
+  }
+  if (composite_queue_.empty()) {
+    ret = pthread_mutex_unlock(&lock_);
+    if (ret)
+      ALOGE("Failed to release compositor lock %d", ret);
+    return ret;
+  }
+
+  std::unique_ptr<DrmDisplayComposition> composition(
+      std::move(composite_queue_.front()));
+  composite_queue_.pop();
+
+  ret = pthread_mutex_unlock(&lock_);
+  if (ret) {
+    ALOGE("Failed to release compositor lock %d", ret);
+    return ret;
+  }
+
+  switch (composition->type()) {
+  case DRM_COMPOSITION_TYPE_FRAME:
+    ret = ApplyFrame(composition.get());
+    if (ret) {
+      ALOGE("Composite failed for display %d", display_);
+      return ret;
+    }
+    ++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;
+  }
+
+  if (active_composition_)
+    active_composition_->FinishComposition();
+
+  active_composition_.swap(composition);
+  return ret;
+}
+
+bool DrmDisplayCompositor::HaveQueuedComposites() const {
+  int ret = pthread_mutex_lock(&lock_);
+  if (ret) {
+    ALOGE("Failed to acquire compositor lock %d", ret);
+    return false;
+  }
+
+  bool empty_ret = !composite_queue_.empty();
+
+  ret = pthread_mutex_unlock(&lock_);
+  if (ret) {
+    ALOGE("Failed to release compositor lock %d", ret);
+    return false;
+  }
+
+  return empty_ret;
+}
+
+void DrmDisplayCompositor::Dump(std::ostringstream *out) const {
+  uint64_t cur_ts;
+
+  int ret = pthread_mutex_lock(&lock_);
+  if (ret)
+    return;
+
+  uint64_t num_frames = dump_frames_composited_;
+  dump_frames_composited_ = 0;
+
+  struct timespec ts;
+  ret = clock_gettime(CLOCK_MONOTONIC, &ts);
+
+  ret |= pthread_mutex_unlock(&lock_);
+  if (ret)
+    return;
+
+  cur_ts = ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec;
+  uint64_t num_ms = (cur_ts - dump_last_timestamp_ns_) / (1000 * 1000);
+  unsigned fps = num_ms ? (num_frames * 1000) / (num_ms) : 0;
+
+  *out << "--DrmDisplayCompositor[" << display_
+       << "]: num_frames=" << num_frames << " num_ms=" << num_ms
+       << " fps=" << fps << "\n";
+
+  dump_last_timestamp_ns_ = cur_ts;
+}
+}
diff --git a/drmdisplaycompositor.h b/drmdisplaycompositor.h
new file mode 100644
index 0000000..9f50664
--- /dev/null
+++ b/drmdisplaycompositor.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_DRM_DISPLAY_COMPOSITOR_H_
+#define ANDROID_DRM_DISPLAY_COMPOSITOR_H_
+
+#include "drm_hwcomposer.h"
+#include "drmcomposition.h"
+#include "drmcompositorworker.h"
+
+#include <pthread.h>
+#include <queue>
+#include <sstream>
+
+#include <hardware/hardware.h>
+#include <hardware/hwcomposer.h>
+
+namespace android {
+
+class DrmDisplayCompositor {
+ public:
+  DrmDisplayCompositor();
+  ~DrmDisplayCompositor();
+
+  int Init(DrmResources *drm, int display);
+
+  int QueueComposition(std::unique_ptr<DrmDisplayComposition> composition);
+  int Composite();
+  void Dump(std::ostringstream *out) const;
+
+  bool HaveQueuedComposites() const;
+
+ private:
+  DrmDisplayCompositor(const DrmDisplayCompositor &) = delete;
+
+  int ApplyFrame(DrmDisplayComposition *display_comp);
+  int ApplyDpms(DrmDisplayComposition *display_comp);
+
+  DrmResources *drm_;
+  int display_;
+
+  DrmCompositorWorker worker_;
+
+  std::queue<std::unique_ptr<DrmDisplayComposition>> composite_queue_;
+  std::unique_ptr<DrmDisplayComposition> active_composition_;
+
+  uint64_t frame_no_;
+
+  bool initialized_;
+  bool active_;
+
+  // mutable since we need to acquire in HaveQueuedComposites
+  mutable pthread_mutex_t lock_;
+
+  // State tracking progress since our last Dump(). These are mutable since
+  // we need to reset them on every Dump() call.
+  mutable uint64_t dump_frames_composited_;
+  mutable uint64_t dump_last_timestamp_ns_;
+};
+}
+
+#endif  // ANDROID_DRM_DISPLAY_COMPOSITOR_H_
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);