drm_hwcomposer: Use hw planes + drm atomic interface

Replace the basic, single overlay, modeset/flip implementation with
a new Compositor instantiation for drm. The new compositor uses the
drm atomic interface to composite layers to multiple hardware planes.

This change also introduces an importer argument in
Compositor::CreateComposition. By specifying the importer, Compositor
instances are responsible for cleaning up buffer objects submitted
via Composition::AddLayer.

Change-Id: Ic292829cd93475d754294b00428de132301092b2
Signed-off-by: Sean Paul <seanpaul@chromium.org>
diff --git a/Android.mk b/Android.mk
index 30dfb5f..262ddfe 100644
--- a/Android.mk
+++ b/Android.mk
@@ -36,6 +36,9 @@
 LOCAL_SRC_FILES := \
 	compositor.cpp \
 	drmresources.cpp \
+        drmcomposition.cpp \
+        drmcompositor.cpp \
+        drmcompositorworker.cpp \
 	drmconnector.cpp \
 	drmcrtc.cpp \
 	drmencoder.cpp \
diff --git a/drmcomposition.cpp b/drmcomposition.cpp
new file mode 100644
index 0000000..8fcb12d
--- /dev/null
+++ b/drmcomposition.cpp
@@ -0,0 +1,167 @@
+/*
+ * 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-composition"
+
+#include "drmcomposition.h"
+#include "drmcrtc.h"
+#include "drmplane.h"
+#include "drmresources.h"
+
+#include <stdlib.h>
+
+#include <cutils/log.h>
+#include <sw_sync.h>
+#include <sync/sync.h>
+
+namespace android {
+
+static const bool kUseOverlayPlanes = false;
+
+DrmCompositionLayer::DrmCompositionLayer() : crtc(NULL), plane(NULL) {
+  memset(&layer, 0, sizeof(layer));
+  layer.acquireFenceFd = -1;
+  memset(&bo, 0, sizeof(bo));
+}
+
+DrmCompositionLayer::~DrmCompositionLayer() {
+}
+
+DrmComposition::DrmComposition(DrmResources *drm, Importer *importer,
+                               uint64_t frame_no)
+    : drm_(drm),
+      importer_(importer),
+      frame_no_(frame_no),
+      timeline_fd_(-1),
+      timeline_(0) {
+  for (DrmResources::PlaneIter iter = drm_->begin_planes();
+       iter != drm_->end_planes(); ++iter) {
+    if ((*iter)->type() == DRM_PLANE_TYPE_PRIMARY)
+      primary_planes_.push_back(*iter);
+    else if (kUseOverlayPlanes && (*iter)->type() == DRM_PLANE_TYPE_OVERLAY)
+      overlay_planes_.push_back(*iter);
+  }
+}
+
+DrmComposition::~DrmComposition() {
+  for (DrmCompositionLayerMap_t::iterator iter = composition_map_.begin();
+       iter != composition_map_.end(); ++iter) {
+    importer_->ReleaseBuffer(&iter->second.bo);
+
+    if (iter->second.layer.acquireFenceFd >= 0)
+      close(iter->second.layer.acquireFenceFd);
+  }
+
+  if (timeline_fd_ >= 0)
+    close(timeline_fd_);
+}
+
+int DrmComposition::Init() {
+  int ret = sw_sync_timeline_create();
+  if (ret < 0) {
+    ALOGE("Failed to create sw sync timeline %d", ret);
+    return ret;
+  }
+  timeline_fd_ = ret;
+  return 0;
+}
+
+unsigned DrmComposition::GetRemainingLayers(int display,
+                                            unsigned num_needed) const {
+  DrmCrtc *crtc = drm_->GetCrtcForDisplay(display);
+  if (!crtc) {
+    ALOGW("Failed to find crtc for display %d", display);
+    return 0;
+  }
+
+  unsigned num_planes = 0;
+  for (std::vector<DrmPlane *>::const_iterator iter = primary_planes_.begin();
+       iter != primary_planes_.end(); ++iter) {
+    if ((*iter)->GetCrtcSupported(*crtc))
+      ++num_planes;
+  }
+  for (std::deque<DrmPlane *>::const_iterator iter = overlay_planes_.begin();
+       iter != overlay_planes_.end(); ++iter) {
+    if ((*iter)->GetCrtcSupported(*crtc))
+      ++num_planes;
+  }
+  return std::min(num_planes, num_needed);
+}
+
+int DrmComposition::AddLayer(int display, hwc_layer_1_t *layer,
+                             hwc_drm_bo *bo) {
+  if (layer->transform != 0)
+    return -EINVAL;
+
+  DrmCrtc *crtc = drm_->GetCrtcForDisplay(display);
+  if (!crtc) {
+    ALOGE("Could not find crtc for display %d", display);
+    return -ENODEV;
+  }
+
+  ++timeline_;
+  layer->releaseFenceFd =
+      sw_sync_fence_create(timeline_fd_, "drm_fence", timeline_);
+  if (layer->releaseFenceFd < 0) {
+    ALOGE("Could not create release fence %d", layer->releaseFenceFd);
+    return layer->releaseFenceFd;
+  }
+
+  DrmCompositionLayer_t c_layer;
+  c_layer.layer = *layer;
+  c_layer.bo = *bo;
+  c_layer.crtc = crtc;
+
+  // First try to find a primary plane for the layer, then fallback on overlays
+  for (std::vector<DrmPlane *>::iterator iter = primary_planes_.begin();
+       iter != primary_planes_.end(); ++iter) {
+    if ((*iter)->GetCrtcSupported(*crtc)) {
+      c_layer.plane = (*iter);
+      primary_planes_.erase(iter);
+      break;
+    }
+  }
+  for (std::deque<DrmPlane *>::iterator iter = overlay_planes_.begin();
+       !c_layer.plane && iter != overlay_planes_.end(); ++iter) {
+    if ((*iter)->GetCrtcSupported(*crtc)) {
+      c_layer.plane = (*iter);
+      overlay_planes_.erase(iter);
+      break;
+    }
+  }
+  if (!c_layer.plane) {
+    close(layer->releaseFenceFd);
+    layer->releaseFenceFd = -1;
+    return -ENOENT;
+  }
+
+  layer->acquireFenceFd = -1;  // We own this now
+  composition_map_.insert(DrmCompositionLayerPair_t(display, c_layer));
+  return 0;
+}
+
+int DrmComposition::FinishComposition() {
+  int ret = sw_sync_timeline_inc(timeline_fd_, timeline_);
+  if (ret)
+    ALOGE("Failed to increment sync timeline %d", ret);
+
+  return ret;
+}
+
+DrmCompositionLayerMap_t *DrmComposition::GetCompositionMap() {
+  return &composition_map_;
+}
+}
diff --git a/drmcomposition.h b/drmcomposition.h
new file mode 100644
index 0000000..5c47fbf
--- /dev/null
+++ b/drmcomposition.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_DRM_COMPOSITION_H_
+#define ANDROID_DRM_COMPOSITION_H_
+
+#include "compositor.h"
+#include "drm_hwcomposer.h"
+#include "drmplane.h"
+#include "importer.h"
+
+#include <deque>
+#include <map>
+#include <vector>
+
+#include <hardware/hardware.h>
+#include <hardware/hwcomposer.h>
+
+namespace android {
+
+typedef struct DrmCompositionLayer {
+  DrmCompositionLayer();
+  ~DrmCompositionLayer();
+
+  hwc_layer_1_t layer;
+  hwc_drm_bo_t bo;
+  DrmCrtc *crtc;
+  DrmPlane *plane;
+} DrmCompositionLayer_t;
+
+typedef std::multimap<int, DrmCompositionLayer> DrmCompositionLayerMap_t;
+typedef std::pair<int, DrmCompositionLayer> DrmCompositionLayerPair_t;
+
+class DrmComposition : public Composition {
+ public:
+  DrmComposition(DrmResources *drm, Importer *importer, uint64_t frame_no);
+  ~DrmComposition();
+
+  virtual int Init();
+
+  virtual unsigned GetRemainingLayers(int display, unsigned num_needed) const;
+  virtual int AddLayer(int display, hwc_layer_1_t *layer, hwc_drm_bo_t *bo);
+
+  int FinishComposition();
+
+  DrmCompositionLayerMap_t *GetCompositionMap();
+
+ private:
+  DrmResources *drm_;
+  Importer *importer_;
+
+  uint64_t frame_no_;
+
+  int timeline_fd_;
+  int timeline_;
+
+  std::vector<DrmPlane *> primary_planes_;
+  std::deque<DrmPlane *> overlay_planes_;
+  DrmCompositionLayerMap_t composition_map_;
+};
+}
+
+#endif  // ANDROID_DRM_COMPOSITION_H_
diff --git a/drmcompositor.cpp b/drmcompositor.cpp
new file mode 100644
index 0000000..ffca4df
--- /dev/null
+++ b/drmcompositor.cpp
@@ -0,0 +1,270 @@
+/*
+ * 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-compositor"
+
+#include "drmcompositor.h"
+#include "drmcrtc.h"
+#include "drmplane.h"
+#include "drmresources.h"
+
+#include <pthread.h>
+#include <stdlib.h>
+
+#include <cutils/log.h>
+#include <sync/sync.h>
+
+namespace android {
+
+DrmCompositor::DrmCompositor(DrmResources *drm)
+    : drm_(drm),
+      worker_(this),
+      active_composition_(NULL),
+      frame_no_(0),
+      initialized_(false) {
+}
+
+DrmCompositor::~DrmCompositor() {
+  if (initialized_)
+    pthread_mutex_destroy(&lock_);
+}
+
+int DrmCompositor::Init() {
+  int ret = pthread_mutex_init(&lock_, NULL);
+  if (ret) {
+    ALOGE("Failed to initialize drm compositor lock %d\n", ret);
+    return ret;
+  }
+  ret = worker_.Init();
+  if (ret) {
+    pthread_mutex_destroy(&lock_);
+    ALOGE("Failed to initialize compositor worker %d\n", ret);
+    return ret;
+  }
+
+  initialized_ = true;
+  return 0;
+}
+
+Composition *DrmCompositor::CreateComposition(Importer *importer) {
+  DrmComposition *composition = new DrmComposition(drm_, importer, frame_no_++);
+  if (!composition) {
+    ALOGE("Failed to allocate drm composition");
+    return NULL;
+  }
+  int ret = composition->Init();
+  if (ret) {
+    ALOGE("Failed to initialize drm composition %d", ret);
+    delete composition;
+    return NULL;
+  }
+  return composition;
+}
+
+int DrmCompositor::QueueComposition(Composition *composition) {
+  int ret = pthread_mutex_lock(&lock_);
+  if (ret) {
+    ALOGE("Failed to acquire compositor lock %d", ret);
+    return ret;
+  }
+
+  composite_queue_.push((DrmComposition *)composition);
+
+  ret = pthread_mutex_unlock(&lock_);
+  if (ret) {
+    ALOGE("Failed to release compositor lock %d", ret);
+    return ret;
+  }
+
+  worker_.Signal();
+  return 0;
+}
+
+int DrmCompositor::PerformModeset(DrmCompositionLayerMap_t::iterator begin,
+                                  DrmCompositionLayerMap_t::iterator end) {
+  DrmCompositionLayer *layer = NULL;
+  for (DrmCompositionLayerMap_t::iterator iter = begin; iter != end; ++iter) {
+    if (iter->second.layer.compositionType == HWC_FRAMEBUFFER_TARGET) {
+      layer = &iter->second;
+      break;
+    }
+  }
+  int display = begin->first;
+  if (!layer) {
+    ALOGE("Could not find target framebuffer for display %d", display);
+    return -ENOENT;
+  }
+
+  drmModeModeInfo m;
+  DrmConnector *connector = drm_->GetConnectorForDisplay(display);
+  connector->active_mode().ToModeModeInfo(&m);
+
+  uint32_t connectors = connector->id();
+  int ret = drmModeSetCrtc(drm_->fd(), layer->crtc->id(), layer->bo.fb_id, 0, 0,
+                           &connectors, 1, &m);
+  if (ret)
+    ALOGE("Failed set crtc for disp %d/%d", display, ret);
+  else
+    layer->crtc->set_requires_modeset(false);
+
+  return ret;
+}
+
+int DrmCompositor::CompositeDisplay(DrmCompositionLayerMap_t::iterator begin,
+                                    DrmCompositionLayerMap_t::iterator end) {
+  int ret = 0;
+  // Wait for all acquire fences to signal
+  for (DrmCompositionLayerMap_t::iterator iter = begin; iter != end; ++iter) {
+    hwc_layer_1_t *layer = &iter->second.layer;
+
+    if (layer->acquireFenceFd < 0)
+      continue;
+
+    ret = sync_wait(layer->acquireFenceFd, -1);
+    if (ret) {
+      ALOGE("Failed to wait for acquire %d/%d", layer->acquireFenceFd, ret);
+      return ret;
+    }
+    close(layer->acquireFenceFd);
+    layer->acquireFenceFd = -1;
+  }
+
+  DrmCrtc *crtc = begin->second.crtc;
+  if (crtc->requires_modeset()) {
+    ret = PerformModeset(begin, end);
+    if (ret)
+      ALOGE("Failed modeset on display %d", begin->first);
+    return ret;
+  }
+
+  drmModePropertySetPtr pset = drmModePropertySetAlloc();
+  if (!pset) {
+    ALOGE("Failed to allocate property set");
+    return -ENOMEM;
+  }
+
+  for (DrmCompositionLayerMap_t::iterator iter = begin; iter != end; ++iter) {
+    DrmCompositionLayer_t *comp = &iter->second;
+    hwc_layer_1_t *layer = &comp->layer;
+    DrmPlane *plane = comp->plane;
+
+    ret =
+        drmModePropertySetAdd(pset, plane->id(), plane->crtc_property().id(),
+                              crtc->id()) ||
+        drmModePropertySetAdd(pset, plane->id(), plane->fb_property().id(),
+                              comp->bo.fb_id) ||
+        drmModePropertySetAdd(pset, plane->id(), plane->crtc_x_property().id(),
+                              layer->displayFrame.left) ||
+        drmModePropertySetAdd(pset, plane->id(), plane->crtc_y_property().id(),
+                              layer->displayFrame.top) ||
+        drmModePropertySetAdd(
+            pset, plane->id(), plane->crtc_w_property().id(),
+            layer->displayFrame.right - layer->displayFrame.left) ||
+        drmModePropertySetAdd(
+            pset, plane->id(), plane->crtc_h_property().id(),
+            layer->displayFrame.bottom - layer->displayFrame.top) ||
+        drmModePropertySetAdd(pset, plane->id(), plane->src_x_property().id(),
+                              layer->sourceCropf.left) ||
+        drmModePropertySetAdd(pset, plane->id(), plane->src_y_property().id(),
+                              layer->sourceCropf.top) ||
+        drmModePropertySetAdd(
+            pset, plane->id(), plane->src_w_property().id(),
+            (int)(layer->sourceCropf.right - layer->sourceCropf.left) << 16) ||
+        drmModePropertySetAdd(
+            pset, plane->id(), plane->src_h_property().id(),
+            (int)(layer->sourceCropf.bottom - layer->sourceCropf.top) << 16);
+    if (ret) {
+      ALOGE("Failed to add plane %d to set", plane->id());
+      break;
+    }
+  }
+
+  if (!ret) {
+    ret = drmModePropertySetCommit(drm_->fd(), 0, drm_, pset);
+    if (ret)
+      ALOGE("Failed to commit pset ret=%d\n", ret);
+  }
+  if (pset)
+    drmModePropertySetFree(pset);
+
+  return ret;
+}
+
+int DrmCompositor::Composite() {
+  int ret = pthread_mutex_lock(&lock_);
+  if (ret) {
+    ALOGE("Failed to acquire compositor lock %d", ret);
+    return ret;
+  }
+  if (composite_queue_.empty()) {
+    ret = pthread_mutex_unlock(&lock_);
+    if (ret)
+      ALOGE("Failed to release compositor lock %d", ret);
+    return ret;
+  }
+
+  DrmComposition *composition = composite_queue_.front();
+  composite_queue_.pop();
+
+  ret = pthread_mutex_unlock(&lock_);
+  if (ret) {
+    ALOGE("Failed to release compositor lock %d", ret);
+    return ret;
+  }
+
+  DrmCompositionLayerMap_t *map = composition->GetCompositionMap();
+  for (DrmResources::ConnectorIter iter = drm_->begin_connectors();
+       iter != drm_->end_connectors(); ++iter) {
+    int display = (*iter)->display();
+    std::pair<DrmCompositionLayerMap_t::iterator,
+              DrmCompositionLayerMap_t::iterator> layer_iters =
+        map->equal_range(display);
+
+    if (layer_iters.first != layer_iters.second) {
+      ret = CompositeDisplay(layer_iters.first, layer_iters.second);
+      if (ret) {
+        ALOGE("Composite failed for display %d:", display);
+        break;
+      }
+    }
+  }
+
+  if (active_composition_) {
+    active_composition_->FinishComposition();
+    delete active_composition_;
+  }
+  active_composition_ = composition;
+  return ret;
+}
+
+bool DrmCompositor::HaveQueuedComposites() const {
+  int ret = pthread_mutex_lock(&lock_);
+  if (ret) {
+    ALOGE("Failed to acquire compositor lock %d", ret);
+    return false;
+  }
+
+  bool empty_ret = !composite_queue_.empty();
+
+  ret = pthread_mutex_unlock(&lock_);
+  if (ret) {
+    ALOGE("Failed to release compositor lock %d", ret);
+    return false;
+  }
+
+  return empty_ret;
+}
+}
diff --git a/drmcompositor.h b/drmcompositor.h
new file mode 100644
index 0000000..6b92a22
--- /dev/null
+++ b/drmcompositor.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_DRM_COMPOSITOR_H_
+#define ANDROID_DRM_COMPOSITOR_H_
+
+#include "compositor.h"
+#include "drm_hwcomposer.h"
+#include "drmcomposition.h"
+#include "drmcompositorworker.h"
+#include "drmplane.h"
+#include "importer.h"
+
+#include <pthread.h>
+#include <queue>
+
+#include <hardware/hardware.h>
+#include <hardware/hwcomposer.h>
+
+namespace android {
+
+class Drm;
+
+class DrmCompositor : public Compositor {
+ public:
+  DrmCompositor(DrmResources *drm);
+  ~DrmCompositor();
+
+  virtual int Init();
+
+  virtual Targeting *targeting() {
+    return NULL;
+  }
+
+  virtual Composition *CreateComposition(Importer *importer);
+
+  virtual int QueueComposition(Composition *composition);
+  virtual int Composite();
+
+  bool HaveQueuedComposites() const;
+
+ private:
+  DrmCompositor(const DrmCompositor &);
+
+  int CompositeDisplay(DrmCompositionLayerMap_t::iterator begin,
+                       DrmCompositionLayerMap_t::iterator end);
+  int PerformModeset(DrmCompositionLayerMap_t::iterator begin,
+                     DrmCompositionLayerMap_t::iterator end);
+
+  DrmResources *drm_;
+
+  DrmCompositorWorker worker_;
+
+  std::queue<DrmComposition *> composite_queue_;
+  DrmComposition *active_composition_;
+
+  uint64_t frame_no_;
+
+  bool initialized_;
+
+  // mutable since we need to acquire in HaveQueuedComposites
+  mutable pthread_mutex_t lock_;
+};
+}
+
+#endif  // ANDROID_DRM_COMPOSITOR_H_
diff --git a/drmcompositorworker.cpp b/drmcompositorworker.cpp
new file mode 100644
index 0000000..9406194
--- /dev/null
+++ b/drmcompositorworker.cpp
@@ -0,0 +1,71 @@
+/*
+ * 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-compositor-worker"
+
+#include "drmcompositor.h"
+#include "drmcompositorworker.h"
+#include "worker.h"
+
+#include <stdlib.h>
+
+#include <cutils/log.h>
+#include <hardware/hardware.h>
+
+namespace android {
+
+DrmCompositorWorker::DrmCompositorWorker(DrmCompositor *compositor)
+    : Worker("drm-compositor", HAL_PRIORITY_URGENT_DISPLAY),
+      compositor_(compositor) {
+}
+
+DrmCompositorWorker::~DrmCompositorWorker() {
+}
+
+int DrmCompositorWorker::Init() {
+  return InitWorker();
+}
+
+void DrmCompositorWorker::Routine() {
+  int ret;
+  if (!compositor_->HaveQueuedComposites()) {
+    ret = Lock();
+    if (ret) {
+      ALOGE("Failed to lock worker, %d", ret);
+      return;
+    }
+
+    int wait_ret = WaitForSignalOrExitLocked();
+
+    ret = Unlock();
+    if (ret) {
+      ALOGE("Failed to unlock worker, %d", ret);
+      return;
+    }
+
+    if (wait_ret == -EINTR) {
+      return;
+    } else if (wait_ret) {
+      ALOGE("Failed to wait for signal, %d", wait_ret);
+      return;
+    }
+  }
+
+  ret = compositor_->Composite();
+  if (ret)
+    ALOGE("Failed to composite! %d", ret);
+}
+}
diff --git a/drmcompositorworker.h b/drmcompositorworker.h
new file mode 100644
index 0000000..8b485bf
--- /dev/null
+++ b/drmcompositorworker.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_DRM_COMPOSITOR_WORKER_H_
+#define ANDROID_DRM_COMPOSITOR_WORKER_H_
+
+#include "worker.h"
+
+namespace android {
+
+class DrmCompositor;
+
+class DrmCompositorWorker : public Worker {
+ public:
+  DrmCompositorWorker(DrmCompositor *compositor);
+  ~DrmCompositorWorker();
+
+  int Init();
+
+ protected:
+  virtual void Routine();
+
+  DrmCompositor *compositor_;
+};
+}
+
+#endif
diff --git a/drmresources.cpp b/drmresources.cpp
index 3da0f04..3429abc 100644
--- a/drmresources.cpp
+++ b/drmresources.cpp
@@ -33,7 +33,7 @@
 
 namespace android {
 
-DrmResources::DrmResources() : fd_(-1), mode_id_(0) {
+DrmResources::DrmResources() : fd_(-1), mode_id_(0), compositor_(this) {
 }
 
 DrmResources::~DrmResources() {
@@ -235,7 +235,7 @@
   if (ret)
     return ret;
 
-  return 0;
+  return compositor_.Init();
 }
 
 int DrmResources::fd() const {
@@ -383,6 +383,10 @@
   return 0;
 }
 
+DrmCompositor *DrmResources::compositor() {
+  return &compositor_;
+}
+
 int DrmResources::GetProperty(uint32_t obj_id, uint32_t obj_type,
                               const char *prop_name, DrmProperty *property) {
   drmModeObjectPropertiesPtr props;
diff --git a/drmresources.h b/drmresources.h
index f329bd9..1261956 100644
--- a/drmresources.h
+++ b/drmresources.h
@@ -17,6 +17,7 @@
 #ifndef ANDROID_DRM_H_
 #define ANDROID_DRM_H_
 
+#include "drmcompositor.h"
 #include "drmconnector.h"
 #include "drmcrtc.h"
 #include "drmencoder.h"
@@ -46,6 +47,7 @@
   DrmConnector *GetConnectorForDisplay(int display) const;
   DrmCrtc *GetCrtcForDisplay(int display) const;
   DrmPlane *GetPlane(uint32_t id) const;
+  DrmCompositor *compositor();
 
   int GetPlaneProperty(const DrmPlane &plane, const char *prop_name,
                        DrmProperty *property);
@@ -68,6 +70,7 @@
   std::vector<DrmEncoder *> encoders_;
   std::vector<DrmCrtc *> crtcs_;
   std::vector<DrmPlane *> planes_;
+  DrmCompositor compositor_;
 };
 }
 
diff --git a/hwcomposer.cpp b/hwcomposer.cpp
index 06c0931..a809c8b 100644
--- a/hwcomposer.cpp
+++ b/hwcomposer.cpp
@@ -38,8 +38,6 @@
 #include <sw_sync.h>
 #include <sync/sync.h>
 
-#define ARRAY_SIZE(arr) (int)(sizeof(arr) / sizeof((arr)[0]))
-
 #define UM_PER_INCH 25400
 
 namespace android {
@@ -57,16 +55,6 @@
 
   std::vector<uint32_t> config_ids;
 
-  struct hwc_worker set_worker;
-
-  std::list<struct hwc_drm_bo> buf_queue;
-  struct hwc_drm_bo front;
-  pthread_mutex_t flip_lock;
-  pthread_cond_t flip_cond;
-
-  int timeline_fd;
-  unsigned timeline_next;
-
   bool enable_vsync_events;
   unsigned int vsync_sequence;
 } hwc_drm_display_t;
@@ -93,61 +81,72 @@
   Importer *importer;
 };
 
-static int hwc_prepare_layer(hwc_layer_1_t *layer) {
-  /* TODO: We can't handle background right now, defer to sufaceFlinger */
-  if (layer->compositionType == HWC_BACKGROUND) {
-    layer->compositionType = HWC_FRAMEBUFFER;
-    ALOGV("Can't handle background layers yet");
-
-    /* TODO: Support sideband compositions */
-  } else if (layer->compositionType == HWC_SIDEBAND) {
-    layer->compositionType = HWC_FRAMEBUFFER;
-    ALOGV("Can't handle sideband content yet");
-  }
-
-  layer->hints = 0;
-
-  /* TODO: Handle cursor by setting compositionType=HWC_CURSOR_OVERLAY */
-  if (layer->flags & HWC_IS_CURSOR_LAYER) {
-    ALOGV("Can't handle async cursors yet");
-  }
-
-  /* TODO: Handle transformations */
-  if (layer->transform) {
-    ALOGV("Can't handle transformations yet");
-  }
-
-  /* TODO: Handle blending & plane alpha*/
-  if (layer->blending == HWC_BLENDING_PREMULT ||
-      layer->blending == HWC_BLENDING_COVERAGE) {
-    ALOGV("Can't handle blending yet");
-  }
-
-  /* TODO: Handle cropping & scaling */
-
-  return 0;
-}
-
-static int hwc_prepare(hwc_composer_device_1_t * /* dev */, size_t num_displays,
+static int hwc_prepare(hwc_composer_device_1_t *dev, size_t num_displays,
                        hwc_display_contents_1_t **display_contents) {
-  /* TODO: Check flags for HWC_GEOMETRY_CHANGED */
+  // XXX: Once we have a GL compositor, just make everything HWC_OVERLAY
+  struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
+  Composition *composition =
+      ctx->drm.compositor()->CreateComposition(ctx->importer);
+  if (!composition) {
+    ALOGE("Drm composition init failed");
+    return -EINVAL;
+  }
 
   for (int i = 0; i < (int)num_displays; ++i) {
     if (!display_contents[i])
       continue;
 
-    for (int j = 0; j < (int)display_contents[i]->numHwLayers; ++j) {
-      int ret = hwc_prepare_layer(&display_contents[i]->hwLayers[j]);
-      if (ret) {
-        ALOGE("Failed to prepare layer %d:%d", j, i);
-        return ret;
-      }
+    int num_layers = display_contents[i]->numHwLayers;
+    int num_planes = composition->GetRemainingLayers(i, num_layers);
+
+    // XXX: Should go away with atomic modeset
+    DrmCrtc *crtc = ctx->drm.GetCrtcForDisplay(i);
+    if (!crtc) {
+      ALOGE("No crtc for display %d", i);
+      delete composition;
+      return -ENODEV;
+    }
+    if (crtc->requires_modeset())
+      num_planes = 0;
+
+    for (int j = std::max(0, num_layers - num_planes); j < num_layers; j++) {
+      if (j >= num_planes)
+        break;
+
+      hwc_layer_1_t *layer = &display_contents[i]->hwLayers[j];
+      if (layer->compositionType == HWC_FRAMEBUFFER)
+        layer->compositionType = HWC_OVERLAY;
     }
   }
 
+  delete composition;
   return 0;
 }
 
+static void hwc_set_cleanup(size_t num_displays,
+                            hwc_display_contents_1_t **display_contents,
+                            Composition *composition) {
+  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;
+    }
+  }
+
+  delete composition;
+}
+
 static int hwc_queue_vblank_event(struct hwc_drm_display *hd) {
   DrmCrtc *crtc = hd->ctx->drm.GetCrtcForDisplay(hd->display);
   if (!crtc) {
@@ -199,29 +198,6 @@
   hd->ctx->procs->vsync(hd->ctx->procs, hd->display, timestamp);
 }
 
-static void hwc_flip_event_handler(int /* fd */, unsigned int /* sequence */,
-                                   unsigned int /* tv_sec */,
-                                   unsigned int /* tv_usec */,
-                                   void *user_data) {
-  struct hwc_drm_display *hd = (struct hwc_drm_display *)user_data;
-
-  int ret = pthread_mutex_lock(&hd->flip_lock);
-  if (ret) {
-    ALOGE("Failed to lock flip lock ret=%d", ret);
-    return;
-  }
-
-  ret = pthread_cond_signal(&hd->flip_cond);
-  if (ret)
-    ALOGE("Failed to signal flip condition ret=%d", ret);
-
-  ret = pthread_mutex_unlock(&hd->flip_lock);
-  if (ret) {
-    ALOGE("Failed to unlock flip lock ret=%d", ret);
-    return;
-  }
-}
-
 static void *hwc_event_worker(void *arg) {
   setpriority(PRIO_PROCESS, 0, HAL_PRIORITY_URGENT_DISPLAY);
 
@@ -233,7 +209,7 @@
 
     drmEventContext event_context;
     event_context.version = DRM_EVENT_CONTEXT_VERSION;
-    event_context.page_flip_handler = hwc_flip_event_handler;
+    event_context.page_flip_handler = NULL;
     event_context.vblank_handler = hwc_vblank_event_handler;
 
     int ret;
@@ -252,272 +228,95 @@
   return NULL;
 }
 
-static bool hwc_mode_is_equal(drmModeModeInfoPtr a, drmModeModeInfoPtr b) {
-  return a->clock == b->clock && a->hdisplay == b->hdisplay &&
-         a->hsync_start == b->hsync_start && a->hsync_end == b->hsync_end &&
-         a->htotal == b->htotal && a->hskew == b->hskew &&
-         a->vdisplay == b->vdisplay && a->vsync_start == b->vsync_start &&
-         a->vsync_end == b->vsync_end && a->vtotal == b->vtotal &&
-         a->vscan == b->vscan && a->vrefresh == b->vrefresh &&
-         a->flags == b->flags && a->type == b->type &&
-         !strcmp(a->name, b->name);
-}
-
-static int hwc_flip(struct hwc_drm_display *hd, struct hwc_drm_bo *buf) {
-  DrmCrtc *crtc = hd->ctx->drm.GetCrtcForDisplay(hd->display);
-  if (!crtc) {
-    ALOGE("Failed to get crtc for display %d", hd->display);
-    return -ENODEV;
+static int hwc_add_layer(int display, hwc_context_t *ctx, hwc_layer_1_t *layer,
+                         Composition *composition) {
+  hwc_drm_bo_t bo;
+  int ret = ctx->importer->ImportBuffer(layer->handle, &bo);
+  if (ret) {
+    ALOGE("Failed to import handle to bo %d", ret);
+    return ret;
   }
 
-  DrmConnector *connector = hd->ctx->drm.GetConnectorForDisplay(hd->display);
-  if (!connector) {
-    ALOGE("Failed to get connector for display %d", hd->display);
-    return -ENODEV;
-  }
-
-  int ret;
-  if (crtc->requires_modeset()) {
-    drmModeModeInfo drm_mode;
-    connector->active_mode().ToModeModeInfo(&drm_mode);
-    uint32_t connector_id = connector->id();
-    ret = drmModeSetCrtc(hd->ctx->drm.fd(), crtc->id(), buf->fb_id, 0, 0,
-                         &connector_id, 1, &drm_mode);
-    if (ret) {
-      ALOGE("Modeset failed for crtc %d", crtc->id());
-      return ret;
-    }
-    crtc->set_requires_modeset(false);
+  ret = composition->AddLayer(display, layer, &bo);
+  if (!ret)
     return 0;
-  }
 
-  ret = drmModePageFlip(hd->ctx->drm.fd(), crtc->id(), buf->fb_id,
-                        DRM_MODE_PAGE_FLIP_EVENT, hd);
-  if (ret) {
-    ALOGE("Failed to flip buffer for crtc %d", crtc->id());
-    return ret;
-  }
+  int destroy_ret = ctx->importer->ReleaseBuffer(&bo);
+  if (destroy_ret)
+    ALOGE("Failed to destroy buffer %d", destroy_ret);
 
-  ret = pthread_cond_wait(&hd->flip_cond, &hd->flip_lock);
-  if (ret) {
-    ALOGE("Failed to wait on condition %d", ret);
-    return ret;
-  }
-
-  return 0;
-}
-
-static int hwc_wait_and_set(struct hwc_drm_display *hd,
-                            struct hwc_drm_bo *buf) {
-  int ret;
-  if (buf->acquire_fence_fd >= 0) {
-    ret = sync_wait(buf->acquire_fence_fd, -1);
-    close(buf->acquire_fence_fd);
-    buf->acquire_fence_fd = -1;
-    if (ret) {
-      ALOGE("Failed to wait for acquire %d", ret);
-      return ret;
-    }
-  }
-
-  ret = hwc_flip(hd, buf);
-  if (ret) {
-    ALOGE("Failed to perform flip\n");
-    return ret;
-  }
-
-  if (!hd->ctx->importer->ReleaseBuffer(buf)) {
-    struct drm_gem_close args;
-    memset(&args, 0, sizeof(args));
-    for (int i = 0; i < ARRAY_SIZE(hd->front.gem_handles); ++i) {
-      if (!hd->front.gem_handles[i])
-        continue;
-
-      ret = pthread_mutex_lock(&hd->set_worker.lock);
-      if (ret) {
-        ALOGE("Failed to lock set lock in wait_and_set() %d", ret);
-        continue;
-      }
-
-      /* check for duplicate handle in buf_queue */
-      bool found = false;
-      for (std::list<struct hwc_drm_bo>::iterator bi = hd->buf_queue.begin();
-           bi != hd->buf_queue.end(); ++bi)
-        for (int j = 0; j < ARRAY_SIZE(bi->gem_handles); ++j)
-          if (hd->front.gem_handles[i] == bi->gem_handles[j])
-            found = true;
-
-      for (int j = 0; j < ARRAY_SIZE(buf->gem_handles); ++j)
-        if (hd->front.gem_handles[i] == buf->gem_handles[j])
-          found = true;
-
-      if (!found) {
-        args.handle = hd->front.gem_handles[i];
-        drmIoctl(hd->ctx->drm.fd(), DRM_IOCTL_GEM_CLOSE, &args);
-      }
-      if (pthread_mutex_unlock(&hd->set_worker.lock))
-        ALOGE("Failed to unlock set lock in wait_and_set() %d", ret);
-    }
-  }
-
-  hd->front = *buf;
-
-  return ret;
-}
-
-static void *hwc_set_worker(void *arg) {
-  setpriority(PRIO_PROCESS, 0, HAL_PRIORITY_URGENT_DISPLAY);
-
-  struct hwc_drm_display *hd = (struct hwc_drm_display *)arg;
-  int ret = pthread_mutex_lock(&hd->flip_lock);
-  if (ret) {
-    ALOGE("Failed to lock flip lock ret=%d", ret);
-    return NULL;
-  }
-
-  do {
-    ret = pthread_mutex_lock(&hd->set_worker.lock);
-    if (ret) {
-      ALOGE("Failed to lock set lock %d", ret);
-      return NULL;
-    }
-
-    if (hd->set_worker.exit)
-      break;
-
-    if (hd->buf_queue.empty()) {
-      ret = pthread_cond_wait(&hd->set_worker.cond, &hd->set_worker.lock);
-      if (ret) {
-        ALOGE("Failed to wait on condition %d", ret);
-        break;
-      }
-    }
-
-    struct hwc_drm_bo buf;
-    buf = hd->buf_queue.front();
-    hd->buf_queue.pop_front();
-
-    ret = pthread_mutex_unlock(&hd->set_worker.lock);
-    if (ret) {
-      ALOGE("Failed to unlock set lock %d", ret);
-      return NULL;
-    }
-
-    ret = hwc_wait_and_set(hd, &buf);
-    if (ret)
-      ALOGE("Failed to wait and set %d", ret);
-
-    ret = sw_sync_timeline_inc(hd->timeline_fd, 1);
-    if (ret)
-      ALOGE("Failed to increment sync timeline %d", ret);
-  } while (true);
-
-  ret = pthread_mutex_unlock(&hd->set_worker.lock);
-  if (ret)
-    ALOGE("Failed to unlock set lock while exiting %d", ret);
-
-  ret = pthread_mutex_unlock(&hd->flip_lock);
-  if (ret)
-    ALOGE("Failed to unlock flip lock ret=%d", ret);
-
-  return NULL;
-}
-
-static void hwc_close_fences(hwc_display_contents_1_t *display_contents) {
-  for (int i = 0; i < (int)display_contents->numHwLayers; ++i) {
-    hwc_layer_1_t *layer = &display_contents->hwLayers[i];
-    if (layer->acquireFenceFd >= 0) {
-      close(layer->acquireFenceFd);
-      layer->acquireFenceFd = -1;
-    }
-  }
-  if (display_contents->outbufAcquireFenceFd >= 0) {
-    close(display_contents->outbufAcquireFenceFd);
-    display_contents->outbufAcquireFenceFd = -1;
-  }
-}
-
-static int hwc_set_display(hwc_context_t *ctx, int display,
-                           hwc_display_contents_1_t *display_contents) {
-  struct hwc_drm_display *hd = &ctx->displays[display];
-  DrmCrtc *crtc = hd->ctx->drm.GetCrtcForDisplay(display);
-  if (!crtc) {
-    ALOGE("There is no active crtc for display %d", display);
-    hwc_close_fences(display_contents);
-    return -ENOENT;
-  }
-
-  /*
-   * TODO: We can only support one hw layer atm, so choose either the
-   * first one or the framebuffer target.
-   */
-  hwc_layer_1_t *layer = NULL;
-  if (!display_contents->numHwLayers) {
-    return 0;
-  } else if (display_contents->numHwLayers == 1) {
-    layer = &display_contents->hwLayers[0];
-  } else {
-    int i;
-    for (i = 0; i < (int)display_contents->numHwLayers; ++i) {
-      layer = &display_contents->hwLayers[i];
-      if (layer->compositionType == HWC_FRAMEBUFFER_TARGET)
-        break;
-    }
-    if (i == (int)display_contents->numHwLayers) {
-      ALOGE("Could not find a suitable layer for display %d", display);
-    }
-  }
-
-  int ret = pthread_mutex_lock(&hd->set_worker.lock);
-  if (ret) {
-    ALOGE("Failed to lock set lock in set() %d", ret);
-    hwc_close_fences(display_contents);
-    return ret;
-  }
-
-  struct hwc_drm_bo buf;
-  ret = ctx->importer->ImportBuffer(layer->handle, &buf);
-  if (ret) {
-    ALOGE("Failed to import handle to drm bo %d", ret);
-    hwc_close_fences(display_contents);
-    return ret;
-  }
-  buf.acquire_fence_fd = layer->acquireFenceFd;
-  layer->acquireFenceFd = -1;
-
-  /*
-   * TODO: Retire and release can use the same sync point here b/c hwc is
-   * restricted to one layer. Once that is no longer true, this will need
-   * to change
-   */
-  ++hd->timeline_next;
-  display_contents->retireFenceFd = sw_sync_fence_create(
-      hd->timeline_fd, "drm_hwc_retire", hd->timeline_next);
-  layer->releaseFenceFd = sw_sync_fence_create(
-      hd->timeline_fd, "drm_hwc_release", hd->timeline_next);
-  hd->buf_queue.push_back(buf);
-
-  ret = pthread_cond_signal(&hd->set_worker.cond);
-  if (ret)
-    ALOGE("Failed to signal set worker %d", ret);
-
-  if (pthread_mutex_unlock(&hd->set_worker.lock))
-    ALOGE("Failed to unlock set lock in set()");
-
-  hwc_close_fences(display_contents);
   return ret;
 }
 
 static int hwc_set(hwc_composer_device_1_t *dev, size_t num_displays,
                    hwc_display_contents_1_t **display_contents) {
   struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
-
-  int ret = 0;
-  for (int i = 0; i < (int)num_displays; ++i) {
-    if (display_contents[i])
-      ret = hwc_set_display(ctx, i, display_contents[i]);
+  Composition *composition =
+      ctx->drm.compositor()->CreateComposition(ctx->importer);
+  if (!composition) {
+    ALOGE("Drm composition init failed");
+    hwc_set_cleanup(num_displays, display_contents, NULL);
+    return -EINVAL;
   }
 
+  int ret;
+  for (int i = 0; i < (int)num_displays; ++i) {
+    if (!display_contents[i])
+      continue;
+
+    DrmCrtc *crtc = ctx->drm.GetCrtcForDisplay(i);
+    if (!crtc) {
+      ALOGE("No crtc for display %d", i);
+      hwc_set_cleanup(num_displays, display_contents, composition);
+      return -ENODEV;
+    }
+
+    hwc_display_contents_1_t *dc = display_contents[i];
+    unsigned num_layers = dc->numHwLayers;
+    unsigned num_planes = composition->GetRemainingLayers(i, num_layers);
+    bool use_target = false;
+    // XXX: We don't need to check for modeset required with atomic modeset
+    if (crtc->requires_modeset() || num_layers > num_planes)
+      use_target = true;
+
+    // XXX: Won't need to worry about FB_TARGET with GL Compositor
+    for (int j = 0; use_target && j < (int)num_layers; ++j) {
+      hwc_layer_1_t *layer = &dc->hwLayers[j];
+      if (layer->compositionType != HWC_FRAMEBUFFER_TARGET)
+        continue;
+
+      ret = hwc_add_layer(i, ctx, layer, composition);
+      if (ret) {
+        ALOGE("Add layer failed %d", ret);
+        hwc_set_cleanup(num_displays, display_contents, composition);
+        return ret;
+      }
+      --num_planes;
+      break;
+    }
+
+    for (int j = 0; num_planes && j < (int)num_layers; ++j) {
+      hwc_layer_1_t *layer = &dc->hwLayers[j];
+      if (layer->compositionType != HWC_OVERLAY)
+        continue;
+
+      ret = hwc_add_layer(i, ctx, layer, composition);
+      if (ret) {
+        ALOGE("Add layer failed %d", ret);
+        hwc_set_cleanup(num_displays, display_contents, composition);
+        return ret;
+      }
+      --num_planes;
+    }
+  }
+
+  ret = ctx->drm.compositor()->QueueComposition(composition);
+  if (ret) {
+    ALOGE("Failed to queue the composition");
+    hwc_set_cleanup(num_displays, display_contents, composition);
+    return ret;
+  }
+  hwc_set_cleanup(num_displays, display_contents, NULL);
   return ret;
 }
 
@@ -744,18 +543,9 @@
   return ret;
 }
 
-static void hwc_destroy_display(struct hwc_drm_display *hd) {
-  if (hwc_destroy_worker(&hd->set_worker))
-    ALOGE("Destroy set worker failed");
-}
-
 static int hwc_device_close(struct hw_device_t *dev) {
   struct hwc_context_t *ctx = (struct hwc_context_t *)dev;
 
-  for (hwc_context_t::DisplayMapIter iter = ctx->displays.begin();
-       iter != ctx->displays.end(); ++iter)
-    hwc_destroy_display(&iter->second);
-
   if (hwc_destroy_worker(&ctx->event_worker))
     ALOGE("Destroy event worker failed");
 
@@ -819,65 +609,15 @@
   hd->enable_vsync_events = false;
   hd->vsync_sequence = 0;
 
-  int ret = pthread_mutex_init(&hd->flip_lock, NULL);
-  if (ret) {
-    ALOGE("Failed to initialize flip lock %d", ret);
-    return ret;
-  }
-
-  ret = pthread_cond_init(&hd->flip_cond, NULL);
-  if (ret) {
-    ALOGE("Failed to intiialize flip condition %d", ret);
-    pthread_mutex_destroy(&hd->flip_lock);
-    return ret;
-  }
-
-  ret = sw_sync_timeline_create();
-  if (ret < 0) {
-    ALOGE("Failed to create sw sync timeline %d", ret);
-    pthread_cond_destroy(&hd->flip_cond);
-    pthread_mutex_destroy(&hd->flip_lock);
-    return ret;
-  }
-  hd->timeline_fd = ret;
-
-  /*
-   * Initialize timeline_next to 1, because point 0 will be the very first
-   * set operation. Since we increment every time set() is called,
-   * initializing to 0 would cause an off-by-one error where
-   * surfaceflinger would composite on the front buffer.
-   */
-  hd->timeline_next = 1;
-
-  ret = hwc_set_initial_config(hd);
+  int ret = hwc_set_initial_config(hd);
   if (ret) {
     ALOGE("Failed to set initial config for d=%d ret=%d", display, ret);
-    close(hd->timeline_fd);
-    pthread_cond_destroy(&hd->flip_cond);
-    pthread_mutex_destroy(&hd->flip_lock);
-    return ret;
-  }
-
-  ret = hwc_initialize_worker(&hd->set_worker, hwc_set_worker, hd);
-  if (ret) {
-    ALOGE("Failed to create set worker %d\n", ret);
-    close(hd->timeline_fd);
-    pthread_cond_destroy(&hd->flip_cond);
-    pthread_mutex_destroy(&hd->flip_lock);
     return ret;
   }
 
   return 0;
 }
 
-static void hwc_free_conn_list(drmModeConnectorPtr *conn_list, int num_conn) {
-  for (int i = 0; i < num_conn; ++i) {
-    if (conn_list[i])
-      drmModeFreeConnector(conn_list[i]);
-  }
-  free(conn_list);
-}
-
 static int hwc_enumerate_displays(struct hwc_context_t *ctx) {
   int ret;
   for (DrmResources::ConnectorIter c = ctx->drm.begin_connectors();