199 lines
4.4 KiB
C
199 lines
4.4 KiB
C
#define LOG_TAG "GRALLOC-ROCKCHIP"
|
|
|
|
#include <cutils/log.h>
|
|
#include <stdlib.h>
|
|
#include <errno.h>
|
|
#include <drm.h>
|
|
#include <rockchip/rockchip_drmif.h>
|
|
|
|
#include "gralloc_drm.h"
|
|
#include "gralloc_drm_priv.h"
|
|
|
|
#define UNUSED(...) (void)(__VA_ARGS__)
|
|
|
|
struct rockchip_info {
|
|
struct gralloc_drm_drv_t base;
|
|
|
|
struct rockchip_device *rockchip;
|
|
int fd;
|
|
};
|
|
|
|
struct rockchip_buffer {
|
|
struct gralloc_drm_bo_t base;
|
|
|
|
struct rockchip_bo *bo;
|
|
};
|
|
|
|
static void drm_gem_rockchip_destroy(struct gralloc_drm_drv_t *drv)
|
|
{
|
|
struct rockchip_info *info = (struct rockchip_info *)drv;
|
|
|
|
if (info->rockchip)
|
|
rockchip_device_destroy(info->rockchip);
|
|
free(info);
|
|
}
|
|
|
|
static struct gralloc_drm_bo_t *drm_gem_rockchip_alloc(
|
|
struct gralloc_drm_drv_t *drv,
|
|
struct gralloc_drm_handle_t *handle)
|
|
{
|
|
struct rockchip_info *info = (struct rockchip_info *)drv;
|
|
struct rockchip_buffer *buf;
|
|
struct drm_gem_close args;
|
|
int ret, cpp, pitch, aligned_width, aligned_height;
|
|
uint32_t size, gem_handle;
|
|
|
|
buf = calloc(1, sizeof(*buf));
|
|
if (!buf) {
|
|
ALOGE("Failed to allocate buffer wrapper\n");
|
|
return NULL;
|
|
}
|
|
|
|
cpp = gralloc_drm_get_bpp(handle->format);
|
|
if (!cpp) {
|
|
ALOGE("unrecognized format 0x%x", handle->format);
|
|
return NULL;
|
|
}
|
|
|
|
aligned_width = handle->width;
|
|
aligned_height = handle->height;
|
|
gralloc_drm_align_geometry(handle->format,
|
|
&aligned_width, &aligned_height);
|
|
|
|
/* TODO: We need to sort out alignment */
|
|
pitch = ALIGN(aligned_width * cpp, 64);
|
|
size = aligned_height * pitch;
|
|
|
|
if (handle->format == HAL_PIXEL_FORMAT_YCbCr_420_888) {
|
|
/*
|
|
* WAR for H264 decoder requiring additional space
|
|
* at the end of destination buffers.
|
|
*/
|
|
uint32_t w_mbs, h_mbs;
|
|
|
|
w_mbs = ALIGN(handle->width, 16) / 16;
|
|
h_mbs = ALIGN(handle->height, 16) / 16;
|
|
size += 64 * w_mbs * h_mbs;
|
|
}
|
|
|
|
if (handle->prime_fd >= 0) {
|
|
ret = drmPrimeFDToHandle(info->fd, handle->prime_fd,
|
|
&gem_handle);
|
|
if (ret) {
|
|
char *c = NULL;
|
|
ALOGE("failed to convert prime fd to handle %d ret=%d",
|
|
handle->prime_fd, ret);
|
|
*c = 0;
|
|
goto err;
|
|
}
|
|
ALOGV("Got handle %d for fd %d\n", gem_handle, handle->prime_fd);
|
|
|
|
buf->bo = rockchip_bo_from_handle(info->rockchip, gem_handle,
|
|
0, size);
|
|
if (!buf->bo) {
|
|
ALOGE("failed to wrap bo handle=%d size=%d\n",
|
|
gem_handle, size);
|
|
|
|
memset(&args, 0, sizeof(args));
|
|
args.handle = gem_handle;
|
|
drmIoctl(info->fd, DRM_IOCTL_GEM_CLOSE, &args);
|
|
return NULL;
|
|
}
|
|
} else {
|
|
buf->bo = rockchip_bo_create(info->rockchip, size, 0);
|
|
if (!buf->bo) {
|
|
ALOGE("failed to allocate bo %dx%dx%dx%d\n",
|
|
handle->height, pitch, cpp, size);
|
|
goto err;
|
|
}
|
|
|
|
gem_handle = rockchip_bo_handle(buf->bo);
|
|
ret = drmPrimeHandleToFD(info->fd, gem_handle, 0,
|
|
&handle->prime_fd);
|
|
ALOGV("Got fd %d for handle %d\n", handle->prime_fd, gem_handle);
|
|
if (ret) {
|
|
ALOGE("failed to get prime fd %d", ret);
|
|
goto err_unref;
|
|
}
|
|
|
|
buf->base.fb_handle = gem_handle;
|
|
}
|
|
|
|
handle->name = 0;
|
|
handle->stride = pitch;
|
|
buf->base.handle = handle;
|
|
|
|
return &buf->base;
|
|
|
|
err_unref:
|
|
rockchip_bo_destroy(buf->bo);
|
|
err:
|
|
free(buf);
|
|
return NULL;
|
|
}
|
|
|
|
static void drm_gem_rockchip_free(struct gralloc_drm_drv_t *drv,
|
|
struct gralloc_drm_bo_t *bo)
|
|
{
|
|
struct rockchip_buffer *buf = (struct rockchip_buffer *)bo;
|
|
|
|
UNUSED(drv);
|
|
|
|
if (bo->handle && bo->handle->prime_fd)
|
|
close(bo->handle->prime_fd);
|
|
|
|
/* TODO: Is destroy correct here? */
|
|
rockchip_bo_destroy(buf->bo);
|
|
free(buf);
|
|
}
|
|
|
|
static int drm_gem_rockchip_map(struct gralloc_drm_drv_t *drv,
|
|
struct gralloc_drm_bo_t *bo, int x, int y, int w, int h,
|
|
int enable_write, void **addr)
|
|
{
|
|
struct rockchip_buffer *buf = (struct rockchip_buffer *)bo;
|
|
|
|
UNUSED(drv, x, y, w, h, enable_write);
|
|
|
|
*addr = rockchip_bo_map(buf->bo);
|
|
if (!*addr) {
|
|
ALOGE("failed to map bo\n");
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void drm_gem_rockchip_unmap(struct gralloc_drm_drv_t *drv,
|
|
struct gralloc_drm_bo_t *bo)
|
|
{
|
|
UNUSED(drv, bo);
|
|
}
|
|
|
|
struct gralloc_drm_drv_t *gralloc_drm_drv_create_for_rockchip(int fd)
|
|
{
|
|
struct rockchip_info *info;
|
|
int ret;
|
|
|
|
info = calloc(1, sizeof(*info));
|
|
if (!info) {
|
|
ALOGE("Failed to allocate rockchip gralloc device\n");
|
|
return NULL;
|
|
}
|
|
|
|
info->rockchip = rockchip_device_create(fd);
|
|
if (!info->rockchip) {
|
|
ALOGE("Failed to create new rockchip instance\n");
|
|
free(info);
|
|
return NULL;
|
|
}
|
|
|
|
info->fd = fd;
|
|
info->base.destroy = drm_gem_rockchip_destroy;
|
|
info->base.alloc = drm_gem_rockchip_alloc;
|
|
info->base.free = drm_gem_rockchip_free;
|
|
info->base.map = drm_gem_rockchip_map;
|
|
info->base.unmap = drm_gem_rockchip_unmap;
|
|
|
|
return &info->base;
|
|
}
|