#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; }