merge in mnc-dr-release history after reset to mnc-dr-dev
diff --git a/drm_hwcomposer.h b/drm_hwcomposer.h
index cebdbee..fdf389b 100644
--- a/drm_hwcomposer.h
+++ b/drm_hwcomposer.h
@@ -22,6 +22,7 @@
 
 #include <hardware/hardware.h>
 #include <hardware/hwcomposer.h>
+#include "seperate_rects.h"
 
 struct hwc_import_context;
 
@@ -71,4 +72,202 @@
 bool hwc_import_bo_release(int fd, struct hwc_import_context *ctx,
                            struct hwc_drm_bo *bo);
 
+namespace android {
+
+class Importer;
+
+class UniqueFd {
+ public:
+  UniqueFd() = default;
+  UniqueFd(int fd) : fd_(fd) {
+  }
+  UniqueFd(UniqueFd &&rhs) {
+    fd_ = rhs.fd_;
+    rhs.fd_ = -1;
+  }
+
+  UniqueFd &operator=(UniqueFd &&rhs) {
+    Set(rhs.Release());
+    return *this;
+  }
+
+  ~UniqueFd() {
+    if (fd_ >= 0)
+      close(fd_);
+  }
+
+  int Release() {
+    int old_fd = fd_;
+    fd_ = -1;
+    return old_fd;
+  }
+
+  int Set(int fd) {
+    if (fd_ >= 0)
+      close(fd_);
+    fd_ = fd;
+    return fd_;
+  }
+
+  void Close() {
+    if (fd_ >= 0)
+      close(fd_);
+    fd_ = -1;
+  }
+
+  int get() {
+    return fd_;
+  }
+
+ private:
+  int fd_ = -1;
+};
+
+struct OutputFd {
+  OutputFd() = default;
+  OutputFd(int *fd) : fd_(fd) {
+  }
+  OutputFd(OutputFd &&rhs) {
+    fd_ = rhs.fd_;
+    rhs.fd_ = NULL;
+  }
+
+  OutputFd &operator=(OutputFd &&rhs);
+
+  int Set(int fd) {
+    if (*fd_ >= 0)
+      close(*fd_);
+    *fd_ = fd;
+    return fd;
+  }
+
+  int get() {
+    return *fd_;
+  }
+
+ private:
+  int *fd_ = NULL;
+};
+
+class DrmHwcBuffer {
+ public:
+  DrmHwcBuffer() = default;
+  DrmHwcBuffer(const hwc_drm_bo &bo, Importer *importer)
+      : bo_(bo), importer_(importer) {
+  }
+  DrmHwcBuffer(DrmHwcBuffer &&rhs) : bo_(rhs.bo_), importer_(rhs.importer_) {
+    rhs.importer_ = NULL;
+  }
+
+  ~DrmHwcBuffer() {
+    Clear();
+  }
+
+  DrmHwcBuffer &operator=(DrmHwcBuffer &&rhs) {
+    Clear();
+    importer_ = rhs.importer_;
+    rhs.importer_ = NULL;
+    bo_ = rhs.bo_;
+    return *this;
+  }
+
+  operator bool() {
+    return importer_ != NULL;
+  }
+
+  hwc_drm_bo *operator->();
+
+  void Clear();
+
+  int ImportBuffer(buffer_handle_t handle, Importer *importer);
+
+ private:
+  hwc_drm_bo bo_;
+  Importer *importer_ = NULL;
+};
+
+class DrmHwcNativeHandle {
+ public:
+  DrmHwcNativeHandle() = default;
+
+  DrmHwcNativeHandle(const gralloc_module_t *gralloc, native_handle_t *handle)
+      : gralloc_(gralloc), handle_(handle) {
+  }
+
+  DrmHwcNativeHandle(DrmHwcNativeHandle &&rhs) {
+    gralloc_ = rhs.gralloc_;
+    rhs.gralloc_ = NULL;
+    handle_ = rhs.handle_;
+    rhs.handle_ = NULL;
+  }
+
+  ~DrmHwcNativeHandle();
+
+  DrmHwcNativeHandle &operator=(DrmHwcNativeHandle &&rhs) {
+    Clear();
+    gralloc_ = rhs.gralloc_;
+    rhs.gralloc_ = NULL;
+    handle_ = rhs.handle_;
+    rhs.handle_ = NULL;
+    return *this;
+  }
+
+  int CopyBufferHandle(buffer_handle_t handle, const gralloc_module_t *gralloc);
+
+  void Clear();
+
+  buffer_handle_t get() const {
+    return handle_;
+  }
+
+ private:
+  const gralloc_module_t *gralloc_ = NULL;
+  native_handle_t *handle_ = NULL;
+};
+
+template <typename T>
+using DrmHwcRect = seperate_rects::Rect<T>;
+
+enum class DrmHwcTransform : uint32_t {
+  kIdentity = 0,
+  kFlipH = HWC_TRANSFORM_FLIP_H,
+  kFlipV = HWC_TRANSFORM_FLIP_V,
+  kRotate90 = HWC_TRANSFORM_ROT_90,
+  kRotate180 = HWC_TRANSFORM_ROT_180,
+  kRotate270 = HWC_TRANSFORM_ROT_270,
+};
+
+enum class DrmHwcBlending : int32_t {
+  kNone = HWC_BLENDING_NONE,
+  kPreMult = HWC_BLENDING_PREMULT,
+  kCoverage = HWC_BLENDING_COVERAGE,
+};
+
+struct DrmHwcLayer {
+  buffer_handle_t sf_handle = NULL;
+  DrmHwcBuffer buffer;
+  DrmHwcNativeHandle handle;
+  DrmHwcTransform transform = DrmHwcTransform::kIdentity;
+  DrmHwcBlending blending = DrmHwcBlending::kNone;
+  uint8_t alpha = 0xff;
+  DrmHwcRect<float> source_crop;
+  DrmHwcRect<int> display_frame;
+  std::vector<DrmHwcRect<int>> source_damage;
+
+  UniqueFd acquire_fence;
+  OutputFd release_fence;
+
+  DrmHwcLayer() = default;
+  DrmHwcLayer(DrmHwcLayer &&rhs) = default;
+
+  int InitFromHwcLayer(hwc_layer_1_t *sf_layer, Importer *importer,
+                       const gralloc_module_t *gralloc);
+};
+
+struct DrmHwcDisplayContents {
+  OutputFd retire_fence;
+  std::vector<DrmHwcLayer> layers;
+};
+}
+
 #endif
diff --git a/drmcomposition.cpp b/drmcomposition.cpp
index 864c5e5..634b0bb 100644
--- a/drmcomposition.cpp
+++ b/drmcomposition.cpp
@@ -69,15 +69,15 @@
 }
 
 int DrmComposition::SetLayers(size_t num_displays,
-                              const DrmCompositionDisplayLayersMap *maps) {
+                              DrmCompositionDisplayLayersMap *maps) {
   int ret = 0;
   for (size_t display_index = 0; display_index < num_displays;
        display_index++) {
-    const DrmCompositionDisplayLayersMap &map = maps[display_index];
+    DrmCompositionDisplayLayersMap &map = maps[display_index];
     int display = map.display;
 
     ret = composition_map_[display]->SetLayers(
-        map.layers, map.num_layers, map.layer_indices, &primary_planes_,
+        map.layers.data(), map.layers.size(), &primary_planes_,
         &overlay_planes_);
     if (ret)
       return ret;
diff --git a/drmcomposition.h b/drmcomposition.h
index 426ced0..a5d9cf1 100644
--- a/drmcomposition.h
+++ b/drmcomposition.h
@@ -22,7 +22,6 @@
 #include "drmplane.h"
 #include "importer.h"
 
-#include <deque>
 #include <map>
 #include <vector>
 
@@ -33,9 +32,11 @@
 
 struct DrmCompositionDisplayLayersMap {
   int display;
-  size_t num_layers;
-  hwc_layer_1_t *layers;
-  size_t *layer_indices;
+  std::vector<DrmHwcLayer> layers;
+
+  DrmCompositionDisplayLayersMap() = default;
+  DrmCompositionDisplayLayersMap(DrmCompositionDisplayLayersMap &&rhs) =
+      default;
 };
 
 class DrmComposition {
@@ -44,8 +45,7 @@
 
   int Init(uint64_t frame_no);
 
-  int SetLayers(size_t num_displays,
-                const DrmCompositionDisplayLayersMap *maps);
+  int SetLayers(size_t num_displays, DrmCompositionDisplayLayersMap *maps);
   int SetDpmsMode(int display, uint32_t dpms_mode);
 
   std::unique_ptr<DrmDisplayComposition> TakeDisplayComposition(int display);
diff --git a/drmdisplaycomposition.cpp b/drmdisplaycomposition.cpp
index c1848e0..457fb5a 100644
--- a/drmdisplaycomposition.cpp
+++ b/drmdisplaycomposition.cpp
@@ -30,39 +30,18 @@
 
 namespace android {
 
-static native_handle_t *dup_buffer_handle(buffer_handle_t handle) {
-  native_handle_t *new_handle =
-      native_handle_create(handle->numFds, handle->numInts);
-  if (new_handle == NULL)
-    return NULL;
-
-  const int *old_data = handle->data;
-  int *new_data = new_handle->data;
-  for (int i = 0; i < handle->numFds; i++) {
-    *new_data = dup(*old_data);
-    old_data++;
-    new_data++;
-  }
-  memcpy(new_data, old_data, sizeof(int) * handle->numInts);
-
-  return new_handle;
-}
-
-static void free_buffer_handle(native_handle_t *handle) {
-  int ret = native_handle_close(handle);
-  if (ret)
-    ALOGE("Failed to close native handle %d", ret);
-  ret = native_handle_delete(handle);
-  if (ret)
-    ALOGE("Failed to delete native handle %d", ret);
-}
-
-DrmCompositionLayer::DrmCompositionLayer()
-    : crtc(NULL), plane(NULL), handle(NULL) {
-  memset(&layer, 0, sizeof(layer));
-  layer.releaseFenceFd = -1;
-  layer.acquireFenceFd = -1;
-  memset(&bo, 0, sizeof(bo));
+DrmCompositionLayer::DrmCompositionLayer(DrmCrtc *crtc, DrmHwcLayer &&l)
+    : crtc(crtc),
+      sf_handle(l.sf_handle),
+      buffer(std::move(l.buffer)),
+      handle(std::move(l.handle)),
+      transform(l.transform),
+      blending(l.blending),
+      alpha(l.alpha),
+      source_crop(l.source_crop),
+      display_frame(l.display_frame),
+      source_damage(l.source_damage),
+      acquire_fence(std::move(l.acquire_fence)) {
 }
 
 DrmDisplayComposition::DrmDisplayComposition()
@@ -79,20 +58,6 @@
 }
 
 DrmDisplayComposition::~DrmDisplayComposition() {
-  for (DrmCompositionLayerVector_t::iterator iter = layers_.begin();
-       iter != layers_.end(); ++iter) {
-    if (importer_ && iter->bo.fb_id)
-      importer_->ReleaseBuffer(&iter->bo);
-
-    if (iter->handle) {
-      gralloc_->unregisterBuffer(gralloc_, iter->handle);
-      free_buffer_handle(iter->handle);
-    }
-
-    if (iter->layer.acquireFenceFd >= 0)
-      close(iter->layer.acquireFenceFd);
-  }
-
   if (timeline_fd_ >= 0) {
     FinishComposition();
     close(timeline_fd_);
@@ -103,18 +68,11 @@
 int DrmDisplayComposition::Init(DrmResources *drm, DrmCrtc *crtc,
                                 Importer *importer, uint64_t frame_no) {
   drm_ = drm;
-  crtc_ = crtc; // Can be NULL if we haven't modeset yet
+  crtc_ = crtc;  // Can be NULL if we haven't modeset yet
   importer_ = importer;
   frame_no_ = frame_no;
 
-  int ret = hw_get_module(GRALLOC_HARDWARE_MODULE_ID,
-                          (const hw_module_t **)&gralloc_);
-  if (ret) {
-    ALOGE("Failed to open gralloc module %d", ret);
-    return ret;
-  }
-
-  ret = sw_sync_timeline_create();
+  int ret = sw_sync_timeline_create();
   if (ret < 0) {
     ALOGE("Failed to create sw sync timeline %d", ret);
     return ret;
@@ -170,8 +128,7 @@
   return ret;
 }
 
-int DrmDisplayComposition::SetLayers(hwc_layer_1_t *layers, size_t num_layers,
-                                     size_t *layer_indices,
+int DrmDisplayComposition::SetLayers(DrmHwcLayer *layers, size_t num_layers,
                                      std::vector<DrmPlane *> *primary_planes,
                                      std::vector<DrmPlane *> *overlay_planes) {
   int ret = 0;
@@ -179,32 +136,10 @@
     return -EINVAL;
 
   for (size_t layer_index = 0; layer_index < num_layers; layer_index++) {
-    hwc_layer_1_t *layer = &layers[layer_indices[layer_index]];
+    DrmHwcLayer *layer = &layers[layer_index];
 
-    native_handle_t *handle_copy = dup_buffer_handle(layer->handle);
-    if (handle_copy == NULL) {
-      ALOGE("Failed to duplicate handle");
-      return -ENOMEM;
-    }
-
-    int ret = gralloc_->registerBuffer(gralloc_, handle_copy);
-    if (ret) {
-      ALOGE("Failed to register buffer handle %d", ret);
-      free_buffer_handle(handle_copy);
-      return ret;
-    }
-
-    layers_.emplace_back();
-    DrmCompositionLayer_t *c_layer = &layers_.back();
-    c_layer->layer = *layer;
-    c_layer->handle = handle_copy;
-    c_layer->crtc = crtc_;
-
-    ret = importer_->ImportBuffer(layer->handle, &c_layer->bo);
-    if (ret) {
-      ALOGE("Failed to import handle of layer %d", ret);
-      goto fail;
-    }
+    layers_.emplace_back(crtc_, std::move(*layer));
+    DrmCompositionLayer *c_layer = &layers_.back();
 
     if (pre_composition_layer_index_ == -1) {
       c_layer->plane = TakePlane(crtc_, primary_planes, overlay_planes);
@@ -218,27 +153,19 @@
         layers_.emplace_back();
         // c_layer's address might have changed when we resized the vector
         c_layer = &layers_[layers_.size() - 2];
-        DrmCompositionLayer_t &pre_comp_layer = layers_.back();
+        DrmCompositionLayer &pre_comp_layer = layers_.back();
         pre_comp_layer.crtc = crtc_;
-        hwc_layer_1_t &pre_comp_output_layer = pre_comp_layer.layer;
-        memset(&pre_comp_output_layer, 0, sizeof(pre_comp_output_layer));
-        pre_comp_output_layer.compositionType = HWC_OVERLAY;
-        pre_comp_output_layer.acquireFenceFd = -1;
-        pre_comp_output_layer.releaseFenceFd = -1;
-        pre_comp_output_layer.planeAlpha = 0xff;
-        pre_comp_output_layer.visibleRegionScreen.numRects = 1;
-        pre_comp_output_layer.visibleRegionScreen.rects =
-            &pre_comp_output_layer.displayFrame;
 
         pre_composition_layer_index_ = layers_.size() - 1;
 
         // This is all to fix up the previous layer, which has now become part
         // of the set of pre-composition layers because we are stealing its
         // plane.
-        DrmCompositionLayer_t &last_c_layer = layers_[layers_.size() - 3];
+        DrmCompositionLayer &last_c_layer = layers_[layers_.size() - 3];
         std::swap(pre_comp_layer.plane, last_c_layer.plane);
-        hwc_layer_1_t *last_layer = &layers[layer_indices[layer_index - 1]];
-        ret = last_layer->releaseFenceFd = CreateNextTimelineFence();
+        OutputFd &last_release_fence = layers[layer_index - 1].release_fence;
+        last_release_fence.Set(CreateNextTimelineFence());
+        ret = last_release_fence.get();
         if (ret < 0) {
           ALOGE("Could not create release fence %d", ret);
           goto fail;
@@ -249,7 +176,8 @@
     if (c_layer->plane == NULL) {
       // Layers to be pre composited all get the earliest release fences as they
       // will get released soonest.
-      ret = layer->releaseFenceFd = CreateNextTimelineFence();
+      layer->release_fence.Set(CreateNextTimelineFence());
+      ret = layer->release_fence.get();
       if (ret < 0) {
         ALOGE("Could not create release fence %d", ret);
         goto fail;
@@ -260,22 +188,17 @@
   timeline_pre_comp_done_ = timeline_;
 
   for (size_t layer_index = 0; layer_index < num_layers; layer_index++) {
-    hwc_layer_1_t *layer = &layers[layer_indices[layer_index]];
-    if (layer->releaseFenceFd >= 0)
+    DrmHwcLayer *layer = &layers[layer_index];
+    if (layer->release_fence.get() >= 0)
       continue;
 
-    ret = layer->releaseFenceFd = CreateNextTimelineFence();
+    ret = layer->release_fence.Set(CreateNextTimelineFence());
     if (ret < 0) {
       ALOGE("Could not create release fence %d", ret);
       goto fail;
     }
   }
 
-  for (size_t layer_index = 0; layer_index < num_layers; layer_index++) {
-    hwc_layer_1_t *layer = &layers[layer_indices[layer_index]];
-    layer->acquireFenceFd = -1;  // We own this now
-  }
-
   type_ = DRM_COMPOSITION_TYPE_FRAME;
   return 0;
 
@@ -283,13 +206,7 @@
 
   for (size_t c_layer_index = 0; c_layer_index < layers_.size();
        c_layer_index++) {
-    DrmCompositionLayer_t &c_layer = layers_[c_layer_index];
-    if (c_layer.handle) {
-      gralloc_->unregisterBuffer(gralloc_, c_layer.handle);
-      free_buffer_handle(c_layer.handle);
-    }
-    if (c_layer.bo.fb_id)
-      importer_->ReleaseBuffer(&c_layer.bo);
+    DrmCompositionLayer &c_layer = layers_[c_layer_index];
     if (c_layer.plane != NULL) {
       std::vector<DrmPlane *> *return_to =
           (c_layer.plane->type() == DRM_PLANE_TYPE_PRIMARY) ? primary_planes
@@ -297,15 +214,9 @@
       return_to->insert(return_to->begin() + c_layer_index, c_layer.plane);
     }
   }
+
   layers_.clear();
 
-  for (size_t layer_index = 0; layer_index < num_layers; layer_index++) {
-    hwc_layer_1_t *layer = &layers[layer_indices[layer_index]];
-    if (layer->releaseFenceFd >= 0) {
-      close(layer->releaseFenceFd);
-      layer->releaseFenceFd = -1;
-    }
-  }
   sw_sync_timeline_inc(timeline_fd_, timeline_ - timeline_current_);
 
   timeline_ = timeline_current_;
@@ -322,35 +233,16 @@
 
 int DrmDisplayComposition::AddPlaneDisable(DrmPlane *plane) {
   layers_.emplace_back();
-  DrmCompositionLayer_t &c_layer = layers_.back();
+  DrmCompositionLayer &c_layer = layers_.back();
   c_layer.crtc = NULL;
   c_layer.plane = plane;
   return 0;
 }
 
 void DrmDisplayComposition::RemoveNoPlaneLayers() {
-  for (auto &comp_layer : layers_) {
-    if (comp_layer.plane != NULL)
-      continue;
-
-    if (importer_ && comp_layer.bo.fb_id) {
-      importer_->ReleaseBuffer(&comp_layer.bo);
-    }
-
-    if (comp_layer.handle) {
-      gralloc_->unregisterBuffer(gralloc_, comp_layer.handle);
-      free_buffer_handle(comp_layer.handle);
-    }
-
-    if (comp_layer.layer.acquireFenceFd >= 0) {
-      close(comp_layer.layer.acquireFenceFd);
-      comp_layer.layer.acquireFenceFd = -1;
-    }
-  }
-
   layers_.erase(
       std::remove_if(layers_.begin(), layers_.end(),
-                     [](DrmCompositionLayer_t &l) { return l.plane == NULL; }),
+                     [](DrmCompositionLayer &l) { return l.plane == NULL; }),
       layers_.end());
 }
 
@@ -362,7 +254,8 @@
   return IncreaseTimelineToPoint(timeline_);
 }
 
-DrmCompositionLayerVector_t *DrmDisplayComposition::GetCompositionLayers() {
+std::vector<DrmCompositionLayer>
+    *DrmDisplayComposition::GetCompositionLayers() {
   return &layers_;
 }
 
diff --git a/drmdisplaycomposition.h b/drmdisplaycomposition.h
index be4ecef..06784f1 100644
--- a/drmdisplaycomposition.h
+++ b/drmdisplaycomposition.h
@@ -37,16 +37,32 @@
   DRM_COMPOSITION_TYPE_DPMS,
 };
 
-typedef struct DrmCompositionLayer {
-  DrmCompositionLayer();
+struct DrmCompositionLayer {
+  DrmCrtc *crtc = NULL;
+  DrmPlane *plane = NULL;
 
-  hwc_layer_1_t layer;
-  hwc_drm_bo_t bo;
-  DrmCrtc *crtc;
-  DrmPlane *plane;
-  native_handle_t *handle;
-} DrmCompositionLayer_t;
-typedef std::vector<DrmCompositionLayer_t> DrmCompositionLayerVector_t;
+  buffer_handle_t sf_handle = NULL;
+  DrmHwcBuffer buffer;
+  DrmHwcNativeHandle handle;
+  DrmHwcTransform transform = DrmHwcTransform::kIdentity;
+  DrmHwcBlending blending = DrmHwcBlending::kNone;
+  uint8_t alpha = 0xff;
+  DrmHwcRect<float> source_crop;
+  DrmHwcRect<int> display_frame;
+  std::vector<DrmHwcRect<int>> source_damage;
+
+  UniqueFd acquire_fence;
+
+  DrmCompositionLayer() = default;
+  DrmCompositionLayer(DrmCrtc *crtc, DrmHwcLayer &&l);
+  DrmCompositionLayer(DrmCompositionLayer &&l) = default;
+
+  DrmCompositionLayer &operator=(DrmCompositionLayer &&l) = default;
+
+  buffer_handle_t get_usable_handle() const {
+    return handle.get() != NULL ? handle.get() : sf_handle;
+  }
+};
 
 class DrmDisplayComposition {
  public:
@@ -58,7 +74,7 @@
 
   DrmCompositionType type() const;
 
-  int SetLayers(hwc_layer_1_t *layers, size_t num_layers, size_t *layer_indices,
+  int SetLayers(DrmHwcLayer *layers, size_t num_layers,
                 std::vector<DrmPlane *> *primary_planes,
                 std::vector<DrmPlane *> *overlay_planes);
   int AddPlaneDisable(DrmPlane *plane);
@@ -68,7 +84,7 @@
   int SignalPreCompositionDone();
   int FinishComposition();
 
-  DrmCompositionLayerVector_t *GetCompositionLayers();
+  std::vector<DrmCompositionLayer> *GetCompositionLayers();
   int pre_composition_layer_index() const;
   uint32_t dpms_mode() const;
 
@@ -97,7 +113,7 @@
   int timeline_current_;
   int timeline_pre_comp_done_;
 
-  DrmCompositionLayerVector_t layers_;
+  std::vector<DrmCompositionLayer> layers_;
   int pre_composition_layer_index_;
   uint32_t dpms_mode_;
 
diff --git a/drmdisplaycompositor.cpp b/drmdisplaycompositor.cpp
index b293681..6ee145f 100644
--- a/drmdisplaycompositor.cpp
+++ b/drmdisplaycompositor.cpp
@@ -146,7 +146,7 @@
 }
 
 static bool drm_composition_layer_has_plane(
-    const DrmCompositionLayer_t &comp_layer) {
+    const DrmCompositionLayer &comp_layer) {
   if (comp_layer.plane != NULL)
     if (comp_layer.plane->type() == DRM_PLANE_TYPE_OVERLAY ||
         comp_layer.plane->type() == DRM_PLANE_TYPE_PRIMARY)
@@ -155,14 +155,15 @@
 }
 
 static bool drm_composition_layer_has_no_plane(
-    const DrmCompositionLayer_t &comp_layer) {
+    const DrmCompositionLayer &comp_layer) {
   return comp_layer.plane == NULL;
 }
 
 int DrmDisplayCompositor::ApplyPreComposite(
     DrmDisplayComposition *display_comp) {
   int ret = 0;
-  DrmCompositionLayerVector_t *layers = display_comp->GetCompositionLayers();
+  std::vector<DrmCompositionLayer> *layers =
+      display_comp->GetCompositionLayers();
 
   DrmConnector *connector = drm_->GetConnectorForDisplay(display_);
   if (connector == NULL) {
@@ -185,12 +186,10 @@
     return -ENOMEM;
   }
 
-  std::vector<hwc_layer_1_t> pre_comp_layers;
+  std::vector<DrmCompositionLayer> pre_comp_layers;
   for (auto &comp_layer : *layers) {
     if (comp_layer.plane == NULL) {
-      pre_comp_layers.push_back(comp_layer.layer);
-      pre_comp_layers.back().handle = comp_layer.handle;
-      comp_layer.layer.acquireFenceFd = -1;
+      pre_comp_layers.emplace_back(std::move(comp_layer));
     }
   }
 
@@ -198,36 +197,26 @@
                                    pre_comp_layers.size(), fb.buffer());
   pre_compositor_->Finish();
 
-  for (auto &pre_comp_layer : pre_comp_layers) {
-    if (pre_comp_layer.acquireFenceFd >= 0) {
-      close(pre_comp_layer.acquireFenceFd);
-      pre_comp_layer.acquireFenceFd = -1;
-    }
-  }
-
   if (ret) {
     ALOGE("Failed to composite layers");
     return ret;
   }
 
-  DrmCompositionLayer_t &pre_comp_layer =
+  DrmCompositionLayer &pre_comp_layer =
       layers->at(display_comp->pre_composition_layer_index());
-  ret = display_comp->importer()->ImportBuffer(fb.buffer()->handle,
-                                               &pre_comp_layer.bo);
+  ret = pre_comp_layer.buffer.ImportBuffer(fb.buffer()->handle,
+                                           display_comp->importer());
   if (ret) {
     ALOGE("Failed to import handle of layer %d", ret);
     return ret;
   }
-  hwc_layer_1_t &pre_comp_output_layer = pre_comp_layer.layer;
-  pre_comp_output_layer.handle = fb.buffer()->handle;
-  pre_comp_output_layer.visibleRegionScreen.rects =
-      &pre_comp_output_layer.displayFrame;
-  pre_comp_output_layer.sourceCropf.right =
-      pre_comp_output_layer.displayFrame.right = fb.buffer()->getWidth();
-  pre_comp_output_layer.sourceCropf.bottom =
-      pre_comp_output_layer.displayFrame.bottom = fb.buffer()->getHeight();
+  pre_comp_layer.source_crop = DrmHwcRect<float>(0, 0, fb.buffer()->getWidth(),
+                                                 fb.buffer()->getHeight());
+  pre_comp_layer.display_frame =
+      DrmHwcRect<int>(0, 0, fb.buffer()->getWidth(), fb.buffer()->getHeight());
 
-  fb.set_release_fence_fd(pre_comp_output_layer.releaseFenceFd);
+  // TODO(zachr) get a release fence
+  // fb.set_release_fence_fd(pre_comp_layer.release_fence.Release());
   framebuffer_index_ = (framebuffer_index_ + 1) % DRM_DISPLAY_BUFFERS;
 
   display_comp->RemoveNoPlaneLayers();
@@ -250,24 +239,22 @@
     return -ENOMEM;
   }
 
-  DrmCompositionLayerVector_t *layers = display_comp->GetCompositionLayers();
-  for (DrmCompositionLayerVector_t::iterator iter = layers->begin();
-       iter != layers->end(); ++iter) {
-    hwc_layer_1_t *layer = &iter->layer;
-
-    if (layer->acquireFenceFd >= 0) {
-      ret = sync_wait(layer->acquireFenceFd, -1);
+  std::vector<DrmCompositionLayer> *layers =
+      display_comp->GetCompositionLayers();
+  for (DrmCompositionLayer &layer : *layers) {
+    int acquire_fence = layer.acquire_fence.get();
+    if (acquire_fence >= 0) {
+      ret = sync_wait(acquire_fence, -1);
       if (ret) {
-        ALOGE("Failed to wait for acquire %d/%d", layer->acquireFenceFd, ret);
+        ALOGE("Failed to wait for acquire %d/%d", acquire_fence, ret);
         drmModePropertySetFree(pset);
         return ret;
       }
-      close(layer->acquireFenceFd);
-      layer->acquireFenceFd = -1;
+      layer.acquire_fence.Close();
     }
 
-    DrmPlane *plane = iter->plane;
-    DrmCrtc *crtc = iter->crtc;
+    DrmPlane *plane = layer.plane;
+    DrmCrtc *crtc = layer.crtc;
 
     // Disable the plane if there's no crtc
     if (!crtc) {
@@ -282,28 +269,34 @@
       continue;
     }
 
+    if (!layer.buffer) {
+      ALOGE("Expected a valid framebuffer for pset");
+      ret = -EINVAL;
+      break;
+    }
+
     uint64_t rotation;
-    switch (layer->transform) {
-      case HWC_TRANSFORM_FLIP_H:
+    switch (layer.transform) {
+      case DrmHwcTransform::kFlipH:
         rotation = 1 << DRM_REFLECT_X;
         break;
-      case HWC_TRANSFORM_FLIP_V:
+      case DrmHwcTransform::kFlipV:
         rotation = 1 << DRM_REFLECT_Y;
         break;
-      case HWC_TRANSFORM_ROT_90:
+      case DrmHwcTransform::kRotate90:
         rotation = 1 << DRM_ROTATE_90;
         break;
-      case HWC_TRANSFORM_ROT_180:
+      case DrmHwcTransform::kRotate180:
         rotation = 1 << DRM_ROTATE_180;
         break;
-      case HWC_TRANSFORM_ROT_270:
+      case DrmHwcTransform::kRotate270:
         rotation = 1 << DRM_ROTATE_270;
         break;
-      case 0:
+      case DrmHwcTransform::kIdentity:
         rotation = 0;
         break;
       default:
-        ALOGE("Invalid transform value 0x%x given", layer->transform);
+        ALOGE("Invalid transform value 0x%x given", layer.transform);
         ret = -EINVAL;
         break;
     }
@@ -321,27 +314,27 @@
         drmModePropertySetAdd(pset, plane->id(), plane->crtc_property().id(),
                               crtc->id()) ||
         drmModePropertySetAdd(pset, plane->id(), plane->fb_property().id(),
-                              iter->bo.fb_id) ||
+                              layer.buffer->fb_id) ||
         drmModePropertySetAdd(pset, plane->id(), plane->crtc_x_property().id(),
-                              layer->displayFrame.left) ||
+                              layer.display_frame.left) ||
         drmModePropertySetAdd(pset, plane->id(), plane->crtc_y_property().id(),
-                              layer->displayFrame.top) ||
+                              layer.display_frame.top) ||
         drmModePropertySetAdd(
             pset, plane->id(), plane->crtc_w_property().id(),
-            layer->displayFrame.right - layer->displayFrame.left) ||
+            layer.display_frame.right - layer.display_frame.left) ||
         drmModePropertySetAdd(
             pset, plane->id(), plane->crtc_h_property().id(),
-            layer->displayFrame.bottom - layer->displayFrame.top) ||
+            layer.display_frame.bottom - layer.display_frame.top) ||
         drmModePropertySetAdd(pset, plane->id(), plane->src_x_property().id(),
-                              (int)(layer->sourceCropf.left) << 16) ||
+                              (int)(layer.source_crop.left) << 16) ||
         drmModePropertySetAdd(pset, plane->id(), plane->src_y_property().id(),
-                              (int)(layer->sourceCropf.top) << 16) ||
+                              (int)(layer.source_crop.top) << 16) ||
         drmModePropertySetAdd(
             pset, plane->id(), plane->src_w_property().id(),
-            (int)(layer->sourceCropf.right - layer->sourceCropf.left) << 16) ||
+            (int)(layer.source_crop.right - layer.source_crop.left) << 16) ||
         drmModePropertySetAdd(
             pset, plane->id(), plane->src_h_property().id(),
-            (int)(layer->sourceCropf.bottom - layer->sourceCropf.top) << 16);
+            (int)(layer.source_crop.bottom - layer.source_crop.top) << 16);
     if (ret) {
       ALOGE("Failed to add plane %d to set", plane->id());
       break;
@@ -412,6 +405,7 @@
 
   std::unique_ptr<DrmDisplayComposition> composition(
       std::move(composite_queue_.front()));
+
   composite_queue_.pop();
 
   ret = pthread_mutex_unlock(&lock_);
@@ -474,6 +468,22 @@
   return empty_ret;
 }
 
+struct DrmDumpLayer {
+  int plane_id;
+  int crtc_id;
+  DrmHwcTransform transform;
+  DrmHwcRect<float> source_crop;
+  DrmHwcRect<int> display_frame;
+
+  DrmDumpLayer(DrmCompositionLayer &rhs)
+      : plane_id(rhs.plane->id()),
+        crtc_id(rhs.crtc ? rhs.crtc->id() : -1),
+        transform(rhs.transform),
+        source_crop(rhs.source_crop),
+        display_frame(rhs.display_frame) {
+  }
+};
+
 void DrmDisplayCompositor::Dump(std::ostringstream *out) const {
   uint64_t cur_ts;
 
@@ -487,9 +497,11 @@
   struct timespec ts;
   ret = clock_gettime(CLOCK_MONOTONIC, &ts);
 
-  DrmCompositionLayerVector_t layers;
+  std::vector<DrmCompositionLayer> *input_layers =
+      active_composition_->GetCompositionLayers();
+  std::vector<DrmDumpLayer> layers;
   if (active_composition_)
-    layers = *active_composition_->GetCompositionLayers();
+    layers.insert(layers.begin(), input_layers->begin(), input_layers->end());
   else
     ret = -EAGAIN;
 
@@ -508,29 +520,26 @@
   dump_last_timestamp_ns_ = cur_ts;
 
   *out << "---- DrmDisplayCompositor Layers: num=" << layers.size() << "\n";
-  for (DrmCompositionLayerVector_t::iterator iter = layers.begin();
+  for (std::vector<DrmDumpLayer>::iterator iter = layers.begin();
        iter != layers.end(); ++iter) {
-    hwc_layer_1_t *layer = &iter->layer;
-    DrmPlane *plane = iter->plane;
+    *out << "------ DrmDisplayCompositor Layer: plane=" << iter->plane_id
+         << " ";
 
-    *out << "------ DrmDisplayCompositor Layer: plane=" << plane->id() << " ";
-
-    DrmCrtc *crtc = iter->crtc;
-    if (!crtc) {
+    if (iter->crtc_id < 0) {
       *out << "disabled\n";
       continue;
     }
 
-    *out << "crtc=" << crtc->id()
-         << " crtc[x/y/w/h]=" << layer->displayFrame.left << "/"
-         << layer->displayFrame.top << "/"
-         << layer->displayFrame.right - layer->displayFrame.left << "/"
-         << layer->displayFrame.bottom - layer->displayFrame.top << " "
-         << " src[x/y/w/h]=" << layer->sourceCropf.left << "/"
-         << layer->sourceCropf.top << "/"
-         << layer->sourceCropf.right - layer->sourceCropf.left << "/"
-         << layer->sourceCropf.bottom - layer->sourceCropf.top
-         << " transform=" << layer->transform << "\n";
+    *out << "crtc=" << iter->crtc_id
+         << " crtc[x/y/w/h]=" << iter->display_frame.left << "/"
+         << iter->display_frame.top << "/"
+         << iter->display_frame.right - iter->display_frame.left << "/"
+         << iter->display_frame.bottom - iter->display_frame.top << " "
+         << " src[x/y/w/h]=" << iter->source_crop.left << "/"
+         << iter->source_crop.top << "/"
+         << iter->source_crop.right - iter->source_crop.left << "/"
+         << iter->source_crop.bottom - iter->source_crop.top
+         << " transform=" << (uint32_t)iter->transform << "\n";
   }
 }
 }
diff --git a/glworker.cpp b/glworker.cpp
index f18ace9..4cbe142 100644
--- a/glworker.cpp
+++ b/glworker.cpp
@@ -33,6 +33,8 @@
 
 #include <utils/Trace.h>
 
+#include "drmdisplaycomposition.h"
+
 #include "glworker.h"
 
 #include "seperate_rects.h"
@@ -184,7 +186,6 @@
 "\n"
 "precision mediump int;                                                     \n"
 "uniform vec4 uViewport;                                                    \n"
-"uniform sampler2D uLayerTextures[LAYER_COUNT];                             \n"
 "uniform vec4 uLayerCrop[LAYER_COUNT];                                      \n"
 "uniform mat2 uTexMatrix[LAYER_COUNT];                                      \n"
 "in vec2 vPosition;                                                         \n"
@@ -193,8 +194,7 @@
 "void main() {                                                              \n"
 "  for (int i = 0; i < LAYER_COUNT; i++) {                                  \n"
 "    vec2 tempCoords = vTexCoords * uTexMatrix[i];                          \n"
-"    fTexCoords[i] = (uLayerCrop[i].xy + tempCoords * uLayerCrop[i].zw) /   \n"
-"                     vec2(textureSize(uLayerTextures[i], 0));              \n"
+"    fTexCoords[i] = uLayerCrop[i].xy + tempCoords * uLayerCrop[i].zw;      \n"
 "  }                                                                        \n"
 "  vec2 scaledPosition = uViewport.xy + vPosition * uViewport.zw;           \n"
 "  gl_Position = vec4(scaledPosition * vec2(2.0) - vec2(1.0), 0.0, 1.0);    \n"
@@ -202,8 +202,9 @@
 
   const GLchar *fragment_shader_source =
 "\n"
+"#extension GL_OES_EGL_image_external : require                             \n"
 "precision mediump float;                                                   \n"
-"uniform sampler2D uLayerTextures[LAYER_COUNT];                             \n"
+"uniform samplerExternalOES uLayerTextures[LAYER_COUNT];                    \n"
 "uniform float uLayerAlpha[LAYER_COUNT];                                    \n"
 "in vec2 fTexCoords[LAYER_COUNT];                                           \n"
 "out vec4 oFragColor;                                                       \n"
@@ -211,7 +212,7 @@
 "  vec3 color = vec3(0.0, 0.0, 0.0);                                        \n"
 "  float alphaCover = 1.0;                                                  \n"
 "  for (int i = 0; i < LAYER_COUNT; i++) {                                  \n"
-"    vec4 texSample = texture(uLayerTextures[i], fTexCoords[i]);            \n"
+"    vec4 texSample = texture2D(uLayerTextures[i], fTexCoords[i]);          \n"
 "    float a = texSample.a * uLayerAlpha[i];                                \n"
 "    color += a * alphaCover * texSample.rgb;                               \n"
 "    alphaCover *= 1.0 - a;                                                 \n"
@@ -305,18 +306,15 @@
   }
 };
 
-static void ConstructCommands(const hwc_layer_1 *layers, size_t num_layers,
+static void ConstructCommands(DrmCompositionLayer *layers, size_t num_layers,
                               std::vector<RenderingCommand> *commands) {
   std::vector<FRect> in_rects;
   std::vector<FRectSet> out_rects;
   int i;
 
   for (unsigned rect_index = 0; rect_index < num_layers; rect_index++) {
-    const hwc_layer_1 &layer = layers[rect_index];
-    FRect rect;
-    in_rects.push_back(FRect(layer.displayFrame.left, layer.displayFrame.top,
-                             layer.displayFrame.right,
-                             layer.displayFrame.bottom));
+    DrmCompositionLayer &layer = layers[rect_index];
+    in_rects.emplace_back(layer.display_frame);
   }
 
   seperate_frects_64(in_rects, &out_rects);
@@ -326,23 +324,28 @@
     commands->push_back(RenderingCommand());
     RenderingCommand &cmd = commands->back();
 
-    memcpy(cmd.bounds, out_rect.rect.bounds, sizeof(cmd.bounds));
+    for (int i = 0; i < 4; i++)
+      cmd.bounds[i] = out_rect.rect.bounds[i];
 
     uint64_t tex_set = out_rect.id_set.getBits();
     for (unsigned i = num_layers - 1; tex_set != 0x0; i--) {
       if (tex_set & (0x1 << i)) {
         tex_set &= ~(0x1 << i);
 
-        const hwc_layer_1 &layer = layers[i];
+        DrmCompositionLayer &layer = layers[i];
 
-        FRect display_rect(layer.displayFrame.left, layer.displayFrame.top,
-                           layer.displayFrame.right, layer.displayFrame.bottom);
+        FRect display_rect(layer.display_frame);
         float display_size[2] = {
             display_rect.bounds[2] - display_rect.bounds[0],
             display_rect.bounds[3] - display_rect.bounds[1]};
 
-        FRect crop_rect(layer.sourceCropf.left, layer.sourceCropf.top,
-                        layer.sourceCropf.right, layer.sourceCropf.bottom);
+        float tex_width = layer.buffer->width;
+        float tex_height = layer.buffer->height;
+        FRect crop_rect(layer.source_crop.left / tex_width,
+                        layer.source_crop.top / tex_height,
+                        layer.source_crop.right / tex_width,
+                        layer.source_crop.bottom / tex_height);
+
         float crop_size[2] = {crop_rect.bounds[2] - crop_rect.bounds[0],
                               crop_rect.bounds[3] - crop_rect.bounds[1]};
 
@@ -352,27 +355,39 @@
 
         bool swap_xy, flip_xy[2];
         switch (layer.transform) {
-          case HWC_TRANSFORM_FLIP_H:
-            swap_xy = false; flip_xy[0] = true; flip_xy[1] = false;
+          case DrmHwcTransform::kFlipH:
+            swap_xy = false;
+            flip_xy[0] = true;
+            flip_xy[1] = false;
             break;
-          case HWC_TRANSFORM_FLIP_V:
-            swap_xy = false; flip_xy[0] = false; flip_xy[1] = true;
+          case DrmHwcTransform::kFlipV:
+            swap_xy = false;
+            flip_xy[0] = false;
+            flip_xy[1] = true;
             break;
-          case HWC_TRANSFORM_ROT_90:
-            swap_xy = true; flip_xy[0] = false; flip_xy[1] = true;
+          case DrmHwcTransform::kRotate90:
+            swap_xy = true;
+            flip_xy[0] = false;
+            flip_xy[1] = true;
             break;
-          case HWC_TRANSFORM_ROT_180:
-            swap_xy = false; flip_xy[0] = true; flip_xy[1] = true;
+          case DrmHwcTransform::kRotate180:
+            swap_xy = false;
+            flip_xy[0] = true;
+            flip_xy[1] = true;
             break;
-          case HWC_TRANSFORM_ROT_270:
-            swap_xy = true; flip_xy[0] = true; flip_xy[1] = false;
+          case DrmHwcTransform::kRotate270:
+            swap_xy = true;
+            flip_xy[0] = true;
+            flip_xy[1] = false;
             break;
           default:
             ALOGE(
                 "Unknown transform for layer: defaulting to identity "
                 "transform");
-          case 0:
-            swap_xy = false; flip_xy[0] = false; flip_xy[1] = false;
+          case DrmHwcTransform::kIdentity:
+            swap_xy = false;
+            flip_xy[0] = false;
+            flip_xy[1] = false;
             break;
         }
 
@@ -394,14 +409,14 @@
           }
         }
 
-        if (layer.blending == HWC_BLENDING_NONE) {
+        if (layer.blending == DrmHwcBlending::kNone) {
           src.alpha = 1.0f;
           // This layer is opaque. There is no point in using layers below this
           // one.
           break;
         }
 
-        src.alpha = layer.planeAlpha / 255.0f;
+        src.alpha = layer.alpha / 255.0f;
       }
     }
   }
@@ -444,13 +459,13 @@
 
   GLuint texture;
   glGenTextures(1, &texture);
-  glBindTexture(GL_TEXTURE_2D, texture);
-  glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, (GLeglImageOES)image);
-  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
-  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
-  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
-  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
-  glBindTexture(GL_TEXTURE_2D, 0);
+  glBindTexture(GL_TEXTURE_EXTERNAL_OES, texture);
+  glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, (GLeglImageOES)image);
+  glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+  glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+  glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_REPEAT);
+  glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_REPEAT);
+  glBindTexture(GL_TEXTURE_EXTERNAL_OES, 0);
 
   out->image.reset(egl_display, image);
   out->texture.reset(texture);
@@ -539,6 +554,9 @@
   if (!HasExtension("GL_OES_EGL_image", gl_extensions))
     ALOGW("GL_OES_EGL_image extension not supported");
 
+  if (!HasExtension("GL_OES_EGL_image_external", gl_extensions))
+    ALOGW("GL_OES_EGL_image_external extension not supported");
+
   GLuint vertex_buffer;
   glGenBuffers(1, &vertex_buffer);
   glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer);
@@ -559,7 +577,8 @@
       ALOGE("Failed to destroy OpenGL ES Context: %s", GetEGLError());
 }
 
-int GLWorkerCompositor::Composite(hwc_layer_1 *layers, size_t num_layers,
+int GLWorkerCompositor::Composite(DrmCompositionLayer *layers,
+                                  size_t num_layers,
                                   const sp<GraphicBuffer> &framebuffer) {
   ATRACE_CALL();
   int ret = 0;
@@ -581,23 +600,14 @@
   }
 
   for (i = 0; i < num_layers; i++) {
-    struct hwc_layer_1 *layer = &layers[i];
-
-    if (ret) {
-      if (layer->acquireFenceFd >= 0) {
-        close(layer->acquireFenceFd);
-        layer->acquireFenceFd = -1;
-      }
-      continue;
-    }
+    DrmCompositionLayer *layer = &layers[i];
 
     layer_textures.emplace_back();
-    ret = CreateTextureFromHandle(egl_display_, layer->handle,
+    ret = CreateTextureFromHandle(egl_display_, layer->get_usable_handle(),
                                   &layer_textures.back());
 
     if (!ret) {
-      ret = EGLFenceWait(egl_display_, layer->acquireFenceFd);
-      layer->acquireFenceFd = -1;
+      ret = EGLFenceWait(egl_display_, layer->acquire_fence.Release());
     }
     if (ret) {
       layer_textures.pop_back();
@@ -658,7 +668,7 @@
       glUniformMatrix2fv(gl_tex_matrix_loc + src_index, 1, GL_FALSE,
                          src.texture_matrix);
       glActiveTexture(GL_TEXTURE0 + src_index);
-      glBindTexture(GL_TEXTURE_2D,
+      glBindTexture(GL_TEXTURE_EXTERNAL_OES,
                     layer_textures[src.texture_index].texture.get());
     }
 
@@ -668,7 +678,7 @@
 
     for (unsigned src_index = 0; src_index < cmd.texture_count; src_index++) {
       glActiveTexture(GL_TEXTURE0 + src_index);
-      glBindTexture(GL_TEXTURE_2D, 0);
+      glBindTexture(GL_TEXTURE_EXTERNAL_OES, 0);
     }
   }
 
diff --git a/glworker.h b/glworker.h
index ce41444..b3163ce 100644
--- a/glworker.h
+++ b/glworker.h
@@ -33,13 +33,15 @@
 
 namespace android {
 
+struct DrmCompositionLayer;
+
 class GLWorkerCompositor {
  public:
   GLWorkerCompositor();
   ~GLWorkerCompositor();
 
   int Init();
-  int Composite(hwc_layer_1 *layers, size_t num_layers,
+  int Composite(DrmCompositionLayer *layers, size_t num_layers,
                 const sp<GraphicBuffer> &framebuffer);
   void Finish();
 
diff --git a/hwcomposer.cpp b/hwcomposer.cpp
index 060a955..0a8b661 100644
--- a/hwcomposer.cpp
+++ b/hwcomposer.cpp
@@ -26,6 +26,7 @@
 
 #include <map>
 #include <vector>
+#include <sstream>
 
 #include <errno.h>
 #include <fcntl.h>
@@ -39,6 +40,8 @@
 #include <cutils/properties.h>
 #include <hardware/hardware.h>
 #include <hardware/hwcomposer.h>
+#include <sw_sync.h>
+#include <sync/sync.h>
 #include <utils/Trace.h>
 
 #define UM_PER_INCH 25400
@@ -46,6 +49,72 @@
 
 namespace android {
 
+class DummySwSyncTimeline {
+ public:
+  int Init() {
+    int ret = timeline_fd_.Set(sw_sync_timeline_create());
+    if (ret < 0)
+      return ret;
+    return 0;
+  }
+
+  UniqueFd CreateDummyFence() {
+    int ret = sw_sync_fence_create(timeline_fd_.get(), "dummy fence",
+                                   timeline_pt_ + 1);
+    if (ret < 0) {
+      ALOGE("Failed to create dummy fence %d", ret);
+      return ret;
+    }
+
+    UniqueFd ret_fd(ret);
+
+    ret = sw_sync_timeline_inc(timeline_fd_.get(), 1);
+    if (ret) {
+      ALOGE("Failed to increment dummy sync timeline %d", ret);
+      return ret;
+    }
+
+    ++timeline_pt_;
+    return ret_fd;
+  }
+
+ private:
+  UniqueFd timeline_fd_;
+  int timeline_pt_ = 0;
+};
+
+struct CheckedOutputFd {
+  CheckedOutputFd(int *fd, const char *description,
+                  DummySwSyncTimeline &timeline)
+      : fd_(fd), description_(description), timeline_(timeline) {
+  }
+  CheckedOutputFd(CheckedOutputFd &&rhs)
+      : description_(rhs.description_), timeline_(rhs.timeline_) {
+    std::swap(fd_, rhs.fd_);
+  }
+
+  CheckedOutputFd &operator=(const CheckedOutputFd &rhs) = delete;
+
+  ~CheckedOutputFd() {
+    if (fd_ == NULL)
+      return;
+
+    if (*fd_ >= 0)
+      return;
+
+    *fd_ = timeline_.CreateDummyFence().Release();
+
+    if (*fd_ < 0)
+      ALOGE("Failed to fill %s (%p == %d) before destruction",
+            description_.c_str(), fd_, *fd_);
+  }
+
+ private:
+  int *fd_ = NULL;
+  std::string description_;
+  DummySwSyncTimeline &timeline_;
+};
+
 typedef struct hwc_drm_display {
   struct hwc_context_t *ctx;
   int display;
@@ -73,9 +142,184 @@
   DisplayMap displays;
   DrmResources drm;
   Importer *importer;
+  const gralloc_module_t *gralloc;
+  DummySwSyncTimeline dummy_timeline;
   bool use_framebuffer_target;
 };
 
+static native_handle_t *dup_buffer_handle(buffer_handle_t handle) {
+  native_handle_t *new_handle =
+      native_handle_create(handle->numFds, handle->numInts);
+  if (new_handle == NULL)
+    return NULL;
+
+  const int *old_data = handle->data;
+  int *new_data = new_handle->data;
+  for (int i = 0; i < handle->numFds; i++) {
+    *new_data = dup(*old_data);
+    old_data++;
+    new_data++;
+  }
+  memcpy(new_data, old_data, sizeof(int) * handle->numInts);
+
+  return new_handle;
+}
+
+static void free_buffer_handle(native_handle_t *handle) {
+  int ret = native_handle_close(handle);
+  if (ret)
+    ALOGE("Failed to close native handle %d", ret);
+  ret = native_handle_delete(handle);
+  if (ret)
+    ALOGE("Failed to delete native handle %d", ret);
+}
+
+OutputFd &OutputFd::operator=(OutputFd &&rhs) {
+  if (fd_ == NULL) {
+    std::swap(fd_, rhs.fd_);
+  } else {
+    if (*fd_ < 0) {
+      ALOGE("Failed to fill OutputFd %p before assignment", fd_);
+    }
+    fd_ = rhs.fd_;
+    rhs.fd_ = NULL;
+  }
+
+  return *this;
+}
+
+hwc_drm_bo *DrmHwcBuffer::operator->() {
+  if (importer_ == NULL) {
+    ALOGE("Access of none existent BO");
+    exit(1);
+    return NULL;
+  }
+  return &bo_;
+}
+
+void DrmHwcBuffer::Clear() {
+  if (importer_ != NULL) {
+    importer_->ReleaseBuffer(&bo_);
+    importer_ = NULL;
+  }
+}
+
+int DrmHwcBuffer::ImportBuffer(buffer_handle_t handle, Importer *importer) {
+  hwc_drm_bo tmp_bo;
+
+  int ret = importer->ImportBuffer(handle, &tmp_bo);
+  if (ret)
+    return ret;
+
+  if (importer_ != NULL) {
+    importer_->ReleaseBuffer(&bo_);
+  }
+
+  importer_ = importer;
+
+  bo_ = tmp_bo;
+
+  return 0;
+}
+
+int DrmHwcNativeHandle::CopyBufferHandle(buffer_handle_t handle,
+                                         const gralloc_module_t *gralloc) {
+  native_handle_t *handle_copy = dup_buffer_handle(handle);
+  if (handle_copy == NULL) {
+    ALOGE("Failed to duplicate handle");
+    return -ENOMEM;
+  }
+
+  int ret = gralloc->registerBuffer(gralloc, handle_copy);
+  if (ret) {
+    ALOGE("Failed to register buffer handle %d", ret);
+    free_buffer_handle(handle_copy);
+    return ret;
+  }
+
+  Clear();
+
+  gralloc_ = gralloc;
+  handle_ = handle_copy;
+
+  return 0;
+}
+
+DrmHwcNativeHandle::~DrmHwcNativeHandle() {
+  Clear();
+}
+
+void DrmHwcNativeHandle::Clear() {
+  if (gralloc_ != NULL && handle_ != NULL) {
+    gralloc_->unregisterBuffer(gralloc_, handle_);
+    free_buffer_handle(handle_);
+    gralloc_ = NULL;
+    handle_ = NULL;
+  }
+}
+
+int DrmHwcLayer::InitFromHwcLayer(hwc_layer_1_t *sf_layer, Importer *importer,
+                                  const gralloc_module_t *gralloc) {
+  sf_handle = sf_layer->handle;
+  int ret = buffer.ImportBuffer(sf_layer->handle, importer);
+  if (ret)
+    return ret;
+
+  ret = handle.CopyBufferHandle(sf_layer->handle, gralloc);
+  if (ret)
+    return ret;
+
+  alpha = sf_layer->planeAlpha;
+
+  switch (sf_layer->transform) {
+    case 0:
+      transform = DrmHwcTransform::kIdentity;
+      break;
+    case HWC_TRANSFORM_FLIP_H:
+      transform = DrmHwcTransform::kFlipH;
+      break;
+    case HWC_TRANSFORM_FLIP_V:
+      transform = DrmHwcTransform::kFlipV;
+      break;
+    case HWC_TRANSFORM_ROT_90:
+      transform = DrmHwcTransform::kRotate90;
+      break;
+    case HWC_TRANSFORM_ROT_180:
+      transform = DrmHwcTransform::kRotate180;
+      break;
+    case HWC_TRANSFORM_ROT_270:
+      transform = DrmHwcTransform::kRotate270;
+      break;
+    default:
+      ALOGE("Invalid transform in hwc_layer_1_t %d", sf_layer->transform);
+      return -EINVAL;
+  }
+
+  switch (sf_layer->blending) {
+    case HWC_BLENDING_NONE:
+      blending = DrmHwcBlending::kNone;
+      break;
+    case HWC_BLENDING_PREMULT:
+      blending = DrmHwcBlending::kPreMult;
+      break;
+    case HWC_BLENDING_COVERAGE:
+      blending = DrmHwcBlending::kCoverage;
+      break;
+    default:
+      ALOGE("Invalid blending in hwc_layer_1_t %d", sf_layer->blending);
+      return -EINVAL;
+  }
+
+  source_crop = DrmHwcRect<float>(
+      sf_layer->sourceCropf.left, sf_layer->sourceCropf.top,
+      sf_layer->sourceCropf.right, sf_layer->sourceCropf.bottom);
+  display_frame = DrmHwcRect<int>(
+      sf_layer->displayFrame.left, sf_layer->displayFrame.top,
+      sf_layer->displayFrame.right, sf_layer->displayFrame.bottom);
+
+  return 0;
+}
+
 static void hwc_dump(struct hwc_composer_device_1 *dev, char *buff,
                      int buff_len) {
   struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
@@ -131,27 +375,6 @@
   return 0;
 }
 
-static void hwc_set_cleanup(size_t num_displays,
-                            hwc_display_contents_1_t **display_contents) {
-  for (int i = 0; i < (int)num_displays; ++i) {
-    if (!display_contents[i])
-      continue;
-
-    hwc_display_contents_1_t *dc = display_contents[i];
-    for (size_t j = 0; j < dc->numHwLayers; ++j) {
-      hwc_layer_1_t *layer = &dc->hwLayers[j];
-      if (layer->acquireFenceFd >= 0) {
-        close(layer->acquireFenceFd);
-        layer->acquireFenceFd = -1;
-      }
-    }
-    if (dc->outbufAcquireFenceFd >= 0) {
-      close(dc->outbufAcquireFenceFd);
-      dc->outbufAcquireFenceFd = -1;
-    }
-  }
-}
-
 static void hwc_add_layer_to_retire_fence(
     hwc_layer_1_t *layer, hwc_display_contents_1_t *display_contents) {
   if (layer->releaseFenceFd < 0)
@@ -168,109 +391,133 @@
 }
 
 static int hwc_set(hwc_composer_device_1_t *dev, size_t num_displays,
-                   hwc_display_contents_1_t **display_contents) {
+                   hwc_display_contents_1_t **sf_display_contents) {
   ATRACE_CALL();
   struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
-  int ret;
-  std::unique_ptr<DrmComposition> composition(
-      ctx->drm.compositor()->CreateComposition(ctx->importer));
-  if (!composition) {
-    ALOGE("Drm composition init failed");
-    hwc_set_cleanup(num_displays, display_contents);
-    return -EINVAL;
-  }
+  int ret = 0;
 
+  std::vector<CheckedOutputFd> checked_output_fences;
+  std::vector<DrmHwcDisplayContents> displays_contents;
   std::vector<DrmCompositionDisplayLayersMap> layers_map;
   std::vector<std::vector<size_t>> layers_indices;
-  layers_map.reserve(num_displays);
+  displays_contents.reserve(num_displays);
+  // layers_map.reserve(num_displays);
   layers_indices.reserve(num_displays);
 
-  for (int i = 0; i < (int)num_displays; ++i) {
-    if (!display_contents[i])
+  // Phase one does nothing that would cause errors. Only take ownership of FDs.
+  for (size_t i = 0; i < num_displays; ++i) {
+    hwc_display_contents_1_t *dc = sf_display_contents[i];
+    displays_contents.emplace_back();
+    DrmHwcDisplayContents &display_contents = displays_contents.back();
+
+    if (!sf_display_contents[i])
       continue;
-    hwc_display_contents_1_t *dc = display_contents[i];
 
-    layers_map.emplace_back();
-    DrmCompositionDisplayLayersMap &map = layers_map[i];
-    map.display = i;
-    map.layers = dc->hwLayers;
+    std::ostringstream display_index_formatter;
+    display_index_formatter << "retire fence for display " << i;
+    std::string display_fence_description(display_index_formatter.str());
+    checked_output_fences.emplace_back(&dc->retireFenceFd,
+                                       display_fence_description.c_str(),
+                                       ctx->dummy_timeline);
+    display_contents.retire_fence = OutputFd(&dc->retireFenceFd);
 
+    size_t num_dc_layers = dc->numHwLayers;
     std::vector<size_t> indices_to_composite;
-    unsigned num_dc_layers = dc->numHwLayers;
     int framebuffer_target_index = -1;
-    for (int j = 0; j < (int)num_dc_layers; ++j) {
-      hwc_layer_1_t *layer = &dc->hwLayers[j];
-      if (layer->flags & HWC_SKIP_LAYER)
+    for (size_t j = 0; j < num_dc_layers; ++j) {
+      hwc_layer_1_t *sf_layer = &dc->hwLayers[j];
+
+      display_contents.layers.emplace_back();
+      DrmHwcLayer &layer = display_contents.layers.back();
+
+      if (sf_layer->flags & HWC_SKIP_LAYER)
         continue;
+
       if (!ctx->use_framebuffer_target) {
-        if (layer->compositionType == HWC_OVERLAY)
+        if (sf_layer->compositionType == HWC_OVERLAY)
           indices_to_composite.push_back(j);
-        if (layer->compositionType == HWC_FRAMEBUFFER_TARGET)
+        if (sf_layer->compositionType == HWC_FRAMEBUFFER_TARGET)
           framebuffer_target_index = j;
       } else {
-        if (layer->compositionType == HWC_FRAMEBUFFER_TARGET)
+        if (sf_layer->compositionType == HWC_FRAMEBUFFER_TARGET)
           indices_to_composite.push_back(j);
       }
+
+      layer.acquire_fence.Set(sf_layer->acquireFenceFd);
+      sf_layer->acquireFenceFd = -1;
+
+      std::ostringstream layer_fence_formatter;
+      layer_fence_formatter << "release fence for layer " << j << " of display "
+                            << i;
+      std::string layer_fence_description(layer_fence_formatter.str());
+      checked_output_fences.emplace_back(&sf_layer->releaseFenceFd,
+                                         layer_fence_description.c_str(),
+                                         ctx->dummy_timeline);
+      layer.release_fence = OutputFd(&sf_layer->releaseFenceFd);
     }
+
     if (ctx->use_framebuffer_target) {
       if (indices_to_composite.size() != 1) {
         ALOGE("Expected 1 (got %d) layer with HWC_FRAMEBUFFER_TARGET",
               indices_to_composite.size());
-        hwc_set_cleanup(num_displays, display_contents);
-        return -EINVAL;
+        ret = -EINVAL;
       }
     } else {
       if (indices_to_composite.empty() && framebuffer_target_index >= 0) {
-        // Fall back to use HWC_FRAMEBUFFER_TARGET if all HWC_OVERLAY layers
-        // are skipped.
-        hwc_layer_1_t *layer = &dc->hwLayers[framebuffer_target_index];
-        if (!layer->handle || (layer->flags & HWC_SKIP_LAYER)) {
-          ALOGE("Expected valid layer with HWC_FRAMEBUFFER_TARGET when all "
-                "HWC_OVERLAY layers are skipped.");
-          hwc_set_cleanup(num_displays, display_contents);
-          return -EINVAL;
+        hwc_layer_1_t *sf_layer = &dc->hwLayers[framebuffer_target_index];
+        if (!sf_layer->handle || (sf_layer->flags & HWC_SKIP_LAYER)) {
+          ALOGE(
+              "Expected valid layer with HWC_FRAMEBUFFER_TARGET when all "
+              "HWC_OVERLAY layers are skipped.");
+          ret = -EINVAL;
         }
         indices_to_composite.push_back(framebuffer_target_index);
       }
     }
+    layers_indices.emplace_back(indices_to_composite);
+  }
 
-    map.num_layers = indices_to_composite.size();
-    layers_indices.emplace_back(std::move(indices_to_composite));
-    map.layer_indices = layers_indices.back().data();
+  if (ret)
+    return ret;
+
+  for (size_t i = 0; i < num_displays; ++i) {
+    hwc_display_contents_1_t *dc = sf_display_contents[i];
+    DrmHwcDisplayContents &display_contents = displays_contents[i];
+    if (!sf_display_contents[i])
+      continue;
+
+    layers_map.emplace_back();
+    DrmCompositionDisplayLayersMap &map = layers_map.back();
+    std::vector<size_t> &indices_to_composite = layers_indices[i];
+    for (size_t j : indices_to_composite) {
+      hwc_layer_1_t *sf_layer = &dc->hwLayers[j];
+
+      DrmHwcLayer &layer = display_contents.layers[j];
+
+      layer.InitFromHwcLayer(sf_layer, ctx->importer, ctx->gralloc);
+      map.layers.emplace_back(std::move(layer));
+    }
+  }
+
+  std::unique_ptr<DrmComposition> composition(
+      ctx->drm.compositor()->CreateComposition(ctx->importer));
+  if (!composition) {
+    ALOGE("Drm composition init failed");
+    return -EINVAL;
   }
 
   ret = composition->SetLayers(layers_map.size(), layers_map.data());
   if (ret) {
-    hwc_set_cleanup(num_displays, display_contents);
     return -EINVAL;
   }
 
   ret = ctx->drm.compositor()->QueueComposition(std::move(composition));
   if (ret) {
-    hwc_set_cleanup(num_displays, display_contents);
     return -EINVAL;
   }
 
   composition.reset(NULL);
 
-  for (int i = 0; i < (int)num_displays; ++i) {
-    if (!display_contents[i])
-      continue;
-    hwc_display_contents_1_t *dc = display_contents[i];
-    unsigned num_dc_layers = dc->numHwLayers;
-    for (int j = 0; j < (int)num_dc_layers; ++j) {
-      hwc_layer_1_t *layer = &dc->hwLayers[j];
-      if (layer->flags & HWC_SKIP_LAYER)
-        continue;
-      if (layer->compositionType == HWC_OVERLAY)
-        hwc_add_layer_to_retire_fence(layer, dc);
-    }
-  }
-
-  if (ret) {
-    ALOGE("Failed to queue the composition");
-  }
-  hwc_set_cleanup(num_displays, display_contents);
   return ret;
 }
 
@@ -551,6 +798,20 @@
     return ret;
   }
 
+  ret = hw_get_module(GRALLOC_HARDWARE_MODULE_ID,
+                      (const hw_module_t **)&ctx->gralloc);
+  if (ret) {
+    ALOGE("Failed to open gralloc module %d", ret);
+    delete ctx;
+    return ret;
+  }
+
+  ret = ctx->dummy_timeline.Init();
+  if (ret) {
+    ALOGE("Failed to create dummy sw sync timeline %d", ret);
+    return ret;
+  }
+
   ctx->importer = Importer::CreateInstance(&ctx->drm);
   if (!ctx->importer) {
     ALOGE("Failed to create importer instance");
diff --git a/seperate_rects.h b/seperate_rects.h
index 9bf95a3..540a5e8 100644
--- a/seperate_rects.h
+++ b/seperate_rects.h
@@ -43,11 +43,19 @@
       : x1(xx1), y1(yy1), x2(xx2), y2(yy2) {
   }
 
-  Rect(const Rect &rhs) {
+  template <typename T>
+  Rect(const Rect<T> &rhs) {
     for (int i = 0; i < 4; i++)
       bounds[i] = rhs.bounds[i];
   }
 
+  template <typename T>
+  Rect<TFloat> &operator=(const Rect<T> &rhs) {
+    for (int i = 0; i < 4; i++)
+      bounds[i] = rhs.bounds[i];
+    return *this;
+  }
+
   bool operator==(const Rect &rhs) const {
     for (int i = 0; i < 4; i++) {
       if (bounds[i] != rhs.bounds[i])