Drm_crtc

数据结构 drm_crtc struct drm_crtc { struct drm_device *dev; struct device_node *port; struct list_head head; char *name; struct drm_modeset_lock mutex; struct drm_mode_object base; struct drm_plane *primary; // for legacy IOCTL struct drm_plane *cursor; // for legacy IOCTL unsigned index; int cursor_x; // legacy int cursor_y; // legacy bool enabled; // legacy struct drm_display_mode mode; // legacy struct drm_display_mode hwmode; // legacy int x; // legacy int y; // legacy const struct drm_crtc_funcs *funcs; uint32_t gamma_size; // legacy uint16_t *gamma_store; // legacy const struct drm_crtc_helper_funcs *helper_private; struct drm_object_properties properties; struct drm_property *scaling_filter_property; struct drm_crtc_state *state; struct list_head commit_list; spinlock_t commit_lock; struct dentry *debugfs_entry; struct drm_crtc_crc crc; unsigned int fence_context; spinlock_t fence_lock; unsigned long fence_seqno; char timeline_name[32]; struct drm_self_refresh_data *self_refresh_data; }; drm_crtc_state struct drm_crtc_state { struct drm_crtc *crtc; bool enable; bool active; bool planes_changed : 1; bool mode_changed : 1; bool active_changed : 1; bool connectors_changed : 1; bool zpos_changed : 1; bool color_mgmt_changed : 1; bool no_vblank : 1; u32 plane_mask; u32 connector_mask; u32 encoder_mask; struct drm_display_mode adjusted_mode; struct drm_display_mode mode; struct drm_property_blob *mode_blob; struct drm_property_blob *degamma_lut; struct drm_property_blob *ctm; struct drm_property_blob *gamma_lut; u32 target_vblank; bool async_flip; bool vrr_enabled; bool self_refresh_active; enum drm_scaling_filter scaling_filter; struct drm_pending_vblank_event *event; struct drm_crtc_commit *commit; struct drm_atomic_state *state; }; enable: crtc 是否需要 enable。...

2024-09-04 · 4 min

DRM Subsystem 6 -- Object and Property

Property CRTCs, planes, connectors 都有各自的 properties(字符串到值的映射)。Userspace 通过设置这些 properties,即可完成对显示参数的设置。 目前只有 CRTCs, planes, connectors 三者有 properties,因此 Userspace 只能对该三者的 properties 进行设置。 DRM 中定义了一系列 standard properties,这些 properties 在每个平台上都会创建,比如 connector 的 standard properties 会通过 drm_connector_create_standard_properties() 在 connector init 过程中自动创建,其他还有 specific 的 properties 需要底层 driver 调用特定的函数来创建,比如 drm_mode_create_dvi_i_properties() 可以创建 select subconnector property。 struct drm_property { struct list_head head; // property链表 struct drm_mode_object base; uint32_t flags; char name[DRM_PROP_NAME_LEN]; // property名称 uint32_t num_values; uint64_t *values; struct drm_device *dev; struct list_head enum_list; }; flags: property flags,需要是以下选项之一:...

2024-09-02 · 3 min

Drm_atomic

struct drm_crtc_commit { struct drm_crtc *crtc; struct kref ref; struct completion flip_done; struct completion hw_done; struct completion cleanup_done; struct list_head commit_entry; struct drm_pending_vblank_event *event; bool abort_completion; }; struct drm_atomic_state { struct kref ref; struct drm_device *dev; bool allow_modeset : 1; bool legacy_cursor_update : 1; bool async_update : 1; bool duplicated : 1; struct __drm_planes_state *planes; struct __drm_crtcs_state *crtcs; int num_connector; struct __drm_connnectors_state *connectors; int num_private_objs; struct __drm_private_objs_state *private_objs; struct drm_modeset_acquire_ctx *acquire_ctx; struct drm_crtc_commit *fake_commit; struct work_struct commit_work; }; allow_modeset: 通过 userspace 传递的 flag DRM_MODE_ATOMIC_ALLOW_MODESET...

2024-08-28 · 1 min

DRM VBlank

Overview 一篇关于垂直同步 V-Sync 解释的文章:https://daily.elepover.com/2021/03/27/vsync/index.html 当 GPU 渲染的速度 > 显示器刷新的速度时,GPU 在显示器还来不及完成渲染完一帧时,就切换了 framebuffer,会导致出现撕裂现象。 帧率大于显示器刷新率时,启用垂直同步。 帧率小于显示器刷新率时,禁用垂直同步。 为了支持 vblank,底层 drvier 需要调用 drm_vblank_init()初始化,另外需要实现 drm_crtc_funcs.enable_vblank 和 drm_crtc_funcs.disable_vblank 两个回调函数,并且在 vblank 中断中调用 drm_crtc_handle_vblank()。 数据结构 struct drm_vblank_crtc { struct drm_device *dev; wait_queue_head_t queue; struct timer_list disable_timer; seqlock_t seqlock; atomic64_t count; ktime_t time; atomic_t refcount; u32 last; u32 max_vblank_count; unsigned int inmodeset; unsigned int pipe; int framedur_ns; int linedur_ns; struct drm_display_mode hwmode; bool enabled; struct kthread_worker *worker; struct list_head pending_work; wait_queue_head_t work_wait_queue; }; pipe: 表示第几个 crtc,在 drm_vblank_init 中初始化。

2024-08-28 · 1 min

Drm_kms_core

数据结构 drm_mode_config_funcs mode setting functions, 该结构体需要在底层 driver 中初始化。 struct drm_mode_config_funcs { struct drm_framebuffer *(*fb_create)(struct drm_device *dev, struct drm_file *file_priv, const struct drm_mode_fb_cmd2 *mode_cmd); const struct drm_format_info *(*get_format_info)(const struct drm_mode_fb_cmd2 *mode_cmd); void (*output_poll_changed)(struct drm_device *dev); enum drm_mode_status (*mode_valid)(struct drm_device *dev, const struct drm_display_mode *mode); int (*atomic_check)(struct drm_device *dev, struct drm_atomic_state *state); int (*atomic_commit)(struct drm_device *dev,struct drm_atomic_state *state, bool nonblock); struct drm_atomic_state *(*atomic_state_alloc)(struct drm_device *dev); void (*atomic_state_clear)(struct drm_atomic_state *state); void (*atomic_state_free)(struct drm_atomic_state *state); }; fb_create: 创建 framebuffer 的回调函数,在 userspace 调用 drmModeAddFB2()之后会调用到。....

2024-08-28 · 3 min

DRM Subsystem 4 -- Plane

数据结构 struct drm_plane_state { struct drm_plane *plane; // backpointer指向plane struct drm_crtc *crtc; // 通过drm_atomic_set_crtc_for_plane绑定的crtc struct drm_framebuffer *fb; // 通过drm_atomic_set_fb_for_plane绑定的fb struct dma_fence *fence; // int32_t crtc_x; // int32_t crtc_y; uint32_t crtc_w, crtc_h; uint32_t src_x; uint32_t src_y; uint32_t src_h, src_w; int32_t hotspot_x, hotspot_y; u16 alpha; uint16_t pixel_blend_mode; unsigned int rotation; unsigned int zpos; unsigned int normalized_zpos; enum drm_color_encoding color_encoding; enum drm_color_range color_range; struct drm_property_blob *fb_damage_clips; bool ignore_damage_clips; struct drm_rect src, dst; bool visible; enum drm_scaling_filter scaling_filter; struct drm_crtc_commit *commit; struct drm_atomic_state *state; bool color_mgmt_changed : 1; }; struct drm_plane_helper_funcs { int (*prepare_fb)(struct drm_plane *plane, struct drm_plane_state *new_state); void (*cleanup_fb)(struct drm_plane *plane, struct drm_plane_state *old_state); int (*begin_fb_access)(struct drm_plane *plane, struct drm_plane_state *new_plane_state); void (*end_fb_access)(struct drm_plane *plane, struct drm_plane_state *new_plane_state); int (*atomic_check)(struct drm_plane *plane, struct drm_atomic_state *state); void (*atomic_update)(struct drm_plane *plane, struct drm_atomic_state *state); void (*atomic_enable)(struct drm_plane *plane, struct drm_atomic_state *state); void (*atomic_disable)(struct drm_plane *plane, struct drm_atomic_state *state); int (*atomic_async_check)(struct drm_plane *plane, struct drm_atomic_state *state); void (*atomic_async_update)(struct drm_plane *plane, struct drm_atomic_state *state); int (*get_scanout_buffer)(struct drm_plane *plane, struct drm_scanout_buffer *sb); void (*panic_flush)(struct drm_plane *plane); }; prepare_fb: 如果没实现,那么在 drm_atomic_helper_prepare_planes 中会调用 drm_gem_plane_helper_prepare_fb()代替。...

2024-08-28 · 1 min

DRM Subsystem 3 -- 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 // 每种drm_mode(CRTC, fb, encoder, connector...)都有会分配drm_mode_object // 提供了lookup,get,put,release callback等机制 struct drm_mode_object base; char comm[TASK_COMM_LEN]; // allocate fb的进程名 const struct drm_format_info *format; // fb 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 Subsystem 3 -- Hardware Driver

中间层 struct drm_driver 底层 driver xxx_drv.c 首先初始化一个struct drm_driver DEFINE_DRM_GEM_DMA_FOPS(fops); static const struct drm_driver mxsfb_driver = { .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC, DRM_GEM_DMA_DRIVER_OPS, .fops = &fops, .name = "mxsfb-drm", .desc = "MXSFB Controller DRM", .date = "20160824", .major = 1, .minor = 0, }; 其中.driver_feature支持的属性有: enum drm_driver_feature { DRIVER_GEM = BIT(0), // GEM 内存管理,一般都需要选上 DRIVER_MODESET = BIT(1), // KMS, kernel mode setting DRIVER_RENDER = BIT(3), // dedicated render node DRIVER_ATOMIC = BIT(4), // 支持所有modesetting userspace API。 DRIVER_SYNCOBJ = BIT(5), // 支持&drm_syncobj,用来主动同步 DRIVER_SYNCOBJ_TIMELINE = BIT(6), DRIVER_COMPUTE_ACCEL = BIT(7), // 支持compute acceleration。和DRIVER_RENDER,DRIVER_MODESET选项互斥,如果同时支持modeset和compute_accel那么就需要实现两个driver。 DRIVER_GEM_GPUVA = BIT(8), // 支持user定义的GPU VA bindings for GEM objects DRIVER_CURSOR_HOTSPOT = BIT(9), // 支持cursor hotspot information // 下面这些都是legacy driver的属性 DRIVER_USE_AGP = BIT(25), // AGP support, 不清楚作用,已不使用 DRIVER_LEGACY = BIT(26), // 使用shadow attach的legacy driver,已淘汰 DRIVER_PCI_DMA = BIT(27), // Legacy PCI DMA supprot, 已不使用 DRIVER_SG = BIT(28), // Legacy scatter/gather DMA support, 已不使用 DRIVER_HAVE_DMA = BIT(29), // Legacy DMA support, 已不使用 DRIVER_HAVE_IRQ = BIT(30), // Legacy irq support, 已不使用 }; 在 driver probe 函数中调用devm_drm_dev_alloc()函数分配struct drm_device空间,drm_dev_alloc()中又会调用drm_dev_init()来进行一系列初始化struct drm_device。...

2024-08-20 · 2 min

DRM Subsystem 2 -- 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 Subsystem 1 -- 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