drm study

学习过程

0319:

  • 对于任何驱动来说,buffer是最重要的,知道了buffer的创建使用这个驱动就会一半了;

  • 现在感觉是一个无头苍蝇,感觉非常复杂:数据结构非常多,之间的关系也非常复杂;

  • 不过没关系,先研究buffer通路;

  • alt text

    • 可以看见应用层对mmap写入的hello world,驱动中vkms_obj->vaddr正是;
    • 对应的pa又是怎么来的呢?
  • 突然有个疑问:应用层是通过remap_pfn_range映射vma和一个pa,如果使用了smmu,这个pa就会变成iova,这时候vma和这个iova是如何映射的呢

  • 实验方法:

    • crc_enabled设置为1:cat /sys/kernel/debug/dri/1/crtc-0/crc/data &
    • vkms_vblank_simulate:./modeset-single-buffer
  • 几个疑问:

    • 这个drm_gem_object应该是与物理内存有关
    • vkms_gem_vmap的调用在mmap和fault之后,我理解是mmap只分配了vma,在fault应该会填入物理地址(好像是分配了page),vkms_gem_vmap中又在分配page,这是为啥呢?
    • 细节非常复杂,先从输入输出入手大致知晓数据结构关系,重要的是关键回调的调用关系vkms_gem_vmap

vgem_test

#include <errno.h>
#include <fcntl.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <unistd.h>
#include <xf86drm.h>
#include <xf86drmMode.h>
#include <sys/poll.h>
#include <sys/ioctl.h>

struct vgem_bo {
	uint32_t handle;
	uint32_t width, height;
	uint32_t bpp, pitch;
	uint64_t size;
};

struct local_vgem_fence_signal {
	uint32_t fence;
	uint32_t flags;
};

struct local_vgem_fence_attach {
	uint32_t handle;
	uint32_t flags;
	uint32_t out_fence;
	uint32_t pad;
};

#define LOCAL_VGEM_FENCE_ATTACH   0x1
#define LOCAL_VGEM_FENCE_SIGNAL   0x2

#define VGEM_FENCE_WRITE 0x1
#define WIP_VGEM_FENCE_NOTIMEOUT 0x2
#define LOCAL_IOCTL_VGEM_FENCE_SIGNAL     DRM_IOW( DRM_COMMAND_BASE + LOCAL_VGEM_FENCE_SIGNAL, struct local_vgem_fence_signal)
#define LOCAL_IOCTL_VGEM_FENCE_ATTACH     DRM_IOWR( DRM_COMMAND_BASE + LOCAL_VGEM_FENCE_ATTACH, struct local_vgem_fence_attach)

int __vgem_create(int fd, struct vgem_bo *bo)
{
	struct drm_mode_create_dumb arg;

	memset(&arg, 0, sizeof(arg));
	arg.width = bo->width;
	arg.height = bo->height;
	arg.bpp = bo->bpp;

	if (drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &arg))
		return -errno;

	bo->handle = arg.handle;
	bo->pitch = arg.pitch;
	bo->size = arg.size;

	return 0;
}

void vgem_create(int fd, struct vgem_bo *bo)
{
	__vgem_create(fd, bo);
}

int prime_handle_to_fd(int fd, uint32_t handle)
{
	struct drm_prime_handle args;

	memset(&args, 0, sizeof(args));
	args.handle = handle;
	args.flags = DRM_CLOEXEC;
	args.fd = -1;

	ioctl(fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &args);

	return args.fd;
}

static int __vgem_fence_attach(int fd, struct local_vgem_fence_attach *arg)
{
	int err = 0;
	if (ioctl(fd, LOCAL_IOCTL_VGEM_FENCE_ATTACH, arg))
		err = -errno;
	errno = 0;
	return err;
}

uint32_t vgem_fence_attach(int fd, struct vgem_bo *bo, unsigned flags)
{
	struct local_vgem_fence_attach arg;

	memset(&arg, 0, sizeof(arg));
	arg.handle = bo->handle;
	arg.flags = flags;
	__vgem_fence_attach(fd, &arg);
	return arg.out_fence;
}

static bool prime_busy(int fd, bool excl)
{
	struct pollfd pfd = { .fd = fd, .events = excl ? POLLOUT : POLLIN };
	return poll(&pfd, 1, 0) == 0;
}

static int ioctl_vgem_fence_signal(int fd, struct local_vgem_fence_signal *arg)
{
	int err = 0;
	if (ioctl(fd, LOCAL_IOCTL_VGEM_FENCE_SIGNAL, arg))
		err = -errno;
	errno = 0;
	return err;
}

int __vgem_fence_signal(int fd, uint32_t fence)
{
	struct local_vgem_fence_signal arg;

	memset(&arg, 0, sizeof(arg));
	arg.fence = fence;

	return ioctl_vgem_fence_signal(fd, &arg);
}

void vgem_fence_signal(int fd, uint32_t fence)
{
	__vgem_fence_signal(fd, fence);
}

void gem_close(int fd, uint32_t handle)
{
	struct drm_gem_close close_bo;

	memset(&close_bo, 0, sizeof(close_bo));
	close_bo.handle = handle;
	ioctl(fd, DRM_IOCTL_GEM_CLOSE, &close_bo);
}

static void test_dmabuf_fence(int fd)
{
	struct vgem_bo bo;
	int dmabuf;
	uint32_t fence;

	bo.width = 1024;
	bo.height = 1;
	bo.bpp = 32;
	vgem_create(fd, &bo);

	/* export, then fence */

	dmabuf = prime_handle_to_fd(fd, bo.handle);	/* 得到dmabuf的fd */

	fence = vgem_fence_attach(fd, &bo, 0);
	prime_busy(dmabuf, false);
	prime_busy(dmabuf, true);

	vgem_fence_signal(fd, fence);
	prime_busy(dmabuf, false);
	prime_busy(dmabuf, true);

	fence = vgem_fence_attach(fd, &bo, VGEM_FENCE_WRITE);
	prime_busy(dmabuf, false);
	prime_busy(dmabuf, true);

	vgem_fence_signal(fd, fence);
	prime_busy(dmabuf, false);
	prime_busy(dmabuf, true);

	close(dmabuf);
	gem_close(fd, bo.handle);
}

int main(int argc, char **argv)
{
        int fd;

        fd = open("/dev/dri/card0", O_RDWR);

        test_dmabuf_fence(fd);

        close(fd);

        return 0;
}

#define _GNU_SOURCE
#include <errno.h>
#include <fcntl.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <time.h>
#include <unistd.h>
#include <xf86drm.h>
#include <xf86drmMode.h>

struct buffer_object {
	uint32_t width;
	uint32_t height;
	uint32_t pitch;
	uint32_t handle;
	uint32_t size;
	uint8_t *vaddr;
	uint32_t fb_id;
};

struct buffer_object buf;

static int modeset_create_fb(int fd, struct buffer_object *bo)
{
	struct drm_mode_create_dumb create = {};
 	struct drm_mode_map_dumb map = {};
	int i = 0;

	/* create a dumb-buffer, the pixel format is XRGB888 */
	create.width = bo->width;
	create.height = bo->height;
	create.bpp = 32;
	drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &create);

	/* bind the dumb-buffer to an FB object */
	bo->pitch = create.pitch;
	bo->size = create.size;
	bo->handle = create.handle;
	drmModeAddFB(fd, bo->width, bo->height, 24, 32, bo->pitch,
			   bo->handle, &bo->fb_id);

	/* map the dumb-buffer to userspace */
	map.handle = create.handle;
	drmIoctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &map);

	bo->vaddr = mmap(0, create.size, PROT_READ | PROT_WRITE,
			MAP_SHARED, fd, map.offset);
	
	printf("vaddr %p\n", bo->vaddr);
	/* initialize the dumb-buffer with white-color */
	for(i = 0; i < bo->size; i+= sizeof("hello world"))
		memcpy(&bo->vaddr[i], "hello world", sizeof("hello world"));

	// memset(bo->vaddr, 0xff, bo->size);

	return 0;
}

static void modeset_destroy_fb(int fd, struct buffer_object *bo)
{
	struct drm_mode_destroy_dumb destroy = {};

	drmModeRmFB(fd, bo->fb_id);

	munmap(bo->vaddr, bo->size);

	destroy.handle = bo->handle;
	drmIoctl(fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy);
}

int main(int argc, char **argv)
{
	int fd;
	drmModeConnector *conn;
	drmModeRes *res;
	uint32_t conn_id;
	uint32_t crtc_id;
	int i;

    printf("%s %d\n", __func__, __LINE__);
	fd = open("/dev/dri/card1", O_RDWR | O_CLOEXEC);
    printf("%s %d\n", __func__, __LINE__);
	res = drmModeGetResources(fd);
    printf("%s %d\n", __func__, __LINE__);
    printf("%s %d\n", __func__, __LINE__);
	crtc_id = res->crtcs[0];
	conn_id = res->connectors[0];

    printf("%s %d, %d\n", __func__, __LINE__, conn_id);
	conn = drmModeGetConnector(fd, conn_id);
    printf("%s %d\n", __func__, __LINE__);
	buf.width = conn->modes[0].hdisplay;
	buf.height = conn->modes[0].vdisplay;

	modeset_create_fb(fd, &buf);
    printf("%s %d\n", __func__, __LINE__);

	drmModeSetCrtc(fd, crtc_id, buf.fb_id,
			0, 0, &conn_id, 1, &conn->modes[0]);
	
	printf("mmap data\n");
	for(i = 0; i < buf.size; i+= sizeof("hello world"))
		printf("%x", ((int *)(buf.vaddr))[i]);


    printf("%s %d\n", __func__, __LINE__);
	// getchar();
    printf("%s %d\n", __func__, __LINE__);
	modeset_destroy_fb(fd, &buf);
    printf("%s %d\n", __func__, __LINE__);
	drmModeFreeConnector(conn);
    printf("%s %d\n", __func__, __LINE__);
	drmModeFreeResources(res);
    printf("%s %d\n", __func__, __LINE__);
	close(fd);

	return 0;
}

posted @ 2025-03-19 23:41  _xingxing  阅读(33)  评论(0)    收藏  举报