您的位置:首页 > 其它

工作笔记之32BPP

2010-09-20 17:45 134 查看
原创,为个人工作日记,请最好不要转载

20100920:

从16BPP提高到32BPP,可以正常显示,但是图片切换不够流畅

搞了快一周了,终于将GDI的驱动流程了解个大概,如下:

WINCE普通驱动是由device.exe加载和管理的,而显示以及输入设备等是由GWES.exe加载和管理的。访问显示驱动的接口也不是CreateFile等文件系统的API,而是由GDI接口CreateDC,ReleaseDC等接口(在wingdi.h中有定义)。
提供给GWES调用的上层GDI接口为DrvAnyBlt、DrvBitBlt等;但实际上公开给GWES的接口只有DrvEnableDriver(),在这个接口中导出其他的接口,如下:
GPEEnableDriver(ULONG iEngineVersion,ULONG cj,DRVENABLEDATA * pded,
PENGCALLBACKS pEngCallbacks)
{
memcpy(pded, &pDrvFn, cj);
}
pDrvFn定义如下:
const DRVENABLEDATA pDrvFn = {
{ DrvEnablePDEV },
{ DrvDisablePDEV },
……
};
&pDrvFn为GDI提供给GWES接口函数数组的首地址,将此地址赋给GPEEnableDriver的pded参数,则实现了将函数接口导出给GWES的目的。
GPE源代码文件: WINCE500/PUBLIC/COMMON/OAK/DRIVERS/DISPLAY/GPE
编译后以LIB的形式提供,位置:

WINCE500/PUBLIC/COMMON/OAK/LIB/ARMV4I/RETAIL/gpe_lib.lib

我每次编译的时候,都是将gpe_lib.lib删除,然后编译GPE工程,再sysgen,保险一点

微软实现的部分:





EmulatedBlt_Internal函数简化版如下:
EmulatedBlt_Internal()

// height、width为位块的行列数,如屏为480*272,那么输出整屏height=272, width=480
// src.Ptr源位块字节地址指针, src.Value为像素值, src.BytesPerAccess为像素字节数
// dst.Bpp:液晶屏的BPP; dst.Ptr:目的位块字节地址指针,
while( height-- )

for( x=0; x<width; x++ )
{
src.Value = ( *src.Ptr ) + ( *(src.Ptr+1) << 8 ) + ( *(src.Ptr+2) << 16 );
src.Ptr += src.BytesPerAccess;
if( pParms->pConvert )
{
src.Value= Parms->pColorConverter->*(pParms->pConvert))( src.Value );
}
if( quickWrite )
{
switch(dst.Bpp)
{
case 8:
*(unsigned char *)dst.Ptr = (unsigned char)src.Value;
break;
case 16:
*(unsigned short *)dst.Ptr = (unsigned short)src.Value;
break;
case 32:
*(unsigned long *)dst.Ptr = (unsigned long)src.Value;
break;
case 24:
*dst.Ptr = (unsigned char)(src.Value);
*(dst.Ptr+1) = (unsigned char)(src.Value>>8);
*(dst.Ptr+2) = (unsigned char)(src.Value>>16);
}
dst.Ptr += dst.BytesPerAccess;
}
}


图片不流畅,主要是在while( height-- ) 输出位块的每个点到LCD buffer时有点卡

将原代码很大一部分直接咔嚓掉,如下(相当于直接写屏),就基本不卡,但是会闪一下(当然颜色是不正常的,只是验证一下,是不是由于这里导致慢的)

while( height-- )
{
// Handle y Shrinking or stretching

// Move all iterators to next line
if( src.RowPtr )
{
src.Ptr = src.RowPtr;
src.RowPtr += src.RowIncrement;

if( ! src.Is24Bit )
{
src.Cache = *(unsigned long *)src.Ptr;
src.CacheState = src.CacheStateNewRow;
}
}
if( mask.RowPtr )
{
mask.Ptr = mask.RowPtr;
mask.RowPtr += mask.RowIncrement;
mask.Cache = *(UNALIGNED unsigned long *)mask.Ptr;
mask.CacheState = mask.CacheStateNewRow;
}
dst.Ptr = dst.RowPtr;
dst.RowPtr += dst.RowIncrement;
xAccum = rowXAccum;

// LARGE_INTEGER LargeInt;
// DWORD dwOpTime;

// QueryPerformanceCounter (&LargeInt);
// dwOpTime = LargeInt.LowPart;

for( x=0; x<width; x++ )
{
if( src.Ptr )
{
src.Value = ( *src.Ptr ) + ( *(src.Ptr+1) << 8 ) + ( *(src.Ptr+2) << 16 );
src.Ptr += src.BytesPerAccess;

originalSrc = ( src.Value &= src.Mask );
originalSrc &= SrcRGBMask;
}
if( quickWrite )
{
switch(dst.Bpp)
{
case 8:
*(unsigned char *)dst.Ptr = (unsigned char)src.Value;
break;
case 16:
*(unsigned short *)dst.Ptr = (unsigned short)src.Value;
break;
case 32:
*(unsigned long *)dst.Ptr = (unsigned long)src.Value;
break;
case 24:
*dst.Ptr = (unsigned char)(src.Value);
*(dst.Ptr+1) = (unsigned char)(src.Value>>8);
*(dst.Ptr+2) = (unsigned char)(src.Value>>16);
}

dst.Ptr += dst.BytesPerAccess;
}

} // next column

} // next row

所以,目前有两个问题解决不了:

1、用微软GDI接口,32BPP显示会慢

2、即使是直接写屏,在图片切换时也会看到闪烁一下

目前想到的解决方法:

1、采用自带LCD控制器的LCD,其内部自带缓存;当要属于数据前将2440 LCD控制的data output disabled掉(while((rLCDCON1>>18)!=271,俺的是272*480的,要等到输出完之后再disabled)),那么,液晶屏就会保持原来的画面,等数据传输完后,再开2440 data output

如果不自带LCD 控制器,因其内部没有缓冲,2440 data disabled掉后,过一会就会出现白屏,这段时间是液晶电容的保持时间

如果可以在液晶保持电容放电到人眼可察觉的程度前,能传输完一帧数据的话,也是可以的(俺的在ADS下直接写屏是可以的,在WINCE下没戏)

2、使用硬件双缓冲,即缓存A和缓存B,A和B来回切换,只要将LCD BUFFER基地址在这两个之间切换即可

但是,一个问题是由于WINCE每次传输的时候不是整屏,往往只是一个块,例如,A中更新了一个块,那么B中就也要更新,浪费内存、浪费时间

3、使用硬件双缓冲,A和B,B是显示用的,A是暂存的,WINCE要输出的数据先输出到A,全部输出完后,再直接写屏到B,

但是,在传输的时候,只知道虚拟地址,并不知道对应的是LCD缓冲中的哪个地址?每次都得将A全部拷贝到B,效率貌似很低(也许用内存DMA传输可以?),A拷贝到B前,LCD DATA output disabled,传输完后enable,这样应该是不会看到卡的过程
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: