一 Framebuffer
数据结构
在DRM
框架中,`Framebuffer``用于存储需要显示的内容,存储的信息包括:
-
需要显示的内容在内存区域的引用;
-
存储在内存中的帧的格式;
-
内存区域的激活区域(即将要显示的内容);
DRM Framebuffer
是一个虚拟的对象,它依赖于特定的实现。Framebuffer
实现依赖于:
- 依赖于内存管理模块,比如
GEM
; - 依赖于显示控制器的能力:
- 支持
DMA
传输类型(可以是连续内存或者Scatter Gather
); IOMMU
;
- 支持
1.1 struct drm_framebuffer
linux
内核使用struct drm_framebuffer
表示一个帧缓冲,包括像素格式、分辨率和显存地址等信息。定义在include/drm/drm_framebuffer.h
;
/**
* struct drm_framebuffer - frame buffer object
*
* Note that the fb is refcounted for the benefit of driver internals,
* for example some hw, disabling a CRTC/plane is asynchronous, and
* scanout does not actually complete until the next vblank. So some
* cleanup (like releasing the reference(s) on the backing GEM bo(s))
* should be deferred. In cases like this, the driver would like to
* hold a ref to the fb even though it has already been removed from
* userspace perspective. See drm_framebuffer_get() and
* drm_framebuffer_put().
*
* The refcount is stored inside the mode object @base.
*/
struct drm_framebuffer {
/**
* @dev: DRM device this framebuffer belongs to
*/
struct drm_device *dev;
/**
* @head: Place on the &drm_mode_config.fb_list, access protected by
* &drm_mode_config.fb_lock.
*/
struct list_head head;
/**
* @base: base modeset object structure, contains the reference count.
*/
struct drm_mode_object base;
/**
* @comm: Name of the process allocating the fb, used for fb dumping.
*/
char comm[TASK_COMM_LEN];
/**
* @format: framebuffer format information
*/
const struct drm_format_info *format;
/**
* @funcs: framebuffer vfunc table
*/
const struct drm_framebuffer_funcs *funcs;
/**
* @pitches: Line stride per buffer. For userspace created object this
* is copied from drm_mode_fb_cmd2.
*/
unsigned int pitches[DRM_FORMAT_MAX_PLANES];
/**
* @offsets: Offset from buffer start to the actual pixel data in bytes,
* per buffer. For userspace created object this is copied from
* drm_mode_fb_cmd2.
*
* Note that this is a linear offset and does not take into account
* tiling or buffer layout per @modifier. It is meant to be used when
* the actual pixel data for this framebuffer plane starts at an offset,
* e.g. when multiple planes are allocated within the same backing
* storage buffer object. For tiled layouts this generally means its
* @offsets must at least be tile-size aligned, but hardware often has
* stricter requirements.
*
* This should not be used to specifiy x/y pixel offsets into the buffer
* data (even for linear buffers). Specifying an x/y pixel offset is
* instead done through the source rectangle in &struct drm_plane_state.
*/
unsigned int offsets[DRM_FORMAT_MAX_PLANES];
/**
* @modifier: Data layout modifier. This is used to describe
* tiling, or also special layouts (like compression) of auxiliary
* buffers. For userspace created object this is copied from
* drm_mode_fb_cmd2.
*/
uint64_t modifier;
/**
* @width: Logical width of the visible area of the framebuffer, in
* pixels.
*/
unsigned int width;
/**
* @height: Logical height of the visible area of the framebuffer, in
* pixels.
*/
unsigned int height;
/**
* @flags: Framebuffer flags like DRM_MODE_FB_INTERLACED or
* DRM_MODE_FB_MODIFIERS.
*/
int flags;
/**
* @hot_x: X coordinate of the cursor hotspot. Used by the legacy cursor
* IOCTL when the driver supports cursor through a DRM_PLANE_TYPE_CURSOR
* universal plane.
*/
int hot_x;
/**
* @hot_y: Y coordinate of the cursor hotspot. Used by the legacy cursor
* IOCTL when the driver supports cursor through a DRM_PLANE_TYPE_CURSOR
* universal plane.
*/
int hot_y;
/**
* @filp_head: Placed on &drm_file.fbs, protected by &drm_file.fbs_lock.
*/
struct list_head filp_head;
/**
* @obj: GEM objects backing the framebuffer, one per plane (optional).
*
* This is used by the GEM framebuffer helpers, see e.g.
* drm_gem_fb_create().
*/
struct drm_gem_object *obj[DRM_FORMAT_MAX_PLANES];
};
该结构体包括以下成员:
dev
:该framebuffer
所属的DRM
设备;head
:链表节点,用于将当前节点添加到drm_mode_config.fb_list
链表;base
:该framebuffer
的基类,struct drm_mode_object
类型;comn
:char
数组,数组长度为32,用于存放分配该fb的进程的名字;format
:帧缓冲的格式信息;funcs
:帧缓冲的函数表;pitches
:无符号int数组,数组长度为4,存放每个plane
缓冲区的行跨度(以字节为单位);offsets
:无符号int数组,数组长度为4,存放每个plane缓冲区中实际像素数据相对于缓冲区起始处的偏移量(以字节为单位);modifier
:数据布局修饰符,用于描述缓冲区的平铺或特殊布局;width
:帧缓冲可见区域的逻辑宽度(以像素为单位);height
:帧缓冲可见区域的逻辑高度(以像素为单位);flags
:帧缓冲的标志,例如DRM_MODE_FB_INTERLACED
或DRM_MODE_FB_MODIFIERS
;hot_x
:光标热点的X坐标, Used by the legacy cursor IOCTL when the driver supports cursor through a DRM_PLANE_TYPE_CURSOR universal plane;hot_y
:光标热点的Y坐标,Used by the legacy cursor IOCTL when the driver supports cursor through a DRM_PLANE_TYPE_CURSOR universal plane;filp_head
:链表节点,用于将该帧缓冲对象加入到drm_file
结构的fbs
链表中,访问此链表需要使用fbs_lock
进行保护;obj
:struct drm_gem_object
类型指针数组,数组长度为4,备份帧缓冲的GEM
对象,每个plane
一个对象;
struct drm_framebuffer
主要元素的展示如下图所示,其中Memory Region
表示帧缓冲区,Dsisplayed Area
表示实际显示区域,图中棕色区域表示实际像素数据相对于帧缓冲区起始处的偏移量;
这里需要介绍一下pitches
、offsets
为啥是个数组,数组的长度为DRM_FORMAT_MAX_PLANES
,通过这个宏我们大概可以了解到每种DRM
格式应该包含多个plane
,因此数组元素的值依次对应每个plane
;
1.2 struct drm_format_info
linux
内核使用struct drm_format_info
表示DRM
格式信息(更准确说应该是帧缓冲数据格式),定义在include/drm/drm_fourcc.h
;
/**
* struct drm_format_info - information about a DRM format
*/
struct drm_format_info {
/** @format: 4CC format identifier (DRM_FORMAT_*) */
u32 format;
/**
* @depth:
*
* Color depth (number of bits per pixel excluding padding bits),
* valid for a subset of RGB formats only. This is a legacy field, do
* not use in new code and set to 0 for new formats.
*/
u8 depth;
/** @num_planes: Number of color planes (1 to 3) */
u8 num_planes;
union {
/**
* @cpp:
*
* Number of bytes per pixel (per plane), this is aliased with
* @char_per_block. It is deprecated in favour of using the
* triplet @char_per_block, @block_w, @block_h for better
* describing the pixel format.
*/
u8 cpp[DRM_FORMAT_MAX_PLANES];
/**
* @char_per_block:
*
* Number of bytes per block (per plane), where blocks are
* defined as a rectangle of pixels which are stored next to
* each other in a byte aligned memory region. Together with
* @block_w and @block_h this is used to properly describe tiles
* in tiled formats or to describe groups of pixels in packed
* formats for which the memory needed for a single pixel is not
* byte aligned.
*
* @cpp has been kept for historical reasons because there are
* a lot of places in drivers where it's used. In drm core for
* generic code paths the preferred way is to use
* @char_per_block, drm_format_info_block_width() and
* drm_format_info_block_height() which allows handling both
* block and non-block formats in the same way.
*
* For formats that are intended to be used only with non-linear
* modifiers both @cpp and @char_per_block must be 0 in the
* generic format table. Drivers could supply accurate
* information from their drm_mode_config.get_format_info hook
* if they want the core to be validating the pitch.
*/
u8 char_per_block[DRM_FORMAT_MAX_PLANES];
};
/**
* @block_w:
*
* Block width in pixels, this is intended to be accessed through
* drm_format_info_block_width()
*/
u8 block_w[DRM_FORMAT_MAX_PLANES];
/**
* @block_h:
*
* Block height in pixels, this is intended to be accessed through
* drm_format_info_block_height()
*/
u8 block_h[DRM_FORMAT_MAX_PLANES];
/** @hsub: Horizontal chroma subsampling factor */
u8 hsub;
/** @vsub: Vertical chroma subsampling factor */
u8 vsub;
/** @has_alpha: Does the format embeds an alpha component? */
bool has_alpha;
/** @is_yuv: Is it a YUV format? */
bool is_yuv;
/** @is_color_indexed: Is it a color-indexed format? */
bool is_color_indexed;
};
它包括以下字段:
format
:4CC
格式标识符(DRM_FORMAT_*
);depth
:颜色深度(每像素的位数,不包括填充位),仅适用于部分RGB
格式。这是一个过时字段,在新代码中不要使用,并且对于新格式设置为0。num_planes
:color plane
数量(1到3)。pp
:数组长度为4,依次存储每个plane
每像素的字节数,与char_per_block
具有别名。对于更好地描述像素格式,已弃用此字段,推荐使用三元组char_per_block
、block_w
、block_h
;char_per_block
:数组长度为4,依次存储每个块的字节数,块被定义为以字节对齐的内存区域中相邻存储的像素矩形。与block_w
和block_h
一起使用,可以正确描述平铺格式中的图块,或者对于单个像素所需的字节对齐的打包格式中的像素组;block_w
:数组长度为4,依次存储块宽度(以像素为单位),应通过drm_format_info_block_width()
访问;block_h
:数组长度为4,依次存储块高度(以像素为单位),应通过drm_format_info_block_height()
访问;hsub
:水平色度亚采样因子;vsub
:垂直色度亚采样因子;has_alpha
:格式是否包含Alpha
分量;is_yuv
:格式是否为YUV
格式;is_color_indexed
:格式是否为索引颜色格式;
1.2.1 FOURCC
什么是4CC
格式(或者说FOURCC format
)?它是一种用于标识数据格式的约定,每个FOURCC
编码由4个ASCII
字符组成,通过表示特定类型的数据格式、编码或标记。
FOURCC
代码最初由Microsoft
引入并广泛应用于多媒体和图像处理领域。它们通常用于标识和区分不同的文件格式、视频编解码器、像素格式、音频格式等。
在计算机图形中,FOURCC
代码常用于指定像素格式,例如在视频编码和解码中。通过使用FOURCC
编码,可以快速识别和解释特定的数据格式,以便进行适当的处理和解码。
需要注意的是,FOURCC
代码只是一种标识符号,代表了特定的格式或类型,具体的实现和处理方式仍需根据具体的应用和上下文来确定。
DRM
支持的FOURCC
格式定义在include/drm/drm_fourcc.h
:
/**
* DRM_FORMAT_MAX_PLANES - maximum number of planes a DRM format can have
*/
#define DRM_FORMAT_MAX_PLANES 4u // DRM格式最多包含的plane数量
/*
* DRM formats are little endian. Define host endian variants for the
* most common formats here, to reduce the #ifdefs needed in drivers.
*
* Note that the DRM_FORMAT_BIG_ENDIAN flag should only be used in
* case the format can't be specified otherwise, so we don't end up
* with two values describing the same format.
*/
#ifdef __BIG_ENDIAN
# define DRM_FORMAT_HOST_XRGB1555 (DRM_FORMAT_XRGB1555 | \
DRM_FORMAT_BIG_ENDIAN)
# define DRM_FORMAT_HOST_RGB565 (DRM_FORMAT_RGB565 | \
DRM_FORMAT_BIG_ENDIAN)
# define DRM_FORMAT_HOST_XRGB8888 DRM_FORMAT_BGRX8888
# define DRM_FORMAT_HOST_ARGB8888 DRM_FORMAT_BGRA8888
#else
# define DRM_FORMAT_HOST_XRGB1555 DRM_FORMAT_XRGB1555
# define DRM_FORMAT_HOST_RGB565 DRM_FORMAT_RGB565
# define DRM_FORMAT_HOST_XRGB8888 DRM_FORMAT_XRGB8888
# define DRM_FORMAT_HOST_ARGB8888 DRM_FORMAT_ARGB8888
#endif
RGB
是颜色的编码格式,它代表红色(R)、绿色(G)和蓝色(B)三个颜色通道。
在RGB
编码中,每个像素使用一个包含三个数字值的元组来表示颜色。这三个值分别表示红色、绿色和蓝色的亮度或强度。每个值的范围是从0到255,其中0表示没有该颜色的亮度,而255表示最高强度或亮度。
ARGB
是在RGB
编码的基础上增加了一个额外的通道——Alpha
通道。Alpha
通道用于表示像素的透明度,即图像中该像素的不透明程度。Alpha
通道的取值范围也是0到255,其中0表示完全透明,255表示完全不透明。
XRGB
是指在RGB
编码中,其中一个字节(8位)被保留但未使用。通常这个保留位是填充0,因此它不影响颜色的表示。这种编码方式常用于某些特定的图形处理操作和计算中,可以提高效率和内存利用率。
1.3 struct drm_framebuffer_funcs
linux
内核使用struct drm_framebuffer_funcs
表示帧缓冲区的基本操作,定义在include/drm/drm_framebuffer.h
:
/**
* struct drm_framebuffer_funcs - framebuffer hooks
*/
struct drm_framebuffer_funcs {
/**
* @destroy:
*
* Clean up framebuffer resources, specifically also unreference the
* backing storage. The core guarantees to call this function for every
* framebuffer successfully created by calling
* &drm_mode_config_