显存管理

Disp_manager.c
为了显示更流畅,事先malloc分配多块缓存,设置好页面内容,然后再把缓存内容全部memcpy复制进framebuffer显存里。每块缓存用VideoMem结构体来描述。

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;

分配 iNum块缓存
为了考虑内存较少的设备, iNum可以为0,直接使用显存framebuffe,所以先将framebuffer放入链表。如果分配了缓存,分配iNum个内存都依次放入链表。若分配缓存,将framebuffer状态改为占用,这样不会被用作缓存分配。对于lcd的显存framebuffer,可以直接在上面描绘数据,而对于分配的缓存,设置好上面的内容后需要将它刷进framebuffer,所以设置了标记位bDevFrameBuffer,是framebuffer就不用刷了。
VideoMem: 为加快显示速度,我们事先在缓存中构造好显示的页面的数据,(这个缓存称为VideoMem)显示时再把VideoMem中的数据复制到设备的显存上

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);	//获取LCD分辨率
	iVMSize = iXres * iYres * iBpp / 8;			//分配内存大小
	iLineBytes = iXres * iBpp / 8;				//分配内存一行的字节数

	/* 先把设备本身的framebuffer放入链表,因为可能不使用缓存
	 * 分配一个T_VideoMem结构体, 注意我们没有分配里面的tPixelDatas.aucPixelDatas
	 * 而是让tPixelDatas.aucPixelDatas指向显示设备的framebuffer*/
	ptNew = malloc(sizeof(T_VideoMem));
	ptNew->tPixelDatas.aucPixelDatas = g_ptDefaultDispOpr->pucDispMem;	/* 指向framebuffer */
	
	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同样大小的缓存" */
		ptNew = malloc(sizeof(T_VideoMem) + iVMSize);
		/* 在T_VideoMem结构体里记录上面分配的"跟framebuffer同样大小的缓存" */
		ptNew->tPixelDatas.aucPixelDatas = (unsigned char *)(ptNew + 1);
		ptNew->iID = 0;						//ID
		ptNew->bDevFrameBuffer = 0;			//普通缓存
		ptNew->eVideoMemState = VMS_FREE;	//状态:空闲
		ptNew->ePicState      = PS_BLANK;	//图片状态:空
		ptNew->tPixelDatas.iWidth  = iXres;	//设置PixelDatas结构体
		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;
}

获得一块可操作的VideoMem(它用于存储要显示的数据),用完后用PutVideoMem来释放。
根据ID从链表中取出缓存,
优先级
1.取出空闲的、ID相同的VideoMem,
2.取出任意一个空闲且没有数据的VideoMem,
3.没有就取出任意一个空闲的VideoMem,
4. 取出任意一个VideoMem。
释放缓存就是将VideoMem的状态改为空闲,内容还在。每个页面的内容具有唯一的ID(根据字符串的assic码相加,基本上是唯一),下次获取VideoMem时,如果相同ID的VideoMem还在,就直接使用省去了内存描绘的过程。

PT_VideoMem GetVideoMem(int iID, int bCur){	//获得显存,参数:ID,给主/子线程使用
	/* 1. 优先: 取出空闲的、ID相同的videomem */
	PT_VideoMem ptTmp = g_ptVideoMemHead;	
	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;
}

唯一的ID,根据字符串的前4个字符的assic码相加

int ID(char *strName){
	return (int)(strName[0]) + (int)(strName[1]) + (int)(strName[2]) + (int)(strName[3]);
}

使用GetVideoMem获得的VideoMem, 用完时用PutVideoMem释放掉
不用将ptVideoMem内规划好的内存释放掉,而是将状态改为空闲,这样下次还要用到该ID的页面时可以直接使用,省去了页面的生成。

void PutVideoMem(PT_VideoMem ptVideoMem){
	ptVideoMem->eVideoMemState = VMS_FREE;  /* 设置VideoMem状态为空闲 */
    if (ptVideoMem->iID == -1)
        ptVideoMem->ePicState = PS_BLANK;  /* 表示里面的数据没有用了 */
}

rander.c
void FlushVideoMemToDev(PT_VideoMem ptVideoMem)
将VideoMem的内容memcpy刷进显存framebuffer,获得默认的显示设备,调用该设备的ShowPage函数。

void FlushVideoMemToDev(PT_VideoMem ptVideoMem){
	if (!ptVideoMem->bDevFrameBuffer){
		GetDefaultDispDev()->ShowPage(ptVideoMem);
	}
}

fb.c
FBShowPage函数,将VideoMem的内从显示到显存framebuffer中。

static int FBShowPage(PT_VideoMem ptVideoMem){
	memcpy(g_tFBOpr.pucDispMem, ptVideoMem->tPixelDatas.aucPixelDatas, ptVideoMem->tPixelDatas.iTotalBytes);
	return 0;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值