接前一篇文章:libdrm全解析九 —— 源码全解析(6)
本文参考以下博文:
特此致谢!
本文继续对include/drm/drm.h中实际功能宏定义进行讲解。
11. DRM_IOCTL_GEM_FLINK
第11个宏是DRM_IOCTL_GEM_FLINK,相应代码如下:
#define DRM_IOCTL_GEM_FLINK DRM_IOWR(0x0a, struct drm_gem_flink)
结合之前文章中的_IOWR(type,nr,size)的最终定义,得到如下代码:
#define DRM_IOCTL_GEM_FLINK ( ((3) << 30) | (('d') << 8) | ((0x0a) << 0) | ((sizeof(struct drm_gem_flink)) << 16) )
struct drm_gem_flink在同文件(include/drm/drm.h)中定义,代码如下:
/* DRM_IOCTL_GEM_FLINK ioctl argument type */
struct drm_gem_flink {
/** Handle for the object being named */
__u32 handle;
/** Returned global name */
__u32 name;
};
drm_gem_flink结构中各成员的意义代码注释描述得很清楚了,在此无需赘述。
DRM_IOCTL_GEM_FLINK虽然并无直接对应的Userspace API(即没有对应的封装),但是libdrm源码中有多处直接对其进行了调用。
- amdgpu/amdgpu_bo.c中:
static int amdgpu_bo_export_flink(amdgpu_bo_handle bo)
{
struct drm_gem_flink flink;
int fd, dma_fd;
uint32_t handle;
int r;
fd = bo->dev->fd;
handle = bo->handle;
if (bo->flink_name)
return 0;
……
memset(&flink, 0, sizeof(flink));
flink.handle = handle;
r = drmIoctl(fd, DRM_IOCTL_GEM_FLINK, &flink);
if (r)
return r;
……
return r;
}
- etnaviv/etnaviv_bo.c中:
/* get the global flink/DRI2 buffer name */
drm_public int etna_bo_get_name(struct etna_bo *bo, uint32_t *name)
{
if (!bo->name) {
struct drm_gem_flink req = {
.handle = bo->handle,
};
int ret;
ret = drmIoctl(bo->dev->fd, DRM_IOCTL_GEM_FLINK, &req);
if (ret) {
return ret;
}
pthread_mutex_lock(&table_lock);
set_name(bo, req.name);
pthread_mutex_unlock(&table_lock);
bo->reuse = 0;
}
*name = bo->name;
return 0;
}
- exynos/exynos_drm.c中:
/*
* Get a gem global object name from a gem object handle.
*
* @bo: a exynos buffer object including gem handle.
* @name: a gem global object name to be got by kernel driver.
*
* this interface is used to get a gem global object name from a gem object
* handle to a buffer that wants to share it with another process.
*
* if true, return 0 else negative.
*/
drm_public int exynos_bo_get_name(struct exynos_bo *bo, uint32_t *name)
{
if (!bo->name) {
struct drm_gem_flink req = {
.handle = bo->handle,
};
int ret;
ret = drmIoctl(bo->dev->fd, DRM_IOCTL_GEM_FLINK, &req);
if (ret) {
fprintf(stderr, "failed to get gem global name[%s].\n",
strerror(errno));
return ret;
}
bo->name = req.name;
}
*name = bo->name;
return 0;
}
- freedreno/freedreno_bo.c中:
drm_public int fd_bo_get_name(struct fd_bo *bo, uint32_t *name)
{
if (!bo->name) {
struct drm_gem_flink req = {
.handle = bo->handle,
};
int ret;
ret = drmIoctl(bo->dev->fd, DRM_IOCTL_GEM_FLINK, &req);
if (ret) {
return ret;
}
pthread_mutex_lock(&table_lock);
set_name(bo, req.name);
pthread_mutex_unlock(&table_lock);
bo->bo_reuse = NO_CACHE;
}
*name = bo->name;
return 0;
}
- intel/intel_bufmgr_gem.c中:
static int
drm_intel_gem_bo_flink(drm_intel_bo *bo, uint32_t * name)
{
drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *) bo->bufmgr;
drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo;
if (!bo_gem->global_name) {
struct drm_gem_flink flink;
memclear(flink);
flink.handle = bo_gem->gem_handle;
if (drmIoctl(bufmgr_gem->fd, DRM_IOCTL_GEM_FLINK, &flink))
return -errno;
pthread_mutex_lock(&bufmgr_gem->lock);
if (!bo_gem->global_name) {
bo_gem->global_name = flink.name;
bo_gem->reusable = false;
HASH_ADD(name_hh, bufmgr_gem->name_table,
global_name, sizeof(bo_gem->global_name),
bo_gem);
}
pthread_mutex_unlock(&bufmgr_gem->lock);
}
*name = bo_gem->global_name;
return 0;
}
- nouveau/nouveau.c中:
drm_public int
nouveau_bo_name_get(struct nouveau_bo *bo, uint32_t *name)
{
struct drm_gem_flink req = { .handle = bo->handle };
struct nouveau_drm *drm = nouveau_drm(&bo->device->object);
struct nouveau_bo_priv *nvbo = nouveau_bo(bo);
*name = nvbo->name;
if (!*name) {
int ret = drmIoctl(drm->fd, DRM_IOCTL_GEM_FLINK, &req);
if (ret) {
*name = 0;
return ret;
}
nvbo->name = *name = req.name;
nouveau_bo_make_global(nvbo);
}
return 0;
}
- omap/omap_drm.c中:
/* get the global flink/DRI2 buffer name */
drm_public int omap_bo_get_name(struct omap_bo *bo, uint32_t *name)
{
if (!bo->name) {
struct drm_gem_flink req = {
.handle = bo->handle,
};
int ret;
ret = drmIoctl(bo->dev->fd, DRM_IOCTL_GEM_FLINK, &req);
if (ret) {
return ret;
}
bo->name = req.name;
}
*name = bo->name;
return 0;
}
- radeon/radeon_bo_gem.c中:
drm_public int
radeon_gem_get_kernel_name(struct radeon_bo *bo, uint32_t *name)
{
struct radeon_bo_gem *bo_gem = (struct radeon_bo_gem*)bo;
struct radeon_bo_int *boi = (struct radeon_bo_int *)bo;
struct drm_gem_flink flink;
int r;
if (bo_gem->name) {
*name = bo_gem->name;
return 0;
}
flink.handle = bo->handle;
r = drmIoctl(boi->bom->fd, DRM_IOCTL_GEM_FLINK, &flink);
if (r) {
return r;
}
bo_gem->name = flink.name;
*name = flink.name;
return 0;
}
- tegra/tegra.c中:
drm_public int drm_tegra_bo_get_name(struct drm_tegra_bo *bo, uint32_t *name)
{
struct drm_tegra *drm = bo->drm;
struct drm_gem_flink args;
int err;
memset(&args, 0, sizeof(args));
args.handle = bo->handle;
err = drmIoctl(drm->fd, DRM_IOCTL_GEM_FLINK, &args);
if (err < 0)
return err;
if (name)
*name = args.name;
return 0;
}
这里顺带把各种显卡都列出来了。每种显卡都会调用DRM_IOCTL_GEM_FLINK对应的drmIoctl。
其余宏定义将在后续文章中继续解析。