DRM驱动(五)之drm_atomic_state

上节讲到《DRM驱动(四)之ADD_FB》调用drmModeAddFB创建drm_framebuffer。然后通过

drmIoctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &map);

vaddr = mmap(0, create.size, PROT_READ | PROT_WRITE,MAP_SHARED, fd, map.offset);

将物理地址map到用户空间后,就可以在这块内存上绘一张自己喜欢的图。接下来就需要把这块内存配置到硬件上面,进行刷图。

刷图有很多中方式,比如:

int drmModeSetCrtc(int fd, uint32_t crtcId, uint32_t bufferId, uint32_t x, uint32_t y, uint32_t *connectors, int count, drmModeModeInfoPtr mode)

fd:文件描述符

crtcId:crtc_id

bufferId:即上节创建的fb id

x,y:在屏幕上的显示坐标

connectors:connector id

count:connector 数量

mode:包括刷新率,分辨率等timing的信息

也可以使用下面接口:

drmModeAtomicAlloc();

drmModeAtomicAddProperty(..., property_id, property_value);

drmModeAtomicCommit(...);

本节以drmModeSetCrtc为例

int drmModeSetCrtc(int fd, uint32_t crtcId, uint32_t bufferId,
           uint32_t x, uint32_t y, uint32_t *connectors, int count,
           drmModeModeInfoPtr mode)
{
    struct drm_mode_crtc crtc;
 
    memclear(crtc);
    crtc.x             = x;
    crtc.y             = y;
    crtc.crtc_id       = crtcId;
    crtc.fb_id         = bufferId;
    crtc.set_connectors_ptr = VOID2U64(connectors);
    crtc.count_connectors = count;
    if (mode) {
      memcpy(&crtc.mode, mode, sizeof(struct drm_mode_modeinfo));
      crtc.mode_valid = 1;
    }
 
    return DRM_IOCTL(fd, DRM_IOCTL_MODE_SETCRTC, &crtc);
}
主要用于填充如下数据结构,传给内核,drm会根据传入的信息配置display硬件。比如crtc_id来指定显示到哪个crtc,fb_id指定哪块使用dumb显存等等。

struct drm_mode_crtc {
__u64 set_connectors_ptr;
__u32 count_connectors;
__u32 crtc_id; /**< Id */
__u32 fb_id; /**< Id of framebuffer */
 
__u32 x; /**< x Position on the framebuffer */
__u32 y; /**< y Position on the framebuffer */
 
__u32 gamma_size;
__u32 mode_valid;
struct drm_mode_modeinfo mode;
}
按照之前的经验,在内核drm_ioctl.c中找到对应函数调用

DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETCRTC, drm_mode_setcrtc, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED)

DRM_IOCTL_DEF(DRM_IOCTL_MODE_ATOMIC, drm_mode_atomic_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED)

drm_mode_setcrtc和drm_mode_atomic_ioctl从函数调用来看都会调用drm_atomic_commit(state) 也就是说应用传入的参数最终会转换成struct drm_atomic_state;

看下struct drm_atomic_state数据结构

struct drm_atomic_state {
    struct kref ref;
 
    struct drm_device *dev;
    bool allow_modeset : 1;
    bool legacy_cursor_update : 1;
    bool async_update : 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 work_struct commit_work;
};
drm_atomic_state和其他组件state的继承关系如下图:

数据结构之间的转换过程:

int drm_mode_setcrtc(struct drm_device *dev, void *data,
             struct drm_file *file_priv)
{
    crtc = drm_crtc_find(dev, file_priv, crtc_req->crtc_id);
 
    if (crtc_req->mode_valid) {
 
        fb = drm_framebuffer_lookup(dev, file_priv, crtc_req->fb_id);
        mode = drm_mode_create(dev);
        ret = drm_mode_convert_umode(mode, &crtc_req->mode);
    }
    if (crtc_req->count_connectors > 0) {
        connector_set = kmalloc_array(crtc_req->count_connectors,
                          sizeof(struct drm_connector *),
                          GFP_KERNEL);
 
        for (i = 0; i < crtc_req->count_connectors; i++) {
            connector_set[i] = NULL;
            set_connectors_ptr = (uint32_t __user *)(unsigned long)crtc_req->set_connectors_ptr;
            connector = drm_connector_lookup(dev, file_priv, out_id);
            connector_set[i] = connector;
        }
    }
 
    set.crtc = crtc;
    set.x = crtc_req->x;
    set.y = crtc_req->y;
    set.mode = mode;
    set.connectors = connector_set;
    set.num_connectors = crtc_req->count_connectors;
    set.fb = fb;
    ret = __drm_mode_set_config_internal(&set, &ctx);
 
out:
    if (fb)
        drm_framebuffer_put(fb);
 
    if (connector_set) {
        for (i = 0; i < crtc_req->count_connectors; i++) {
            if (connector_set[i])
                drm_connector_put(connector_set[i]);
        }
    }
    kfree(connector_set);
    drm_mode_destroy(dev, mode);
 
    return ret;
}
drm_mode_setcrtc的主要作用:

根据应用传入的crtc_id找到crtc
根据应用传入的fb_id,找到对应的drm_framebuffer
根据应用传入的mode,创建一个drm_display_mode
根据传入的set_connectors_ptr,找到驱动对应的connector
将以上信息转为struct drm_mode_set并调用__drm_mode_set_config_internal
static int __drm_mode_set_config_internal(struct drm_mode_set *set,
                      struct drm_modeset_acquire_ctx *ctx)
{
    struct drm_crtc *crtc = set->crtc;
    struct drm_framebuffer *fb;
    struct drm_crtc *tmp;
    drm_for_each_crtc(tmp, crtc->dev)
        tmp->primary->old_fb = tmp->primary->fb;
 
    fb = set->fb;
    
    ret = drm_atomic_helper_set_config(set, ctx);
    if (ret == 0) {
        crtc->primary->crtc = crtc;
        crtc->primary->fb = fb;
    }
 
    return ret;
}
__drm_mode_set_config_internal的内容比较少,主要调用drm_atomic_helper_set_config

int drm_atomic_helper_set_config(struct drm_mode_set *set,
                 struct drm_modeset_acquire_ctx *ctx)
{
    struct drm_atomic_state *state;
    struct drm_crtc *crtc = set->crtc;
    int ret = 0;
    state = drm_atomic_state_alloc(crtc->dev);
 
    ret = __drm_atomic_helper_set_config(set, state);
 
    ret = drm_atomic_commit(state);
fail:
    drm_atomic_state_put(state);
    return ret;
}
drm_atomic_helper_set_config的主要作用:

创建struct drm_atomic_state
将struct drm_mode_set转换成为struct drm_atomic_state
调用drm_atomic_commit 将修改commit到硬件
int __drm_atomic_helper_set_config(struct drm_mode_set *set,
        struct drm_atomic_state *state)
{
    struct drm_crtc_state *crtc_state;
    struct drm_plane_state *primary_state;
    struct drm_crtc *crtc = set->crtc;
    int hdisplay, vdisplay;
    int ret;
 
    crtc_state = drm_atomic_get_crtc_state(state, crtc);
 
    primary_state = drm_atomic_get_plane_state(state, crtc->primary);
 
    ret = drm_atomic_set_mode_for_crtc(crtc_state, set->mode);
 
    crtc_state->active = true;
 
    ret = drm_atomic_set_crtc_for_plane(primary_state, crtc);
 
    drm_mode_get_hv_timing(set->mode, &hdisplay, &vdisplay);
 
    drm_atomic_set_fb_for_plane(primary_state, set->fb);
    primary_state->crtc_x = 0;
    primary_state->crtc_y = 0;
    primary_state->crtc_w = hdisplay;
    primary_state->crtc_h = vdisplay;
    primary_state->src_x = set->x << 16;
    primary_state->src_y = set->y << 16;
    if (drm_rotation_90_or_270(primary_state->rotation)) {
        primary_state->src_w = vdisplay << 16;
        primary_state->src_h = hdisplay << 16;
    } else {
        primary_state->src_w = hdisplay << 16;
        primary_state->src_h = vdisplay << 16;
    }
 
    ret = update_output_state(state, set);
 
    return 0;
}
这块比较代码有点复杂,这里简单的用一个表格说明几个比较重要的结构体数据之间的对应关系,不再赘述代码里的内容。

本节介绍了应用调用drmModeSetCrtc时传入参数转换为struct drm_atomic_state的过程,下节将介绍drm利用drm_atomic_state中内容更新图像的过程。

注:文中代码仅作说明,删除了一些错误处理等内容,介意可以看下drm驱动的源码。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/15716.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Python中list遍历的几种方式之没有好与不好,只有合适不合适

Python中list遍历的几种方式 引言 Python是一种动态、解释型的高级编程语言&#xff0c;以其简洁、易读的语法而广受欢迎。在Python中&#xff0c;list是一种非常重要的数据结构&#xff0c;它允许存储一系列的元素&#xff0c;这些元素可以是任何类型。遍历list是处理数据的…

nginx的Connection refused

问题描述 nginx的错误日志中突然出现大量的的Connection refused问题&#xff0c;日志如下&#xff1a; 2020/03/19 09:52:53 [error] 20117#20117: *7403411764 connect() failed (111: Connection refused) while connecting to upstream, client: xxx.xxx.xxx.xxx, server:…

解决CLion调试时无法显示变量值的问题

1 问题描述 使用CLion的时候&#xff0c;调试时无法显示变量的值&#xff0c;例如&#xff1a; 图来自StackOverflow。 2 解决办法 可以尝试切换调试器解决&#xff0c;在Linux下&#xff0c;CLion支持GDB和LLDB&#xff0c;如果GDB不行&#xff0c;可以切换到LLDB。 切换方…

医院信息化IT监控一体化运维实践

作者: 晓风 在医疗信息化日益发展的今天&#xff0c;医院数据中心的运维工作显得尤为重要。为了确保医疗系统的稳定运行&#xff0c;保障患者数据的安全与完整&#xff0c;我院在信息化IT监控一体化运维方面进行了深入的探索和实践。 一、背景与挑战 我院的机房设备规模已有50…

主动归档存储的策略研讨

在媒体与娱乐&#xff08;M&E&#xff09;行业中&#xff0c;主动存档策略对于应对内容的持续需求增长、控制存储成本膨胀以及实现档案内容的货币化至关重要。以下是对此策略的深入分析&#xff1a; ### 持续的内容需求带来的挑战 M&E企业面临着巨大的挑战&#xff1…

【Spring】SSM整合_入门代码实现

1. Maven依赖 在pom.xml中添加SSM框架的依赖 <!-- Spring Core --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.3.x</version> </dependency>…

软件杯 题目: 基于深度学习的疲劳驾驶检测 深度学习

文章目录 0 前言1 课题背景2 实现目标3 当前市面上疲劳驾驶检测的方法4 相关数据集5 基于头部姿态的驾驶疲劳检测5.1 如何确定疲劳状态5.2 算法步骤5.3 打瞌睡判断 6 基于CNN与SVM的疲劳检测方法6.1 网络结构6.2 疲劳图像分类训练6.3 训练结果 7 最后 0 前言 &#x1f525; 优…

为什么单片机不能直接驱动继电器和电磁阀

文章是瑞生网转载&#xff0c;PDF格式文章下载&#xff1a; 为什么单片机不能直接驱动继电器和电磁阀.pdf: https://url83.ctfile.com/f/45573183-1247189072-10b6d1?p7526 (访问密码: 7526)

java-数组内存分配

在 Java 中&#xff0c;数组是一种基本数据结构&#xff0c;用于存储一系列相同类型的数据。在内存中&#xff0c;数组分配是一块连续的内存空间&#xff0c;用于存储数组中的所有元素。本篇文章将详细解释 Java 中数组的内存分配&#xff0c;包括数组的声明、创建、内存模型以…

memcpy的使⽤和模拟实现

目录 一&#xff1a;memcpy的使⽤ memcpy的使⽤的代码 二&#xff1a;memcpy函数的模拟实现: memcpy和strcpy的区别 用途&#xff1a; 安全性&#xff1a; 数据类型&#xff1a; 性能&#xff1a; 在字符串中的用法示例&#xff1a; memcpy: strcpy 一&#xff1a;…

Ajax面试题精选及参考答案(3万字长文)

目录 什么是Ajax,它的核心原理是什么? Ajax应用程序的优势有哪些? Ajax最大的特点是什么?

Science 基于尖峰时序编码的模拟神经触觉系统,可实现动态对象分类

快速处理和有效利用手与物体交互过程中产生的动态触觉信号&#xff08;例如触摸和抓握&#xff09;对于触觉探索和灵巧的物体操作至关重要。将电子皮肤&#xff08;e-skins&#xff09;推进到模仿自然触觉的水平&#xff0c;是恢复截肢者和瘫痪患者丧失的功能的可行解决方案&am…

实现地图上展示坐标时,不要全部展示、只展示几个距离相对较大marker点位,随着地图放大再全部展示出来。

比例尺级别地面分辨率 &#xff08;米/像素&#xff09;比例尺0156543.031&#xff1a;591658700.82178271.5151&#xff1a;295829350.4239135.75751&#xff1a;147914675.2319567.878751&#xff1a;73957337.649783.9393751&#xff1a;36978668.854891.9696881&#xff1a…

电机控制系列模块解析(22)—— 零矢量刹车

一、零矢量刹车 基本概念 逆变器通常采用三相桥式结构&#xff0c;包含六个功率开关元件&#xff08;如IGBT或MOSFET&#xff09;&#xff0c;分为上桥臂和下桥臂。每个桥臂由两个反并联的开关元件组成&#xff0c;上桥臂和下桥臂对应于电机三相绕组的正负端。正常工作时&…

mongodb在游戏开发领域的优势

1、分布式id 游戏服务器里的大部分数据都是要求全局唯一的&#xff0c;例如玩家id&#xff0c;道具id。之所以有这种要求&#xff0c;是因为运营业务上需要进行合服操作&#xff0c;保证不同服的数据在进行合服之后&#xff0c;也能保证id不冲突。如果采用关系型数据库&#x…

【C++题解】1699 - 输出是2的倍数,但非3的倍数的数

问题&#xff1a;1699 - 输出是2的倍数&#xff0c;但非3的倍数的数 类型&#xff1a;循环 题目描述&#xff1a; 请从键盘读入一个整数 n&#xff0c;输出 1∼n 中所有是 2 的倍数&#xff0c;但非 3 的倍数的数&#xff0c;每行 1个。 比如&#xff0c;读入一个整数10 &…

Spring AI实战之二:Chat API基础知识大串讲(重要)

欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码)&#xff1a;https://github.com/zq2599/blog_demos Spring AI实战全系列链接 Spring AI实战之一&#xff1a;快速体验(OpenAI)Spring AI实战之二&#xff1a;Chat API基础知识大串讲(重要)SpringAIOllama三部曲…

Linux:进程地址空间、进程控制(一.进程创建、进程终止、进程等待)

上次介绍了环境变量&#xff1a;Linux&#xff1a;进程概念&#xff08;四.main函数的参数、环境变量及其相关操作&#xff09; 文章目录 1.程序地址空间知识点总结上述空间排布结构是在内存吗&#xff1f;&#xff08;进程地址空间引入&#xff09; 2.进程地址空间明确几个点进…

NDIS小端口驱动开发(三)

微型端口驱动程序处理来自过度驱动程序的发送请求&#xff0c;并发出接收指示。 在单个函数调用中&#xff0c;NDIS 微型端口驱动程序可以指示具有多个接收 NET_BUFFER_LIST 结构的链接列表。 微型端口驱动程序可以处理对每个NET_BUFFER_LIST结构上具有多个 NET_BUFFER 结构的多…

JAVA -- > 初识JAVA

初始JAVA 第一个JAVA程序详解 public class Main {public static void main(String[] args) {System.out.println("Hello world");} }1.public class Main: 类型,作为被public修饰的类,必须与文件名一致 2.public static 是JAVA中main函数准写法,记住该格式即可 …