drm_hwcomposer: duplicate buffer_handles before hwc_set returns

This is needed because SF will sometimes release buffer_handles before GL gets
to using them for composition.

Change-Id: I01db0975cc82d6b59bf4f9521a24071baf89c38a
diff --git a/drmdisplaycomposition.cpp b/drmdisplaycomposition.cpp
index c76a23c..d29b957 100644
--- a/drmdisplaycomposition.cpp
+++ b/drmdisplaycomposition.cpp
@@ -30,7 +30,35 @@
 
 namespace android {
 
-DrmCompositionLayer::DrmCompositionLayer() : crtc(NULL), plane(NULL) {
+static native_handle_t *dup_buffer_handle(buffer_handle_t handle) {
+  native_handle_t *new_handle =
+      native_handle_create(handle->numFds, handle->numInts);
+  if (new_handle == NULL)
+    return NULL;
+
+  const int *old_data = handle->data;
+  int *new_data = new_handle->data;
+  for (int i = 0; i < handle->numFds; i++) {
+    *new_data = dup(*old_data);
+    old_data++;
+    new_data++;
+  }
+  memcpy(new_data, old_data, sizeof(int) * handle->numInts);
+
+  return new_handle;
+}
+
+static void free_buffer_handle(native_handle_t *handle) {
+  int ret = native_handle_close(handle);
+  if (ret)
+    ALOGE("Failed to close native handle %d", ret);
+  ret = native_handle_delete(handle);
+  if (ret)
+    ALOGE("Failed to delete native handle %d", ret);
+}
+
+DrmCompositionLayer::DrmCompositionLayer()
+    : crtc(NULL), plane(NULL), handle(NULL) {
   memset(&layer, 0, sizeof(layer));
   layer.acquireFenceFd = -1;
   memset(&bo, 0, sizeof(bo));
@@ -55,6 +83,11 @@
     if (importer_ && iter->bo.fb_id)
       importer_->ReleaseBuffer(&iter->bo);
 
+    if (iter->handle) {
+      gralloc_->unregisterBuffer(gralloc_, iter->handle);
+      free_buffer_handle(iter->handle);
+    }
+
     if (iter->layer.acquireFenceFd >= 0)
       close(iter->layer.acquireFenceFd);
   }
@@ -70,7 +103,14 @@
   drm_ = drm;
   importer_ = importer;
 
-  int ret = sw_sync_timeline_create();
+  int ret = hw_get_module(GRALLOC_HARDWARE_MODULE_ID,
+                          (const hw_module_t **)&gralloc_);
+  if (ret) {
+    ALOGE("Failed to open gralloc module %d", ret);
+    return ret;
+  }
+
+  ret = sw_sync_timeline_create();
   if (ret < 0) {
     ALOGE("Failed to create sw sync timeline %d", ret);
     return ret;
@@ -92,10 +132,24 @@
   if (!validate_composition_type(DRM_COMPOSITION_TYPE_FRAME))
     return -EINVAL;
 
+  native_handle_t *handle_copy = dup_buffer_handle(layer->handle);
+  if (handle_copy == NULL) {
+    ALOGE("Failed to duplicate handle");
+    return -ENOMEM;
+  }
+
+  int ret = gralloc_->registerBuffer(gralloc_, handle_copy);
+  if (ret) {
+    ALOGE("Failed to register buffer handle %d", ret);
+    free_buffer_handle(handle_copy);
+    return ret;
+  }
+
   ++timeline_;
   layer->releaseFenceFd =
       sw_sync_fence_create(timeline_fd_, "drm_fence", timeline_);
   if (layer->releaseFenceFd < 0) {
+    free_buffer_handle(handle_copy);
     ALOGE("Could not create release fence %d", layer->releaseFenceFd);
     return layer->releaseFenceFd;
   }
@@ -105,6 +159,7 @@
   c_layer.bo = *bo;
   c_layer.crtc = crtc;
   c_layer.plane = plane;
+  c_layer.handle = handle_copy;
 
   layer->acquireFenceFd = -1;  // We own this now
   layers_.push_back(c_layer);
@@ -150,6 +205,32 @@
   return 0;
 }
 
+void DrmDisplayComposition::RemoveNoPlaneLayers() {
+  for (auto &comp_layer : layers_) {
+    if (comp_layer.plane != NULL)
+      continue;
+
+    if (importer_ && comp_layer.bo.fb_id) {
+      importer_->ReleaseBuffer(&comp_layer.bo);
+    }
+
+    if (comp_layer.handle) {
+      gralloc_->unregisterBuffer(gralloc_, comp_layer.handle);
+      free_buffer_handle(comp_layer.handle);
+    }
+
+    if (comp_layer.layer.acquireFenceFd >= 0) {
+      close(comp_layer.layer.acquireFenceFd);
+      comp_layer.layer.acquireFenceFd = -1;
+    }
+  }
+
+  layers_.erase(
+      std::remove_if(layers_.begin(), layers_.end(),
+                     [](DrmCompositionLayer_t &l) { return l.plane == NULL; }),
+      layers_.end());
+}
+
 int DrmDisplayComposition::FinishComposition() {
   int timeline_increase = timeline_ - timeline_current_;
   if (timeline_increase <= 0)
diff --git a/drmdisplaycomposition.h b/drmdisplaycomposition.h
index 7202c7c..76da993 100644
--- a/drmdisplaycomposition.h
+++ b/drmdisplaycomposition.h
@@ -23,6 +23,7 @@
 
 #include <vector>
 
+#include <hardware/gralloc.h>
 #include <hardware/hardware.h>
 #include <hardware/hwcomposer.h>
 
@@ -42,6 +43,7 @@
   hwc_drm_bo_t bo;
   DrmCrtc *crtc;
   DrmPlane *plane;
+  native_handle_t *handle;
 } DrmCompositionLayer_t;
 typedef std::vector<DrmCompositionLayer_t> DrmCompositionLayerVector_t;
 
@@ -62,6 +64,7 @@
   int AddPlaneDisable(DrmPlane *plane);
   int AddDpmsMode(uint32_t dpms_mode);
 
+  void RemoveNoPlaneLayers();
   int FinishComposition();
 
   DrmCompositionLayerVector_t *GetCompositionLayers();
@@ -76,6 +79,7 @@
 
   DrmResources *drm_;
   Importer *importer_;
+  const gralloc_module_t *gralloc_;
 
   DrmCompositionType type_;
 
diff --git a/drmdisplaycompositor.cpp b/drmdisplaycompositor.cpp
index b76d81d..1e02e73 100644
--- a/drmdisplaycompositor.cpp
+++ b/drmdisplaycompositor.cpp
@@ -186,11 +186,6 @@
     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();
@@ -199,20 +194,32 @@
       return ret;
     }
   }
+
+  std::vector<hwc_layer_1_t> pre_comp_layers;
+  for (auto &comp_layer : *layers) {
+    if (comp_layer.plane == NULL) {
+      pre_comp_layers.push_back(comp_layer.layer);
+      pre_comp_layers.back().handle = comp_layer.handle;
+      comp_layer.layer.acquireFenceFd = -1;
+    }
+  }
+
   ret = pre_compositor_->CompositeAndFinish(
       pre_comp_layers.data(), pre_comp_layers.size(), fb.buffer());
+
+  for (auto &pre_comp_layer : pre_comp_layers) {
+    if (pre_comp_layer.acquireFenceFd >= 0) {
+      close(pre_comp_layer.acquireFenceFd);
+      pre_comp_layer.acquireFenceFd = -1;
+    }
+  }
+
   if (ret) {
     ALOGE("Failed to composite layers");
     return ret;
   }
 
-  for (auto &comp_layer : *layers)
-    if (comp_layer.plane == NULL)
-      display_comp->importer()->ReleaseBuffer(&comp_layer.bo);
-
-  layers->erase(std::remove_if(layers->begin(), layers->end(),
-                               drm_composition_layer_has_no_plane),
-                layers->end());
+  display_comp->RemoveNoPlaneLayers();
 
   hwc_layer_1_t pre_comp_output_layer;
   memset(&pre_comp_output_layer, 0, sizeof(pre_comp_output_layer));
diff --git a/glworker.cpp b/glworker.cpp
index df6a8f2..fe2fd66 100644
--- a/glworker.cpp
+++ b/glworker.cpp
@@ -600,11 +600,13 @@
   }
 
   for (i = 0; i < num_layers; i++) {
-    const struct hwc_layer_1 *layer = &layers[i];
+    struct hwc_layer_1 *layer = &layers[i];
 
     if (ret) {
-      if (layer->acquireFenceFd >= 0)
+      if (layer->acquireFenceFd >= 0) {
         close(layer->acquireFenceFd);
+        layer->acquireFenceFd = -1;
+      }
       continue;
     }
 
@@ -613,6 +615,7 @@
                                   &layer_textures.back());
     if (!ret) {
       ret = EGLFenceWait(egl_display_, layer->acquireFenceFd);
+      layer->acquireFenceFd = -1;
     }
     if (ret) {
       layer_textures.pop_back();