#include <fcntl.h>
#include <errno.h>
#include <xf86drm.h>
+#include <vc4_drm.h>
#include <pthread.h>
#include <hal-common.h>
#include <hal-tbm-types.h>
#include "tbm_backend_log.h"
#include "tbm_backend_list.h"
+#define VC4_DRM_NAME "vc4"
+
#define TBM_COLOR_FORMAT_COUNT 4
#define STRERR_BUFSIZE 128
#define SIZE_ALIGN(value, base) (((value) + ((base) - 1)) & ~((base) - 1))
#define TBM_SURFACE_ALIGNMENT_PITCH_YUV (32)
#define TBM_SURFACE_ALIGNMENT_HEIGHT_YUV (16)
+//#define VC4_TILED_FORMAT 1
+
struct dma_buf_info {
unsigned long size;
unsigned int fence_supported;
static int
_tbm_vc4_open_drm()
{
- struct udev *udev = NULL;
- struct udev_enumerate *e = NULL;
- struct udev_list_entry *entry = NULL;
- struct udev_device *device = NULL, *drm_device = NULL, *pci = NULL;
- const char *filepath, *id;
- struct stat s;
int fd = -1;
- int ret;
- udev = udev_new();
- if (!udev) {
- TBM_BACKEND_ERR("udev_new() failed.\n");
- return -1;
+ fd = drmOpen(VC4_DRM_NAME, NULL);
+ if (fd < 0) {
+ TBM_BACKEND_ERR("fail to open drm.(%s)\n", VC4_DRM_NAME);
}
- e = udev_enumerate_new(udev);
- udev_enumerate_add_match_subsystem(e, "drm");
- udev_enumerate_add_match_sysname(e, "card[0-9]*");
- udev_enumerate_scan_devices(e);
+ if (fd < 0) {
+ struct udev *udev = NULL;
+ struct udev_enumerate *e = NULL;
+ struct udev_list_entry *entry = NULL;
+ struct udev_device *device = NULL, *drm_device = NULL, *device_parent = NULL;
+ const char *filepath;
+ struct stat s;
+ int ret;
+
+ TBM_BACKEND_DBG("search drm-device by udev\n");
+
+ udev = udev_new();
+ if (!udev) {
+ TBM_BACKEND_ERR("udev_new() failed.\n");
+ return -1;
+ }
- drm_device = NULL;
- udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
- filepath = udev_list_entry_get_name(entry);
- device = udev_device_new_from_syspath(udev, filepath);
- if (!device)
- continue;
-
- pci = udev_device_get_parent_with_subsystem_devtype(device, "pci", NULL);
- if (pci) {
- id = udev_device_get_sysattr_value(pci, "boot_vga");
- if (id && !strcmp(id, "1")) {
- if (drm_device)
- udev_device_unref(drm_device);
- drm_device = device;
- break;
+ e = udev_enumerate_new(udev);
+ udev_enumerate_add_match_subsystem(e, "drm");
+ udev_enumerate_add_match_sysname(e, "card[0-9]*");
+ udev_enumerate_scan_devices(e);
+
+ udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
+ device = udev_device_new_from_syspath(udev_enumerate_get_udev(e),
+ udev_list_entry_get_name(entry));
+ device_parent = udev_device_get_parent(device);
+ /* Not need unref device_parent. device_parent and device have same refcnt */
+ if (device_parent) {
+ if (strcmp(udev_device_get_sysname(device_parent), "vc4-drm") == 0) {
+ drm_device = device;
+ TBM_BACKEND_DBG("Found render device: '%s' (%s)\n",
+ udev_device_get_syspath(drm_device),
+ udev_device_get_sysname(device_parent));
+ break;
+ }
}
+ udev_device_unref(device);
}
- if (!drm_device)
- drm_device = device;
- else
- udev_device_unref(device);
- }
+ udev_enumerate_unref(e);
- udev_enumerate_unref(e);
+ /* Get device file path. */
+ filepath = udev_device_get_devnode(drm_device);
+ if (!filepath) {
+ TBM_BACKEND_ERR("udev_device_get_devnode() failed.\n");
+ udev_device_unref(drm_device);
+ udev_unref(udev);
+ return -1;
+ }
- /* Get device file path. */
- filepath = udev_device_get_devnode(drm_device);
- if (!filepath) {
- TBM_BACKEND_ERR("udev_device_get_devnode() failed.\n");
- udev_device_unref(drm_device);
- udev_unref(udev);
- return -1;
- }
+ /* Open DRM device file and check validity. */
+ fd = open(filepath, O_RDWR | O_CLOEXEC);
+ if (fd < 0) {
+ TBM_BACKEND_ERR("open(%s, O_RDWR | O_CLOEXEC) failed.\n");
+ udev_device_unref(drm_device);
+ udev_unref(udev);
+ return -1;
+ }
- /* Open DRM device file and check validity. */
- fd = open(filepath, O_RDWR | O_CLOEXEC);
- if (fd < 0) {
- TBM_BACKEND_ERR("open(%s, O_RDWR | O_CLOEXEC) failed.\n");
- udev_device_unref(drm_device);
- udev_unref(udev);
- return -1;
- }
+ ret = fstat(fd, &s);
+ if (ret) {
+ TBM_BACKEND_ERR("fstat() failed %s.\n");
+ close(fd);
+ udev_device_unref(drm_device);
+ udev_unref(udev);
+ return -1;
+ }
- ret = fstat(fd, &s);
- if (ret) {
- TBM_BACKEND_ERR("fstat() failed %s.\n");
- close(fd);
udev_device_unref(drm_device);
udev_unref(udev);
- return -1;
}
- udev_device_unref(drm_device);
- udev_unref(udev);
-
return fd;
}
break;
case HAL_TBM_DEVICE_CPU:
if (!bo_data->pBase) {
- struct drm_mode_map_dumb arg = {0,};
+ struct drm_vc4_mmap_bo arg = {0, };
void *map = NULL;
arg.handle = bo_data->gem;
- if (drmIoctl(bo_data->fd, DRM_IOCTL_MODE_MAP_DUMB, &arg)) {
+ if (drmIoctl(bo_data->fd, DRM_IOCTL_VC4_MMAP_BO, &arg)) {
TBM_BACKEND_ERR("Cannot map_vc4 gem=%d\n", bo_data->gem);
return (hal_tbm_bo_handle) NULL;
}
{
hal_tbm_bufmgr_capability capabilities = HAL_TBM_BUFMGR_CAPABILITY_NONE;
+#ifdef VC4_TILED_FORMAT
+ capabilities = HAL_TBM_BUFMGR_CAPABILITY_SHARE_KEY|HAL_TBM_BUFMGR_CAPABILITY_SHARE_FD|HAL_TBM_BUFMGR_CAPABILITY_TILED_MEMORY;
+#else
capabilities = HAL_TBM_BUFMGR_CAPABILITY_SHARE_KEY|HAL_TBM_BUFMGR_CAPABILITY_SHARE_FD;
+#endif
if (error)
*error = HAL_TBM_ERROR_NONE;
}
+#ifdef VC4_TILED_FORMAT
+#include <drm_fourcc.h>
+static inline uint32_t
+vc4_utile_width(int cpp)
+{
+ switch (cpp) {
+ case 1:
+ case 2:
+ return 8;
+ case 4:
+ return 4;
+ case 8:
+ return 2;
+ default:
+ return 4;
+ }
+}
+
+static inline uint32_t
+vc4_utile_height(int cpp)
+{
+ switch (cpp) {
+ case 1:
+ return 8;
+ case 2:
+ case 4:
+ case 8:
+ return 4;
+ default:
+ return 4;
+ }
+}
+
+static inline bool
+vc4_size_is_lt(uint32_t width, uint32_t height, int cpp)
+{
+ return (width <= 4 * vc4_utile_width(cpp) ||
+ height <= 4 * vc4_utile_height(cpp));
+}
+
+static hal_tbm_bo *
+tbm_vc4_bufmgr_alloc_bo_with_tiled_format(hal_tbm_bufmgr *bufmgr, int width, int height,
+ int cpp, int format, hal_tbm_bo_memory_type flags, int bo_idx, hal_tbm_error *err)
+{
+ tbm_vc4_bufmgr *bufmgr_data = (tbm_vc4_bufmgr *)bufmgr;
+ tbm_vc4_bo *bo_data;
+ uint32_t utile_w = vc4_utile_width(cpp);
+ uint32_t utile_h = vc4_utile_height(cpp);
+ uint32_t level_width, level_height;
+ int size;
+ uint32_t stride;
+
+
+ level_width = width;
+ level_height = height;
+
+ if (bufmgr_data == NULL) {
+ TBM_BACKEND_ERR("bufmgr is null\n");
+ return NULL;
+ }
+
+ if (vc4_size_is_lt(level_width, level_height, cpp)) {
+ level_width = SIZE_ALIGN(level_width, utile_w);
+ level_height = SIZE_ALIGN(level_height, utile_h);
+ } else {
+ level_width = SIZE_ALIGN(level_width,
+ 4 * 2 * utile_w);
+ level_height = SIZE_ALIGN(level_height,
+ 4 * 2 * utile_h);
+ }
+
+ stride = level_width * cpp;
+
+ size = level_height * stride;
+ size = SIZE_ALIGN(size, 4096);
+
+
+ bo_data = calloc(1, sizeof(struct _tbm_vc4_bo));
+ if (!bo_data) {
+ TBM_BACKEND_ERR("fail to allocate the bo_data private\n");
+ return NULL;
+ }
+ bo_data->bufmgr_data = bufmgr_data;
+
+ struct drm_vc4_create_bo arg = {0, };
+
+ arg.size = (__u32)size;
+ arg.flags = flags;/*currently no values for the flags,but it may be used in future extension*/
+ if (drmIoctl(bufmgr_data->fd, DRM_IOCTL_VC4_CREATE_BO, &arg)) {
+ TBM_BACKEND_ERR("Cannot create bo_data(flag:%x, size:%d)\n", arg.flags,
+ (unsigned int)arg.size);
+ free(bo_data);
+ return NULL;
+ }
+
+ bo_data->fd = bufmgr_data->fd;
+ bo_data->gem = (unsigned int)arg.handle;
+ bo_data->size = size;
+ bo_data->flags_tbm = flags;
+ bo_data->name = _get_name(bo_data->fd, bo_data->gem);
+
+ if (!_bo_init_cache_state(bufmgr_data, bo_data, 0)) {
+ TBM_BACKEND_ERR("fail init cache state(%d)\n", bo_data->name);
+ free(bo_data);
+ return NULL;
+ }
+
+ pthread_mutex_init(&bo_data->mutex, NULL);
+
+ if (bufmgr_data->use_dma_fence && !bo_data->dmabuf) {
+ struct drm_prime_handle arg = {0, };
+
+ arg.handle = bo_data->gem;
+ if (drmIoctl(bo_data->fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &arg)) {
+ TBM_BACKEND_ERR("Cannot dmabuf=%d\n", bo_data->gem);
+ free(bo_data);
+ return NULL;
+ }
+ bo_data->dmabuf = arg.fd;
+ }
+
+ //set modifier
+ uint64_t modifier;
+ modifier = DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED;
+ struct drm_vc4_set_tiling set_tiling = {
+ .handle = bo_data->gem,
+ .modifier = modifier,
+ };
+ drmIoctl(bo_data->fd, DRM_IOCTL_VC4_SET_TILING, &set_tiling);
+
+
+ /* add bo_data to hash */
+ if (drmHashInsert(bufmgr_data->hashBos, bo_data->name, (void *)bo_data) < 0)
+ TBM_BACKEND_ERR("Cannot insert bo_data to Hash(%d)\n", bo_data->name);
+
+ TBM_BACKEND_DBG(" bo_data:%p, gem:%d(%d), flags:%d(%d), size:%d\n",
+ bo_data,
+ bo_data->gem, bo_data->name,
+ bo_data->flags_tbm,
+ bo_data->size);
+
+ return (hal_tbm_bo *)bo_data;
+}
+#endif
+
static int
_tbm_vc4_bufmgr_get_num_planes(hal_tbm_format format)
{
case HAL_TBM_FORMAT_BGRA8888:
bpp = 32;
_offset = 0;
+#ifdef VC4_TILED_FORMAT
+ if (vc4_size_is_lt(width, height, 4)) {
+ width = SIZE_ALIGN(width, vc4_utile_width(4));
+ height = SIZE_ALIGN(height, vc4_utile_height(4));
+
+ } else {
+ width = SIZE_ALIGN(width, 32);
+ uint32_t utile_h = vc4_utile_height(bpp);
+ height = SIZE_ALIGN(height, 8*utile_h);
+ }
+#endif
_pitch = SIZE_ALIGN((width * bpp) >> 3, TBM_SURFACE_ALIGNMENT_PITCH_RGB);
_size = SIZE_ALIGN(_pitch * height, TBM_SURFACE_ALIGNMENT_PLANE);
_bo_idx = 0;
}
bo_data->bufmgr_data = bufmgr_data;
- struct drm_mode_create_dumb arg = {0, };
- //as we know only size for new bo set height=1 and bpp=8 and in this case
- //width will by equal to size in bytes;
- arg.height = 1;
- arg.bpp = 8;
- arg.width = size;
+ struct drm_vc4_create_bo arg = {0, };
+
+ arg.size = (__u32)size;
arg.flags = flags;/*currently no values for the flags,but it may be used in future extension*/
- if (drmIoctl(bufmgr_data->fd, DRM_IOCTL_MODE_CREATE_DUMB, &arg)) {
+ if (drmIoctl(bufmgr_data->fd, DRM_IOCTL_VC4_CREATE_BO, &arg)) {
TBM_BACKEND_ERR("Cannot create bo_data(flag:%x, size:%d)\n", arg.flags,
(unsigned int)arg.size);
free(bo_data);
bo_data->name = name;
bo_data->flags_tbm = 0;
+#ifdef VC4_TILED_FORMAT
+ struct drm_vc4_get_tiling get_tiling = {
+ .handle = bo_data->gem,
+ };
+ drmIoctl(bo_data->fd, DRM_IOCTL_VC4_GET_TILING, &get_tiling);
+
+ if (get_tiling.modifier == DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED)
+ bo_data->flags_tbm |= HAL_TBM_BO_TILED;
+#endif
+
if (!_bo_init_cache_state(bufmgr_data, bo_data, 1)) {
TBM_BACKEND_ERR("fail init cache state(%d)\n", bo_data->name);
free(bo_data);
bo_data->name = key;
bo_data->flags_tbm = 0;
+#ifdef VC4_TILED_FORMAT
+ struct drm_vc4_get_tiling get_tiling = {
+ .handle = bo_data->gem,
+ };
+ drmIoctl(bo_data->fd, DRM_IOCTL_VC4_GET_TILING, &get_tiling);
+
+ if (get_tiling.modifier == DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED)
+ bo_data->flags_tbm |= HAL_TBM_BO_TILED;
+#endif
+
if (!_bo_init_cache_state(bufmgr_data, bo_data, 1)) {
TBM_BACKEND_ERR("fail init cache state(%d)\n", bo_data->name);
free(bo_data);
bufmgr_funcs->bufmgr_alloc_surface = tbm_vc4_bufmgr_alloc_surface;
bufmgr_funcs->bufmgr_import_surface = tbm_vc4_bufmgr_import_surface;
bufmgr_funcs->bufmgr_alloc_bo = tbm_vc4_bufmgr_alloc_bo;
+#ifdef VC4_TILED_FORMAT
+ bufmgr_funcs->bufmgr_alloc_bo_with_format = tbm_vc4_bufmgr_alloc_bo_with_tiled_format;
+#else
bufmgr_funcs->bufmgr_alloc_bo_with_format = NULL;
+#endif
bufmgr_funcs->bufmgr_import_fd = tbm_vc4_bufmgr_import_fd;
bufmgr_funcs->bufmgr_import_key = tbm_vc4_bufmgr_import_key;