drm_hwcomposer: Wrap the importers in a class

This will allow us to move the importer functionality into the
drmcompositor.

Change-Id: I4274ebd1776c4d7879342c54a2b7c4095ebc50f4
Signed-off-by: Sean Paul <seanpaul@chromium.org>
diff --git a/Android.mk b/Android.mk
index 81e7e48..30dfb5f 100644
--- a/Android.mk
+++ b/Android.mk
@@ -26,6 +26,7 @@
 	libutils \
 
 LOCAL_C_INCLUDES := \
+	external/drm_gralloc \
 	external/libdrm \
 	external/libdrm/include/drm \
 	system/core/include/utils \
@@ -38,19 +39,18 @@
 	drmconnector.cpp \
 	drmcrtc.cpp \
 	drmencoder.cpp \
+        drmgenericimporter.cpp \
 	drmmode.cpp \
 	drmplane.cpp \
 	drmproperty.cpp \
 	hwcomposer.cpp \
+        nvimporter.cpp \
 	worker.cpp
 
-ifeq ($(strip $(BOARD_DRM_HWCOMPOSER_BUFFER_IMPORTER)),drm-gralloc)
-LOCAL_C_INCLUDES += external/drm_gralloc
-LOCAL_SRC_FILES += hwcomposer_import_drm_gralloc.cpp
-endif
 ifeq ($(strip $(BOARD_DRM_HWCOMPOSER_BUFFER_IMPORTER)),nvidia-gralloc)
-LOCAL_C_INCLUDES += external/drm_gralloc
-LOCAL_SRC_FILES += hwcomposer_import_nv_gralloc.cpp
+LOCAL_CPPFLAGS += -DUSE_NVIDIA_IMPORTER
+else
+LOCAL_CPPFLAGS += -DUSE_DRM_GENERIC_IMPORTER
 endif
 
 LOCAL_MODULE := hwcomposer.drm
diff --git a/drmgenericimporter.cpp b/drmgenericimporter.cpp
new file mode 100644
index 0000000..8c90f5f
--- /dev/null
+++ b/drmgenericimporter.cpp
@@ -0,0 +1,145 @@
+/*
+ * 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 LOG_TAG "hwc-drm-generic-importer"
+
+#include "importer.h"
+#include "drmresources.h"
+#include "drmgenericimporter.h"
+
+#include <drm/drm_fourcc.h>
+#include <xf86drm.h>
+#include <xf86drmMode.h>
+
+#include <cutils/log.h>
+#include <gralloc_drm.h>
+#include <gralloc_drm_priv.h>
+#include <gralloc_drm_handle.h>
+#include <hardware/gralloc.h>
+
+namespace android {
+
+#ifdef USE_DRM_GENERIC_IMPORTER
+// static
+Importer *Importer::CreateInstance(DrmResources *drm) {
+  DrmGenericImporter *importer = new DrmGenericImporter(drm);
+  if (!importer)
+    return NULL;
+
+  int ret = importer->Init();
+  if (ret) {
+    ALOGE("Failed to initialize the nv importer %d", ret);
+    delete importer;
+    return NULL;
+  }
+  return importer;
+}
+#endif
+
+DrmGenericImporter::DrmGenericImporter(DrmResources *drm) : drm_(drm) {
+}
+
+DrmGenericImporter::~DrmGenericImporter() {
+}
+
+int DrmGenericImporter::Init() {
+  int ret = hw_get_module(GRALLOC_HARDWARE_MODULE_ID,
+                          (const hw_module_t **)&gralloc_);
+  if (ret) {
+    ALOGE("Failed to open gralloc module");
+    return ret;
+  }
+  return 0;
+}
+
+uint32_t DrmGenericImporter::ConvertHalFormatToDrm(uint32_t hal_format) {
+  switch (hal_format) {
+    case HAL_PIXEL_FORMAT_RGB_888:
+      return DRM_FORMAT_BGR888;
+    case HAL_PIXEL_FORMAT_BGRA_8888:
+      return DRM_FORMAT_ARGB8888;
+    case HAL_PIXEL_FORMAT_RGBX_8888:
+      return DRM_FORMAT_XBGR8888;
+    case HAL_PIXEL_FORMAT_RGBA_8888:
+      return DRM_FORMAT_ABGR8888;
+    case HAL_PIXEL_FORMAT_RGB_565:
+      return DRM_FORMAT_BGR565;
+    case HAL_PIXEL_FORMAT_YV12:
+      return DRM_FORMAT_YVU420;
+    default:
+      ALOGE("Cannot convert hal format to drm format %u", hal_format);
+      return -EINVAL;
+  }
+}
+
+int DrmGenericImporter::ImportBuffer(buffer_handle_t handle, hwc_drm_bo_t *bo) {
+  gralloc_drm_handle_t *gr_handle = gralloc_drm_handle(handle);
+  if (!gr_handle)
+    return -EINVAL;
+
+  struct gralloc_drm_bo_t *gralloc_bo = gr_handle->data;
+  if (!gralloc_bo) {
+    ALOGE("Could not get drm bo from 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->format = ConvertHalFormatToDrm(gr_handle->format);
+  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);
+  if (ret) {
+    ALOGE("could not create drm fb %d", ret);
+    return ret;
+  }
+
+  return ret;
+}
+
+int DrmGenericImporter::ReleaseBuffer(hwc_drm_bo_t *bo) {
+  if (bo->fb_id)
+    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));
+  int num_gem_handles = sizeof(bo->gem_handles) / sizeof(bo->gem_handles[0]);
+  for (int i = 0; i < num_gem_handles; 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);
+    else
+      bo->gem_handles[i] = 0;
+  }
+  return 0;
+}
+}
diff --git a/drmgenericimporter.h b/drmgenericimporter.h
new file mode 100644
index 0000000..d509ed8
--- /dev/null
+++ b/drmgenericimporter.h
@@ -0,0 +1,46 @@
+/*
+ * 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_GENERIC_IMPORTER_H_
+#define ANDROID_DRM_GENERIC_IMPORTER_H_
+
+#include "drmresources.h"
+#include "importer.h"
+
+#include <hardware/gralloc.h>
+
+namespace android {
+
+class DrmGenericImporter : public Importer {
+ public:
+  DrmGenericImporter(DrmResources *drm);
+  virtual ~DrmGenericImporter();
+
+  int Init();
+
+  virtual int ImportBuffer(buffer_handle_t handle, hwc_drm_bo_t *bo);
+  virtual int ReleaseBuffer(hwc_drm_bo_t *bo);
+
+ private:
+  uint32_t ConvertHalFormatToDrm(uint32_t hal_format);
+
+  DrmResources *drm_;
+
+  const gralloc_module_t *gralloc_;
+};
+}
+
+#endif
diff --git a/hwcomposer.cpp b/hwcomposer.cpp
index c9452b6..06c0931 100644
--- a/hwcomposer.cpp
+++ b/hwcomposer.cpp
@@ -18,6 +18,7 @@
 
 #include "drm_hwcomposer.h"
 #include "drmresources.h"
+#include "importer.h"
 
 #include <errno.h>
 #include <fcntl.h>
@@ -75,14 +76,21 @@
   typedef std::map<int, hwc_drm_display_t> DisplayMap;
   typedef DisplayMap::iterator DisplayMapIter;
 
+  hwc_context_t() : procs(NULL), importer(NULL) {
+  }
+
+  ~hwc_context_t() {
+    delete importer;
+  }
+
   hwc_composer_device_1_t device;
   hwc_procs_t const *procs;
-  struct hwc_import_context *import_ctx;
 
   struct hwc_worker event_worker;
 
   DisplayMap displays;
   DrmResources drm;
+  Importer *importer;
 };
 
 static int hwc_prepare_layer(hwc_layer_1_t *layer) {
@@ -318,8 +326,7 @@
     return ret;
   }
 
-  if (hwc_import_bo_release(hd->ctx->drm.fd(), hd->ctx->import_ctx,
-                            &hd->front)) {
+  if (!hd->ctx->importer->ReleaseBuffer(buf)) {
     struct drm_gem_close args;
     memset(&args, 0, sizeof(args));
     for (int i = 0; i < ARRAY_SIZE(hd->front.gem_handles); ++i) {
@@ -469,9 +476,7 @@
   }
 
   struct hwc_drm_bo buf;
-  memset(&buf, 0, sizeof(buf));
-  ret =
-      hwc_import_bo_create(ctx->drm.fd(), ctx->import_ctx, layer->handle, &buf);
+  ret = ctx->importer->ImportBuffer(layer->handle, &buf);
   if (ret) {
     ALOGE("Failed to import handle to drm bo %d", ret);
     hwc_close_fences(display_contents);
@@ -754,12 +759,7 @@
   if (hwc_destroy_worker(&ctx->event_worker))
     ALOGE("Destroy event worker failed");
 
-  int ret = hwc_import_destroy(ctx->import_ctx);
-  if (ret)
-    ALOGE("Could not destroy import %d", ret);
-
   delete ctx;
-
   return 0;
 }
 
@@ -912,9 +912,9 @@
     return ret;
   }
 
-  ret = hwc_import_init(&ctx->import_ctx);
-  if (ret) {
-    ALOGE("Failed to initialize import context");
+  ctx->importer = Importer::CreateInstance(&ctx->drm);
+  if (!ctx->importer) {
+    ALOGE("Failed to create importer instance");
     delete ctx;
     return ret;
   }
diff --git a/hwcomposer_import_drm_gralloc.cpp b/hwcomposer_import_drm_gralloc.cpp
deleted file mode 100644
index 5958f57..0000000
--- a/hwcomposer_import_drm_gralloc.cpp
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * 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 <stdlib.h>
-
-#include <cutils/log.h>
-
-#include <drm/drm_fourcc.h>
-
-#include <gralloc_drm.h>
-#include <gralloc_drm_priv.h>
-#include <gralloc_drm_handle.h>
-
-#include "drm_hwcomposer.h"
-
-struct hwc_import_context {
-  struct drm_module_t *gralloc_module;
-};
-
-int hwc_import_init(struct hwc_import_context **ctx) {
-  struct hwc_import_context *import_ctx;
-
-  import_ctx = (struct hwc_import_context *)calloc(1, sizeof(*import_ctx));
-  if (!ctx) {
-    ALOGE("Failed to allocate gralloc import context");
-    return -ENOMEM;
-  }
-
-  int ret = hw_get_module(GRALLOC_HARDWARE_MODULE_ID,
-                      (const hw_module_t **)&import_ctx->gralloc_module);
-  if (ret) {
-    ALOGE("Failed to open gralloc module");
-    free(import_ctx);
-    return ret;
-  }
-
-  *ctx = import_ctx;
-
-  return 0;
-}
-
-int hwc_import_destroy(struct hwc_import_context *ctx) {
-  free(ctx);
-  return 0;
-}
-
-static uint32_t hwc_convert_hal_format_to_drm_format(uint32_t hal_format) {
-  switch (hal_format) {
-    case HAL_PIXEL_FORMAT_RGB_888:
-      return DRM_FORMAT_BGR888;
-    case HAL_PIXEL_FORMAT_BGRA_8888:
-      return DRM_FORMAT_ARGB8888;
-    case HAL_PIXEL_FORMAT_RGBX_8888:
-      return DRM_FORMAT_XBGR8888;
-    case HAL_PIXEL_FORMAT_RGBA_8888:
-      return DRM_FORMAT_ABGR8888;
-    case HAL_PIXEL_FORMAT_RGB_565:
-      return DRM_FORMAT_BGR565;
-    case HAL_PIXEL_FORMAT_YV12:
-      return DRM_FORMAT_YVU420;
-    default:
-      ALOGE("Cannot convert hal format to drm format %u", hal_format);
-      return -EINVAL;
-  }
-}
-
-int hwc_import_bo_create(int fd, hwc_import_context *ctx,
-                         buffer_handle_t handle, struct hwc_drm_bo *bo) {
-  gralloc_drm_handle_t *gr_handle = gralloc_drm_handle(handle);
-  if (!gr_handle)
-    return -EINVAL;
-
-  struct gralloc_drm_bo_t *gralloc_bo = gr_handle->data;
-  if (!gralloc_bo) {
-    ALOGE("Could not get drm bo from handle");
-    return -EINVAL;
-  }
-
-  uint32_t gem_handle;
-  int ret = drmPrimeFDToHandle(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;
-  }
-
-  bo->width = gr_handle->width;
-  bo->height = gr_handle->height;
-  bo->format = hwc_convert_hal_format_to_drm_format(gr_handle->format);
-  bo->pitches[0] = gr_handle->stride;
-  bo->gem_handles[0] = gem_handle;
-  bo->offsets[0] = 0;
-
-  ret = drmModeAddFB2(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;
-}
-
-bool hwc_import_bo_release(int fd, hwc_import_context */* ctx */,
-                           struct hwc_drm_bo *bo) {
-  if (bo->fb_id)
-    if (drmModeRmFB(fd, bo->fb_id))
-      ALOGE("Failed to rm fb");
-
-  /* hwc may close the gem handles now. */
-  return true;
-}
diff --git a/hwcomposer_import_nv_gralloc.cpp b/hwcomposer_import_nv_gralloc.cpp
deleted file mode 100644
index ef6bdb2..0000000
--- a/hwcomposer_import_nv_gralloc.cpp
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- * Copyright (C) 2015 NVIDIA Corporation.
- *
- * 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 <cutils/log.h>
-#include <hardware/gralloc.h>
-
-#include <stdlib.h>
-#include <xf86drm.h>
-#include <xf86drmMode.h>
-#include "drm_hwcomposer.h"
-
-#define ARRAY_SIZE(arr) (int)(sizeof(arr) / sizeof((arr)[0]))
-
-struct hwc_import_context {
-  const gralloc_module_t *gralloc_module;
-};
-
-int hwc_import_init(struct hwc_import_context **ctx) {
-  struct hwc_import_context *import_ctx = (struct hwc_import_context *)calloc(1, sizeof(*import_ctx));
-  if (!ctx) {
-    ALOGE("Failed to allocate gralloc import context");
-    return -ENOMEM;
-  }
-
-  int ret = hw_get_module(GRALLOC_HARDWARE_MODULE_ID,
-                      (const hw_module_t **)&import_ctx->gralloc_module);
-  if (ret) {
-    ALOGE("Failed to open gralloc module");
-    free(import_ctx);
-    return ret;
-  }
-
-  if (!strcasecmp(import_ctx->gralloc_module->common.author, "NVIDIA"))
-    ALOGW("Using non-NVIDIA gralloc module: %s\n",
-          import_ctx->gralloc_module->common.name);
-
-  *ctx = import_ctx;
-
-  return 0;
-}
-
-int hwc_import_destroy(struct hwc_import_context *ctx) {
-  free(ctx);
-  return 0;
-}
-
-struct importer_priv {
-  int drm_fd;
-  struct hwc_drm_bo bo;
-};
-
-static void free_priv(void *p) {
-  struct importer_priv *priv = (struct importer_priv *)p;
-  if (priv->bo.fb_id) {
-    int ret = drmModeRmFB(priv->drm_fd, priv->bo.fb_id);
-    if (ret)
-      ALOGE("Failed to rm fb %d", ret);
-  }
-
-  struct drm_gem_close gem_close;
-  memset(&gem_close, 0, sizeof(gem_close));
-  for (int i = 0; i < ARRAY_SIZE(priv->bo.gem_handles); i++) {
-    if (!priv->bo.gem_handles[i])
-      continue;
-    gem_close.handle = priv->bo.gem_handles[i];
-    int ret = drmIoctl(priv->drm_fd, DRM_IOCTL_GEM_CLOSE, &gem_close);
-    if (ret)
-      ALOGE("Failed to close gem handle %d", ret);
-  }
-
-  free(priv);
-}
-
-static int hwc_import_set_priv(hwc_import_context *ctx, buffer_handle_t handle,
-                               struct importer_priv *priv) {
-  const gralloc_module_t *g = ctx->gralloc_module;
-  return g->perform(g, GRALLOC_MODULE_PERFORM_SET_IMPORTER_PRIVATE, handle,
-                    free_priv, priv);
-}
-
-static struct importer_priv *hwc_import_get_priv(hwc_import_context *ctx,
-                                                 buffer_handle_t handle) {
-  const gralloc_module_t *g = ctx->gralloc_module;
-  void *priv = NULL;
-  int ret = g->perform(g, GRALLOC_MODULE_PERFORM_GET_IMPORTER_PRIVATE, handle,
-                   free_priv, &priv);
-  return ret ? NULL : (struct importer_priv *)priv;
-}
-
-int hwc_import_bo_create(int fd, hwc_import_context *ctx,
-                         buffer_handle_t handle, struct hwc_drm_bo *bo) {
-  /* Get imported bo that is cached in gralloc buffer, or create a new one. */
-  struct importer_priv *priv = hwc_import_get_priv(ctx, handle);
-  if (priv) {
-    *bo = priv->bo;
-    return 0;
-  }
-
-  priv = (struct importer_priv *)calloc(1, sizeof(*priv));
-  if (!priv)
-    return -ENOMEM;
-  priv->drm_fd = fd;
-
-  const gralloc_module_t *g = ctx->gralloc_module;
-  int ret =
-      g->perform(g, GRALLOC_MODULE_PERFORM_DRM_IMPORT, fd, handle, &priv->bo);
-  if (ret) {
-    ALOGE("GRALLOC_MODULE_PERFORM_DRM_IMPORT failed %d", ret);
-    free_priv(priv);
-    return ret;
-  }
-
-  ret = drmModeAddFB2(fd, priv->bo.width, priv->bo.height, priv->bo.format,
-                      priv->bo.gem_handles, priv->bo.pitches,
-                      priv->bo.offsets, &priv->bo.fb_id, 0);
-  if (ret) {
-    ALOGE("Failed to add fb %d", ret);
-    free_priv(priv);
-    return ret;
-  }
-
-  ret = hwc_import_set_priv(ctx, handle, priv);
-  if (ret) {
-    /* This will happen is persist.tegra.gpu_mapping_cache is 0/off,
-     * or if NV gralloc runs out of "priv slots" (currently 3 per buffer,
-     * only one of which should be used by drm_hwcomposer). */
-    ALOGE("Failed to register free callback for imported buffer %d", ret);
-    free_priv(priv);
-    return ret;
-  }
-  *bo = priv->bo;
-  return ret;
-}
-
-bool hwc_import_bo_release(int fd, hwc_import_context *ctx,
-                           struct hwc_drm_bo *bo) {
-  /* hwc may not close the gem handles, we own them */
-  return false;
-}
diff --git a/importer.h b/importer.h
new file mode 100644
index 0000000..8bd40da
--- /dev/null
+++ b/importer.h
@@ -0,0 +1,51 @@
+/*
+ * 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_IMPORTER_H_
+#define ANDROID_DRM_IMPORTER_H_
+
+#include "drm_hwcomposer.h"
+
+#include <hardware/hardware.h>
+#include <hardware/hwcomposer.h>
+
+namespace android {
+
+class DrmResources;
+
+class Importer {
+ public:
+  virtual ~Importer() {
+  }
+
+  // Creates a platform-specific importer instance
+  static Importer *CreateInstance(DrmResources *drm);
+
+  // Imports the buffer referred to by handle into bo.
+  //
+  // Note: This can be called from a different thread than ReleaseBuffer. The
+  //       implementation is responsible for ensuring thread safety.
+  virtual int ImportBuffer(buffer_handle_t handle, hwc_drm_bo_t *bo) = 0;
+
+  // Releases the buffer object (ie: does the inverse of ImportBuffer)
+  //
+  // Note: This can be called from a different thread than ImportBuffer. The
+  //       implementation is responsible for ensuring thread safety.
+  virtual int ReleaseBuffer(hwc_drm_bo_t *bo) = 0;
+};
+}
+
+#endif
diff --git a/nvimporter.cpp b/nvimporter.cpp
new file mode 100644
index 0000000..d673438
--- /dev/null
+++ b/nvimporter.cpp
@@ -0,0 +1,164 @@
+/*
+ * 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 LOG_TAG "hwc-nv-importer"
+
+#include "drmresources.h"
+#include "importer.h"
+#include "nvimporter.h"
+
+#include <xf86drm.h>
+#include <xf86drmMode.h>
+
+#include <cutils/log.h>
+#include <hardware/gralloc.h>
+
+namespace android {
+
+#ifdef USE_NVIDIA_IMPORTER
+// static
+Importer *Importer::CreateInstance(DrmResources *drm) {
+  NvImporter *importer = new NvImporter(drm);
+  if (!importer)
+    return NULL;
+
+  int ret = importer->Init();
+  if (ret) {
+    ALOGE("Failed to initialize the nv importer %d", ret);
+    delete importer;
+    return NULL;
+  }
+  return importer;
+}
+#endif
+
+NvImporter::NvImporter(DrmResources *drm) : drm_(drm) {
+}
+
+NvImporter::~NvImporter() {
+}
+
+int NvImporter::Init() {
+  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;
+  }
+
+  if (strcasecmp(gralloc_->common.author, "NVIDIA"))
+    ALOGW("Using non-NVIDIA gralloc module: %s/%s\n", gralloc_->common.name,
+          gralloc_->common.author);
+
+  return 0;
+}
+
+int NvImporter::ImportBuffer(buffer_handle_t handle, hwc_drm_bo_t *bo) {
+  memset(bo, 0, sizeof(hwc_drm_bo_t));
+  NvBuffer_t *buf = GrallocGetNvBuffer(handle);
+  if (buf) {
+    *bo = buf->bo;
+    return 0;
+  }
+
+  buf = new NvBuffer_t();
+  if (!buf) {
+    ALOGE("Failed to allocate new NvBuffer_t");
+    return -ENOMEM;
+  }
+  buf->importer = this;
+
+  int ret = gralloc_->perform(gralloc_, GRALLOC_MODULE_PERFORM_DRM_IMPORT,
+                              drm_->fd(), handle, &buf->bo);
+  if (ret) {
+    ALOGE("GRALLOC_MODULE_PERFORM_DRM_IMPORT failed %d", ret);
+    delete buf;
+    return ret;
+  }
+
+  ret = drmModeAddFB2(drm_->fd(), buf->bo.width, buf->bo.height, buf->bo.format,
+                      buf->bo.gem_handles, buf->bo.pitches, buf->bo.offsets,
+                      &buf->bo.fb_id, 0);
+  if (ret) {
+    ALOGE("Failed to add fb %d", ret);
+    ReleaseBufferImpl(&buf->bo);
+    delete buf;
+    return ret;
+  }
+
+  ret = GrallocSetNvBuffer(handle, buf);
+  if (ret) {
+    /* This will happen is persist.tegra.gpu_mapping_cache is 0/off,
+     * or if NV gralloc runs out of "priv slots" (currently 3 per buffer,
+     * only one of which should be used by drm_hwcomposer). */
+    ALOGE("Failed to register free callback for imported buffer %d", ret);
+    ReleaseBufferImpl(&buf->bo);
+    delete buf;
+    return ret;
+  }
+  *bo = buf->bo;
+  return 0;
+}
+
+int NvImporter::ReleaseBuffer(hwc_drm_bo_t * /* bo */) {
+  /* Stub this out since we don't want hwc releasing buffers */
+  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::ReleaseBufferImpl(hwc_drm_bo_t *bo) {
+  if (bo->fb_id) {
+    int ret = drmModeRmFB(drm_->fd(), bo->fb_id);
+    if (ret)
+      ALOGE("Failed to rm fb %d", ret);
+  }
+
+  struct drm_gem_close gem_close;
+  memset(&gem_close, 0, sizeof(gem_close));
+  int num_gem_handles = sizeof(bo->gem_handles) / sizeof(bo->gem_handles[0]);
+  for (int i = 0; i < num_gem_handles; 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);
+    else
+      bo->gem_handles[i] = 0;
+  }
+}
+
+NvImporter::NvBuffer_t *NvImporter::GrallocGetNvBuffer(buffer_handle_t handle) {
+  void *priv = NULL;
+  int ret =
+      gralloc_->perform(gralloc_, GRALLOC_MODULE_PERFORM_GET_IMPORTER_PRIVATE,
+                        handle, ReleaseBufferCallback, &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);
+}
+}
diff --git a/nvimporter.h b/nvimporter.h
new file mode 100644
index 0000000..e3bdd1c
--- /dev/null
+++ b/nvimporter.h
@@ -0,0 +1,55 @@
+/*
+ * 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_NV_IMPORTER_H_
+#define ANDROID_NV_IMPORTER_H_
+
+#include "drmresources.h"
+#include "importer.h"
+
+#include <hardware/gralloc.h>
+
+namespace android {
+
+class NvImporter : public Importer {
+ public:
+  NvImporter(DrmResources *drm);
+  virtual ~NvImporter();
+
+  int Init();
+
+  virtual int ImportBuffer(buffer_handle_t handle, hwc_drm_bo_t *bo);
+  virtual int ReleaseBuffer(hwc_drm_bo_t *bo);
+
+ private:
+  typedef struct NvBuffer {
+    NvImporter *importer;
+    hwc_drm_bo_t bo;
+  } NvBuffer_t;
+
+  static void ReleaseBufferCallback(void *nv_buffer);
+  void ReleaseBufferImpl(hwc_drm_bo_t *bo);
+
+  NvBuffer_t *GrallocGetNvBuffer(buffer_handle_t handle);
+  int GrallocSetNvBuffer(buffer_handle_t handle, NvBuffer_t *buf);
+
+  DrmResources *drm_;
+
+  const gralloc_module_t *gralloc_;
+};
+}
+
+#endif