|
DIBのフレームバッファの容量は、ビットマップの大きさや色深度で容量が大きく変わり描画速度にも差が出てきます。今回は、具体的にいくつかの大きさ・色深度でDIBを作成し、そのDIBをスクロールしながら描画することで実際にどの程度の速度差が出てくるのか、実験してみることにしましょう。 DIBの作成と描画今回作成するDIBは、色深度が8/24/32bppの3種類です。以下のように指定した大きさで各色形式のDIBを作成するinit()を定義して、大きさを変えながら各色形式のDIBの描画速度を調べてみましょう。
void init(int w,int h) { /* DIBを指定サイズで初期化 */
BYTE c;
LPDWORD lpWork;
int i;
iWidth=w;
iHeight=h;
if (lpBuf!=NULL)
GlobalFree(lpBuf);
/* DIB用バッファ作成 */
lpBuf=GlobalAlloc(GPTR,sizeof(BITMAPINFO)*3+iWidth*iHeight*8+sizeof(RGBQUAD)*255);
/* 32bppDIB用ヘッダ設定 */
lpbi32bpp=(LPBITMAPINFO)lpBuf;
lp32Pixels=(LPBYTE)(lpbi32bpp+1);
lpbi32bpp->bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
lpbi32bpp->bmiHeader.biWidth=iWidth;
lpbi32bpp->bmiHeader.biHeight=iHeight;
lpbi32bpp->bmiHeader.biPlanes=1;
lpbi32bpp->bmiHeader.biBitCount=32;
lpbi32bpp->bmiHeader.biCompression=BI_RGB;
/* 24bppDIB用ヘッダ設定 */
lpbi24bpp=(LPBITMAPINFO)(lp32Pixels+iWidth*iHeight*4);
lp24Pixels=(LPBYTE)(lpbi24bpp+1);
lpbi24bpp->bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
lpbi24bpp->bmiHeader.biWidth=iWidth;
lpbi24bpp->bmiHeader.biHeight=iHeight;
lpbi24bpp->bmiHeader.biPlanes=1;
lpbi24bpp->bmiHeader.biBitCount=24;
lpbi24bpp->bmiHeader.biCompression=BI_RGB;
/* 8bppDIB用ヘッダ設定 */
lpbi8bpp=(LPBITMAPINFO)(lp24Pixels+iWidth*iHeight*3);
lp8Pixels=(LPBYTE)lpbi8bpp+sizeof(BITMAPINFO)+sizeof(RGBQUAD)*255;
lpbi8bpp->bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
lpbi8bpp->bmiHeader.biWidth=iWidth;
lpbi8bpp->bmiHeader.biHeight=iHeight;
lpbi8bpp->bmiHeader.biPlanes=1;
lpbi8bpp->bmiHeader.biBitCount=8;
lpbi8bpp->bmiHeader.biCompression=BI_RGB;
lpWork=(LPDWORD)lpbi8bpp->bmiColors;
for (i=1;i<256;i++) /* カラーテーブル作成 */
lpWork[i]=(i << 16)+(i << 8)+i;
/* 各DIBのピクセル列にランダムな色を設定 */
for (i=0;i<iWidth*iHeight;i++) {
c=(BYTE)(rand() & 0xff);
lp32Pixels[i*4]=c; /* 32bppは青 */
lp24Pixels[i*3+1]=c; /* 24bppは緑 */
lp8Pixels[i]=c; /* 8bppはグレースケール */
}
}
初期化関数init()では、まず3枚のDIB用のバッファをまとめて確保します。必要な容量は、BITMAPINFOヘッダ用にsizeof(BITMAPINFO)*3、8ビットDIBのカラーテーブル用にsizeof(RGBQUAD)*255、そしてピクセル列用にiWidth*iHeight*(4+3+1)=iWidth*iHeight*8((4+3+1)は各ピクセル列における1ピクセル当たりのバイト数)なので、 /* DIB用バッファ作成 */ lpBuf=GlobalAlloc(GPTR,sizeof(BITMAPINFO)*3+iWidth*iHeight*8+sizeof(RGBQUAD)*255); として確保します。そして、確保したバッファを以下のようにポインタに分配。
続いて描画処理。今回は、現在選択されている色深度を変数dwModeに設定してこの変数の値で描画するDIBを変えるようにしました。DIBのピクセル列は、毎回メインループでスクロールさせてから描画します。
while (1) { /* メインループ */
if (PeekMessage(&msg,NULL,0,0,PM_NOREMOVE)) {
if (!GetMessage (&msg,NULL,0,0)) /* メッセージ処理 */
return msg.wParam ;
TranslateMessage(&msg);
DispatchMessage(&msg);
} else { /* 1ピクセルスクロールして再描画 */
dwTime2=timeGetTime()-dwTime;
dwTime=timeGetTime();
if (dwMode==32) { /* 1ピクセル下スクロール */
MoveMemory(lp32Pixels,lp32Pixels+iWidth*4,iWidth*(iHeight-1)*4);
for (i=0;i<iWidth;i++) {
c=(BYTE)(rand() & 0xff);
lp32Pixels[i*4+iWidth*(iHeight-1)*4]=c;
}
} else if (dwMode==24) {
MoveMemory(lp24Pixels,lp24Pixels+iWidth*3,iWidth*(iHeight-1)*3);
for (i=0;i<iWidth;i++) {
c=(BYTE)(rand() & 0xff);
lp24Pixels[i*3+iWidth*(iHeight-1)*3+1]=c;
}
} else {
MoveMemory(lp8Pixels,lp8Pixels+iWidth,iWidth*(iHeight-1));
for (i=0;i<iWidth;i++) {
c=(BYTE)(rand() & 0xff);
lp8Pixels[i+iWidth*(iHeight-1)]=c;
}
}
InvalidateRect(hwMain,NULL,FALSE);
UpdateWindow (hwMain);
}
}
画面の描画処理では、以下のようにDIBをSetDIBitsToDevice()で描画し、ついでにフレームレートも表示してみました。
void draw(HDC hdc) {
DWORD dwFps;
TCHAR lpszStr[64];
if (dwMode==32) /* 選択されているDIBを描画 */
SetDIBitsToDevice(hdc,0,32,iWidth,iHeight,0,0,0,iHeight,lp32Pixels,lpbi32bpp,DIB_RGB_COLORS);
else if (dwMode==24)
SetDIBitsToDevice(hdc,0,32,iWidth,iHeight,0,0,0,iHeight,lp24Pixels,lpbi24bpp,DIB_RGB_COLORS);
else if (dwMode==8)
SetDIBitsToDevice(hdc,0,32,iWidth,iHeight,0,0,0,iHeight,lp8Pixels,lpbi8bpp,DIB_RGB_COLORS);
if (dwTime2!=0) { /* フレームレート描画 */
dwFps=(DWORD)(1000/dwTime2);
wsprintf(lpszStr,"%dFPS",dwFps);
SetTextColor(hdc,RGB(192,0,255));
TextOut(hdc,0,0,lpszStr,lstrlen(lpszStr));
}
}
ビットマップの大きさや色深度は、以下のようにして作成したコンボボックスで選択します。
hwBpp=CreateWindow("COMBOBOX",NULL,WS_CHILD|WS_VISIBLE|CBS_DROPDOWN,
60,4,80,90,hwnd,(HMENU)0,hInst,NULL);
SendMessage(hwBpp,CB_ADDSTRING,-1,(LPARAM)"32bpp");
SendMessage(hwBpp,CB_ADDSTRING,-1,(LPARAM)"24bpp");
SendMessage(hwBpp,CB_ADDSTRING,-1,(LPARAM)" 8bpp");
SendMessage(hwBpp,CB_SETCURSEL,0,1);
hwSize=CreateWindow("COMBOBOX",NULL,WS_CHILD|WS_VISIBLE|CBS_DROPDOWN,
148,4,100,90,hwnd,(HMENU)1,hInst,NULL);
SendMessage(hwSize,CB_ADDSTRING,-1,(LPARAM)"256*256");
SendMessage(hwSize,CB_ADDSTRING,-1,(LPARAM)"512*512");
SendMessage(hwSize,CB_ADDSTRING,-1,(LPARAM)"768*768");
SendMessage(hwSize,CB_SETCURSEL,1,2);
プログラムプログラムを実行したら、コンボボックスでDIBの大きさ・色深度を変えて各条件でフレームレートがどうなるか、確かめてみてください。私の環境では、
という感じでした。興味深いことに、BGM奏者でWMAファイルを再生しながら実験する(この時のフレームレートはカッコ内)と、256*256ピクセルの時にフレームレートが跳ね上がる現象が見られました。MCIによるWMA再生時に、マルチメディアタイマ関連の処理が走ってその影響(timeGetTime()の精度向上?)が出ているのかもしれません。また、セカンドマシンでも試してみましたが、いずれも色深度による差はそれほどなく、特にセカンドマシンでは32ビットの方が高速になる傾向が見られました。なお、測定環境は以下のとおりです。
8ビットの方が転送量が少なく高速になるかも、と思ったのですが、環境によってはそうでもないみたいですね。また、ほとんどの環境でこの程度の性能であれば実用上はあまり速度を意識する必要はないのですが、DIBの描画速度は環境によって大きく変わってくるはずです。しかもいろいろな所で話を聞くと、どうもG200/G400の描画速度は例外的に速いのではないか、という気もしてきます。 |