Snap for 6227608 from 2231d9f2ae3681cb0afd540d17949716a835379a to r-keystone-qcom-release

Change-Id: I94810af8e2a1db8448b3505d5f37e400b227729e
diff --git a/drm/vsyncworker.cpp b/drm/vsyncworker.cpp
index d022887..08ab301 100644
--- a/drm/vsyncworker.cpp
+++ b/drm/vsyncworker.cpp
@@ -126,14 +126,10 @@
     }
   }
 
-  bool enabled = enabled_;
   int display = display_;
   std::shared_ptr<VsyncCallback> callback(callback_);
   Unlock();
 
-  if (!enabled)
-    return;
-
   DrmCrtc *crtc = drm_->GetCrtcForDisplay(display);
   if (!crtc) {
     ALOGE("Failed to get crtc for display");
@@ -161,6 +157,26 @@
   }
 
   /*
+   * VSync could be disabled during routine execution so it could potentially
+   * lead to crash since callback's inner hook could be invalid anymore. We have
+   * no control over lifetime of this hook, therefore we can't rely that it'll
+   * be valid after vsync disabling.
+   *
+   * Blocking VSyncControl to wait until routine
+   * will finish execution is logically correct way to fix this issue, but it
+   * creates visible lags and stutters, so we have to resort to other ways of
+   * mitigating this issue.
+   *
+   * Doing check before attempt to invoke callback drastically shortens the
+   * window when such situation could happen and that allows us to practically
+   * avoid this issue.
+   *
+   * Please note that issue described below is different one and it is related
+   * to RegisterCallback, not to disabling vsync via VSyncControl.
+   */
+  if (!enabled_)
+    return;
+  /*
    * There's a race here where a change in callback_ will not take effect until
    * the next subsequent requested vsync. This is unavoidable since we can't
    * call the vsync hook while holding the thread lock.
diff --git a/drmhwctwo.cpp b/drmhwctwo.cpp
index ffc5fcd..ab39144 100644
--- a/drmhwctwo.cpp
+++ b/drmhwctwo.cpp
@@ -128,9 +128,58 @@
   return unsupported(__func__, display);
 }
 
-void DrmHwcTwo::Dump(uint32_t *size, char *buffer) {
-  // TODO: Implement dump
-  unsupported(__func__, size, buffer);
+std::string DrmHwcTwo::HwcDisplay::DumpDelta(
+    DrmHwcTwo::HwcDisplay::Stats delta) {
+  if (delta.total_pixops_ == 0)
+    return "No stats yet";
+  double Ratio = 1.0 - double(delta.gpu_pixops_) / double(delta.total_pixops_);
+
+  return (std::stringstream()
+          << " Total frames count: " << delta.total_frames_ << "\n"
+          << " Failed to test commit frames: " << delta.failed_kms_validate_
+          << "\n"
+          << " Failed to commit frames: " << delta.failed_kms_present_ << "\n"
+          << ((delta.failed_kms_present_ > 0)
+                  ? " !!! Internal failure, FIX it please\n"
+                  : "")
+          << " Pixel operations (free units)"
+          << " : [TOTAL: " << delta.total_pixops_
+          << " / GPU: " << delta.gpu_pixops_ << "]\n"
+          << " Composition efficiency: " << Ratio)
+      .str();
+}
+
+std::string DrmHwcTwo::HwcDisplay::Dump() {
+  auto out = (std::stringstream()
+              << "- Display on: " << connector_->name() << "\n"
+              << "Statistics since system boot:\n"
+              << DumpDelta(total_stats_) << "\n\n"
+              << "Statistics since last dumpsys request:\n"
+              << DumpDelta(total_stats_.minus(prev_stats_)) << "\n\n")
+                 .str();
+
+  memcpy(&prev_stats_, &total_stats_, sizeof(Stats));
+  return out;
+}
+
+void DrmHwcTwo::Dump(uint32_t *outSize, char *outBuffer) {
+  supported(__func__);
+
+  if (outBuffer != nullptr) {
+    auto copiedBytes = mDumpString.copy(outBuffer, *outSize);
+    *outSize = static_cast<uint32_t>(copiedBytes);
+    return;
+  }
+
+  std::stringstream output;
+
+  output << "-- drm_hwcomposer --\n\n";
+
+  for (std::pair<const hwc2_display_t, DrmHwcTwo::HwcDisplay> &dp : displays_)
+    output << dp.second.Dump();
+
+  mDumpString = output.str();
+  *outSize = static_cast<uint32_t>(mDumpString.size());
 }
 
 uint32_t DrmHwcTwo::GetMaxVirtualDisplayCount() {
@@ -154,9 +203,6 @@
 
   switch (callback) {
     case HWC2::Callback::Hotplug: {
-      auto hotplug = reinterpret_cast<HWC2_PFN_HOTPLUG>(function);
-      hotplug(data, HWC_DISPLAY_PRIMARY,
-              static_cast<int32_t>(HWC2::Connection::Connected));
       auto &drmDevices = resource_manager_.getDrmDevices();
       for (auto &device : drmDevices)
         HandleInitialHotplugState(device.get());
@@ -182,8 +228,16 @@
       drm_(drm),
       importer_(importer),
       handle_(handle),
-      type_(type) {
+      type_(type),
+      color_transform_hint_(HAL_COLOR_TRANSFORM_IDENTITY) {
   supported(__func__);
+
+  // clang-format off
+  color_transform_matrix_ = {1.0, 0.0, 0.0, 0.0,
+                             0.0, 1.0, 0.0, 0.0,
+                             0.0, 0.0, 1.0, 0.0,
+                             0.0, 0.0, 0.0, 1.0};
+  // clang-format on
 }
 
 void DrmHwcTwo::HwcDisplay::ClearDisplay() {
@@ -657,7 +711,12 @@
   supported(__func__);
   HWC2::Error ret;
 
+  ++total_stats_.total_frames_;
+
   ret = CreateComposition(false);
+  if (ret != HWC2::Error::None)
+    ++total_stats_.failed_kms_present_;
+
   if (ret == HWC2::Error::BadLayer) {
     // Can we really have no client or device layers?
     *present_fence = -1;
@@ -737,8 +796,18 @@
 HWC2::Error DrmHwcTwo::HwcDisplay::SetColorTransform(const float *matrix,
                                                      int32_t hint) {
   supported(__func__);
-  // TODO: Force client composition if we get this
-  return unsupported(__func__, matrix, hint);
+  if (hint < HAL_COLOR_TRANSFORM_IDENTITY ||
+      hint > HAL_COLOR_TRANSFORM_CORRECT_TRITANOPIA)
+    return HWC2::Error::BadParameter;
+
+  if (!matrix && hint == HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX)
+    return HWC2::Error::BadParameter;
+
+  color_transform_hint_ = static_cast<android_color_transform_t>(hint);
+  if (color_transform_hint_ == HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX)
+    std::copy(matrix, matrix + MATRIX_SIZE, color_transform_matrix_.begin());
+
+  return HWC2::Error::None;
 }
 
 HWC2::Error DrmHwcTwo::HwcDisplay::SetOutputBuffer(buffer_handle_t buffer,
@@ -785,6 +854,30 @@
   return HWC2::Error::None;
 }
 
+uint32_t DrmHwcTwo::HwcDisplay::CalcPixOps(
+    std::map<uint32_t, DrmHwcTwo::HwcLayer *> &z_map, size_t first_z,
+    size_t size) {
+  uint32_t pixops = 0;
+  for (std::pair<const uint32_t, DrmHwcTwo::HwcLayer *> &l : z_map) {
+    if (l.first >= first_z && l.first < first_z + size) {
+      hwc_rect_t df = l.second->display_frame();
+      pixops += (df.right - df.left) * (df.bottom - df.top);
+    }
+  }
+  return pixops;
+}
+
+void DrmHwcTwo::HwcDisplay::MarkValidated(
+    std::map<uint32_t, DrmHwcTwo::HwcLayer *> &z_map, size_t client_first_z,
+    size_t client_size) {
+  for (std::pair<const uint32_t, DrmHwcTwo::HwcLayer *> &l : z_map) {
+    if (l.first >= client_first_z && l.first < client_first_z + client_size)
+      l.second->set_validated_type(HWC2::Composition::Client);
+    else
+      l.second->set_validated_type(HWC2::Composition::Device);
+  }
+}
+
 HWC2::Error DrmHwcTwo::HwcDisplay::ValidateDisplay(uint32_t *num_types,
                                                    uint32_t *num_requests) {
   supported(__func__);
@@ -799,28 +892,63 @@
   if (avail_planes < layers_.size())
     avail_planes--;
 
-  std::map<uint32_t, DrmHwcTwo::HwcLayer *, std::greater<int>> z_map;
+  std::map<uint32_t, DrmHwcTwo::HwcLayer *> z_map;
   for (std::pair<const hwc2_layer_t, DrmHwcTwo::HwcLayer> &l : layers_)
     z_map.emplace(std::make_pair(l.second.z_order(), &l.second));
 
-  bool gpu_block = false;
-  for (std::pair<const uint32_t, DrmHwcTwo::HwcLayer *> &l : z_map) {
-    if (gpu_block || avail_planes == 0 ||
-        !HardwareSupportsLayerType(l.second->sf_type()) ||
-        !importer_->CanImportBuffer(l.second->buffer())) {
-      gpu_block = true;
-      ++*num_types;
-    } else {
-      avail_planes--;
-    }
+  uint32_t total_pixops = CalcPixOps(z_map, 0, z_map.size()), gpu_pixops = 0;
 
-    l.second->set_validated_type(gpu_block ? HWC2::Composition::Client
-                                           : HWC2::Composition::Device);
+  int client_start = -1, client_size = 0;
+
+  for (std::pair<const uint32_t, DrmHwcTwo::HwcLayer *> &l : z_map) {
+    if (!HardwareSupportsLayerType(l.second->sf_type()) ||
+        !importer_->CanImportBuffer(l.second->buffer()) ||
+        color_transform_hint_ != HAL_COLOR_TRANSFORM_IDENTITY) {
+      if (client_start < 0)
+        client_start = l.first;
+      client_size = (l.first - client_start) + 1;
+    }
   }
 
-  if (CreateComposition(true) != HWC2::Error::None)
-    for (std::pair<const hwc2_layer_t, DrmHwcTwo::HwcLayer> &l : layers_)
-      l.second.set_validated_type(HWC2::Composition::Client);
+  int extra_client = (z_map.size() - client_size) - avail_planes;
+  if (extra_client > 0) {
+    int start = 0, steps;
+    if (client_size != 0) {
+      int prepend = std::min(client_start, extra_client);
+      int append = std::min(int(z_map.size() - (client_start + client_size)),
+                            extra_client);
+      start = client_start - prepend;
+      client_size += extra_client;
+      steps = 1 + std::min(std::min(append, prepend),
+                           int(z_map.size()) - (start + client_size));
+    } else {
+      client_size = extra_client;
+      steps = 1 + z_map.size() - extra_client;
+    }
+
+    gpu_pixops = INT_MAX;
+    for (int i = 0; i < steps; i++) {
+      uint32_t po = CalcPixOps(z_map, start + i, client_size);
+      if (po < gpu_pixops) {
+        gpu_pixops = po;
+        client_start = start + i;
+      }
+    }
+  }
+
+  MarkValidated(z_map, client_start, client_size);
+
+  if (CreateComposition(true) != HWC2::Error::None) {
+    ++total_stats_.failed_kms_validate_;
+    gpu_pixops = total_pixops;
+    client_size = z_map.size();
+    MarkValidated(z_map, 0, client_size);
+  }
+
+  *num_types = client_size;
+
+  total_stats_.gpu_pixops_ += gpu_pixops;
+  total_stats_.total_pixops_ += total_pixops;
 
   return *num_types ? HWC2::Error::HasChanges : HWC2::Error::None;
 }
@@ -855,8 +983,10 @@
 }
 
 HWC2::Error DrmHwcTwo::HwcLayer::SetLayerColor(hwc_color_t color) {
-  // TODO: Punt to client composition here?
-  return unsupported(__func__, color);
+  // TODO: Put to client composition here?
+  supported(__func__);
+  layer_color_ = color;
+  return HWC2::Error::None;
 }
 
 HWC2::Error DrmHwcTwo::HwcLayer::SetLayerCompositionType(int32_t type) {
diff --git a/include/drmhwcgralloc.h b/include/drmhwcgralloc.h
index 65a4007..b959714 100644
--- a/include/drmhwcgralloc.h
+++ b/include/drmhwcgralloc.h
@@ -29,8 +29,11 @@
   uint32_t pixel_stride;
   uint32_t pitches[HWC_DRM_BO_MAX_PLANES];
   uint32_t offsets[HWC_DRM_BO_MAX_PLANES];
+  uint32_t prime_fds[HWC_DRM_BO_MAX_PLANES];
   uint32_t gem_handles[HWC_DRM_BO_MAX_PLANES];
+  uint64_t modifiers[HWC_DRM_BO_MAX_PLANES];
   uint32_t fb_id;
+  bool with_modifiers;
   int acquire_fence_fd;
   void *priv;
 } hwc_drm_bo_t;
diff --git a/include/drmhwctwo.h b/include/drmhwctwo.h
index c6ce640..babe000 100644
--- a/include/drmhwctwo.h
+++ b/include/drmhwctwo.h
@@ -22,6 +22,7 @@
 
 #include <hardware/hwcomposer2.h>
 
+#include <array>
 #include <map>
 
 namespace android {
@@ -86,6 +87,10 @@
       return OutputFd(&release_fence_raw_);
     }
 
+    hwc_rect_t display_frame() {
+      return display_frame_;
+    }
+
     void PopulateDrmLayer(DrmHwcLayer *layer);
 
     // Layer hooks
@@ -120,6 +125,7 @@
     hwc_frect_t source_crop_;
     int32_t cursor_x_;
     int32_t cursor_y_;
+    hwc_color_t layer_color_;
     HWC2::Transform transform_ = HWC2::Transform::None;
     uint32_t z_order_ = 0;
     android_dataspace_t dataspace_ = HAL_DATASPACE_UNKNOWN;
@@ -145,6 +151,8 @@
                                       hwc2_function_pointer_t func);
     void ClearDisplay();
 
+    std::string Dump();
+
     // HWC Hooks
     HWC2::Error AcceptDisplayChanges();
     HWC2::Error CreateLayer(hwc2_layer_t *layer);
@@ -194,6 +202,12 @@
     HWC2::Error CreateComposition(bool test);
     void AddFenceToPresentFence(int fd);
     bool HardwareSupportsLayerType(HWC2::Composition comp_type);
+    uint32_t CalcPixOps(std::map<uint32_t, DrmHwcTwo::HwcLayer *> &z_map,
+                        size_t first_z, size_t size);
+    void MarkValidated(std::map<uint32_t, DrmHwcTwo::HwcLayer *> &z_map,
+                       size_t client_first_z, size_t client_size);
+
+    constexpr static size_t MATRIX_SIZE = 16;
 
     ResourceManager *resource_manager_;
     DrmDevice *drm_;
@@ -214,8 +228,26 @@
     HwcLayer client_layer_;
     UniqueFd present_fence_;
     int32_t color_mode_;
+    std::array<float, MATRIX_SIZE> color_transform_matrix_;
+    android_color_transform_t color_transform_hint_;
 
     uint32_t frame_no_ = 0;
+    /* Statistics */
+    struct Stats {
+      Stats minus(Stats b) {
+        return {total_frames_ - b.total_frames_,
+                total_pixops_ - b.total_pixops_, gpu_pixops_ - b.gpu_pixops_,
+                failed_kms_validate_ - b.failed_kms_validate_,
+                failed_kms_present_ - b.failed_kms_present_};
+      }
+
+      uint32_t total_frames_ = 0;
+      uint64_t total_pixops_ = 0;
+      uint64_t gpu_pixops_ = 0;
+      uint32_t failed_kms_validate_ = 0;
+      uint32_t failed_kms_present_ = 0;
+    } total_stats_, prev_stats_;
+    std::string DumpDelta(DrmHwcTwo::HwcDisplay::Stats delta);
   };
 
   class DrmHotplugHandler : public DrmEventHandler {
@@ -289,7 +321,7 @@
   HWC2::Error CreateVirtualDisplay(uint32_t width, uint32_t height,
                                    int32_t *format, hwc2_display_t *display);
   HWC2::Error DestroyVirtualDisplay(hwc2_display_t display);
-  void Dump(uint32_t *size, char *buffer);
+  void Dump(uint32_t *outSize, char *outBuffer);
   uint32_t GetMaxVirtualDisplayCount();
   HWC2::Error RegisterCallback(int32_t descriptor, hwc2_callback_data_t data,
                                hwc2_function_pointer_t function);
@@ -300,5 +332,7 @@
   ResourceManager resource_manager_;
   std::map<hwc2_display_t, HwcDisplay> displays_;
   std::map<HWC2::Callback, HwcCallback> callbacks_;
+
+  std::string mDumpString;
 };
 }  // namespace android
diff --git a/include/platform.h b/include/platform.h
index 6fdece2..6775e29 100644
--- a/include/platform.h
+++ b/include/platform.h
@@ -52,6 +52,9 @@
 
   // Checks if importer can import the buffer.
   virtual bool CanImportBuffer(buffer_handle_t handle) = 0;
+
+  // Convert platform-dependent buffer format to drm_hwc internal format.
+  virtual int ConvertBoInfo(buffer_handle_t handle, hwc_drm_bo_t *bo) = 0;
 };
 
 class Planner {
diff --git a/include/vsyncworker.h b/include/vsyncworker.h
index b2bca9d..96f7432 100644
--- a/include/vsyncworker.h
+++ b/include/vsyncworker.h
@@ -60,7 +60,7 @@
   std::shared_ptr<VsyncCallback> callback_ = NULL;
 
   int display_;
-  bool enabled_;
+  std::atomic_bool enabled_;
   int64_t last_timestamp_;
 };
 }  // namespace android
diff --git a/platform/platformdrmgeneric.cpp b/platform/platformdrmgeneric.cpp
index 0883b90..1aa8160 100644
--- a/platform/platformdrmgeneric.cpp
+++ b/platform/platformdrmgeneric.cpp
@@ -110,19 +110,12 @@
   }
 }
 
-int DrmGenericImporter::ImportBuffer(buffer_handle_t handle, hwc_drm_bo_t *bo) {
+int DrmGenericImporter::ConvertBoInfo(buffer_handle_t handle,
+                                      hwc_drm_bo_t *bo) {
   gralloc_handle_t *gr_handle = gralloc_handle(handle);
   if (!gr_handle)
     return -EINVAL;
 
-  uint32_t gem_handle;
-  int ret = drmPrimeFDToHandle(drm_->fd(), gr_handle->prime_fd, &gem_handle);
-  if (ret) {
-    ALOGE("failed to import prime fd %d ret=%d", gr_handle->prime_fd, ret);
-    return ret;
-  }
-
-  memset(bo, 0, sizeof(hwc_drm_bo_t));
   bo->width = gr_handle->width;
   bo->height = gr_handle->height;
   bo->hal_format = gr_handle->format;
@@ -132,17 +125,55 @@
   bo->usage = gr_handle->usage;
   bo->pixel_stride = (gr_handle->stride * 8) /
                      DrmFormatToBitsPerPixel(bo->format);
+  bo->prime_fds[0] = gr_handle->prime_fd;
   bo->pitches[0] = gr_handle->stride;
-  bo->gem_handles[0] = gem_handle;
   bo->offsets[0] = 0;
 
-  ret = drmModeAddFB2(drm_->fd(), bo->width, bo->height, bo->format,
-                      bo->gem_handles, bo->pitches, bo->offsets, &bo->fb_id, 0);
+  return 0;
+}
+
+int DrmGenericImporter::ImportBuffer(buffer_handle_t handle, hwc_drm_bo_t *bo) {
+  memset(bo, 0, sizeof(hwc_drm_bo_t));
+
+  int ret = ConvertBoInfo(handle, bo);
+  if (ret)
+    return ret;
+
+  ret = drmPrimeFDToHandle(drm_->fd(), bo->prime_fds[0], &bo->gem_handles[0]);
+  if (ret) {
+    ALOGE("failed to import prime fd %d ret=%d", bo->prime_fds[0], ret);
+    return ret;
+  }
+
+  for (int i = 1; i < HWC_DRM_BO_MAX_PLANES; i++) {
+    int fd = bo->prime_fds[i];
+    if (fd != 0) {
+      if (fd != bo->prime_fds[0]) {
+        ALOGE("Multiplanar FBs are not supported by this version of composer");
+        return -ENOTSUP;
+      }
+      bo->gem_handles[i] = bo->gem_handles[0];
+    }
+  }
+
+  if (!bo->with_modifiers)
+    ret = drmModeAddFB2(drm_->fd(), bo->width, bo->height, bo->format,
+                        bo->gem_handles, bo->pitches, bo->offsets, &bo->fb_id,
+                        0);
+  else
+    ret = drmModeAddFB2WithModifiers(drm_->fd(), bo->width, bo->height,
+                                     bo->format, bo->gem_handles, bo->pitches,
+                                     bo->offsets, bo->modifiers, &bo->fb_id,
+                                     bo->modifiers[0] ? DRM_MODE_FB_MODIFIERS
+                                                      : 0);
+
   if (ret) {
     ALOGE("could not create drm fb %d", ret);
     return ret;
   }
 
+  ImportHandle(bo->gem_handles[0]);
+
   return ret;
 }
 
@@ -151,17 +182,12 @@
     if (drmModeRmFB(drm_->fd(), bo->fb_id))
       ALOGE("Failed to rm fb");
 
-  struct drm_gem_close gem_close;
-  memset(&gem_close, 0, sizeof(gem_close));
-
   for (int i = 0; i < HWC_DRM_BO_MAX_PLANES; i++) {
     if (!bo->gem_handles[i])
       continue;
 
-    gem_close.handle = bo->gem_handles[i];
-    int ret = drmIoctl(drm_->fd(), DRM_IOCTL_GEM_CLOSE, &gem_close);
-    if (ret) {
-      ALOGE("Failed to close gem handle %d %d", i, ret);
+    if (ReleaseHandle(bo->gem_handles[i])) {
+      ALOGE("Failed to release gem handle %d", bo->gem_handles[i]);
     } else {
       for (int j = i + 1; j < HWC_DRM_BO_MAX_PLANES; j++)
         if (bo->gem_handles[j] == bo->gem_handles[i])
@@ -173,13 +199,17 @@
 }
 
 bool DrmGenericImporter::CanImportBuffer(buffer_handle_t handle) {
-  if (handle == NULL)
+  hwc_drm_bo_t bo;
+
+  int ret = ConvertBoInfo(handle, &bo);
+  if (ret)
     return false;
 
-  if (exclude_non_hwfb_) {
-    gralloc_handle_t *hnd = gralloc_handle(handle);
-    return hnd->usage & GRALLOC_USAGE_HW_FB;
-  }
+  if (bo.prime_fds[0] == 0)
+    return false;
+
+  if (exclude_non_hwfb_ && !(bo.usage & GRALLOC_USAGE_HW_FB))
+    return false;
 
   return true;
 }
@@ -191,4 +221,32 @@
   return planner;
 }
 #endif
+
+int DrmGenericImporter::ImportHandle(uint32_t gem_handle) {
+  gem_refcount_[gem_handle]++;
+
+  return 0;
+}
+
+int DrmGenericImporter::ReleaseHandle(uint32_t gem_handle) {
+  if (--gem_refcount_[gem_handle])
+    return 0;
+
+  gem_refcount_.erase(gem_handle);
+
+  return CloseHandle(gem_handle);
+}
+
+int DrmGenericImporter::CloseHandle(uint32_t gem_handle) {
+  struct drm_gem_close gem_close;
+
+  memset(&gem_close, 0, sizeof(gem_close));
+
+  gem_close.handle = gem_handle;
+  int ret = drmIoctl(drm_->fd(), DRM_IOCTL_GEM_CLOSE, &gem_close);
+  if (ret)
+    ALOGE("Failed to close gem handle %d %d", gem_handle, ret);
+
+  return ret;
+}
 }
diff --git a/platform/platformdrmgeneric.h b/platform/platformdrmgeneric.h
index 7bb2ea2..f9d923f 100644
--- a/platform/platformdrmgeneric.h
+++ b/platform/platformdrmgeneric.h
@@ -21,6 +21,7 @@
 #include "platform.h"
 
 #include <hardware/gralloc.h>
+#include <map>
 
 #include <drm/drm_fourcc.h>
 
@@ -40,6 +41,10 @@
   int ImportBuffer(buffer_handle_t handle, hwc_drm_bo_t *bo) override;
   int ReleaseBuffer(hwc_drm_bo_t *bo) override;
   bool CanImportBuffer(buffer_handle_t handle) override;
+  int ImportHandle(uint32_t gem_handle);
+  int ReleaseHandle(uint32_t gem_handle);
+
+  int ConvertBoInfo(buffer_handle_t handle, hwc_drm_bo_t *bo) override;
 
   uint32_t ConvertHalFormatToDrm(uint32_t hal_format);
   uint32_t DrmFormatToBitsPerPixel(uint32_t drm_format);
@@ -50,6 +55,9 @@
  private:
   const gralloc_module_t *gralloc_;
   bool exclude_non_hwfb_;
+
+  int CloseHandle(uint32_t gem_handle);
+  std::map<uint32_t, int> gem_refcount_;
 };
 }  // namespace android
 
diff --git a/platform/platformhisi.cpp b/platform/platformhisi.cpp
index 2e6ac43..1f1478f 100644
--- a/platform/platformhisi.cpp
+++ b/platform/platformhisi.cpp
@@ -92,41 +92,29 @@
     case DRM_FORMAT_YVU420:
       return false;
     default:
-      ALOGE("Unsupported format %u assuming rgb?", drm_format);
+      ALOGV("Unsupported format %u assuming rgb?", drm_format);
       return true;
   }
 }
 
-int HisiImporter::ImportBuffer(buffer_handle_t handle, hwc_drm_bo_t *bo) {
+int HisiImporter::ConvertBoInfo(buffer_handle_t handle, hwc_drm_bo_t *bo) {
   bool is_rgb;
-  uint64_t modifiers[4] = {0};
-
-  memset(bo, 0, sizeof(hwc_drm_bo_t));
 
   private_handle_t const *hnd = reinterpret_cast<private_handle_t const *>(
       handle);
   if (!hnd)
     return -EINVAL;
 
-  // We can't import these types of buffers.
-  // These buffers should have been filtered out with CanImportBuffer()
   if (!(hnd->usage & GRALLOC_USAGE_HW_FB))
     return -EINVAL;
 
-  uint32_t gem_handle;
-  int ret = drmPrimeFDToHandle(drm_->fd(), hnd->share_fd, &gem_handle);
-  if (ret) {
-    ALOGE("failed to import prime fd %d ret=%d", hnd->share_fd, ret);
-    return ret;
-  }
-
   uint32_t fmt = ConvertHalFormatToDrm(hnd->req_format);
   if (fmt == DRM_FORMAT_INVALID)
     return -EINVAL;
 
-  is_rgb = IsDrmFormatRgb(fmt);
-  modifiers[0] = ConvertGrallocFormatToDrmModifiers(hnd->internal_format,
-                                                    is_rgb);
+  is_rgb = HisiImporter::IsDrmFormatRgb(fmt);
+  bo->modifiers[0] = HisiImporter::
+      ConvertGrallocFormatToDrmModifiers(hnd->internal_format, is_rgb);
 
   bo->width = hnd->width;
   bo->height = hnd->height;
@@ -135,7 +123,7 @@
   bo->usage = hnd->usage;
   bo->pixel_stride = hnd->stride;
   bo->pitches[0] = hnd->byte_stride;
-  bo->gem_handles[0] = gem_handle;
+  bo->prime_fds[0] = hnd->share_fd;
   bo->offsets[0] = 0;
 
   switch (fmt) {
@@ -150,11 +138,11 @@
       int v_size = vu_stride * (adjusted_height / 2);
 
       /* V plane*/
-      bo->gem_handles[1] = gem_handle;
+      bo->prime_fds[1] = hnd->share_fd;
       bo->pitches[1] = vu_stride;
       bo->offsets[1] = y_size;
       /* U plane */
-      bo->gem_handles[2] = gem_handle;
+      bo->prime_fds[2] = hnd->share_fd;
       bo->pitches[2] = vu_stride;
       bo->offsets[2] = y_size + v_size;
       break;
@@ -163,23 +151,9 @@
       break;
   }
 
-  ret = drmModeAddFB2WithModifiers(drm_->fd(), bo->width, bo->height,
-                                   bo->format, bo->gem_handles, bo->pitches,
-                                   bo->offsets, modifiers, &bo->fb_id,
-                                   modifiers[0] ? DRM_MODE_FB_MODIFIERS : 0);
+  bo->with_modifiers = true;
 
-  if (ret) {
-    ALOGE("could not create drm fb %d", ret);
-    return ret;
-  }
-
-  return ret;
-}
-
-bool HisiImporter::CanImportBuffer(buffer_handle_t handle) {
-  private_handle_t const *hnd = reinterpret_cast<private_handle_t const *>(
-      handle);
-  return hnd && (hnd->usage & GRALLOC_USAGE_HW_FB);
+  return 0;
 }
 
 class PlanStageHiSi : public Planner::PlanStage {
diff --git a/platform/platformhisi.h b/platform/platformhisi.h
index 9dfea89..f127bdb 100644
--- a/platform/platformhisi.h
+++ b/platform/platformhisi.h
@@ -31,8 +31,7 @@
  public:
   using DrmGenericImporter::DrmGenericImporter;
 
-  int ImportBuffer(buffer_handle_t handle, hwc_drm_bo_t *bo) override;
-  bool CanImportBuffer(buffer_handle_t handle) override;
+  int ConvertBoInfo(buffer_handle_t handle, hwc_drm_bo_t *bo) override;
 
  private:
   uint64_t ConvertGrallocFormatToDrmModifiers(uint64_t flags, bool is_rgb);
diff --git a/platform/platformimagination.cpp b/platform/platformimagination.cpp
index 565e6ee..ea34ecc 100644
--- a/platform/platformimagination.cpp
+++ b/platform/platformimagination.cpp
@@ -22,30 +22,22 @@
   return importer;
 }
 
-int ImaginationImporter::ImportBuffer(buffer_handle_t handle,
-                                      hwc_drm_bo_t *bo) {
+int ImaginationImporter::ConvertBoInfo(buffer_handle_t handle,
+                                       hwc_drm_bo_t *bo) {
   IMG_native_handle_t *hnd = (IMG_native_handle_t *)handle;
   if (!hnd)
     return -EINVAL;
 
-  uint32_t gem_handle;
-  int ret = drmPrimeFDToHandle(drm_->fd(), hnd->fd[0], &gem_handle);
-  if (ret) {
-    ALOGE("failed to import prime fd %d ret=%d", hnd->fd[0], ret);
-    return ret;
-  }
-
   /* Extra bits are responsible for buffer compression and memory layout */
   if (hnd->iFormat & ~0x10f) {
-    ALOGE("Special buffer formats are not supported");
+    ALOGV("Special buffer formats are not supported");
     return -EINVAL;
   }
 
-  memset(bo, 0, sizeof(hwc_drm_bo_t));
   bo->width = hnd->iWidth;
   bo->height = hnd->iHeight;
   bo->usage = hnd->usage;
-  bo->gem_handles[0] = gem_handle;
+  bo->prime_fds[0] = hnd->fd[0];
   bo->pitches[0] = ALIGN(hnd->iWidth, HW_ALIGN) * hnd->uiBpp >> 3;
 
   switch (hnd->iFormat) {
@@ -57,18 +49,11 @@
     default:
       bo->format = ConvertHalFormatToDrm(hnd->iFormat & 0xf);
       if (bo->format == DRM_FORMAT_INVALID) {
-        ALOGE("Cannot convert hal format to drm format %u", hnd->iFormat);
+        ALOGV("Cannot convert hal format to drm format %u", hnd->iFormat);
         return -EINVAL;
       }
   }
 
-  ret = drmModeAddFB2(drm_->fd(), bo->width, bo->height, bo->format,
-                      bo->gem_handles, bo->pitches, bo->offsets, &bo->fb_id, 0);
-  if (ret) {
-    ALOGE("could not create drm fb ret: %d", ret);
-    return ret;
-  }
-
   return 0;
 }
 
diff --git a/platform/platformimagination.h b/platform/platformimagination.h
index 85dfc45..f2a7cb7 100644
--- a/platform/platformimagination.h
+++ b/platform/platformimagination.h
@@ -15,7 +15,7 @@
  public:
   using DrmGenericImporter::DrmGenericImporter;
 
-  int ImportBuffer(buffer_handle_t handle, hwc_drm_bo_t *bo) override;
+  int ConvertBoInfo(buffer_handle_t handle, hwc_drm_bo_t *bo) override;
 };
 }  // namespace android
 
diff --git a/platform/platformmeson.cpp b/platform/platformmeson.cpp
index 5184972..ad3aff1 100644
--- a/platform/platformmeson.cpp
+++ b/platform/platformmeson.cpp
@@ -75,33 +75,21 @@
 }
 #endif
 
-int MesonImporter::ImportBuffer(buffer_handle_t handle, hwc_drm_bo_t *bo) {
-  uint64_t modifiers[4] = {0};
-
-  memset(bo, 0, sizeof(hwc_drm_bo_t));
-
+int MesonImporter::ConvertBoInfo(buffer_handle_t handle, hwc_drm_bo_t *bo) {
   private_handle_t const *hnd = reinterpret_cast<private_handle_t const *>(
       handle);
   if (!hnd)
     return -EINVAL;
 
-  // We can't import these types of buffers.
-  // These buffers should have been filtered out with CanImportBuffer()
   if (!(hnd->usage & GRALLOC_USAGE_HW_FB))
     return -EINVAL;
 
-  uint32_t gem_handle;
-  int ret = drmPrimeFDToHandle(drm_->fd(), hnd->share_fd, &gem_handle);
-  if (ret) {
-    ALOGE("failed to import prime fd %d ret=%d", hnd->share_fd, ret);
-    return ret;
-  }
-
   uint32_t fmt = ConvertHalFormatToDrm(hnd->req_format);
   if (fmt == DRM_FORMAT_INVALID)
     return -EINVAL;
 
-  modifiers[0] = ConvertGrallocFormatToDrmModifiers(hnd->internal_format);
+  bo->modifiers[0] = MesonImporter::ConvertGrallocFormatToDrmModifiers(
+      hnd->internal_format);
 
   bo->width = hnd->width;
   bo->height = hnd->height;
@@ -109,27 +97,13 @@
   bo->format = fmt;
   bo->usage = hnd->usage;
   bo->pixel_stride = hnd->stride;
+  bo->prime_fds[0] = hnd->share_fd;
   bo->pitches[0] = hnd->byte_stride;
-  bo->gem_handles[0] = gem_handle;
   bo->offsets[0] = 0;
 
-  ret = drmModeAddFB2WithModifiers(drm_->fd(), bo->width, bo->height,
-                                   bo->format, bo->gem_handles, bo->pitches,
-                                   bo->offsets, modifiers, &bo->fb_id,
-                                   modifiers[0] ? DRM_MODE_FB_MODIFIERS : 0);
+  bo->with_modifiers = true;
 
-  if (ret) {
-    ALOGE("could not create drm fb %d", ret);
-    return ret;
-  }
-
-  return ret;
-}
-
-bool MesonImporter::CanImportBuffer(buffer_handle_t handle) {
-  private_handle_t const *hnd = reinterpret_cast<private_handle_t const *>(
-      handle);
-  return hnd && (hnd->usage & GRALLOC_USAGE_HW_FB);
+  return 0;
 }
 
 std::unique_ptr<Planner> Planner::CreateInstance(DrmDevice *) {
diff --git a/platform/platformmeson.h b/platform/platformmeson.h
index 7be7702..f29b796 100644
--- a/platform/platformmeson.h
+++ b/platform/platformmeson.h
@@ -31,8 +31,7 @@
  public:
   using DrmGenericImporter::DrmGenericImporter;
 
-  int ImportBuffer(buffer_handle_t handle, hwc_drm_bo_t *bo) override;
-  bool CanImportBuffer(buffer_handle_t handle) override;
+  int ConvertBoInfo(buffer_handle_t handle, hwc_drm_bo_t *bo) override;
 
  private:
   uint64_t ConvertGrallocFormatToDrmModifiers(uint64_t flags);
diff --git a/platform/platformminigbm.cpp b/platform/platformminigbm.cpp
index a65e196..df195d3 100644
--- a/platform/platformminigbm.cpp
+++ b/platform/platformminigbm.cpp
@@ -44,37 +44,23 @@
   return importer;
 }
 
-int DrmMinigbmImporter::ImportBuffer(buffer_handle_t handle, hwc_drm_bo_t *bo) {
+int DrmMinigbmImporter::ConvertBoInfo(buffer_handle_t handle,
+                                      hwc_drm_bo_t *bo) {
   cros_gralloc_handle *gr_handle = (cros_gralloc_handle *)handle;
   if (!gr_handle)
     return -EINVAL;
 
-  uint32_t gem_handle;
-  int ret = drmPrimeFDToHandle(drm_->fd(), gr_handle->fds[0], &gem_handle);
-  if (ret) {
-    ALOGE("failed to import prime fd %d ret=%d", gr_handle->fds[0], ret);
-    return ret;
-  }
-
-  memset(bo, 0, sizeof(hwc_drm_bo_t));
   bo->width = gr_handle->width;
   bo->height = gr_handle->height;
   bo->hal_format = gr_handle->droid_format;
   bo->format = gr_handle->format;
   bo->usage = gr_handle->usage;
   bo->pixel_stride = gr_handle->pixel_stride;
+  bo->prime_fds[0] = gr_handle->fds[0];
   bo->pitches[0] = gr_handle->strides[0];
   bo->offsets[0] = gr_handle->offsets[0];
-  bo->gem_handles[0] = gem_handle;
 
-  ret = drmModeAddFB2(drm_->fd(), bo->width, bo->height, bo->format,
-                      bo->gem_handles, bo->pitches, bo->offsets, &bo->fb_id, 0);
-  if (ret) {
-    ALOGE("could not create drm fb %d", ret);
-    return ret;
-  }
-
-  return ret;
+  return 0;
 }
 
 std::unique_ptr<Planner> Planner::CreateInstance(DrmDevice *) {
diff --git a/platform/platformminigbm.h b/platform/platformminigbm.h
index ff69f14..053b2aa 100644
--- a/platform/platformminigbm.h
+++ b/platform/platformminigbm.h
@@ -28,7 +28,7 @@
 class DrmMinigbmImporter : public DrmGenericImporter {
  public:
   using DrmGenericImporter::DrmGenericImporter;
-  int ImportBuffer(buffer_handle_t handle, hwc_drm_bo_t *bo) override;
+  int ConvertBoInfo(buffer_handle_t handle, hwc_drm_bo_t *bo) override;
 };
 
 }  // namespace android