日別アーカイブ: 2009年1月5日

HTC Touch Diamond で Direct3DMobile を使う。ハードウエアアクセラレータ

やっと HTC Touch Diamond で Direct3DMobile が動くようになりました。
ハードウエアアクセラレータがきいていて、一応 VGA のフルスクリーンで
28~29fps くらい出ています。
かなり苦労しました。

Direct3D Mobile

caps を見ると Touch Pro なども同じかもしれません。

●苦労話

とにかく Touch Diamond では Direct3DM が全く動かなくて驚きました。
昔作ったプログラムも全滅で、WindowsMobile6 SDK のサンプルもだめ。
プログラムは動作するものの全く描画されないという症状。

caps はそれらしい値が取れていて、しかもハードウエアアクセラレータが有効との
魅力的な値を返してきます。
実際に d3dm_ati.dll が読み込まれているところまでは確認できます。

それでも画面は変わらず Clear() で埋めたカラーすら画面には現れてこないという。
D3DMPRESENT_PARAMETERS の組み合わせをいくら変えてもだめ。
画面の回転方向を変えてもだめ。

API 呼び出しは矛盾する設定をするとエラーになるので、一応動作しているようにも
見えます。

ちなみに d3dmref.dll も無いのでリファレンスラスタライザも使えません。
何とか d3dm_ati.dll が動く条件を見つけるしかなさそうです。

とりあえず Present() が悪いのかレンダリングそのものが走っていないのかだけ確認
してみます。

BeginScene();
Clear();
EndScene();
Present();

GetBackBuffer();
CopyRect(); // BackBuffer → ImageSurface
ImageSurface->LockRect()
// 読み出し
ImageSurface->UnlockRect()

こんな感じで BackBuffer の値を読み出してみると、一応カラーが書き込まれている
ことがわかりました。
Present() が失敗してるだけでレンダリングそのものは動いています。
でも Present() はエラーを返さず、Device も Lost していません。

BackBuffer には書き込まれていることがわかったので、Lock して読み出して
自分で Window に描画すれば (力業だけど) 描画できるのではないかと思いつきました。

フレームバッファの値を直接読み出して CPU で DIB に変換。CompatibleBitmap に
描画してからウィンドウにコピー。
最終的には R5G6B5 サーフェースの値がそのまま DIB として利用できることが
わかったので、転送や変換を減らして下記の通りです。

  ~
iDevice->Present( NULL, NULL, NULL, NULL );

IDirect3DMobileSurface*	iBack= NULL;
iDevice->GetBackBuffer( 0, &iBack );
iDevice->CopyRects( iBack, NULL, 0, iSurface, NULL );
iBack->Release();

D3DMLOCKED_RECT	lock;
iSurface->LockRect( &lock, NULL, D3DMLOCK_READONLY );
SetDIBitsToDevice( hDC, 0, 0, Width, Height, 0, 0, 0, Height,
		lock.pBits, &BitmapHead, DIB_RGB_COLORS );
iSurface->UnlockRect();

一応これで VGA (640×480) フルスクリーンでの Direct3DM の描画に成功しました。
でもかなり遅いです。上の最適化した状態で目測 5fps 程度。

この方法は FullScreen でも Windowed どちらでも動作しますが、最終的には
Bitmap 化するためウィンドウの中に描画しています。
転送を減らすため、試しに QVGA 240×320 くらいにフレームバッファを縮小してみます。

FullScreen の場合デバイスの解像度と一致していないとハングアップするので
Windowed = TRUE に。QVGA だとこの方法でも 15fps くらいになりました。

ふとこの状態で Lock & Copy をやめてみると、DIB を通さなくてもちゃんと
描画されていて、しかも 30fps 近く出ていることを発見!
ハードウエアアクセラレータ効いています。

その後いろいろためした結果、なんと「640×480 のレンダリングだけ」失敗することが
わかりました。
例えば 1pixel 減らして 480 x 639 や 478×640 にすると描画できます。

FullScreen (Windowed = FALSE) の場合デバイスの解像度と一致していないと
エラーで落ちるので、WindowMode (Windowed = TRUE) が必須となります。

●結論

・解像度を 480×640 より小さくする (480×639 or 479×640 など)
・小さくするために必ず WindowMode にする

の条件さえ満たせば Touch Diamond でも Direct3D でポリゴン描画できます。

SDK のサンプルなど、多くのプログラムは GetSystemMetrics( SM_CXSCREEN )、
GetSystemMetrics( SM_CYSCREEN ) を使ってデバイスの解像度でレンダリング
しようとしています。これが原因でした。

わかってしまえば簡単なんだけど、、、途中何度挫折しかけたことか。
リファレンスラスタライザが使えていたらすぐあきらめていたかも。