blob: b4381736ca69e06ac2f94050e1d983e830655d2a [file] [log] [blame]
/*
* Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include <assert.h>
#include <fcntl.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <xf86drm.h>
#include "gbm_priv.h"
#include "helpers.h"
#include "util.h"
extern struct gbm_driver gbm_driver_cirrus;
extern struct gbm_driver gbm_driver_evdi;
#ifdef GBM_EXYNOS
extern struct gbm_driver gbm_driver_exynos;
#endif
extern struct gbm_driver gbm_driver_gma500;
#ifdef GBM_I915
extern struct gbm_driver gbm_driver_i915;
#endif
#ifdef GBM_MARVELL
extern struct gbm_driver gbm_driver_marvell;
#endif
#ifdef GBM_MEDIATEK
extern struct gbm_driver gbm_driver_mediatek;
#endif
#ifdef GBM_ROCKCHIP
extern struct gbm_driver gbm_driver_rockchip;
#endif
#ifdef GBM_TEGRA
extern struct gbm_driver gbm_driver_tegra;
#endif
extern struct gbm_driver gbm_driver_udl;
extern struct gbm_driver gbm_driver_virtio_gpu;
static struct gbm_driver *gbm_get_driver(int fd)
{
drmVersionPtr drm_version;
unsigned int i;
drm_version = drmGetVersion(fd);
if (!drm_version)
return NULL;
struct gbm_driver *driver_list[] = {
&gbm_driver_cirrus,
&gbm_driver_evdi,
#ifdef GBM_EXYNOS
&gbm_driver_exynos,
#endif
&gbm_driver_gma500,
#ifdef GBM_I915
&gbm_driver_i915,
#endif
#ifdef GBM_MARVELL
&gbm_driver_marvell,
#endif
#ifdef GBM_MEDIATEK
&gbm_driver_mediatek,
#endif
#ifdef GBM_ROCKCHIP
&gbm_driver_rockchip,
#endif
#ifdef GBM_TEGRA
&gbm_driver_tegra,
#endif
&gbm_driver_udl,
&gbm_driver_virtio_gpu,
};
for(i = 0; i < ARRAY_SIZE(driver_list); i++)
if (!strcmp(drm_version->name, driver_list[i]->name))
{
drmFreeVersion(drm_version);
return driver_list[i];
}
drmFreeVersion(drm_version);
return NULL;
}
PUBLIC int
gbm_device_get_fd(struct gbm_device *gbm)
{
return gbm->fd;
}
PUBLIC const char *
gbm_device_get_backend_name(struct gbm_device *gbm)
{
return gbm->driver->name;
}
PUBLIC int
gbm_device_is_format_supported(struct gbm_device *gbm,
uint32_t format, uint32_t usage)
{
unsigned i;
if (format == GBM_BO_FORMAT_XRGB8888)
format = GBM_FORMAT_XRGB8888;
if (format == GBM_BO_FORMAT_ARGB8888)
format = GBM_FORMAT_ARGB8888;
if (usage & GBM_BO_USE_CURSOR &&
usage & GBM_BO_USE_RENDERING)
return 0;
for(i = 0 ; i < ARRAY_SIZE(gbm->driver->format_list); i++)
{
if (!gbm->driver->format_list[i].format)
break;
if (gbm->driver->format_list[i].format == format &&
(gbm->driver->format_list[i].usage & usage) == usage)
return 1;
}
return 0;
}
PUBLIC struct gbm_device *gbm_create_device(int fd)
{
struct gbm_device *gbm;
int ret;
gbm = (struct gbm_device*) malloc(sizeof(*gbm));
if (!gbm)
return NULL;
gbm->fd = fd;
gbm->driver = gbm_get_driver(fd);
if (!gbm->driver) {
free(gbm);
return NULL;
}
if (gbm->driver->init) {
ret = gbm->driver->init(gbm);
if (ret) {
free(gbm);
return NULL;
}
}
return gbm;
}
PUBLIC void gbm_device_destroy(struct gbm_device *gbm)
{
if (gbm->driver->close)
gbm->driver->close(gbm);
free(gbm);
}
PUBLIC struct gbm_surface *gbm_surface_create(struct gbm_device *gbm,
uint32_t width, uint32_t height,
uint32_t format, uint32_t flags)
{
struct gbm_surface *surface =
(struct gbm_surface*) malloc(sizeof(*surface));
if (!surface)
return NULL;
return surface;
}
PUBLIC void gbm_surface_destroy(struct gbm_surface *surface)
{
free(surface);
}
PUBLIC struct gbm_bo *gbm_surface_lock_front_buffer(struct gbm_surface *surface)
{
return NULL;
}
PUBLIC void gbm_surface_release_buffer(struct gbm_surface *surface,
struct gbm_bo *bo)
{
}
static struct gbm_bo *gbm_bo_new(struct gbm_device *gbm,
uint32_t width, uint32_t height,
uint32_t format)
{
struct gbm_bo *bo;
bo = (struct gbm_bo*) calloc(1, sizeof(*bo));
if (!bo)
return NULL;
bo->gbm = gbm;
bo->width = width;
bo->height = height;
bo->format = format;
bo->num_planes = gbm_num_planes_from_format(format);
if (!bo->num_planes) {
free(bo);
return NULL;
}
return bo;
}
PUBLIC struct gbm_bo *gbm_bo_create(struct gbm_device *gbm, uint32_t width,
uint32_t height, uint32_t format,
uint32_t flags)
{
struct gbm_bo *bo;
int ret;
if (!gbm_device_is_format_supported(gbm, format, flags))
return NULL;
bo = gbm_bo_new(gbm, width, height, format);
if (!bo)
return NULL;
ret = gbm->driver->bo_create(bo, width, height, format, flags);
if (ret) {
free(bo);
return NULL;
}
return bo;
}
PUBLIC void gbm_bo_destroy(struct gbm_bo *bo)
{
if (bo->destroy_user_data) {
bo->destroy_user_data(bo, bo->user_data);
bo->destroy_user_data = NULL;
bo->user_data = NULL;
}
bo->gbm->driver->bo_destroy(bo);
free(bo);
}
PUBLIC struct gbm_bo *
gbm_bo_import(struct gbm_device *gbm, uint32_t type,
void *buffer, uint32_t usage)
{
struct gbm_import_fd_data *fd_data = buffer;
struct gbm_bo *bo;
struct drm_prime_handle prime_handle;
int ret;
if (type != GBM_BO_IMPORT_FD)
return NULL;
if (!gbm_device_is_format_supported(gbm, fd_data->format, usage))
return NULL;
/* This function can support only single plane formats. */
/* If multi-plane import is desired, new function should be added. */
if (gbm_num_planes_from_format(fd_data->format) != 1)
return NULL;
bo = gbm_bo_new(gbm, fd_data->width, fd_data->height, fd_data->format);
if (!bo)
return NULL;
bo->strides[0] = fd_data->stride;
bo->sizes[0] = fd_data->height * fd_data->stride;
prime_handle.fd = fd_data->fd;
ret = drmIoctl(bo->gbm->fd, DRM_IOCTL_PRIME_FD_TO_HANDLE, &prime_handle);
if (ret) {
fprintf(stderr, "minigbm: DRM_IOCTL_PRIME_FD_TO_HANDLE failed "
"(fd=%u)\n", prime_handle.fd);
free(bo);
return NULL;
}
bo->handles[0].u32 = prime_handle.handle;
return bo;
}
PUBLIC uint32_t
gbm_bo_get_width(struct gbm_bo *bo)
{
return bo->width;
}
PUBLIC uint32_t
gbm_bo_get_height(struct gbm_bo *bo)
{
return bo->height;
}
PUBLIC uint32_t
gbm_bo_get_stride(struct gbm_bo *bo)
{
return gbm_bo_get_plane_stride(bo, 0);
}
PUBLIC uint32_t
gbm_bo_get_stride_or_tiling(struct gbm_bo *bo)
{
return bo->tiling ? bo->tiling : gbm_bo_get_stride(bo);
}
PUBLIC uint32_t
gbm_bo_get_format(struct gbm_bo *bo)
{
return bo->format;
}
PUBLIC struct gbm_device *
gbm_bo_get_device(struct gbm_bo *bo)
{
return bo->gbm;
}
PUBLIC union gbm_bo_handle
gbm_bo_get_handle(struct gbm_bo *bo)
{
return gbm_bo_get_plane_handle(bo, 0);
}
PUBLIC int
gbm_bo_get_fd(struct gbm_bo *bo)
{
return gbm_bo_get_plane_fd(bo, 0);
}
PUBLIC size_t
gbm_bo_get_num_planes(struct gbm_bo *bo)
{
return bo->num_planes;
}
PUBLIC union gbm_bo_handle
gbm_bo_get_plane_handle(struct gbm_bo *bo, size_t plane)
{
assert(plane < bo->num_planes);
return bo->handles[plane];
}
#ifndef DRM_RDWR
#define DRM_RDWR O_RDWR
#endif
PUBLIC int
gbm_bo_get_plane_fd(struct gbm_bo *bo, size_t plane)
{
int fd;
assert(plane < bo->num_planes);
if (drmPrimeHandleToFD(
gbm_device_get_fd(bo->gbm),
gbm_bo_get_plane_handle(bo, plane).u32,
DRM_CLOEXEC | DRM_RDWR,
&fd))
return -1;
else
return fd;
}
PUBLIC uint32_t
gbm_bo_get_plane_offset(struct gbm_bo *bo, size_t plane)
{
assert(plane < bo->num_planes);
return bo->offsets[plane];
}
PUBLIC uint32_t
gbm_bo_get_plane_size(struct gbm_bo *bo, size_t plane)
{
assert(plane < bo->num_planes);
return bo->sizes[plane];
}
PUBLIC uint32_t
gbm_bo_get_plane_stride(struct gbm_bo *bo, size_t plane)
{
assert(plane < bo->num_planes);
return bo->strides[plane];
}
PUBLIC void
gbm_bo_set_user_data(struct gbm_bo *bo, void *data,
void (*destroy_user_data)(struct gbm_bo *, void *))
{
bo->user_data = data;
bo->destroy_user_data = destroy_user_data;
}
PUBLIC void *
gbm_bo_get_user_data(struct gbm_bo *bo)
{
return bo->user_data;
}