Rockchip RK3399 - DRM framebuffer、plane、gem基础知识

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类型;
  • comnchar数组,数组长度为32,用于存放分配该fb的进程的名字;
  • format:帧缓冲的格式信息;
  • funcs:帧缓冲的函数表;
  • pitches:无符号int数组,数组长度为4,存放每个plane缓冲区的行跨度(以字节为单位);
  • offsets:无符号int数组,数组长度为4,存放每个plane缓冲区中实际像素数据相对于缓冲区起始处的偏移量(以字节为单位);
  • modifier:数据布局修饰符,用于描述缓冲区的平铺或特殊布局;
  • width:帧缓冲可见区域的逻辑宽度(以像素为单位);
  • height:帧缓冲可见区域的逻辑高度(以像素为单位);
  • flags:帧缓冲的标志,例如DRM_MODE_FB_INTERLACEDDRM_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进行保护;
  • objstruct drm_gem_object类型指针数组,数组长度为4,备份帧缓冲的GEM对象,每个plane一个对象;

struct drm_framebuffer主要元素的展示如下图所示,其中Memory Region表示帧缓冲区,Dsisplayed Area表示实际显示区域,图中棕色区域表示实际像素数据相对于帧缓冲区起始处的偏移量;

这里需要介绍一下pitchesoffsets为啥是个数组,数组的长度为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;
};

它包括以下字段:

  • format4CC格式标识符(DRM_FORMAT_*);
  • depth:颜色深度(每像素的位数,不包括填充位),仅适用于部分RGB格式。这是一个过时字段,在新代码中不要使用,并且对于新格式设置为0。
  • num_planescolor plane数量(1到3)。
  • pp:数组长度为4,依次存储每个plane每像素的字节数,与char_per_block具有别名。对于更好地描述像素格式,已弃用此字段,推荐使用三元组char_per_blockblock_wblock_h
  • char_per_block:数组长度为4,依次存储每个块的字节数,块被定义为以字节对齐的内存区域中相邻存储的像素矩形。与block_wblock_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_
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Graceful_scenery

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值