Direct3D Matrix の並びと SSE 命令

Matrix の並びには row major と column major の2種類あります。
たまにどっちがどっちかわからなくなりますが、row major が「三」で
column major が「川」。
演算上はどちらも違いは無くデータ配列が異なっているだけです。
特にシェーダーのコード上は大差ないです。演算もデータ構造も使う側に委ねられて
いてどちらでも使えます。

シェーダーコンパイラ fxc は /Zpr, /Zpc のオプションで並びの方向を指定する
ことが出来ます。
このオプションによって、たとえば vector * matrix の乗算が dp (dot product)
に展開されるか mad に展開されるか切り替わります。
どっちの設定だろうが乗算の前後を入れ替えれば良いだけなので、正直自分の記述と
デフォルトが異なっている場合にオプションで入れ替えればよい、とそのくらいの
認識でした。

fxc のデフォルトは /Zpc で column-major になっています。
上の演算であれば mad に展開されます。

シェーダーの場合 dp, mad どちらでも基本的に演算命令数は変わらず、効率の差は
生じません。ただ mad の方が vector の w=1 の代入が簡略化されるケースがある
ため小さくなることがあります。
これがそのまま GPU ネイティブコード上でも影響があるかどうかはまた別です。
AMD stream のように swizzle 時に直接 w に 1 を書き込めるなら差は無くなると
思います。

; opos= mul( mat, float4(v.xyz,1) );

; /Zpr
mov r0.xyz, cb0[4].xyzx
mov r0.w, l(1.000000)
dp4 o0.x, cb0[0].xyzw, r0.xyzw
dp4 o0.y, cb0[1].xyzw, r0.xyzw
dp4 o0.z, cb0[2].xyzw, r0.xyzw
dp4 o0.w, cb0[3].xyzw, r0.xyzw

; /Zpc
mul r0.xyzw, cb0[1].xyzw, cb0[4].yyyy
mad r0.xyzw, cb0[0].xyzw, cb0[4].xxxx, r0.xyzw
mad r0.xyzw, cb0[2].xyzw, cb0[4].zzzz, r0.xyzw
add o0.xyzw, r0.xyzw, cb0[3].xyzw

Direct3D ではもともと column major の形式で D3DMATIRX が定義されていました。
D3D9 以前、固定機能パイプラインでは API に渡すデータ並びを共通化する必要が
あったためと思われます。
そのため自前のライブラリでもほぼ D3DMATRIX 互換で使っていました。

typedef struct _D3DMATRIX {
    union {
        struct {
            float   _11, _12, _13, _14;
            float   _21, _22, _23, _24;
            float   _31, _32, _33, _34;
            float   _41, _42, _43, _44;

        };
        float m[4][4];
    };
} D3DMATRIX;

ただし実際はターゲットハードウエアやライブラリの仕様に合わせたり、最適化の
ために row major 形式に変換することが多かった思います。
シェーダーの演算上は大差なくても contant buffer の利用効率に影響があるからです。
昔は Constant Buffer が非常に小さかったため、index で参照する matrix は
4×3 でないとほとんど入りませんでした。
そのため Bone として使う geometry 用の matrix 乗算ルーチンをライブラリに
加えています。これは乗算結果を転置の 4×3 で返す専用命令です。

そろそろ D3DMATRIX 互換性もいらないかなと思い、最初から全部 row major で
持つようにライブラリを書き換えてみました。

基本的には自前の Matrix を下記のように定義し直すだけで、メンバにアクセスして
いるコードはほぼそのまま動きます。

struct {
    float  _11, _21, _31, _41;
    float  _12, _22, _32, _42;
    float  _13, _23, _33, _43;
    float  _14, _24, _34, _44;
};

修正が必要なのは、部分的に vector みなしてアクセスしていた処理と、SSE 命令で
記述していた各種関数です。
4×4 の matrix 同士の乗算では修正は不要ですが、それ以外はいろいろ見直す必要が
ありそうです。
たとえば vector との乗算だと、mad ではなく dp 相当の水平演算になります。

SSE4.1 の dpps を使ってみました。SSE4 のヘッダは smmintrin.h。
実命令数がわかるように dest 側のレジスタを共通にしています。

// SSE4.1
__m128 xmm0;
xmm0= _mm_load_ps( &v.x );

xmm1= _mm_load_ps( &_11 );
xmm1= _mm_dp_ps( xmm1, xmm0, 0xf1 );

xmm2= _mm_load_ps( &_12 );
xmm2= _mm_dp_ps( xmm2, xmm0, 0xf2 );
xmm1= _mm_add_ps( xmm1, xmm2 );

xmm2= _mm_load_ps( &_13 );
xmm2= _mm_dp_ps( xmm2, xmm0, 0xf4 );
xmm1= _mm_add_ps( xmm1, xmm2 );

xmm2= _mm_load_ps( &_14 );
xmm2= _mm_dp_ps( xmm2, xmm0, 0xf8 );
xmm1= _mm_add_ps( xmm1, xmm2 );

Shader のように簡単に記述できますが SSE4.1 対応 CPU (Penryn 以降) でないと
動きません。
試しに SSE3 の haddps を使ってみました。

// SSE3
xmm0= _mm_load_ps( &v.x );

xmm1= _mm_load_ps( &_11 );
xmm1= _mm_mul_ps( xmm1, xmm0 );

xmm2= _mm_load_ps( &_12 );
xmm2= _mm_mul_ps( xmm2, xmm0 );

xmm1= _mm_hadd_ps( xmm1, xmm2 );

xmm3= _mm_load_ps( &_13 );
xmm3= _mm_mul_ps( xmm3, xmm0 );

xmm2= _mm_load_ps( &_14 );
xmm2= _mm_mul_ps( xmm2, xmm0 );

xmm3= _mm_hadd_ps( xmm3, xmm2 );
xmm1= _mm_hadd_ps( xmm1, xmm3 );

全く同じ命令数でした。
SSE3 対応 PC の方が多いしこっちの方が良さそうです。
SSE4 命令は命令長が長いので生成バイナリも小さくなります。
ただもっと複雑なケースだと、入力を自由に選択できたり出力マスク可能な dpps
の方が融通が利いて少ない命令で書けるようです。
以前はこんな感じ。

// SSE1 (column major)
xmm0= _mm_load_ps( &v.x );

xmm1= xmm0;
xmm1= _mm_shuffle_ps( xmm1, xmm1, _MM_SHUFFLE(0,0,0,0) );
xmm2= _mm_load_ps( &_11 );
xmm1= _mm_mul_ps( xmm1, xmm2 );

xmm3= xmm0;
xmm3= _mm_shuffle_ps( xmm3, xmm3, _MM_SHUFFLE(1,1,1,1) );
xmm2= _mm_load_ps( &_21 );
xmm3= _mm_mul_ps( xmm3, xmm2 );
xmm1= _mm_add_ps( xmm1, xmm3 );

xmm3= xmm0;
xmm3= _mm_shuffle_ps( xmm3, xmm3, _MM_SHUFFLE(2,2,2,2) );
xmm2= _mm_load_ps( &_31 );
xmm3= _mm_mul_ps( xmm3, xmm2 );
xmm1= _mm_add_ps( xmm1, xmm3 );

xmm0= _mm_shuffle_ps( xmm0, xmm0, _MM_SHUFFLE(3,3,3,3) );
xmm2= _mm_load_ps( &_41 );
xmm0= _mm_mul_ps( xmm0, xmm2 );
xmm1= _mm_add_ps( xmm1, xmm0 );

matrix 同士の乗算も水平演算命令で書けるかと思い少々考えてみましたがレジスタ
が足りなくてうまくいっていません。
x64 だとレジスタ数が倍あるため intrinsic で書いたとおりのコードに展開されます。
x86 では待避のためのスタックが使われていました。

関連エントリ
Intel AVX その3 命令
D3D10 row_major column_major
SSE についてのメモ(2) SSE4など

WiMAX ルータ URoad-5000 (3) 三日目

今日は不調でした。

●繊細な WiMAX

接続が切れる場所は結構あります。
移動中安定して使えないのは、ハンドオーバーが出来ないからではなく
圏外になる区間がまだあちこちあるからです。
エリア以外でも、たとえば停車中でも併走する路線に電車が横付けされると
その間通信が止まったりすることがあります。
同じ電車でも車両や場所、混み具合、上り下りの違いでも影響があるようです。

ただ一時的に通信が止まっても、圏内になって電波をつかめばまた通信は始まります。
スムーズに復帰さえできれば十分で、全く使えないってことはなく使えます。
というのも、つながる場所も切れる場所も毎日通っているとほぼ把握できるから。
つながればそれなりに速いので、いつ更新しておけばいいのかタイミングがわかります。

●問題再発

URoad-5000 の問題は WiMAX とはまた別のところにあるようです。
何らかのタイミングでアダプタが反応しなくなることがあります。

・UD01SS の LED が点灯したまま
・URoad-5000 の WiMAX 電波受信 LED は直前の状態で固定 (変化しなくなる)

一時的に通信が途切れて停止し、その後復帰のための初期化待ちで失敗している
ように見えます。
無線 LAN は生きており、WiMAX のアンテナランプも点灯したままなので一見
きちんとつながっているように見えます。でも通信しても反応はなし。
新宿駅でホームに別の電車が入ってきたときに通信が止まり、その後目的地に
着くまで復活しませんでした。

一度 UD01SS を抜いて差し直したのち、しばらく待つと復活しました。
UD01SS を差し直した直後、しばらく UD01SS の LED が点灯したままになる点に
注意です。またハングアップ状態かと思いがちですが根気よく待ちます。

初日にほとんど使えなかったのも、これが原因だったと思われます。
VAIO type P で UD01SS を使用していたときはこのような症状は出ていませんでした。

●LED の読み方

URoad-5000 の本体 LED と、UD01SS の LED 両方から状態を判断する必要があります。

WiMAX アダプタ UD01SS 本体の青色 LED

(1) URoad-5000 の電源が入っていない状態 – 消灯
(2) URoad-5000 の電源を入れてもまだ初期化されていない状態 – 消灯
(3) URoad-5000 の無線も起動し、WiMAX の初期化が始まった状態 – 常時点灯
(4) 初期化が終わり、WiMAX を検索している状態 – 消灯
(5) WiMAX に接続できた場合 – 通信があると点滅、無ければ消灯

初期化中 (4) のようにしばらく常時点灯する期間があります。
URoad-5000 本体の WiMAX 電波ランプは、電波をつかむ (5) の段階になるまで消灯
したままです。

現時点でわかってる状態をまとめてみます。

                UD01SS LED        本体WiMAX LED
---------------------------------------------------------------------
本体電源off        消灯             消灯
本体電源on         消灯             一瞬点灯
本体初期化中       消灯             点灯
無線LAN起動後      消灯             消灯
WiMAX初期化中      常時点灯         消灯
WiMAX検索中        消灯             消灯
WiMAX接続後     通信に応じて点滅  電波強度=色,通信=点滅(圏外=消灯)
圏外から脱出等     常時点灯         消灯
ハングアップ時     常時点灯         直前の状態で固定

これらの挙動はファームアップなどで変わる可能性があります。

ハングアップかどうかの判断は、UD01SS の LED が点灯したままで長時間通信
できない状態が続いた場合です。通常はしばらくたつと LED が消えます。
このとき高い確率で本体の WiMAX LED が点灯しており、色が変化しません。

やはり瞬間的な電波の遮断で UD01SS の初期化がかかったものの、その状態を
URoad-5000 側が正しく認識していないのが原因だと思われます。

移動時以外は長時間稼働しても特に問題は出ていません。
一カ所にとどまった状態だと安定して利用できています。

●まとめ

状況の把握が出来れば対策可能なので、移動中でも十分使えると思います。
小さくて軽量な本体もバッテリー駆動出来る点も良いです。
ただ鞄に入れたまま手放しで待機しておくには、まだ不安かもしれません。
もし本体の方に何らかの問題があるならファームウエアの更新で改善できるでしょうか。

関連エントリ
WiMAX ルータ URoad-5000 (2) 二日目
WiMAX ルータ URoad-5000
Windows7 beta で UQ WiMAX

WiMAX ルータ URoad-5000 (2) 二日目

今日は非常に好調でした。
昨日の不安定さとは大違いで、電車の車内でもきちんとつながるし使えています。
WiMAX の電波状況は右端の LED。消灯→赤→橙→緑 と変化します。
この変化や強さが、普段 VAIO type P + UD01SS で使っていたときとの記憶と
完全に一致。
切れる場所、つながって使える場所も同じで、切れたあとの再接続も問題なく
普通にブラウズできました。
試した場所は新宿近辺から中央総武各駅停車。

つながらない区間はところどころありますが、全く使えないほどではありません。
先日の報告は訂正させていただきます。申し訳ありません。
移動時につながらなくなった症状の条件はまだ絞り込めていないので、もう少し
使ってからレポートしたいと思います。

uroad5000

電波状況や通信時の点滅を凝視しながらだったので、こんな感じ(↑)の手持ちで
使用していました。
一体型ケースがあってもいい良いんじゃないかと思うくらい軽くて薄い本体です。
ポケットに余裕で入ります。iPhone 3GS と両方合わせて 260g くらい。

充電の仕方はまだよくわかっていません。
AC アダプタをつなぐと電源が入ってしまい、いちいち電源を切らないと通信待機
状態のままになります。無線 LAN も見えます。
また充電中のバッテリーマークはずっと緑色で一晩充電しても変化はなし。
充電完了かどうか区別できないようです。
何時間充電すればよいかも記載されていないので、この辺もあとで問い合わせてみます。

バッテリーマークも電波感度マークも一般的なアイコン形状(↓)だけど
バーの本数は変わりません。色が変わるだけ。

uroad5000

ドラクエの Wi-Fi ショッピングも、PSP まいにちいっしょポータブルのデータ更新も
どこでも出来るようになりました。
時間がかかる更新処理は移動中ではなく電波の安定したところでやった方が良いです。
やはりつながるとそこそこ速くて快適です。
Eye-Fi を試すのを忘れました。バッテリーの持ちなどもまた後日。

いらないケース
・ノート PC で使う場合は直接 USB アダプタを差した方が使いやすいし高速

必要なケース
・ノート PC が 64bit OS の場合
・iPod touch, PSP, DS 等、PC 無しでモバイル通信したい場合

※次回に続く(2009/08/06)

関連エントリ
Windows7 beta で UQ WiMAX
WiMAX ルータ URoad-5000

WiMAX ルータ URoad-5000

シンセイコーポレーションのモバイルルータ URoad-5000 購入しました。

URoad-5000

WiMAX の回線をどこでも使えるようにするための無線LAN ルーターです。
同じシンセイコーポレーション製の USB WiMAX アダプタを使うことが出来ます。
ちょうど UQ WiMAX 用のUD01SS を持っていたので、ビックカメラで URoad-5000
のみ購入してきました。

●使えるアダプタ

URoad-5000 は USB タイプの WiMAX アダプタに対応したモバイルルーターなので
単体では何も出来ません。添付の「かんたん説明マニュアル」を見ると使える
アダプタは MW-U2510 だけだそうです。

web サイトの FAQ (よくある質問) を読むと UD01SS, UD03SS, BDSS01,
MW-U2510/DM が使えるとのこと。これら全部 MW-U2510 と同じものだそうです。
実際 UD01SS の USB コネクタの裏側には「モデル名 MW-U2510」と小さい字で
書かれています。

●使い道

今のところ iPhone 等の携帯端末から WiMAX 回線を使うには PC か WiMAX 対応
ルーターが必要になります。ルーターの場合アドホックに対応していない
DS や PSP でも使用できます。
箱にも PSP, NINTENDO DS, iPod touch 対応と書かれていました。

また WiMAX の USB アダプタには 64bit OS 向けドライバがまだありません。
ルータ経由なら Windows7 x64 からも WiMAX つなげられるようになるはずです。

●説明書がない

最初に少々戸惑ったのは本体の取扱説明書がないことです。
無線LAN 設定方法までの手順が書かれた「かんたん設定マニュアル」は入って
いましたが、他に説明書も CD-ROM 等もありません。
バッテリーの入れ方や充電方法(ACアダプタをつなぐと電源が入ってしまう)など、
難しくはないけど、しばらく使ってみないとわからないことがあります。
購入時に店員が念入りに付属品の確認をしていたのはこのためかもしれません。
説明書がない等の問い合わせがあるのではないでしょうか。

製品情報ページには FAQ の pdf が掲載されており、補足の説明はこちらを見る
ことになるようです。

●大きさ

本体はバッテリー内蔵ながら非常に小さく手に持った感じも軽量です。
カタログ値でバッテリー込み 110g。
実測でバッテリーパックが 49g、本体が 57g の合計 106g でした。
重量の半分近くがバッテリーです。
UD01SS は実測 19g だったのであわせて 125g くらい。

uroad5000
↑左端が UD01SS、真ん中が URoad-5000

大きさも iPhone くらいのサイズで予想よりも薄型でした。
WindowsMobile のスマートフォンをもう1つ持ち歩くくらいの感覚です。

ただ USB アダプタ UD01SS を接続すると持ち歩きに不安な形ででっぱります。
ノート PC に直接差した場合と可搬性はあまり変わらないかもしれません。

uroad5000
uroad5000

●利用は簡単

USB WiMAX アダプタ UD01SS は、もともと UQ から購入したもので PC につないで
使用していました。そのまま URoad-5000 に差し込むだけで使えるようです。

サイドの小さいボタンを長押しして電源を入れると、しばらくして接続ランプが
点灯します。

最初から WEP と WPA-PSK(TKIP) 対応の 2種類の SSID が登録されていました。
キーはどちらも同じで本体裏に貼ってあるシールに書かれています。
SSID, KEY, PIN と 3つ番号があるけど使うのは「KEY:~」の方です。

WEP しか使えない DS は URoad-****** の方につなぎます。それ以外は
URoadWPS-****** を使えば大丈夫なはずです。(もしだめなら URoad- の方へ)
つながったら「かんたん設定マニュアル」に従って、ブラウザからセキュリティ
等の設定変更ができるようになります。

●電源投入

まだほとんど使っていないので実際のバッテリー寿命などはまだわかりません。
スペック上は連続使用 3時間だそうです。
AC アダプタのコネクタはサイズは細くて特殊な形状でしたが、アダプタ本体も
割と小さい方でしょう。AC アダプタの電圧は 5V。
バッテリーの電源容量は 3.7V 2200mAh でした。

電源を入れてから WiMAX が利用可能になるまで少々時間がかかります。

(1) Wireless LAN のランプが点灯するまで 25秒
(2) USBアダプタ(UD01SS) の LED がつくまで 40秒
(3) WiMAX の電波状況ランプが点灯して使えるようになるまで 60~70秒

電源を入れてから 1分少々。特に UD01SS が電波をつかんで安定するまで意外に
時間がかかるようです。たまに初期化に失敗するのか UD01SS の再初期化が
何度か行われるようで、その場合は 2分近くかかることもありました。

つながらないときは何度も電源入れ直したりアダプタを抜き差しして
しまいましたが、しばらく待つのが正解のようです。
ちなみに電源入れたあとに UD01SS を差し込んでも大丈夫でした。

●速度

VAIO type P に UD01SS 直差しで 3Mbps 出る場所でテストしました。
URoad-5000 経由では 2Mbps。思ったよりも速度が落ちています。

周囲に無線 LAN 機器が多数あるので、無線 LAN 側が混信している可能性もあります。
チャンネルを手動で変更すると多少上がって 2.3Mbps 程に。
でも主に移動時に使うので自動選択に戻しました。

URoad-5000 は 11b/g/n に対応しています。
VAIO type P (Windows7 RC) のダイアログでは 300Mbps と表示されており、
11n で接続されていたようです。

●接続

とりあえず VAIO type P 、DS lite 、iPhone でつないでみました。
それなりに快適で、これなら iPod touch のままでも良かったんじゃないかと
一瞬思いました。

電源を入れてから鞄にいれて都内の電車内で使ってみました。結果はほぼ全滅です。
駅で停車中たまにつながりますが駅間では切れます。
圏外からの再接続が間に合わないらしく、停車中圏内になってもほとんど安定して
使える状態にはなりませんでした。

また VAIO type P に直差しした場合よりも感度が落ちるのか、以前ノート PC で
ぎりぎり使えていた場所でもなかなか安定しません。
とりあえず通勤時は使えないことが判明。
iPod touch + UQ で十分かも、と思ったのは間違いでした。

●まとめ

優先 LAN 端子はなく無線 LAN のみです。
WiMAX 以外使えない専用機なので WiMAX をしっかり使おう、という人向けです。
小型軽量でバッテリー駆動できるのはメリットですが、移動中は安定しません
外出時どこかに腰を据えて使うことになります。

PC に直接アダプタをさして使うよりも速度は少々落ちます。
通信速度も、圏外からの立ち上がりも若干時間がかかるようになった印象です。
ルーターのオーバーヘッドなのか電波の入りが悪くなるのが原因なのかはわかりません。

利点は PC なしで WiMAX の回線が使えることです。
iPod touch や iPhone で高速なネット接続出来ますし、外出時に DS や PSP を
ネットにつなぐこともできるでしょう。

自分の用途だと使える場所が限られてしまうので、まだ活躍できるかわかりませんが
これからいろいろ使ってみます。

※ 次回に続く (2009/08/05)

関連エントリ
Windows7 beta で UQ WiMAX

Windows7 Multitouch API (3)

こちらで触れたように Multitouch 周りは Windows7 ベータの時と仕様が若干
変わっています。なかなか試せず時間がたってしまいました。
ベータの WM_TOUCH

Multitouch API には 2系統あります。WM_TOUCH と WM_GESTURE です。
WM_TOUCH は複数の点の座標をそのまま送ってくるメッセージ、WM_GESTURE は
ある程度の動作を判断したあとに送られてきます。
両者は共存できないので、あらかじめどちらを使うか切り替えておくことになります。

ベータの時は WM_TOUCHDOWN, WM_TOUCHUP, WM_TOUCHMOVE と 3種類
メッセージがありました。RC 以降は WM_TOUCH 一つにまとめられています。
WM_TOUCH 系は複数のタッチ点の座標を一度に送信してくるため、それぞれ個別に
DOWN/UP する可能性があります。受け取った構造体の TOUCHINPUT には個別に
UP/DOWN/MOVE フラグが立っているので情報としては十分です。
複数の点をまとめて WM_TOUCHDOWN/TOUCHUP/TOUCHMOVE とひとくくりに
なっていたのは GESTURE のような操作を想定していたからかもしれません。

少々不思議なのは個別の UP/DOWN/MOVE は本当に区別できるのかということ。
座標はその瞬間サンプリングされたタッチ点なので厳密には個々のポイントを区別
することができず、連続性を持った値になるとは限りません。
例えば移動中のマルチタッチ点が増えたとして、どの点が新規にタッチされたものか
区別しなければならないということです。
サンプリングレートが十分速くて移動が限られている UI 操作ならそれほど問題
ないのかもしれません。
WM_TOUCH のイベントでは Windows 側で同一点の処理が行われており、
TOUCHINPUT の dwID に識別番号が入っています。
dwID が同じものを見ていくと DOWN ~ MOVE ~ UP の流れを見ることが
できるわけです。

lparam がハンドルなので、GetTouchInputInfo() で詳細を受け取ります。
これもベータ時の HANDLE から HTOUCHINPUT に変更されているようです。

void WM_Touch( UINT mes, WPARAM wparam, LPARAM lparam )
{
    int inputs= LOWORD( wparam );
    TOUCHINPUT  tbuf[ 32 ]; // inputs
    HTOUCHINPUT	hinput= reinterpret_cast( lparam );
    if( GetTouchInputInfo( hinput, inputs, tbuf, sizeof(TOUCHINPUT) ) ){
        TOUCHINPUT*  tp= tbuf;
        for( int i= 0 ; i< inputs && i < 32 ; i++, tp++ ){
            ~
	    tp->dwID // 識別
	    tp->x, tp->y // 座標
	    tp->dwFlags // UP/DOWN/MOVE
	}
    }
    CloseTouchInputHandle( hinput );
}

実際の 2点タッチだとこんな感じです。

0:(34054,41033) ID=3 flag=3a mask=4 ex=0 cx=4881 cy=5874 DOWN INRANGE PRIMARY NOCOALESCE 

0:(34054,41033) ID=3 flag=39 mask=4 ex=0 cx=4881 cy=5874 MVOE INRANGE PRIMARY NOCOALESCE 
1:(46230,31629) ID=4 flag=2a mask=4 ex=0 cx=5162 cy=5057 DOWN INRANGE NOCOALESCE 

0:(34007,40957) ID=3 flag=19 mask=4 ex=0 cx=5179 cy=5057 MVOE INRANGE PRIMARY 
1:(46224,31614) ID=4 flag=09 mask=4 ex=0 cx=4974 cy=5874 MVOE INRANGE 

0:(33966,40880) ID=3 flag=39 mask=4 ex=0 cx=5121 cy=5061 MVOE INRANGE PRIMARY NOCOALESCE 
1:(46212,31600) ID=4 flag=29 mask=4 ex=0 cx=4951 cy=5877 MVOE INRANGE NOCOALESCE 

0:(33796,40627) ID=3 flag=39 mask=4 ex=0 cx=5121 cy=5061 MVOE INRANGE PRIMARY NOCOALESCE 
1:(46330,31582) ID=4 flag=29 mask=4 ex=0 cx=4951 cy=5877 MVOE INRANGE NOCOALESCE 

0:(33632,40378) ID=3 flag=39 mask=4 ex=0 cx=4916 cy=5068 MVOE INRANGE PRIMARY NOCOALESCE 
1:(46447,31563) ID=4 flag=29 mask=4 ex=0 cx=4904 cy=5870 MVOE INRANGE NOCOALESCE 

0:(33082,39298) ID=3 flag=39 mask=4 ex=0 cx=4916 cy=5068 MVOE INRANGE PRIMARY NOCOALESCE 
1:(46757,31680) ID=4 flag=29 mask=4 ex=0 cx=4904 cy=5870 MVOE INRANGE NOCOALESCE 

0:(32531,38217) ID=3 flag=19 mask=4 ex=0 cx=3779 cy=5108 MVOE INRANGE PRIMARY 
1:(47074,31801) ID=4 flag=09 mask=4 ex=0 cx=4464 cy=5870 MVOE INRANGE 

0:(32531,38217) ID=3 flag=34 mask=4 ex=0 cx=3779 cy=5108 UP PRIMARY NOCOALESCE 
1:(47074,31801) ID=4 flag=29 mask=4 ex=0 cx=4464 cy=5870 MVOE INRANGE NOCOALESCE 

0:(47074,31801) ID=4 flag=24 mask=4 ex=0 cx=4464 cy=5870 UP NOCOALESCE 

座標値をピクセルに変換するには TOUCH_COORD_TO_PIXEL()。

HP TouchSmart IQ800 を使っていますが、たまに multi touch が無効になっている
ことがあります。何らかの更新のタイミングで、別のドライバに上書きされて
しまっているようです。ドライバを入れ直すと再び使えるようになります。

nextwindow Windows 7 Touch Screen Driver

関連エントリ
Windows SDK for Windows7 RC と Multitouch / Direct3D 11
Windows7 Multitouch API その(2) WM_GESTURE 系
Windows7 Multitouch API