工作笔记之32BPP

本文记录了在Windows CE中,32BPP显示不流畅的问题及其原因分析。作者探讨了GDI驱动流程,指出EmulatedBlt_Internal函数中的瓶颈,并提出了采用带LCD控制器的屏幕、硬件双缓冲等可能的解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原创,为个人工作日记,请最好不要转载

20100920:

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

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

     

 WINCE普通驱动是由device.exe加载和管理的,而显示以及输入设备等是由GWES.exe加载和管理的。访问显示驱动的接口也不是CreateFile等文件系统的API,而是由GDI接口CreateDC,ReleaseDC等接口(wingdi.h中有定义)

   提供给GWES调用的上层GDI接口为DrvAnyBltDrvBitBlt等;但实际上公开给GWES的接口只有DrvEnableDriver(),在这个接口中导出其他的接口,如下:

GPEEnableDriver(ULONG iEngineVersion,ULONG cj,DRVENABLEDATA * pded,

PENGCALLBACKS   pEngCallbacks)

{

memcpy(pded, &pDrvFn, cj);

}

pDrvFn定义如下:

const DRVENABLEDATA pDrvFn = {

    {   DrvEnablePDEV           },

{   DrvDisablePDEV          },

……

};

&pDrvFnGDI提供给GWES接口函数数组的首地址,将此地址赋给GPEEnableDriverpded参数,则实现了将函数接口导出给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()

       // heightwidth为位块的行列数,如屏为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,这样应该是不会看到卡的过程

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值