#define LOG_TAG "GRALLOC-GBM"
-#include <cutils/log.h>
+#include <log/log.h>
#include <cutils/atomic.h>
#include <cutils/properties.h>
#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
+#include <assert.h>
+#include <xf86drm.h>
#include <hardware/gralloc.h>
#include <system/graphics.h>
#include <gbm.h>
#include "gralloc_gbm_priv.h"
-#include "gralloc_drm_handle.h"
+#include <android/gralloc_handle.h>
+
+#include <unordered_map>
#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 */
+static std::unordered_map<buffer_handle_t, struct gbm_bo *> gbm_bo_handle_map;
+struct bo_data_t {
+ void *map_data;
int lock_count;
int locked_for;
-
- unsigned int refcount;
};
-static int32_t gralloc_gbm_pid = 0;
+void gralloc_gbm_destroy_user_data(struct gbm_bo *bo, void *data)
+{
+ struct bo_data_t *bo_data = (struct bo_data_t *)data;
+ delete bo_data;
+
+ (void)bo;
+}
+
+static struct bo_data_t *gbm_bo_data(struct gbm_bo *bo) {
+ return (struct bo_data_t *)gbm_bo_get_user_data(bo);
+}
+
static uint32_t get_gbm_format(int format)
{
fmt = GBM_FORMAT_RGB888;
break;
case HAL_PIXEL_FORMAT_RGB_565:
- fmt = GBM_FORMAT_BGR565;
+ fmt = GBM_FORMAT_RGB565;
break;
case HAL_PIXEL_FORMAT_BGRA_8888:
fmt = GBM_FORMAT_ARGB8888;
break;
case HAL_PIXEL_FORMAT_YV12:
+ /* YV12 is planar, but must be a single buffer so ask for GR88 */
+ fmt = GBM_FORMAT_GR88;
+ break;
case HAL_PIXEL_FORMAT_YCbCr_422_SP:
case HAL_PIXEL_FORMAT_YCrCb_420_SP:
default:
return fmt;
}
+static int gralloc_gbm_get_bpp(int format)
+{
+ int bpp;
+
+ switch (format) {
+ case HAL_PIXEL_FORMAT_RGBA_8888:
+ case HAL_PIXEL_FORMAT_RGBX_8888:
+ case HAL_PIXEL_FORMAT_BGRA_8888:
+ bpp = 4;
+ break;
+ case HAL_PIXEL_FORMAT_RGB_888:
+ bpp = 3;
+ break;
+ case HAL_PIXEL_FORMAT_RGB_565:
+ case HAL_PIXEL_FORMAT_YCbCr_422_I:
+ bpp = 2;
+ break;
+ /* planar; only Y is considered */
+ case HAL_PIXEL_FORMAT_YV12:
+ case HAL_PIXEL_FORMAT_YCbCr_422_SP:
+ case HAL_PIXEL_FORMAT_YCrCb_420_SP:
+ bpp = 1;
+ break;
+ default:
+ bpp = 0;
+ break;
+ }
+
+ return bpp;
+}
+
static unsigned int get_pipe_bind(int usage)
{
unsigned int bind = 0;
bind |= GBM_BO_USE_RENDERING;
if (usage & GRALLOC_USAGE_HW_FB)
bind |= GBM_BO_USE_SCANOUT;
+ if (usage & GRALLOC_USAGE_HW_COMPOSER)
+ bind |= GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING;
return bind;
}
-static struct gralloc_gbm_bo_t *gbm_import(struct gbm_device *gbm,
- struct gralloc_gbm_handle_t *handle)
+static struct gbm_bo *gbm_import(struct gbm_device *gbm,
+ buffer_handle_t _handle)
{
- struct gralloc_gbm_bo_t *buf;
+ struct gbm_bo *bo;
+ struct gralloc_handle_t *handle = gralloc_handle(_handle);
+ #ifdef GBM_BO_IMPORT_FD_MODIFIER
+ struct gbm_import_fd_modifier_data data;
+ #else
struct gbm_import_fd_data data;
- int format = get_gbm_format(handle->format);
- int usage = get_pipe_bind(handle->usage);
+ #endif
+ int format = get_gbm_format(handle->format);
if (handle->prime_fd < 0)
return NULL;
- buf = new struct gralloc_gbm_bo_t();
- if (!buf) {
- ALOGE("failed to allocate pipe buffer");
- return NULL;
+ memset(&data, 0, sizeof(data));
+ data.width = handle->width;
+ data.height = handle->height;
+ data.format = format;
+ /* Adjust the width and height for a GBM GR88 buffer */
+ if (handle->format == HAL_PIXEL_FORMAT_YV12) {
+ data.width /= 2;
+ data.height += handle->height / 2;
}
+ #ifdef GBM_BO_IMPORT_FD_MODIFIER
+ data.num_fds = 1;
+ data.fds[0] = handle->prime_fd;
+ data.strides[0] = handle->stride;
+ data.modifier = handle->modifier;
+ bo = gbm_bo_import(gbm, GBM_BO_IMPORT_FD_MODIFIER, &data, 0);
+ #else
data.fd = handle->prime_fd;
- data.width = handle->width;
- data.height = handle->height;
data.stride = handle->stride;
- data.format = format;
+ bo = gbm_bo_import(gbm, GBM_BO_IMPORT_FD, &data, 0);
+ #endif
- buf->bo = gbm_bo_import(gbm, GBM_BO_IMPORT_FD, &data, 0);
- if (!buf->bo) {
- delete buf;
- return NULL;
- }
- return buf;
+ return bo;
}
-static struct gralloc_gbm_bo_t *gbm_alloc(struct gbm_device *gbm,
- struct gralloc_gbm_handle_t *handle)
+static struct gbm_bo *gbm_alloc(struct gbm_device *gbm,
+ buffer_handle_t _handle)
{
- struct gralloc_gbm_bo_t *buf;
+ struct gbm_bo *bo;
+ struct gralloc_handle_t *handle = gralloc_handle(_handle);
int format = get_gbm_format(handle->format);
int usage = get_pipe_bind(handle->usage);
int width, height;
- buf = new struct gralloc_gbm_bo_t();
- if (!buf) {
- ALOGE("failed to allocate pipe buffer");
- return NULL;
- }
-
width = handle->width;
height = handle->height;
if (usage & GBM_BO_USE_CURSOR) {
height = 64;
}
- ALOGD("create BO, size=%dx%d, fmt=%d, usage=%x",
+ /*
+ * For YV12, we request GR88, so halve the width since we're getting
+ * 16bpp. Then increase the height by 1.5 for the U and V planes.
+ */
+ if (handle->format == HAL_PIXEL_FORMAT_YV12) {
+ width /= 2;
+ height += handle->height / 2;
+ }
+
+ ALOGV("create BO, size=%dx%d, fmt=%d, usage=%x",
handle->width, handle->height, handle->format, usage);
- buf->bo = gbm_bo_create(gbm, width, height, format, usage);
- if (!buf->bo) {
+ bo = gbm_bo_create(gbm, width, height, format, usage);
+ if (!bo) {
ALOGE("failed to create BO, size=%dx%d, fmt=%d, usage=%x",
handle->width, handle->height, handle->format, usage);
- delete buf;
return NULL;
}
- handle->prime_fd = gbm_bo_get_fd(buf->bo);
- handle->stride = gbm_bo_get_stride(buf->bo);
+ handle->prime_fd = gbm_bo_get_fd(bo);
+ handle->stride = gbm_bo_get_stride(bo);
+ #ifdef GBM_BO_IMPORT_FD_MODIFIER
+ handle->modifier = gbm_bo_get_modifier(bo);
+ #endif
- return buf;
+ return bo;
}
-static void gbm_free(struct gralloc_gbm_bo_t *bo)
+int gbm_free(buffer_handle_t handle)
{
- struct gralloc_gbm_handle_t *handle = bo->handle;
+ struct gbm_bo *bo = gralloc_gbm_bo_from_handle(handle);
- close(handle->prime_fd);
- handle->prime_fd = -1;
+ if (!bo)
+ return -EINVAL;
- gbm_bo_destroy(bo->bo);
- delete bo;
+ gbm_bo_handle_map.erase(handle);
+ gbm_bo_destroy(bo);
+ return 0;
}
-static int gbm_map(struct gralloc_gbm_bo_t *bo, int x, int y, int w, int h,
- int enable_write, void **addr)
+/*
+ * Return the bo of a registered handle.
+ */
+struct gbm_bo *gralloc_gbm_bo_from_handle(buffer_handle_t handle)
+{
+ return gbm_bo_handle_map[handle];
+}
+
+static int gbm_map(buffer_handle_t handle, int enable_write, void **addr)
{
int err = 0;
+ int flags = GBM_BO_TRANSFER_READ;
+ struct gbm_bo *bo = gralloc_gbm_bo_from_handle(handle);
+ struct bo_data_t *bo_data = gbm_bo_data(bo);
+ uint32_t stride;
- if (bo->map_data)
+ if (bo_data->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 (enable_write)
+ flags |= GBM_BO_TRANSFER_WRITE;
+
+ *addr = gbm_bo_map(bo, 0, 0, gbm_bo_get_width(bo), gbm_bo_get_height(bo),
+ flags, &stride, &bo_data->map_data);
+ ALOGV("mapped bo %p at %p", bo, *addr);
if (*addr == NULL)
- err = -ENOMEM;
+ return -ENOMEM;
+
+ assert(stride == gbm_bo_get_stride(bo));
return err;
}
-static void gbm_unmap(struct gralloc_gbm_bo_t *bo)
+static void gbm_unmap(struct gbm_bo *bo)
{
- gbm_bo_unmap(bo->bo, bo->map_data);
- bo->map_data = NULL;
+ struct bo_data_t *bo_data = gbm_bo_data(bo);
+
+ gbm_bo_unmap(bo, bo_data->map_data);
+ bo_data->map_data = NULL;
}
void gbm_dev_destroy(struct gbm_device *gbm)
close(fd);
}
-struct gbm_device *gbm_dev_create(void)
+struct gbm_device *gbm_dev_create(bool master)
{
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 (property_get("gralloc.gbm.device", path, NULL) > 0)
+ fd = open(path, O_RDWR | O_CLOEXEC);
+ else
+ fd = drmOpenByFB(0, master ? DRM_NODE_PRIMARY : DRM_NODE_RENDER);
+
if (fd < 0) {
ALOGE("failed to open %s", path);
return NULL;
gbm = gbm_create_device(fd);
if (!gbm) {
ALOGE("failed to create gbm device");
+ close(fd);
}
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)
+int gralloc_gbm_handle_register(buffer_handle_t _handle, struct gbm_device *gbm)
{
- return (validate_handle(handle, gbm)) ? 0 : -EINVAL;
-}
+ struct gbm_bo *bo;
-/*
- * 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;
+ if (!_handle)
+ return -EINVAL;
+
+ if (gbm_bo_handle_map.count(_handle))
+ return -EINVAL;
- bo = validate_handle(handle, NULL);
+ bo = gbm_import(gbm, _handle);
if (!bo)
return -EINVAL;
- if (bo->imported)
- gralloc_gbm_bo_decref(bo);
+ gbm_bo_handle_map.emplace(_handle, bo);
return 0;
}
/*
- * Create a buffer handle.
+ * Unregister a buffer handle. It is no-op for handles created locally.
*/
-static struct gralloc_gbm_handle_t *create_bo_handle(int width,
- int height, int format, int usage)
+int gralloc_gbm_handle_unregister(buffer_handle_t handle)
{
- 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;
+ return gbm_free(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)
+buffer_handle_t gralloc_gbm_bo_create(struct gbm_device *gbm,
+ int width, int height, int format, int usage, int *stride)
{
- struct gralloc_gbm_bo_t *bo;
- struct gralloc_gbm_handle_t *handle;
+ struct gbm_bo *bo;
+ native_handle_t *handle;
- handle = create_bo_handle(width, height, format, usage);
+ handle = gralloc_handle_create(width, height, format, usage);
if (!handle)
return NULL;
bo = gbm_alloc(gbm, handle);
if (!bo) {
- delete handle;
+ native_handle_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);
-}
+ gbm_bo_handle_map.emplace(handle, bo);
-/*
- * 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;
-}
+ /* in pixels */
+ *stride = gralloc_handle(handle)->stride / gralloc_gbm_get_bpp(format);
-/*
- * 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;
+ return handle;
}
/*
- * 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,
+int gralloc_gbm_bo_lock(buffer_handle_t handle,
+ int usage, int /*x*/, int /*y*/, int /*w*/, int /*h*/,
void **addr)
{
- if ((bo->handle->usage & usage) != usage) {
+ struct gralloc_handle_t *gbm_handle = gralloc_handle(handle);
+ struct gbm_bo *bo = gralloc_gbm_bo_from_handle(handle);
+ struct bo_data_t *bo_data;
+
+ if (!bo)
+ return -EINVAL;
+
+ if ((gbm_handle->usage & usage) != (uint32_t)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)) {
+ if (!(gbm_handle->usage & GRALLOC_USAGE_SW_READ_OFTEN) &&
+ !(gbm_handle->usage & GRALLOC_USAGE_HW_FB) &&
+ !(gbm_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);
+ gbm_handle->usage, usage);
return -EINVAL;
}
}
+ bo_data = gbm_bo_data(bo);
+ if (!bo_data) {
+ bo_data = new struct bo_data_t();
+ gbm_bo_set_user_data(bo, bo_data, gralloc_gbm_destroy_user_data);
+ }
+
+ ALOGV("lock bo %p, cnt=%d, usage=%x", bo, bo_data->lock_count, usage);
+
/* allow multiple locks with compatible usages */
- if (bo->lock_count && (bo->locked_for & usage) != usage)
+ if (bo_data->lock_count && (bo_data->locked_for & usage) != usage)
return -EINVAL;
- usage |= bo->locked_for;
+ usage |= bo_data->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);
+ int err = gbm_map(handle, write, addr);
if (err)
return err;
}
/* kernel handles the synchronization here */
}
- bo->lock_count++;
- bo->locked_for |= usage;
+ bo_data->lock_count++;
+ bo_data->locked_for |= usage;
return 0;
}
/*
* Unlock a bo.
*/
-void gralloc_gbm_bo_unlock(struct gralloc_gbm_bo_t *bo)
+int gralloc_gbm_bo_unlock(buffer_handle_t handle)
{
- int mapped = bo->locked_for &
+ struct gbm_bo *bo = gralloc_gbm_bo_from_handle(handle);
+ struct bo_data_t *bo_data;
+ if (!bo)
+ return -EINVAL;
+
+ bo_data = gbm_bo_data(bo);
+
+ int mapped = bo_data->locked_for &
(GRALLOC_USAGE_SW_WRITE_MASK | GRALLOC_USAGE_SW_READ_MASK);
- if (!bo->lock_count)
- return;
+ if (!bo_data->lock_count)
+ return 0;
if (mapped)
gbm_unmap(bo);
- bo->lock_count--;
- if (!bo->lock_count)
- bo->locked_for = 0;
+ bo_data->lock_count--;
+ if (!bo_data->lock_count)
+ bo_data->locked_for = 0;
+
+ return 0;
+}
+
+#define GRALLOC_ALIGN(value, base) (((value) + ((base)-1)) & ~((base)-1))
+
+int gralloc_gbm_bo_lock_ycbcr(buffer_handle_t handle,
+ int usage, int x, int y, int w, int h,
+ struct android_ycbcr *ycbcr)
+{
+ struct gralloc_handle_t *hnd = gralloc_handle(handle);
+ int ystride, cstride;
+ void *addr = 0;
+ int err;
+
+ ALOGV("handle %p, hnd %p, usage 0x%x", handle, hnd, usage);
+
+ err = gralloc_gbm_bo_lock(handle, usage, x, y, w, h, &addr);
+ if (err)
+ return err;
+
+ memset(ycbcr->reserved, 0, sizeof(ycbcr->reserved));
+
+ switch (hnd->format) {
+ case HAL_PIXEL_FORMAT_YCrCb_420_SP:
+ ystride = cstride = GRALLOC_ALIGN(hnd->width, 16);
+ ycbcr->y = addr;
+ ycbcr->cr = (unsigned char *)addr + ystride * hnd->height;
+ ycbcr->cb = (unsigned char *)addr + ystride * hnd->height + 1;
+ ycbcr->ystride = ystride;
+ ycbcr->cstride = cstride;
+ ycbcr->chroma_step = 2;
+ break;
+ case HAL_PIXEL_FORMAT_YV12:
+ ystride = hnd->width;
+ cstride = GRALLOC_ALIGN(ystride / 2, 16);
+ ycbcr->y = addr;
+ ycbcr->cr = (unsigned char *)addr + ystride * hnd->height;
+ ycbcr->cb = (unsigned char *)addr + ystride * hnd->height + cstride * hnd->height / 2;
+ ycbcr->ystride = ystride;
+ ycbcr->cstride = cstride;
+ ycbcr->chroma_step = 1;
+ break;
+ default:
+ ALOGE("Can not lock buffer, invalid format: 0x%x", hnd->format);
+ return -EINVAL;
+ }
+
+ return 0;
}