8.4.1 MainPage显存管理即页面框架
1.页面的框架
main_page.c
#include <config.h>
#include <page_manager.h>
static T_PageAction g_tMainPageAction = {
.name = "main",
.Run = MainPageRun,
.GetInputEvent = MainPageGetInputEvent,
.Prepare = MainPagePrepare;
};
static void MainPageRun(void)
{
/* 1. 显示页面 */
ShowMainPage(g_atMainPageLayOut);
/* 2. 创建Prepare线程 */
/* 3. 调用GetInputEvent获得输入事件,进而处理 */
while (1)
{
InputEvent = MainPageGetInputEvent();
switch (InputEvent)
{
case "浏览模式":
{
/* 保存当前页面 */
StorePage();
Page("explore")->Run();
/* 恢复之前的页面 */
RestorePage();
break;
}
case "连播模式":
{
/* 保存当前页面 */
StorePage();
Page("auto")->Run();
break;
}
case "设置":
{
/* 保存当前页面 */
StorePage();
Page("setting")->Run();
/* 恢复之前的页面 */
RestorePage();
break;
}
}
}
}
int MainPageGetInputEvent(...)
{
/* 获得原始的触摸屏数据
* 它是调用input_manager.c的函数,此函数会让当前线否休眠
* 当触摸屏线程获得数据后,会把它唤醒
*/
GetInputEvent();
/* 处理数据 */
}
int MainPageInit(void)
{
return RegisterPageAction(&g_tMainPageAction);
}
2.显存管理
3.函数解析
头文件中的结构体
disp_manager.h
/* 显示区域,含该区域的左上角/右下角座标
* 如果是图标,还含有图标的文件名
*/
typedef struct Layout {
int iTopLeftX;
int iTopLeftY;
int iBotRightX;
int iBotRightY;
char *strIconName;
}T_Layout, *PT_Layout;
/* VideoMem的状态:
* 空闲/用于预先准备显示内容/用于当前线程
*/
typedef enum {
VMS_FREE = 0,
VMS_USED_FOR_PREPARE,
VMS_USED_FOR_CUR,
}E_VideoMemState;
/* VideoMem中内存里图片的状态:
* 空白/正在生成/已经生成
*/
typedef enum {
PS_BLANK = 0,
PS_GENERATING,
PS_GENERATED,
}E_PicState;
typedef struct VideoMem {
int iID; /* ID值,用于标识不同的页面 */
int bDevFrameBuffer; /* 1: 这个VideoMem是显示设备的显存; 0: 只是一个普通缓存 */
E_VideoMemState eVideoMemState; /* 这个VideoMem的状态 */
E_PicState ePicState; /* VideoMem中内存里图片的状态 */
T_PixelDatas tPixelDatas; /* 内存: 用来存储图像 */
struct VideoMem *ptNext; /* 链表 */
}T_VideoMem, *PT_VideoMem;
disp_manager.c
AllocVideoMem
int AllocVideoMem(int iNum)
{
int i;
int iXres = 0;
int iYres = 0;
int iBpp = 0;
int iVMSize;
int iLineBytes;
PT_VideoMem ptNew;
/* 确定VideoMem的大小
*/
GetDispResolution(&iXres, &iYres, &iBpp);
iVMSize = iXres * iYres * iBpp / 8;
iLineBytes = iXres * iBpp / 8;
/* 先把设备本身的framebuffer放入链表
* 分配一个T_VideoMem结构体, 注意我们没有分配里面的tPixelDatas.aucPixelDatas
* 而是让tPixelDatas.aucPixelDatas指向显示设备的framebuffer
*/
ptNew = malloc(sizeof(T_VideoMem));
if (ptNew == NULL)
{
return -1;
}
/* 指向framebuffer */
ptNew->tPixelDatas.aucPixelDatas = g_ptDefaultDispOpr->pucDispMem;
ptNew->iID = 0;
ptNew->bDevFrameBuffer = 1; /* 表示这个VideoMem是设备本身的framebuffer, 而不是用作缓存作用的VideoMem */
ptNew->eVideoMemState = VMS_FREE;
ptNew->ePicState = PS_BLANK;
ptNew->tPixelDatas.iWidth = iXres;
ptNew->tPixelDatas.iHeight = iYres;
ptNew->tPixelDatas.iBpp = iBpp;
ptNew->tPixelDatas.iLineBytes = iLineBytes;
ptNew->tPixelDatas.iTotalBytes = iVMSize;
if (iNum != 0)
{
/* 如果下面要分配用于缓存的VideoMem,
* 把设备本身framebuffer对应的VideoMem状态设置为VMS_USED_FOR_CUR,
* 表示这个VideoMem不会被作为缓存分配出去
*/
ptNew->eVideoMemState = VMS_USED_FOR_CUR;
}
/* 放入链表 */
ptNew->ptNext = g_ptVideoMemHead;
g_ptVideoMemHead = ptNew;
/*
* 分配用于缓存的VideoMem
*/
for (i = 0; i < iNum; i++)
{
/* 分配T_VideoMem结构体本身和"跟framebuffer同样大小的缓存" */
/* 这里分配的sizeof(T_VideoMem) + iVMSize即一个文件头,和剩下的framebuffer大小的内存空间
*/
ptNew = malloc(sizeof(T_VideoMem) + iVMSize);
if (ptNew == NULL)
{
return -1;
}
/* 在T_VideoMem结构体里记录上面分配的"跟framebuffer同样大小的缓存" */
ptNew->tPixelDatas.aucPixelDatas = (unsigned char *)(ptNew + 1);
ptNew->iID = 0;
ptNew->bDevFrameBuffer = 0;
ptNew->eVideoMemState = VMS_FREE;
ptNew->ePicState = PS_BLANK;
ptNew->tPixelDatas.iWidth = iXres;
ptNew->tPixelDatas.iHeight = iYres;
ptNew->tPixelDatas.iBpp = iBpp;
ptNew->tPixelDatas.iLineBytes = iLineBytes;
ptNew->tPixelDatas.iTotalBytes = iVMSize;
/* 放入链表 */
ptNew->ptNext = g_ptVideoMemHead;
g_ptVideoMemHead = ptNew;
}
return 0;
}
GetVideoMem
/**********************************************************************
* 函数名称: GetVideoMem
* 功能描述: 获得一块可操作的VideoMem(它用于存储要显示的数据),
* 用完后用PutVideoMem来释放
* 输入参数: iID - ID值,先尝试在众多VideoMem中找到ID值相同的
* bCur - 1表示当前程序马上要使用VideoMem,无法如何都要返回一个VideoMem
* 0表示这是为了改进性能而提前取得VideoMem,不是必需的
* 输出参数: 无
* 返 回 值: NULL - 失败,没有可用的VideoMem
* 非NULL - 成功,返回PT_VideoMem结构体
* 修改日期 版本号 修改人 修改内容
* -----------------------------------------------
* 2013/02/08 V1.0 韦东山 创建
***********************************************************************/
PT_VideoMem GetVideoMem(int iID, int bCur)
{
PT_VideoMem ptTmp = g_ptVideoMemHead;
/* 1. 优先: 取出空闲的、ID相同的videomem */
while (ptTmp)
{
if ((ptTmp->eVideoMemState == VMS_FREE) && (ptTmp->iID == iID))
{
ptTmp->eVideoMemState = bCur ? VMS_USED_FOR_CUR : VMS_USED_FOR_PREPARE;
return ptTmp;
}
ptTmp = ptTmp->ptNext;
}
/* 2. 如果前面不成功, 取出一个空闲的并且里面没有数据(ptVideoMem->ePicState = PS_BLANK)的VideoMem */
ptTmp = g_ptVideoMemHead;
while (ptTmp)
{
if ((ptTmp->eVideoMemState == VMS_FREE) && (ptTmp->ePicState == PS_BLANK))
{
ptTmp->iID = iID;
ptTmp->eVideoMemState = bCur ? VMS_USED_FOR_CUR : VMS_USED_FOR_PREPARE;
return ptTmp;
}
ptTmp = ptTmp->ptNext;
}
/* 3. 如果前面不成功: 取出任意一个空闲的VideoMem */
ptTmp = g_ptVideoMemHead;
while (ptTmp)
{
if (ptTmp->eVideoMemState == VMS_FREE)
{
ptTmp->iID = iID;
ptTmp->ePicState = PS_BLANK;
ptTmp->eVideoMemState = bCur ? VMS_USED_FOR_CUR : VMS_USED_FOR_PREPARE;
return ptTmp;
}
ptTmp = ptTmp->ptNext;
}
/* 4. 如果没有空闲的VideoMem并且bCur为1, 则取出任意一个VideoMem(不管它是否空闲) */
if (bCur)
{
ptTmp = g_ptVideoMemHead;
ptTmp->iID = iID;
ptTmp->ePicState = PS_BLANK;
ptTmp->eVideoMemState = bCur ? VMS_USED_FOR_CUR : VMS_USED_FOR_PREPARE;
return ptTmp;
}
return NULL;
}
PutVideoMem
/**********************************************************************
* 函数名称: PutVideoMem
* 功能描述: 使用GetVideoMem获得的VideoMem, 用完时用PutVideoMem释放掉
* 输入参数: ptVideoMem - 使用完毕的VideoMem
* 输出参数: 无
* 返 回 值: 无
* 修改日期 版本号 修改人 修改内容
* -----------------------------------------------
* 2013/02/08 V1.0 韦东山 创建
***********************************************************************/
void PutVideoMem(PT_VideoMem ptVideoMem)
{
ptVideoMem->eVideoMemState = VMS_FREE; /* 设置VideoMem状态为空闲 */
if (ptVideoMem->iID == -1)
{
ptVideoMem->ePicState = PS_BLANK; /* 表示里面的数据没有用了 */
}
}
render.c
FlushVideoMemToDev
/**********************************************************************
* 函数名称: FlushVideoMemToDev
* 功能描述: 把缓冲区中的数据刷到显示设备上去,即在显示设备上显示缓冲区中的图像
* 输入参数: ptVideoMem - 缓冲区,内含象素数据
* 输出参数: 无
* 返 回 值: 0 - 成功, 其他值 - 失败
* 修改日期 版本号 修改人 修改内容
* -----------------------------------------------
* 2013/02/08 V1.0 韦东山 创建
***********************************************************************/
void FlushVideoMemToDev(PT_VideoMem ptVideoMem)
{
//memcpy(GetDefaultDispDev()->pucDispMem, ptVideoMem->tPixelDatas.aucPixelDatas, ptVideoMem.tPixelDatas.iHeight * ptVideoMem.tPixelDatas.iLineBytes);
if (!ptVideoMem->bDevFrameBuffer)
{
GetDefaultDispDev()->ShowPage(ptVideoMem);
}
}