在上一小节中实现了图标的显示,基本工作就准备好了。现在要来做的是显示下面这些页面:
先做主页面的显示:
我们要在显示main_page.c
页面的三个图标出来,其实完成的就是我们之前每个页面的框架中的第一步显示页面,即完成如下截图部分的代码。
1、显存的分配和获取
在写这个代码之前,我们先来了解一下硬件上面是怎么回事:不管你用的是什么开发板,在我们的板子上面,2440
也好或者其他单板也好,里面会有 LCD
控 制 器 或 者 称 为 显 卡 ,外 面 接 有LCD
。LCD
控制器或者显卡上面对应要有显存。我们写显示器的驱动程序的时候会在内存里面分配一块所谓的显存,在我们这里称为 framebuffer
。而 LCD
控制器或者显卡会从 framebuffer
里把数据取出来,发给 LCD
。当我们想显示图片的话,直接把图片写到 framebuffer
里就可以了。
那我们写应用程序时怎么做呢?可以先打开驱动程序,得到这块framebuffer
,然后就可以在这块显存里面直接写数据了。但是这样有缺点,如果你的程序运行得很慢,当你在 LCD
上面描图片的时候就会发现是一行一行很慢地描。就是说内容更新的很慢。
那我们到底一般会这么做呢?会先 malloc
一块内存,这块内存和 framebuffer
的大小是一样的。我们事先将要显示的图片数据全部放到这块内存里,弄好之后再一股脑 memcpy
到framebuffer
里面。这样 LCD
的图片就一下子更新好了。就不会出现逐行逐行或者逐块逐块地显示了。
所以针对于每个页面我们要先获得分配好的内存,然后设置里面的内容(主要是RGB
数据部分和一些flag
),然后写到我们实际的FB
的显存中。
代码见:第 1 个 项 目 数 码 相 框 全 部 源 码 _ 图 片 _ 文 档 \ 源 码 ( 含 讲 课 过 程 中 即 时 编 写 的 文 档 )\12. 数 码 相 框 项 目\14.digital_photo_frame_8.4.2_图片_源码\14.digital_photo_frame_8.4.2 节_图片_源码\14.digial_photo_frame
。
应用程序事先分配好多块内存,用于显存:
1.1、构造显存链表的结构体
但是要考虑由于我们是嵌入式系统,针对于某些型号可能内存不够用,所以分配多个显存并非对应每种型号都适用的,所以我们要兼容这些型号,我们在构造显存的链表的时候,应该在最头部加上设备实际分配的fb
的显存,对应这些内存不够用的设备,我们可以只使用这个显存链表的第一个成员即可,那么对于每个显存链表中结构体的成员应该如何考虑呢?(实际上也就是每个显存里面除了要保存RGB
数据供实际的设备显存fb
使用,还需要哪些表示来表示和区分这些其余的显存的,比如我现在有5个页面,也就是要分配5
个显存,外加一个fb
的实际设备的显存,假如我要显示main_page
这个页面,我们首先要把main_page
页面对应的显存里面对应的数据给fb
就可以显示,但是要解决几个问题:怎么从显存链表里面找到main_page
的显存呢?main_page
里面的显存里面的RGB
数据有没有准备好呢?等等),从如上几点考虑,我们的显存链表结构体构造成员如下:
- 1、由于我们的目的是为了让所有的页面都对应分配一个显存,那样对应每个页面都会有对应的显存保存它的数据,我们之后用户操作返回,或者前进时,在每个页面的显存就不用再次去设置里面的内容,所以我们需要一个
ID
来标识每个显存,当用户去返回,或者跳转到另外的页面时,就可以直接利用原来的对应的显存来进行显示里面的数据,所以需要以ID来辨别显存; - 2、我们之前有提到过,在用户点击触摸之后,会有一段时间的间隙,我们利用这段间隙,把可能下次要准备的页面通过多线程的方式准备好,所以我们还需要一个成员用来判断这个显存是给主线程使用,还是
prepare
线程使用的,另外给个初始状态是未被使用的,所以需要一个显存的进程使用状态eVideoMemState
; - 3、我们所分配的显存中主要还是用来存放要显示的每一页的数据,我们需要定义一个标志位来表示这个显存里面的对应的数据的情况,,是已经有了数据,还是正在产生数据,还是空的,成员为
ePicState
; - 4、最开始我们说了我们要在链表的头部加上一个实际
LCD
设备的fb
的显存,但是我们如何标识出链表中的成员是不是fb
的实际设备显存呢,用标志位bDevFrameBuffer
表示; - 5、最主要的还是给每个显存里面提供要现实页面的
RGB
数据,也就是我们之前有定义的T_PixelDatas tPixelDatas
; - 6、最后就是要提供链表的指向下一个链表的成员
struct VideoMem *ptNext
。
最终的结构体定义如下:
构造完显存的链表的结构体之后,我们就要实现这个链表,我们肯定要提供一个分配显存的函数int AllocVideoMem(int iNum)
,其次我们最终是要把链表里面的某一个显存成员memcpy
个fb
实际的显存,所以我们还需要一个从链表中提取显存的函数,我们分配显存肯定能是在应用层最开始就配分的,比如说我们要分配5
块显存,里面的具体内容在最开始分配的时候基本上都是一样的,比如ID
都设置为0
,当具体的页面比如main_page
去取显存的时候,发现5
个的ID
都是0
,就会随机取一块然后再具体分配ID
和对应的页面的RGB
数据给显存,下次相同的页面只需要再取到同样的ID
的显存就可以了。
1.2、显存分配函数
提供一个分配显存的函数给最顶层使用,我们先来看分配显存的函数如何实现。
1、将我们自己分配的显存加入显存链表
针对于我们要分配的显存,我们肯定是用malloc
来分配,那么要分配多大呢?要注意的是并非sizeof(T_VideoMem)
这么大,T_VideoMem
这个结构体只是用来标识我们的分配的显存的,里面虽然有定义对应页面的数据的指针,但sizeof(T_VideoMem)
并没有包含页面对应数据的大小,所以还要分配对应页面数据的大小,其实我们的数据也就是我们LCD
的分辨率的大小:sizeof(T_VideoMem)
+ LCD的数据大小
。
- 1、获取LCD的分辨率
要获得我们LCD
的数据大小,就是要获取我们LCD
的分辨率来计算的,我们之前的代码有获取x、y
值,但要知道要分配多少个字节,还需要知道bpp
参数,所以修改代码:
然后我们就可以获取bpp
了: