Revert "Revert "drm_hwcomposer: have DrmDisplayCompositor do its own OpenGL composition""

This reverts commit cbe9c01336e23a63259db65d22d63d6a697b8813.
diff --git a/drmcomposition.cpp b/drmcomposition.cpp
index 805fd26..f4e8d9d 100644
--- a/drmcomposition.cpp
+++ b/drmcomposition.cpp
@@ -63,26 +63,9 @@
   return 0;
 }
 
-unsigned DrmComposition::GetRemainingLayers(int display,
+unsigned DrmComposition::GetRemainingLayers(int /*display*/,
                                             unsigned num_needed) const {
-  DrmCrtc *crtc = drm_->GetCrtcForDisplay(display);
-  if (!crtc) {
-    ALOGE("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::vector<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);
+  return num_needed;
 }
 
 int DrmComposition::AddLayer(int display, hwc_layer_1_t *layer,
@@ -111,10 +94,6 @@
       break;
     }
   }
-  if (!plane) {
-    ALOGE("Failed to find plane for display %d", display);
-    return -ENOENT;
-  }
   return composition_map_[display]->AddLayer(layer, bo, crtc, plane);
 }
 
diff --git a/drmdisplaycomposition.cpp b/drmdisplaycomposition.cpp
index cce1d56..21a9c2a 100644
--- a/drmdisplaycomposition.cpp
+++ b/drmdisplaycomposition.cpp
@@ -112,6 +112,28 @@
   return 0;
 }
 
+int DrmDisplayComposition::AddLayer(hwc_layer_1_t *layer, DrmCrtc *crtc,
+                                    DrmPlane *plane) {
+  if (layer->transform != 0)
+    return -EINVAL;
+
+  if (!validate_composition_type(DRM_COMPOSITION_TYPE_FRAME))
+    return -EINVAL;
+
+  hwc_drm_bo_t bo;
+  int ret = importer_->ImportBuffer(layer->handle, &bo);
+  if (ret) {
+    ALOGE("Failed to import handle of layer %d", ret);
+    return ret;
+  }
+
+  ret = AddLayer(layer, &bo, crtc, plane);
+  if (ret)
+    importer_->ReleaseBuffer(&bo);
+
+  return ret;
+}
+
 int DrmDisplayComposition::AddDpmsMode(uint32_t dpms_mode) {
   if (!validate_composition_type(DRM_COMPOSITION_TYPE_DPMS))
     return -EINVAL;
diff --git a/drmdisplaycomposition.h b/drmdisplaycomposition.h
index 1df8dee..9c51078 100644
--- a/drmdisplaycomposition.h
+++ b/drmdisplaycomposition.h
@@ -56,6 +56,9 @@
 
   int AddLayer(hwc_layer_1_t *layer, hwc_drm_bo_t *bo, DrmCrtc *crtc,
                DrmPlane *plane);
+  // Like the AddLayer that accepts a hwc_drm_bo_t, but uses Importer to import
+  // the layer->handle itself.
+  int AddLayer(hwc_layer_1_t *layer, DrmCrtc *crtc, DrmPlane *plane);
   int AddPlaneDisable(DrmPlane *plane);
   int AddDpmsMode(uint32_t dpms_mode);
 
diff --git a/drmdisplaycompositor.cpp b/drmdisplaycompositor.cpp
index e0d808f..7f43503 100644
--- a/drmdisplaycompositor.cpp
+++ b/drmdisplaycompositor.cpp
@@ -21,7 +21,9 @@
 #include "drmcrtc.h"
 #include "drmplane.h"
 #include "drmresources.h"
+#include "glworker.h"
 
+#include <algorithm>
 #include <pthread.h>
 #include <sstream>
 #include <stdlib.h>
@@ -42,6 +44,7 @@
       frame_no_(0),
       initialized_(false),
       active_(false),
+      framebuffer_index_(0),
       dump_frames_composited_(0),
       dump_last_timestamp_ns_(0) {
   struct timespec ts;
@@ -132,16 +135,132 @@
   return 0;
 }
 
+static bool drm_composition_layer_has_plane(
+    const DrmCompositionLayer_t &comp_layer) {
+  if (comp_layer.plane != NULL)
+    if (comp_layer.plane->type() == DRM_PLANE_TYPE_OVERLAY ||
+        comp_layer.plane->type() == DRM_PLANE_TYPE_PRIMARY)
+      return true;
+  return false;
+}
+
+static bool drm_composition_layer_has_no_plane(
+    const DrmCompositionLayer_t &comp_layer) {
+  return comp_layer.plane == NULL;
+}
+
+int DrmDisplayCompositor::ApplyPreComposite(
+    DrmDisplayComposition *display_comp) {
+  int ret = 0;
+  DrmCompositionLayerVector_t *layers = display_comp->GetCompositionLayers();
+
+  auto last_layer = find_if(layers->rbegin(), layers->rend(),
+                            drm_composition_layer_has_plane);
+  if (last_layer == layers->rend()) {
+    ALOGE("Frame has no overlays");
+    return -EINVAL;
+  }
+
+  DrmCompositionLayer_t &comp_layer = *last_layer;
+  DrmPlane *stolen_plane = NULL;
+  std::swap(stolen_plane, comp_layer.plane);
+
+  DrmConnector *connector = drm_->GetConnectorForDisplay(display_);
+  if (connector == NULL) {
+    ALOGE("Failed to determine display mode: no connector for display %d",
+          display_);
+    return -ENODEV;
+  }
+
+  const DrmMode &mode = connector->active_mode();
+  DrmFramebuffer &fb = framebuffers_[framebuffer_index_];
+  ret = fb.WaitReleased(-1);
+  if (ret) {
+    ALOGE("Failed to wait for framebuffer release %d", ret);
+    return ret;
+  }
+  fb.set_release_fence_fd(-1);
+  if (!fb.Allocate(mode.h_display(), mode.v_display())) {
+    ALOGE("Failed to allocate framebuffer with size %dx%d", mode.h_display(),
+          mode.v_display());
+    return -ENOMEM;
+  }
+
+  std::vector<hwc_layer_1_t> pre_comp_layers;
+  for (const auto &comp_layer : *layers)
+    if (comp_layer.plane == NULL)
+      pre_comp_layers.push_back(comp_layer.layer);
+
+  if (!pre_compositor_) {
+    pre_compositor_.reset(new GLWorkerCompositor());
+    ret = pre_compositor_->Init();
+    if (ret) {
+      ALOGE("Failed to initialize OpenGL compositor %d", ret);
+      return ret;
+    }
+  }
+  ret = pre_compositor_->CompositeAndFinish(
+      pre_comp_layers.data(), pre_comp_layers.size(), fb.buffer());
+  if (ret) {
+    ALOGE("Failed to composite layers");
+    return ret;
+  }
+
+  layers->erase(std::remove_if(layers->begin(), layers->end(),
+                               drm_composition_layer_has_no_plane),
+                layers->end());
+
+  hwc_layer_1_t pre_comp_output_layer;
+  memset(&pre_comp_output_layer, 0, sizeof(pre_comp_output_layer));
+  pre_comp_output_layer.compositionType = HWC_OVERLAY;
+  pre_comp_output_layer.handle = fb.buffer()->handle;
+  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_comp_output_layer.sourceCropf.top =
+      pre_comp_output_layer.displayFrame.top = 0;
+  pre_comp_output_layer.sourceCropf.left =
+      pre_comp_output_layer.displayFrame.left = 0;
+  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();
+
+  ret = display_comp->AddLayer(&pre_comp_output_layer,
+                               drm_->GetCrtcForDisplay(display_), stolen_plane);
+  if (ret) {
+    ALOGE("Failed to add composited layer %d", ret);
+    return ret;
+  }
+
+  fb.set_release_fence_fd(pre_comp_output_layer.releaseFenceFd);
+  framebuffer_index_ = (framebuffer_index_ + 1) % DRM_DISPLAY_BUFFERS;
+
+  return ret;
+}
+
 int DrmDisplayCompositor::ApplyFrame(DrmDisplayComposition *display_comp) {
   int ret = 0;
 
+  DrmCompositionLayerVector_t *layers = display_comp->GetCompositionLayers();
+  bool use_pre_comp = std::any_of(layers->begin(), layers->end(),
+                                  drm_composition_layer_has_no_plane);
+
+  if (use_pre_comp) {
+    ret = ApplyPreComposite(display_comp);
+    if (ret)
+      return ret;
+  }
+
   drmModePropertySetPtr pset = drmModePropertySetAlloc();
   if (!pset) {
     ALOGE("Failed to allocate property set");
     return -ENOMEM;
   }
 
-  DrmCompositionLayerVector_t *layers = display_comp->GetCompositionLayers();
   for (DrmCompositionLayerVector_t::iterator iter = layers->begin();
        iter != layers->end(); ++iter) {
     hwc_layer_1_t *layer = &iter->layer;
diff --git a/drmdisplaycompositor.h b/drmdisplaycompositor.h
index 9f50664..46d71ae 100644
--- a/drmdisplaycompositor.h
+++ b/drmdisplaycompositor.h
@@ -20,6 +20,7 @@
 #include "drm_hwcomposer.h"
 #include "drmcomposition.h"
 #include "drmcompositorworker.h"
+#include "drmframebuffer.h"
 
 #include <pthread.h>
 #include <queue>
@@ -28,8 +29,12 @@
 #include <hardware/hardware.h>
 #include <hardware/hwcomposer.h>
 
+#define DRM_DISPLAY_BUFFERS 2
+
 namespace android {
 
+class GLWorkerCompositor;
+
 class DrmDisplayCompositor {
  public:
   DrmDisplayCompositor();
@@ -46,6 +51,7 @@
  private:
   DrmDisplayCompositor(const DrmDisplayCompositor &) = delete;
 
+  int ApplyPreComposite(DrmDisplayComposition *display_comp);
   int ApplyFrame(DrmDisplayComposition *display_comp);
   int ApplyDpms(DrmDisplayComposition *display_comp);
 
@@ -62,6 +68,10 @@
   bool initialized_;
   bool active_;
 
+  int framebuffer_index_;
+  DrmFramebuffer framebuffers_[DRM_DISPLAY_BUFFERS];
+  std::unique_ptr<GLWorkerCompositor> pre_compositor_;
+
   // mutable since we need to acquire in HaveQueuedComposites
   mutable pthread_mutex_t lock_;
 
diff --git a/drmframebuffer.h b/drmframebuffer.h
new file mode 100644
index 0000000..6f078d9
--- /dev/null
+++ b/drmframebuffer.h
@@ -0,0 +1,102 @@
+/*
+ * 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_FRAMEBUFFER_
+#define ANDROID_DRM_FRAMEBUFFER_
+
+#include <stdint.h>
+
+#include <sync/sync.h>
+
+#include <ui/GraphicBuffer.h>
+
+namespace android {
+
+struct DrmFramebuffer {
+  DrmFramebuffer() : release_fence_fd_(-1) {
+  }
+
+  ~DrmFramebuffer() {
+    if (release_fence_fd() >= 0)
+      close(release_fence_fd());
+  }
+
+  bool is_valid() {
+    return buffer_ != NULL;
+  }
+
+  sp<GraphicBuffer> buffer() {
+    return buffer_;
+  }
+
+  int release_fence_fd() {
+    return release_fence_fd_;
+  }
+
+  void set_release_fence_fd(int fd) {
+    if (release_fence_fd_ >= 0)
+      close(release_fence_fd_);
+    release_fence_fd_ = fd;
+  }
+
+  bool Allocate(uint32_t w, uint32_t h) {
+    if (is_valid()) {
+      if (buffer_->getWidth() == w && buffer_->getHeight() == h)
+        return true;
+
+      if (release_fence_fd_ >= 0) {
+        if (sync_wait(release_fence_fd_, -1) != 0) {
+          return false;
+        }
+      }
+      Clear();
+    }
+    buffer_ = new GraphicBuffer(w, h, PIXEL_FORMAT_RGBA_8888,
+                                GRALLOC_USAGE_HW_FB | GRALLOC_USAGE_HW_RENDER |
+                                    GRALLOC_USAGE_HW_COMPOSER);
+    release_fence_fd_ = -1;
+    return is_valid();
+  }
+
+  void Clear() {
+    if (!is_valid())
+      return;
+
+    if (release_fence_fd_ >= 0) {
+      close(release_fence_fd_);
+      release_fence_fd_ = -1;
+    }
+
+    buffer_.clear();
+  }
+
+  int WaitReleased(int timeout_milliseconds) {
+    if (!is_valid())
+      return 0;
+    if (release_fence_fd_ < 0)
+      return 0;
+
+    int ret = sync_wait(release_fence_fd_, timeout_milliseconds);
+    return ret;
+  }
+
+ private:
+  sp<GraphicBuffer> buffer_;
+  int release_fence_fd_;
+};
+}
+
+#endif  // ANDROID_DRM_FRAMEBUFFER_
diff --git a/glworker.cpp b/glworker.cpp
index c737c45..e0d337b 100644
--- a/glworker.cpp
+++ b/glworker.cpp
@@ -702,6 +702,14 @@
   return ret;
 }
 
+int GLWorkerCompositor::CompositeAndFinish(hwc_layer_1 *layers,
+                                           size_t num_layers,
+                                           sp<GraphicBuffer> framebuffer) {
+  int ret = Composite(layers, num_layers, framebuffer);
+  glFinish();
+  return ret;
+}
+
 int GLWorker::DoComposition(GLWorkerCompositor &compositor, Work *work) {
   int ret =
       compositor.Composite(work->layers, work->num_layers, work->framebuffer);
diff --git a/glworker.h b/glworker.h
index e9febec..9550cbe 100644
--- a/glworker.h
+++ b/glworker.h
@@ -88,6 +88,8 @@
 
   int Composite(hwc_layer_1 *layers, size_t num_layers,
                 sp<GraphicBuffer> framebuffer);
+  int CompositeAndFinish(hwc_layer_1 *layers, size_t num_layers,
+                         sp<GraphicBuffer> framebuffer);
 
  private:
   EGLDisplay egl_display_;