概述
笔者在涉及RK平台中如下链路时,对drm申请的buffer相关字段有些疑惑。因此写此贴作为一个记录。
mppdec解码 --> rga缩放 --> drm显示
流程解析
如下接口是申请drm类型的dumb。首先需要传入的fd是设备的文件句柄,比如/dev/dri/card0。随后通过drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &arg)
申请到一个DUMB的内存块,此时出现了handle
,随后又通过drmPrimeHandleToFD
获取到一个fd(对应buff_fd
)。
static struct bo_new *
bo_create_dumb(int fd, unsigned int width, unsigned int height, unsigned int bpp)
{
struct drm_mode_create_dumb arg;
struct bo_new *bo;
int ret;
bo = calloc(1, sizeof(*bo));
if (bo == NULL) {
fprintf(stderr, "failed to allocate buffer object\n");
return NULL;
}
memset(&arg, 0, sizeof(arg));
arg.bpp = bpp;
arg.width = width;
arg.height = height;
ret = drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &arg);
if (ret) {
fprintf(stderr, "failed to create dumb buffer: %s\n",
strerror(errno));
free(bo);
return NULL;
}
bo->fd = fd;
bo->handle = arg.handle;
bo->size = arg.size;
bo->pitch = arg.pitch;
drmPrimeHandleToFD(fd, arg.handle, 0, &bo->buff_fd);
return bo;
}
上述函数执行完毕,我们获取到drm buff的一个handle和一个fd。但是在该drm buff送往drm显示时,还需要再进行一次转换(通过接口drmModeAddFB2
),需要获取一个fb(对应代码fb_id
)。
kmsmem = calloc(sizeof(KMSMEM), 1);
kmsmem->bo = bo_create(self->fd, vinfo->format,
vinfo->width, vinfo->height,
handles, pitches,
offsets, UTIL_PATTERN_TILES);
printf("bo handles: %d, %d, %d, %d, ptr %p\n", handles[0],
handles[1], handles[2], handles[3], kmsmem->bo->ptr);
ret = drmModeAddFB2 (self->fd, vinfo->width, vinfo->height,
vinfo->format, handles, pitches,
offsets, &kmsmem->fb_id, 0);
在drm送显时,则是传入上文提到的fb,比如如下代码中的fb_id
:
ret = drmModeSetPlane (self->fd, self->plane_id, self->crtc_id, fb_id, 0,
result.x, result.y, result.w, result.h,
/* source/cropping coordinates are given in Q16 */
src.x << 16, src.y << 16, src.w << 16, src.h << 16);
总结
上文中涉及drm buff的三个变量:handle,fd,fb;我的理解如下:
- handle:驱动层的标识符,因此通过drmIoctl像驱动获取到的标识符便为handle形式。
- fd:用户层的标识符,用户可通过该fd,对buffer进行map处理。在rga处理时,可直接使用drm buff的fd作为接口入参。
// rk扩展ffmpeg解码器时自定义的结构。代码中的fd就是drmbuff的fd。
drm_fram_desc = (AVDRMFrameDescriptor*)frame->data[0];
memset(&src_info, 0, sizeof(rga_info_t));
src_info.fd = drm_fram_desc->objects[0].fd;
src_info.mmuFlag = 1;
// 目标为新申请的drm buff的fd,rga缩放后,新的图像存放此处。
memset(&dst_info, 0, sizeof(rga_info_t));
dst_info.fd = buffer->bo->buff_fd;
dst_info.mmuFlag = 1;
/********** set the rect_info **********/
rga_set_rect(&src_info.rect, 0, 0, srcWidth, srcHeight, srcWidth/*stride*/, srcHeight, srcFormat);
rga_set_rect(&dst_info.rect, 0, 0, dstWidth, dstHeight, dstWidth/*stride*/, dstHeight, dstFormat);
src_info.rotation = rotate;
ret = c_RkRgaBlit(&src_info, &dst_info, NULL);
if (ret) {
av_log(NULL, AV_LOG_FATAL, "rk rga split func failed!\n");
return;
}
- fb:我理解为framebuff的标识符,用于额外封装drm buff为framebuff结构,然后才能通过drm接口送显。之所以封装,是因为framebuff额外提供了当前buff的宽高等信息。