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/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_;
+}
+}