summaryrefslogtreecommitdiffstats
path: root/gralloc_gbm.cpp
diff options
context:
space:
mode:
authorRob Herring <robh@kernel.org>2011-06-12 16:21:30 +0800
committerRob Herring <robh@kernel.org>2016-04-01 15:32:25 -0500
commitf6a33583e7ac19ef5a3f1d104b768ecd471fa851 (patch)
tree2372158843f33af9b4d0a3a5da6653033abfd1b7 /gralloc_gbm.cpp
downloadgbm_gralloc-f6a33583e7ac19ef5a3f1d104b768ecd471fa851.tar.gz
gbm_gralloc-f6a33583e7ac19ef5a3f1d104b768ecd471fa851.tar.xz
Initial GBM based gralloc
Based on drm_gralloc. Some remants of drm_gralloc remain to be compatible with mesa and drm_hwcomposer. Signed-off-by: Rob Herring <robh@kernel.org>
Diffstat (limited to 'gralloc_gbm.cpp')
-rw-r--r--gralloc_gbm.cpp486
1 files changed, 486 insertions, 0 deletions
diff --git a/gralloc_gbm.cpp b/gralloc_gbm.cpp
new file mode 100644
index 0000000..115aa8c
--- /dev/null
+++ b/gralloc_gbm.cpp
@@ -0,0 +1,486 @@
+/*
+ * Copyright (C) 2010-2011 Chia-I Wu <olvaffe@gmail.com>
+ * Copyright (C) 2010-2011 LunarG Inc.
+ * Copyright (C) 2016 Linaro, Ltd., Rob Herring <robh@kernel.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#define LOG_TAG "GRALLOC-GBM"
+
+#include <cutils/log.h>
+#include <cutils/atomic.h>
+#include <cutils/properties.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include <hardware/gralloc.h>
+#include <system/graphics.h>
+
+#include <gbm.h>
+
+#include "gralloc_gbm_priv.h"
+#include "gralloc_drm_handle.h"
+
+#define MAX(a, b) (((a) > (b)) ? (a) : (b))
+
+#define unlikely(x) __builtin_expect(!!(x), 0)
+
+struct gralloc_gbm_bo_t {
+ struct gbm_bo *bo;
+ void *map_data;
+
+ struct gralloc_gbm_handle_t *handle;
+
+ int imported; /* the handle is from a remote proces when true */
+
+ int lock_count;
+ int locked_for;
+
+ unsigned int refcount;
+};
+
+static int32_t gralloc_gbm_pid = 0;
+
+static uint32_t get_gbm_format(int format)
+{
+ uint32_t fmt;
+
+ switch (format) {
+ case HAL_PIXEL_FORMAT_RGBA_8888:
+ fmt = GBM_FORMAT_ABGR8888;
+ break;
+ case HAL_PIXEL_FORMAT_RGBX_8888:
+ fmt = GBM_FORMAT_XBGR8888;
+ break;
+ case HAL_PIXEL_FORMAT_RGB_888:
+ fmt = GBM_FORMAT_RGB888;
+ break;
+ case HAL_PIXEL_FORMAT_RGB_565:
+ fmt = GBM_FORMAT_BGR565;
+ break;
+ case HAL_PIXEL_FORMAT_BGRA_8888:
+ fmt = GBM_FORMAT_ARGB8888;
+ break;
+ case HAL_PIXEL_FORMAT_YV12:
+ case HAL_PIXEL_FORMAT_YCbCr_422_SP:
+ case HAL_PIXEL_FORMAT_YCrCb_420_SP:
+ default:
+ fmt = 0;
+ break;
+ }
+
+ return fmt;
+}
+
+static unsigned get_pipe_bind(int usage)
+{
+ unsigned bind = 0;
+#if 0
+ if (usage & GRALLOC_USAGE_SW_READ_MASK)
+ bind |= PIPE_BIND_TRANSFER_READ;
+ if (usage & GRALLOC_USAGE_SW_WRITE_MASK)
+ bind |= PIPE_BIND_TRANSFER_WRITE;
+ if (usage & GRALLOC_USAGE_HW_TEXTURE)
+ bind |= PIPE_BIND_SAMPLER_VIEW;
+#endif
+ if (usage & GRALLOC_USAGE_HW_RENDER)
+ bind |= GBM_BO_USE_RENDERING;
+ if (usage & GRALLOC_USAGE_HW_FB) {
+ bind |= GBM_BO_USE_SCANOUT;
+ }
+
+ return bind;
+}
+
+static struct gralloc_gbm_bo_t *gbm_import(struct gbm_device *gbm,
+ struct gralloc_gbm_handle_t *handle)
+{
+ struct gralloc_gbm_bo_t *buf;
+ struct gbm_import_fd_data data;
+ int format = get_gbm_format(handle->format);
+ int usage = get_pipe_bind(handle->usage);
+
+ if (handle->prime_fd < 0)
+ return NULL;
+
+ buf = new struct gralloc_gbm_bo_t();
+ if (!buf) {
+ ALOGE("failed to allocate pipe buffer");
+ return NULL;
+ }
+
+ data.fd = handle->prime_fd;
+ data.width = handle->width;
+ data.height = handle->height;
+ data.stride = handle->stride;
+ data.format = format;
+
+ buf->bo = gbm_bo_import(gbm, GBM_BO_IMPORT_FD, &data, 0);
+ if (!buf->bo) {
+ delete buf;
+ return NULL;
+ }
+ return buf;
+}
+
+static struct gralloc_gbm_bo_t *gbm_alloc(struct gbm_device *gbm,
+ struct gralloc_gbm_handle_t *handle)
+{
+ struct gralloc_gbm_bo_t *buf;
+ int format = get_gbm_format(handle->format);
+ int usage = get_pipe_bind(handle->usage);
+
+ buf = new struct gralloc_gbm_bo_t();
+ if (!buf) {
+ ALOGE("failed to allocate pipe buffer");
+ return NULL;
+ }
+
+ buf->bo = gbm_bo_create(gbm, handle->width, handle->height, format, usage);
+ if (!buf->bo) {
+ delete buf;
+ return NULL;
+ }
+
+ handle->prime_fd = gbm_bo_get_fd(buf->bo);
+ handle->stride = gbm_bo_get_stride(buf->bo);
+
+ return buf;
+}
+
+static void gbm_free(struct gralloc_gbm_bo_t *bo)
+{
+ struct gralloc_gbm_handle_t *handle = bo->handle;
+
+ close(handle->prime_fd);
+ handle->prime_fd = -1;
+
+ gbm_bo_destroy(bo->bo);
+ delete bo;
+}
+
+static int gbm_map(struct gralloc_gbm_bo_t *bo, int x, int y, int w, int h,
+ int enable_write, void **addr)
+{
+ int err = 0;
+
+ if (bo->map_data)
+ return -EINVAL;
+
+ *addr = gbm_bo_map(bo->bo, x, y, w, h, 0, &bo->map_data);
+ ALOGE("mapped bo %p at %p", bo, *addr);
+ if (*addr == NULL)
+ err = -ENOMEM;
+
+ return err;
+}
+
+static void gbm_unmap(struct gralloc_gbm_bo_t *bo)
+{
+ gbm_bo_unmap(bo->bo, bo->map_data);
+ bo->map_data = NULL;
+}
+
+void gbm_dev_destroy(struct gbm_device *gbm)
+{
+ int fd = gbm_device_get_fd(gbm);
+
+ gbm_device_destroy(gbm);
+ close(fd);
+}
+
+struct gbm_device *gbm_dev_create(void)
+{
+ struct gbm_device *gbm;
+ char path[PROPERTY_VALUE_MAX];
+ int fd;
+
+ property_get("gralloc.gbm.device", path, "/dev/dri/renderD128");
+ fd = open(path, O_RDWR);
+ if (fd < 0) {
+ ALOGE("failed to open %s", path);
+ return NULL;
+ }
+
+ gbm = gbm_create_device(fd);
+ if (!gbm) {
+ ALOGE("failed to create gbm device");
+ }
+
+ return gbm;
+}
+
+/*
+ * Return the pid of the process.
+ */
+static int gralloc_gbm_get_pid(void)
+{
+ if (unlikely(!gralloc_gbm_pid))
+ android_atomic_write((int32_t) getpid(), &gralloc_gbm_pid);
+
+ return gralloc_gbm_pid;
+}
+
+/*
+ * Validate a buffer handle and return the associated bo.
+ */
+static struct gralloc_gbm_bo_t *validate_handle(buffer_handle_t _handle,
+ struct gbm_device *gbm)
+{
+ struct gralloc_gbm_bo_t *bo;
+ struct gralloc_gbm_handle_t *handle = gralloc_gbm_handle(_handle);
+
+ if (!handle)
+ return NULL;
+
+ /* the buffer handle is passed to a new process */
+ //ALOGE("data_owner=%d gralloc_pid=%d data=%p\n", handle->data_owner, gralloc_gbm_get_pid(), handle->data);
+ if (handle->data_owner == gralloc_gbm_get_pid())
+ return (struct gralloc_gbm_bo_t *)handle->data;
+
+ /* check only */
+ if (!gbm)
+ return NULL;
+
+ ALOGE("handle: name=%d pfd=%d\n", handle->name,
+ handle->prime_fd);
+ /* create the struct gralloc_gbm_bo_t locally */
+ if (handle->name || handle->prime_fd >= 0)
+ bo = gbm_import(gbm, handle);
+ else /* an invalid handle */
+ bo = NULL;
+ if (bo) {
+ bo->imported = 1;
+ bo->handle = handle;
+ bo->refcount = 1;
+ }
+
+ handle->data_owner = gralloc_gbm_get_pid();
+ handle->data = bo;
+
+ return bo;
+}
+
+/*
+ * Register a buffer handle.
+ */
+int gralloc_gbm_handle_register(buffer_handle_t handle, struct gbm_device *gbm)
+{
+ return (validate_handle(handle, gbm)) ? 0 : -EINVAL;
+}
+
+/*
+ * Unregister a buffer handle. It is no-op for handles created locally.
+ */
+int gralloc_gbm_handle_unregister(buffer_handle_t handle)
+{
+ struct gralloc_gbm_bo_t *bo;
+
+ bo = validate_handle(handle, NULL);
+ if (!bo)
+ return -EINVAL;
+
+ if (bo->imported)
+ gralloc_gbm_bo_decref(bo);
+
+ return 0;
+}
+
+/*
+ * Create a buffer handle.
+ */
+static struct gralloc_gbm_handle_t *create_bo_handle(int width,
+ int height, int format, int usage)
+{
+ struct gralloc_gbm_handle_t *handle;
+
+ handle = new gralloc_gbm_handle_t();
+ if (!handle)
+ return NULL;
+
+ handle->base.version = sizeof(handle->base);
+ handle->base.numInts = GRALLOC_GBM_HANDLE_NUM_INTS;
+ handle->base.numFds = GRALLOC_GBM_HANDLE_NUM_FDS;
+
+ handle->magic = GRALLOC_GBM_HANDLE_MAGIC;
+ handle->width = width;
+ handle->height = height;
+ handle->format = format;
+ handle->usage = usage;
+ handle->prime_fd = -1;
+
+ return handle;
+}
+
+/*
+ * Create a bo.
+ */
+struct gralloc_gbm_bo_t *gralloc_gbm_bo_create(struct gbm_device *gbm,
+ int width, int height, int format, int usage)
+{
+ struct gralloc_gbm_bo_t *bo;
+ struct gralloc_gbm_handle_t *handle;
+
+ handle = create_bo_handle(width, height, format, usage);
+ if (!handle)
+ return NULL;
+
+ bo = gbm_alloc(gbm, handle);
+ if (!bo) {
+ delete handle;
+ return NULL;
+ }
+
+ bo->imported = 0;
+ bo->handle = handle;
+ bo->refcount = 1;
+
+ handle->data_owner = gralloc_gbm_get_pid();
+ handle->data = bo;
+
+ return bo;
+}
+
+/*
+ * Destroy a bo.
+ */
+static void gralloc_gbm_bo_destroy(struct gralloc_gbm_bo_t *bo)
+{
+ struct gralloc_gbm_handle_t *handle = bo->handle;
+ int imported = bo->imported;
+
+ /* gralloc still has a reference */
+ if (bo->refcount)
+ return;
+
+ gbm_free(bo);
+ if (imported) {
+ handle->data_owner = 0;
+ handle->data = 0;
+ }
+ else {
+ delete handle;
+ }
+}
+
+/*
+ * Decrease refcount, if no refs anymore then destroy.
+ */
+void gralloc_gbm_bo_decref(struct gralloc_gbm_bo_t *bo)
+{
+ if (!--bo->refcount)
+ gralloc_gbm_bo_destroy(bo);
+}
+
+/*
+ * Return the bo of a registered handle.
+ */
+struct gralloc_gbm_bo_t *gralloc_gbm_bo_from_handle(buffer_handle_t handle)
+{
+ return validate_handle(handle, NULL);
+}
+
+/*
+ * Get the buffer handle and stride of a bo.
+ */
+buffer_handle_t gralloc_gbm_bo_get_handle(struct gralloc_gbm_bo_t *bo)
+{
+ return &bo->handle->base;
+}
+
+/*
+ * Get the buffer handle and stride of a bo.
+ */
+struct gbm_bo *gralloc_gbm_bo_to_gbm_bo(struct gralloc_gbm_bo_t *_bo)
+{
+ return _bo->bo;
+}
+
+/*
+ * Query YUV component offsets for a buffer handle
+ */
+void gralloc_gbm_resolve_format(buffer_handle_t _handle,
+ uint32_t *pitches, uint32_t *offsets, uint32_t *handles)
+{}
+
+/*
+ * Lock a bo. XXX thread-safety?
+ */
+int gralloc_gbm_bo_lock(struct gralloc_gbm_bo_t *bo,
+ int usage, int x, int y, int w, int h,
+ void **addr)
+{
+ if ((bo->handle->usage & usage) != usage) {
+ /* make FB special for testing software renderer with */
+
+ if (!(bo->handle->usage & GRALLOC_USAGE_SW_READ_OFTEN) &&
+ !(bo->handle->usage & GRALLOC_USAGE_HW_FB) &&
+ !(bo->handle->usage & GRALLOC_USAGE_HW_TEXTURE)) {
+ ALOGE("bo.usage:x%X/usage:x%X is not GRALLOC_USAGE_HW_FB or GRALLOC_USAGE_HW_TEXTURE",
+ bo->handle->usage, usage);
+ return -EINVAL;
+ }
+ }
+
+ /* allow multiple locks with compatible usages */
+ if (bo->lock_count && (bo->locked_for & usage) != usage)
+ return -EINVAL;
+
+ usage |= bo->locked_for;
+
+ if (usage & (GRALLOC_USAGE_SW_WRITE_MASK |
+ GRALLOC_USAGE_SW_READ_MASK)) {
+ /* the driver is supposed to wait for the bo */
+ int write = !!(usage & GRALLOC_USAGE_SW_WRITE_MASK);
+ int err = gbm_map(bo, x, y, w, h, write, addr);
+ if (err)
+ return err;
+ }
+ else {
+ /* kernel handles the synchronization here */
+ }
+
+ bo->lock_count++;
+ bo->locked_for |= usage;
+
+ return 0;
+}
+
+/*
+ * Unlock a bo.
+ */
+void gralloc_gbm_bo_unlock(struct gralloc_gbm_bo_t *bo)
+{
+ int mapped = bo->locked_for &
+ (GRALLOC_USAGE_SW_WRITE_MASK | GRALLOC_USAGE_SW_READ_MASK);
+
+ if (!bo->lock_count)
+ return;
+
+ if (mapped)
+ gbm_unmap(bo);
+
+ bo->lock_count--;
+ if (!bo->lock_count)
+ bo->locked_for = 0;
+}