RK3568平台(显示篇)FrameBuffer 应用编程

news2024/11/15 17:29:09

一.FrameBuffer介绍

FrameBuffer(帧缓冲器)是一种计算机图形学概念,用于在显示器上显示图形和文本。在 计算机显示系统中,FrameBuffer 可以看作是显存的一个抽象概念,用于存储显示屏幕上显示 的像素点的颜色和位置信息。FrameBuffer 包含了所有要在显示器上显示的像素点的颜色值, 每个像素点的颜色值通常用一个 32 位的无符号整数表示,其中每 8 个比特表示一个颜色分 量(红、绿、蓝和透明度)。

二.LCD基础

成像原理:

液晶 LCD 显示器是由两片平行的玻璃基板组成,两片平行的玻璃基板之间放置了一个液晶 盒。在下基板玻璃上,有一组被称为薄膜晶体管(TFT)的电子元件,而在上基板玻璃上则放 置了彩色滤光片。液晶分子可以通过施加电压来改变其方向,从而控制光线的传播方向。具体 地说,TFT 上的电信号会通过电压的变化来控制液晶分子的方向,使其可以旋转或者不旋转。 通过这种方式,每个像素点的偏振光可以被控制为出射或不出射,从而达到显示图像的目的。

分辨率:

分辨率(Resolution)是指在一定的屏幕尺寸下,可以显示的像素点的数量。它通常用于 描述数字设备(如电视、计算机显示器、智能手机、平板电脑等)的屏幕质量和清晰度,以及 图像和视频的清晰度和细节。

720p       1280 x 720 高清电视、视频游戏和视频流媒体

1080p     1920 x 1080 高清电视、计算机显示器和视频游戏

2K           2560 x 1440 高端计算机显示器和智能手机

4K           3840 x 2160 高端电视、计算机显示器和游戏机

8K           7680 x 4320 高端电视和计算机显示器

像素格式:

像素格式通常包括两个方面的信息:色彩深度和色彩空间。

色彩深度:指的是每个像素存储颜色信息所需要的位数,通常以位/像素(bit/pixel)的形式 表示。例如,8 位像素格式表示每个像素使用 8 个二进制位来表示颜色信息,可以表示 256 种 不同的颜色。而 16 位像素格式则可以表示 65536 种不同的颜色。

色彩空间:是指用来描述颜色的数学模型。不同的色彩空间有不同的颜色模型和颜色空间, 它们可以描述不同的颜色和亮度值。例如,RGB 色彩空间使用红、绿、蓝三个颜色通道来描述 颜色,而 YUV 色彩空间使用亮度和两个色差通道来描述颜色。常见的像素格式包括 RGB、YUV、 YCbCr 等。

三.LCD 成像步骤

帧缓冲区(frame buffer):用于存放 LCD 显示数据的显存。帧缓冲区通过 LCD 控制器和 LCD 面板之间建立一一映射关系。

LCD 控制器:配置 LCD 控制器,用于发出 LCD 控制信号并驱动 LCD 显示。 扫描方式:如图所示,从一行开始到一帧结束的扫描方向为从左到右,从上到下。

HSYNC:行同步信号,用于行切换。当一行扫描结束并需要扫描新行时,需要先发送行同 步信号。

VSYNC:列同步信号,用于列切换。当一帧扫描结束并需要扫描新的一帧时,需要先发送 列同步信号。

时钟信号:每当一个时钟信号到来时,对应的扫描点将移动一个单位。 下面是成像步骤的图形描述:

LCD 驱动器类似于一支电子枪,它由 LCD 控制器控制,LCD 控制器从显存中获取像素数据 并发送命令给电子枪发射像素颜色。整个成像过程可以分为以下 3 个步骤:

步骤 1:LCD 控制器发送 VSYNC 信号,告诉电子枪要开始发射新帧了。电子枪将枪头调整 到 LCD 屏幕的左上角,准备开始发射像素。

步骤 2:LCD 控制器同时发送 HSYNC 信号,告诉电子枪新的一行开始了,并且从左向右 开始扫射像素。但是电子枪反应速度较慢,需要一段时间才能开始扫射像素,因此会出现一些 无效的数据区域。当一行结束时,LCD 控制器再次发送 HSYNC 信号,电子枪将枪头扭转到下一 行开始扫描,也会出现一些左右无效区域。当一帧结束时,LCD 控制器会等待电子枪游离一段 时间,然后开始下一帧的成像。

步骤 3:当电子枪扫描到最后一行结束时,LCD 控制器不会再发送有效像素数据,并且等 待电子枪游离一段时间,因此出现了下方的无效区。之后回到步骤 1 开始重复。 至此 LCD 成像步骤就介绍完了。

四.LCD 应用编程介绍

应用程序通过对 LCD 设备节点 /dev/fb0 (假设 LCD 对应的设备节点是 /dev/fb0)进行 I/O 操作即可实现对 LCD 的显示控制,实质就相当于读写了 LCD 的显存,而显存是 LCD 的 显示缓冲区,LCD 硬件会从显存中读取数据显示到 LCD 液晶面板上。
在应用程序中,操作/dev/fbX 的一般步骤如下:

①、首先打开 /dev/fbX 设备文件。
②、使用 ioctl() 函数获取到当前显示设备的参数信息,譬如屏幕的分辨率大小、像素格式,根据屏幕参 数计算显示缓冲区的大小。
③、通过存储映射 I/O 方式将屏幕的显示缓冲区映射到用户空间( mmap )。
④、映射成功后就可以直接读写屏幕的显示缓冲区,进行绘图或图片显示等操作了。
⑤、完成显示后,调用 munmap() 取消映射、并调用 close() 关闭设备文件。

使用 ioctl()获取屏幕参数信息:

FBIOGET_VSCREENINFO : 表示获取 FrameBuffer 设备的可变参数信息,可变参数信息使用 struct fb_var_screeninfo 结 构 体 来 描 述 , 所 以 此 时 ioctl() 需 要 有 第 三 个 参 数 , 它 是 一 个 struct fb_var_screeninfo *指针,指向 struct fb_var_screeninfo 类型对象,调用 ioctl() 会将 LCD 屏的可变参 数信息保存在 struct fb_var_screeninfo 类型对象中,如下所示:

struct fb_var_screeninfo fb_var;
ioctl(fd, FBIOGET_VSCREENINFO, &fb_var);

struct fb_var_screeninfo 结构体内容如下所示:

struct fb_var_screeninfo {
__u32 xres ;
/* 可视区域,一行有多少个像素点, X 分辨率 */
__u32 yres ;
/* 可视区域,一列有多少个像素点, Y 分辨率 */
__u32 xres_virtual ;
/* 虚拟区域,一行有多少个像素点 */
__u32 yres_virtual ;
/* 虚拟区域,一列有多少个像素点 */
__u32 xoffset ;
/* 虚拟到可见屏幕之间的行偏移 */
__u32 yoffset ;
/* 虚拟到可见屏幕之间的列偏移 */
__u32 bits_per_pixel ; /* 每个像素点使用多少个 bit 来描述,也就是像素深度 bpp */
__u32 grayscale ;
/* =0 表示彩色 , =1 表示灰度 , >1 表示 FOURCC 颜色 */
/* 用于描述 R 、 G 、 B 三种颜色分量分别用多少位来表示以及它们各自的偏移量 */
struct fb_bitfield red ;
/* Red 颜色分量色域偏移 */
struct fb_bitfield green ; /* Green 颜色分量色域偏移 */
struct fb_bitfield blue ; /* Blue 颜色分量色域偏移 */
struct fb_bitfield transp ; /* 透明度分量色域偏移 */
__u32 nonstd ;
/* nonstd 等于 0 ,表示标准像素格式;不等于 0 则表示非标准像素格式 */
__u32 activate ;
__u32 height ;
/* 用来描述 LCD 屏显示图像的高度(以毫米为单位) */
__u32 width ;
/* 用来描述 LCD 屏显示图像的宽度(以毫米为单位) */
__u32 accel_flags ;
/* 以下这些变量表示时序参数 */
__u32 pixclock ;
/* pixel clock in ps (pico seconds) */
__u32 left_margin ;
/* time from sync to picture */
__u32 right_margin ; /* time from picture to sync */
__u32 upper_margin ; /* time from sync to picture */
__u32 lower_margin ;
__u32 hsync_len ;
/* length of horizontal sync */
__u32 vsync_len ;
/* length of vertical sync */
__u32 sync ;
/* see FB_SYNC_* */
__u32 vmode ;
/* see FB_VMODE_* */
__u32 rotate ;
/* angle we rotate counter clockwise */
__u32 colorspace ;
/* colorspace for FOURCC-based modes */
__u32 reserved [ 4 ];
/* Reserved for future compatibility */
};

FBIOGET_FSCREENINFO : 表示获取 FrameBuffer 设备的固定参数信息,既然是固定参数,那就 意味着应用程序不可修改。固定参数信息使用struct fb_fix_screeninfo 结构体来描述,所以此时 ioctl() 需要有第三个参数,它是一个 struct fb_fix_screeninfo * 指针,指向 struct fb_fix_screeninfo 类型对象, 调用 ioctl() 会将 LCD 的固定参数信息保存在 struct fb_fix_screeninfo 对象中,如下所示:

struct fb_fix_screeninfo fb_fix;
ioctl(fd, FBIOGET_FSCREENINFO, &fb_fix);

 struct fb_fix_screeninfo 结构体内容如下所示:

struct fb_fix_screeninfo {
char id [ 16 ];
/* 字符串形式的标识符 */
unsigned long smem_start ; /* 显存的起始地址(物理地址) */
__u32 smem_len ;
/* 显存的长度 */
__u32 type ;
__u32 type_aux ;
__u32 visual ;
__u16 xpanstep ;
__u16 ypanstep ;
__u16 ywrapstep ;
__u32 line_length ;
/* 一行的字节数 */
unsigned long mmio_start ; /* Start of Memory Mapped I/O(physical address) */
__u32 mmio_len ;
/* Length of Memory Mapped I/O */
__u32 accel ;
/* Indicate to driver which specific chip/card we have */
__u16 capabilities ;
__u16 reserved [ 2 ];
};

使用 mmap()将显示缓冲区映射到用户空间

为什么这里需要使用存储映射 I/O 这种方式呢?其实使用普通的 I/O 方式(譬如直接 read 、 write )也是 可以的,只是,当数据量比较大时,普通 I/O 方式效率较低。假设某一显示器的分辨率为 1920 * 1080 ,像 素格式为 ARGB8888 ,针对该显示器,刷一帧图像的数据量为 1920 x 1080 x 32 / 8 = 8294400 个字节(约等 于 8MB ),这还只是一帧的图像数据,而对于显示器来说,显示的图像往往是动态改变的,意味着图像数 据会被不断更新。
在这种情况下,数据量是比较庞大的,使用普通 I/O 方式必然导致效率低下,所以才会采用存储映射 I/O 方式。

LCD 应用编程实验:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <linux/fb.h>

#define SCREEN_WIDTH 800
#define SCREEN_HEIGHT 1280
#define BYTES_PER_PIXEL 4 // 32-bit color (RGBA)

int main(int argc, char* argv[]) 
{
    int fbfd = 0; // framebuffer设备的文件描述符
    struct fb_var_screeninfo vinfo; // 可变屏幕信息
    struct fb_fix_screeninfo finfo; // 固定屏幕信息
    char *fbp = NULL; // framebuffer内存的指针

    // 打开framebuffer设备以进行读写
    fbfd = open("/dev/fb0", O_RDWR);
    if (fbfd == -1) 
	{
        perror("Error: 无法打开framebuffer设备");
        exit(1);
    }

    // 获取固定屏幕信息
    if (ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo) == -1) 
	{
        perror("Error: 读取固定信息时发生错误");
        exit(2);
    }

    // 获取可变屏幕信息
    if (ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo) == -1) 
	{
        perror("Error: 读取可变信息时发生错误");
        exit(3);
    }

    // 将framebuffer设备内存映射到用户空间
    fbp = (char*)mmap(0, finfo.smem_len, PROT_READ | PROT_WRITE, MAP_SHARED, fbfd, 0);
    if ((int)fbp == -1) 
	{
        perror("Error: 映射framebuffer设备到内存时出错");
        exit(4);
    }

    // 计算线条的像素位置和颜色值
    int x = atoi(argv[1]);
    int y = atoi(argv[2]);
    int length = atoi(argv[3]);
    unsigned int color = 0xFFFF0000; // 红色 (格式:ARGB)

    // 绘制线条
    for (int i = 0; i < length; i++) 
	{
        int location = (x + i) * BYTES_PER_PIXEL + (y * SCREEN_WIDTH * BYTES_PER_PIXEL);
        *((unsigned int*)(fbp + location)) = color;
    }

   // 刷新framebuffer以显示绘制的线条
    struct fb_var_screeninfo new_vinfo;
    new_vinfo.activate = FB_ACTIVATE_VBL;
    ioctl(fbfd, FBIOPUT_VSCREENINFO, &new_vinfo);

    // 从用户空间中取消映射framebuffer设备内存
    if (munmap(fbp, finfo.smem_len) == -1) 
	{
        perror("Error: 从内存中取消映射framebuffer设备时发生错误");
        exit(6);
    }

    // 关闭framebuffer设备
    close(fbfd);

    return 0;
}

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

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

相关文章

ElementUi el-tree动态加载节点数据 load方法触发机制

需求背景&#xff1a;需要根据点击后获取的数据动态渲染一个 el-tree&#xff0c;同时渲染出来的 el-tree&#xff0c;需要点击节点时才能获取该节点的层数的获取&#xff0c;如图所示&#xff0c;我需要点击“组”节点才能渲染“设备列表”树&#xff0c;同时“设备列表”树的…

Vue16-绑定class样式

一、vue绑定class样式 1-1、需求一&#xff1a;字符串写法 vue实现class样式绑定 1-2、需求二 点击div&#xff0c;随机切换样式。 math.random()&#xff1a;随机数的范围[0, 1) 1-3、需求三&#xff1a;数组写法 样式的追加 1-4、需求四 &#xff1a;对象写法 二、vue绑定…

浅解Reids持久化

Reids持久化 RDB redis的存储方式&#xff1a; rdb文件都是二进制&#xff0c;很小&#xff0c;里面存的是数据 实现方式 redis-cli链接到redis服务端 使用save命令 注&#xff1a;不推荐 因为save命令是直接写到磁盘里面&#xff0c;速度特别慢&#xff0c;一般都是redis…

MySQl基础----Linux下搭建mysql软件及登录和基本使用(附实操图超简单一看就会)

绪论​ 涓滴之水可磨损大石&#xff0c;不是由于他力量强大&#xff0c;而是由于昼夜不舍地滴坠。 只有勤奋不懈地努力&#xff0c;才能够获得那些技巧。 ——贝多芬。新开MySQL篇章&#xff0c;本章非常基础包括如何在Linux上搭建&#xff08;当然上面的SQL语句你在其他能执行…

UnityXR Interaction Toolkit 如何使用XRHand手部识别

前言 Unity的XR Interaction Toolkit是一个强大的框架,允许开发者快速构建沉浸式的VR和AR体验。随着虚拟现实技术的发展,手部追踪成为了提升用户交互体验的关键技术之一。 本文将介绍如何在Unity中使用XR Interaction Toolkit实现手部识别功能。 准备工作 在开始之前,请…

Chat-TTS:windows本地部署实践【有手就行】

最近Chat-TTS模型很火&#xff0c;生成的语音以假乱真&#xff0c;几乎听不出AI的味道。我自己在本地部署玩了一下&#xff0c;记录一下其中遇到的问题。 环境&#xff1a; 系统&#xff1a;windows 11 GPU&#xff1a; Nvidia 4060 Cuda&#xff1a;12.1&#xff08;建议安…

后方碰撞预警系统技术规范(简化版)

后方碰撞预警系统技术规范(简化版) 1 系统概述2 预警区域3 预警目标4 功能需求功能条件5 显示需求6 指标需求1 系统概述 后方碰撞预警系统RCW(Rear Collision Warning)是在后方车辆即将与自车发生碰撞之前,激活危险警告灯以较高频率闪烁,从而吸引后方驾驶员的注意力,避免…

PG 数据库常用参数调整

1.shard_buffers Postgresql使用自己的缓冲区,也使用操作系统缓冲区。这意味着数据存储在内存中两次,首先是 Postgresql缓冲区,然后是操作系统缓冲区。 与其他数据库不同, Postgresql不提供直接IO。这称为双缓冲&#xff08;就是磁盘中的时候读的时候先放在数据库的缓冲区&am…

【Python教程】3-控制流、循环结构与简单字符串操作

在整理自己的笔记的时候发现了当年学习python时候整理的笔记&#xff0c;稍微整理一下&#xff0c;分享出来&#xff0c;方便记录和查看吧。个人觉得如果想简单了解一名语言或者技术&#xff0c;最简单的方式就是通过菜鸟教程去学习一下。今后会从python开始重新更新&#xff0…

Vue17-条件渲染

一、使用v-show属性做条件渲染 控制元素的显示和隐藏 v-show里面也能是表达式&#xff0c;只要表达式的值是boolean就行。 或者 当时结构还在&#xff1a; 二、使用v-if属性做条件渲染 结构也不在了 三、示例 方式一&#xff1a; 方式二&#xff1a; 当元素有很高的切换频率&am…

【web本地存储】storage事件,StorageEvent对象介绍

storage事件 Web Storage API 内建了一套事件通知机制&#xff0c;当存储区域的内容发生改变&#xff08;包括增加、修改、删除数据&#xff09;时&#xff0c;就会自动触发storage事件&#xff0c;并把它发送给所有感兴趣的监听者&#xff0c;因此&#xff0c;如果需要跟踪存…

第十二届蓝桥杯单片机国赛练习代码

文章目录 前言一、问题重述二、主函数总结 前言 第十五蓝桥杯国赛落幕已有十天&#xff0c;是时候总结一下&#xff0c;这个专栏也将结束。虽然并没有取得预期的结果&#xff0c;但故事结尾并不总是美满的。下面是赛前练习的第十二届国赛的代码。 一、问题重述 二、主函数 完整…

万向节锁死(Gimbal Lock)

Gimbal Lock是一个常见的3D动画问题,主要由旋转顺序引起的。我来详细解释一下它的成因: 在三维空间中,任何旋转都可以分解为绕X,Y,Z三个轴的欧拉旋转(Euler Rotation)。每个轴的旋转是按照一定顺序进行的,比如XYZ或ZYX等。 理论上,通过这三个旋转值的组合,可以达到任意的空间…

MATLAB实现磷虾算法(Krill herd algorithm)

1.算法介绍 磷虾算法&#xff08;Krill Herd Algorithm, KH&#xff09;是一种基于生物启发的优化算法&#xff0c;其原理模拟了南极磷虾&#xff08;Euphausia superba&#xff09;群体的聚集行为。该算法旨在通过模拟磷虾个体间的相互作用、觅食行为和随机扩散&#xff0c;来…

设计模式 —— 观察者模式

设计模式 —— 观察者模式 什么是观察者模式观察者模式定义观察者模式的角色观察者模式的使用场景观察者模式的实现 被观察者&#xff08;Subject&#xff09;观察者&#xff08;Observer&#xff09;通知&#xff08;notify&#xff09;更新显示&#xff08;update&#xff09…

Webpack 从入门到精通-基础篇

一、webpack 简介 1.1 webpack 是什么 webpack 是一种前端资源构建工具&#xff0c;一个静态模块打包器(module bundler)。 在 webpack 看来, 前端的所有资源文件(js/json/css/img/less/...)都会作为模块处理。 它将根据模块的依赖关系进行静态分析&#xff0c;打包生成对应的…

MYSQL六、存储引擎的认识

一、存储引擎 1、MySQL体系结构 连接层&#xff1a;最上层是一些客户端和链接服务&#xff0c;包含本地sock 通信和大多数基于客户端/服务端工具实现的类似于TCP/IP的通信。主要完成一些类似于连接处理、授权认证、及相关的安全方案。在该层上引入了线程池的概念&#xff0c;为…

Open vSwitch 数据包接收的实现

一、Open vSwitch 数据包的来源 Open vSwitch 中的数据包有许多种来源&#xff1a; 物理网络接口&#xff1a;OVS 可以连接到物理网络设备&#xff0c;并处理从这些设备收到的数据包。这些数据包可能来自外部网络&#xff0c;需要被转发或进一步处理。虚拟网络接口&#xff1a…

MySQL 常见客户端程序

本篇主要介绍MySQL常见的客户端程序 目录 一、mysqlcheck 二、mysqldump 三、mysqladmin 四、mysqldumpslow 五、mysqlbinlog 六、mysqlshow 显示列的具体信息​编辑 七、mysqlslap 一、mysqlcheck mysqlcheck是MySQL的表维护程序&#xff0c;其功能主要包含以下四个方…

遗传算法笔记:基本工作流程

1 介绍 遗传算法有5个主要任务&#xff0c;直到找到最终的解决方案 2 举例 2.1 问题描述 比如我们有 5 个变量和约束&#xff0c;其中 X1、X2、X3、X4 和 X5 是非负整数且小于 10&#xff08;0、1、2、4、5、6、7、8、9&#xff09;我们希望找到 X1、X2、X3、X4 和 X5 的最…