DRM -- FrameBuffer

Framebuffer 帧缓冲区是抽象的内存对象,提供了扫描到 CRTC 的像素源。应用程序通过 IOCTLDRM_IOCTL_MODE_ADDFB(2)来创建 framebuffer,会返回一个不透明句柄,该句柄可以传递给 KMS CRTC、来控制 plane configuration 和 page flip 功能。 数据结构 struct drm_framebuffer { struct drm_device *dev; struct list_head head; // framebuffer链表,可能有多个fb struct drm_mode_object base; char comm[TASK_COMM_LEN]; // allocate fb的进程名 const struct drm_format_info *format; // fb pixel format const struct drm_framebuffer_funcs *funcs; // 一行多少bytes, 会从用户空间的drm_mode_fb_cmd2拷贝过来 unsigned int pitches[DRM_FORMAT_MAX_PLANES]; // framebuffer和actual pixel data的offset,也从drm_mode_fb_cmd2拷贝过来 unsigned int offsets[DRM_FORMAT_MAX_PLANES]; uint64_t modifier; // 从drm_mode_fb_cmd2的modifier拷贝过来,DRM_FORMAT_MOD_XXX unsigned int width; // framebuffer宽 unsigned int height; // framebuffer高 int flags; // DRM_MODE_FB_INTERLACED, DRM_MODE_FB_MODIFIERS struct list_head filp_head; struct drm_gem_object *obj[DRM_FORMAT_MAX_PLANES]; }; struct drm_format_info { u32 format; // FOURCC格式,DRM_FORMAT_* u8 depth; // color depth, legacy field, 设置为0。 u8 num_planes; // Number of color planes (1 to 3) union { // 每个plane的bytes per pixel, legacy field。 u8 cpp[DRM_FORMAT_MAX_PLANES]; // 每个plane的bytes per block。用于单个pixel不是byte对齐的情况。 // block大小用下面的block_w和block_h来描述。 u8 char_per_block[DRM_FORMAT_MAX_PLANES]; }; u8 block_w[DRM_FORMAT_MAX_PLANES]; // block width占几个bytes u8 block_h[DRM_FORMAT_MAX_PLANES]; // block height占几个bytes u8 hsub; // 行采样因子 u8 vsub; // 列采样因子,比如yuv422那么hsub=2, vsub=1 bool has_alpha; // pixel format中是否含有alpha bool is_yuv; // 是不是yuv格式 bool is_color_indexed; // 是不是color_indexed格式,即伪彩,存index进color LUT查找对应颜色 }; struct drm_framebuffer_funcs { void (*destroy)(struct drm_framebuffer *framebuffer); int (*create_handle)(struct drm_framebuffer *fb, struct drm_file *file_priv, unsigned int *handle); // 有些硬件在fb内容更新后不会主动刷新内容到屏幕上。 // userspace需要通过DRM_IOCTL_MODE_DIRTYFB ioctl调用到dirty函数来刷新屏幕的某块区域。 int (*dirty)(struct drm_framebuffer *framebuffer, struct drm_file *file_priv, unsigned flags, unsigned color, struct drm_clip_rect *clips, unsigned num_clips); }; 注册 framebuffer 用户空间通过drmModeAddFB2()或drmModeAddFB2WithModifiers()函数来注册 framebuffer,需要传入struct drm_mode_fb_cmd2,除了fb_id是返回的参数,其他都是需要传入的参数:...

2024-08-28 · 3 min

DRM -- Userspace Application

参考 https://github.com/dvdhrm/docs/tree/master/drm-howto 中的 modeset-atomic.c Modeset prepare 首先 open drm 设备节点: fd = open("/dev/dri/card0", O_RDWR | O_CLOEXEC); 设置 client 的 capability: drmSetClientCap(fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1); drmSetClientCap(fd, DRM_CLIENT_CAP_ATOMIC, 1); 第一行设置 drm file_priv->universal_planes=1。 第二行设置 file_priv->atomic=1, file_priv->universal_planes=1, file_priv->aspect_ratio_allowed = 1。 获取 client 的 capability: drmGetCap(fd, DRM_CAP_DUMB_BUFFER, &cap); drmGetCap(fd, DRM_CAP_CRTC_IN_VBLANK_EVENT, &cap); 第一行,如果 drm_driver 提供了 dumb_create 回调,则返回 1,一般都会提供。 第二行,必定返回 1,现在 driver 都会支持 Vblank 事件。 获取 resources: drmModeGetResources(); drmIoctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res); 得到 fbs/crtcs/connectors/encoders 的数量,以及每个对应的 id,还有显示支持的最大最小长宽,填充结构体: typedef struct _drmModeRes { int count_fbs; uint32_t *fbs; int count_crtcs; uint32_t *crtcs; int count_connectors; uint32_t *connectors; int count_encoders; uint32_t *encoders; uint32_t min_width, max_width; uint32_t min_height, max_height; } drmModeRes, *drmModeResPtr; 获取 connector:...

2024-08-20 · 2 min

DRM -- Graphic Introduction

Reference https://docs.kernel.org/gpu/index.html introduction 中提供了一些关于 DRM 的讲座和 slides 材料。 https://bootlin.com/doc/training/graphics/graphics-slides.pdf Basic Theory and Concepts About Graphics YUV 数据格式 采样 YUV 格式,由一个 Y 的亮度分量(Luma)和 U(蓝色投影 Cb)和 V(红色投影 Cr)的色度分量(Chroma)表示。 4:4:4 表示不降低色度(UV)通道的采样率。每个 Y 分量对应一组 UV 分量。 4:2:2 表示 2:1 水平下采样,没有垂直下采样。每两个 Y 分量共享一组 UV 分量。 4:2:0 表示 2:1 水平下采样,同时 2:1 垂直下采样。每四个 Y 分量共享一组 UV 分量。 4:1:1 表示 4:1 水平下采样,没有垂直下采样。每四个 Y 分量共享一组 UV 分量。 BT.601 中规定的 YUV 和 RGB 的转换公式: \(R=Y+1.140*V-0.7\) \(G=Y-0.343*U-0.711*V+0.526\) \(B=Y+1.765*U-0.883\) \(Y=0.299*R+0.587*G+0.114*B\) \(U=-0.169*R-0.331*G+0.500*B\) \(V=0.500*R-0.439*G-0.081\*B\)...

2024-08-20 · 1 min