wayland_shm: Add exynos allocator for dmabuf

Allows clients on exynos hardware to allocate GEM buffer objects
to back DMAbuf buffers.
This commit is contained in:
Derek Foreman 2016-06-02 07:06:26 -05:00
parent 0f07f67b12
commit 821aada3c4
3 changed files with 383 additions and 0 deletions

View File

@ -10,6 +10,10 @@
#include <intel_bufmgr.h>
#include <i915_drm.h>
#include <exynos_drm.h>
#include <exynos_drmif.h>
#include <sys/mman.h>
#include "linux-dmabuf-unstable-v1-client-protocol.h"
#define SYM(lib, xx) \
@ -88,6 +92,11 @@ drm_intel_bo *(*sym_drm_intel_bo_alloc_tiled)(drm_intel_bufmgr *mgr, const char
void (*sym_drm_intel_bo_unreference)(drm_intel_bo *bo) = NULL;
int (*sym_drmPrimeHandleToFD)(int fd, uint32_t handle, uint32_t flags, int *prime_fd);
struct exynos_device *(*sym_exynos_device_create)(int fd) = NULL;
struct exynos_bo *(*sym_exynos_bo_create)(struct exynos_device *dev, size_t size, uint32_t flags) = NULL;
void *(*sym_exynos_bo_map)(struct exynos_bo *bo) = NULL;
void (*sym_exynos_bo_destroy)(struct exynos_bo *bo) = NULL;
static Buffer_Handle *
_intel_alloc(Buffer_Manager *self, const char *name, int w, int h, unsigned long *stride, int32_t *fd)
{
@ -179,6 +188,95 @@ err:
return EINA_FALSE;
}
static Buffer_Handle *
_exynos_alloc(Buffer_Manager *self, const char *name EINA_UNUSED, int w, int h, unsigned long *stride, int32_t *fd)
{
size_t size = w * h * 4;
struct exynos_bo *out;
*stride = w * 4;
out = sym_exynos_bo_create(self->priv, size, 0);
if (!out) return NULL;
/* First try to allocate an mmapable buffer with O_RDWR,
* if that fails retry unmappable - if the compositor is
* using GL it won't need to mmap the buffer and this can
* work - otherwise it'll reject this buffer and we'll
* have to fall back to shm rendering.
*/
if (sym_drmPrimeHandleToFD(drm_fd, out->handle,
DRM_CLOEXEC | O_RDWR, fd) != 0)
if (sym_drmPrimeHandleToFD(drm_fd, out->handle,
DRM_CLOEXEC, fd) != 0) goto err;
return (Buffer_Handle *)out;
err:
sym_exynos_bo_destroy(out);
return NULL;
}
static void *
_exynos_map(Dmabuf_Buffer *buf)
{
struct exynos_bo *bo;
void *ptr;
bo = (struct exynos_bo *)buf->bh;
ptr = mmap(0, bo->size, PROT_READ | PROT_WRITE, MAP_SHARED, buf->fd, 0);
if (ptr == MAP_FAILED) return NULL;
return ptr;
}
static void
_exynos_unmap(Dmabuf_Buffer *buf)
{
struct exynos_bo *bo;
bo = (struct exynos_bo *)buf->bh;
munmap(buf->mapping, bo->size);
}
static void
_exynos_discard(Dmabuf_Buffer *buf)
{
struct exynos_bo *bo;
bo = (struct exynos_bo *)buf->bh;
sym_exynos_bo_destroy(bo);
}
static Eina_Bool
_exynos_buffer_manager_setup(int fd)
{
Eina_Bool fail = EINA_FALSE;
void *drm_exynos_lib;
drm_exynos_lib = dlopen("libdrm_exynos.so", RTLD_LAZY | RTLD_GLOBAL);
if (!drm_exynos_lib) return EINA_FALSE;
SYM(drm_exynos_lib, exynos_device_create);
SYM(drm_exynos_lib, exynos_bo_create);
SYM(drm_exynos_lib, exynos_bo_map);
SYM(drm_exynos_lib, exynos_bo_destroy);
SYM(drm_exynos_lib, drmPrimeHandleToFD);
if (fail) goto err;
buffer_manager->priv = sym_exynos_device_create(fd);
if (!buffer_manager->priv) goto err;
buffer_manager->alloc = _exynos_alloc;
buffer_manager->map = _exynos_map;
buffer_manager->unmap = _exynos_unmap;
buffer_manager->discard = _exynos_discard;
return EINA_TRUE;
err:
dlclose(drm_exynos_lib);
return EINA_FALSE;
}
static Buffer_Manager *
_buffer_manager_get(void)
{
@ -194,6 +292,7 @@ _buffer_manager_get(void)
if (fd < 0) goto err_drm;
success = _intel_buffer_manager_setup(fd);
if (!success) success = _exynos_buffer_manager_setup(fd);
if (!success) goto err_bm;
drm_fd = fd;

View File

@ -0,0 +1,172 @@
/* exynos_drm.h
*
* Copyright (c) 2011 Samsung Electronics Co., Ltd.
* Authors:
* Inki Dae <inki.dae@samsung.com>
* Joonyoung Shim <jy0922.shim@samsung.com>
* Seung-Woo Kim <sw0312.kim@samsung.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef _EXYNOS_DRM_H_
#define _EXYNOS_DRM_H_
#include "drm.h"
/**
* User-desired buffer creation information structure.
*
* @size: user-desired memory allocation size.
* - this size value would be page-aligned internally.
* @flags: user request for setting memory type or cache attributes.
* @handle: returned a handle to created gem object.
* - this handle will be set by gem module of kernel side.
*/
struct drm_exynos_gem_create {
uint64_t size;
unsigned int flags;
unsigned int handle;
};
/**
* A structure to gem information.
*
* @handle: a handle to gem object created.
* @flags: flag value including memory type and cache attribute and
* this value would be set by driver.
* @size: size to memory region allocated by gem and this size would
* be set by driver.
*/
struct drm_exynos_gem_info {
unsigned int handle;
unsigned int flags;
uint64_t size;
};
/**
* A structure for user connection request of virtual display.
*
* @connection: indicate whether doing connetion or not by user.
* @extensions: if this value is 1 then the vidi driver would need additional
* 128bytes edid data.
* @edid: the edid data pointer from user side.
*/
struct drm_exynos_vidi_connection {
unsigned int connection;
unsigned int extensions;
uint64_t edid;
};
/* memory type definitions. */
enum e_drm_exynos_gem_mem_type {
/* Physically Continuous memory and used as default. */
EXYNOS_BO_CONTIG = 0 << 0,
/* Physically Non-Continuous memory. */
EXYNOS_BO_NONCONTIG = 1 << 0,
/* non-cachable mapping and used as default. */
EXYNOS_BO_NONCACHABLE = 0 << 1,
/* cachable mapping. */
EXYNOS_BO_CACHABLE = 1 << 1,
/* write-combine mapping. */
EXYNOS_BO_WC = 1 << 2,
EXYNOS_BO_MASK = EXYNOS_BO_NONCONTIG | EXYNOS_BO_CACHABLE |
EXYNOS_BO_WC
};
struct drm_exynos_g2d_get_ver {
__u32 major;
__u32 minor;
};
struct drm_exynos_g2d_cmd {
__u32 offset;
__u32 data;
};
enum drm_exynos_g2d_buf_type {
G2D_BUF_USERPTR = 1 << 31,
};
enum drm_exynos_g2d_event_type {
G2D_EVENT_NOT,
G2D_EVENT_NONSTOP,
G2D_EVENT_STOP, /* not yet */
};
struct drm_exynos_g2d_userptr {
unsigned long userptr;
unsigned long size;
};
struct drm_exynos_g2d_set_cmdlist {
__u64 cmd;
__u64 cmd_buf;
__u32 cmd_nr;
__u32 cmd_buf_nr;
/* for g2d event */
__u64 event_type;
__u64 user_data;
};
struct drm_exynos_g2d_exec {
__u64 async;
};
#define DRM_EXYNOS_GEM_CREATE 0x00
/* Reserved 0x04 ~ 0x05 for exynos specific gem ioctl */
#define DRM_EXYNOS_GEM_GET 0x04
#define DRM_EXYNOS_VIDI_CONNECTION 0x07
/* G2D */
#define DRM_EXYNOS_G2D_GET_VER 0x20
#define DRM_EXYNOS_G2D_SET_CMDLIST 0x21
#define DRM_EXYNOS_G2D_EXEC 0x22
#define DRM_IOCTL_EXYNOS_GEM_CREATE DRM_IOWR(DRM_COMMAND_BASE + \
DRM_EXYNOS_GEM_CREATE, struct drm_exynos_gem_create)
#define DRM_IOCTL_EXYNOS_GEM_GET DRM_IOWR(DRM_COMMAND_BASE + \
DRM_EXYNOS_GEM_GET, struct drm_exynos_gem_info)
#define DRM_IOCTL_EXYNOS_VIDI_CONNECTION DRM_IOWR(DRM_COMMAND_BASE + \
DRM_EXYNOS_VIDI_CONNECTION, struct drm_exynos_vidi_connection)
#define DRM_IOCTL_EXYNOS_G2D_GET_VER DRM_IOWR(DRM_COMMAND_BASE + \
DRM_EXYNOS_G2D_GET_VER, struct drm_exynos_g2d_get_ver)
#define DRM_IOCTL_EXYNOS_G2D_SET_CMDLIST DRM_IOWR(DRM_COMMAND_BASE + \
DRM_EXYNOS_G2D_SET_CMDLIST, struct drm_exynos_g2d_set_cmdlist)
#define DRM_IOCTL_EXYNOS_G2D_EXEC DRM_IOWR(DRM_COMMAND_BASE + \
DRM_EXYNOS_G2D_EXEC, struct drm_exynos_g2d_exec)
/* EXYNOS specific events */
#define DRM_EXYNOS_G2D_EVENT 0x80000000
struct drm_exynos_g2d_event {
struct drm_event base;
__u64 user_data;
__u32 tv_sec;
__u32 tv_usec;
__u32 cmdlist_no;
__u32 reserved;
};
#endif

View File

@ -0,0 +1,112 @@
/*
* Copyright (C) 2012 Samsung Electronics Co., Ltd.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* Authors:
* Inki Dae <inki.dae@samsung.com>
*/
#ifndef EXYNOS_DRMIF_H_
#define EXYNOS_DRMIF_H_
#include <xf86drm.h>
#include <stdint.h>
#include "exynos_drm.h"
struct exynos_device {
int fd;
};
/*
* Exynos Buffer Object structure.
*
* @dev: exynos device object allocated.
* @handle: a gem handle to gem object created.
* @flags: indicate memory allocation and cache attribute types.
* @size: size to the buffer created.
* @vaddr: user space address to a gem buffer mmaped.
* @name: a gem global handle from flink request.
*/
struct exynos_bo {
struct exynos_device *dev;
uint32_t handle;
uint32_t flags;
size_t size;
void *vaddr;
uint32_t name;
};
#define EXYNOS_EVENT_CONTEXT_VERSION 1
/*
* Exynos Event Context structure.
*
* @base: base context (for core events).
* @version: version info similar to the one in 'drmEventContext'.
* @g2d_event_handler: handler for G2D events.
*/
struct exynos_event_context {
drmEventContext base;
int version;
void (*g2d_event_handler)(int fd, unsigned int cmdlist_no,
unsigned int tv_sec, unsigned int tv_usec,
void *user_data);
};
/*
* device related functions:
*/
struct exynos_device * exynos_device_create(int fd);
void exynos_device_destroy(struct exynos_device *dev);
/*
* buffer-object related functions:
*/
struct exynos_bo * exynos_bo_create(struct exynos_device *dev,
size_t size, uint32_t flags);
int exynos_bo_get_info(struct exynos_device *dev, uint32_t handle,
size_t *size, uint32_t *flags);
void exynos_bo_destroy(struct exynos_bo *bo);
struct exynos_bo * exynos_bo_from_name(struct exynos_device *dev, uint32_t name);
int exynos_bo_get_name(struct exynos_bo *bo, uint32_t *name);
uint32_t exynos_bo_handle(struct exynos_bo *bo);
void * exynos_bo_map(struct exynos_bo *bo);
int exynos_prime_handle_to_fd(struct exynos_device *dev, uint32_t handle,
int *fd);
int exynos_prime_fd_to_handle(struct exynos_device *dev, int fd,
uint32_t *handle);
/*
* Virtual Display related functions:
*/
int exynos_vidi_connection(struct exynos_device *dev, uint32_t connect,
uint32_t ext, void *edid);
/*
* event handling related functions:
*/
int exynos_handle_event(struct exynos_device *dev,
struct exynos_event_context *ctx);
#endif /* EXYNOS_DRMIF_H_ */