drm_hwcomposer: Cache FB and gem in gralloc buffer
Move drm fb object creation to the importer.
In NV importer, use GRALLOC_MODULE_PERFORM_SET_IMPORTER_PRIVATE
and GRALLOC_MODULE_PERFORM_GET_IMPORTER_PRIVATE to cache the hwc_drm_bo
in the gralloc buffer. This avoids the need to recreate fb objects
again each frame, and also greatly simplifies managing the lifetime of
the gem handles.
The drm_gralloc importer does not support caching at this point. In an
attempt to keep it somewhat working, add hwc_import_bo_release function
that hwc calls when it's ok to rm fb. If hwc_import_bo_release returns
true, then hwc will clean up gem handles as it did before.
We should consider doing a follow-up patch that adds fb/gem caching to
drm_gralloc importer also. Then some of the code that is kept in this
patch for backwards compatibility can be removed.
Change-Id: I92857dcaddf8cea219ebc041e16ef76087a1b696
Reviewed-on: https://chrome-internal-review.googlesource.com/200895
Reviewed-by: Stéphane Marchesin <marcheu@google.com>
Commit-Queue: Stéphane Marchesin <marcheu@google.com>
Tested-by: Stéphane Marchesin <marcheu@google.com>
diff --git a/hwcomposer_import_nv_gralloc.cpp b/hwcomposer_import_nv_gralloc.cpp
index 4b9ad0f..f012aab 100644
--- a/hwcomposer_import_nv_gralloc.cpp
+++ b/hwcomposer_import_nv_gralloc.cpp
@@ -19,8 +19,12 @@
#include <cutils/log.h>
#include <hardware/gralloc.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;
};
@@ -63,11 +67,105 @@
return 0;
}
-int hwc_create_bo_from_import(int fd, hwc_import_context *ctx,
- buffer_handle_t handle, struct hwc_drm_bo *bo)
+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;
+ struct drm_gem_close gem_close;
+ int i, ret;
+
+ if (priv->bo.fb_id) {
+ ret = drmModeRmFB(priv->drm_fd, priv->bo.fb_id);
+ if (ret)
+ ALOGE("Failed to rm fb %d", ret);
+ }
+
+ memset(&gem_close, 0, sizeof(gem_close));
+ for (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];
+ 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)
+{
+ int ret;
const gralloc_module_t *g = ctx->gralloc_module;
- bo->importer_fd = -1;
- return g->perform(g, GRALLOC_MODULE_PERFORM_DRM_IMPORT, fd, handle, bo);
+ 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)
+{
+ int ret;
+ void *priv = NULL;
+ const gralloc_module_t *g = ctx->gralloc_module;
+
+ 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)
+{
+ int ret = 0;
+ const gralloc_module_t *g = ctx->gralloc_module;
+
+ /* 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) {
+ priv = (struct importer_priv *)calloc(1, sizeof(*priv));
+ if (!priv)
+ return -ENOMEM;
+ priv->drm_fd = fd;
+
+ 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;
}