13.display文件夹分析

1.用到的结构体

 /*确定一个图层的大小,用于对图标显示位置的解释*/
typedef struct Layout {		
	int iTopLeftX;			//左上角xy坐标
	int iTopLeftY;
	int iBotRightX;			//右下角xy坐标
	int iBotRightY;
	char *strIconName;		//图标的名字,即用的哪张图片
}T_Layout, *PT_Layout;

 /*用于对事先分配好的几块内存的状态标致*/
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;       /* 内存: 用来存储图像,这里不是指针,当分配一个T_VideoMem结构体时,这一块内存就已经分配了*/
	struct VideoMem *ptNext;        /* 链表 */
}T_VideoMem, *PT_VideoMem;

/*显示设备结构体,用来注册设备用*/
typedef struct DispOpr {
	char *name;             		/* 显示模块的名字 */
	int iXres;               		/* X分辨率 */
	int iYres;              		/* Y分辨率 */
	int iBpp;                		/* 一个象素用多少位来表示 */
	int iLineWidth;          		/* 一行数据占据多少字节 */
	unsigned char *pucDispMem;  	/* 显存地址 */
	int (*DeviceInit)(void);     	/* 设备初始化函数 */
	int (*ShowPixel)(int iPenX, int iPenY, unsigned int dwColor);    /* 把指定座标的象素设为某颜色 */
	int (*CleanScreen)(unsigned int dwBackColor);                    /* 清屏为某颜色 */
	int (*ShowPage)(PT_VideoMem ptVideoMem);                         /* 显示一页,数据源自ptVideoMem */
	struct DispOpr *ptNext;     	/* 链表 */
}T_DispOpr, *PT_DispOpr;

2.disp_manager.c

static PT_DispOpr g_ptDispOprHead;		//显示设备的头
static PT_DispOpr g_ptDefaultDispOpr;	//默认的显示设备
static PT_VideoMem g_ptVideoMemHead;	//那几块缓存的头

int RegisterDispOpr(PT_DispOpr ptDispOpr);		//注册一个设备
void ShowDispOpr(void);							//显示一下都有哪些设备注册了
int DisplayInit(void);							//调用需要注册设备的注册函数
void SelectAndInitDefaultDispDev(char *name);	//通过名字选择默认设备,并调用其初始化函数和清屏
PT_DispOpr GetDefaultDispDev(void);				//获得默认显示设备的结构体
int GetDispResolution(int *piXres, int *piYres, int *piBpp);	//获得显示设备的分辨率信息
int AllocVideoMem(int iNum);					//分配iNum块buffer,用来提前填满显示数据
PT_VideoMem GetDevVideoMem(void);				//相当于获得设备的framebuffer
PT_VideoMem GetVideoMem(int iID, int bCur);		//根据ID号获得一块内存,并把状态设置为bCur
void PutVideoMem(PT_VideoMem ptVideoMem);		//使用GetVideoMem获得的VideoMem, 用完时用PutVideoMem释放掉
void ClearVideoMem(PT_VideoMem ptVideoMem, unsigned int dwColor);//把某块分配的内存清为某种颜色,与设备的CleanScreen函数不同,设备的CleanScreen只是清framebuffer
void ClearVideoMemRegion(PT_VideoMem ptVideoMem, PT_Layout ptLayout, unsigned int dwColor);
int FBInit(void);

重要函数具体解析

分配几块内存供 提前准备显示数据 使用
int AllocVideoMem(int iNum)
{
	int i;

	int iXres = 0;
	int iYres = 0;
	int iBpp  = 0;

	int iVMSize;		//整块buffer的大小
	int iLineBytes;		//一行的大小

	PT_VideoMem ptNew;

	/* 获得显示设备的分辨率及bpp,求出一块完整的显示需要多少buffer */
	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));			/* 用一个 T_VideoMem  结构体来标识framebuffer */
	if (ptNew == NULL)
	{
		return -1;
	}

	/* 指向framebuffer */
	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)			//就是说要分配其他的内存,不仅仅使用framebuffer
	{
		/* 如果下面要分配用于缓存的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);		//除了要分配一个结构体的空间,还需要分配一个buffer的空间,这样分配使这两块内存连在一起
		if (ptNew == NULL)
		{
			return -1;
		}
		/* 在T_VideoMem结构体里记录上面分配的"跟framebuffer同样大小的缓存" */
		ptNew->tPixelDatas.aucPixelDatas = (unsigned char *)(ptNew + 1);	//指向空着的这块内存

		ptNew->iID = 0;
		ptNew->bDevFrameBuffer = 0;						//不是frambuffer
		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;
}

根据ID号获取一块内存,并更改状态bCur
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))				//这块内存之前用过,有对应的ID号,并且现在未被使用
		{
			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;					//执行到这里说明目前这个ID号的内存,之前一次也没有用过,这里就找一块空着的给他用
	while (ptTmp)
	{
		if ((ptTmp->eVideoMemState == VMS_FREE) && (ptTmp->ePicState == PS_BLANK))	//找一个未被使用并且空着的,注意:有ID号的内存,但是里面没东西,也是会被分给别人用的
		{
			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;
}

把某一块内存刷成某一个颜色
void ClearVideoMem(PT_VideoMem ptVideoMem, unsigned int dwColor)
{
	unsigned char *pucVM;
	unsigned short *pwVM16bpp;
	unsigned int *pdwVM32bpp;
	unsigned short wColor16bpp; /* 565 */
	int iRed;
	int iGreen;
	int iBlue;
	int i = 0;

	pucVM	   = ptVideoMem->tPixelDatas.aucPixelDatas;	//获得这一块内存的地址
	pwVM16bpp  = (unsigned short *)pucVM;				//强制转换成对应bpp,这样地址自加就可以了
	pdwVM32bpp = (unsigned int *)pucVM;

	switch (ptVideoMem->tPixelDatas.iBpp)			//根据bpp选择不同的
	{
		case 8:
		{
			memset(pucVM, dwColor, ptVideoMem->tPixelDatas.iTotalBytes);	//memset只会取dwColor的后8位,把整个内存填满
			break;
		}
		case 16:
		{
			/* 先根据32位的dwColor构造出16位的wColor16bpp */
			//32位的dwColor应该是RGB888的,只使用低24位,如下
			iRed   = (dwColor >> (16+3)) & 0x1f;
			iGreen = (dwColor >> (8+2)) & 0x3f;
			iBlue  = (dwColor >> 3) & 0x1f;
			wColor16bpp = (iRed << 11) | (iGreen << 5) | iBlue;	//改成565的
			while (i < ptVideoMem->tPixelDatas.iTotalBytes)
			{
				*pwVM16bpp	= wColor16bpp;
				pwVM16bpp++;
				i += 2;
			}
			break;
		}
		case 32:
		{
			while (i < ptVideoMem->tPixelDatas.iTotalBytes)	//32字节的就直接4个字节4个字节地写进去
			{
				*pdwVM32bpp = dwColor;
				pdwVM32bpp++;
				i += 4;
			}
			break;
		}
		default :
		{
			DBG_PRINTF("can't support %d bpp\n", ptVideoMem->tPixelDatas.iBpp);
			return;
		}
	}

}
把某个内存中的某一块地方刷成某个颜色
void ClearVideoMemRegion(PT_VideoMem ptVideoMem, PT_Layout ptLayout, unsigned int dwColor)
{
	unsigned char *pucVM;			
	unsigned short *pwVM16bpp;
	unsigned int *pdwVM32bpp;
	unsigned short wColor16bpp; /* 565 */
	int iRed;
	int iGreen;
	int iBlue;
	int iX;
	int iY;
    int iLineBytesClear;
    int i;
	//算出初始的地址
	pucVM	   = ptVideoMem->tPixelDatas.aucPixelDatas + ptLayout->iTopLeftY * ptVideoMem->tPixelDatas.iLineBytes + ptLayout->iTopLeftX * ptVideoMem->tPixelDatas.iBpp / 8;
	pwVM16bpp  = (unsigned short *)pucVM;
	pdwVM32bpp = (unsigned int *)pucVM;

    iLineBytesClear = (ptLayout->iBotRightX - ptLayout->iTopLeftX + 1) * ptVideoMem->tPixelDatas.iBpp / 8;	//要清的这块内存,一行有多少Bytes

	switch (ptVideoMem->tPixelDatas.iBpp)
	{
		case 8:
		{
            for (iY = ptLayout->iTopLeftY; iY <= ptLayout->iBotRightY; iY++)	//一行一行的memset
            {
    			memset(pucVM, dwColor, iLineBytesClear);
                pucVM += ptVideoMem->tPixelDatas.iLineBytes;
            }
			break;
		}
		case 16:
		{
			/* 先根据32位的dwColor构造出16位的wColor16bpp */
			iRed   = (dwColor >> (16+3)) & 0x1f;
			iGreen = (dwColor >> (8+2)) & 0x3f;
			iBlue  = (dwColor >> 3) & 0x1f;
			wColor16bpp = (iRed << 11) | (iGreen << 5) | iBlue;
            for (iY = ptLayout->iTopLeftY; iY <= ptLayout->iBotRightY; iY++)	//一行一行地来
            {
                i = 0;
                for (iX = ptLayout->iTopLeftX; iX <= ptLayout->iBotRightX; iX++)  //一个像素一个像素的cp
    			{
    				pwVM16bpp[i++]	= wColor16bpp;									//这里用i主要是让pwVM16bpp始终指向本行的首地址,在下面换行的时候就简单了
    			}
                pwVM16bpp = (unsigned short *)((unsigned int)pwVM16bpp + ptVideoMem->tPixelDatas.iLineBytes); //指向下一行
            }
			break;
		}
		case 32:
		{
            for (iY = ptLayout->iTopLeftY; iY <= ptLayout->iBotRightY; iY++)	    //一行一行
            {
                i = 0;
                for (iX = ptLayout->iTopLeftX; iX <= ptLayout->iBotRightX; iX++)	//一个像素一个像素
    			{
    				pdwVM32bpp[i++]	= dwColor;
    			}
                pdwVM32bpp = (unsigned int *)((unsigned int)pdwVM32bpp + ptVideoMem->tPixelDatas.iLineBytes);	//下一行,与16bpp大同小异
            }
			break;
		}
		default :
		{
			DBG_PRINTF("can't support %d bpp\n", ptVideoMem->tPixelDatas.iBpp);
			return;
		}
	}

}

3.fb.c

/* 屏的初始化,包括了
 * 打开屏、获得屏的可变与不可变信息、屏的framebuffer映射到内存
 * 计算整个framebuffer的大小、计算一行的大小、填充T_DispOpr结构体
 * */
static int FBDeviceInit(void)

/* 屏上某一个点的显示 */
static int FBShowPixel(int iX, int iY, unsigned int dwColor)

/* T_DispOpr结构体中的一项
 * 在该显示设备(这里是屏)上显示一页
 * 本质就是 PT_VideoMem->tPixelDatas.aucPixelDatas 地址memcpy到 framebuffer中
 * */
static int FBShowPage(PT_VideoMem ptVideoMem)

/* 把屏清成某一种颜色 */
static int FBCleanScreen(unsigned int dwBackColor)

/* 注册,在disp_manager.c中调用,disp_manager.h中声明 */
int FBInit(void)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值