Merge "drm_hwcomposer: integrate GLCompositor with hwcomposer" into mnc-dev
diff --git a/compositor.cpp b/compositor.cpp
index 20f860f..3f85dc7 100644
--- a/compositor.cpp
+++ b/compositor.cpp
@@ -16,6 +16,8 @@
 
 #include "compositor.h"
 
+#include <sstream>
+
 namespace android {
 
 Targeting::~Targeting() {
@@ -27,4 +29,7 @@
 Compositor::~Compositor() {
 }
 
+void Compositor::Dump(std::ostringstream */* out */) const {
+}
+
 }  // namespace android
diff --git a/compositor.h b/compositor.h
index b4956b6..e148416 100644
--- a/compositor.h
+++ b/compositor.h
@@ -19,6 +19,8 @@
 
 #include "importer.h"
 
+#include <sstream>
+
 struct hwc_layer_1;
 struct hwc_drm_bo;
 
@@ -98,6 +100,9 @@
   // on a worker thread. Each Composite call handles one composition that was
   // submitted via QueueComposition in FIFO order. Returns 0 on success.
   virtual int Composite() = 0;
+
+  // Dumps state from the Compositor to the out stream
+  virtual void Dump(std::ostringstream *out) const;
 };
 
 }  // namespace android
diff --git a/drm_hwcomposer.h b/drm_hwcomposer.h
index c82506c..cebdbee 100644
--- a/drm_hwcomposer.h
+++ b/drm_hwcomposer.h
@@ -60,6 +60,7 @@
   uint32_t gem_handles[4];
   uint32_t fb_id;
   int acquire_fence_fd;
+  void *priv;
 } hwc_drm_bo_t;
 
 int hwc_import_init(struct hwc_import_context **ctx);
diff --git a/drmcomposition.cpp b/drmcomposition.cpp
index 8fcb12d..07e08da 100644
--- a/drmcomposition.cpp
+++ b/drmcomposition.cpp
@@ -29,7 +29,7 @@
 
 namespace android {
 
-static const bool kUseOverlayPlanes = false;
+static const bool kUseOverlayPlanes = true;
 
 DrmCompositionLayer::DrmCompositionLayer() : crtc(NULL), plane(NULL) {
   memset(&layer, 0, sizeof(layer));
diff --git a/drmcompositor.cpp b/drmcompositor.cpp
index ffca4df..bf95601 100644
--- a/drmcompositor.cpp
+++ b/drmcompositor.cpp
@@ -22,7 +22,9 @@
 #include "drmresources.h"
 
 #include <pthread.h>
+#include <sstream>
 #include <stdlib.h>
+#include <time.h>
 
 #include <cutils/log.h>
 #include <sync/sync.h>
@@ -34,7 +36,13 @@
       worker_(this),
       active_composition_(NULL),
       frame_no_(0),
-      initialized_(false) {
+      initialized_(false),
+      dump_frames_composited_(0),
+      dump_last_timestamp_ns_(0) {
+  struct timespec ts;
+  if (clock_gettime(CLOCK_MONOTONIC, &ts))
+    return;
+  dump_last_timestamp_ns_ = ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec;
 }
 
 DrmCompositor::~DrmCompositor() {
@@ -218,6 +226,7 @@
 
   DrmComposition *composition = composite_queue_.front();
   composite_queue_.pop();
+  ++dump_frames_composited_;
 
   ret = pthread_mutex_unlock(&lock_);
   if (ret) {
@@ -267,4 +276,31 @@
 
   return empty_ret;
 }
+
+void DrmCompositor::Dump(std::ostringstream *out) const {
+  uint64_t cur_ts;
+
+  int ret = pthread_mutex_lock(&lock_);
+  if (ret)
+    return;
+
+  uint64_t num_frames = dump_frames_composited_;
+  dump_frames_composited_ = 0;
+
+  struct timespec ts;
+  ret = clock_gettime(CLOCK_MONOTONIC, &ts);
+
+  ret |= pthread_mutex_unlock(&lock_);
+  if (ret)
+    return;
+
+  cur_ts = ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec;
+  uint64_t num_ms = (cur_ts - dump_last_timestamp_ns_) / (1000 * 1000);
+  unsigned fps = num_ms ? (num_frames * 1000) / (num_ms) : 0;
+
+  *out << "DrmCompositor: num_frames=" << num_frames << " num_ms=" << num_ms <<
+          " fps=" << fps << "\n";
+
+  dump_last_timestamp_ns_ = cur_ts;
+}
 }
diff --git a/drmcompositor.h b/drmcompositor.h
index 6b92a22..ad1316c 100644
--- a/drmcompositor.h
+++ b/drmcompositor.h
@@ -26,6 +26,7 @@
 
 #include <pthread.h>
 #include <queue>
+#include <sstream>
 
 #include <hardware/hardware.h>
 #include <hardware/hwcomposer.h>
@@ -49,6 +50,7 @@
 
   virtual int QueueComposition(Composition *composition);
   virtual int Composite();
+  virtual void Dump(std::ostringstream *out) const;
 
   bool HaveQueuedComposites() const;
 
@@ -73,6 +75,11 @@
 
   // mutable since we need to acquire in HaveQueuedComposites
   mutable pthread_mutex_t lock_;
+
+  // State tracking progress since our last Dump(). These are mutable since
+  // we need to reset them on every Dump() call.
+  mutable uint64_t dump_frames_composited_;
+  mutable uint64_t dump_last_timestamp_ns_;
 };
 }
 
diff --git a/hwcomposer.cpp b/hwcomposer.cpp
index f1d1e1e..6a30fbe 100644
--- a/hwcomposer.cpp
+++ b/hwcomposer.cpp
@@ -154,6 +154,16 @@
   GLCompositor pre_compositor;
 };
 
+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;
+  std::ostringstream out;
+
+  ctx->drm.compositor()->Dump(&out);
+  std::string out_str = out.str();
+  strncpy(buff, out_str.c_str(), std::min((size_t)buff_len, out_str.length()));
+}
+
 static int hwc_prepare(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;
@@ -714,6 +724,7 @@
   ctx->device.common.module = const_cast<hw_module_t *>(module);
   ctx->device.common.close = hwc_device_close;
 
+  ctx->device.dump = hwc_dump;
   ctx->device.prepare = hwc_prepare;
   ctx->device.set = hwc_set;
   ctx->device.eventControl = hwc_event_control;
diff --git a/nvimporter.cpp b/nvimporter.cpp
index d673438..93b9129 100644
--- a/nvimporter.cpp
+++ b/nvimporter.cpp
@@ -20,6 +20,7 @@
 #include "importer.h"
 #include "nvimporter.h"
 
+#include <stdatomic.h>
 #include <xf86drm.h>
 #include <xf86drmMode.h>
 
@@ -70,6 +71,7 @@
   memset(bo, 0, sizeof(hwc_drm_bo_t));
   NvBuffer_t *buf = GrallocGetNvBuffer(handle);
   if (buf) {
+    atomic_fetch_add(&buf->ref, 1);
     *bo = buf->bo;
     return 0;
   }
@@ -79,8 +81,14 @@
     ALOGE("Failed to allocate new NvBuffer_t");
     return -ENOMEM;
   }
+  buf->bo.priv = buf;
   buf->importer = this;
 
+  // We initialize the reference count to 2 since NvGralloc is still using this
+  // buffer (will be cleared in the NvGrallocRelease), and the other
+  // reference is for HWC (this ImportBuffer call).
+  atomic_init(&buf->ref, 2);
+
   int ret = gralloc_->perform(gralloc_, GRALLOC_MODULE_PERFORM_DRM_IMPORT,
                               drm_->fd(), handle, &buf->bo);
   if (ret) {
@@ -113,16 +121,24 @@
   return 0;
 }
 
-int NvImporter::ReleaseBuffer(hwc_drm_bo_t * /* bo */) {
-  /* Stub this out since we don't want hwc releasing buffers */
+int NvImporter::ReleaseBuffer(hwc_drm_bo_t * bo) {
+  NvBuffer_t *buf = (NvBuffer_t *)bo->priv;
+  if (!buf) {
+    ALOGE("Freeing bo %ld, buf is NULL!", bo->fb_id);
+    return 0;
+  }
+  if (atomic_fetch_sub(&buf->ref, 1) > 1)
+    return 0;
+
+  ReleaseBufferImpl(bo);
+  delete buf;
   return 0;
 }
 
 // static
-void NvImporter::ReleaseBufferCallback(void *nv_buffer) {
-  NvBuffer_t *buf = (NvBuffer_t *)nv_buffer;
-  buf->importer->ReleaseBufferImpl(&buf->bo);
-  delete buf;
+void NvImporter::NvGrallocRelease(void *nv_buffer) {
+  NvBuffer_t *buf = (NvBuffer *)nv_buffer;
+  buf->importer->ReleaseBuffer(&buf->bo);
 }
 
 void NvImporter::ReleaseBufferImpl(hwc_drm_bo_t *bo) {
@@ -152,13 +168,13 @@
   void *priv = NULL;
   int ret =
       gralloc_->perform(gralloc_, GRALLOC_MODULE_PERFORM_GET_IMPORTER_PRIVATE,
-                        handle, ReleaseBufferCallback, &priv);
+                        handle, NvGrallocRelease, &priv);
   return ret ? NULL : (NvBuffer_t *)priv;
 }
 
 int NvImporter::GrallocSetNvBuffer(buffer_handle_t handle, NvBuffer_t *buf) {
   return gralloc_->perform(gralloc_,
                            GRALLOC_MODULE_PERFORM_SET_IMPORTER_PRIVATE, handle,
-                           ReleaseBufferCallback, buf);
+                           NvGrallocRelease, buf);
 }
 }
diff --git a/nvimporter.h b/nvimporter.h
index e3bdd1c..a07f577 100644
--- a/nvimporter.h
+++ b/nvimporter.h
@@ -20,6 +20,8 @@
 #include "drmresources.h"
 #include "importer.h"
 
+#include <stdatomic.h>
+
 #include <hardware/gralloc.h>
 
 namespace android {
@@ -38,9 +40,10 @@
   typedef struct NvBuffer {
     NvImporter *importer;
     hwc_drm_bo_t bo;
+    atomic_int ref;
   } NvBuffer_t;
 
-  static void ReleaseBufferCallback(void *nv_buffer);
+  static void NvGrallocRelease(void *nv_buffer);
   void ReleaseBufferImpl(hwc_drm_bo_t *bo);
 
   NvBuffer_t *GrallocGetNvBuffer(buffer_handle_t handle);