Revert "drm_hwcomposer: remove GLCompositor and the GLWorker thread"

This reverts commit abebc7a78fe8a4df6495c8e5064719dc92b04004.

For now until we figure out a more stable solution for SF/hwc

Change-Id: I7a505fc67873f943704e8b48db4167b9beca7691
diff --git a/Android.mk b/Android.mk
index ccb230e..eadfe2b 100644
--- a/Android.mk
+++ b/Android.mk
@@ -50,6 +50,7 @@
 	drmmode.cpp \
 	drmplane.cpp \
 	drmproperty.cpp \
+	gl_compositor.cpp \
 	glworker.cpp \
 	hwcomposer.cpp \
 	seperate_rects.cpp \
diff --git a/gl_compositor.cpp b/gl_compositor.cpp
new file mode 100644
index 0000000..0605c04
--- /dev/null
+++ b/gl_compositor.cpp
@@ -0,0 +1,295 @@
+/*
+ * 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 ATRACE_TAG ATRACE_TAG_GRAPHICS
+#define LOG_TAG "GLCompositor"
+
+#include <vector>
+
+#include <cutils/log.h>
+
+#include <ui/GraphicBuffer.h>
+#include <utils/Trace.h>
+
+#include <sync/sync.h>
+#include <sw_sync.h>
+
+#include "drm_hwcomposer.h"
+
+#include "gl_compositor.h"
+#include "glworker.h"
+
+namespace android {
+
+static const char *get_gl_error(void);
+static const char *get_egl_error(void);
+static bool has_extension(const char *extension, const char *extensions);
+
+template <typename T>
+int AllocResource(std::vector<T> &array) {
+  for (typename std::vector<T>::iterator it = array.begin(); it != array.end();
+       ++it) {
+    if (!it->is_some()) {
+      return std::distance(array.begin(), it);
+    }
+  }
+
+  array.push_back(T());
+  return array.size() - 1;
+}
+
+template <typename T>
+void FreeResource(std::vector<T> &array, int index) {
+  if (index == (int)array.size() - 1) {
+    array.pop_back();
+  } else if (index >= 0 && (unsigned)index < array.size()) {
+    array[index].Reset();
+  }
+}
+
+struct GLTarget {
+  sp<GraphicBuffer> fb;
+  bool forgotten;
+  unsigned composition_count;
+
+  GLTarget() : forgotten(true), composition_count(0) {
+  }
+
+  void Reset() {
+    fb.clear();
+    forgotten = true;
+    composition_count = 0;
+  }
+
+  bool is_some() const {
+    return fb != NULL;
+  }
+};
+
+struct GLCompositor::priv_data {
+  int current_target;
+  std::vector<GLTarget> targets;
+  std::vector<GLComposition *> compositions;
+
+  GLWorker worker;
+
+  priv_data() : current_target(-1) {
+  }
+};
+
+class GLComposition : public Composition {
+ public:
+  struct LayerData {
+    hwc_layer_1 layer;
+    hwc_drm_bo bo;
+  };
+
+  GLComposition(GLCompositor *owner, Importer *imp)
+      : compositor(owner), importer(imp), target_handle(-1), timeline_fd(-1) {
+    int ret = sw_sync_timeline_create();
+    if (ret < 0) {
+      ALOGE("Failed to create sw sync timeline %d", ret);
+    }
+    timeline_fd = ret;
+  }
+
+  virtual ~GLComposition() {
+    if (timeline_fd >= 0)
+      close(timeline_fd);
+
+    if (compositor == NULL) {
+      return;
+    }
+
+    // Removes this composition from the owning compositor automatically.
+    std::vector<GLComposition *> &compositions =
+        compositor->priv_->compositions;
+    std::vector<GLComposition *>::iterator it =
+        std::find(compositions.begin(), compositions.end(), this);
+    if (it != compositions.end()) {
+      compositions.erase(it);
+    }
+
+    GLTarget *target = &compositor->priv_->targets[target_handle];
+    target->composition_count--;
+    compositor->CheckAndDestroyTarget(target_handle);
+  }
+
+  virtual int AddLayer(int display, hwc_layer_1 *layer, hwc_drm_bo *bo) {
+    (void)display;
+    if (layer->compositionType != HWC_OVERLAY) {
+      ALOGE("Must add layers with compositionType == HWC_OVERLAY");
+      return 1;
+    }
+
+    if (layer->handle == 0) {
+      ALOGE("Must add layers with valid buffer handle");
+      return 1;
+    }
+
+    layer->releaseFenceFd = sw_sync_fence_create(
+        timeline_fd, "GLComposition release fence", layers.size() + 1);
+
+    layers.push_back(*layer);
+
+    return importer->ReleaseBuffer(bo);
+  }
+
+  virtual unsigned GetRemainingLayers(int display, unsigned num_needed) const {
+    (void)display;
+    return num_needed;
+  }
+
+  GLCompositor *compositor;
+  Importer *importer;
+  int target_handle;
+  int timeline_fd;
+  std::vector<hwc_layer_1> layers;
+};
+
+GLCompositor::GLCompositor() {
+  priv_ = new priv_data;
+}
+
+GLCompositor::~GLCompositor() {
+  for (std::vector<GLComposition *>::iterator it = priv_->compositions.end();
+       it != priv_->compositions.begin(); it = priv_->compositions.end()) {
+    --it;
+
+    // Prevents compositor from trying to erase itself
+    (*it)->compositor = NULL;
+    delete *it;
+    priv_->compositions.erase(it);
+  }
+
+  delete priv_;
+}
+
+int GLCompositor::Init() {
+  return priv_->worker.Init();
+}
+
+Targeting *GLCompositor::targeting() {
+  return (Targeting *)this;
+}
+
+int GLCompositor::CreateTarget(sp<GraphicBuffer> &buffer) {
+  int ret;
+
+  int target_handle = AllocResource(priv_->targets);
+  GLTarget *target = &priv_->targets[target_handle];
+
+  target->fb = buffer;
+  target->forgotten = false;
+
+  return target_handle;
+}
+
+void GLCompositor::SetTarget(int target_handle) {
+  if (target_handle >= 0 && (unsigned)target_handle < priv_->targets.size()) {
+    GLTarget *target = &priv_->targets[target_handle];
+    if (target->is_some()) {
+      priv_->current_target = target_handle;
+      return;
+    }
+  }
+
+  priv_->current_target = -1;
+}
+
+void GLCompositor::ForgetTarget(int target_handle) {
+  if (target_handle >= 0 && (unsigned)target_handle < priv_->targets.size()) {
+    if (target_handle == priv_->current_target) {
+      priv_->current_target = -1;
+    }
+
+    GLTarget *target = &priv_->targets[target_handle];
+    if (target->is_some()) {
+      target->forgotten = true;
+      CheckAndDestroyTarget(target_handle);
+      return;
+    }
+  }
+
+  ALOGE("Failed to forget target because of invalid handle");
+}
+
+void GLCompositor::CheckAndDestroyTarget(int target_handle) {
+  GLTarget *target = &priv_->targets[target_handle];
+  if (target->composition_count == 0 && target->forgotten) {
+    FreeResource(priv_->targets, target_handle);
+  }
+}
+
+Composition *GLCompositor::CreateComposition(Importer *importer) {
+  if (priv_->current_target >= 0 &&
+      (unsigned)priv_->current_target < priv_->targets.size()) {
+    GLTarget *target = &priv_->targets[priv_->current_target];
+    if (target->is_some()) {
+      GLComposition *composition = new GLComposition(this, importer);
+      composition->target_handle = priv_->current_target;
+      target->composition_count++;
+      priv_->compositions.push_back(composition);
+      return composition;
+    }
+  }
+
+  ALOGE("Failed to create composition because of invalid target handle %d",
+        priv_->current_target);
+
+  return NULL;
+}
+
+int GLCompositor::QueueComposition(Composition *composition) {
+  if (composition) {
+    GLComposition *gl_composition = (GLComposition *)composition;
+    int ret = DoComposition(gl_composition);
+    gl_composition->timeline_fd = -1;
+    delete composition;
+    return ret;
+  }
+
+  ALOGE("Failed to queue composition because of invalid composition handle");
+
+  return -EINVAL;
+}
+
+int GLCompositor::Composite() {
+  return 0;
+}
+
+int GLCompositor::DoComposition(GLComposition *composition) {
+  ATRACE_CALL();
+  int ret = 0;
+
+  GLTarget *target = &priv_->targets[composition->target_handle];
+  GLWorker::Work work;
+  work.layers = composition->layers.data();
+  work.num_layers = composition->layers.size();
+  work.timeline_fd = composition->timeline_fd;
+  work.framebuffer = target->fb;
+
+  ret = priv_->worker.DoWork(&work);
+
+  if (work.timeline_fd >= 0) {
+    sw_sync_timeline_inc(work.timeline_fd, work.num_layers + 1);
+    close(work.timeline_fd);
+  }
+
+  return ret;
+}
+
+}  // namespace android
diff --git a/gl_compositor.h b/gl_compositor.h
new file mode 100644
index 0000000..450ca67
--- /dev/null
+++ b/gl_compositor.h
@@ -0,0 +1,61 @@
+/*
+ * 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.
+ */
+
+#include <stdint.h>
+#include <stdint.h>
+#include "compositor.h"
+
+struct hwc_layer_1;
+struct hwc_import_context;
+
+namespace android {
+
+class GLComposition;
+
+class GLCompositor : public Compositor, public Targeting {
+ public:
+  GLCompositor();
+  virtual ~GLCompositor();
+
+  virtual int Init();
+  virtual Targeting *targeting();
+  virtual int CreateTarget(sp<android::GraphicBuffer> &buffer);
+  virtual void SetTarget(int target);
+  virtual void ForgetTarget(int target);
+  virtual Composition *CreateComposition(Importer *importer);
+  virtual int QueueComposition(Composition *composition);
+  virtual int Composite();
+
+ private:
+  struct priv_data;
+  struct texture_from_handle;
+
+  struct priv_data *priv_;
+
+  int BeginContext();
+  int EndContext();
+  int GenerateShaders();
+  int DoComposition(GLComposition *composition);
+  int DoFenceWait(int acquireFenceFd);
+  int CreateTextureFromHandle(buffer_handle_t handle,
+                              struct texture_from_handle *tex);
+  void DestroyTextureFromHandle(const struct texture_from_handle &tex);
+  void CheckAndDestroyTarget(int target_handle);
+
+  friend GLComposition;
+};
+
+}  // namespace android
diff --git a/glworker.cpp b/glworker.cpp
index df6a8f2..e0d337b 100644
--- a/glworker.cpp
+++ b/glworker.cpp
@@ -23,6 +23,9 @@
 
 #include <sys/resource.h>
 
+#include <sync/sync.h>
+#include <sw_sync.h>
+
 #include <hardware/hardware.h>
 #include <hardware/hwcomposer.h>
 
@@ -707,4 +710,193 @@
   return ret;
 }
 
+int GLWorker::DoComposition(GLWorkerCompositor &compositor, Work *work) {
+  int ret =
+      compositor.Composite(work->layers, work->num_layers, work->framebuffer);
+
+  int timeline_fd = work->timeline_fd;
+  work->timeline_fd = -1;
+
+  if (ret) {
+    worker_ret_ = ret;
+    glFinish();
+    sw_sync_timeline_inc(timeline_fd, work->num_layers);
+    close(timeline_fd);
+    return pthread_cond_signal(&work_done_cond_);
+  }
+
+  unsigned timeline_count = work->num_layers + 1;
+  worker_ret_ = sw_sync_fence_create(timeline_fd, "GLComposition done fence",
+                                     timeline_count);
+  ret = pthread_cond_signal(&work_done_cond_);
+
+  glFinish();
+
+  sw_sync_timeline_inc(timeline_fd, timeline_count);
+  close(timeline_fd);
+
+  return ret;
+}
+
+GLWorker::GLWorker() : initialized_(false) {
+}
+
+GLWorker::~GLWorker() {
+  if (!initialized_)
+    return;
+
+  if (SignalWorker(NULL, true) != 0 || pthread_join(thread_, NULL) != 0)
+    pthread_kill(thread_, SIGTERM);
+
+  pthread_cond_destroy(&work_ready_cond_);
+  pthread_cond_destroy(&work_done_cond_);
+  pthread_mutex_destroy(&lock_);
+}
+
+#define TRY(x, n, g)                  \
+  ret = x;                            \
+  if (ret) {                          \
+    ALOGE("Failed to " n " %d", ret); \
+    g;                                \
+  }
+
+#define TRY_RETURN(x, n) TRY(x, n, return ret)
+
+int GLWorker::Init() {
+  int ret = 0;
+
+  worker_work_ = NULL;
+  worker_exit_ = false;
+  worker_ret_ = -1;
+
+  ret = pthread_cond_init(&work_ready_cond_, NULL);
+  if (ret) {
+    ALOGE("Failed to int GLThread condition %d", ret);
+    return ret;
+  }
+
+  ret = pthread_cond_init(&work_done_cond_, NULL);
+  if (ret) {
+    ALOGE("Failed to int GLThread condition %d", ret);
+    pthread_cond_destroy(&work_ready_cond_);
+    return ret;
+  }
+
+  ret = pthread_mutex_init(&lock_, NULL);
+  if (ret) {
+    ALOGE("Failed to init GLThread lock %d", ret);
+    pthread_cond_destroy(&work_ready_cond_);
+    pthread_cond_destroy(&work_done_cond_);
+    return ret;
+  }
+
+  ret = pthread_create(&thread_, NULL, StartRoutine, this);
+  if (ret) {
+    ALOGE("Failed to create GLThread %d", ret);
+    pthread_cond_destroy(&work_ready_cond_);
+    pthread_cond_destroy(&work_done_cond_);
+    pthread_mutex_destroy(&lock_);
+    return ret;
+  }
+
+  initialized_ = true;
+
+  TRY_RETURN(pthread_mutex_lock(&lock_), "lock GLThread");
+
+  while (!worker_exit_ && worker_ret_ != 0)
+    TRY(pthread_cond_wait(&work_done_cond_, &lock_), "wait on condition",
+        goto out_unlock);
+
+  ret = worker_ret_;
+
+out_unlock:
+  int unlock_ret = pthread_mutex_unlock(&lock_);
+  if (unlock_ret) {
+    ret = unlock_ret;
+    ALOGE("Failed to unlock GLThread %d", unlock_ret);
+  }
+  return ret;
+}
+
+int GLWorker::SignalWorker(Work *work, bool worker_exit) {
+  int ret = 0;
+  if (worker_exit_)
+    return -EINVAL;
+  TRY_RETURN(pthread_mutex_lock(&lock_), "lock GLThread");
+  worker_work_ = work;
+  worker_exit_ = worker_exit;
+  ret = pthread_cond_signal(&work_ready_cond_);
+  if (ret) {
+    ALOGE("Failed to signal GLThread caller %d", ret);
+    pthread_mutex_unlock(&lock_);
+    return ret;
+  }
+  ret = pthread_cond_wait(&work_done_cond_, &lock_);
+  if (ret) {
+    ALOGE("Failed to wait on GLThread %d", ret);
+    pthread_mutex_unlock(&lock_);
+    return ret;
+  }
+
+  ret = worker_ret_;
+  if (ret) {
+    pthread_mutex_unlock(&lock_);
+    return ret;
+  }
+  TRY_RETURN(pthread_mutex_unlock(&lock_), "unlock GLThread");
+  return ret;
+}
+
+int GLWorker::DoWork(Work *work) {
+  return SignalWorker(work, false);
+}
+
+void GLWorker::WorkerRoutine() {
+  int ret = 0;
+
+  TRY(pthread_mutex_lock(&lock_), "lock GLThread", return );
+
+  GLWorkerCompositor compositor;
+
+  TRY(compositor.Init(), "initialize GL", goto out_signal_done);
+
+  worker_ret_ = 0;
+  TRY(pthread_cond_signal(&work_done_cond_), "signal GLThread caller",
+      goto out_signal_done);
+
+  while (true) {
+    while (worker_work_ == NULL && !worker_exit_)
+      TRY(pthread_cond_wait(&work_ready_cond_, &lock_), "wait on condition",
+          goto out_signal_done);
+
+    if (worker_exit_) {
+      ret = 0;
+      break;
+    }
+
+    ret = DoComposition(compositor, worker_work_);
+
+    worker_work_ = NULL;
+    if (ret) {
+      break;
+    }
+  }
+
+out_signal_done:
+  worker_exit_ = true;
+  worker_ret_ = ret;
+  TRY(pthread_cond_signal(&work_done_cond_), "signal GLThread caller",
+      goto out_unlock);
+out_unlock:
+  TRY(pthread_mutex_unlock(&lock_), "unlock GLThread", return );
+}
+
+/* static */
+void *GLWorker::StartRoutine(void *arg) {
+  setpriority(PRIO_PROCESS, 0, HAL_PRIORITY_URGENT_DISPLAY);
+  GLWorker *worker = (GLWorker *)arg;
+  worker->WorkerRoutine();
+  return NULL;
+}
+
 }  // namespace android
diff --git a/glworker.h b/glworker.h
index 8252b62..9550cbe 100644
--- a/glworker.h
+++ b/glworker.h
@@ -17,6 +17,8 @@
 #ifndef ANDROID_GL_WORKER_H_
 #define ANDROID_GL_WORKER_H_
 
+#include <pthread.h>
+
 #include <memory>
 #include <vector>
 
@@ -96,6 +98,44 @@
   std::vector<AutoGLProgram> blend_programs_;
   AutoGLBuffer vertex_buffer_;
 };
+
+class GLWorker {
+ public:
+  struct Work {
+    hwc_layer_1 *layers;
+    size_t num_layers;
+    int timeline_fd;
+    sp<GraphicBuffer> framebuffer;
+
+    Work() = default;
+    Work(const Work &rhs) = delete;
+  };
+
+  GLWorker();
+  ~GLWorker();
+
+  int Init();
+
+  int DoWork(Work *work);
+
+ private:
+  bool initialized_;
+  pthread_t thread_;
+  pthread_mutex_t lock_;
+  pthread_cond_t work_ready_cond_;
+  pthread_cond_t work_done_cond_;
+  Work *worker_work_;
+  bool work_ready_;
+  bool worker_exit_;
+  int worker_ret_;
+
+  void WorkerRoutine();
+  int DoComposition(GLWorkerCompositor &compositor, Work *work);
+
+  int SignalWorker(Work *work, bool worker_exit);
+
+  static void *StartRoutine(void *arg);
+};
 }
 
 #endif
diff --git a/hwcomposer.cpp b/hwcomposer.cpp
index b4b1a50..18f6921 100644
--- a/hwcomposer.cpp
+++ b/hwcomposer.cpp
@@ -19,6 +19,7 @@
 
 #include "drm_hwcomposer.h"
 #include "drmresources.h"
+#include "gl_compositor.h"
 #include "importer.h"
 #include "vsyncworker.h"
 
@@ -37,6 +38,10 @@
 #include <cutils/properties.h>
 #include <hardware/hardware.h>
 #include <hardware/hwcomposer.h>
+#include <sw_sync.h>
+#include <sync/sync.h>
+#include <ui/GraphicBuffer.h>
+#include <ui/PixelFormat.h>
 #include <utils/Trace.h>
 
 #define UM_PER_INCH 25400
@@ -44,6 +49,80 @@
 
 namespace android {
 
+struct hwc_drm_display_framebuffer {
+  hwc_drm_display_framebuffer() : release_fence_fd_(-1) {
+  }
+
+  ~hwc_drm_display_framebuffer() {
+    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, android::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_;
+};
+
+
 typedef struct hwc_drm_display {
   struct hwc_context_t *ctx;
   int display;
@@ -51,6 +130,9 @@
   std::vector<uint32_t> config_ids;
 
   VSyncWorker vsync_worker;
+
+  hwc_drm_display_framebuffer fb_chain[HWC_FB_BUFFERS];
+  int fb_idx;
 } hwc_drm_display_t;
 
 struct hwc_context_t {
@@ -71,6 +153,7 @@
   DisplayMap displays;
   DrmResources drm;
   Importer *importer;
+  GLCompositor pre_compositor;
 };
 
 static void hwc_dump(struct hwc_composer_device_1* dev, char *buff,
@@ -197,9 +280,12 @@
     }
 
     unsigned num_planes = composition->GetRemainingLayers(i, num_layers);
+    bool use_pre_compositor = false;
 
     if (num_layers > num_planes) {
-      ALOGE("Can not composite %u with only %u planes", num_layers, num_planes);
+      use_pre_compositor = true;
+      // Reserve one of the planes for the result of the pre compositor.
+      num_planes--;
     }
 
     for (j = 0; num_planes && j < (int)num_dc_layers; ++j) {
@@ -219,6 +305,123 @@
 
       --num_planes;
     }
+
+    int last_comp_layer = j;
+
+    if (use_pre_compositor) {
+      hwc_drm_display_t *hd = &ctx->displays[i];
+      struct hwc_drm_display_framebuffer *fb = &hd->fb_chain[hd->fb_idx];
+      ret = fb->WaitReleased(-1);
+      if (ret) {
+        ALOGE("Failed to wait for framebuffer %d", ret);
+        hwc_set_cleanup(num_displays, display_contents, composition);
+        return ret;
+      }
+
+      DrmConnector *connector = ctx->drm.GetConnectorForDisplay(i);
+      if (!connector) {
+        ALOGE("No connector for display %d", i);
+        hwc_set_cleanup(num_displays, display_contents, composition);
+        return -ENODEV;
+      }
+
+      const DrmMode &mode = connector->active_mode();
+      if (!fb->Allocate(mode.h_display(), mode.v_display())) {
+        ALOGE("Failed to allocate framebuffer with size %dx%d",
+              mode.h_display(), mode.v_display());
+        hwc_set_cleanup(num_displays, display_contents, composition);
+        return -EINVAL;
+      }
+
+      sp<GraphicBuffer> fb_buffer = fb->buffer();
+      if (fb_buffer == NULL) {
+        ALOGE("Framebuffer is NULL");
+        hwc_set_cleanup(num_displays, display_contents, composition);
+        return -EINVAL;
+      }
+
+      Targeting *targeting = ctx->pre_compositor.targeting();
+      if (targeting == NULL) {
+        ALOGE("Pre-compositor does not support targeting");
+        hwc_set_cleanup(num_displays, display_contents, composition);
+        return -EINVAL;
+      }
+
+      int target = targeting->CreateTarget(fb_buffer);
+      targeting->SetTarget(target);
+
+      Composition *pre_composition = ctx->pre_compositor.CreateComposition(ctx->importer);
+      if (pre_composition == NULL) {
+        ALOGE("Failed to create pre-composition");
+        targeting->ForgetTarget(target);
+        hwc_set_cleanup(num_displays, display_contents, composition);
+        return -EINVAL;
+      }
+
+      for (j = last_comp_layer; 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)
+          continue;
+        ret = hwc_add_layer(i, ctx, layer, pre_composition);
+        if (ret) {
+          ALOGE("Add layer failed %d", ret);
+          delete pre_composition;
+          targeting->ForgetTarget(target);
+          hwc_set_cleanup(num_displays, display_contents, composition);
+          return ret;
+        }
+      }
+
+      ret = ctx->pre_compositor.QueueComposition(pre_composition);
+      pre_composition = NULL;
+
+      targeting->ForgetTarget(target);
+      if (ret < 0 && ret != -EALREADY) {
+        ALOGE("Pre-composition failed %d", ret);
+        hwc_set_cleanup(num_displays, display_contents, composition);
+        return ret;
+      }
+
+      for (j = last_comp_layer; 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)
+          continue;
+        layer->acquireFenceFd = -1;
+      }
+
+      hwc_layer_1_t composite_layer;
+      hwc_rect_t visible_rect;
+      memset(&composite_layer, 0, sizeof(composite_layer));
+      memset(&visible_rect, 0, sizeof(visible_rect));
+
+      composite_layer.compositionType = HWC_OVERLAY;
+      composite_layer.handle = fb_buffer->getNativeBuffer()->handle;
+      composite_layer.sourceCropf.right = composite_layer.displayFrame.right =
+          visible_rect.right = fb_buffer->getWidth();
+      composite_layer.sourceCropf.bottom = composite_layer.displayFrame.bottom =
+          visible_rect.bottom = fb_buffer->getHeight();
+      composite_layer.visibleRegionScreen.numRects = 1;
+      composite_layer.visibleRegionScreen.rects = &visible_rect;
+      composite_layer.acquireFenceFd = ret == -EALREADY ? -1 : ret;
+      // A known invalid fd in case AddLayer does not modify this field.
+      composite_layer.releaseFenceFd = -1;
+      composite_layer.planeAlpha = 0xff;
+
+      ret = hwc_add_layer(i, ctx, &composite_layer, composition);
+      if (ret) {
+        ALOGE("Add layer failed %d", ret);
+        hwc_set_cleanup(num_displays, display_contents, composition);
+        return ret;
+      }
+      hwc_add_layer_to_retire_fence(&composite_layer, dc);
+
+      fb->set_release_fence_fd(composite_layer.releaseFenceFd);
+      hd->fb_idx = (hd->fb_idx + 1) % HWC_FB_BUFFERS;
+    }
   }
 
   ret = ctx->drm.compositor()->QueueComposition(composition);
@@ -459,6 +662,7 @@
   hwc_drm_display_t *hd = &ctx->displays[display];
   hd->ctx = ctx;
   hd->display = display;
+  hd->fb_idx = 0;
 
   int ret = hwc_set_initial_config(hd);
   if (ret) {
@@ -509,6 +713,13 @@
     return ret;
   }
 
+  ret = ctx->pre_compositor.Init();
+  if (ret) {
+    ALOGE("Can't initialize OpenGL Compositor object %d", ret);
+    delete ctx;
+    return ret;
+  }
+
   ctx->importer = Importer::CreateInstance(&ctx->drm);
   if (!ctx->importer) {
     ALOGE("Failed to create importer instance");