Merge remote-tracking branch 'aosp/upstream-master' into aosp-fdo-merge

Merge upstream freedesktop/master branch into aosp/master.

Upstream now supports required changes for HiKey/HiKey960 to
use drm_hwcomposer.

Change-Id: I50598105e38b01ea9411c5e7ba809396d7085e23
Signed-off-by: John Stultz <john.stultz@linaro.org>
diff --git a/.clang-format b/.clang-format
index 5382f9b..984fa5e 100644
--- a/.clang-format
+++ b/.clang-format
@@ -1,4 +1,7 @@
 BasedOnStyle: Google
+AllowAllParametersOfDeclarationOnNextLine: false
 AllowShortIfStatementsOnASingleLine: false
 AllowShortLoopsOnASingleLine: false
 AllowShortFunctionsOnASingleLine: None
+PenaltyBreakAssignment: 10000000
+PenaltyBreakBeforeFirstCallParameter: 1000
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 43bce5f..24c4a0a 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -2,7 +2,7 @@
 
 before_script:
   - apt-get --quiet update --yes >/dev/null
-  - apt-get --quiet install --yes clang-format-3.5 git >/dev/null
+  - apt-get --quiet install --yes clang-format-5.0 git >/dev/null
 
 stages:
   - style
@@ -11,7 +11,7 @@
   stage: style
   script:
     - git fetch https://gitlab.freedesktop.org/drm-hwcomposer/drm-hwcomposer.git
-    - git diff -U0 --no-color FETCH_HEAD...HEAD -- | clang-format-diff-3.5 -p 1 -style=file > format-fixup.patch
+    - git diff -U0 --no-color FETCH_HEAD...HEAD -- | clang-format-diff-5.0 -p 1 -style=file > format-fixup.patch
     - if [ -s format-fixup.patch ]; then cat format-fixup.patch && exit 1; fi
   artifacts:
     when: on_failure
diff --git a/Android.mk b/Android.mk
index 3d48ba5..d5ee200 100644
--- a/Android.mk
+++ b/Android.mk
@@ -14,16 +14,13 @@
 
 ifeq ($(strip $(BOARD_USES_DRM_HWCOMPOSER)),true)
 
+DRM_HWC_ANDROID_MAJOR_VERSION := $(word 1, $(subst ., , $(PLATFORM_VERSION)))
+
 LOCAL_PATH := $(call my-dir)
 
 common_drm_hwcomposer_cflags := \
     -Wall \
     -Werror \
-    -Wno-unused-function \
-    -Wno-unused-label \
-    -Wno-unused-parameter \
-    -Wno-unused-private-field \
-    -Wno-unused-variable \
 
 # =====================
 # libdrmhwc_utils.a
@@ -61,7 +58,8 @@
 
 LOCAL_SRC_FILES := \
 	autolock.cpp \
-	drmresources.cpp \
+	resourcemanager.cpp \
+	drmdevice.cpp \
 	drmconnector.cpp \
 	drmcrtc.cpp \
 	drmdisplaycomposition.cpp \
@@ -83,6 +81,10 @@
 	-DHWC2_USE_CPP11 \
 	-DHWC2_INCLUDE_STRINGIFICATION
 
+ifneq ($(filter 2 3 4 5 6 7 8, $(DRM_HWC_ANDROID_MAJOR_VERSION)),)
+LOCAL_CPPFLAGS += -DHWC2_USE_OLD_GB_IMPORT
+endif
+
 
 ifeq ($(TARGET_PRODUCT),hikey960)
 LOCAL_CPPFLAGS += -DUSE_HISI_IMPORTER
diff --git a/autofd.h b/autofd.h
index 1edc9c5..9af6c22 100644
--- a/autofd.h
+++ b/autofd.h
@@ -101,6 +101,6 @@
  private:
   int *fd_ = NULL;
 };
-}
+}  // namespace android
 
 #endif
diff --git a/autolock.cpp b/autolock.cpp
index 795a8c2..4e9552a 100644
--- a/autolock.cpp
+++ b/autolock.cpp
@@ -53,4 +53,4 @@
   locked_ = false;
   return 0;
 }
-}
+}  // namespace android
diff --git a/autolock.h b/autolock.h
index 3b824e2..006406a 100644
--- a/autolock.h
+++ b/autolock.h
@@ -39,4 +39,4 @@
   bool locked_ = false;
   const char *const name_;
 };
-}
+}  // namespace android
diff --git a/drmconnector.cpp b/drmconnector.cpp
index 10b96b5..756791f 100644
--- a/drmconnector.cpp
+++ b/drmconnector.cpp
@@ -17,7 +17,7 @@
 #define LOG_TAG "hwc-drm-connector"
 
 #include "drmconnector.h"
-#include "drmresources.h"
+#include "drmdevice.h"
 
 #include <errno.h>
 #include <stdint.h>
@@ -27,7 +27,7 @@
 
 namespace android {
 
-DrmConnector::DrmConnector(DrmResources *drm, drmModeConnectorPtr c,
+DrmConnector::DrmConnector(DrmDevice *drm, drmModeConnectorPtr c,
                            DrmEncoder *current_encoder,
                            std::vector<DrmEncoder *> &possible_encoders)
     : drm_(drm),
@@ -52,6 +52,26 @@
     ALOGE("Could not get CRTC_ID property\n");
     return ret;
   }
+  if (writeback()) {
+    ret = drm_->GetConnectorProperty(*this, "WRITEBACK_PIXEL_FORMATS",
+                                     &writeback_pixel_formats_);
+    if (ret) {
+      ALOGE("Could not get WRITEBACK_PIXEL_FORMATS connector_id = %d\n", id_);
+      return ret;
+    }
+    ret = drm_->GetConnectorProperty(*this, "WRITEBACK_FB_ID",
+                                     &writeback_fb_id_);
+    if (ret) {
+      ALOGE("Could not get WRITEBACK_FB_ID connector_id = %d\n", id_);
+      return ret;
+    }
+    ret = drm_->GetConnectorProperty(*this, "WRITEBACK_OUT_FENCE_PTR",
+                                     &writeback_out_fence_);
+    if (ret) {
+      ALOGE("Could not get WRITEBACK_OUT_FENCE_PTR connector_id = %d\n", id_);
+      return ret;
+    }
+  }
   return 0;
 }
 
@@ -73,13 +93,22 @@
 }
 
 bool DrmConnector::external() const {
-  return type_ == DRM_MODE_CONNECTOR_HDMIA || type_ == DRM_MODE_CONNECTOR_DisplayPort ||
+  return type_ == DRM_MODE_CONNECTOR_HDMIA ||
+         type_ == DRM_MODE_CONNECTOR_DisplayPort ||
          type_ == DRM_MODE_CONNECTOR_DVID || type_ == DRM_MODE_CONNECTOR_DVII ||
          type_ == DRM_MODE_CONNECTOR_VGA;
 }
 
+bool DrmConnector::writeback() const {
+#ifdef DRM_MODE_CONNECTOR_WRITEBACK
+  return type_ == DRM_MODE_CONNECTOR_WRITEBACK;
+#else
+  return false;
+#endif
+}
+
 bool DrmConnector::valid_type() const {
-  return internal() || external();
+  return internal() || external() || writeback();
 }
 
 int DrmConnector::UpdateModes() {
@@ -130,6 +159,18 @@
   return crtc_id_property_;
 }
 
+const DrmProperty &DrmConnector::writeback_pixel_formats() const {
+  return writeback_pixel_formats_;
+}
+
+const DrmProperty &DrmConnector::writeback_fb_id() const {
+  return writeback_fb_id_;
+}
+
+const DrmProperty &DrmConnector::writeback_out_fence() const {
+  return writeback_out_fence_;
+}
+
 DrmEncoder *DrmConnector::encoder() const {
   return encoder_;
 }
@@ -149,4 +190,4 @@
 uint32_t DrmConnector::mm_height() const {
   return mm_height_;
 }
-}
+}  // namespace android
diff --git a/drmconnector.h b/drmconnector.h
index 5601e06..4f7f6a8 100644
--- a/drmconnector.h
+++ b/drmconnector.h
@@ -22,16 +22,16 @@
 #include "drmproperty.h"
 
 #include <stdint.h>
-#include <vector>
 #include <xf86drmMode.h>
+#include <vector>
 
 namespace android {
 
-class DrmResources;
+class DrmDevice;
 
 class DrmConnector {
  public:
-  DrmConnector(DrmResources *drm, drmModeConnectorPtr c,
+  DrmConnector(DrmDevice *drm, drmModeConnectorPtr c,
                DrmEncoder *current_encoder,
                std::vector<DrmEncoder *> &possible_encoders);
   DrmConnector(const DrmProperty &) = delete;
@@ -46,6 +46,7 @@
 
   bool internal() const;
   bool external() const;
+  bool writeback() const;
   bool valid_type() const;
 
   int UpdateModes();
@@ -58,6 +59,9 @@
 
   const DrmProperty &dpms_property() const;
   const DrmProperty &crtc_id_property() const;
+  const DrmProperty &writeback_pixel_formats() const;
+  const DrmProperty &writeback_fb_id() const;
+  const DrmProperty &writeback_out_fence() const;
 
   const std::vector<DrmEncoder *> &possible_encoders() const {
     return possible_encoders_;
@@ -71,7 +75,7 @@
   uint32_t mm_height() const;
 
  private:
-  DrmResources *drm_;
+  DrmDevice *drm_;
 
   uint32_t id_;
   DrmEncoder *encoder_;
@@ -88,9 +92,12 @@
 
   DrmProperty dpms_property_;
   DrmProperty crtc_id_property_;
+  DrmProperty writeback_pixel_formats_;
+  DrmProperty writeback_fb_id_;
+  DrmProperty writeback_out_fence_;
 
   std::vector<DrmEncoder *> possible_encoders_;
 };
-}
+}  // namespace android
 
 #endif  // ANDROID_DRM_PLANE_H_
diff --git a/drmcrtc.cpp b/drmcrtc.cpp
index 4033269..b627291 100644
--- a/drmcrtc.cpp
+++ b/drmcrtc.cpp
@@ -17,7 +17,7 @@
 #define LOG_TAG "hwc-drm-crtc"
 
 #include "drmcrtc.h"
-#include "drmresources.h"
+#include "drmdevice.h"
 
 #include <stdint.h>
 #include <xf86drmMode.h>
@@ -26,12 +26,8 @@
 
 namespace android {
 
-DrmCrtc::DrmCrtc(DrmResources *drm, drmModeCrtcPtr c, unsigned pipe)
-    : drm_(drm),
-      id_(c->crtc_id),
-      pipe_(pipe),
-      display_(-1),
-      mode_(&c->mode) {
+DrmCrtc::DrmCrtc(DrmDevice *drm, drmModeCrtcPtr c, unsigned pipe)
+    : drm_(drm), id_(c->crtc_id), pipe_(pipe), display_(-1), mode_(&c->mode) {
 }
 
 int DrmCrtc::Init() {
@@ -86,4 +82,4 @@
 const DrmProperty &DrmCrtc::out_fence_ptr_property() const {
   return out_fence_ptr_property_;
 }
-}
+}  // namespace android
diff --git a/drmcrtc.h b/drmcrtc.h
index c5a5599..3075f9b 100644
--- a/drmcrtc.h
+++ b/drmcrtc.h
@@ -25,11 +25,11 @@
 
 namespace android {
 
-class DrmResources;
+class DrmDevice;
 
 class DrmCrtc {
  public:
-  DrmCrtc(DrmResources *drm, drmModeCrtcPtr c, unsigned pipe);
+  DrmCrtc(DrmDevice *drm, drmModeCrtcPtr c, unsigned pipe);
   DrmCrtc(const DrmCrtc &) = delete;
   DrmCrtc &operator=(const DrmCrtc &) = delete;
 
@@ -48,7 +48,7 @@
   const DrmProperty &out_fence_ptr_property() const;
 
  private:
-  DrmResources *drm_;
+  DrmDevice *drm_;
 
   uint32_t id_;
   unsigned pipe_;
@@ -60,6 +60,6 @@
   DrmProperty mode_property_;
   DrmProperty out_fence_ptr_property_;
 };
-}
+}  // namespace android
 
 #endif  // ANDROID_DRM_CRTC_H_
diff --git a/drmdevice.cpp b/drmdevice.cpp
new file mode 100644
index 0000000..2007fdd
--- /dev/null
+++ b/drmdevice.cpp
@@ -0,0 +1,486 @@
+/*
+ * 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-device"
+
+#include "drmdevice.h"
+#include "drmconnector.h"
+#include "drmcrtc.h"
+#include "drmencoder.h"
+#include "drmeventlistener.h"
+#include "drmplane.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <xf86drm.h>
+#include <xf86drmMode.h>
+#include <cinttypes>
+
+#include <cutils/properties.h>
+#include <log/log.h>
+
+namespace android {
+
+DrmDevice::DrmDevice() : event_listener_(this) {
+}
+
+DrmDevice::~DrmDevice() {
+  event_listener_.Exit();
+}
+
+std::tuple<int, int> DrmDevice::Init(const char *path, int num_displays) {
+  /* TODO: Use drmOpenControl here instead */
+  fd_.Set(open(path, O_RDWR));
+  if (fd() < 0) {
+    ALOGE("Failed to open dri- %s", strerror(-errno));
+    return std::make_tuple(-ENODEV, 0);
+  }
+
+  int ret = drmSetClientCap(fd(), DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
+  if (ret) {
+    ALOGE("Failed to set universal plane cap %d", ret);
+    return std::make_tuple(ret, 0);
+  }
+
+  ret = drmSetClientCap(fd(), DRM_CLIENT_CAP_ATOMIC, 1);
+  if (ret) {
+    ALOGE("Failed to set atomic cap %d", ret);
+    return std::make_tuple(ret, 0);
+  }
+
+#ifdef DRM_CLIENT_CAP_WRITEBACK_CONNECTORS
+  ret = drmSetClientCap(fd(), DRM_CLIENT_CAP_WRITEBACK_CONNECTORS, 1);
+  if (ret) {
+    ALOGI("Failed to set writeback cap %d", ret);
+    ret = 0;
+  }
+#endif
+
+  drmModeResPtr res = drmModeGetResources(fd());
+  if (!res) {
+    ALOGE("Failed to get DrmDevice resources");
+    return std::make_tuple(-ENODEV, 0);
+  }
+
+  min_resolution_ = std::pair<uint32_t, uint32_t>(res->min_width,
+                                                  res->min_height);
+  max_resolution_ = std::pair<uint32_t, uint32_t>(res->max_width,
+                                                  res->max_height);
+
+  // Assumes that the primary display will always be in the first
+  // drm_device opened.
+  bool found_primary = num_displays != 0;
+
+  for (int i = 0; !ret && i < res->count_crtcs; ++i) {
+    drmModeCrtcPtr c = drmModeGetCrtc(fd(), res->crtcs[i]);
+    if (!c) {
+      ALOGE("Failed to get crtc %d", res->crtcs[i]);
+      ret = -ENODEV;
+      break;
+    }
+
+    std::unique_ptr<DrmCrtc> crtc(new DrmCrtc(this, c, i));
+    drmModeFreeCrtc(c);
+
+    ret = crtc->Init();
+    if (ret) {
+      ALOGE("Failed to initialize crtc %d", res->crtcs[i]);
+      break;
+    }
+    crtcs_.emplace_back(std::move(crtc));
+  }
+
+  std::vector<int> possible_clones;
+  for (int i = 0; !ret && i < res->count_encoders; ++i) {
+    drmModeEncoderPtr e = drmModeGetEncoder(fd(), res->encoders[i]);
+    if (!e) {
+      ALOGE("Failed to get encoder %d", res->encoders[i]);
+      ret = -ENODEV;
+      break;
+    }
+
+    std::vector<DrmCrtc *> possible_crtcs;
+    DrmCrtc *current_crtc = NULL;
+    for (auto &crtc : crtcs_) {
+      if ((1 << crtc->pipe()) & e->possible_crtcs)
+        possible_crtcs.push_back(crtc.get());
+
+      if (crtc->id() == e->crtc_id)
+        current_crtc = crtc.get();
+    }
+
+    std::unique_ptr<DrmEncoder> enc(
+        new DrmEncoder(e, current_crtc, possible_crtcs));
+    possible_clones.push_back(e->possible_clones);
+    drmModeFreeEncoder(e);
+
+    encoders_.emplace_back(std::move(enc));
+  }
+
+  for (unsigned int i = 0; i < encoders_.size(); i++) {
+    for (unsigned int j = 0; j < encoders_.size(); j++)
+      if (possible_clones[i] & (1 << j))
+        encoders_[i]->AddPossibleClone(encoders_[j].get());
+  }
+
+  for (int i = 0; !ret && i < res->count_connectors; ++i) {
+    drmModeConnectorPtr c = drmModeGetConnector(fd(), res->connectors[i]);
+    if (!c) {
+      ALOGE("Failed to get connector %d", res->connectors[i]);
+      ret = -ENODEV;
+      break;
+    }
+
+    std::vector<DrmEncoder *> possible_encoders;
+    DrmEncoder *current_encoder = NULL;
+    for (int j = 0; j < c->count_encoders; ++j) {
+      for (auto &encoder : encoders_) {
+        if (encoder->id() == c->encoders[j])
+          possible_encoders.push_back(encoder.get());
+        if (encoder->id() == c->encoder_id)
+          current_encoder = encoder.get();
+      }
+    }
+
+    std::unique_ptr<DrmConnector> conn(
+        new DrmConnector(this, c, current_encoder, possible_encoders));
+
+    drmModeFreeConnector(c);
+
+    ret = conn->Init();
+    if (ret) {
+      ALOGE("Init connector %d failed", res->connectors[i]);
+      break;
+    }
+
+    if (conn->writeback())
+      writeback_connectors_.emplace_back(std::move(conn));
+    else
+      connectors_.emplace_back(std::move(conn));
+  }
+
+  // First look for primary amongst internal connectors
+  for (auto &conn : connectors_) {
+    if (conn->internal() && !found_primary) {
+      conn->set_display(num_displays);
+      displays_[num_displays] = num_displays;
+      ++num_displays;
+      found_primary = true;
+      break;
+    }
+  }
+
+  // Then pick first available as primary and for the others assign
+  // consecutive display_numbers.
+  for (auto &conn : connectors_) {
+    if (conn->external() || conn->internal()) {
+      if (!found_primary) {
+        conn->set_display(num_displays);
+        displays_[num_displays] = num_displays;
+        found_primary = true;
+        ++num_displays;
+      } else if (conn->display() < 0) {
+        conn->set_display(num_displays);
+        displays_[num_displays] = num_displays;
+        ++num_displays;
+      }
+    }
+  }
+
+  if (res)
+    drmModeFreeResources(res);
+
+  // Catch-all for the above loops
+  if (ret)
+    return std::make_tuple(ret, 0);
+
+  drmModePlaneResPtr plane_res = drmModeGetPlaneResources(fd());
+  if (!plane_res) {
+    ALOGE("Failed to get plane resources");
+    return std::make_tuple(-ENOENT, 0);
+  }
+
+  for (uint32_t i = 0; i < plane_res->count_planes; ++i) {
+    drmModePlanePtr p = drmModeGetPlane(fd(), plane_res->planes[i]);
+    if (!p) {
+      ALOGE("Failed to get plane %d", plane_res->planes[i]);
+      ret = -ENODEV;
+      break;
+    }
+
+    std::unique_ptr<DrmPlane> plane(new DrmPlane(this, p));
+
+    drmModeFreePlane(p);
+
+    ret = plane->Init();
+    if (ret) {
+      ALOGE("Init plane %d failed", plane_res->planes[i]);
+      break;
+    }
+
+    planes_.emplace_back(std::move(plane));
+  }
+  drmModeFreePlaneResources(plane_res);
+  if (ret)
+    return std::make_tuple(ret, 0);
+
+  ret = event_listener_.Init();
+  if (ret) {
+    ALOGE("Can't initialize event listener %d", ret);
+    return std::make_tuple(ret, 0);
+  }
+
+  for (auto &conn : connectors_) {
+    ret = CreateDisplayPipe(conn.get());
+    if (ret) {
+      ALOGE("Failed CreateDisplayPipe %d with %d", conn->id(), ret);
+      return std::make_tuple(ret, 0);
+    }
+    if (!AttachWriteback(conn.get())) {
+      ALOGI("Display %d has writeback attach to it", conn->display());
+    }
+  }
+  return std::make_tuple(ret, displays_.size());
+}
+
+bool DrmDevice::HandlesDisplay(int display) const {
+  return displays_.find(display) != displays_.end();
+}
+
+DrmConnector *DrmDevice::GetConnectorForDisplay(int display) const {
+  for (auto &conn : connectors_) {
+    if (conn->display() == display)
+      return conn.get();
+  }
+  return NULL;
+}
+
+DrmConnector *DrmDevice::GetWritebackConnectorForDisplay(int display) const {
+  for (auto &conn : writeback_connectors_) {
+    if (conn->display() == display)
+      return conn.get();
+  }
+  return NULL;
+}
+
+// TODO what happens when hotplugging
+DrmConnector *DrmDevice::AvailableWritebackConnector(int display) const {
+  DrmConnector *writeback_conn = GetWritebackConnectorForDisplay(display);
+  DrmConnector *display_conn = GetConnectorForDisplay(display);
+  // If we have a writeback already attached to the same CRTC just use that,
+  // if possible.
+  if (display_conn && writeback_conn &&
+      writeback_conn->encoder()->CanClone(display_conn->encoder()))
+    return writeback_conn;
+
+  // Use another CRTC if available and doesn't have any connector
+  for (auto &crtc : crtcs_) {
+    if (crtc->display() == display)
+      continue;
+    display_conn = GetConnectorForDisplay(crtc->display());
+    // If we have a display connected don't use it for writeback
+    if (display_conn && display_conn->state() == DRM_MODE_CONNECTED)
+      continue;
+    writeback_conn = GetWritebackConnectorForDisplay(crtc->display());
+    if (writeback_conn)
+      return writeback_conn;
+  }
+  return NULL;
+}
+
+DrmCrtc *DrmDevice::GetCrtcForDisplay(int display) const {
+  for (auto &crtc : crtcs_) {
+    if (crtc->display() == display)
+      return crtc.get();
+  }
+  return NULL;
+}
+
+DrmPlane *DrmDevice::GetPlane(uint32_t id) const {
+  for (auto &plane : planes_) {
+    if (plane->id() == id)
+      return plane.get();
+  }
+  return NULL;
+}
+
+const std::vector<std::unique_ptr<DrmCrtc>> &DrmDevice::crtcs() const {
+  return crtcs_;
+}
+
+uint32_t DrmDevice::next_mode_id() {
+  return ++mode_id_;
+}
+
+int DrmDevice::TryEncoderForDisplay(int display, DrmEncoder *enc) {
+  /* First try to use the currently-bound crtc */
+  DrmCrtc *crtc = enc->crtc();
+  if (crtc && crtc->can_bind(display)) {
+    crtc->set_display(display);
+    enc->set_crtc(crtc);
+    return 0;
+  }
+
+  /* Try to find a possible crtc which will work */
+  for (DrmCrtc *crtc : enc->possible_crtcs()) {
+    /* We've already tried this earlier */
+    if (crtc == enc->crtc())
+      continue;
+
+    if (crtc->can_bind(display)) {
+      crtc->set_display(display);
+      enc->set_crtc(crtc);
+      return 0;
+    }
+  }
+
+  /* We can't use the encoder, but nothing went wrong, try another one */
+  return -EAGAIN;
+}
+
+int DrmDevice::CreateDisplayPipe(DrmConnector *connector) {
+  int display = connector->display();
+  /* Try to use current setup first */
+  if (connector->encoder()) {
+    int ret = TryEncoderForDisplay(display, connector->encoder());
+    if (!ret) {
+      return 0;
+    } else if (ret != -EAGAIN) {
+      ALOGE("Could not set mode %d/%d", display, ret);
+      return ret;
+    }
+  }
+
+  for (DrmEncoder *enc : connector->possible_encoders()) {
+    int ret = TryEncoderForDisplay(display, enc);
+    if (!ret) {
+      connector->set_encoder(enc);
+      return 0;
+    } else if (ret != -EAGAIN) {
+      ALOGE("Could not set mode %d/%d", display, ret);
+      return ret;
+    }
+  }
+  ALOGE("Could not find a suitable encoder/crtc for display %d",
+        connector->display());
+  return -ENODEV;
+}
+
+// Attach writeback connector to the CRTC linked to the display_conn
+int DrmDevice::AttachWriteback(DrmConnector *display_conn) {
+  DrmCrtc *display_crtc = display_conn->encoder()->crtc();
+  if (GetWritebackConnectorForDisplay(display_crtc->display()) != NULL) {
+    ALOGE("Display already has writeback attach to it");
+    return -EINVAL;
+  }
+  for (auto &writeback_conn : writeback_connectors_) {
+    if (writeback_conn->display() >= 0)
+      continue;
+    for (DrmEncoder *writeback_enc : writeback_conn->possible_encoders()) {
+      for (DrmCrtc *possible_crtc : writeback_enc->possible_crtcs()) {
+        if (possible_crtc != display_crtc)
+          continue;
+        // Use just encoders which had not been bound already
+        if (writeback_enc->can_bind(display_crtc->display())) {
+          writeback_enc->set_crtc(display_crtc);
+          writeback_conn->set_encoder(writeback_enc);
+          writeback_conn->set_display(display_crtc->display());
+          writeback_conn->UpdateModes();
+          return 0;
+        }
+      }
+    }
+  }
+  return -EINVAL;
+}
+
+int DrmDevice::CreatePropertyBlob(void *data, size_t length,
+                                  uint32_t *blob_id) {
+  struct drm_mode_create_blob create_blob;
+  memset(&create_blob, 0, sizeof(create_blob));
+  create_blob.length = length;
+  create_blob.data = (__u64)data;
+
+  int ret = drmIoctl(fd(), DRM_IOCTL_MODE_CREATEPROPBLOB, &create_blob);
+  if (ret) {
+    ALOGE("Failed to create mode property blob %d", ret);
+    return ret;
+  }
+  *blob_id = create_blob.blob_id;
+  return 0;
+}
+
+int DrmDevice::DestroyPropertyBlob(uint32_t blob_id) {
+  if (!blob_id)
+    return 0;
+
+  struct drm_mode_destroy_blob destroy_blob;
+  memset(&destroy_blob, 0, sizeof(destroy_blob));
+  destroy_blob.blob_id = (__u32)blob_id;
+  int ret = drmIoctl(fd(), DRM_IOCTL_MODE_DESTROYPROPBLOB, &destroy_blob);
+  if (ret) {
+    ALOGE("Failed to destroy mode property blob %" PRIu32 "/%d", blob_id, ret);
+    return ret;
+  }
+  return 0;
+}
+
+DrmEventListener *DrmDevice::event_listener() {
+  return &event_listener_;
+}
+
+int DrmDevice::GetProperty(uint32_t obj_id, uint32_t obj_type,
+                           const char *prop_name, DrmProperty *property) {
+  drmModeObjectPropertiesPtr props;
+
+  props = drmModeObjectGetProperties(fd(), obj_id, obj_type);
+  if (!props) {
+    ALOGE("Failed to get properties for %d/%x", obj_id, obj_type);
+    return -ENODEV;
+  }
+
+  bool found = false;
+  for (int i = 0; !found && (size_t)i < props->count_props; ++i) {
+    drmModePropertyPtr p = drmModeGetProperty(fd(), props->props[i]);
+    if (!strcmp(p->name, prop_name)) {
+      property->Init(p, props->prop_values[i]);
+      found = true;
+    }
+    drmModeFreeProperty(p);
+  }
+
+  drmModeFreeObjectProperties(props);
+  return found ? 0 : -ENOENT;
+}
+
+int DrmDevice::GetPlaneProperty(const DrmPlane &plane, const char *prop_name,
+                                DrmProperty *property) {
+  return GetProperty(plane.id(), DRM_MODE_OBJECT_PLANE, prop_name, property);
+}
+
+int DrmDevice::GetCrtcProperty(const DrmCrtc &crtc, const char *prop_name,
+                               DrmProperty *property) {
+  return GetProperty(crtc.id(), DRM_MODE_OBJECT_CRTC, prop_name, property);
+}
+
+int DrmDevice::GetConnectorProperty(const DrmConnector &connector,
+                                    const char *prop_name,
+                                    DrmProperty *property) {
+  return GetProperty(connector.id(), DRM_MODE_OBJECT_CONNECTOR, prop_name,
+                     property);
+}
+}  // namespace android
diff --git a/drmresources.h b/drmdevice.h
similarity index 83%
rename from drmresources.h
rename to drmdevice.h
index 4cca48c..da1b961 100644
--- a/drmresources.h
+++ b/drmdevice.h
@@ -22,17 +22,19 @@
 #include "drmencoder.h"
 #include "drmeventlistener.h"
 #include "drmplane.h"
+#include "platform.h"
 
 #include <stdint.h>
+#include <tuple>
 
 namespace android {
 
-class DrmResources {
+class DrmDevice {
  public:
-  DrmResources();
-  ~DrmResources();
+  DrmDevice();
+  ~DrmDevice();
 
-  int Init();
+  std::tuple<int, int> Init(const char *path, int num_displays);
 
   int fd() const {
     return fd_.get();
@@ -55,6 +57,8 @@
   }
 
   DrmConnector *GetConnectorForDisplay(int display) const;
+  DrmConnector *GetWritebackConnectorForDisplay(int display) const;
+  DrmConnector *AvailableWritebackConnector(int display) const;
   DrmCrtc *GetCrtcForDisplay(int display) const;
   DrmPlane *GetPlane(uint32_t id) const;
   DrmEventListener *event_listener();
@@ -71,6 +75,7 @@
 
   int CreatePropertyBlob(void *data, size_t length, uint32_t *blob_id);
   int DestroyPropertyBlob(uint32_t blob_id);
+  bool HandlesDisplay(int display) const;
 
  private:
   int TryEncoderForDisplay(int display, DrmEncoder *enc);
@@ -78,11 +83,13 @@
                   DrmProperty *property);
 
   int CreateDisplayPipe(DrmConnector *connector);
+  int AttachWriteback(DrmConnector *display_conn);
 
   UniqueFd fd_;
   uint32_t mode_id_ = 0;
 
   std::vector<std::unique_ptr<DrmConnector>> connectors_;
+  std::vector<std::unique_ptr<DrmConnector>> writeback_connectors_;
   std::vector<std::unique_ptr<DrmEncoder>> encoders_;
   std::vector<std::unique_ptr<DrmCrtc>> crtcs_;
   std::vector<std::unique_ptr<DrmPlane>> planes_;
@@ -90,7 +97,8 @@
 
   std::pair<uint32_t, uint32_t> min_resolution_;
   std::pair<uint32_t, uint32_t> max_resolution_;
+  std::map<int, int> displays_;
 };
-}
+}  // namespace android
 
 #endif  // ANDROID_DRM_H_
diff --git a/drmdisplaycomposition.cpp b/drmdisplaycomposition.cpp
index 129bec2..b710fe1 100644
--- a/drmdisplaycomposition.cpp
+++ b/drmdisplaycomposition.cpp
@@ -17,10 +17,10 @@
 #define LOG_TAG "hwc-drm-display-composition"
 
 #include "drmdisplaycomposition.h"
-#include "drmdisplaycompositor.h"
 #include "drmcrtc.h"
+#include "drmdevice.h"
+#include "drmdisplaycompositor.h"
 #include "drmplane.h"
-#include "drmresources.h"
 #include "platform.h"
 
 #include <stdlib.h>
@@ -37,7 +37,7 @@
 DrmDisplayComposition::~DrmDisplayComposition() {
 }
 
-int DrmDisplayComposition::Init(DrmResources *drm, DrmCrtc *crtc,
+int DrmDisplayComposition::Init(DrmDevice *drm, DrmCrtc *crtc,
                                 Importer *importer, Planner *planner,
                                 uint64_t frame_no) {
   drm_ = drm;
@@ -107,9 +107,10 @@
     to_composite.emplace(std::make_pair(i, &layers_[i]));
 
   int ret;
-  std::vector<DrmCompositionPlane> plan;
-  std::tie(ret, composition_planes_) = planner_->ProvisionPlanes(
-      to_composite, crtc_, primary_planes, overlay_planes);
+  std::tie(ret,
+           composition_planes_) = planner_->ProvisionPlanes(to_composite, crtc_,
+                                                            primary_planes,
+                                                            overlay_planes);
   if (ret) {
     ALOGE("Planner failed provisioning planes ret=%d", ret);
     return ret;
@@ -295,4 +296,4 @@
     *out << "\n";
   }
 }
-}
+}  // namespace android
diff --git a/drmdisplaycomposition.h b/drmdisplaycomposition.h
index b4c5892..2a5b1a4 100644
--- a/drmdisplaycomposition.h
+++ b/drmdisplaycomposition.h
@@ -111,8 +111,8 @@
   DrmDisplayComposition(const DrmDisplayComposition &) = delete;
   ~DrmDisplayComposition();
 
-  int Init(DrmResources *drm, DrmCrtc *crtc, Importer *importer,
-           Planner *planner, uint64_t frame_no);
+  int Init(DrmDevice *drm, DrmCrtc *crtc, Importer *importer, Planner *planner,
+           uint64_t frame_no);
 
   int SetLayers(DrmHwcLayer *layers, size_t num_layers, bool geometry_changed);
   int AddPlaneComposition(DrmCompositionPlane plane);
@@ -176,7 +176,7 @@
  private:
   bool validate_composition_type(DrmCompositionType desired);
 
-  DrmResources *drm_ = NULL;
+  DrmDevice *drm_ = NULL;
   DrmCrtc *crtc_ = NULL;
   Importer *importer_ = NULL;
   Planner *planner_ = NULL;
@@ -193,6 +193,6 @@
 
   uint64_t frame_no_ = 0;
 };
-}
+}  // namespace android
 
 #endif  // ANDROID_DRM_DISPLAY_COMPOSITION_H_
diff --git a/drmdisplaycompositor.cpp b/drmdisplaycompositor.cpp
index e7e0694..f479f10 100644
--- a/drmdisplaycompositor.cpp
+++ b/drmdisplaycompositor.cpp
@@ -26,26 +26,44 @@
 #include <sstream>
 #include <vector>
 
-#include <log/log.h>
 #include <drm/drm_mode.h>
+#include <log/log.h>
 #include <sync/sync.h>
 #include <utils/Trace.h>
 
 #include "autolock.h"
 #include "drmcrtc.h"
+#include "drmdevice.h"
 #include "drmplane.h"
-#include "drmresources.h"
+
+static const uint32_t kWaitWritebackFence = 100;  // ms
 
 namespace android {
 
+class CompositorVsyncCallback : public VsyncCallback {
+ public:
+  CompositorVsyncCallback(DrmDisplayCompositor *compositor)
+      : compositor_(compositor) {
+  }
+
+  void Callback(int display, int64_t timestamp) {
+    compositor_->Vsync(display, timestamp);
+  }
+
+ private:
+  DrmDisplayCompositor *compositor_;
+};
+
 DrmDisplayCompositor::DrmDisplayCompositor()
-    : drm_(NULL),
+    : resource_manager_(NULL),
       display_(-1),
       initialized_(false),
       active_(false),
       use_hw_overlays_(true),
       dump_frames_composited_(0),
-      dump_last_timestamp_ns_(0) {
+      dump_last_timestamp_ns_(0),
+      flatten_countdown_(FLATTEN_COUNTDOWN_INIT),
+      writeback_fence_(-1) {
   struct timespec ts;
   if (clock_gettime(CLOCK_MONOTONIC, &ts))
     return;
@@ -56,14 +74,15 @@
   if (!initialized_)
     return;
 
+  vsync_worker_.Exit();
   int ret = pthread_mutex_lock(&lock_);
   if (ret)
     ALOGE("Failed to acquire compositor lock %d", ret);
-
+  DrmDevice *drm = resource_manager_->GetDrmDevice(display_);
   if (mode_.blob_id)
-    drm_->DestroyPropertyBlob(mode_.blob_id);
+    drm->DestroyPropertyBlob(mode_.blob_id);
   if (mode_.old_blob_id)
-    drm_->DestroyPropertyBlob(mode_.old_blob_id);
+    drm->DestroyPropertyBlob(mode_.old_blob_id);
 
   active_composition_.reset();
 
@@ -74,15 +93,24 @@
   pthread_mutex_destroy(&lock_);
 }
 
-int DrmDisplayCompositor::Init(DrmResources *drm, int display) {
-  drm_ = drm;
+int DrmDisplayCompositor::Init(ResourceManager *resource_manager, int display) {
+  resource_manager_ = resource_manager;
   display_ = display;
-
+  DrmDevice *drm = resource_manager_->GetDrmDevice(display);
+  if (!drm) {
+    ALOGE("Could not find drmdevice for display");
+    return -EINVAL;
+  }
   int ret = pthread_mutex_init(&lock_, NULL);
   if (ret) {
     ALOGE("Failed to initialize drm compositor lock %d\n", ret);
     return ret;
   }
+  planner_ = Planner::CreateInstance(drm);
+
+  vsync_worker_.Init(drm, display_);
+  auto callback = std::make_shared<CompositorVsyncCallback>(this);
+  vsync_worker_.RegisterCallback(callback);
 
   initialized_ = true;
   return 0;
@@ -93,9 +121,32 @@
   return std::unique_ptr<DrmDisplayComposition>(new DrmDisplayComposition());
 }
 
+std::unique_ptr<DrmDisplayComposition>
+DrmDisplayCompositor::CreateInitializedComposition() const {
+  DrmDevice *drm = resource_manager_->GetDrmDevice(display_);
+  DrmCrtc *crtc = drm->GetCrtcForDisplay(display_);
+  if (!crtc) {
+    ALOGE("Failed to find crtc for display = %d", display_);
+    return std::unique_ptr<DrmDisplayComposition>();
+  }
+  std::unique_ptr<DrmDisplayComposition> comp = CreateComposition();
+  std::shared_ptr<Importer> importer = resource_manager_->GetImporter(display_);
+  if (!importer) {
+    ALOGE("Failed to find resources for display = %d", display_);
+    return std::unique_ptr<DrmDisplayComposition>();
+  }
+  int ret = comp->Init(drm, crtc, importer.get(), planner_.get(), 0);
+  if (ret) {
+    ALOGE("Failed to init composition for display = %d", display_);
+    return std::unique_ptr<DrmDisplayComposition>();
+  }
+  return comp;
+}
+
 std::tuple<uint32_t, uint32_t, int>
 DrmDisplayCompositor::GetActiveModeResolution() {
-  DrmConnector *connector = drm_->GetConnectorForDisplay(display_);
+  DrmDevice *drm = resource_manager_->GetDrmDevice(display_);
+  DrmConnector *connector = drm->GetConnectorForDisplay(display_);
   if (connector == NULL) {
     ALOGE("Failed to determine display mode: no connector for display %d",
           display_);
@@ -114,8 +165,8 @@
   }
 
   int ret;
-  std::vector<DrmCompositionPlane> &comp_planes =
-      display_comp->composition_planes();
+  std::vector<DrmCompositionPlane> &comp_planes = display_comp
+                                                      ->composition_planes();
   for (DrmCompositionPlane &comp_plane : comp_planes) {
     DrmPlane *plane = comp_plane.plane();
     ret = drmModeAtomicAddProperty(pset, plane->id(),
@@ -128,8 +179,8 @@
       return ret;
     }
   }
-
-  ret = drmModeAtomicCommit(drm_->fd(), pset, 0, drm_);
+  DrmDevice *drm = resource_manager_->GetDrmDevice(display_);
+  ret = drmModeAtomicCommit(drm->fd(), pset, 0, drm);
   if (ret) {
     ALOGE("Failed to commit pset ret=%d\n", ret);
     drmModeAtomicFree(pset);
@@ -140,23 +191,65 @@
   return 0;
 }
 
+int DrmDisplayCompositor::SetupWritebackCommit(drmModeAtomicReqPtr pset,
+                                               uint32_t crtc_id,
+                                               DrmConnector *writeback_conn,
+                                               DrmHwcBuffer *writeback_buffer) {
+  int ret = 0;
+  if (writeback_conn->writeback_fb_id().id() == 0 ||
+      writeback_conn->writeback_out_fence().id() == 0) {
+    ALOGE("Writeback properties don't exit");
+    return -EINVAL;
+  }
+  if ((*writeback_buffer)->fb_id == 0) {
+    ALOGE("Invalid writeback buffer");
+    return -EINVAL;
+  }
+  ret = drmModeAtomicAddProperty(pset, writeback_conn->id(),
+                                 writeback_conn->writeback_fb_id().id(),
+                                 (*writeback_buffer)->fb_id);
+  if (ret < 0) {
+    ALOGE("Failed to add writeback_fb_id");
+    return ret;
+  }
+  ret = drmModeAtomicAddProperty(pset, writeback_conn->id(),
+                                 writeback_conn->writeback_out_fence().id(),
+                                 (uint64_t)&writeback_fence_);
+  if (ret < 0) {
+    ALOGE("Failed to add writeback_out_fence");
+    return ret;
+  }
+
+  ret = drmModeAtomicAddProperty(pset, writeback_conn->id(),
+                                 writeback_conn->crtc_id_property().id(),
+                                 crtc_id);
+  if (ret < 0) {
+    ALOGE("Failed to  attach writeback");
+    return ret;
+  }
+  return 0;
+}
+
 int DrmDisplayCompositor::CommitFrame(DrmDisplayComposition *display_comp,
-                                      bool test_only) {
+                                      bool test_only,
+                                      DrmConnector *writeback_conn,
+                                      DrmHwcBuffer *writeback_buffer) {
   ATRACE_CALL();
 
   int ret = 0;
 
   std::vector<DrmHwcLayer> &layers = display_comp->layers();
-  std::vector<DrmCompositionPlane> &comp_planes =
-      display_comp->composition_planes();
-  uint64_t out_fences[drm_->crtcs().size()];
+  std::vector<DrmCompositionPlane> &comp_planes = display_comp
+                                                      ->composition_planes();
+  DrmDevice *drm = resource_manager_->GetDrmDevice(display_);
+  uint64_t out_fences[drm->crtcs().size()];
 
-  DrmConnector *connector = drm_->GetConnectorForDisplay(display_);
+  DrmConnector *connector = drm->GetConnectorForDisplay(display_);
   if (!connector) {
     ALOGE("Could not locate connector for display %d", display_);
     return -ENODEV;
   }
-  DrmCrtc *crtc = drm_->GetCrtcForDisplay(display_);
+  DrmCrtc *crtc = drm->GetCrtcForDisplay(display_);
   if (!crtc) {
     ALOGE("Could not locate crtc for display %d", display_);
     return -ENODEV;
@@ -168,9 +261,22 @@
     return -ENOMEM;
   }
 
+  if (writeback_buffer != NULL) {
+    if (writeback_conn == NULL) {
+      ALOGE("Invalid arguments requested writeback without writeback conn");
+      return -EINVAL;
+    }
+    ret = SetupWritebackCommit(pset, crtc->id(), writeback_conn,
+                               writeback_buffer);
+    if (ret < 0) {
+      ALOGE("Failed to Setup Writeback Commit ret = %d", ret);
+      return ret;
+    }
+  }
   if (crtc->out_fence_ptr_property().id() != 0) {
-    ret = drmModeAtomicAddProperty(pset, crtc->id(), crtc->out_fence_ptr_property().id(),
-                                   (uint64_t) &out_fences[crtc->pipe()]);
+    ret = drmModeAtomicAddProperty(pset, crtc->id(),
+                                   crtc->out_fence_ptr_property().id(),
+                                   (uint64_t)&out_fences[crtc->pipe()]);
     if (ret < 0) {
       ALOGE("Failed to add OUT_FENCE_PTR property to pset: %d", ret);
       drmModeAtomicFree(pset);
@@ -179,7 +285,8 @@
   }
 
   if (mode_.needs_modeset) {
-    ret = drmModeAtomicAddProperty(pset, crtc->id(), crtc->active_property().id(), 1);
+    ret = drmModeAtomicAddProperty(pset, crtc->id(),
+                                   crtc->active_property().id(), 1);
     if (ret < 0) {
       ALOGE("Failed to add crtc active to pset\n");
       drmModeAtomicFree(pset);
@@ -251,8 +358,8 @@
       if (fence_fd >= 0) {
         int prop_id = plane->in_fence_fd_property().id();
         if (prop_id == 0) {
-                ALOGE("Failed to get IN_FENCE_FD property id");
-                break;
+          ALOGE("Failed to get IN_FENCE_FD property id");
+          break;
         }
         ret = drmModeAtomicAddProperty(pset, plane->id(), prop_id, fence_fd);
         if (ret < 0) {
@@ -299,24 +406,28 @@
     ret |= drmModeAtomicAddProperty(pset, plane->id(),
                                     plane->crtc_y_property().id(),
                                     display_frame.top) < 0;
-    ret |= drmModeAtomicAddProperty(
-               pset, plane->id(), plane->crtc_w_property().id(),
-               display_frame.right - display_frame.left) < 0;
-    ret |= drmModeAtomicAddProperty(
-               pset, plane->id(), plane->crtc_h_property().id(),
-               display_frame.bottom - display_frame.top) < 0;
+    ret |= drmModeAtomicAddProperty(pset, plane->id(),
+                                    plane->crtc_w_property().id(),
+                                    display_frame.right - display_frame.left) <
+           0;
+    ret |= drmModeAtomicAddProperty(pset, plane->id(),
+                                    plane->crtc_h_property().id(),
+                                    display_frame.bottom - display_frame.top) <
+           0;
     ret |= drmModeAtomicAddProperty(pset, plane->id(),
                                     plane->src_x_property().id(),
                                     (int)(source_crop.left) << 16) < 0;
     ret |= drmModeAtomicAddProperty(pset, plane->id(),
                                     plane->src_y_property().id(),
                                     (int)(source_crop.top) << 16) < 0;
-    ret |= drmModeAtomicAddProperty(
-               pset, plane->id(), plane->src_w_property().id(),
-               (int)(source_crop.right - source_crop.left) << 16) < 0;
-    ret |= drmModeAtomicAddProperty(
-               pset, plane->id(), plane->src_h_property().id(),
-               (int)(source_crop.bottom - source_crop.top) << 16) < 0;
+    ret |= drmModeAtomicAddProperty(pset, plane->id(),
+                                    plane->src_w_property().id(),
+                                    (int)(source_crop.right - source_crop.left)
+                                        << 16) < 0;
+    ret |= drmModeAtomicAddProperty(pset, plane->id(),
+                                    plane->src_h_property().id(),
+                                    (int)(source_crop.bottom - source_crop.top)
+                                        << 16) < 0;
     if (ret) {
       ALOGE("Failed to add plane %d to set", plane->id());
       break;
@@ -335,8 +446,7 @@
 
     if (plane->alpha_property().id()) {
       ret = drmModeAtomicAddProperty(pset, plane->id(),
-                                     plane->alpha_property().id(),
-                                     alpha) < 0;
+                                     plane->alpha_property().id(), alpha) < 0;
       if (ret) {
         ALOGE("Failed to add alpha property %d to plane %d",
               plane->alpha_property().id(), plane->id());
@@ -350,7 +460,7 @@
     if (test_only)
       flags |= DRM_MODE_ATOMIC_TEST_ONLY;
 
-    ret = drmModeAtomicCommit(drm_->fd(), pset, flags, drm_);
+    ret = drmModeAtomicCommit(drm->fd(), pset, flags, drm);
     if (ret) {
       if (!test_only)
         ALOGE("Failed to commit pset ret=%d\n", ret);
@@ -362,7 +472,7 @@
     drmModeAtomicFree(pset);
 
   if (!test_only && mode_.needs_modeset) {
-    ret = drm_->DestroyPropertyBlob(mode_.old_blob_id);
+    ret = drm->DestroyPropertyBlob(mode_.old_blob_id);
     if (ret) {
       ALOGE("Failed to destroy old mode property blob %" PRIu32 "/%d",
             mode_.old_blob_id, ret);
@@ -383,21 +493,22 @@
   }
 
   if (crtc->out_fence_ptr_property().id()) {
-    display_comp->set_out_fence((int) out_fences[crtc->pipe()]);
+    display_comp->set_out_fence((int)out_fences[crtc->pipe()]);
   }
 
   return ret;
 }
 
 int DrmDisplayCompositor::ApplyDpms(DrmDisplayComposition *display_comp) {
-  DrmConnector *conn = drm_->GetConnectorForDisplay(display_);
+  DrmDevice *drm = resource_manager_->GetDrmDevice(display_);
+  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(),
+  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());
@@ -413,8 +524,9 @@
   mode.ToDrmModeModeInfo(&drm_mode);
 
   uint32_t id = 0;
-  int ret = drm_->CreatePropertyBlob(&drm_mode,
-                                     sizeof(struct drm_mode_modeinfo), &id);
+  DrmDevice *drm = resource_manager_->GetDrmDevice(display_);
+  int ret = drm->CreatePropertyBlob(&drm_mode, sizeof(struct drm_mode_modeinfo),
+                                    &id);
   if (ret) {
     ALOGE("Failed to create mode property blob %d", ret);
     return std::make_tuple(ret, 0);
@@ -424,11 +536,6 @@
 }
 
 void DrmDisplayCompositor::ClearDisplay() {
-  AutoLock lock(&lock_, "compositor");
-  int ret = lock.Lock();
-  if (ret)
-    return;
-
   if (!active_composition_)
     return;
 
@@ -436,14 +543,24 @@
     return;
 
   active_composition_.reset(NULL);
+  vsync_worker_.VSyncControl(false);
 }
 
 void DrmDisplayCompositor::ApplyFrame(
-    std::unique_ptr<DrmDisplayComposition> composition, int status) {
+    std::unique_ptr<DrmDisplayComposition> composition, int status,
+    bool writeback) {
+  AutoLock lock(&lock_, __func__);
+  if (lock.Lock())
+    return;
   int ret = status;
 
-  if (!ret)
+  if (!ret) {
+    if (writeback && !CountdownExpired()) {
+      ALOGE("Abort playing back scene");
+      return;
+    }
     ret = CommitFrame(composition.get(), false);
+  }
 
   if (ret) {
     ALOGE("Composite failed for display %d", display_);
@@ -454,16 +571,10 @@
   }
   ++dump_frames_composited_;
 
-  ret = pthread_mutex_lock(&lock_);
-  if (ret)
-    ALOGE("Failed to acquire lock for active_composition swap");
-
   active_composition_.swap(composition);
 
-  if (!ret)
-    ret = pthread_mutex_unlock(&lock_);
-  if (ret)
-    ALOGE("Failed to release lock for active_composition swap");
+  flatten_countdown_ = FLATTEN_COUNTDOWN_INIT;
+  vsync_worker_.VSyncControl(!writeback);
 }
 
 int DrmDisplayCompositor::ApplyComposition(
@@ -492,7 +603,8 @@
     case DRM_COMPOSITION_TYPE_MODESET:
       mode_.mode = composition->display_mode();
       if (mode_.blob_id)
-        drm_->DestroyPropertyBlob(mode_.blob_id);
+        resource_manager_->GetDrmDevice(display_)->DestroyPropertyBlob(
+            mode_.blob_id);
       std::tie(ret, mode_.blob_id) = CreateModeBlob(mode_.mode);
       if (ret) {
         ALOGE("Failed to create mode blob for display %d", display_);
@@ -512,6 +624,337 @@
   return CommitFrame(composition, true);
 }
 
+// Flatten a scene on the display by using a writeback connector
+// and returns the composition result as a DrmHwcLayer.
+int DrmDisplayCompositor::FlattenOnDisplay(
+    std::unique_ptr<DrmDisplayComposition> &src, DrmConnector *writeback_conn,
+    DrmMode &src_mode, DrmHwcLayer *writeback_layer) {
+  int ret = 0;
+  DrmDevice *drm = resource_manager_->GetDrmDevice(display_);
+  ret = writeback_conn->UpdateModes();
+  if (ret) {
+    ALOGE("Failed to update modes %d", ret);
+    return ret;
+  }
+  for (const DrmMode &mode : writeback_conn->modes()) {
+    if (mode.h_display() == src_mode.h_display() &&
+        mode.v_display() == src_mode.v_display()) {
+      mode_.mode = mode;
+      if (mode_.blob_id)
+        drm->DestroyPropertyBlob(mode_.blob_id);
+      std::tie(ret, mode_.blob_id) = CreateModeBlob(mode_.mode);
+      if (ret) {
+        ALOGE("Failed to create mode blob for display %d", display_);
+        return ret;
+      }
+      mode_.needs_modeset = true;
+      break;
+    }
+  }
+  if (mode_.blob_id <= 0) {
+    ALOGE("Failed to find similar mode");
+    return -EINVAL;
+  }
+
+  DrmCrtc *crtc = drm->GetCrtcForDisplay(display_);
+  if (!crtc) {
+    ALOGE("Failed to find crtc for display %d", display_);
+    return -EINVAL;
+  }
+  // TODO what happens if planes could go to both CRTCs, I don't think it's
+  // handled anywhere
+  std::vector<DrmPlane *> primary_planes;
+  std::vector<DrmPlane *> overlay_planes;
+  for (auto &plane : drm->planes()) {
+    if (!plane->GetCrtcSupported(*crtc))
+      continue;
+    if (plane->type() == DRM_PLANE_TYPE_PRIMARY)
+      primary_planes.push_back(plane.get());
+    else if (plane->type() == DRM_PLANE_TYPE_OVERLAY)
+      overlay_planes.push_back(plane.get());
+  }
+
+  ret = src->Plan(&primary_planes, &overlay_planes);
+  if (ret) {
+    ALOGE("Failed to plan the composition ret = %d", ret);
+    return ret;
+  }
+
+  // Disable the planes we're not using
+  for (auto i = primary_planes.begin(); i != primary_planes.end();) {
+    src->AddPlaneDisable(*i);
+    i = primary_planes.erase(i);
+  }
+  for (auto i = overlay_planes.begin(); i != overlay_planes.end();) {
+    src->AddPlaneDisable(*i);
+    i = overlay_planes.erase(i);
+  }
+
+  AutoLock lock(&lock_, __func__);
+  ret = lock.Lock();
+  if (ret)
+    return ret;
+  DrmFramebuffer *writeback_fb = &framebuffers_[framebuffer_index_];
+  framebuffer_index_ = (framebuffer_index_ + 1) % DRM_DISPLAY_BUFFERS;
+  if (!writeback_fb->Allocate(mode_.mode.h_display(), mode_.mode.v_display())) {
+    ALOGE("Failed to allocate writeback buffer");
+    return -ENOMEM;
+  }
+  DrmHwcBuffer *writeback_buffer = &writeback_layer->buffer;
+  writeback_layer->sf_handle = writeback_fb->buffer()->handle;
+  ret = writeback_layer->ImportBuffer(
+      resource_manager_->GetImporter(display_).get());
+  if (ret) {
+    ALOGE("Failed to import writeback buffer");
+    return ret;
+  }
+
+  ret = CommitFrame(src.get(), true, writeback_conn, writeback_buffer);
+  if (ret) {
+    ALOGE("Atomic check failed");
+    return ret;
+  }
+  ret = CommitFrame(src.get(), false, writeback_conn, writeback_buffer);
+  if (ret) {
+    ALOGE("Atomic commit failed");
+    return ret;
+  }
+
+  ret = sync_wait(writeback_fence_, kWaitWritebackFence);
+  writeback_layer->acquire_fence.Set(writeback_fence_);
+  writeback_fence_ = -1;
+  if (ret) {
+    ALOGE("Failed to wait on writeback fence");
+    return ret;
+  }
+  return 0;
+}
+
+// Flatten a scene by enabling the writeback connector attached
+// to the same CRTC as the one driving the display.
+int DrmDisplayCompositor::FlattenSerial(DrmConnector *writeback_conn) {
+  ALOGV("FlattenSerial by enabling writeback connector to the same crtc");
+  // Flattened composition with only one layer that is obtained
+  // using the writeback connector
+  std::unique_ptr<DrmDisplayComposition>
+      writeback_comp = CreateInitializedComposition();
+  if (!writeback_comp)
+    return -EINVAL;
+
+  AutoLock lock(&lock_, __func__);
+  int ret = lock.Lock();
+  if (ret)
+    return ret;
+  if (!CountdownExpired() || active_composition_->layers().size() < 2) {
+    ALOGV("Flattening is not needed");
+    return -EALREADY;
+  }
+
+  DrmFramebuffer *writeback_fb = &framebuffers_[framebuffer_index_];
+  framebuffer_index_ = (framebuffer_index_ + 1) % DRM_DISPLAY_BUFFERS;
+  lock.Unlock();
+
+  if (!writeback_fb->Allocate(mode_.mode.h_display(), mode_.mode.v_display())) {
+    ALOGE("Failed to allocate writeback buffer");
+    return -ENOMEM;
+  }
+  writeback_comp->layers().emplace_back();
+
+  DrmHwcLayer &writeback_layer = writeback_comp->layers().back();
+  writeback_layer.sf_handle = writeback_fb->buffer()->handle;
+  writeback_layer.source_crop = {0, 0, (float)mode_.mode.h_display(),
+                                 (float)mode_.mode.v_display()};
+  writeback_layer.display_frame = {0, 0, (int)mode_.mode.h_display(),
+                                   (int)mode_.mode.v_display()};
+  ret = writeback_layer.ImportBuffer(
+      resource_manager_->GetImporter(display_).get());
+  if (ret || writeback_comp->layers().size() != 1) {
+    ALOGE("Failed to import writeback buffer");
+    return ret;
+  }
+
+  drmModeAtomicReqPtr pset = drmModeAtomicAlloc();
+  if (!pset) {
+    ALOGE("Failed to allocate property set");
+    return -ENOMEM;
+  }
+  DrmDevice *drm = resource_manager_->GetDrmDevice(display_);
+  DrmCrtc *crtc = drm->GetCrtcForDisplay(display_);
+  if (!crtc) {
+    ALOGE("Failed to find crtc for display %d", display_);
+    return -EINVAL;
+  }
+  ret = SetupWritebackCommit(pset, crtc->id(), writeback_conn,
+                             &writeback_layer.buffer);
+  if (ret < 0) {
+    ALOGE("Failed to Setup Writeback Commit");
+    return ret;
+  }
+  ret = drmModeAtomicCommit(drm->fd(), pset, 0, drm);
+  if (ret) {
+    ALOGE("Failed to enable writeback %d", ret);
+    return ret;
+  }
+  ret = sync_wait(writeback_fence_, kWaitWritebackFence);
+  writeback_layer.acquire_fence.Set(writeback_fence_);
+  writeback_fence_ = -1;
+  if (ret) {
+    ALOGE("Failed to wait on writeback fence");
+    return ret;
+  }
+
+  DrmCompositionPlane squashed_comp(DrmCompositionPlane::Type::kLayer, NULL,
+                                    crtc);
+  for (auto &drmplane : drm->planes()) {
+    if (!drmplane->GetCrtcSupported(*crtc))
+      continue;
+    if (!squashed_comp.plane() && drmplane->type() == DRM_PLANE_TYPE_PRIMARY)
+      squashed_comp.set_plane(drmplane.get());
+    else
+      writeback_comp->AddPlaneDisable(drmplane.get());
+  }
+  squashed_comp.source_layers().push_back(0);
+  ret = writeback_comp->AddPlaneComposition(std::move(squashed_comp));
+  if (ret) {
+    ALOGE("Failed to add flatten scene");
+    return ret;
+  }
+
+  ApplyFrame(std::move(writeback_comp), 0, true);
+  return 0;
+}
+
+// Flatten a scene by using a crtc which works concurrent with
+// the one driving the display.
+int DrmDisplayCompositor::FlattenConcurrent(DrmConnector *writeback_conn) {
+  ALOGV("FlattenConcurrent by using an unused crtc/display");
+  int ret = 0;
+  DrmDisplayCompositor drmdisplaycompositor;
+  ret = drmdisplaycompositor.Init(resource_manager_, writeback_conn->display());
+  if (ret) {
+    ALOGE("Failed to init  drmdisplaycompositor = %d", ret);
+    return ret;
+  }
+  // Copy of the active_composition, needed because of two things:
+  // 1) Not to hold the lock for the whole time we are accessing
+  //    active_composition
+  // 2) It will be committed on a crtc that might not be on the same
+  //     dri node, so buffers need to be imported on the right node.
+  std::unique_ptr<DrmDisplayComposition>
+      copy_comp = drmdisplaycompositor.CreateInitializedComposition();
+
+  // Writeback composition that will be committed to the display.
+  std::unique_ptr<DrmDisplayComposition>
+      writeback_comp = CreateInitializedComposition();
+
+  if (!copy_comp || !writeback_comp)
+    return -EINVAL;
+  AutoLock lock(&lock_, __func__);
+  ret = lock.Lock();
+  if (ret)
+    return ret;
+  if (!CountdownExpired() || active_composition_->layers().size() < 2) {
+    ALOGV("Flattening is not needed");
+    return -EALREADY;
+  }
+  DrmCrtc *crtc = active_composition_->crtc();
+
+  std::vector<DrmHwcLayer> copy_layers;
+  for (DrmHwcLayer &src_layer : active_composition_->layers()) {
+    DrmHwcLayer copy;
+    ret = copy.InitFromDrmHwcLayer(&src_layer,
+                                   resource_manager_
+                                       ->GetImporter(writeback_conn->display())
+                                       .get());
+    if (ret) {
+      ALOGE("Failed to import buffer ret = %d", ret);
+      return -EINVAL;
+    }
+    copy_layers.emplace_back(std::move(copy));
+  }
+  ret = copy_comp->SetLayers(copy_layers.data(), copy_layers.size(), true);
+  if (ret) {
+    ALOGE("Failed to set copy_comp layers");
+    return ret;
+  }
+
+  lock.Unlock();
+  DrmHwcLayer writeback_layer;
+  ret = drmdisplaycompositor.FlattenOnDisplay(copy_comp, writeback_conn,
+                                              mode_.mode, &writeback_layer);
+  if (ret) {
+    ALOGE("Failed to flatten on display ret = %d", ret);
+    return ret;
+  }
+
+  DrmCompositionPlane squashed_comp(DrmCompositionPlane::Type::kLayer, NULL,
+                                    crtc);
+  for (auto &drmplane : resource_manager_->GetDrmDevice(display_)->planes()) {
+    if (!drmplane->GetCrtcSupported(*crtc))
+      continue;
+    if (drmplane->type() == DRM_PLANE_TYPE_PRIMARY)
+      squashed_comp.set_plane(drmplane.get());
+    else
+      writeback_comp->AddPlaneDisable(drmplane.get());
+  }
+  writeback_comp->layers().emplace_back();
+  DrmHwcLayer &next_layer = writeback_comp->layers().back();
+  next_layer.sf_handle = writeback_layer.get_usable_handle();
+  next_layer.blending = DrmHwcBlending::kPreMult;
+  next_layer.source_crop = {0, 0, (float)mode_.mode.h_display(),
+                            (float)mode_.mode.v_display()};
+  next_layer.display_frame = {0, 0, (int)mode_.mode.h_display(),
+                              (int)mode_.mode.v_display()};
+  ret = next_layer.ImportBuffer(resource_manager_->GetImporter(display_).get());
+  if (ret) {
+    ALOGE("Failed to import framebuffer for display %d", ret);
+    return ret;
+  }
+  squashed_comp.source_layers().push_back(0);
+  ret = writeback_comp->AddPlaneComposition(std::move(squashed_comp));
+  if (ret) {
+    ALOGE("Failed to add plane composition %d", ret);
+    return ret;
+  }
+  ApplyFrame(std::move(writeback_comp), 0, true);
+  return ret;
+}
+
+int DrmDisplayCompositor::FlattenActiveComposition() {
+  DrmConnector *writeback_conn = resource_manager_->AvailableWritebackConnector(
+      display_);
+  if (!active_composition_ || !writeback_conn) {
+    ALOGV("No writeback connector available");
+    return -EINVAL;
+  }
+
+  if (writeback_conn->display() != display_) {
+    return FlattenConcurrent(writeback_conn);
+  } else {
+    return FlattenSerial(writeback_conn);
+  }
+
+  return 0;
+}
+
+bool DrmDisplayCompositor::CountdownExpired() const {
+  return flatten_countdown_ <= 0;
+}
+
+void DrmDisplayCompositor::Vsync(int display, int64_t timestamp) {
+  AutoLock lock(&lock_, __func__);
+  if (lock.Lock())
+    return;
+  flatten_countdown_--;
+  if (!CountdownExpired())
+    return;
+  lock.Unlock();
+  int ret = FlattenActiveComposition();
+  ALOGV("scene flattening triggered for display %d at timestamp %" PRIu64
+        " result = %d \n",
+        display, timestamp, ret);
+}
+
 void DrmDisplayCompositor::Dump(std::ostringstream *out) const {
   int ret = pthread_mutex_lock(&lock_);
   if (ret)
@@ -539,4 +982,4 @@
 
   pthread_mutex_unlock(&lock_);
 }
-}
+}  // namespace android
diff --git a/drmdisplaycompositor.h b/drmdisplaycompositor.h
index 0d85949..67f6334 100644
--- a/drmdisplaycompositor.h
+++ b/drmdisplaycompositor.h
@@ -17,9 +17,11 @@
 #ifndef ANDROID_DRM_DISPLAY_COMPOSITOR_H_
 #define ANDROID_DRM_DISPLAY_COMPOSITOR_H_
 
-#include "drmhwcomposer.h"
 #include "drmdisplaycomposition.h"
 #include "drmframebuffer.h"
+#include "drmhwcomposer.h"
+#include "resourcemanager.h"
+#include "vsyncworker.h"
 
 #include <pthread.h>
 #include <memory>
@@ -33,6 +35,10 @@
 // squash a frame that the hw can't display with hw overlays.
 #define DRM_DISPLAY_BUFFERS 3
 
+// If a scene is still for this number of vblanks flatten it to reduce power
+// consumption.
+#define FLATTEN_COUNTDOWN_INIT 60
+
 namespace android {
 
 class DrmDisplayCompositor {
@@ -40,13 +46,15 @@
   DrmDisplayCompositor();
   ~DrmDisplayCompositor();
 
-  int Init(DrmResources *drm, int display);
+  int Init(ResourceManager *resource_manager, int display);
 
   std::unique_ptr<DrmDisplayComposition> CreateComposition() const;
+  std::unique_ptr<DrmDisplayComposition> CreateInitializedComposition() const;
   int ApplyComposition(std::unique_ptr<DrmDisplayComposition> composition);
   int TestComposition(DrmDisplayComposition *composition);
   int Composite();
   void Dump(std::ostringstream *out) const;
+  void Vsync(int display, int64_t timestamp);
 
   std::tuple<uint32_t, uint32_t, int> GetActiveModeResolution();
 
@@ -65,20 +73,30 @@
   static const int kAcquireWaitTries = 5;
   static const int kAcquireWaitTimeoutMs = 100;
 
-  int PrepareFramebuffer(DrmFramebuffer &fb,
-                         DrmDisplayComposition *display_comp);
-  int PrepareFrame(DrmDisplayComposition *display_comp);
-  int CommitFrame(DrmDisplayComposition *display_comp, bool test_only);
+  int CommitFrame(DrmDisplayComposition *display_comp, bool test_only,
+                  DrmConnector *writeback_conn = NULL,
+                  DrmHwcBuffer *writeback_buffer = NULL);
+  int SetupWritebackCommit(drmModeAtomicReqPtr pset, uint32_t crtc_id,
+                           DrmConnector *writeback_conn,
+                           DrmHwcBuffer *writeback_buffer);
   int ApplyDpms(DrmDisplayComposition *display_comp);
   int DisablePlanes(DrmDisplayComposition *display_comp);
 
   void ClearDisplay();
   void ApplyFrame(std::unique_ptr<DrmDisplayComposition> composition,
-                  int status);
+                  int status, bool writeback = false);
+  int FlattenActiveComposition();
+  int FlattenSerial(DrmConnector *writeback_conn);
+  int FlattenConcurrent(DrmConnector *writeback_conn);
+  int FlattenOnDisplay(std::unique_ptr<DrmDisplayComposition> &src,
+                       DrmConnector *writeback_conn, DrmMode &src_mode,
+                       DrmHwcLayer *writeback_layer);
+
+  bool CountdownExpired() const;
 
   std::tuple<int, uint32_t> CreateModeBlob(const DrmMode &mode);
 
-  DrmResources *drm_;
+  ResourceManager *resource_manager_;
   int display_;
 
   std::unique_ptr<DrmDisplayComposition> active_composition_;
@@ -99,7 +117,11 @@
   // we need to reset them on every Dump() call.
   mutable uint64_t dump_frames_composited_;
   mutable uint64_t dump_last_timestamp_ns_;
+  VSyncWorker vsync_worker_;
+  int64_t flatten_countdown_;
+  std::unique_ptr<Planner> planner_;
+  int writeback_fence_;
 };
-}
+}  // namespace android
 
 #endif  // ANDROID_DRM_DISPLAY_COMPOSITOR_H_
diff --git a/drmencoder.cpp b/drmencoder.cpp
index 3d762f3..c36fca1 100644
--- a/drmencoder.cpp
+++ b/drmencoder.cpp
@@ -14,9 +14,9 @@
  * limitations under the License.
  */
 
-#include "drmcrtc.h"
 #include "drmencoder.h"
-#include "drmresources.h"
+#include "drmcrtc.h"
+#include "drmdevice.h"
 
 #include <stdint.h>
 #include <xf86drmMode.h>
@@ -27,6 +27,7 @@
                        const std::vector<DrmCrtc *> &possible_crtcs)
     : id_(e->encoder_id),
       crtc_(current_crtc),
+      display_(-1),
       possible_crtcs_(possible_crtcs) {
 }
 
@@ -38,7 +39,24 @@
   return crtc_;
 }
 
+bool DrmEncoder::CanClone(DrmEncoder *possible_clone) {
+  return possible_clones_.find(possible_clone) != possible_clones_.end();
+}
+
+void DrmEncoder::AddPossibleClone(DrmEncoder *possible_clone) {
+  possible_clones_.insert(possible_clone);
+}
+
 void DrmEncoder::set_crtc(DrmCrtc *crtc) {
   crtc_ = crtc;
+  display_ = crtc->display();
 }
+
+int DrmEncoder::display() const {
+  return display_;
 }
+
+bool DrmEncoder::can_bind(int display) const {
+  return display_ == -1 || display_ == display;
+}
+}  // namespace android
diff --git a/drmencoder.h b/drmencoder.h
index 58ccbfb..8a7f682 100644
--- a/drmencoder.h
+++ b/drmencoder.h
@@ -20,8 +20,9 @@
 #include "drmcrtc.h"
 
 #include <stdint.h>
-#include <vector>
 #include <xf86drmMode.h>
+#include <set>
+#include <vector>
 
 namespace android {
 
@@ -36,17 +37,23 @@
 
   DrmCrtc *crtc() const;
   void set_crtc(DrmCrtc *crtc);
+  bool can_bind(int display) const;
+  int display() const;
 
   const std::vector<DrmCrtc *> &possible_crtcs() const {
     return possible_crtcs_;
   }
+  bool CanClone(DrmEncoder *encoder);
+  void AddPossibleClone(DrmEncoder *possible_clone);
 
  private:
   uint32_t id_;
   DrmCrtc *crtc_;
+  int display_;
 
   std::vector<DrmCrtc *> possible_crtcs_;
+  std::set<DrmEncoder *> possible_clones_;
 };
-}
+}  // namespace android
 
 #endif  // ANDROID_DRM_ENCODER_H_
diff --git a/drmeventlistener.cpp b/drmeventlistener.cpp
index 9cdff81..6aab6fb 100644
--- a/drmeventlistener.cpp
+++ b/drmeventlistener.cpp
@@ -17,23 +17,22 @@
 #define LOG_TAG "hwc-drm-event-listener"
 
 #include "drmeventlistener.h"
-#include "drmresources.h"
+#include "drmdevice.h"
 
 #include <assert.h>
 #include <errno.h>
 #include <linux/netlink.h>
 #include <sys/socket.h>
 
-#include <log/log.h>
 #include <hardware/hardware.h>
 #include <hardware/hwcomposer.h>
+#include <log/log.h>
 #include <xf86drm.h>
 
 namespace android {
 
-DrmEventListener::DrmEventListener(DrmResources *drm)
-    : Worker("drm-event-listener", HAL_PRIORITY_URGENT_DISPLAY),
-      drm_(drm) {
+DrmEventListener::DrmEventListener(DrmDevice *drm)
+    : Worker("drm-event-listener", HAL_PRIORITY_URGENT_DISPLAY), drm_(drm) {
 }
 
 int DrmEventListener::Init() {
@@ -126,14 +125,14 @@
   } while (ret == -1 && errno == EINTR);
 
   if (FD_ISSET(drm_->fd(), &fds_)) {
-    drmEventContext event_context = {
-        .version = 2,
-        .vblank_handler = NULL,
-        .page_flip_handler = DrmEventListener::FlipHandler};
+    drmEventContext event_context =
+        {.version = 2,
+         .vblank_handler = NULL,
+         .page_flip_handler = DrmEventListener::FlipHandler};
     drmHandleEvent(drm_->fd(), &event_context);
   }
 
   if (FD_ISSET(uevent_fd_.get(), &fds_))
     UEventHandler();
 }
-}
+}  // namespace android
diff --git a/drmeventlistener.h b/drmeventlistener.h
index 61eefe8..d8a61a5 100644
--- a/drmeventlistener.h
+++ b/drmeventlistener.h
@@ -22,7 +22,7 @@
 
 namespace android {
 
-class DrmResources;
+class DrmDevice;
 
 class DrmEventHandler {
  public:
@@ -36,7 +36,7 @@
 
 class DrmEventListener : public Worker {
  public:
-  DrmEventListener(DrmResources *drm);
+  DrmEventListener(DrmDevice *drm);
   virtual ~DrmEventListener() {
   }
 
@@ -57,9 +57,9 @@
   UniqueFd uevent_fd_;
   int max_fd_ = -1;
 
-  DrmResources *drm_;
+  DrmDevice *drm_;
   DrmEventHandler *hotplug_handler_ = NULL;
 };
-}
+}  // namespace android
 
 #endif
diff --git a/drmframebuffer.h b/drmframebuffer.h
index 897589c..9032d3a 100644
--- a/drmframebuffer.h
+++ b/drmframebuffer.h
@@ -65,7 +65,7 @@
       }
       Clear();
     }
-    buffer_ = new GraphicBuffer(w, h, PIXEL_FORMAT_RGBA_8888,
+    buffer_ = new GraphicBuffer(w, h, PIXEL_FORMAT_RGB_888,
                                 GRALLOC_USAGE_HW_FB | GRALLOC_USAGE_HW_RENDER |
                                     GRALLOC_USAGE_HW_COMPOSER);
     release_fence_fd_ = -1;
@@ -102,6 +102,6 @@
   sp<GraphicBuffer> buffer_;
   int release_fence_fd_;
 };
-}
+}  // namespace android
 
 #endif  // ANDROID_DRM_FRAMEBUFFER_
diff --git a/drmhwcgralloc.h b/drmhwcgralloc.h
index 759746a..65a4007 100644
--- a/drmhwcgralloc.h
+++ b/drmhwcgralloc.h
@@ -19,14 +19,17 @@
 
 #include <stdint.h>
 
+#define HWC_DRM_BO_MAX_PLANES 4
 typedef struct hwc_drm_bo {
   uint32_t width;
   uint32_t height;
-  uint32_t format; /* DRM_FORMAT_* from drm_fourcc.h */
+  uint32_t format;     /* DRM_FORMAT_* from drm_fourcc.h */
+  uint32_t hal_format; /* HAL_PIXEL_FORMAT_* */
   uint32_t usage;
-  uint32_t pitches[4];
-  uint32_t offsets[4];
-  uint32_t gem_handles[4];
+  uint32_t pixel_stride;
+  uint32_t pitches[HWC_DRM_BO_MAX_PLANES];
+  uint32_t offsets[HWC_DRM_BO_MAX_PLANES];
+  uint32_t gem_handles[HWC_DRM_BO_MAX_PLANES];
   uint32_t fb_id;
   int acquire_fence_fd;
   void *priv;
diff --git a/drmhwcomposer.h b/drmhwcomposer.h
index ab8f087..2af7e6e 100644
--- a/drmhwcomposer.h
+++ b/drmhwcomposer.h
@@ -142,6 +142,7 @@
   OutputFd release_fence;
 
   int ImportBuffer(Importer *importer);
+  int InitFromDrmHwcLayer(DrmHwcLayer *layer, Importer *importer);
 
   void SetTransform(int32_t sf_transform);
   void SetSourceCrop(hwc_frect_t const &crop);
@@ -161,6 +162,6 @@
   OutputFd retire_fence;
   std::vector<DrmHwcLayer> layers;
 };
-}
+}  // namespace android
 
 #endif
diff --git a/drmhwctwo.cpp b/drmhwctwo.cpp
index 6bab17b..c801f2e 100644
--- a/drmhwctwo.cpp
+++ b/drmhwctwo.cpp
@@ -17,19 +17,19 @@
 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
 #define LOG_TAG "hwc-drm-two"
 
+#include "drmhwctwo.h"
 #include "drmdisplaycomposition.h"
 #include "drmhwcomposer.h"
-#include "drmhwctwo.h"
 #include "platform.h"
 #include "vsyncworker.h"
 
 #include <inttypes.h>
 #include <string>
 
-#include <log/log.h>
 #include <cutils/properties.h>
 #include <hardware/hardware.h>
 #include <hardware/hwcomposer2.h>
+#include <log/log.h>
 
 namespace android {
 
@@ -58,24 +58,27 @@
 }
 
 HWC2::Error DrmHwcTwo::Init() {
-  int ret = drm_.Init();
+  int ret = resource_manager_.Init();
   if (ret) {
-    ALOGE("Can't initialize drm object %d", ret);
+    ALOGE("Can't initialize the resource manager %d", ret);
     return HWC2::Error::NoResources;
   }
 
-  importer_.reset(Importer::CreateInstance(&drm_));
-  if (!importer_) {
-    ALOGE("Failed to create importer instance");
+  DrmDevice *drm = resource_manager_.GetDrmDevice(HWC_DISPLAY_PRIMARY);
+  std::shared_ptr<Importer> importer = resource_manager_.GetImporter(
+      HWC_DISPLAY_PRIMARY);
+  if (!drm || !importer) {
+    ALOGE("Failed to get a valid drmresource and importer");
     return HWC2::Error::NoResources;
   }
 
   displays_.emplace(std::piecewise_construct,
                     std::forward_as_tuple(HWC_DISPLAY_PRIMARY),
-                    std::forward_as_tuple(&drm_, importer_, HWC_DISPLAY_PRIMARY,
+                    std::forward_as_tuple(&resource_manager_, drm, importer,
+                                          HWC_DISPLAY_PRIMARY,
                                           HWC2::DisplayType::Physical));
 
-  DrmCrtc *crtc = drm_.GetCrtcForDisplay(static_cast<int>(HWC_DISPLAY_PRIMARY));
+  DrmCrtc *crtc = drm->GetCrtcForDisplay(static_cast<int>(HWC_DISPLAY_PRIMARY));
   if (!crtc) {
     ALOGE("Failed to get crtc for display %d",
           static_cast<int>(HWC_DISPLAY_PRIMARY));
@@ -83,7 +86,7 @@
   }
 
   std::vector<DrmPlane *> display_planes;
-  for (auto &plane : drm_.planes()) {
+  for (auto &plane : drm->planes()) {
     if (plane->GetCrtcSupported(*crtc))
       display_planes.push_back(plane.get());
   }
@@ -150,10 +153,15 @@
   return HWC2::Error::None;
 }
 
-DrmHwcTwo::HwcDisplay::HwcDisplay(DrmResources *drm,
+DrmHwcTwo::HwcDisplay::HwcDisplay(ResourceManager *resource_manager,
+                                  DrmDevice *drm,
                                   std::shared_ptr<Importer> importer,
                                   hwc2_display_t handle, HWC2::DisplayType type)
-    : drm_(drm), importer_(importer), handle_(handle), type_(type) {
+    : resource_manager_(resource_manager),
+      drm_(drm),
+      importer_(importer),
+      handle_(handle),
+      type_(type) {
   supported(__func__);
 }
 
@@ -166,7 +174,7 @@
   }
 
   int display = static_cast<int>(handle_);
-  int ret = compositor_.Init(drm_, display);
+  int ret = compositor_.Init(resource_manager_, display);
   if (ret) {
     ALOGE("Failed display compositor init for display %d (%d)", display, ret);
     return HWC2::Error::NoResources;
@@ -314,9 +322,11 @@
                                                        int32_t attribute_in,
                                                        int32_t *value) {
   supported(__func__);
-  auto mode =
-      std::find_if(connector_->modes().begin(), connector_->modes().end(),
-                   [config](DrmMode const &m) { return m.id() == config; });
+  auto mode = std::find_if(connector_->modes().begin(),
+                           connector_->modes().end(),
+                           [config](DrmMode const &m) {
+                             return m.id() == config;
+                           });
   if (mode == connector_->modes().end()) {
     ALOGE("Could not find active mode for %d", config);
     return HWC2::Error::BadConfig;
@@ -425,8 +435,8 @@
 }
 
 HWC2::Error DrmHwcTwo::HwcDisplay::GetHdrCapabilities(
-    uint32_t *num_types, int32_t */*types*/, float */*max_luminance*/,
-    float */*max_average_luminance*/, float */*min_luminance*/) {
+    uint32_t *num_types, int32_t * /*types*/, float * /*max_luminance*/,
+    float * /*max_average_luminance*/, float * /*min_luminance*/) {
   supported(__func__);
   *num_types = 0;
   return HWC2::Error::None;
@@ -517,8 +527,8 @@
     map.layers.emplace_back(std::move(layer));
   }
 
-  std::unique_ptr<DrmDisplayComposition> composition =
-      compositor_.CreateComposition();
+  std::unique_ptr<DrmDisplayComposition> composition = compositor_
+                                                           .CreateComposition();
   composition->Init(drm_, crtc_, importer_.get(), planner_.get(), frame_no_);
 
   // TODO: Don't always assume geometry changed
@@ -584,16 +594,18 @@
 
 HWC2::Error DrmHwcTwo::HwcDisplay::SetActiveConfig(hwc2_config_t config) {
   supported(__func__);
-  auto mode =
-      std::find_if(connector_->modes().begin(), connector_->modes().end(),
-                   [config](DrmMode const &m) { return m.id() == config; });
+  auto mode = std::find_if(connector_->modes().begin(),
+                           connector_->modes().end(),
+                           [config](DrmMode const &m) {
+                             return m.id() == config;
+                           });
   if (mode == connector_->modes().end()) {
     ALOGE("Could not find active mode for %d", config);
     return HWC2::Error::BadConfig;
   }
 
-  std::unique_ptr<DrmDisplayComposition> composition =
-      compositor_.CreateComposition();
+  std::unique_ptr<DrmDisplayComposition> composition = compositor_
+                                                           .CreateComposition();
   composition->Init(drm_, crtc_, importer_.get(), planner_.get(), frame_no_);
   int ret = composition->SetDisplayMode(*mode);
   ret = compositor_.ApplyComposition(std::move(composition));
@@ -672,8 +684,8 @@
       return HWC2::Error::Unsupported;
   };
 
-  std::unique_ptr<DrmDisplayComposition> composition =
-      compositor_.CreateComposition();
+  std::unique_ptr<DrmDisplayComposition> composition = compositor_
+                                                           .CreateComposition();
   composition->Init(drm_, crtc_, importer_.get(), planner_.get(), frame_no_);
   composition->SetDpmsMode(dpms_value);
   int ret = compositor_.ApplyComposition(std::move(composition));
@@ -693,10 +705,10 @@
 HWC2::Error DrmHwcTwo::HwcDisplay::ValidateDisplay(uint32_t *num_types,
                                                    uint32_t *num_requests) {
   supported(__func__);
-  size_t plane_count = 0;
   *num_types = 0;
   *num_requests = 0;
   size_t avail_planes = primary_planes_.size() + overlay_planes_.size();
+  bool comp_failed = false;
 
   HWC2::Error ret;
 
@@ -705,8 +717,7 @@
 
   ret = CreateComposition(true);
   if (ret != HWC2::Error::None)
-    // Assume the test failed due to overlay planes
-    avail_planes = 1;
+    comp_failed = true;
 
   std::map<uint32_t, DrmHwcTwo::HwcLayer *, std::greater<int>> z_map;
   for (std::pair<const hwc2_layer_t, DrmHwcTwo::HwcLayer> &l : layers_) {
@@ -722,7 +733,7 @@
     avail_planes--;
 
   for (std::pair<const uint32_t, DrmHwcTwo::HwcLayer *> &l : z_map) {
-    if (!avail_planes--)
+    if (comp_failed || !avail_planes--)
       break;
     l.second->set_validated_type(HWC2::Composition::Device);
   }
@@ -896,7 +907,7 @@
       return ToHook<HWC2_PFN_CREATE_VIRTUAL_DISPLAY>(
           DeviceHook<int32_t, decltype(&DrmHwcTwo::CreateVirtualDisplay),
                      &DrmHwcTwo::CreateVirtualDisplay, uint32_t, uint32_t,
-                     int32_t*, hwc2_display_t *>);
+                     int32_t *, hwc2_display_t *>);
     case HWC2::FunctionDescriptor::DestroyVirtualDisplay:
       return ToHook<HWC2_PFN_DESTROY_VIRTUAL_DISPLAY>(
           DeviceHook<int32_t, decltype(&DrmHwcTwo::DestroyVirtualDisplay),
@@ -947,13 +958,15 @@
           DisplayHook<decltype(&HwcDisplay::GetColorModes),
                       &HwcDisplay::GetColorModes, uint32_t *, int32_t *>);
     case HWC2::FunctionDescriptor::GetDisplayAttribute:
-      return ToHook<HWC2_PFN_GET_DISPLAY_ATTRIBUTE>(DisplayHook<
-          decltype(&HwcDisplay::GetDisplayAttribute),
-          &HwcDisplay::GetDisplayAttribute, hwc2_config_t, int32_t, int32_t *>);
+      return ToHook<HWC2_PFN_GET_DISPLAY_ATTRIBUTE>(
+          DisplayHook<decltype(&HwcDisplay::GetDisplayAttribute),
+                      &HwcDisplay::GetDisplayAttribute, hwc2_config_t, int32_t,
+                      int32_t *>);
     case HWC2::FunctionDescriptor::GetDisplayConfigs:
-      return ToHook<HWC2_PFN_GET_DISPLAY_CONFIGS>(DisplayHook<
-          decltype(&HwcDisplay::GetDisplayConfigs),
-          &HwcDisplay::GetDisplayConfigs, uint32_t *, hwc2_config_t *>);
+      return ToHook<HWC2_PFN_GET_DISPLAY_CONFIGS>(
+          DisplayHook<decltype(&HwcDisplay::GetDisplayConfigs),
+                      &HwcDisplay::GetDisplayConfigs, uint32_t *,
+                      hwc2_config_t *>);
     case HWC2::FunctionDescriptor::GetDisplayName:
       return ToHook<HWC2_PFN_GET_DISPLAY_NAME>(
           DisplayHook<decltype(&HwcDisplay::GetDisplayName),
@@ -990,9 +1003,10 @@
           DisplayHook<decltype(&HwcDisplay::SetActiveConfig),
                       &HwcDisplay::SetActiveConfig, hwc2_config_t>);
     case HWC2::FunctionDescriptor::SetClientTarget:
-      return ToHook<HWC2_PFN_SET_CLIENT_TARGET>(DisplayHook<
-          decltype(&HwcDisplay::SetClientTarget), &HwcDisplay::SetClientTarget,
-          buffer_handle_t, int32_t, int32_t, hwc_region_t>);
+      return ToHook<HWC2_PFN_SET_CLIENT_TARGET>(
+          DisplayHook<decltype(&HwcDisplay::SetClientTarget),
+                      &HwcDisplay::SetClientTarget, buffer_handle_t, int32_t,
+                      int32_t, hwc_region_t>);
     case HWC2::FunctionDescriptor::SetColorMode:
       return ToHook<HWC2_PFN_SET_COLOR_MODE>(
           DisplayHook<decltype(&HwcDisplay::SetColorMode),
@@ -1052,9 +1066,10 @@
           LayerHook<decltype(&HwcLayer::SetLayerPlaneAlpha),
                     &HwcLayer::SetLayerPlaneAlpha, float>);
     case HWC2::FunctionDescriptor::SetLayerSidebandStream:
-      return ToHook<HWC2_PFN_SET_LAYER_SIDEBAND_STREAM>(LayerHook<
-          decltype(&HwcLayer::SetLayerSidebandStream),
-          &HwcLayer::SetLayerSidebandStream, const native_handle_t *>);
+      return ToHook<HWC2_PFN_SET_LAYER_SIDEBAND_STREAM>(
+          LayerHook<decltype(&HwcLayer::SetLayerSidebandStream),
+                    &HwcLayer::SetLayerSidebandStream,
+                    const native_handle_t *>);
     case HWC2::FunctionDescriptor::SetLayerSourceCrop:
       return ToHook<HWC2_PFN_SET_LAYER_SOURCE_CROP>(
           LayerHook<decltype(&HwcLayer::SetLayerSourceCrop),
@@ -1107,7 +1122,7 @@
   ctx.release();
   return 0;
 }
-}
+}  // namespace android
 
 static struct hw_module_methods_t hwc2_module_methods = {
     .open = android::DrmHwcTwo::HookDevOpen,
diff --git a/drmhwctwo.h b/drmhwctwo.h
index 82a9768..fd14b1f 100644
--- a/drmhwctwo.h
+++ b/drmhwctwo.h
@@ -16,8 +16,8 @@
 
 #include "drmdisplaycompositor.h"
 #include "drmhwcomposer.h"
-#include "drmresources.h"
 #include "platform.h"
+#include "resourcemanager.h"
 #include "vsyncworker.h"
 
 #include <hardware/hwcomposer2.h>
@@ -135,8 +135,9 @@
 
   class HwcDisplay {
    public:
-    HwcDisplay(DrmResources *drm, std::shared_ptr<Importer> importer,
-               hwc2_display_t handle, HWC2::DisplayType type);
+    HwcDisplay(ResourceManager *resource_manager, DrmDevice *drm,
+               std::shared_ptr<Importer> importer, hwc2_display_t handle,
+               HWC2::DisplayType type);
     HwcDisplay(const HwcDisplay &) = delete;
     HWC2::Error Init(std::vector<DrmPlane *> *planes);
 
@@ -188,7 +189,8 @@
     HWC2::Error CreateComposition(bool test);
     void AddFenceToRetireFence(int fd);
 
-    DrmResources *drm_;
+    ResourceManager *resource_manager_;
+    DrmDevice *drm_;
     DrmDisplayCompositor compositor_;
     std::shared_ptr<Importer> importer_;
     std::unique_ptr<Planner> planner_;
@@ -253,17 +255,15 @@
 
   // Device functions
   HWC2::Error CreateVirtualDisplay(uint32_t width, uint32_t height,
-                                   int32_t *format,
-                                   hwc2_display_t *display);
+                                   int32_t *format, hwc2_display_t *display);
   HWC2::Error DestroyVirtualDisplay(hwc2_display_t display);
   void Dump(uint32_t *size, char *buffer);
   uint32_t GetMaxVirtualDisplayCount();
   HWC2::Error RegisterCallback(int32_t descriptor, hwc2_callback_data_t data,
                                hwc2_function_pointer_t function);
 
-  DrmResources drm_;
-  std::shared_ptr<Importer> importer_;  // Shared with HwcDisplay
+  ResourceManager resource_manager_;
   std::map<hwc2_display_t, HwcDisplay> displays_;
   std::map<HWC2::Callback, HwcCallback> callbacks_;
 };
-}
+}  // namespace android
diff --git a/drmmode.cpp b/drmmode.cpp
index 081efcd..5f2e7c2 100644
--- a/drmmode.cpp
+++ b/drmmode.cpp
@@ -15,11 +15,11 @@
  */
 
 #include "drmmode.h"
-#include "drmresources.h"
+#include "drmdevice.h"
 
 #include <stdint.h>
-#include <string>
 #include <xf86drmMode.h>
+#include <string>
 
 namespace android {
 
@@ -122,8 +122,8 @@
 }
 
 float DrmMode::v_refresh() const {
-  return v_refresh_ ? v_refresh_ * 1.0f :
-                      clock_ / (float)(v_total_ * h_total_) * 1000.0f;
+  return v_refresh_ ? v_refresh_ * 1.0f
+                    : clock_ / (float)(v_total_ * h_total_) * 1000.0f;
 }
 
 uint32_t DrmMode::flags() const {
@@ -137,4 +137,4 @@
 std::string DrmMode::name() const {
   return name_;
 }
-}
+}  // namespace android
diff --git a/drmmode.h b/drmmode.h
index b383168..4cc06b1 100644
--- a/drmmode.h
+++ b/drmmode.h
@@ -18,8 +18,8 @@
 #define ANDROID_DRM_MODE_H_
 
 #include <stdint.h>
-#include <string>
 #include <xf86drmMode.h>
+#include <string>
 
 namespace android {
 
@@ -77,6 +77,6 @@
 
   std::string name_;
 };
-}
+}  // namespace android
 
 #endif  // ANDROID_DRM_MODE_H_
diff --git a/drmplane.cpp b/drmplane.cpp
index 4449256..2603e16 100644
--- a/drmplane.cpp
+++ b/drmplane.cpp
@@ -17,18 +17,18 @@
 #define LOG_TAG "hwc-drm-plane"
 
 #include "drmplane.h"
-#include "drmresources.h"
+#include "drmdevice.h"
 
-#include <cinttypes>
 #include <errno.h>
 #include <stdint.h>
+#include <cinttypes>
 
 #include <log/log.h>
 #include <xf86drmMode.h>
 
 namespace android {
 
-DrmPlane::DrmPlane(DrmResources *drm, drmModePlanePtr p)
+DrmPlane::DrmPlane(DrmDevice *drm, drmModePlanePtr p)
     : drm_(drm), id_(p->plane_id), possible_crtc_mask_(p->possible_crtcs) {
 }
 
@@ -196,4 +196,4 @@
 const DrmProperty &DrmPlane::in_fence_fd_property() const {
   return in_fence_fd_property_;
 }
-}
+}  // namespace android
diff --git a/drmplane.h b/drmplane.h
index 5b73b08..46dbc94 100644
--- a/drmplane.h
+++ b/drmplane.h
@@ -26,11 +26,11 @@
 
 namespace android {
 
-class DrmResources;
+class DrmDevice;
 
 class DrmPlane {
  public:
-  DrmPlane(DrmResources *drm, drmModePlanePtr p);
+  DrmPlane(DrmDevice *drm, drmModePlanePtr p);
   DrmPlane(const DrmPlane &) = delete;
   DrmPlane &operator=(const DrmPlane &) = delete;
 
@@ -57,7 +57,7 @@
   const DrmProperty &in_fence_fd_property() const;
 
  private:
-  DrmResources *drm_;
+  DrmDevice *drm_;
   uint32_t id_;
 
   uint32_t possible_crtc_mask_;
@@ -78,6 +78,6 @@
   DrmProperty alpha_property_;
   DrmProperty in_fence_fd_property_;
 };
-}
+}  // namespace android
 
 #endif  // ANDROID_DRM_PLANE_H_
diff --git a/drmproperty.cpp b/drmproperty.cpp
index 6f65dac..e71c159 100644
--- a/drmproperty.cpp
+++ b/drmproperty.cpp
@@ -15,7 +15,7 @@
  */
 
 #include "drmproperty.h"
-#include "drmresources.h"
+#include "drmdevice.h"
 
 #include <errno.h>
 #include <stdint.h>
@@ -99,4 +99,4 @@
       return -EINVAL;
   }
 }
-}
+}  // namespace android
diff --git a/drmproperty.h b/drmproperty.h
index 648eda7..dc01c88 100644
--- a/drmproperty.h
+++ b/drmproperty.h
@@ -18,8 +18,8 @@
 #define ANDROID_DRM_PROPERTY_H_
 
 #include <stdint.h>
-#include <string>
 #include <xf86drmMode.h>
+#include <string>
 #include <vector>
 
 namespace android {
@@ -67,6 +67,6 @@
   std::vector<DrmPropertyEnum> enums_;
   std::vector<uint32_t> blob_ids_;
 };
-}
+}  // namespace android
 
 #endif  // ANDROID_DRM_PROPERTY_H_
diff --git a/drmresources.cpp b/drmresources.cpp
deleted file mode 100644
index ec6664c..0000000
--- a/drmresources.cpp
+++ /dev/null
@@ -1,392 +0,0 @@
-/*
- * 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-resources"
-
-#include "drmconnector.h"
-#include "drmcrtc.h"
-#include "drmencoder.h"
-#include "drmeventlistener.h"
-#include "drmplane.h"
-#include "drmresources.h"
-
-#include <cinttypes>
-#include <errno.h>
-#include <fcntl.h>
-#include <stdint.h>
-#include <xf86drm.h>
-#include <xf86drmMode.h>
-
-#include <log/log.h>
-#include <cutils/properties.h>
-
-namespace android {
-
-DrmResources::DrmResources() : event_listener_(this) {
-}
-
-DrmResources::~DrmResources() {
-  event_listener_.Exit();
-}
-
-int DrmResources::Init() {
-  char path[PROPERTY_VALUE_MAX];
-  property_get("hwc.drm.device", path, "/dev/dri/card0");
-
-  /* TODO: Use drmOpenControl here instead */
-  fd_.Set(open(path, O_RDWR));
-  if (fd() < 0) {
-    ALOGE("Failed to open dri- %s", strerror(-errno));
-    return -ENODEV;
-  }
-
-  int ret = drmSetClientCap(fd(), DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
-  if (ret) {
-    ALOGE("Failed to set universal plane cap %d", ret);
-    return ret;
-  }
-
-  ret = drmSetClientCap(fd(), DRM_CLIENT_CAP_ATOMIC, 1);
-  if (ret) {
-    ALOGE("Failed to set atomic cap %d", ret);
-    return ret;
-  }
-
-  drmModeResPtr res = drmModeGetResources(fd());
-  if (!res) {
-    ALOGE("Failed to get DrmResources resources");
-    return -ENODEV;
-  }
-
-  min_resolution_ =
-      std::pair<uint32_t, uint32_t>(res->min_width, res->min_height);
-  max_resolution_ =
-      std::pair<uint32_t, uint32_t>(res->max_width, res->max_height);
-
-  bool found_primary = false;
-  int display_num = 1;
-
-  for (int i = 0; !ret && i < res->count_crtcs; ++i) {
-    drmModeCrtcPtr c = drmModeGetCrtc(fd(), res->crtcs[i]);
-    if (!c) {
-      ALOGE("Failed to get crtc %d", res->crtcs[i]);
-      ret = -ENODEV;
-      break;
-    }
-
-    std::unique_ptr<DrmCrtc> crtc(new DrmCrtc(this, c, i));
-    drmModeFreeCrtc(c);
-
-    ret = crtc->Init();
-    if (ret) {
-      ALOGE("Failed to initialize crtc %d", res->crtcs[i]);
-      break;
-    }
-    crtcs_.emplace_back(std::move(crtc));
-  }
-
-  for (int i = 0; !ret && i < res->count_encoders; ++i) {
-    drmModeEncoderPtr e = drmModeGetEncoder(fd(), res->encoders[i]);
-    if (!e) {
-      ALOGE("Failed to get encoder %d", res->encoders[i]);
-      ret = -ENODEV;
-      break;
-    }
-
-    std::vector<DrmCrtc *> possible_crtcs;
-    DrmCrtc *current_crtc = NULL;
-    for (auto &crtc : crtcs_) {
-      if ((1 << crtc->pipe()) & e->possible_crtcs)
-        possible_crtcs.push_back(crtc.get());
-
-      if (crtc->id() == e->crtc_id)
-        current_crtc = crtc.get();
-    }
-
-    std::unique_ptr<DrmEncoder> enc(
-        new DrmEncoder(e, current_crtc, possible_crtcs));
-
-    drmModeFreeEncoder(e);
-
-    encoders_.emplace_back(std::move(enc));
-  }
-
-  for (int i = 0; !ret && i < res->count_connectors; ++i) {
-    drmModeConnectorPtr c = drmModeGetConnector(fd(), res->connectors[i]);
-    if (!c) {
-      ALOGE("Failed to get connector %d", res->connectors[i]);
-      ret = -ENODEV;
-      break;
-    }
-
-    std::vector<DrmEncoder *> possible_encoders;
-    DrmEncoder *current_encoder = NULL;
-    for (int j = 0; j < c->count_encoders; ++j) {
-      for (auto &encoder : encoders_) {
-        if (encoder->id() == c->encoders[j])
-          possible_encoders.push_back(encoder.get());
-        if (encoder->id() == c->encoder_id)
-          current_encoder = encoder.get();
-      }
-    }
-
-    std::unique_ptr<DrmConnector> conn(
-        new DrmConnector(this, c, current_encoder, possible_encoders));
-
-    drmModeFreeConnector(c);
-
-    ret = conn->Init();
-    if (ret) {
-      ALOGE("Init connector %d failed", res->connectors[i]);
-      break;
-    }
-
-    connectors_.emplace_back(std::move(conn));
-  }
-
-  // First look for primary amongst internal connectors
-  for (auto &conn : connectors_) {
-    if (conn->internal() && !found_primary) {
-      conn->set_display(0);
-      found_primary = true;
-    } else {
-      conn->set_display(display_num);
-      ++display_num;
-    }
-  }
-
-  // Then look for primary amongst external connectors
-  for (auto &conn : connectors_) {
-    if (conn->external() && !found_primary) {
-      conn->set_display(0);
-      found_primary = true;
-    }
-  }
-
-  if (res)
-    drmModeFreeResources(res);
-
-  // Catch-all for the above loops
-  if (ret)
-    return ret;
-
-  drmModePlaneResPtr plane_res = drmModeGetPlaneResources(fd());
-  if (!plane_res) {
-    ALOGE("Failed to get plane resources");
-    return -ENOENT;
-  }
-
-  for (uint32_t i = 0; i < plane_res->count_planes; ++i) {
-    drmModePlanePtr p = drmModeGetPlane(fd(), plane_res->planes[i]);
-    if (!p) {
-      ALOGE("Failed to get plane %d", plane_res->planes[i]);
-      ret = -ENODEV;
-      break;
-    }
-
-    std::unique_ptr<DrmPlane> plane(new DrmPlane(this, p));
-
-    drmModeFreePlane(p);
-
-    ret = plane->Init();
-    if (ret) {
-      ALOGE("Init plane %d failed", plane_res->planes[i]);
-      break;
-    }
-
-    planes_.emplace_back(std::move(plane));
-  }
-  drmModeFreePlaneResources(plane_res);
-  if (ret)
-    return ret;
-
-  ret = event_listener_.Init();
-  if (ret) {
-    ALOGE("Can't initialize event listener %d", ret);
-    return ret;
-  }
-
-  for (auto &conn : connectors_) {
-    ret = CreateDisplayPipe(conn.get());
-    if (ret) {
-      ALOGE("Failed CreateDisplayPipe %d with %d", conn->id(), ret);
-      return ret;
-    }
-  }
-  return 0;
-}
-
-DrmConnector *DrmResources::GetConnectorForDisplay(int display) const {
-  for (auto &conn : connectors_) {
-    if (conn->display() == display)
-      return conn.get();
-  }
-  return NULL;
-}
-
-DrmCrtc *DrmResources::GetCrtcForDisplay(int display) const {
-  for (auto &crtc : crtcs_) {
-    if (crtc->display() == display)
-      return crtc.get();
-  }
-  return NULL;
-}
-
-DrmPlane *DrmResources::GetPlane(uint32_t id) const {
-  for (auto &plane : planes_) {
-    if (plane->id() == id)
-      return plane.get();
-  }
-  return NULL;
-}
-
-const std::vector<std::unique_ptr<DrmCrtc>> & DrmResources::crtcs() const {
-  return crtcs_;
-}
-
-uint32_t DrmResources::next_mode_id() {
-  return ++mode_id_;
-}
-
-int DrmResources::TryEncoderForDisplay(int display, DrmEncoder *enc) {
-  /* First try to use the currently-bound crtc */
-  DrmCrtc *crtc = enc->crtc();
-  if (crtc && crtc->can_bind(display)) {
-    crtc->set_display(display);
-    return 0;
-  }
-
-  /* Try to find a possible crtc which will work */
-  for (DrmCrtc *crtc : enc->possible_crtcs()) {
-    /* We've already tried this earlier */
-    if (crtc == enc->crtc())
-      continue;
-
-    if (crtc->can_bind(display)) {
-      enc->set_crtc(crtc);
-      crtc->set_display(display);
-      return 0;
-    }
-  }
-
-  /* We can't use the encoder, but nothing went wrong, try another one */
-  return -EAGAIN;
-}
-
-int DrmResources::CreateDisplayPipe(DrmConnector *connector) {
-  int display = connector->display();
-  /* Try to use current setup first */
-  if (connector->encoder()) {
-    int ret = TryEncoderForDisplay(display, connector->encoder());
-    if (!ret) {
-      return 0;
-    } else if (ret != -EAGAIN) {
-      ALOGE("Could not set mode %d/%d", display, ret);
-      return ret;
-    }
-  }
-
-  for (DrmEncoder *enc : connector->possible_encoders()) {
-    int ret = TryEncoderForDisplay(display, enc);
-    if (!ret) {
-      connector->set_encoder(enc);
-      return 0;
-    } else if (ret != -EAGAIN) {
-      ALOGE("Could not set mode %d/%d", display, ret);
-      return ret;
-    }
-  }
-  ALOGE("Could not find a suitable encoder/crtc for display %d",
-        connector->display());
-  return -ENODEV;
-}
-
-int DrmResources::CreatePropertyBlob(void *data, size_t length,
-                                     uint32_t *blob_id) {
-  struct drm_mode_create_blob create_blob;
-  memset(&create_blob, 0, sizeof(create_blob));
-  create_blob.length = length;
-  create_blob.data = (__u64)data;
-
-  int ret = drmIoctl(fd(), DRM_IOCTL_MODE_CREATEPROPBLOB, &create_blob);
-  if (ret) {
-    ALOGE("Failed to create mode property blob %d", ret);
-    return ret;
-  }
-  *blob_id = create_blob.blob_id;
-  return 0;
-}
-
-int DrmResources::DestroyPropertyBlob(uint32_t blob_id) {
-  if (!blob_id)
-    return 0;
-
-  struct drm_mode_destroy_blob destroy_blob;
-  memset(&destroy_blob, 0, sizeof(destroy_blob));
-  destroy_blob.blob_id = (__u32)blob_id;
-  int ret = drmIoctl(fd(), DRM_IOCTL_MODE_DESTROYPROPBLOB, &destroy_blob);
-  if (ret) {
-    ALOGE("Failed to destroy mode property blob %" PRIu32 "/%d", blob_id, ret);
-    return ret;
-  }
-  return 0;
-}
-
-DrmEventListener *DrmResources::event_listener() {
-  return &event_listener_;
-}
-
-int DrmResources::GetProperty(uint32_t obj_id, uint32_t obj_type,
-                              const char *prop_name, DrmProperty *property) {
-  drmModeObjectPropertiesPtr props;
-
-  props = drmModeObjectGetProperties(fd(), obj_id, obj_type);
-  if (!props) {
-    ALOGE("Failed to get properties for %d/%x", obj_id, obj_type);
-    return -ENODEV;
-  }
-
-  bool found = false;
-  for (int i = 0; !found && (size_t)i < props->count_props; ++i) {
-    drmModePropertyPtr p = drmModeGetProperty(fd(), props->props[i]);
-    if (!strcmp(p->name, prop_name)) {
-      property->Init(p, props->prop_values[i]);
-      found = true;
-    }
-    drmModeFreeProperty(p);
-  }
-
-  drmModeFreeObjectProperties(props);
-  return found ? 0 : -ENOENT;
-}
-
-int DrmResources::GetPlaneProperty(const DrmPlane &plane, const char *prop_name,
-                                   DrmProperty *property) {
-  return GetProperty(plane.id(), DRM_MODE_OBJECT_PLANE, prop_name, property);
-}
-
-int DrmResources::GetCrtcProperty(const DrmCrtc &crtc, const char *prop_name,
-                                  DrmProperty *property) {
-  return GetProperty(crtc.id(), DRM_MODE_OBJECT_CRTC, prop_name, property);
-}
-
-int DrmResources::GetConnectorProperty(const DrmConnector &connector,
-                                       const char *prop_name,
-                                       DrmProperty *property) {
-  return GetProperty(connector.id(), DRM_MODE_OBJECT_CONNECTOR, prop_name,
-                     property);
-}
-}
diff --git a/hwcutils.cpp b/hwcutils.cpp
index be70a39..87e3c42 100644
--- a/hwcutils.cpp
+++ b/hwcutils.cpp
@@ -23,6 +23,8 @@
 #include <log/log.h>
 #include <ui/GraphicBufferMapper.h>
 
+#define UNUSED(x) (void)(x)
+
 namespace android {
 
 const hwc_drm_bo *DrmHwcBuffer::operator->() const {
@@ -60,13 +62,24 @@
 }
 
 int DrmHwcNativeHandle::CopyBufferHandle(buffer_handle_t handle, int width,
-                                         int height, int layerCount,
-                                         int format, int usage, int stride) {
+                                         int height, int layerCount, int format,
+                                         int usage, int stride) {
   native_handle_t *handle_copy;
   GraphicBufferMapper &gm(GraphicBufferMapper::get());
-  int ret =
-      gm.importBuffer(handle, width, height, layerCount, format, usage,
-                      stride, const_cast<buffer_handle_t *>(&handle_copy));
+  int ret;
+
+#ifdef HWC2_USE_OLD_GB_IMPORT
+  UNUSED(width);
+  UNUSED(height);
+  UNUSED(layerCount);
+  UNUSED(format);
+  UNUSED(usage);
+  UNUSED(stride);
+  ret = gm.importBuffer(handle, const_cast<buffer_handle_t *>(&handle_copy));
+#else
+  ret = gm.importBuffer(handle, width, height, layerCount, format, usage,
+                        stride, const_cast<buffer_handle_t *>(&handle_copy));
+#endif
   if (ret) {
     ALOGE("Failed to import buffer handle %d", ret);
     return ret;
@@ -101,9 +114,13 @@
 
   const hwc_drm_bo *bo = buffer.operator->();
 
-  // FIXME: Add layerCount and a pixel stride to the hwc_drm_bo
-  ret = handle.CopyBufferHandle(sf_handle, bo->width, bo->height,
-                                1, bo->format, bo->usage, bo->width);
+  unsigned int layer_count;
+  for (layer_count = 0; layer_count < HWC_DRM_BO_MAX_PLANES; ++layer_count)
+    if (bo->gem_handles[layer_count] == 0)
+      break;
+
+  ret = handle.CopyBufferHandle(sf_handle, bo->width, bo->height, layer_count,
+                                bo->hal_format, bo->usage, bo->pixel_stride);
   if (ret)
     return ret;
 
@@ -112,6 +129,18 @@
   return 0;
 }
 
+int DrmHwcLayer::InitFromDrmHwcLayer(DrmHwcLayer *src_layer,
+                                     Importer *importer) {
+  blending = src_layer->blending;
+  sf_handle = src_layer->sf_handle;
+  acquire_fence = -1;
+  display_frame = src_layer->display_frame;
+  alpha = src_layer->alpha;
+  source_crop = src_layer->source_crop;
+  transform = src_layer->transform;
+  return ImportBuffer(importer);
+}
+
 void DrmHwcLayer::SetSourceCrop(hwc_frect_t const &crop) {
   source_crop = crop;
 }
@@ -139,4 +168,4 @@
       transform |= DrmHwcTransform::kRotate90;
   }
 }
-}
+}  // namespace android
diff --git a/platform.cpp b/platform.cpp
index b6c39d0..af18124 100644
--- a/platform.cpp
+++ b/platform.cpp
@@ -16,8 +16,8 @@
 
 #define LOG_TAG "hwc-platform"
 
-#include "drmresources.h"
 #include "platform.h"
+#include "drmdevice.h"
 
 #include <log/log.h>
 
@@ -41,8 +41,8 @@
     std::vector<DrmPlane *> *primary_planes,
     std::vector<DrmPlane *> *overlay_planes) {
   std::vector<DrmCompositionPlane> composition;
-  std::vector<DrmPlane *> planes =
-      GetUsablePlanes(crtc, primary_planes, overlay_planes);
+  std::vector<DrmPlane *> planes = GetUsablePlanes(crtc, primary_planes,
+                                                   overlay_planes);
   if (planes.empty()) {
     ALOGE("Display %d has no usable planes", crtc->display());
     return std::make_tuple(-ENODEV, std::vector<DrmCompositionPlane>());
@@ -101,4 +101,4 @@
 
   return 0;
 }
-}
+}  // namespace android
diff --git a/platform.h b/platform.h
index 068499e..37c4647 100644
--- a/platform.h
+++ b/platform.h
@@ -28,7 +28,7 @@
 
 namespace android {
 
-class DrmResources;
+class DrmDevice;
 
 class Importer {
  public:
@@ -36,7 +36,7 @@
   }
 
   // Creates a platform-specific importer instance
-  static Importer *CreateInstance(DrmResources *drm);
+  static Importer *CreateInstance(DrmDevice *drm);
 
   // Imports the buffer referred to by handle into bo.
   //
@@ -88,7 +88,7 @@
   };
 
   // Creates a planner instance with platform-specific planning stages
-  static std::unique_ptr<Planner> CreateInstance(DrmResources *drm);
+  static std::unique_ptr<Planner> CreateInstance(DrmDevice *drm);
 
   // Takes a stack of layers and provisions hardware planes for them. If the
   // entire stack can't fit in hardware, FIXME
@@ -136,5 +136,5 @@
                       std::map<size_t, DrmHwcLayer *> &layers, DrmCrtc *crtc,
                       std::vector<DrmPlane *> *planes);
 };
-}
+}  // namespace android
 #endif
diff --git a/platformdrmgeneric.cpp b/platformdrmgeneric.cpp
index 7c4758d..24d0650 100644
--- a/platformdrmgeneric.cpp
+++ b/platformdrmgeneric.cpp
@@ -16,23 +16,23 @@
 
 #define LOG_TAG "hwc-platform-drm-generic"
 
-#include "drmresources.h"
-#include "platform.h"
 #include "platformdrmgeneric.h"
+#include "drmdevice.h"
+#include "platform.h"
 
 #include <drm/drm_fourcc.h>
 #include <xf86drm.h>
 #include <xf86drmMode.h>
 
-#include <log/log.h>
 #include <gralloc_handle.h>
 #include <hardware/gralloc.h>
+#include <log/log.h>
 
 namespace android {
 
 #ifdef USE_DRM_GENERIC_IMPORTER
 // static
-Importer *Importer::CreateInstance(DrmResources *drm) {
+Importer *Importer::CreateInstance(DrmDevice *drm) {
   DrmGenericImporter *importer = new DrmGenericImporter(drm);
   if (!importer)
     return NULL;
@@ -47,7 +47,7 @@
 }
 #endif
 
-DrmGenericImporter::DrmGenericImporter(DrmResources *drm) : drm_(drm) {
+DrmGenericImporter::DrmGenericImporter(DrmDevice *drm) : drm_(drm) {
 }
 
 DrmGenericImporter::~DrmGenericImporter() {
@@ -83,6 +83,24 @@
   }
 }
 
+uint32_t DrmGenericImporter::DrmFormatToBitsPerPixel(uint32_t drm_format) {
+  switch (drm_format) {
+    case DRM_FORMAT_ARGB8888:
+    case DRM_FORMAT_XBGR8888:
+    case DRM_FORMAT_ABGR8888:
+      return 32;
+    case DRM_FORMAT_BGR888:
+      return 24;
+    case DRM_FORMAT_BGR565:
+      return 16;
+    case DRM_FORMAT_YVU420:
+      return 12;
+    default:
+      ALOGE("Cannot convert hal format %u to bpp (returning 32)", drm_format);
+      return 32;
+  }
+}
+
 int DrmGenericImporter::ImportBuffer(buffer_handle_t handle, hwc_drm_bo_t *bo) {
   gralloc_handle_t *gr_handle = gralloc_handle(handle);
   if (!gr_handle)
@@ -98,8 +116,11 @@
   memset(bo, 0, sizeof(hwc_drm_bo_t));
   bo->width = gr_handle->width;
   bo->height = gr_handle->height;
+  bo->hal_format = gr_handle->format;
   bo->format = ConvertHalFormatToDrm(gr_handle->format);
   bo->usage = gr_handle->usage;
+  bo->pixel_stride = (gr_handle->stride * 8) /
+                     DrmFormatToBitsPerPixel(bo->format);
   bo->pitches[0] = gr_handle->stride;
   bo->gem_handles[0] = gem_handle;
   bo->offsets[0] = 0;
@@ -121,8 +142,8 @@
 
   struct drm_gem_close gem_close;
   memset(&gem_close, 0, sizeof(gem_close));
-  int num_gem_handles = sizeof(bo->gem_handles) / sizeof(bo->gem_handles[0]);
-  for (int i = 0; i < num_gem_handles; i++) {
+
+  for (int i = 0; i < HWC_DRM_BO_MAX_PLANES; i++) {
     if (!bo->gem_handles[i])
       continue;
 
@@ -131,7 +152,7 @@
     if (ret) {
       ALOGE("Failed to close gem handle %d %d", i, ret);
     } else {
-      for (int j = i + 1; j < num_gem_handles; j++)
+      for (int j = i + 1; j < HWC_DRM_BO_MAX_PLANES; j++)
         if (bo->gem_handles[j] == bo->gem_handles[i])
           bo->gem_handles[j] = 0;
       bo->gem_handles[i] = 0;
@@ -141,7 +162,7 @@
 }
 
 #ifdef USE_DRM_GENERIC_IMPORTER
-std::unique_ptr<Planner> Planner::CreateInstance(DrmResources *) {
+std::unique_ptr<Planner> Planner::CreateInstance(DrmDevice *) {
   std::unique_ptr<Planner> planner(new Planner);
   planner->AddStage<PlanStageGreedy>();
   return planner;
diff --git a/platformdrmgeneric.h b/platformdrmgeneric.h
index 0339e1e..d46e8b0 100644
--- a/platformdrmgeneric.h
+++ b/platformdrmgeneric.h
@@ -17,7 +17,7 @@
 #ifndef ANDROID_PLATFORM_DRM_GENERIC_H_
 #define ANDROID_PLATFORM_DRM_GENERIC_H_
 
-#include "drmresources.h"
+#include "drmdevice.h"
 #include "platform.h"
 
 #include <hardware/gralloc.h>
@@ -26,7 +26,7 @@
 
 class DrmGenericImporter : public Importer {
  public:
-  DrmGenericImporter(DrmResources *drm);
+  DrmGenericImporter(DrmDevice *drm);
   ~DrmGenericImporter() override;
 
   int Init();
@@ -35,12 +35,13 @@
   int ReleaseBuffer(hwc_drm_bo_t *bo) override;
 
   uint32_t ConvertHalFormatToDrm(uint32_t hal_format);
- private:
+  uint32_t DrmFormatToBitsPerPixel(uint32_t drm_format);
 
-  DrmResources *drm_;
+ private:
+  DrmDevice *drm_;
 
   const gralloc_module_t *gralloc_;
 };
-}
+}  // namespace android
 
 #endif
diff --git a/platformhisi.cpp b/platformhisi.cpp
index d4428d0..68bb5a7 100644
--- a/platformhisi.cpp
+++ b/platformhisi.cpp
@@ -16,26 +16,25 @@
 
 #define LOG_TAG "hwc-platform-hisi"
 
-#include "drmresources.h"
-#include "platform.h"
 #include "platformhisi.h"
-
+#include "drmdevice.h"
+#include "platform.h"
 
 #include <drm/drm_fourcc.h>
-#include <cinttypes>
 #include <stdatomic.h>
 #include <xf86drm.h>
 #include <xf86drmMode.h>
+#include <cinttypes>
 
-#include <log/log.h>
 #include <hardware/gralloc.h>
+#include <log/log.h>
 #include "gralloc_priv.h"
 
 #define MALI_ALIGN(value, base) (((value) + ((base)-1)) & ~((base)-1))
 
 namespace android {
 
-Importer *Importer::CreateInstance(DrmResources *drm) {
+Importer *Importer::CreateInstance(DrmDevice *drm) {
   HisiImporter *importer = new HisiImporter(drm);
   if (!importer)
     return NULL;
@@ -49,7 +48,8 @@
   return importer;
 }
 
-HisiImporter::HisiImporter(DrmResources *drm) : DrmGenericImporter(drm), drm_(drm) {
+HisiImporter::HisiImporter(DrmDevice *drm)
+    : DrmGenericImporter(drm), drm_(drm) {
 }
 
 HisiImporter::~HisiImporter() {
@@ -71,11 +71,18 @@
 }
 
 int HisiImporter::ImportBuffer(buffer_handle_t handle, hwc_drm_bo_t *bo) {
-  private_handle_t const *hnd =
-      reinterpret_cast<private_handle_t const *>(handle);
+  memset(bo, 0, sizeof(hwc_drm_bo_t));
+
+  private_handle_t const *hnd = reinterpret_cast<private_handle_t const *>(
+      handle);
   if (!hnd)
     return -EINVAL;
 
+  // We can't import these types of buffers, so pretend we did and rely on the
+  // planner to skip them when choosing layers for planes
+  if (!(hnd->usage & GRALLOC_USAGE_HW_FB))
+    return 0;
+
   uint32_t gem_handle;
   int ret = drmPrimeFDToHandle(drm_->fd(), hnd->share_fd, &gem_handle);
   if (ret) {
@@ -87,12 +94,12 @@
   if (fmt < 0)
     return fmt;
 
-  memset(bo, 0, sizeof(hwc_drm_bo_t));
   bo->width = hnd->width;
   bo->height = hnd->height;
+  bo->hal_format = hnd->req_format;
   bo->format = fmt;
   bo->usage = hnd->usage;
-
+  bo->pixel_stride = hnd->stride;
   bo->pitches[0] = hnd->byte_stride;
   bo->gem_handles[0] = gem_handle;
   bo->offsets[0] = 0;
@@ -132,9 +139,45 @@
   return ret;
 }
 
-std::unique_ptr<Planner> Planner::CreateInstance(DrmResources *) {
+class PlanStageHiSi : public Planner::PlanStage {
+ public:
+  int ProvisionPlanes(std::vector<DrmCompositionPlane> *composition,
+                      std::map<size_t, DrmHwcLayer *> &layers, DrmCrtc *crtc,
+                      std::vector<DrmPlane *> *planes) {
+    int layers_added = 0;
+    int initial_layers = layers.size();
+    // Fill up as many planes as we can with buffers that do not have HW_FB
+    // usage
+    for (auto i = layers.begin(); i != layers.end(); i = layers.erase(i)) {
+      if (!(i->second->gralloc_buffer_usage & GRALLOC_USAGE_HW_FB))
+        continue;
+
+      int ret = Emplace(composition, planes, DrmCompositionPlane::Type::kLayer,
+                        crtc, i->first);
+      layers_added++;
+      // We don't have any planes left
+      if (ret == -ENOENT)
+        break;
+      else if (ret)
+        ALOGE("Failed to emplace layer %zu, dropping it", i->first);
+    }
+    /*
+     * If we only have one layer, but we didn't emplace anything, we
+     * can run into trouble, as we might try to device composite a
+     * buffer we fake-imported, which can cause things to jamb up.
+     * So return an error in this case to ensure we force client
+     * compositing.
+     */
+    if (!layers_added && (initial_layers <= 1))
+      return -EINVAL;
+
+    return 0;
+  }
+};
+
+std::unique_ptr<Planner> Planner::CreateInstance(DrmDevice *) {
   std::unique_ptr<Planner> planner(new Planner);
-  planner->AddStage<PlanStageGreedy>();
+  planner->AddStage<PlanStageHiSi>();
   return planner;
 }
-}
+}  // namespace android
diff --git a/platformhisi.h b/platformhisi.h
index a098692..2b2d439 100644
--- a/platformhisi.h
+++ b/platformhisi.h
@@ -17,7 +17,7 @@
 #ifndef ANDROID_PLATFORM_HISI_H_
 #define ANDROID_PLATFORM_HISI_H_
 
-#include "drmresources.h"
+#include "drmdevice.h"
 #include "platform.h"
 #include "platformdrmgeneric.h"
 
@@ -29,7 +29,7 @@
 
 class HisiImporter : public DrmGenericImporter {
  public:
-  HisiImporter(DrmResources *drm);
+  HisiImporter(DrmDevice *drm);
   ~HisiImporter() override;
 
   int Init();
@@ -37,11 +37,10 @@
   int ImportBuffer(buffer_handle_t handle, hwc_drm_bo_t *bo) override;
 
  private:
-
-  DrmResources *drm_;
+  DrmDevice *drm_;
 
   const gralloc_module_t *gralloc_;
 };
-}
+}  // namespace android
 
 #endif
diff --git a/platformminigbm.cpp b/platformminigbm.cpp
index 8e3cc65..2040768 100644
--- a/platformminigbm.cpp
+++ b/platformminigbm.cpp
@@ -16,16 +16,16 @@
 
 #define LOG_TAG "hwc-platform-drm-minigbm"
 
+#include "platformminigbm.h"
 #include "drmresources.h"
 #include "platform.h"
-#include "platformminigbm.h"
 
 #include <drm/drm_fourcc.h>
 #include <xf86drm.h>
 #include <xf86drmMode.h>
 
-#include <log/log.h>
 #include <hardware/gralloc.h>
+#include <log/log.h>
 
 #include "cros_gralloc_handle.h"
 
@@ -45,7 +45,8 @@
   return importer;
 }
 
-DrmMinigbmImporter::DrmMinigbmImporter(DrmResources *drm) : DrmGenericImporter(drm), drm_(drm) {
+DrmMinigbmImporter::DrmMinigbmImporter(DrmResources *drm)
+    : DrmGenericImporter(drm), drm_(drm) {
 }
 
 DrmMinigbmImporter::~DrmMinigbmImporter() {
@@ -81,8 +82,10 @@
   memset(bo, 0, sizeof(hwc_drm_bo_t));
   bo->width = gr_handle->width;
   bo->height = gr_handle->height;
+  bo->hal_format = gr_handle->droid_format;
   bo->format = gr_handle->format;
   bo->usage = gr_handle->usage;
+  bo->pixel_stride = gr_handle->pixel_stride;
   bo->pitches[0] = gr_handle->strides[0];
   bo->offsets[0] = gr_handle->offsets[0];
   bo->gem_handles[0] = gem_handle;
@@ -103,4 +106,4 @@
   return planner;
 }
 
-}
+}  // namespace android
diff --git a/platformminigbm.h b/platformminigbm.h
index f25bf7b..f5807b9 100644
--- a/platformminigbm.h
+++ b/platformminigbm.h
@@ -40,6 +40,6 @@
   const gralloc_module_t *gralloc_;
 };
 
-}
+}  // namespace android
 
 #endif
diff --git a/resourcemanager.cpp b/resourcemanager.cpp
new file mode 100644
index 0000000..6e23561
--- /dev/null
+++ b/resourcemanager.cpp
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2018 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-resource-manager"
+
+#include "resourcemanager.h"
+
+#include <cutils/properties.h>
+#include <log/log.h>
+#include <sstream>
+#include <string>
+
+namespace android {
+
+ResourceManager::ResourceManager() : num_displays_(0), gralloc_(NULL) {
+}
+
+int ResourceManager::Init() {
+  char path_pattern[PROPERTY_VALUE_MAX];
+  // Could be a valid path or it can have at the end of it the wildcard %
+  // which means that it will try open all devices until an error is met.
+  int path_len = property_get("hwc.drm.device", path_pattern, "/dev/dri/card0");
+  int ret = 0;
+  if (path_pattern[path_len - 1] != '%') {
+    ret = AddDrmDevice(std::string(path_pattern));
+  } else {
+    path_pattern[path_len - 1] = '\0';
+    for (int idx = 0; !ret; ++idx) {
+      std::ostringstream path;
+      path << path_pattern << idx;
+      ret = AddDrmDevice(path.str());
+    }
+  }
+
+  if (!num_displays_) {
+    ALOGE("Failed to initialize any displays");
+    return ret ? -EINVAL : ret;
+  }
+
+  return hw_get_module(GRALLOC_HARDWARE_MODULE_ID,
+                       (const hw_module_t **)&gralloc_);
+}
+
+int ResourceManager::AddDrmDevice(std::string path) {
+  std::unique_ptr<DrmDevice> drm = std::make_unique<DrmDevice>();
+  int displays_added, ret;
+  std::tie(ret, displays_added) = drm->Init(path.c_str(), num_displays_);
+  if (ret)
+    return ret;
+  std::shared_ptr<Importer> importer;
+  importer.reset(Importer::CreateInstance(drm.get()));
+  if (!importer) {
+    ALOGE("Failed to create importer instance");
+    return -ENODEV;
+  }
+  importers_.push_back(importer);
+  drms_.push_back(std::move(drm));
+  num_displays_ += displays_added;
+  return ret;
+}
+
+DrmConnector *ResourceManager::AvailableWritebackConnector(int display) {
+  DrmDevice *drm_device = GetDrmDevice(display);
+  DrmConnector *writeback_conn = NULL;
+  if (drm_device) {
+    writeback_conn = drm_device->AvailableWritebackConnector(display);
+    if (writeback_conn)
+      return writeback_conn;
+  }
+  for (auto &drm : drms_) {
+    if (drm.get() == drm_device)
+      continue;
+    writeback_conn = drm->AvailableWritebackConnector(display);
+    if (writeback_conn)
+      return writeback_conn;
+  }
+  return writeback_conn;
+}
+
+DrmDevice *ResourceManager::GetDrmDevice(int display) {
+  for (auto &drm : drms_) {
+    if (drm->HandlesDisplay(display))
+      return drm.get();
+  }
+  return NULL;
+}
+
+std::shared_ptr<Importer> ResourceManager::GetImporter(int display) {
+  for (unsigned int i = 0; i < drms_.size(); i++) {
+    if (drms_[i]->HandlesDisplay(display))
+      return importers_[i];
+  }
+  return NULL;
+}
+
+const gralloc_module_t *ResourceManager::gralloc() {
+  return gralloc_;
+}
+}  // namespace android
diff --git a/resourcemanager.h b/resourcemanager.h
new file mode 100644
index 0000000..463739b
--- /dev/null
+++ b/resourcemanager.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2018 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 RESOURCEMANAGER_H
+#define RESOURCEMANAGER_H
+
+#include "drmdevice.h"
+#include "platform.h"
+
+#include <string.h>
+
+namespace android {
+
+class ResourceManager {
+ public:
+  ResourceManager();
+  ResourceManager(const ResourceManager &) = delete;
+  ResourceManager &operator=(const ResourceManager &) = delete;
+  int Init();
+  DrmDevice *GetDrmDevice(int display);
+  std::shared_ptr<Importer> GetImporter(int display);
+  const gralloc_module_t *gralloc();
+  DrmConnector *AvailableWritebackConnector(int display);
+
+ private:
+  int AddDrmDevice(std::string path);
+
+  int num_displays_;
+  std::vector<std::unique_ptr<DrmDevice>> drms_;
+  std::vector<std::shared_ptr<Importer>> importers_;
+  const gralloc_module_t *gralloc_;
+};
+}  // namespace android
+
+#endif  // RESOURCEMANAGER_H
diff --git a/vsyncworker.cpp b/vsyncworker.cpp
index 6ac016d..d022887 100644
--- a/vsyncworker.cpp
+++ b/vsyncworker.cpp
@@ -16,18 +16,18 @@
 
 #define LOG_TAG "hwc-vsync-worker"
 
-#include "drmresources.h"
 #include "vsyncworker.h"
+#include "drmdevice.h"
 #include "worker.h"
 
-#include <map>
 #include <stdlib.h>
 #include <time.h>
 #include <xf86drm.h>
 #include <xf86drmMode.h>
+#include <map>
 
-#include <log/log.h>
 #include <hardware/hardware.h>
+#include <log/log.h>
 
 namespace android {
 
@@ -42,7 +42,7 @@
 VSyncWorker::~VSyncWorker() {
 }
 
-int VSyncWorker::Init(DrmResources *drm, int display) {
+int VSyncWorker::Init(DrmDevice *drm, int display) {
   drm_ = drm;
   display_ = display;
 
@@ -99,8 +99,9 @@
     ALOGW("Vsync worker active with conn=%p refresh=%f\n", conn,
           conn ? conn->active_mode().v_refresh() : 0.0f);
 
-  int64_t phased_timestamp = GetPhasedVSync(
-      kOneSecondNs / refresh, vsync.tv_sec * kOneSecondNs + vsync.tv_nsec);
+  int64_t phased_timestamp = GetPhasedVSync(kOneSecondNs / refresh,
+                                            vsync.tv_sec * kOneSecondNs +
+                                                vsync.tv_nsec);
   vsync.tv_sec = phased_timestamp / kOneSecondNs;
   vsync.tv_nsec = phased_timestamp - (vsync.tv_sec * kOneSecondNs);
   do {
@@ -172,4 +173,4 @@
     callback->Callback(display, timestamp);
   last_timestamp_ = timestamp;
 }
-}
+}  // namespace android
diff --git a/vsyncworker.h b/vsyncworker.h
index 787152e..b2bca9d 100644
--- a/vsyncworker.h
+++ b/vsyncworker.h
@@ -17,11 +17,11 @@
 #ifndef ANDROID_EVENT_WORKER_H_
 #define ANDROID_EVENT_WORKER_H_
 
-#include "drmresources.h"
+#include "drmdevice.h"
 #include "worker.h"
 
-#include <map>
 #include <stdint.h>
+#include <map>
 
 #include <hardware/hardware.h>
 #include <hardware/hwcomposer.h>
@@ -40,7 +40,7 @@
   VSyncWorker();
   ~VSyncWorker() override;
 
-  int Init(DrmResources *drm, int display);
+  int Init(DrmDevice *drm, int display);
   void RegisterCallback(std::shared_ptr<VsyncCallback> callback);
 
   void VSyncControl(bool enabled);
@@ -52,7 +52,7 @@
   int64_t GetPhasedVSync(int64_t frame_ns, int64_t current);
   int SyntheticWaitVBlank(int64_t *timestamp);
 
-  DrmResources *drm_;
+  DrmDevice *drm_;
 
   // shared_ptr since we need to use this outside of the thread lock (to
   // actually call the hook) and we don't want the memory freed until we're
@@ -63,6 +63,6 @@
   bool enabled_;
   int64_t last_timestamp_;
 };
-}
+}  // namespace android
 
 #endif
diff --git a/worker.cpp b/worker.cpp
index da6c580..0dceb16 100644
--- a/worker.cpp
+++ b/worker.cpp
@@ -91,4 +91,4 @@
     Routine();
   }
 }
-}
+}  // namespace android
diff --git a/worker.h b/worker.h
index 8f6295b..7909038 100644
--- a/worker.h
+++ b/worker.h
@@ -77,5 +77,5 @@
   bool exit_;
   bool initialized_;
 };
-}
+}  // namespace android
 #endif