前面介紹了如何直接操作WinCE的FrameBuffer,這裡将介紹一種通過寫FrameBuffer顯示資源中BMP圖檔的方法。并與使用GDI做一個比較,看看直接讀寫FrameBuffer是否能提高效率?
采用GDI的方法,關鍵代碼如下:
hScrDC = CreateDC(TEXT("DISPLAY"),NULL,NULL,NULL);
hMemDC = CreateCompatibleDC (hScrDC);
bmp.LoadBitmap(MAKEINTRESOURCE(IDB_BITMAP1));
bmp.GetBitmap(&bmpInfo);
SelectObject(hMemDC,bmp);
BitBlt(hScrDC,0,0,dwWidth,dwHeight,hMemDC,0,0,SRCCOPY);
采用直接寫FrameBuffer的方法,關鍵代碼如下:
HINSTANCE hInst = (HINSTANCE)::GetModuleHandle(NULL);
HRSRC hrc = FindResource((HMODULE)hInst,MAKEINTRESOURCE(IDB_BITMAP1),RT_BITMAP);
HGLOBAL hGlobal = LoadResource(NULL,hrc);
dwBufSize = ::SizeofResource(NULL,hrc);
gbmpBuf = (PBYTE)::LockResource(hGlobal);
memcpy(gpLCDBuf,gbmpBuf,dwBufSize);
資源中加載的BMP圖檔是從WinCE的顯存中直接儲存下來的,如下圖所示。

使用BitBlt顯示的效果如下圖所示。
直接寫顯存的效果如下圖所示。
可以看到采用BitBlt,資源中的BMP似乎被真實顯示。采用直接寫屏的方法顔色被還原了,但往右偏了一些。他們分别使用的時間如下圖所示,GDI使用了145ms,直接寫顯存大概1ms。
很明顯,直接寫顯存比使用BitBlt快很多,但位置有偏差。那麼用GDI能否有更快的方法?它為什麼這麼慢。又嘗試着用了GDI的另外一種方法顯示。代碼如下:
bmi.bmih.biSize = sizeof(bmi.bmih);
bmi.bmih.biWidth = dwWidth;
bmi.bmih.biHeight = -dwHeight;
bmi.bmih.biPlanes = 1;
bmi.bmih.biBitCount = (BYTE)bmpInfo.bmBitsPixel;
bmi.bmih.biSizeImage = 0;
bmi.bmih.biXPelsPerMeter = 0;
bmi.bmih.biYPelsPerMeter = 0;
bmi.bmih.biClrUsed = 0;
bmi.bmih.biClrImportant = 0;
bmi.bmih.biCompression = BI_BITFIELDS;
*(DWORD *)(&bmi.rgq[0]) = 0xF800;
*(DWORD *)(&bmi.rgq[1]) = 0x07E0;
*(DWORD *)(&bmi.rgq[2]) = 0x001F;
StretchDIBits (hScrDC, 0, 0, dwWidth, dwHeight, 0, 0, dwWidth, dwHeight,
gbmpBuf, (PBITMAPINFO)&bmi, DIB_RGB_COLORS, SRCCOPY);
采用這種方法,顯示效果和DDraw完全一樣,速度也不相上下,同樣比BitBlt快很多。這是為什麼呢?玄妙就在bmi.rgq,這裡設定的BIT MASK與顯示驅動中一緻,是以,效果相當于直接寫屏,顔色也對了,效率也高了。而BitBlt預設的BIT MASK估計與驅動中的不一緻,進而導緻多做一些記憶體運算,花費了一些時間。為了驗證這個想法,修改bmi.rgq的設定如下:
*(DWORD *)(&bmi.rgq[1]) = 0x03E0;
這種情況下,顔色顯示與BitBlt一樣,使用的時間也差不多。看來并不是使用GDI就一定會慢,BIT MASK才是關鍵。16位色的BIT MASK主要有以下幾種。
// XRRRRRGG.GGGBBBBB 0x7C00 0x03E0 0x1F
// RRRRRXGG.GGGBBBBB 0xF800 0x03E0 0x1F
// RRRRRGGG.GGXBBBBB 0xF800 0x07C0 0x1F
// RRRRRGGG.GGGBBBBB 0xF800 0x07E0 0x1F
在實際開發過程中,這個小細節可以注意一下,也許可以提高一些效率。