2009/09/30
NetWalker PC-Z1 Cortex-A8 (ARM) 浮動小数演算の実行速度
先日のテストでは Atom に匹敵する実行速度を出していながら、浮動小数演算では
大きく差をつけられる結果となりました。
もう少し詳しく調べたところ、いろいろわかってきました。
結論は
・VFP が遅い
・NEON の SIMD 2/4 を使えばかなり速い
・NEON の単精度スカラー同士の演算は VFP なので遅い
今回は直接命令毎の実行速度を測ってみます。例えば整数乗算なら下記のような感じで。
省略していますが実際には mul 命令を 40 個並べています。
これを 100M 回 (1億) ループします。
各種演算命令を並べてテストした結果が下記の通りです。
4000M 命令の実行時間の実測値 (秒) です。
命令はパイプラインがストールしないよう、意味がないけど依存が発生しない組み合わせで
並べています。
整数演算は mul でおよそ 392M命令/sec です。add の場合は 775M 命令なので、
ほぼ 1命令/cycle に近い数値で実行出来ていることがわかります。
問題の VFP による浮動小数演算は乗算で 5倍、add 比で 9倍も遅くなっています。
倍精度の乗算でも 10% ほどしか増えていないので、オーバーヘッドは別のところに
あるのかもしれません。
丸めモードや Flush-to-Zero モードなど、FPSCR も書き換えてみましたが結果は同じでした。
なお乗算する値が 0 の場合のみ、fmuls は 3割ほど速い速度で完了します。
対照的に NEON がかなり高速です。4要素(128bit) の SIMD 演算であるにもかかわらず
整数演算と同速度で実行しており、2要素(64bit) の SIMD の場合はむしろ整数演算よりも
高速です。ほぼ 1cycle 毎に 2 float の演算をしています。
さらに積和演算が可能なので、SIMD で vmla を用いた場合
40命令 × 100Mループ × 4 (SIMD) × 2 (積和) / 10sec = およそ 3.2G FLOPS
となります。
ではなぜ普通にコンパイルしたプログラムの浮動小数演算が遅いのかと言えば、NEON の
スカラー演算命令は VFP と共有されているからです。
sレジスタ を用いた演算は、NEON ではなく VFP で実行されます。
実際に vmul.f32 s,s,s は fmuls s,s,s と全く同じバイトコードでした。
コンパイラは一般の浮動小数演算では VFP 命令を出力しています。
結局最初に書いたとおり VFP が非常に遅いという結論になります。
そのためスカラー演算であっても 2/4 ベクタとみなして NEON 命令を使った方が
高速になるわけです。
例えば fmuls s,s,s → vmul.f32 d,d,d なら 10 倍です。
実際のアプリケーションで使ったわけではありませんが、周辺を考えなければ Atom 比でも
結構良い結果になるのではないでしょうか。
これが iPod touch 3G/iPhone 3GS の大きさにも収まっていると考えればなおさらです。
vmla は破壊代入するため、他の命令のように同じオペランドのまま並べると依存が発生して
ストールします。5倍ほど遅くなるので、このテストでは代入側レジスタを 5個用いて
インターリーブしています。quad 時スループット 2 のレイテンシ 10 くらいでしょうか。
関連エントリ
・NetWalker PC-Z1 Atom と速度比較
・NetWalker PC-Z1 Bluetooth とキーカスタムその他
・NetWalker PC-Z1 意外にいける
・Netwalker PC-Z1 買いました
・タッチタイプの境界
・NetWalker PC-Z1
大きく差をつけられる結果となりました。
もう少し詳しく調べたところ、いろいろわかってきました。
結論は
・VFP が遅い
・NEON の SIMD 2/4 を使えばかなり速い
・NEON の単精度スカラー同士の演算は VFP なので遅い
今回は直接命令毎の実行速度を測ってみます。例えば整数乗算なら下記のような感じで。
省略していますが実際には mul 命令を 40 個並べています。
これを 100M 回 (1億) ループします。
static void Start_ASMINT_MUL() { TimerClass timer; timer.Begin(); __asm__ __volatile__( "\ mov r2, #123 \n\ " : : : "r2","cc" ); for( int i= 0 ; i< VECTOR_LOOP ; i++ ){ __asm__ __volatile__( "\ mul r3, r2, r2 \n\ mul r3, r2, r2 \n\ ~ " : : : "r3","cc" ); } timer.End( "ASMINT_MUL" ); }
各種演算命令を並べてテストした結果が下記の通りです。
4000M 命令の実行時間の実測値 (秒) です。
i.MX515 Cortex-A8 (ARM) 800MHz 命令 実行時間 演算ユニットと演算単位 --------------------------------------------------------------- mul r,r,r 10.21 sec ALU 32bit add r,r,r 5.16 sec ALU 32bit fmuls s,s,s 50.45 sec VFP 32bit fadds s,s,s 45.45 sec VFP 32bit fmuld d,d,d 55.49 sec VFP 64bit vmul.f32 s,s,s 50.45 sec VFP 32bit vmul.f32 q,q,q 10.07 sec NEON 128bit (32bit x4) vadd.f32 q,q,q 10.08 sec NEON 128bit (32bit x4) vmla.f32 q,q,q 10.09 sec NEON 128bit (32bit x4) 積和 vmul.f32 d,d,d 5.04 sec NEON 64bit (32bit x2)
命令はパイプラインがストールしないよう、意味がないけど依存が発生しない組み合わせで
並べています。
整数演算は mul でおよそ 392M命令/sec です。add の場合は 775M 命令なので、
ほぼ 1命令/cycle に近い数値で実行出来ていることがわかります。
問題の VFP による浮動小数演算は乗算で 5倍、add 比で 9倍も遅くなっています。
倍精度の乗算でも 10% ほどしか増えていないので、オーバーヘッドは別のところに
あるのかもしれません。
丸めモードや Flush-to-Zero モードなど、FPSCR も書き換えてみましたが結果は同じでした。
なお乗算する値が 0 の場合のみ、fmuls は 3割ほど速い速度で完了します。
対照的に NEON がかなり高速です。4要素(128bit) の SIMD 演算であるにもかかわらず
整数演算と同速度で実行しており、2要素(64bit) の SIMD の場合はむしろ整数演算よりも
高速です。ほぼ 1cycle 毎に 2 float の演算をしています。
さらに積和演算が可能なので、SIMD で vmla を用いた場合
40命令 × 100Mループ × 4 (SIMD) × 2 (積和) / 10sec = およそ 3.2G FLOPS
となります。
ではなぜ普通にコンパイルしたプログラムの浮動小数演算が遅いのかと言えば、NEON の
スカラー演算命令は VFP と共有されているからです。
sレジスタ を用いた演算は、NEON ではなく VFP で実行されます。
実際に vmul.f32 s,s,s は fmuls s,s,s と全く同じバイトコードでした。
コンパイラは一般の浮動小数演算では VFP 命令を出力しています。
結局最初に書いたとおり VFP が非常に遅いという結論になります。
そのためスカラー演算であっても 2/4 ベクタとみなして NEON 命令を使った方が
高速になるわけです。
例えば fmuls s,s,s → vmul.f32 d,d,d なら 10 倍です。
実際のアプリケーションで使ったわけではありませんが、周辺を考えなければ Atom 比でも
結構良い結果になるのではないでしょうか。
これが iPod touch 3G/iPhone 3GS の大きさにも収まっていると考えればなおさらです。
vmla は破壊代入するため、他の命令のように同じオペランドのまま並べると依存が発生して
ストールします。5倍ほど遅くなるので、このテストでは代入側レジスタを 5個用いて
インターリーブしています。quad 時スループット 2 のレイテンシ 10 くらいでしょうか。
関連エントリ
・NetWalker PC-Z1 Atom と速度比較
・NetWalker PC-Z1 Bluetooth とキーカスタムその他
・NetWalker PC-Z1 意外にいける
・Netwalker PC-Z1 買いました
・タッチタイプの境界
・NetWalker PC-Z1
2009/09/29
NetWalker PC-Z1 Atom と速度比較
Atom と比べてみました。
あくまで参考程度でお願いします。
テストは基本的にただのループかつシングルスレッドのみです。
数値は Real Time なので厳密なコードのみの実行速度ではないです。
ALU 全部キャッシュに収まる整数演算とループ
FPU スカラーの浮動小数演算を含んだループ
MEM1 8bit 単位のメモリアクセス
MEM4 32bit 単位のメモリアクセス
(5)~(10) が NetWalker です。
浮動小数演算以外はほぼ Atom と近い範囲で、クロック差があるにもかかわらずかなり
善戦しています。おそらく整数演算に関してはシングルスレッドかつキャッシュに入る場合、
同クロックの Atom よりも高速です。
ただし実際の動作速度は CPU core の速度だけでなく、メモリや SSD 等他のデバイスの
影響が大きいので、これだけで判断することは出来ません。
また Atom は HT 前提のパイプライン設計なので、シングルスレッドではその性能を
出し切れていないともいえます。
同じように (1) の Core i7 も 8 スレッドのうち 1つだです。ちなみに (1) は
同時に VirtualBox の仮想 PC が動いていたりとかなりの悪条件で走らせました。
計測も Real 時間なので、バックグラウンドで動いているタスクの影響を少なからず
受けているといえます。この場合 HT を持っている Atom の方が若干有利に働くかも
しれません。
(3) は Z540 の電源設定を変更して、上限 800MHz で動かしたものです。
ALU FPU 時間はクロック数に比例して遅くなりました。MEM1/MEM4 はそれほど変化が
ないようです。この点から MEM1/4 の実行速度は CPU core の速度度よりも、メモリ
アクセス時間の割合の方が大きいと考えられます。
(2)/(3) と (4) はクロック比と速度が一致していません。これはおそらくコンパイラ
の差です。最適化の傾向が異なっており、ループ内の演算に無駄があり畳み込める
条件では gcc の方が高速でした。また VC は SSE 命令を使っており、gcc は
-msse4 をつけても FPU 命令に展開されています。
MEM1 は 1byte 単位で 32MByte を読み書きしています。
MEM4 は 4byte 単位で 64MByte アクセスしています。
よってループ回数は MEM4 が半分になります。
(4) の結果を見ると MEM4 は MEM1 のちょうど半分の時間で完了しているので、
このテストではデータサイズが速度に影響を与えていないようです。
浮動小数演算はただのスカラー演算です。遅すぎて、設定ミスとか例外が発生してるの
ではないかと疑いました。一応 vfp,neon,soft と 3通り試しています。
取りあえずエミュレーションよりは速いことがわかります。
きちんと SIMD を活用すれば、もう少しそれなりの速度が出るのかもしれません。
Thumb-2 の効果は確認できました。16/32bit 命令が混在しており、FP 命令呼び出しも
特に速度が落ちていないようです。
浮動小数演算以外は思ったよりも速いです。浮動小数演算が著しく遅いのは、
プログラムのミスなのかまだ良くわかっていません。
ARM の浮動小数演算に関しては下記ページを参考にさせていただきました。
・ひまじめ 組み込みLInux
(2009/09/30 追記) 続き>> NetWalker PC-Z1 Cortex-A8 浮動小数演算の実行速度
(2009/09/30 追記) 続き>> NetWalker PC-Z1 Cortex-A8 浮動小数演算の実行速度
関連エントリ
・NetWalker PC-Z1 Bluetooth とキーカスタムその他
・NetWalker PC-Z1 意外にいける
・Netwalker PC-Z1 買いました
・タッチタイプの境界
・NetWalker PC-Z1
あくまで参考程度でお願いします。
ALU FPU MEM1 MEM4 9.32 5.17 4.24 3.20 (1) Core i7 920 2.67GHz 29.41 29.36 43.83 27.43 (2) Atom Z540 1.86GHz 68.68 68.73 46.70 36.45 (3) Atom Z540 800MHz 42.88 44.09 39.45 20.03 (4) Atom N270 1.60GHz 37.82 209.76 56.35 30.68 (5) Cortex-A8 800MHz NEON 37.84 209.79 58.17 30.69 (6) Cortex-A8 800MHz VFP 37.83 252.80 56.34 30.75 (7) Cortex-A8 800MHz soft 42.96 211.02 55.86 30.52 (8) Cortex-A8 800MHz NEON + Thumb-2 42.85 212.18 55.87 30.53 (9) Cortex-A8 800MHz VFP + Thumb-2 42.92 267.23 55.84 30.54 (10) Cortex-A8 800MHz soft + Thumb-2 単位は秒、値が小さい方が高速
テストは基本的にただのループかつシングルスレッドのみです。
数値は Real Time なので厳密なコードのみの実行速度ではないです。
ALU 全部キャッシュに収まる整数演算とループ
FPU スカラーの浮動小数演算を含んだループ
MEM1 8bit 単位のメモリアクセス
MEM4 32bit 単位のメモリアクセス
(5)~(10) が NetWalker です。
浮動小数演算以外はほぼ Atom と近い範囲で、クロック差があるにもかかわらずかなり
善戦しています。おそらく整数演算に関してはシングルスレッドかつキャッシュに入る場合、
同クロックの Atom よりも高速です。
ただし実際の動作速度は CPU core の速度だけでなく、メモリや SSD 等他のデバイスの
影響が大きいので、これだけで判断することは出来ません。
また Atom は HT 前提のパイプライン設計なので、シングルスレッドではその性能を
出し切れていないともいえます。
同じように (1) の Core i7 も 8 スレッドのうち 1つだです。ちなみに (1) は
同時に VirtualBox の仮想 PC が動いていたりとかなりの悪条件で走らせました。
計測も Real 時間なので、バックグラウンドで動いているタスクの影響を少なからず
受けているといえます。この場合 HT を持っている Atom の方が若干有利に働くかも
しれません。
(3) は Z540 の電源設定を変更して、上限 800MHz で動かしたものです。
ALU FPU 時間はクロック数に比例して遅くなりました。MEM1/MEM4 はそれほど変化が
ないようです。この点から MEM1/4 の実行速度は CPU core の速度度よりも、メモリ
アクセス時間の割合の方が大きいと考えられます。
(2)/(3) と (4) はクロック比と速度が一致していません。これはおそらくコンパイラ
の差です。最適化の傾向が異なっており、ループ内の演算に無駄があり畳み込める
条件では gcc の方が高速でした。また VC は SSE 命令を使っており、gcc は
-msse4 をつけても FPU 命令に展開されています。
MEM1 は 1byte 単位で 32MByte を読み書きしています。
MEM4 は 4byte 単位で 64MByte アクセスしています。
よってループ回数は MEM4 が半分になります。
(4) の結果を見ると MEM4 は MEM1 のちょうど半分の時間で完了しているので、
このテストではデータサイズが速度に影響を与えていないようです。
浮動小数演算はただのスカラー演算です。遅すぎて、設定ミスとか例外が発生してるの
ではないかと疑いました。一応 vfp,neon,soft と 3通り試しています。
取りあえずエミュレーションよりは速いことがわかります。
きちんと SIMD を活用すれば、もう少しそれなりの速度が出るのかもしれません。
Thumb-2 の効果は確認できました。16/32bit 命令が混在しており、FP 命令呼び出しも
特に速度が落ちていないようです。
浮動小数演算以外は思ったよりも速いです。浮動小数演算が著しく遅いのは、
プログラムのミスなのかまだ良くわかっていません。
ARM の浮動小数演算に関しては下記ページを参考にさせていただきました。
・ひまじめ 組み込みLInux
(2009/09/30 追記) 続き>> NetWalker PC-Z1 Cortex-A8 浮動小数演算の実行速度
(1) PC Core i7 920 2.67GHz Windows7 RTM x64, VC2008 x86 -arch:SSE2 (2) VAIO type P Atom Z540 1.86GHz Windows7 RC x86, VC2008 x86 -arch:SSE2 (3) VAIO type P Atom Z540 1.86GHz (800MHz) Windows7 RC x86, VC2008 x86 -arch:SSE2 (4) EeePC 901 Atom N270 1.6GHz Ubuntu 9.04 x86, gcc-4.3.3 -mssse3 (5) NetWalker PC-Z1 i.MX515 Cortex-A8 800MHz NEON Ubuntu 9.04 armel, gcc-4.3.3 -mfloat-abi=softfp -mfpu=neon (6) NetWalker PC-Z1 i.MX515 Cortex-A8 800MHz VFP Ubuntu 9.04 armel, gcc-4.3.3 -mfloat-abi=softfp -mfpu=vfp (7) NetWalker PC-Z1 i.MX515 Cortex-A8 800MHz soft Ubuntu 9.04 armel, gcc-4.3.3 -mfloat-abi=soft (8) NetWalker PC-Z1 i.MX515 Cortex-A8 800MHz NEON + Thumb-2 Ubuntu 9.04 armel, gcc-4.3.3 -mfloat-abi=softfp -mfpu=neon -mthumb (9) NetWalker PC-Z1 i.MX515 Cortex-A8 800MHz VFP + Thumb-2 Ubuntu 9.04 armel, gcc-4.3.3 -mfloat-abi=softfp -mfpu=vfp -mthumb (10) NetWalker PC-Z1 i.MX515 Cortex-A8 800MHz soft + Thumb-2 Ubuntu 9.04 armel, gcc-4.3.3 -mfloat-abi=soft -mthumb
(2009/09/30 追記) 続き>> NetWalker PC-Z1 Cortex-A8 浮動小数演算の実行速度
関連エントリ
・NetWalker PC-Z1 Bluetooth とキーカスタムその他
・NetWalker PC-Z1 意外にいける
・Netwalker PC-Z1 買いました
・タッチタイプの境界
・NetWalker PC-Z1
2009/09/28
GeForce ドライバ 191.03 beta
GeForce のドライバ 191.03 (beta) が出ています。
やっと OpenGL 3.2 と Compute Shader 4.0 の共存が出来るようになりました。
どちらも動いています。
・GEFORCE/ION DRIVER RELEASE 191
この辺 RADEON はまだ対応していませんが、すでに DirectX11 が動く 5870 が発売されました。
ShaderModel とか Compte Shader の対応とか非常に興味あるけど
週末 RADEON HD 5870 はすでに売り切れでした。
関連エントリ
・OpenGL や GLSL の互換性
・Direct3D11/DirectX11 GeForce の ComputeShader とドライバ
やっと OpenGL 3.2 と Compute Shader 4.0 の共存が出来るようになりました。
どちらも動いています。
・GEFORCE/ION DRIVER RELEASE 191
この辺 RADEON はまだ対応していませんが、すでに DirectX11 が動く 5870 が発売されました。
ShaderModel とか Compte Shader の対応とか非常に興味あるけど
週末 RADEON HD 5870 はすでに売り切れでした。
関連エントリ
・OpenGL や GLSL の互換性
・Direct3D11/DirectX11 GeForce の ComputeShader とドライバ
2009/09/26
NetWalker PC-Z1 Bluetooth とキーカスタムその他
●Bluetooth
Bluetooth アダプタ Princeton PTM-UBT3S, PLANEX BT-Mini2EDR を使ってみました。
・システム → システム管理 → Synaptic パッケージマネージャー
・gnome-bluetooth をインストール指定 → 適用
・いったんログアウトして再ログイン
アダプタを接続すると通知スペースに Bluetooth のアイコンが表示されるので
そこからペアリング等を行います。または システム → 設定 → Bluetooth 。
ペアリングしたもの。
マウス SONY VGP-BMS33, キーボード REUDO RBK-2100BTJ
二回ほどサスペンド後にアダプタを認識してないことがありましたが、
電源入れ直し等で復活。以降は今のところ動いています。
●キーボード
購入時からキーボードの配列のカスタマイズを考えていました。
本当は uinput を使いたいのですが module uinput.ko が無かったので取りあえず
xmodmap を使います。
$ xmodmap -pke > $HOME/.Xmodmap
以降 .Xmodmap の書き換えでキー配列の入れ替えができます。
書き換えた内容はログインし直しで適用されるはずです。
その場で確認するなら
$ xmdomap $HOME/.Xmodmap
上のコマンド実行だけだとサスペンド後に配列が戻ってしまいます。
再ログインしておけばサスペンド後も有効となります。
$HOME に .Xmodmap で始まるファイルが複数ある場合、ログイン時にどれを用いるか
選択画面が出ます。
実際に設定してみます。
例えば [/?] (61) と [;+] (47) を入れ替えるなら 61 と 47 を交換します。
Shift や Control キーを入れ替える場合はモディファイヤの再登録が必要です。
例えば内蔵キーボードの右下部分を上記のように並べ替えるには
●キーボードカスタマイズ uinput
User Input を利用するとプログラムでキーの挙動をカスタマイズすることが可能です。
下記のページを参考にさせていただきました。
・Linux Input Subsystemの使い方
x86 PC の Ubuntu 上で試してみました。
入力を遅延判定させた場合のバッファリングとかそのフラッシュなど、Windows /
WindowsMobile 上で ctrlswapmini や em1key を作っていたときとほとんど同じ感覚です。
おそらく同等のプログラムの移植も可能だと思います。
日本語入力の状態が取得できれば親指シフト入力も対応できるでしょう。
(2009/10/03 追記: 親指シフトについてはこちらをどうぞ)
NetWalker 向けのプログラムも作ったのですが uinput が使えずまだ試しておりません。
実際のプログラム例は下記の通りです。
これは [A] と [B] を交換するだけです。サンプルにあった hook_main.c/.h をそのまま
使わせていただきました。hook_main.c をリンクするだけで動作します。
●その他気がついたことなど
最初すぐにバッテリーが減ったように見えるけど、ステータスでは「バッテリー容量:中」。
容量とアイコンの見た目が合っていません。
フラッシュメモリの容量は 4GB ですが、初期状態の空きはおよそ 2.7GB でした。
カタログには「ユーザーエリア 2GB」と書かれているので若干余裕があります。
RAM 容量は 512MB、利用可能な空間は 480MB。
Firefox、ドキュメントビューア、コンソールを起動して消費メモリは 200MB くらい。
ページを複数開いてもまだまだ大丈夫です。
「パネルへ追加」から「CPU 周波数の計測モニタ」を追加してみました。
CPU クロックはピーク時 800MHz で、アイドル時は 160MHz まで落ちているようです。
上パネルの時計の設定から都市を登録しておくと天気や温度も表示されます。
[Fn]+[8] で画面のバックライトだけ消すことが可能です。
黒い色を買ったせいか汚れは結構目立ちます。
ストラップをつけられるのは便利です。手でもって使う場合も安心。
仕様一覧によるとフレームバッファは 16bit 65536色です。
関連エントリ
・NetWalker PC-Z1 意外にいける
・Netwalker PC-Z1 買いました
・タッチタイプの境界
・NetWalker PC-Z1
Bluetooth アダプタ Princeton PTM-UBT3S, PLANEX BT-Mini2EDR を使ってみました。
・システム → システム管理 → Synaptic パッケージマネージャー
・gnome-bluetooth をインストール指定 → 適用
・いったんログアウトして再ログイン
アダプタを接続すると通知スペースに Bluetooth のアイコンが表示されるので
そこからペアリング等を行います。または システム → 設定 → Bluetooth 。
ペアリングしたもの。
マウス SONY VGP-BMS33, キーボード REUDO RBK-2100BTJ
二回ほどサスペンド後にアダプタを認識してないことがありましたが、
電源入れ直し等で復活。以降は今のところ動いています。
●キーボード
購入時からキーボードの配列のカスタマイズを考えていました。
本当は uinput を使いたいのですが module uinput.ko が無かったので取りあえず
xmodmap を使います。
$ xmodmap -pke > $HOME/.Xmodmap
以降 .Xmodmap の書き換えでキー配列の入れ替えができます。
書き換えた内容はログインし直しで適用されるはずです。
その場で確認するなら
$ xmdomap $HOME/.Xmodmap
上のコマンド実行だけだとサスペンド後に配列が戻ってしまいます。
再ログインしておけばサスペンド後も有効となります。
$HOME に .Xmodmap で始まるファイルが複数ある場合、ログイン時にどれを用いるか
選択画面が出ます。
実際に設定してみます。
例えば [/?] (61) と [;+] (47) を入れ替えるなら 61 と 47 を交換します。
!keycode 47 = semicolon plus semicolon plus semicolon plus keycode 61 = semicolon plus semicolon plus semicolon plus !keycode 61 = slash question slash question slash question keycode 47 = slash question slash question slash question
Shift や Control キーを入れ替える場合はモディファイヤの再登録が必要です。
[ J ][ K ][ L ][/? ][Ent] [ M ][<,][>.][ ↑ ][Sft] ↓ [ J ][ K ][ L ][;+ ][Ent] [ M ][<,][>.][ /? ][ ↑]
例えば内蔵キーボードの右下部分を上記のように並べ替えるには
! ファイル先頭で remove remove shift = Shift_R !keycode 47 = semicolon plus semicolon plus semicolon plus keycode 61 = semicolon plus semicolon plus semicolon plus !keycode 61 = slash question slash question slash question keycode 111 = slash question slash question slash question !keycode 62 = Shift_R NoSymbol Shift_R NoSymbol Shift_R keycode 47 = Shift_R NoSymbol Shift_R NoSymbol Shift_R !keycode 111 = Up NoSymbol Up NoSymbol Up keycode 62 = Up NoSymbol Up NoSymbol Up ! ファイル最後で add し直し add shift = Shift_R
●キーボードカスタマイズ uinput
User Input を利用するとプログラムでキーの挙動をカスタマイズすることが可能です。
下記のページを参考にさせていただきました。
・Linux Input Subsystemの使い方
x86 PC の Ubuntu 上で試してみました。
入力を遅延判定させた場合のバッファリングとかそのフラッシュなど、Windows /
WindowsMobile 上で ctrlswapmini や em1key を作っていたときとほとんど同じ感覚です。
おそらく同等のプログラムの移植も可能だと思います。
日本語入力の状態が取得できれば親指シフト入力も対応できるでしょう。
(2009/10/03 追記: 親指シフトについてはこちらをどうぞ)
NetWalker 向けのプログラムも作ったのですが uinput が使えずまだ試しておりません。
実際のプログラム例は下記の通りです。
これは [A] と [B] を交換するだけです。サンプルにあった hook_main.c/.h をそのまま
使わせていただきました。hook_main.c をリンクするだけで動作します。
// swap_AB.c // swap_AB /dev/input/event* #include <stdio.h> #include <linux/input.h> #include <linux/uinput.h> #include <sys/ioctl.h> #include "hook_main.h" const char* name= "swap_AB"; const char* version_information= "swap_AB"; const char* description= "swap_AB"; static int keyboard_fd= 0; void* init_event_handler( int number_of_event_device_files, int* event_fds ) { ioctl( keyboard_fd= *event_fds, EVIOCGRAB, 1 ); return NULL; } void finalize_event_hander( void* user_data ) { ioctl( keyboard_fd, EVIOCGRAB, 0 ); } void handle_event( int fd, struct input_event event, void* user_data ) { int vk= event.code; if( event.type == EV_KEY ){ switch( vk ){ case KEY_A: vk= KEY_B; break; case KEY_B: vk= KEY_A; break; } } send_event( event.type, vk, event.value ); } void set_event_bits( int ui_fd ) { int i; ioctl( ui_fd, UI_SET_EVBIT, EV_KEY ); for( i= 0 ; i< 256 ; i++ ){ ioctl( ui_fd, UI_SET_KEYBIT, i ); } }
●その他気がついたことなど
最初すぐにバッテリーが減ったように見えるけど、ステータスでは「バッテリー容量:中」。
容量とアイコンの見た目が合っていません。
フラッシュメモリの容量は 4GB ですが、初期状態の空きはおよそ 2.7GB でした。
カタログには「ユーザーエリア 2GB」と書かれているので若干余裕があります。
RAM 容量は 512MB、利用可能な空間は 480MB。
Firefox、ドキュメントビューア、コンソールを起動して消費メモリは 200MB くらい。
ページを複数開いてもまだまだ大丈夫です。
「パネルへ追加」から「CPU 周波数の計測モニタ」を追加してみました。
CPU クロックはピーク時 800MHz で、アイドル時は 160MHz まで落ちているようです。
上パネルの時計の設定から都市を登録しておくと天気や温度も表示されます。
[Fn]+[8] で画面のバックライトだけ消すことが可能です。
黒い色を買ったせいか汚れは結構目立ちます。
ストラップをつけられるのは便利です。手でもって使う場合も安心。
仕様一覧によるとフレームバッファは 16bit 65536色です。
関連エントリ
・NetWalker PC-Z1 意外にいける
・Netwalker PC-Z1 買いました
・タッチタイプの境界
・NetWalker PC-Z1
2009/09/25
NetWalker PC-Z1 意外にいける
二日ほど使った感想は「結構良い」です。
意外といったら失礼かもしれませんが、いろいろな面で見直しました。
●両手で持つ
前回書いたとおりネット接続はあまり考えてなかったのですが、使ってみたらこれが快適でした。
無線 LAN さえあれば立っていても横になった状態でも楽にブラウズできます。
・両手持ちしたときちょうど良い位置にあるオプティカルポイント。ほぼこれだけで操作できる。
・ちょっとした検索文字列の入力なら十分役に立つキーボード。
・小さいけど十分な解像度の液晶画面もあるしフォントも見やすい。
・NetBook より軽量で持ち上げられる。
・熱も持たずにバッテリーの持ちも良い。
・中断も DS のようにふたを閉じるだけ。電源を入れるとすぐに復帰する。
電車内でもモバイルルータ併用で立ったまま使ってみました。これも思いのほか使いやすい。
Firefox でネットを見たり、電波の届かない地下鉄区間もメモ打ちしたりと便利に使えます。
以前使っていたスマートフォンで、親指タイプには苦手意識がありました。
W-ZERO3[es] や EM・ONE は、クリック感はあるものの小さくて堅い QWERTY キーで、
爪で押す必要があったり、ボタンが浅いので隣のキーを押してしまうことも多かったからです。
逆に W-ZERO3[es] のテンキー部分は指で押せる大きさで打ちやすいものでした。
同じように NetWalker のキーも指の腹で押せるし、親指ならぐらつくキートップでも確実に
打てるため、それなりに使いやすいことがわかりました。
キーを押し下げた場合の感触はいまいちで引っかかりがあるけれど、親指打ちも結構いけるんだと、
今更ながら気がついたというのが本音です。
ただ両手持ちの親指打ちだと、中央付近のキーは少々遠く感じます。
端ぎりぎりまでキーがあるし Fn や Ctrl を併用する操作は慣れがいるかもしれません。
親指タイプとタッチタイプの両用を欲張ったための弊害でしょう。
この辺の操作は今後のカスタマイズで何とでもなると思います。
むしろ変にメーカー固有のカスタマイズが入ってない素のパソコンキーボード状態なのは
好ましいことです。
●オプティカルポイント
マウス代わりに用いるデバイスです。
タッチパッドのように指でスライドしてカーソルをコントロールします。
反応が良くてきびきび動いてくれます。
PC-NJ70A の光センサー液晶パッドは反応が悪くて使いづらかったので、なおさらそう感じる
のかもしれません。また比較対象があれですが、PS3 ワイヤレスキーパッドのタッチパッド
モードより思い通りに動かせます。
デフォルト状態では少々カーソルの動きが速すぎる感じがします。ウィンドウの切り替えや
ダイアログのボタン、ブラウザの操作は快適なのですが、小さいアイコンやスクロールバーに
正確にあわせるのは苦手です。
使うアプリケーションや用途次第だと思いますが、個人的にはブラウザの操作だけなら
これで十分でした。
設定でマウスの速度や感度を多少いじっています。間違って「☆」マークに触れてしまうと
誤動作するので、スクロールモードに切り替わらないようこちらも封印しています。
●アプリケーション
開発環境を用意したり、アプリストアを設けたり、最近そういう試みが増えた気がします。
携帯 OS に限らずありとあらゆるプラットフォームで。
開発側、使う側、両方の敷居を下げる意味があるのでしょう。
iPhone のような盛り上がりをどこか期待している反面、専用アプリを用意しなければいけない
と言う現実問題がそこにあるのかもしれません。
結局開発者に投げてしまっているわけで、実際にアプリケーションがどれだけ充実するのか未知数です。
NetWalker は普通の Linux を採用したおかげで最初から豊富なアプリケーションが揃っています。
インストールも一覧から選択するだけで簡単です。
以前 WindowsCE の Handheld PC を使っていた頃も使えるアプリケーションソフトが限られて
いました。Desktop 向け Windows がそのまま動くなら何の心配もないのですが。
もう1つの利点は削除された機能がないことです。
モバイル向けの移植ではないので、操作や機能が簡略化されていたり、削られているような
ことがありません。
MID としてみたら上記 2点はメリットですが、UMPC としてみたらこれらはごく当たり前の
ことかもしれません。
そういう意味では NetWalker は MID のカテゴリとして売られているけど、
実質 ARM を使った UMPC の一種だと言えます。
●キーボード
個性だと割り切っています。
●最後に
NetBook が流行し多くの機種が販売されていますが、どれも EeePC に倣ったかのような
画一的なスペックで意外に個性がないように見えます。おそらくコストの事情もあるのでしょう。
本当なら用途を特定したような、もっとユニークなデバイスが登場しても良さそうです。
ASUS のキーボード一体型みたいな。
MID / UMPC にはまだお手本となる大ヒット機種がないせいか、比較的個性を出しやすいようです。
NetWalker を店頭で熱心に見ていると、店員が「おすすめしづらい」製品だと漏らしていました。
過去の経験に当てはまらず具体的な用途を想像しづらいのかもしれません。
「今まで無かった新しいもの」 かまたは 「本当に用途がわからないもの」 のどちらかでしょう。
うまく説明できないものこそ新しいジャンルを切り開く可能性もありますが
果たして NetWalker はどちらになるでしょうか。
個人的にはスマートフォンの機動性を確保しつつ十分使えるパソコンだと認識しました。
関連エントリ
・Netwalker PC-Z1 買いました
・タッチタイプの境界
・NetWalker PC-Z1
意外といったら失礼かもしれませんが、いろいろな面で見直しました。
●両手で持つ
前回書いたとおりネット接続はあまり考えてなかったのですが、使ってみたらこれが快適でした。
無線 LAN さえあれば立っていても横になった状態でも楽にブラウズできます。
・両手持ちしたときちょうど良い位置にあるオプティカルポイント。ほぼこれだけで操作できる。
・ちょっとした検索文字列の入力なら十分役に立つキーボード。
・小さいけど十分な解像度の液晶画面もあるしフォントも見やすい。
・NetBook より軽量で持ち上げられる。
・熱も持たずにバッテリーの持ちも良い。
・中断も DS のようにふたを閉じるだけ。電源を入れるとすぐに復帰する。
電車内でもモバイルルータ併用で立ったまま使ってみました。これも思いのほか使いやすい。
Firefox でネットを見たり、電波の届かない地下鉄区間もメモ打ちしたりと便利に使えます。
以前使っていたスマートフォンで、親指タイプには苦手意識がありました。
W-ZERO3[es] や EM・ONE は、クリック感はあるものの小さくて堅い QWERTY キーで、
爪で押す必要があったり、ボタンが浅いので隣のキーを押してしまうことも多かったからです。
逆に W-ZERO3[es] のテンキー部分は指で押せる大きさで打ちやすいものでした。
同じように NetWalker のキーも指の腹で押せるし、親指ならぐらつくキートップでも確実に
打てるため、それなりに使いやすいことがわかりました。
キーを押し下げた場合の感触はいまいちで引っかかりがあるけれど、親指打ちも結構いけるんだと、
今更ながら気がついたというのが本音です。
ただ両手持ちの親指打ちだと、中央付近のキーは少々遠く感じます。
端ぎりぎりまでキーがあるし Fn や Ctrl を併用する操作は慣れがいるかもしれません。
親指タイプとタッチタイプの両用を欲張ったための弊害でしょう。
この辺の操作は今後のカスタマイズで何とでもなると思います。
むしろ変にメーカー固有のカスタマイズが入ってない素のパソコンキーボード状態なのは
好ましいことです。
●オプティカルポイント
マウス代わりに用いるデバイスです。
タッチパッドのように指でスライドしてカーソルをコントロールします。
反応が良くてきびきび動いてくれます。
PC-NJ70A の光センサー液晶パッドは反応が悪くて使いづらかったので、なおさらそう感じる
のかもしれません。また比較対象があれですが、PS3 ワイヤレスキーパッドのタッチパッド
モードより思い通りに動かせます。
デフォルト状態では少々カーソルの動きが速すぎる感じがします。ウィンドウの切り替えや
ダイアログのボタン、ブラウザの操作は快適なのですが、小さいアイコンやスクロールバーに
正確にあわせるのは苦手です。
使うアプリケーションや用途次第だと思いますが、個人的にはブラウザの操作だけなら
これで十分でした。
設定でマウスの速度や感度を多少いじっています。間違って「☆」マークに触れてしまうと
誤動作するので、スクロールモードに切り替わらないようこちらも封印しています。
●アプリケーション
開発環境を用意したり、アプリストアを設けたり、最近そういう試みが増えた気がします。
携帯 OS に限らずありとあらゆるプラットフォームで。
開発側、使う側、両方の敷居を下げる意味があるのでしょう。
iPhone のような盛り上がりをどこか期待している反面、専用アプリを用意しなければいけない
と言う現実問題がそこにあるのかもしれません。
結局開発者に投げてしまっているわけで、実際にアプリケーションがどれだけ充実するのか未知数です。
NetWalker は普通の Linux を採用したおかげで最初から豊富なアプリケーションが揃っています。
インストールも一覧から選択するだけで簡単です。
以前 WindowsCE の Handheld PC を使っていた頃も使えるアプリケーションソフトが限られて
いました。Desktop 向け Windows がそのまま動くなら何の心配もないのですが。
もう1つの利点は削除された機能がないことです。
モバイル向けの移植ではないので、操作や機能が簡略化されていたり、削られているような
ことがありません。
MID としてみたら上記 2点はメリットですが、UMPC としてみたらこれらはごく当たり前の
ことかもしれません。
そういう意味では NetWalker は MID のカテゴリとして売られているけど、
実質 ARM を使った UMPC の一種だと言えます。
●キーボード
個性だと割り切っています。
●最後に
NetBook が流行し多くの機種が販売されていますが、どれも EeePC に倣ったかのような
画一的なスペックで意外に個性がないように見えます。おそらくコストの事情もあるのでしょう。
本当なら用途を特定したような、もっとユニークなデバイスが登場しても良さそうです。
ASUS のキーボード一体型みたいな。
MID / UMPC にはまだお手本となる大ヒット機種がないせいか、比較的個性を出しやすいようです。
NetWalker を店頭で熱心に見ていると、店員が「おすすめしづらい」製品だと漏らしていました。
過去の経験に当てはまらず具体的な用途を想像しづらいのかもしれません。
「今まで無かった新しいもの」 かまたは 「本当に用途がわからないもの」 のどちらかでしょう。
うまく説明できないものこそ新しいジャンルを切り開く可能性もありますが
果たして NetWalker はどちらになるでしょうか。
個人的にはスマートフォンの機動性を確保しつつ十分使えるパソコンだと認識しました。
関連エントリ
・Netwalker PC-Z1 買いました
・タッチタイプの境界
・NetWalker PC-Z1
2009/09/24
Netwalker PC-Z1 買いました
NetWalker は Linux 搭載ミニ PC です。
ARM 系 CPU に Ubuntu がそのまま入っています。
本体は小さいながらキーボードを搭載し、約 400g と軽量でバッテリーも長持ちします。
逆に欠点も多く、価格が高めであること、限られたフラッシュ容量や Bluetooth が無いなど
スペックも低め、なかなか言うことをきかないキーボードなど、思ったより使う人を選びます。
はじめて触ったのは2日前。
ホームポジションにぎりぎり指が乗るだけのキーピッチがあるのに、あまりにも思うように
タイプできなくて店頭で 30分くらい奮闘。力を入れて意識して打てば
何とか文字抜け無しに打てるといったところ。
一時は諦めたけど、ずっと気になっていて結局買ってしまいました。
●外観
実測で 401g ありました。見た目は電子辞書。
Netbook と比べても PC らしからぬ印象なのは、通風口がまったく無いせいかもしれません。
ファンレスは当然として側面も裏面もスリット無しです。
●電源
スマートフォンやかつての Handhed PC のように、電源切断 = サスペンド (スリープ) 推奨
と書かれています。シャットダウンとの違いは同梱のパンフレットにも説明があります。
3秒起動なのはサスペンドからの復帰のこと。スリープを使えば Windows PC でも同じ
ですが、サスペンドを常用できるくらい省電力だということなのでしょう。
シャットダウン状態からの起動はそれなりに時間がかかります。
バッテリー動作で実測 1分45秒 かかりました。
この数値は Windows7 + Atom Z540 + 高速 SSD の Netbook のおよそ 2倍です。
OS の起動自体はそれほど速くありません。
初起動後は若干遅めで、アプリ起動だけでなくメニューやホットキーの動作なども
ワンテンポ遅れる印象がありました。最初だけだったようで、しばらく使って落ち着いたら
それなりのレスポンス速度で動いています。
●画面
高密度できれいに見えます。
最初から太めで大きなフォントが使われているため見やすい画面です。
5インチ で 1024x600 なので この の計算式に当てはめると 約 237.4 ppi 。
LOOX U に負けるけど VAIO type P よりは高密度です。
KOHJINSHA PM は 4.8 インチなのでさらに細かく 247.3 ppi 。
● Ubuntu
本当にそのまま Ubuntu です。起動画面も desktop も見慣れたものです。
あくまで個人的な話ですが、vim も入っているしキーバインドも普段通りなので、買って
何のソフト導入もカスタマイズもせずにすぐ使用できたのは初めてかもしれません。
●ポインティングデバイス
キーボードの右上、ヒンジとの間に OPTICALPOINT が埋め込まれています。
きちんと設定して使ったら結構反応も良く使いやすそうです。
店頭でたまにカーソルが動かない端末がありましたがその原因も判明しました。
オプティカルポイントには「カーソルモード」と「ホイールモード」の2種類があって、
ホイールモードだとカーソルが動かずスクロール動作になる仕組みです。
「☆」マークまたは Fn +[9] で切り替わります。
おそらく店頭の端末もホイールモードに切り替わっていたため。
カーソルが出っぱなしだと固まったように見えるので少々分かりにくいところです。
PC-NJ70A で苦労させれた光センサー液晶パッドよりはレスポンスも良好です。
そういえば画面がタッチパネルであることをすっかり忘れていました。
●クイックスタートボタン
キーボードとヒンジの間、電源ボタンの隣に描かれているアイコンはタッチ式のボタンに
なっています。デフォルトで起動の遅いアプリが登録されているので、間違って触れてしまうと
ちょっとしたダメージが。
設定で無効にすることが出来なかったので「デスクトップの表示」にしておきました。
●通信
内蔵している通信手段は無線 LAN のみ。
Bluetooth が入ってないのは寂しいですが、おかげでまだ Bluetooth キーボードやマウスに
逃げることなく使っています。
UQ WiMAX の USB アダプタは、Windows でも x64 未対応だったりと期待できないので
必要な時はモバイルルータ URoad-5000 に頼るつもりです。
●キーボード
タッチタイピングによる入力は相変わらず敷居が高いです。
キーを打った後に定位置に吸い込むような感触が無く、むしろ球面を押し込むような反発
とぐらつきがあります。
キーを押したあとの指の位置が安定しないので、隣のキーを押してしまったりホーム
ポジションが徐々にずれたりします。指を離したときもわかりにくい。
まだあまり速く打てないけどだいぶ慣れてきました。
●用途
現状お勧めしづらいし、キーボードも配列以前のところでかなり使いづらい印象です。
それでもぎりぎり打てるサイズなので敢えて使いこなしてみたくなります。
正直割と気に入っています。
ネット接続よりも今のところは無謀にも文字入力用の端末として考えています。
CPU は Cortex-A8 だし、もし AMD Z430 の OpenGL ES 2.0 が使えるなら
また違う使い方が出来るでしょう。
関連エントリ
・タッチタイプの境界
・NetWalker PC-Z1
・OpenGL ES 2.0
・WiMAX ルータ URoad-5000 (4) 充電の仕方
ARM 系 CPU に Ubuntu がそのまま入っています。
本体は小さいながらキーボードを搭載し、約 400g と軽量でバッテリーも長持ちします。
逆に欠点も多く、価格が高めであること、限られたフラッシュ容量や Bluetooth が無いなど
スペックも低め、なかなか言うことをきかないキーボードなど、思ったより使う人を選びます。
はじめて触ったのは2日前。
ホームポジションにぎりぎり指が乗るだけのキーピッチがあるのに、あまりにも思うように
タイプできなくて店頭で 30分くらい奮闘。力を入れて意識して打てば
何とか文字抜け無しに打てるといったところ。
一時は諦めたけど、ずっと気になっていて結局買ってしまいました。
●外観
実測で 401g ありました。見た目は電子辞書。
Netbook と比べても PC らしからぬ印象なのは、通風口がまったく無いせいかもしれません。
ファンレスは当然として側面も裏面もスリット無しです。
●電源
スマートフォンやかつての Handhed PC のように、電源切断 = サスペンド (スリープ) 推奨
と書かれています。シャットダウンとの違いは同梱のパンフレットにも説明があります。
3秒起動なのはサスペンドからの復帰のこと。スリープを使えば Windows PC でも同じ
ですが、サスペンドを常用できるくらい省電力だということなのでしょう。
シャットダウン状態からの起動はそれなりに時間がかかります。
バッテリー動作で実測 1分45秒 かかりました。
この数値は Windows7 + Atom Z540 + 高速 SSD の Netbook のおよそ 2倍です。
OS の起動自体はそれほど速くありません。
初起動後は若干遅めで、アプリ起動だけでなくメニューやホットキーの動作なども
ワンテンポ遅れる印象がありました。最初だけだったようで、しばらく使って落ち着いたら
それなりのレスポンス速度で動いています。
●画面
高密度できれいに見えます。
最初から太めで大きなフォントが使われているため見やすい画面です。
5インチ で 1024x600 なので この の計算式に当てはめると 約 237.4 ppi 。
LOOX U に負けるけど VAIO type P よりは高密度です。
KOHJINSHA PM は 4.8 インチなのでさらに細かく 247.3 ppi 。
● Ubuntu
本当にそのまま Ubuntu です。起動画面も desktop も見慣れたものです。
あくまで個人的な話ですが、vim も入っているしキーバインドも普段通りなので、買って
何のソフト導入もカスタマイズもせずにすぐ使用できたのは初めてかもしれません。
●ポインティングデバイス
キーボードの右上、ヒンジとの間に OPTICALPOINT が埋め込まれています。
きちんと設定して使ったら結構反応も良く使いやすそうです。
店頭でたまにカーソルが動かない端末がありましたがその原因も判明しました。
オプティカルポイントには「カーソルモード」と「ホイールモード」の2種類があって、
ホイールモードだとカーソルが動かずスクロール動作になる仕組みです。
「☆」マークまたは Fn +[9] で切り替わります。
おそらく店頭の端末もホイールモードに切り替わっていたため。
カーソルが出っぱなしだと固まったように見えるので少々分かりにくいところです。
PC-NJ70A で苦労させれた光センサー液晶パッドよりはレスポンスも良好です。
そういえば画面がタッチパネルであることをすっかり忘れていました。
●クイックスタートボタン
キーボードとヒンジの間、電源ボタンの隣に描かれているアイコンはタッチ式のボタンに
なっています。デフォルトで起動の遅いアプリが登録されているので、間違って触れてしまうと
ちょっとしたダメージが。
設定で無効にすることが出来なかったので「デスクトップの表示」にしておきました。
●通信
内蔵している通信手段は無線 LAN のみ。
Bluetooth が入ってないのは寂しいですが、おかげでまだ Bluetooth キーボードやマウスに
逃げることなく使っています。
UQ WiMAX の USB アダプタは、Windows でも x64 未対応だったりと期待できないので
必要な時はモバイルルータ URoad-5000 に頼るつもりです。
●キーボード
タッチタイピングによる入力は相変わらず敷居が高いです。
キーを打った後に定位置に吸い込むような感触が無く、むしろ球面を押し込むような反発
とぐらつきがあります。
キーを押したあとの指の位置が安定しないので、隣のキーを押してしまったりホーム
ポジションが徐々にずれたりします。指を離したときもわかりにくい。
まだあまり速く打てないけどだいぶ慣れてきました。
●用途
現状お勧めしづらいし、キーボードも配列以前のところでかなり使いづらい印象です。
それでもぎりぎり打てるサイズなので敢えて使いこなしてみたくなります。
正直割と気に入っています。
ネット接続よりも今のところは無謀にも文字入力用の端末として考えています。
CPU は Cortex-A8 だし、もし AMD Z430 の OpenGL ES 2.0 が使えるなら
また違う使い方が出来るでしょう。
関連エントリ
・タッチタイプの境界
・NetWalker PC-Z1
・OpenGL ES 2.0
・WiMAX ルータ URoad-5000 (4) 充電の仕方
2009/09/23
RADEON HD 5870 と DirectX 11
Direct3D 11 対応 GPU RADEON HD 5870/5850 が発表されました。
Windows7 発売に間に合うし、Direct3D 11 SDK も直前に RTM しています。
足並みが揃った良いタイミングです。
あとは安定して入手できるかどうか、ドライバが間に合うかどうかでしょう。
・AMD、業界初DirectX 11対応GPU「Radeon HD 5800」シリーズ ~上位モデルは1,600SP搭載の2.7TFLOPS
最近は GPU の世代が代わり 機能が増えても一時的なパフォーマンスの低下は見られなく
なりました。GeForce 6800 や 8800 の時もそうでしたがむしろ倍のスコアを出しています。
速度を求める場合も機能が目的でも、安心して手を出せるのは嬉しいところです。
Direct3D 10 → Direct3D 11 の更新は API 的なデザインの変更は少ないものの、
Direct3D 8 → Direct3D 9 と同じように増えた機能はかなりあります。
・汎用性の向上 Compute Shader
・グラフィックス機能の進化 Tessellation, BC6H/BC7
・管理機能の強化 Dynamic Shader Linkage
・スレッド対応 Deferred Context
等
一見地味な Dynamic Shader Linkage や Deferred Context も、開発者にとっては
大変嬉しい機能です。
Dynamic Shader Linkage は描画発行時にシェーダー内の飛び先を決定することが出来ます。
いわば関数ポインタのようなもので、シェーダーの種類を増やさずに機能の切り替えを
容易にしてくれます。
Deferred Context は他のスレッドが発行した描画命令を Display List としてバッファリングし、
コンテキストに矛盾が生じないようにします。
シェーダーの機能切り替えも効率よいスレッドの活用も、これまではアプリケーション側で工夫して
実現する必要がありました。
つまり DirectX 11 では従来 CPU 側で行ってきたいくつかの分野もアクセラレーションの
対象となっているといえます。GPGPU に限らず GPU の役割は徐々に広がっているようです。
今後 CPU/GPU もお互いに相手の機能を取り込むだけではなく、より連携しやすいような歩み寄りも
必要ではないでしょうか。例えば CPU にも積極的に GPU 連携のための命令が追加されるとか。
SSE5 の half 型変換命令はその一つの好例かもしれません。
DirectX/GPU 年表 も更新しました。
関連エントリ
・DirectX SDK August 2009 の解説と Direct3D 11 RTM
・Direct3D11/DirectX11 (18) GPU を使ったアウトラインフォントの描画の(6)
・Direct3D11/DirectX11 (13) TessFactor とシェーダーリンクの補足など
・Direct3D11/DirectX11 (12) テセレータのレンダーステート他
Windows7 発売に間に合うし、Direct3D 11 SDK も直前に RTM しています。
足並みが揃った良いタイミングです。
あとは安定して入手できるかどうか、ドライバが間に合うかどうかでしょう。
・AMD、業界初DirectX 11対応GPU「Radeon HD 5800」シリーズ ~上位モデルは1,600SP搭載の2.7TFLOPS
最近は GPU の世代が代わり 機能が増えても一時的なパフォーマンスの低下は見られなく
なりました。GeForce 6800 や 8800 の時もそうでしたがむしろ倍のスコアを出しています。
速度を求める場合も機能が目的でも、安心して手を出せるのは嬉しいところです。
Direct3D 10 → Direct3D 11 の更新は API 的なデザインの変更は少ないものの、
Direct3D 8 → Direct3D 9 と同じように増えた機能はかなりあります。
・汎用性の向上 Compute Shader
・グラフィックス機能の進化 Tessellation, BC6H/BC7
・管理機能の強化 Dynamic Shader Linkage
・スレッド対応 Deferred Context
等
一見地味な Dynamic Shader Linkage や Deferred Context も、開発者にとっては
大変嬉しい機能です。
Dynamic Shader Linkage は描画発行時にシェーダー内の飛び先を決定することが出来ます。
いわば関数ポインタのようなもので、シェーダーの種類を増やさずに機能の切り替えを
容易にしてくれます。
Deferred Context は他のスレッドが発行した描画命令を Display List としてバッファリングし、
コンテキストに矛盾が生じないようにします。
シェーダーの機能切り替えも効率よいスレッドの活用も、これまではアプリケーション側で工夫して
実現する必要がありました。
つまり DirectX 11 では従来 CPU 側で行ってきたいくつかの分野もアクセラレーションの
対象となっているといえます。GPGPU に限らず GPU の役割は徐々に広がっているようです。
今後 CPU/GPU もお互いに相手の機能を取り込むだけではなく、より連携しやすいような歩み寄りも
必要ではないでしょうか。例えば CPU にも積極的に GPU 連携のための命令が追加されるとか。
SSE5 の half 型変換命令はその一つの好例かもしれません。
DirectX/GPU 年表 も更新しました。
関連エントリ
・DirectX SDK August 2009 の解説と Direct3D 11 RTM
・Direct3D11/DirectX11 (18) GPU を使ったアウトラインフォントの描画の(6)
・Direct3D11/DirectX11 (13) TessFactor とシェーダーリンクの補足など
・Direct3D11/DirectX11 (12) テセレータのレンダーステート他
2009/09/22
キーピッチ一覧
昨日の表に仕様もいくつか追加してみました。
RAM は搭載可能最大値、バッテリーは小または標準時。
関連エントリ
・タッチタイプの境界
key pitch CPU RAM KOHJINSHA PM 12.0mm Atom Z510 1.1GHz 512MB 345g 7H 59800円 WILLCOM D4 12.2mm Atom Z520 1.3GHz 1GB 460g 1.5H HTC Shift 13.0mm x86 A110 800MHz 1GB 800g 2H Jornada680 13.2mm SH3 133MHz 16MB 510g 138000円 Jornada720 13.2mm StrongARM 206MHz 32MB 510g 10H 94800円 Libretto 20 13.5mm DX4 75MHz 75MHz 20MB 840g 3H 178000円 NetWalker PC-Z1 14.0mm Cortex-A8 800MHz 512MB 409g 10H 44800円 Loox U50X/V 14.0mm x86 A110 800MHz 1GB 599g 3.8H Sigmarion II 14.1mm MIPS VR4131 200MHz 32MB 500g 10H Sigmarion III 14.1mm ARM PXA255 400MHz 64MB 455g 10H KOHJINSHA SK 14.2mm Atom Z530 1.3GHz 1GB 720g 3.1H Libretto 70 14.5mm MMX Pentium 120MHz 32MB 850g 3H Libretto 100 14.5mm MMX Pentium 166MHz 64MB 950g 2H Loox U/C40 14.8mm Atom Z530 1.6GHz 1GB 565g 4.2H Libretto SS1000 15.0mm MMX Pentium 166MHz 96MB 820g 3H Libretto ff1100 15.0mm MMX Pentium 266MHz 128MB 980g 3H EeePC 901-X 15.5mm Atom N270 1.6GHz 2GB 1100g 8.3H 59800円 VAIO type P 90 16.5mm Atom Z540 1.86GHz 2GB 588g 4H MobileGear MC/R530 16.5mm MIPS VR4121 168MHz 32MB 770g 10H 110000円 MobileGear MC/R700 16.5mm MIPS VR4121 131MHz 32MB 1100g 8H 155000円
RAM は搭載可能最大値、バッテリーは小または標準時。
関連エントリ
・タッチタイプの境界
2009/09/21
タッチタイプの境界
店頭で NetWalker PC-Z1 と KOHJINSHA PM (PM1WX16SA) を触ってきました。
タッチタイピング前提でどこまでキーを打てるか興味あったからです。
・SHARP NetWalker
・KOHJINSHA PM series
NetWalker はホームポジションに指を載せることが可能で、サイズの割にそこそこ
打てそうな印象でしたが予想以上に苦戦しました。なかなかタイピングのこつがつかめず
最初はキーの取りこぼしが多くてさんざんな結果に。
見かねた店員が 「両手でもって親指で打てばいいですよ」 とかアドバイスしてくれたほど。
キートップが不安定で、指先の感触だけでは入力出来たかどうか判断しづらいのが原因のようです。
文字を確実に打つには、指先の感触に頼らないで完全に底打ちするくらい押し込まなければ
なりません。
店頭の不安定な飾り台ではだめで、安定したテーブルの上に置いて指先に力を入れて強く
つぶし込む気持ちで打てば割と打てるようになりました。
ただこれだけ力を込めてタイプするなら、今まで敬遠しがちだった他のどのキーボードでも
使いこなす自信が付きそうです。
PM (mbook) はキーの感触が良く、NetWalker よりも軽く確実に打つことが出来ます。
問題はキーピッチの方で、ホームポジションにぎりぎり指を乗せられるか若干はみ出る感じです。
キー配列は PM の方が好みなのですが、やっぱり指が窮屈なのか速く打とうとすると
うまく文字を探せないことがありました。
キーピッチだけがすべてではないと思いますが、過去に使ったことがある端末および同系統の
機種を調べてみました。"*" は実際に所有して長時間使ったことがあるものです。
個人的に気に入っており、タッチタイプで打ちやすかったのが MC/R530 と Jornada 720。
当時はあまり意識しなかったけど Libretto 100 も普通に使っていた気がします。
今のところ 13mm 前後が境界線です。NetWalker のキーボードを確認するため、
長時間練習したことを考えれば 12mm も慣れたら何とかなるんでしょうか。
以下はキーピッチを調べる上で参考にしたページです。
・PC watch Libretto 新機種
・TOSHIBA Libretto 100 の発売について
・製品マニュアル HP Jornada 720 ハンドヘルド PC
・VAIO type P スペック
・NECインフロンティア Mobile Gear Age
・Wikipedia モバイルギア
・Eee PC 1000H-X速攻レビュー
・Panasonic レッツノートラインナップ比較表
・工人舎「PM」~ワイシャツのポケットに入る超小型Windows PC
・LOOX U カタログモデル仕様
・Atom搭載「LOOX U」の進化ぶりを写真でじっくり解説する
タッチタイピング前提でどこまでキーを打てるか興味あったからです。
・SHARP NetWalker
・KOHJINSHA PM series
NetWalker はホームポジションに指を載せることが可能で、サイズの割にそこそこ
打てそうな印象でしたが予想以上に苦戦しました。なかなかタイピングのこつがつかめず
最初はキーの取りこぼしが多くてさんざんな結果に。
見かねた店員が 「両手でもって親指で打てばいいですよ」 とかアドバイスしてくれたほど。
キートップが不安定で、指先の感触だけでは入力出来たかどうか判断しづらいのが原因のようです。
文字を確実に打つには、指先の感触に頼らないで完全に底打ちするくらい押し込まなければ
なりません。
店頭の不安定な飾り台ではだめで、安定したテーブルの上に置いて指先に力を入れて強く
つぶし込む気持ちで打てば割と打てるようになりました。
ただこれだけ力を込めてタイプするなら、今まで敬遠しがちだった他のどのキーボードでも
使いこなす自信が付きそうです。
PM (mbook) はキーの感触が良く、NetWalker よりも軽く確実に打つことが出来ます。
問題はキーピッチの方で、ホームポジションにぎりぎり指を乗せられるか若干はみ出る感じです。
キー配列は PM の方が好みなのですが、やっぱり指が窮屈なのか速く打とうとすると
うまく文字を探せないことがありました。
キーピッチだけがすべてではないと思いますが、過去に使ったことがある端末および同系統の
機種を調べてみました。"*" は実際に所有して長時間使ったことがあるものです。
mbook M1/PM 12.0mm Jornada680 13.2mm Jornada720 13.2mm * Libretto 20 13.5mm NetWalker 14.0mm Loox U50 14.0mm * Sigmarion 14.1mm Libretto 70 14.5mm Libretto 100 14.5mm * Loox U 14.8mm EeePC 901-X 15.5mm * VAIO type P 16.5mm * Mobile Gear II MC/R530 16.5mm * Mobile Gear II MC/R700 16.5mm * Let's Note R4 17.0mm * PC Keyboard 19.0mm *
個人的に気に入っており、タッチタイプで打ちやすかったのが MC/R530 と Jornada 720。
当時はあまり意識しなかったけど Libretto 100 も普通に使っていた気がします。
今のところ 13mm 前後が境界線です。NetWalker のキーボードを確認するため、
長時間練習したことを考えれば 12mm も慣れたら何とかなるんでしょうか。
以下はキーピッチを調べる上で参考にしたページです。
・PC watch Libretto 新機種
・TOSHIBA Libretto 100 の発売について
・製品マニュアル HP Jornada 720 ハンドヘルド PC
・VAIO type P スペック
・NECインフロンティア Mobile Gear Age
・Wikipedia モバイルギア
・Eee PC 1000H-X速攻レビュー
・Panasonic レッツノートラインナップ比較表
・工人舎「PM」~ワイシャツのポケットに入る超小型Windows PC
・LOOX U カタログモデル仕様
・Atom搭載「LOOX U」の進化ぶりを写真でじっくり解説する
2009/09/16
Mobile GPU
HYPERでんちの GPU 年表更新しました。
ほとんどが Mobile デバイスの追加です。
2009年になって一気に Shader 対応端末が普及したことがわかります。
この流れを推し進めているは OpenGL ES 2.0 。
OpenGL ES 2.0 は Direct3D 10 以降のように Shader パイプラインしか定義しておらず
GL ES 2.0 対応であればシェーダーベースの GPU であることがわかります。
デバイスの機能的にもシェーダーに進むそれなりの理由があるのでしょう。
例えば一部 GPU はすでにユニファイドシェーダーを採用しています。
ShaderModel 4.0 にかなり近いか、最初から 4.0 に対応し得る設計です。
シェーダーユニットの再利用は実行効率的にも優れており、ユニットの個数で
スケーラビリティを保ちやすいなどのメリットが考えられます。
また CPU の補助として GPGPU 的な使い方も視野に入れているようです。
他にも先行しているデスクトップ向け 3D ゲームの移植しやすさや同等のテクニックが
使えること、デスクトップ向け GPU の設計を流用できる、バス帯域の制約から演算の
比重を高めるなど、考えられる理由があります。
表を見ているとかつてのデスクトップ向け 3D アクセラレータが多数登場し、
各社多種のビデオカードがしのぎを削っていた頃を思い出します。
ほぼ 2強で占められたハイエンドと違い、様々な GPU が使われているようです。
電力も面積も限られているモバイル向け GPU にとってバス帯域は大きな問題です。
タイルベースで深度判定のみ先行し、最小限のフラグメントのみレンダリングする
PowerVR と同じように、AMD もチップ内の少量かつ高速な RAM を用いたタイルベース
レンダリングを行っているようです。この辺の工夫も非常に興味深いところです。
WindowsVista/7 のウィンドウが GPU 描画になったのと同じように、Mobile デバイス
でも 3D アクセラレータを用いた表現が重要となっています。
一般のアプリケーションも当たり前のように GPU を使っているなんて
3D アクセラレータが乗っていなかったり、乗っていてもドライバが無くて使えなかった
昔からは考えられないことです。
とはいえ今時の CPU は速いので、MI-Zaurus + CPU だけでレンダリングしていた頃を
考えれば CPU でも十分描画できるのかもしれません。
・GPU 年表
・Direct3D Mobile DeviceCaps 一覧
・Zaurus GA 3D Engine
ほとんどが Mobile デバイスの追加です。
2009年になって一気に Shader 対応端末が普及したことがわかります。
この流れを推し進めているは OpenGL ES 2.0 。
OpenGL ES 2.0 は Direct3D 10 以降のように Shader パイプラインしか定義しておらず
GL ES 2.0 対応であればシェーダーベースの GPU であることがわかります。
デバイスの機能的にもシェーダーに進むそれなりの理由があるのでしょう。
例えば一部 GPU はすでにユニファイドシェーダーを採用しています。
ShaderModel 4.0 にかなり近いか、最初から 4.0 に対応し得る設計です。
シェーダーユニットの再利用は実行効率的にも優れており、ユニットの個数で
スケーラビリティを保ちやすいなどのメリットが考えられます。
また CPU の補助として GPGPU 的な使い方も視野に入れているようです。
他にも先行しているデスクトップ向け 3D ゲームの移植しやすさや同等のテクニックが
使えること、デスクトップ向け GPU の設計を流用できる、バス帯域の制約から演算の
比重を高めるなど、考えられる理由があります。
表を見ているとかつてのデスクトップ向け 3D アクセラレータが多数登場し、
各社多種のビデオカードがしのぎを削っていた頃を思い出します。
ほぼ 2強で占められたハイエンドと違い、様々な GPU が使われているようです。
電力も面積も限られているモバイル向け GPU にとってバス帯域は大きな問題です。
タイルベースで深度判定のみ先行し、最小限のフラグメントのみレンダリングする
PowerVR と同じように、AMD もチップ内の少量かつ高速な RAM を用いたタイルベース
レンダリングを行っているようです。この辺の工夫も非常に興味深いところです。
WindowsVista/7 のウィンドウが GPU 描画になったのと同じように、Mobile デバイス
でも 3D アクセラレータを用いた表現が重要となっています。
一般のアプリケーションも当たり前のように GPU を使っているなんて
3D アクセラレータが乗っていなかったり、乗っていてもドライバが無くて使えなかった
昔からは考えられないことです。
とはいえ今時の CPU は速いので、MI-Zaurus + CPU だけでレンダリングしていた頃を
考えれば CPU でも十分描画できるのかもしれません。
・GPU 年表
・Direct3D Mobile DeviceCaps 一覧
・Zaurus GA 3D Engine
簡単なテストです。
出来るだけ描画面積を小さくしてほぼ頂点演算のみ。
単一マテリアルかつ共有頂点、48000ポリゴンの最適化していない素のモデルデータを
描画しています。Indexed + Triangle List で Strip 化や頂点キャッシュ用ソートを
していません。
VAIO Type P で描画してみました。
当初 OpenGL を使おうとしましたがドライバが未対応でした(↓)。
D3D11 の CapsViewer で調べると Direct3D 11 の FEATURE_LEVEL_9 も未対応。
Direct3D 10 の FeatureLevel 9_1 には対応しています。
今回は昔作った Direct3D 9 のツール&シェーダーを使っています。
シェーダーも複数の機能を盛り込んで汎用化したもので、あまり最適化されていません。
・Atom Z540 + GMA500
・Windows7 RC で Aero off
この条件で上記モデルデータを 4個描画しておよそ 38fps。
結果だけ見ると頂点演算は 7.3M triangles/sec くらい。
Wikipedia PowerVR によると GMA500 は PowerVR SGX535 で 28M poly/s 。
記載されているピーク値の 1/4 くらいですが最初はこんなもんでしょう。
モデルを拡大して描画面積を広げるとあっという間に処理落ちします。
Unified シェーダーということもあって、おそらくピーク値は極端な値を示す傾向があると
考えられます。つまり実際のアプリケーションで使う場合、シェーダーユニットをピクセルにも
割り振る必要があるので、その分だけ数値は落ちます。
こんなにいい加減なテストでも PowerVR MBX Lite の性能値として記載されている頂点
演算速度よりはおそらく高速です。頂点だけに絞ればかなりの差が付きそうです。
また iPhone 3GS + GL ES 2.0 で同じモデルデータを描画したところほとんど同じ
結果になりました。4個描画時に 40fps、7.68M tri/s くらいです。
こちらの方が多少簡略化したフラグメントシェーダーを用いており、厳密に同一条件では
ありませんが、ピクセルの影響は少ないのでほぼ同じとみて良さそうです。
どちらも同じ SGX 535 相当であることが結果からも明らかになりました。
つまり Type P は、iPhone 3GS や iPod touch 3G とほとんど同じ能力の GPU で
8倍の面積を描画していることになります。
ちなみに GeForce/RADEON などデスクトップ PC 向け GPU だと、上記モデルは
100~150個 * 60fps 出ます。GPU グレード間の差が付かないので、ハイエンドだと
このテストは低負荷すぎるようです。
関連エントリ
・VAIO type P + Windows7 RC で Direct3D 11
・Intel GMA500 のスペックについて考える。続き (2)
出来るだけ描画面積を小さくしてほぼ頂点演算のみ。
単一マテリアルかつ共有頂点、48000ポリゴンの最適化していない素のモデルデータを
描画しています。Indexed + Triangle List で Strip 化や頂点キャッシュ用ソートを
していません。
VAIO Type P で描画してみました。
当初 OpenGL を使おうとしましたがドライバが未対応でした(↓)。
GL_VERSION: 1.1.0 GL_RENDERER: GDI Generic GL_VENDOR: Microsoft Corporation GL_SHADING_LANGUAGE_VERSION: (null)
D3D11 の CapsViewer で調べると Direct3D 11 の FEATURE_LEVEL_9 も未対応。
Direct3D 10 の FeatureLevel 9_1 には対応しています。
今回は昔作った Direct3D 9 のツール&シェーダーを使っています。
シェーダーも複数の機能を盛り込んで汎用化したもので、あまり最適化されていません。
・Atom Z540 + GMA500
・Windows7 RC で Aero off
この条件で上記モデルデータを 4個描画しておよそ 38fps。
結果だけ見ると頂点演算は 7.3M triangles/sec くらい。
Wikipedia PowerVR によると GMA500 は PowerVR SGX535 で 28M poly/s 。
記載されているピーク値の 1/4 くらいですが最初はこんなもんでしょう。
モデルを拡大して描画面積を広げるとあっという間に処理落ちします。
Unified シェーダーということもあって、おそらくピーク値は極端な値を示す傾向があると
考えられます。つまり実際のアプリケーションで使う場合、シェーダーユニットをピクセルにも
割り振る必要があるので、その分だけ数値は落ちます。
こんなにいい加減なテストでも PowerVR MBX Lite の性能値として記載されている頂点
演算速度よりはおそらく高速です。頂点だけに絞ればかなりの差が付きそうです。
また iPhone 3GS + GL ES 2.0 で同じモデルデータを描画したところほとんど同じ
結果になりました。4個描画時に 40fps、7.68M tri/s くらいです。
こちらの方が多少簡略化したフラグメントシェーダーを用いており、厳密に同一条件では
ありませんが、ピクセルの影響は少ないのでほぼ同じとみて良さそうです。
どちらも同じ SGX 535 相当であることが結果からも明らかになりました。
つまり Type P は、iPhone 3GS や iPod touch 3G とほとんど同じ能力の GPU で
8倍の面積を描画していることになります。
ちなみに GeForce/RADEON などデスクトップ PC 向け GPU だと、上記モデルは
100~150個 * 60fps 出ます。GPU グレード間の差が付かないので、ハイエンドだと
このテストは低負荷すぎるようです。
関連エントリ
・VAIO type P + Windows7 RC で Direct3D 11
・Intel GMA500 のスペックについて考える。続き (2)
2009/09/14
OpenGL や GLSL の互換性
Direct3D の HLSL コンパイラは Microsoft が用意しており、共通のバイトコードを
生成しています。
実行時はさらにドライバが GPU 毎のネイティブコードに最適化&変換を行っています。
一見二度手間ですが、最初の最適化は共通バイトコードへの変換時に済んでいます。
時間のかかる巨大なシェーダーでも事前に変換しておくことが可能だし、コンパイラ部の
最適化の恩恵はすべての GPU で受けられます。
ドライバも共通コードからの変換だけ行えばよいので、互換性も比較的維持しやすいのでは
ないかと考えられます。
その代わり一度バイナリにしてしまうと、コンパイルした時点のコンパイラの能力である程度
固定されます。あとからコンパイラが強化される可能性もあるし、GPU が ShaderModel 5.0
対応になっても、3.0 向けにコンパイルしたシェーダーで能力を出し切れるとは限りません。
OpenGL の GLSL の場合 API が受け取るのは生のソースコードです。
コンパイルそのものが GPU ドライバの役目となっていて、中間の共通コードがありません。
動的にコンパイルするメリットは常にハードに最適なプロファイルを選べることです。
逆にデメリットとしては、コンパイル時間がかかるのではないかとの懸念もありますが
もっと別の問題もあるようです。
今まで GeForce で組み立ててきたコードを RADEON で走らせてみました。
環境は下記の通り。
● Version 指定
RADEON の GLSL では「#version」はソースコードの先頭にないとエラーになります。
・#version の前にプリプロセッサ命令があるだけでもだめ。
・glShaderSource() に複数のソースコードを渡している場合、最初のコードの先頭でないとだめ。2番目以降のソースコードには記述できない。
この挙動は OpenGLES 2.0 の GLSL と同じです。また GLSLangSpec.Full.1.40.05.pdf
を見ても、#version の前に許されるのはコメントとホワイトスぺースのみと記載されています。
こちらの動作の方が正解でした。
ただプリプロセッサ命令も許されていないので、複数のターゲット間で互換性ととる場合に
version 指定を分岐できないのは不便です。C 言語側の Shader Loader 部分に手を加えて、
独自のプリプロセッサを追加するなどの対策が必要かもしれません。
● precision 指定
OpenGL ES の GLSL から取り入れた仕様として precision 指定があります。
宣言時に変数が必要とする精度のヒントを与えます。
highp, middlep, lowp の 3段階ありますが
・GeForce は in/out 宣言の前に必要
・RADEON は in/out 宣言の後ろ書かないとエラー
RADEON の場合必ず何らかの精度指定が必須で、個別指定かまたはデフォルトの
precision 行が必要です。GeForce は無くても通ります。
とりあえず最初にデフォルト宣言をしておけばどちらでも通ります。
細かく個別に宣言をしている場合は注意。
ドキュメントを見る限り RADEON の方が正しいようです。
全体的に GeForce の方が判定が緩く RADEON の方が厳密になっています。
GPU のドライバ毎にコンパイラの仕様が異なっている可能性を考えると、
Direct3D + HLSL のように共通化されている方が楽だと思います。
慣れるまではこれらの互換性の維持に苦労しそうです。
●OpenGL 3.1
現段階で OpenGL 3.2/GLSL 1.5 に対応しているのは GeForce 190.57 だけです。
RADEON で試すにあたって OpenGL 3.1/GLSL 1.4 で動作するように修正しました。
GeForce の場合、最初に wglCreateContext() で作った Context がすでに
OpenGL 3.x に対応していました。
wglCreateContextAttribsARB() で作り直さなくても動作します。
RADEON の場合 OpenGL 2.1 だったので、wglCreateContextAttribsARB() が必要です。
でもシェーダーバージョンは同じ。
● Extension の判定
GeForce 190.57 を Version 3.1 で作り直した場合のはまりです。
Extension の判定で glGetString( GL_EXTENSIONS ) を参照していましたが、
Context を作り直すとエラーになります。
ドキュメントをよく見ると glGetString( GL_EXTENSIONS ) は古い仕様で、
OpenGL 3.x の場合は
を用いるのが正しいやり方のようです。
WGL_CONTEXT_FLAGS_ARB を 0 にしても
WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB がセットされてしまうことが
原因のようです。
190.62 では WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB を指定しない限り
大丈夫でした。
互換性周りはまだ慣れてないせいか、または出来るだけ共通で動かそうと欲張っている
せいか苦労しています。
Direct3D の場合問題になる互換性はハードウエア能力の差でした。
その後 Direct3D 10 では完全に足並みが揃って、GeForce も RADEON もほとんど
区別せずに同じシェーダーが動くようになっています。
OpenGL ではハードウエア能力の違いよりも、まだまだドライバの差が表面化している感じです。
API 仕様が決まっても、安定するまでしばらく時間がかかるのかもしれません。
関連エントリ
・OpenGL の同期と描画速度の測定
・OpenGL のはじめ方 (2) wgl
・OpenGL 3.2 GeometryShader をもう少し使ってみる
・OpenGL GLSL のバージョン
・OpenGL 3.2 の GeometryShader
・OpenGL のはじめ方
生成しています。
実行時はさらにドライバが GPU 毎のネイティブコードに最適化&変換を行っています。
一見二度手間ですが、最初の最適化は共通バイトコードへの変換時に済んでいます。
時間のかかる巨大なシェーダーでも事前に変換しておくことが可能だし、コンパイラ部の
最適化の恩恵はすべての GPU で受けられます。
ドライバも共通コードからの変換だけ行えばよいので、互換性も比較的維持しやすいのでは
ないかと考えられます。
その代わり一度バイナリにしてしまうと、コンパイルした時点のコンパイラの能力である程度
固定されます。あとからコンパイラが強化される可能性もあるし、GPU が ShaderModel 5.0
対応になっても、3.0 向けにコンパイルしたシェーダーで能力を出し切れるとは限りません。
OpenGL の GLSL の場合 API が受け取るのは生のソースコードです。
コンパイルそのものが GPU ドライバの役目となっていて、中間の共通コードがありません。
動的にコンパイルするメリットは常にハードに最適なプロファイルを選べることです。
逆にデメリットとしては、コンパイル時間がかかるのではないかとの懸念もありますが
もっと別の問題もあるようです。
今まで GeForce で組み立ててきたコードを RADEON で走らせてみました。
環境は下記の通り。
GeForce 9800GT 190.62 (GL 3.1 GLSL 1.4) WHQL GeForce GTX280 190.57 (GL 3.2 GLSL 1.5) RADEON HD 4760 Catalyst 9.9 (GL 3.1 GLSL 1.4)
● Version 指定
RADEON の GLSL では「#version」はソースコードの先頭にないとエラーになります。
・#version の前にプリプロセッサ命令があるだけでもだめ。
・glShaderSource() に複数のソースコードを渡している場合、最初のコードの先頭でないとだめ。2番目以降のソースコードには記述できない。
この挙動は OpenGLES 2.0 の GLSL と同じです。また GLSLangSpec.Full.1.40.05.pdf
を見ても、#version の前に許されるのはコメントとホワイトスぺースのみと記載されています。
こちらの動作の方が正解でした。
ただプリプロセッサ命令も許されていないので、複数のターゲット間で互換性ととる場合に
version 指定を分岐できないのは不便です。C 言語側の Shader Loader 部分に手を加えて、
独自のプリプロセッサを追加するなどの対策が必要かもしれません。
● precision 指定
OpenGL ES の GLSL から取り入れた仕様として precision 指定があります。
宣言時に変数が必要とする精度のヒントを与えます。
highp, middlep, lowp の 3段階ありますが
・GeForce は in/out 宣言の前に必要
・RADEON は in/out 宣言の後ろ書かないとエラー
RADEON の場合必ず何らかの精度指定が必須で、個別指定かまたはデフォルトの
precision 行が必要です。GeForce は無くても通ります。
とりあえず最初にデフォルト宣言をしておけばどちらでも通ります。
細かく個別に宣言をしている場合は注意。
precision highp float;
ドキュメントを見る限り RADEON の方が正しいようです。
全体的に GeForce の方が判定が緩く RADEON の方が厳密になっています。
GPU のドライバ毎にコンパイラの仕様が異なっている可能性を考えると、
Direct3D + HLSL のように共通化されている方が楽だと思います。
慣れるまではこれらの互換性の維持に苦労しそうです。
●OpenGL 3.1
現段階で OpenGL 3.2/GLSL 1.5 に対応しているのは GeForce 190.57 だけです。
RADEON で試すにあたって OpenGL 3.1/GLSL 1.4 で動作するように修正しました。
GeForce の場合、最初に wglCreateContext() で作った Context がすでに
OpenGL 3.x に対応していました。
wglCreateContextAttribsARB() で作り直さなくても動作します。
RADEON の場合 OpenGL 2.1 だったので、wglCreateContextAttribsARB() が必要です。
でもシェーダーバージョンは同じ。
// GeForce 190.57 // wglCreateContext() GL VERSION: 3.2.0 GL RENDERER: GeForce GTX 280/PCI/SSE2 GL VENDOR: NVIDIA Corporation GL SHADING_LANGUAGE_VERSION: 1.50 NVIDIA via Cg compiler ↓ // wglCreateContextAttribsARB() GL VERSION: 3.1.0 GL RENDERER: GeForce GTX 280/PCI/SSE2 GL VENDOR: NVIDIA Corporation GL SHADING_LANGUAGE_VERSION: 1.40 NVIDIA via Cg compiler // GeForce 190.62 // wglCreateContext() GL_VERSION: 3.1.0 GL_RENDERER: GeForce 9800 GT/PCI/SSE2 GL_VENDOR: NVIDIA Corporation GL_SHADING_LANGUAGE_VERSION: 1.40 NVIDIA via Cg compiler ↓ // wglCreateContextAttribsARB() GL_VERSION: 3.1.0 GL_RENDERER: GeForce 9800 GT/PCI/SSE2 GL_VENDOR: NVIDIA Corporation GL_SHADING_LANGUAGE_VERSION: 1.40 NVIDIA via Cg compiler
// RADEON 9.9 // wglCreateContext() GL_VERSION: 2.1.8918 GL_RENDERER: ATI Radeon HD 4600 Series GL_VENDOR: ATI Technologies Inc. GL_SHADING_LANGUAGE_VERSION: 1.40 ↓ // wglCreateContextAttribsARB() GL_VERSION: 3.1.8918 GL_RENDERER: ATI Radeon HD 4600 Series GL_VENDOR: ATI Technologies Inc. GL_SHADING_LANGUAGE_VERSION: 1.40
● Extension の判定
GeForce 190.57 を Version 3.1 で作り直した場合のはまりです。
Extension の判定で glGetString( GL_EXTENSIONS ) を参照していましたが、
Context を作り直すとエラーになります。
ドキュメントをよく見ると glGetString( GL_EXTENSIONS ) は古い仕様で、
OpenGL 3.x の場合は
glGetIntegerv( GL_NUM_EXTENSIONS, .. ) glGetStringi( GL_EXTENSIONS, .. )
を用いるのが正しいやり方のようです。
WGL_CONTEXT_FLAGS_ARB を 0 にしても
WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB がセットされてしまうことが
原因のようです。
190.62 では WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB を指定しない限り
大丈夫でした。
互換性周りはまだ慣れてないせいか、または出来るだけ共通で動かそうと欲張っている
せいか苦労しています。
Direct3D の場合問題になる互換性はハードウエア能力の差でした。
その後 Direct3D 10 では完全に足並みが揃って、GeForce も RADEON もほとんど
区別せずに同じシェーダーが動くようになっています。
OpenGL ではハードウエア能力の違いよりも、まだまだドライバの差が表面化している感じです。
API 仕様が決まっても、安定するまでしばらく時間がかかるのかもしれません。
関連エントリ
・OpenGL の同期と描画速度の測定
・OpenGL のはじめ方 (2) wgl
・OpenGL 3.2 GeometryShader をもう少し使ってみる
・OpenGL GLSL のバージョン
・OpenGL 3.2 の GeometryShader
・OpenGL のはじめ方
2009/09/13
DirectX SDK August 2009 texconvex のデータ化け
前回書いた BC6H/BC7 のデータ化けですが BC1/DXT1 でも同様の問題が発生する
ことがわかりました。texconvex.exe に何らかの問題があるようです。
DirectX SDK August 2009 付属 texconv.exe と texconvex.exe を、それぞれ
x86 と x64 で比較してみました。
変換スクリプト(バッチ)
入力は 512x512 サイズの bmp。mipmap 無し。
texconv と texconvex で出力拡張子の大文字小文字がばらばらなのも気になるところ。
出力ファイルサイズはすべて同一です。つまり 512*512*2 = 131072 、
131072 + 128 = 131200 なので、128byte の DDS ヘッダのみ追加されている状態です。
DXT10 ヘッダ (Direct3D 10 拡張ヘッダ) は存在していないことになります。
バイナリを比較すると、texconv を用いた下記 2ファイルは完全に同一です。
使用したコンバータが x86 か x64 だけの違いなので、一致していないと困ります。
・dx9_dxt1_64_t000.dds
・dx9_dxt1_86_t000.dds
texconvex を用いた dx10~, dx11~ の各ファイルはお互いにどれとも一致しませんでした。
それどころかコンバータを実行するたびにバイト単位で相違が生じています。
↓正常なファイル (dx9_dxt1_86_t000.dds)
↓問題のファイル (dx11_bc1_86_t000.dds)
・データ本体の先頭 16byte が欠けている
・データ本体の先頭に 32byte のゴミデータが挿入されている
・データ本体が 16byte 下がっている
これはまだましな方です。
dx10_bc1_64_t000.dds の場合 224byte の不明なデータが挿入されていました。
この症状は、以前下記エントリで試した texconv10.exe の頃と変わっていないような気がします。
・Direct3D10 と DDS テクスチャフォーマット
ヘッダ部分の相違は下記の通り。こちらは特に問題は無いです。
texconvex で出力フォーマットの指定を R8G8B8A8_UNORM にするとデータが全部ゼロで埋められてしまいます。
関連エントリ
・DirectX SDK August 2009 の解説と Direct3D 11 RTM
・Direct3D10 と DDS テクスチャフォーマット
ことがわかりました。texconvex.exe に何らかの問題があるようです。
DirectX SDK August 2009 付属 texconv.exe と texconvex.exe を、それぞれ
x86 と x64 で比較してみました。
変換スクリプト(バッチ)
set DXSDK_UTILBIN=${DXSDK_DIR}Utilities/bin set BIN86=$DXSDK_UTILBIN/x86 set BIN64=$DXSDK_UTILBIN/x64 set CONV86=$BIN86/texconv.exe set CONVEX86=$BIN86/texconvex.exe set CONV86=$BIN64/texconv.exe set CONVEX86=$BIN64/texconvex.exe $CONV86 -ft dds -f DXT1 -m 1 -px dx9_dxt1_86_ t000.bmp $CONV64 -ft dds -f DXT1 -m 1 -px dx9_dxt1_64_ t000.bmp $CONVEX86 -10 -ft dds -f BC1_UNORM -m 1 -px dx10_bc1_86_ t000.bmp $CONVEX64 -10 -ft dds -f BC1_UNORM -m 1 -px dx10_bc1_64_ t000.bmp $CONVEX86 -11 -ft dds -f BC1_UNORM -m 1 -px dx11_bc1_86_ t000.bmp $CONVEX64 -11 -ft dds -f BC1_UNORM -m 1 -px dx11_bc1_64_ t000.bmp hexdump dx9_dxt1_86_t000.dds > dx9_dxt1_86_t000.txt hexdump dx9_dxt1_64_t000.dds > dx9_dxt1_64_t000.txt hexdump dx10_bc1_86_t000.dds > dx10_bc1_86_t000.txt hexdump dx10_bc1_64_t000.dds > dx10_bc1_64_t000.txt hexdump dx11_bc1_86_t000.dds > dx11_bc1_86_t000.txt hexdump dx11_bc1_64_t000.dds > dx11_bc1_64_t000.txt
入力は 512x512 サイズの bmp。mipmap 無し。
texconv と texconvex で出力拡張子の大文字小文字がばらばらなのも気になるところ。
131200 dx9_dxt1_64_t000.dds 131200 dx9_dxt1_86_t000.dds 131200 dx10_bc1_64_t000.DDS 131200 dx10_bc1_86_t000.DDS 131200 dx11_bc1_64_t000.DDS 131200 dx11_bc1_86_t000.DDS
出力ファイルサイズはすべて同一です。つまり 512*512*2 = 131072 、
131072 + 128 = 131200 なので、128byte の DDS ヘッダのみ追加されている状態です。
DXT10 ヘッダ (Direct3D 10 拡張ヘッダ) は存在していないことになります。
バイナリを比較すると、texconv を用いた下記 2ファイルは完全に同一です。
使用したコンバータが x86 か x64 だけの違いなので、一致していないと困ります。
・dx9_dxt1_64_t000.dds
・dx9_dxt1_86_t000.dds
texconvex を用いた dx10~, dx11~ の各ファイルはお互いにどれとも一致しませんでした。
それどころかコンバータを実行するたびにバイト単位で相違が生じています。
↓正常なファイル (dx9_dxt1_86_t000.dds)
00000000 : 44 44 53 20 7c 00 00 00 07 10 00 00 00 02 00 00 DDS |........... 00000010 : 00 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000020 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000030 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000040 : 00 00 00 00 00 00 00 00 00 00 00 00 20 00 00 00 ............ ... 00000050 : 04 00 00 00 44 58 54 31 00 00 00 00 00 00 00 00 ....DXT1........ 00000060 : 00 00 00 00 00 00 00 00 00 00 00 00 00 10 00 00 ................ 00000070 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000080 : a7 5b 23 11 d7 3f 0a 8a 49 6c 84 19 5e de a0 ca ここからデータ 00000090 : 74 9d e6 31 fd 3b 2b ed 91 9d e5 29 fa 58 16 d7 000000a0 : f6 ce c8 42 75 ff a8 af cc 84 e2 21 b7 aa f0 5e 000000b0 : eb 8c 61 2a c2 ca 7b ea 57 df c2 21 2f ad f5 d5 000000c0 : 92 be e2 29 82 02 a9 55 93 be a0 19 5f fe 0a a2 000000d0 : 57 d7 e2 3a 77 ea a0 a2 32 ae e6 4a 25 95 b8 c2 000000e0 : 79 e7 e8 4a 2a 28 b7 a5 36 d7 26 5b d6 b8 00 e0 000000f0 : d2 be e3 42 fc e2 e0 b7 4f be 82 32 ff d7 3a f8 00000100 : cd b5 80 21 a5 ea 5c f7 6d 7c 81 21 aa 22 d5 df
↓問題のファイル (dx11_bc1_86_t000.dds)
00000000 : 44 44 53 20 7c 00 00 00 06 00 00 00 00 02 00 00 DDS |........... 00000010 : 00 02 00 00 00 04 00 00 00 00 00 00 01 00 00 00 ................ 00000020 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000030 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000040 : 00 00 00 00 00 00 00 00 00 00 00 00 20 00 00 00 ............ ... 00000050 : 04 00 00 00 44 58 54 31 04 00 00 00 00 00 00 00 ....DXT1........ 00000060 : 00 00 00 00 00 00 00 00 00 00 00 00 00 10 00 00 ................ 00000070 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000080 : 00 00 00 00 00 00 00 00 24 2a 00 0e 24 86 08 00 00000090 : 80 00 4d 02 00 00 00 00 20 da 0d 00 00 00 00 00 000000a0 : 74 9d e6 31 fd 3b 2b ed 91 9d e5 29 fa 58 16 d7 000000b0 : f6 ce c8 42 75 ff a8 af cc 84 e2 21 b7 aa f0 5e 000000c0 : eb 8c 61 2a c2 ca 7b ea 57 df c2 21 2f ad f5 d5 000000d0 : 92 be e2 29 82 02 a9 55 93 be a0 19 5f fe 0a a2 000000e0 : 57 d7 e2 3a 77 ea a0 a2 32 ae e6 4a 25 95 b8 c2 000000f0 : 79 e7 e8 4a 2a 28 b7 a5 36 d7 26 5b d6 b8 00 e0 00000100 : d2 be e3 42 fc e2 e0 b7 4f be 82 32 ff d7 3a f8
・データ本体の先頭 16byte が欠けている
・データ本体の先頭に 32byte のゴミデータが挿入されている
・データ本体が 16byte 下がっている
これはまだましな方です。
dx10_bc1_64_t000.dds の場合 224byte の不明なデータが挿入されていました。
この症状は、以前下記エントリで試した texconv10.exe の頃と変わっていないような気がします。
・Direct3D10 と DDS テクスチャフォーマット
ヘッダ部分の相違は下記の通り。こちらは特に問題は無いです。
・texconv (dx9) dwFlags= 0x00001007 = DDSD_PIXELFORMAT|DDSD_WIDTH|DDSD_HEIGHT|DDSD_CAPS dwPitchOrLinearSize= 0 (DDSD_LINEARSIZE が無いので無視できる) dwDepth= 0 (DDSD_DEPTH が無いので無視できる) dwMipMapCount= 0 (DDSD_MIPMAP が無いので無視できる) ・texconvex (dx11) dwFlags= 0x00000006 = DDSD_WIDTH|DDSD_HEIGHT dwPitchOrLinearSize= 0x400 (DDSD_LINEARSIZE が無いので無視できる) dwDepth= 1 (DDSD_DEPTH が無いので無視できる) dwMipMapCount= 1 (DDSD_MIPMAP が無いので無視できる) ・共通 dwSize = 0x007c = 124 = ヘッダサイズ dwWidth = 0x0200 = 512 dwHeight = 0x0200 = 512 dwPfSize = 0x0020 = 32 = PIXELFORMAT サイズ dwPfFlags= 0x0004 = DDPF_FOURCC dwFourCC = "DXT1" dwCaps = 0x1000 = DDSCAPS_TEXTURE
texconvex で出力フォーマットの指定を R8G8B8A8_UNORM にするとデータが全部ゼロで埋められてしまいます。
関連エントリ
・DirectX SDK August 2009 の解説と Direct3D 11 RTM
・Direct3D10 と DDS テクスチャフォーマット
2009/09/11
DirectX SDK August 2009 の解説と Direct3D 11 RTM
DirectX SDK August 2009 が出ています。
ついに Direct3D 11 の RTM 対応となりました。
・DirectX SDK (August 2009)
D3D11 自体は Windows 7 や Windows SDK for Windows7 で RTM 版が出ています。
デバッグ向けライブラリや D3DX、ツールを含んだ SDK としてはこれが最初です。
これで安心して Windows7 RTM 環境へ移行できそうです。
●大きなトピック
予想通りベータ版で欠けていた機能が追加されました。
例えば
・Effect (fx)
・BC6/7 対応コンバータ
特に Effect はベータに入っていてもおかしくない大きなコンポーネントです。
もしかして SDK のリリースが遅れた原因もこのあたりでしょうか。
マニュアルの完成度は高く、大幅に更新されているようです。
ドキュメントも March SDK で足りなかった各項目が埋まっており、説明も増えて結構
力が入っています。かなり好印象です。
また今回新たに明らかになった点もいくつかあります。特に次の 2つ
● FeatureLevel 9_3 は ShaderModel 2.0 だった
最初マニュアルの表記ミスかと思いました。
CapsViewer でも確かに 2.0 と表示されるので間違いではないようです。
● CapsViewer が復活した!!
FeatureLevel 登場時から結局 caps と同じことではないかと心配しましたが、
今回のリリースではそれを正式に認めたようなもの。
本当に CapsViewer に組み込まれてしまいました。
DXCapsViewer.exe を起動すると DXGI 1.1 Devices の欄が追加されています。
それぞれの FeatureLevel 毎に対応機能やフォーマットなど、各ドライバの対応状況を
確認することが出来ます。

●D3DCSX が追加された
D3DX の ComputeShader 版です。prefix は D3DX のまま。
D3DX*.dll, D3DCompiler*.dll のように、番号付きの dll が今後追加されていく
ことになるようです。
●バージョンと互換性
SDK のメジャー番号は 9 のままです。
厳密には DirectX 9 SDK の中に Direct3D 10 や Direct3D 11 が含まれている
扱いになります。とはいえ、便宜上 DirectX 11 と表記することも多いです。
DirectX だけでなく Direct2D や DirectWrite も含まれています。
Vista でも動作します。
●ID3D11DeviceContext の更新
・追加
ID3D11DeviceContext::CopyStructureCount()
・削除
ID3D11DeviceContext::GetTextFilterSize()
ID3D11DeviceContext::SetTextFilterSize()
以前 DebugLayer が動かなかった原因はこの辺にありそうです。
● D3D11_PRIMITIVE の追加
enum D3D11_PRIMITIVE が追加されています。
似たようなシンボルとしてすでに D3D11_PRIMITIVE_TOPOLOGY が存在しています。
定義を見ると STRIP 形式が外されているようです。D3D11_PRIMITIVE は唯一
D3D11_SHADER_DESC の中で用いられています。考えられる用途は下記の通りです。
・D3D11_PRIMITIVE_TOPOLOGY ( strip あり )
IA や SO など strip 形式を含めたプリミティブの指定。
・D3D11_PRIMITIVE ( strip 無し )
GeometryShader / HullShader など、頂点ストリームやキャッシュを通過し、
Triangle (Primitive) 単位で入力が必要なシェーダーの指定で用いる。
● BC6H/BC7 texture
新しい圧縮テクスチャフォーマットです。繰り返しになりますが、従来 DXT と
呼ばれていたフォーマットは Direct3D 10 より BC に名称が変わっています。
付属のコマンドラインツール texconvex.exe を使うと実際に BC6H/BC7 で圧縮できる
ようになりました。DxTex.exe などそれ以外のツールは Direct3D 9 のテクスチャしか
扱えないので要注意です。
実際に試しましたが、圧縮は非常に低速です。
最初 1600x1200 のデータを渡してしまってかなり後悔しました。
結局中断して 640x480 でやり直したくらい。それでも結構待たされています。
Core i7 920 なのに。
リファレンスデバイスを指定したアプリを作れば一応読み込むことが出来ました。
ただデータの一部が化けており正しく出ていない可能性があります。
DXT10 形式の dds データ化けは以前もあったので、使い方のミスかツール側の
問題かもしれません。
DXT10 ヘッダを追加した dds テクスチャは D3D10 で登場したものの、対応したツール
はまだあまり出ていません。128byte + 20byte と中途半端なヘッダサイズになって
しまうため、一括ロードだと SSE 対応も難しいという欠点があります。
●残るは GPU (とドライバ)
とりあえず 9_3 の Shader Model 2.0 と、DXCapsViewer には驚きました。
Direct3D 8 の改革が Direct3D 9 で完成したように、
Direct3D 10 で目指したものの完成形が Direct3D 11 だといえるでしょう。
手持ちのコードは March 2009 から Direct3D 11 に移行しましたが、互換性も取れる
ようになったし、かなり使いやすい印象です。
あとは対応 GPU が発売されるのを待つばかり。
関連エントリ
・Direct3D11 Windows7 RTM と DebugLayer
・Direct3D11/DirectX11 ComputeShader 4.0 を使う
・DirectX SDK March 2009
・Gamefest2008 と Direct3D 11
・Direct3D10 と DDS テクスチャフォーマット
ついに Direct3D 11 の RTM 対応となりました。
・DirectX SDK (August 2009)
D3D11 自体は Windows 7 や Windows SDK for Windows7 で RTM 版が出ています。
デバッグ向けライブラリや D3DX、ツールを含んだ SDK としてはこれが最初です。
これで安心して Windows7 RTM 環境へ移行できそうです。
●大きなトピック
予想通りベータ版で欠けていた機能が追加されました。
例えば
・Effect (fx)
・BC6/7 対応コンバータ
特に Effect はベータに入っていてもおかしくない大きなコンポーネントです。
もしかして SDK のリリースが遅れた原因もこのあたりでしょうか。
マニュアルの完成度は高く、大幅に更新されているようです。
ドキュメントも March SDK で足りなかった各項目が埋まっており、説明も増えて結構
力が入っています。かなり好印象です。
また今回新たに明らかになった点もいくつかあります。特に次の 2つ
● FeatureLevel 9_3 は ShaderModel 2.0 だった
最初マニュアルの表記ミスかと思いました。
CapsViewer でも確かに 2.0 と表示されるので間違いではないようです。
11_0 sm5.0 10_1 sm4.1 10_0 sm4.0 9_3 sm2.0 (4_0_level_9_3) << ここ 9_2 sm2.0 (4_0_level_9_1) 9_1 sm2.0 (4_0_level_9_1)
● CapsViewer が復活した!!
FeatureLevel 登場時から結局 caps と同じことではないかと心配しましたが、
今回のリリースではそれを正式に認めたようなもの。
本当に CapsViewer に組み込まれてしまいました。
DXCapsViewer.exe を起動すると DXGI 1.1 Devices の欄が追加されています。
それぞれの FeatureLevel 毎に対応機能やフォーマットなど、各ドライバの対応状況を
確認することが出来ます。

●D3DCSX が追加された
D3DX の ComputeShader 版です。prefix は D3DX のまま。
D3DX*.dll, D3DCompiler*.dll のように、番号付きの dll が今後追加されていく
ことになるようです。
●バージョンと互換性
SDK のメジャー番号は 9 のままです。
厳密には DirectX 9 SDK の中に Direct3D 10 や Direct3D 11 が含まれている
扱いになります。とはいえ、便宜上 DirectX 11 と表記することも多いです。
DirectX だけでなく Direct2D や DirectWrite も含まれています。
Vista でも動作します。
●ID3D11DeviceContext の更新
・追加
ID3D11DeviceContext::CopyStructureCount()
・削除
ID3D11DeviceContext::GetTextFilterSize()
ID3D11DeviceContext::SetTextFilterSize()
以前 DebugLayer が動かなかった原因はこの辺にありそうです。
● D3D11_PRIMITIVE の追加
enum D3D11_PRIMITIVE が追加されています。
似たようなシンボルとしてすでに D3D11_PRIMITIVE_TOPOLOGY が存在しています。
定義を見ると STRIP 形式が外されているようです。D3D11_PRIMITIVE は唯一
D3D11_SHADER_DESC の中で用いられています。考えられる用途は下記の通りです。
・D3D11_PRIMITIVE_TOPOLOGY ( strip あり )
IA や SO など strip 形式を含めたプリミティブの指定。
・D3D11_PRIMITIVE ( strip 無し )
GeometryShader / HullShader など、頂点ストリームやキャッシュを通過し、
Triangle (Primitive) 単位で入力が必要なシェーダーの指定で用いる。
● BC6H/BC7 texture
新しい圧縮テクスチャフォーマットです。繰り返しになりますが、従来 DXT と
呼ばれていたフォーマットは Direct3D 10 より BC に名称が変わっています。
BC1 4bpp ← DXT1 BC2 8bpp ← DXT2/3 BC3 8bpp ← DXT4/5 BC4 4bpp ← 1チャンネル圧縮 BC5 8bpp ← 2チャンネル圧縮, 法線圧縮 (3Dc/ATI2) BC6 8bpp ← (BC6H_UF16, BC6H_SF16) BC7 8bpp ← (BC7_UNORM, BC7_UNORM_SRGB)
付属のコマンドラインツール texconvex.exe を使うと実際に BC6H/BC7 で圧縮できる
ようになりました。DxTex.exe などそれ以外のツールは Direct3D 9 のテクスチャしか
扱えないので要注意です。
実際に試しましたが、圧縮は非常に低速です。
最初 1600x1200 のデータを渡してしまってかなり後悔しました。
結局中断して 640x480 でやり直したくらい。それでも結構待たされています。
Core i7 920 なのに。
リファレンスデバイスを指定したアプリを作れば一応読み込むことが出来ました。
ただデータの一部が化けており正しく出ていない可能性があります。
DXT10 形式の dds データ化けは以前もあったので、使い方のミスかツール側の
問題かもしれません。
DXT10 ヘッダを追加した dds テクスチャは D3D10 で登場したものの、対応したツール
はまだあまり出ていません。128byte + 20byte と中途半端なヘッダサイズになって
しまうため、一括ロードだと SSE 対応も難しいという欠点があります。
●残るは GPU (とドライバ)
とりあえず 9_3 の Shader Model 2.0 と、DXCapsViewer には驚きました。
Direct3D 8 の改革が Direct3D 9 で完成したように、
Direct3D 10 で目指したものの完成形が Direct3D 11 だといえるでしょう。
手持ちのコードは March 2009 から Direct3D 11 に移行しましたが、互換性も取れる
ようになったし、かなり使いやすい印象です。
あとは対応 GPU が発売されるのを待つばかり。
関連エントリ
・Direct3D11 Windows7 RTM と DebugLayer
・Direct3D11/DirectX11 ComputeShader 4.0 を使う
・DirectX SDK March 2009
・Gamefest2008 と Direct3D 11
・Direct3D10 と DDS テクスチャフォーマット
2009/09/10
OpenGL の同期と描画速度の測定
そろそろパフォーマンスの測定もしようと思い同期周りを調べてみます。
ゲームでは CPU と GPU の同期の設計が重要です。描画パフォーマンス優先なら CPU と
GPU ができるだけ並列動作するようにスケジューリングしておきます。
動的な頂点生成で CPU からデータを転送する場合、またはクエリによって GPU の結果を
CPU で受け取る場合など、お互いに待っている時間をなくすようにします。
ここで間違うとパフォーマンスに大きく影響を与えることがあります。
●インターバルの設定
Direct3D 同様に描画時間の管理を自前で行っていたのですが、ウエイト無しにしても
必ず 60fps 前後で止まってしまうことに気がつきました。
ヘッダを見ていたら wglSwapIntervalEXT() を見つけたので使えるか確認。
GeForce GTX280 + 190.57 、"WGL_EXT_swap_control" が含まれています。
これで Display と同期せずに最大速度で描画するようになりました。
モニタのリフレッシュレート依存だと思いますが、 1 を与えると 60fps 固定、
2でその半分となりました。
●フェンス
D3D では ID3D11Query を用いて GPU の状態を受け取ることが出来ます。
レンダリングしたピクセル数、演算頂点数といったレンダリング結果の問い合わせだけでなく、
同期のための Event (Fence) や TimeStamp も含まれています。
OpenGL にも glBeginQuery() ~ glEndQuery() があります。
こちらはもともと実際にレンダリングした pixel 数を返す Occlusion Query の機能だった
ようです。Direct3D にも昔からあるもので、この手のオクルージョン判定は高速化のためと
言うよりレンズフレアの描画などに用いられていました。
同期用の機能は別の API になっていて、glSyncFence() を使います。
fence は描画コマンドと同じように PushBuffer (CommandBuffer) に記録されます。
レンダリングが fence に到達すると、対応する同期オブジェクトを Signal 状態にします。
CPU では同期オブジェクトの状態を見ることで、描画の進行具合と同期を取ることが出来ます。
glClientWaitSync() は Timeout 時間を指定可能で、状態を返すことが出来ます。
glWaitSync() は Signal 状態になるまで、つまり完了するまでブロックします。
glSynciv() を用いて、現在の状態を参照することも出来るようです。
SwapBuffers() の動作をまだ厳密につかんでいないので、これで正しいかどうか
必要なのかどうかもわかりませんが、同期の例としてはこんな感じで。
●速度の測定
当初 TimeStamp が見つからなかったのですが Extension の方にありました。
GL_EXT_timer_query です。GeForce は対応していました。
glBeginQuery() ~ glEndQuery() が拡張されていて、GPU 処理の経過時間を
計測することが出来ます。
Begin ~ End 区間に発行した GPU 命令の実行時間が返ります。値は nano 秒です。
Direct3D とは少々使い方が異なります。D3D11_QUERY_TIMESTAMP の場合は絶対時間、
つまり GPU クロックの参照に相当し、かつ単位は GPU/ドライバ によって異なります。
また計測期間が連続しているとは限らないため、その結果も受け取る必要があります。
D3D11_QUERY_TIMESTAMP_DISJOINT はこれらの追加情報を返します。
実際に用いる場合は query を 2重化して、1~2フレーム前の結果を受け取るようにします。
これで数値がとれるようになったので、あとは実際に試すだけです。

↑計測の例
OpenGL ES にはこの手の API が無いので、出来れば一通り追加して欲しいところです。
関連エントリ
・OpenGL のはじめ方 (2) wgl
・OpenGL 3.2 GeometryShader をもう少し使ってみる
・OpenGL GLSL のバージョン
・OpenGL 3.2 の GeometryShader
・OpenGL のはじめ方
・OpenGL ES 2.0 Emulator
・OpenGL ES 2.0
・OpenGLES2.0 DDS テクスチャを読み込む
・OpenGLES2.0 Direct3D とのフォーマット変換
・OpenGLES 2.0 頂点フォーマットの管理
・OpenGLES2.0 の頂点
・OpenGLES2.0 D3D座標系
・OpenGLES2.0 シェーダー管理
ゲームでは CPU と GPU の同期の設計が重要です。描画パフォーマンス優先なら CPU と
GPU ができるだけ並列動作するようにスケジューリングしておきます。
動的な頂点生成で CPU からデータを転送する場合、またはクエリによって GPU の結果を
CPU で受け取る場合など、お互いに待っている時間をなくすようにします。
ここで間違うとパフォーマンスに大きく影響を与えることがあります。
●インターバルの設定
Direct3D 同様に描画時間の管理を自前で行っていたのですが、ウエイト無しにしても
必ず 60fps 前後で止まってしまうことに気がつきました。
ヘッダを見ていたら wglSwapIntervalEXT() を見つけたので使えるか確認。
GeForce GTX280 + 190.57 、"WGL_EXT_swap_control" が含まれています。
wglSwapIntervalEXT( 0 );
これで Display と同期せずに最大速度で描画するようになりました。
モニタのリフレッシュレート依存だと思いますが、 1 を与えると 60fps 固定、
2でその半分となりました。
●フェンス
D3D では ID3D11Query を用いて GPU の状態を受け取ることが出来ます。
レンダリングしたピクセル数、演算頂点数といったレンダリング結果の問い合わせだけでなく、
同期のための Event (Fence) や TimeStamp も含まれています。
OpenGL にも glBeginQuery() ~ glEndQuery() があります。
こちらはもともと実際にレンダリングした pixel 数を返す Occlusion Query の機能だった
ようです。Direct3D にも昔からあるもので、この手のオクルージョン判定は高速化のためと
言うよりレンズフレアの描画などに用いられていました。
同期用の機能は別の API になっていて、glSyncFence() を使います。
fence は描画コマンドと同じように PushBuffer (CommandBuffer) に記録されます。
レンダリングが fence に到達すると、対応する同期オブジェクトを Signal 状態にします。
CPU では同期オブジェクトの状態を見ることで、描画の進行具合と同期を取ることが出来ます。
// 挿入 GLsync SyncObject; SyncObject= glFenceSync( GL_SYNC_GPU_COMMANDS_COMPLETE, 0 ); // 同期待ち glClientWaitSync( SyncObject, 0, 0 ); // no wait glWaitSync( SyncObject, 0, GL_TIMEOUT_IGNORED ); // 削除 glDeleteSync( SyncObject );
glClientWaitSync() は Timeout 時間を指定可能で、状態を返すことが出来ます。
glWaitSync() は Signal 状態になるまで、つまり完了するまでブロックします。
glSynciv() を用いて、現在の状態を参照することも出来るようです。
SwapBuffers() の動作をまだ厳密につかんでいないので、これで正しいかどうか
必要なのかどうかもわかりませんが、同期の例としてはこんな感じで。
static GLsync SyncObject[2]; static int SyncCurrent= 0; static int FenceCount= 0; void Render() { ~ SyncObject[SyncCurrent]= glFenceSync( GL_SYNC_GPU_COMMANDS_COMPLETE, 0 ); SwapBuffers( hDC ); Current^= 1; if( FenceCount ){ glWaitSync( SyncObject[SyncCurrent], 0, GL_TIMEOUT_IGNORED ); glDeleteSync( SyncObject[SyncCurrent] ); } FenceCount= 1; }
●速度の測定
当初 TimeStamp が見つからなかったのですが Extension の方にありました。
GL_EXT_timer_query です。GeForce は対応していました。
glBeginQuery() ~ glEndQuery() が拡張されていて、GPU 処理の経過時間を
計測することが出来ます。
// 作成 const int maxid= 8; GLuint idbuffer[maxid]; glGenQueries( maxid, idbuffer ); // 削除 glDeleteQueries( maxid, idbuffer ); // 計測 glBeginQuery( GL_TIME_ELAPSED_EXT, idbuffer[0] ); ~ // 計測期間 glEndQuery( GL_TIME_ELAPSED_EXT ); // 結果が準備できているか調べる&待つ GLuint qret= FALSE; do{ glGetQueryObjectuiv( id, GL_QUERY_RESULT_AVAILABLE, &qret ); }while( qret != TRUE ); // 計測結果の受け取り GLuint64EXT data= 0; glGetQueryObjectui64vEXT( id, GL_QUERY_RESULT, &data );
Begin ~ End 区間に発行した GPU 命令の実行時間が返ります。値は nano 秒です。
Direct3D とは少々使い方が異なります。D3D11_QUERY_TIMESTAMP の場合は絶対時間、
つまり GPU クロックの参照に相当し、かつ単位は GPU/ドライバ によって異なります。
また計測期間が連続しているとは限らないため、その結果も受け取る必要があります。
D3D11_QUERY_TIMESTAMP_DISJOINT はこれらの追加情報を返します。
実際に用いる場合は query を 2重化して、1~2フレーム前の結果を受け取るようにします。
これで数値がとれるようになったので、あとは実際に試すだけです。

↑計測の例
OpenGL ES にはこの手の API が無いので、出来れば一通り追加して欲しいところです。
関連エントリ
・OpenGL のはじめ方 (2) wgl
・OpenGL 3.2 GeometryShader をもう少し使ってみる
・OpenGL GLSL のバージョン
・OpenGL 3.2 の GeometryShader
・OpenGL のはじめ方
・OpenGL ES 2.0 Emulator
・OpenGL ES 2.0
・OpenGLES2.0 DDS テクスチャを読み込む
・OpenGLES2.0 Direct3D とのフォーマット変換
・OpenGLES 2.0 頂点フォーマットの管理
・OpenGLES2.0 の頂点
・OpenGLES2.0 D3D座標系
・OpenGLES2.0 シェーダー管理
2009/09/09
iPhone アプリが瞬間的に落ちる心地よさ
iPhone 3GS 使っていて久しぶりに Safari が落ちました。
iPhone の偉いところは、一切ためらわずにアプリが即時落ちること。
この潔さは心地よいとすらいえます。
これが WindowsMobile や PocketPC だと…
・なんだかアプリが重くなってくる
・反応が鈍いなと思いつつ粘ろうとする
・しばらく円グラフがぐるぐる回って操作できなくなる
・さらにしばらく待って完全に固まったことを確認
・諦めてリセットボタンを押す
・起動するまでじっと待つ。1分以上かかる。
この間、実に数分間を無駄にすることになります。
iPhone では問題が発生したアプリが即時終了してくれるおかげで
・待たせない
ユーザーが操作を選択できる状態に戻ります。
すぐに同じアプリを立ち上げてページを開き直すことも出来ます。
また落ちる可能性はありますが、不安定な状態で我慢して使い続けるよりは
起動し直した方がましなはずです。
もしくは、別の同等のアプリに切り替えるという選択も出来ます。
何らかの対策ができるということ。
・システムを巻き込まない
とりあえずすぐに電話受けられる状態に戻ってくれます。
無限ループのようなリセットしなければならない状態は回避されます。
もちろん落ちないのが一番良いわけで根本的な解決はなっていませんが、
リセットするくらいの困った状況はほとんど無くなりました。
回復不可能なのに下手にエラーメッセージが出て待たせたり、固まったりするのは
一番避けるべきことだったのだと思い知らされました。
iPhone の偉いところは、一切ためらわずにアプリが即時落ちること。
この潔さは心地よいとすらいえます。
これが WindowsMobile や PocketPC だと…
・なんだかアプリが重くなってくる
・反応が鈍いなと思いつつ粘ろうとする
・しばらく円グラフがぐるぐる回って操作できなくなる
・さらにしばらく待って完全に固まったことを確認
・諦めてリセットボタンを押す
・起動するまでじっと待つ。1分以上かかる。
この間、実に数分間を無駄にすることになります。
iPhone では問題が発生したアプリが即時終了してくれるおかげで
・待たせない
ユーザーが操作を選択できる状態に戻ります。
すぐに同じアプリを立ち上げてページを開き直すことも出来ます。
また落ちる可能性はありますが、不安定な状態で我慢して使い続けるよりは
起動し直した方がましなはずです。
もしくは、別の同等のアプリに切り替えるという選択も出来ます。
何らかの対策ができるということ。
・システムを巻き込まない
とりあえずすぐに電話受けられる状態に戻ってくれます。
無限ループのようなリセットしなければならない状態は回避されます。
もちろん落ちないのが一番良いわけで根本的な解決はなっていませんが、
リセットするくらいの困った状況はほとんど無くなりました。
回復不可能なのに下手にエラーメッセージが出て待たせたり、固まったりするのは
一番避けるべきことだったのだと思い知らされました。
2009/09/08
NetWalker PC-Z1
SHARP から新しい端末 NetWalker PC-Z1 が出ます。
小型のノート PC の外観とスマートフォン向け CPU を組み合わせたもの。
かつて似たようなデバイスがあったことを思い出します。
ARM や MIPS など組み込み向けの CPU を搭載し、小型でバッテリー寿命長くて
キーボードを搭載した Handheld PC。WindowsCE H/PC Pro や H/PC 2000 のことです。
ポケットに入る小型なものから 9インチ 800x600 の液晶を持ったノート PC クラスまで、
結構いろんなタイプのハードが揃っていました。
普通の PC との違いは HDD が無く軽量の専用 OS を載せていること。
タッチを用いるなど操作性も違うし、動くソフトウエアも限られるけど、
普段からサスペンド状態ですぐ電源が入るなどそれなりに使う意味がありました。
今回の NetWalker が昔の WindowsCE を搭載した H/PC と違うのは
一般の Desktop / Notebook PC 向けにリリースされている Linux 環境を乗せていることです。
Linux ディストリビューションの一つ Ubuntu をそのまま採用しています。
実際ハード的にも ARM Cortex-A8 800MHz に RAM 512MB + SSD。
最初の Netbook もこれくらいの中身だったし、スペック的にも本当に Netbook に
近いことになります。
・初期の Netbook と同等のスペックを持つ
・デスクトップ向けの汎用 OS を使っている
これらが昔のハンドヘルド PC との大きな違いといえるでしょうか。
そこで今回はあえて NetWalker を ARM を使ったノート PC であると定義することにします。
ここで問題となるのは、Atom を使った 小型の PC とほとんど変わらなくなってくるということ。
例えば同じ Linux を動かすにしても、x86 の方が選択肢が多いし情報も多いし、ハードや
ソフトの対応状況を考えても有利ではないかと言うことです。x86 の小型の UMPC とか
Netbook とかに Linux を入れてもほぼ同じように使えるのではないかと考えられます。
それじゃ NetWalker の立場はどうなるのかといえば、それはおそらく
日本のメーカーがはじめて Linux (Ubuntu) だけ に対応した PC を売ろうとしている事実。
(すでに過去に存在していたらごめんなさい)
選択肢として Linux も選べるのではなく最初から Ubuntu だけ。
家電や携帯電話のように内部で利用しているわけではなく、デスクトップとして載せています。
x86 でないからこそできた決断だし x86 だったらメーカーもユーザーもここまで
割り切れなかったのではないでしょうか。
ARM シリーズの性能向上と Atom の省電力化により使われ方も近づいています。
そんな中、ARM を使った PC の特徴となり得るのは Windows を入れたくならないこと
ではないかと、NetWalker を見て思いました。
今後どのような展開になるか興味あるところです。
小型のノート PC の外観とスマートフォン向け CPU を組み合わせたもの。
かつて似たようなデバイスがあったことを思い出します。
ARM や MIPS など組み込み向けの CPU を搭載し、小型でバッテリー寿命長くて
キーボードを搭載した Handheld PC。WindowsCE H/PC Pro や H/PC 2000 のことです。
ポケットに入る小型なものから 9インチ 800x600 の液晶を持ったノート PC クラスまで、
結構いろんなタイプのハードが揃っていました。
普通の PC との違いは HDD が無く軽量の専用 OS を載せていること。
タッチを用いるなど操作性も違うし、動くソフトウエアも限られるけど、
普段からサスペンド状態ですぐ電源が入るなどそれなりに使う意味がありました。
今回の NetWalker が昔の WindowsCE を搭載した H/PC と違うのは
一般の Desktop / Notebook PC 向けにリリースされている Linux 環境を乗せていることです。
Linux ディストリビューションの一つ Ubuntu をそのまま採用しています。
実際ハード的にも ARM Cortex-A8 800MHz に RAM 512MB + SSD。
最初の Netbook もこれくらいの中身だったし、スペック的にも本当に Netbook に
近いことになります。
・初期の Netbook と同等のスペックを持つ
・デスクトップ向けの汎用 OS を使っている
これらが昔のハンドヘルド PC との大きな違いといえるでしょうか。
そこで今回はあえて NetWalker を ARM を使ったノート PC であると定義することにします。
ここで問題となるのは、Atom を使った 小型の PC とほとんど変わらなくなってくるということ。
例えば同じ Linux を動かすにしても、x86 の方が選択肢が多いし情報も多いし、ハードや
ソフトの対応状況を考えても有利ではないかと言うことです。x86 の小型の UMPC とか
Netbook とかに Linux を入れてもほぼ同じように使えるのではないかと考えられます。
それじゃ NetWalker の立場はどうなるのかといえば、それはおそらく
日本のメーカーがはじめて Linux (Ubuntu) だけ に対応した PC を売ろうとしている事実。
(すでに過去に存在していたらごめんなさい)
選択肢として Linux も選べるのではなく最初から Ubuntu だけ。
家電や携帯電話のように内部で利用しているわけではなく、デスクトップとして載せています。
x86 でないからこそできた決断だし x86 だったらメーカーもユーザーもここまで
割り切れなかったのではないでしょうか。
ARM シリーズの性能向上と Atom の省電力化により使われ方も近づいています。
そんな中、ARM を使った PC の特徴となり得るのは Windows を入れたくならないこと
ではないかと、NetWalker を見て思いました。
今後どのような展開になるか興味あるところです。
2009/09/07
WindowsMobile touchkeysip v1.11
いくつか複数の問い合わせが重なったので更新してみました。
使用期間が短いため問題ある場合は引き続き旧バージョンをお使いください。
・touchkeysip v1.11 ソフトウエア入力パネル
●複数の sip 登録
オプション画面を拡張しました。オプション画面の開き方は次の通り。
右上のプルダウンメニューで「Sip 0」~「Sip 2」の切り替えが出来ます。
3 種類それぞれに対して個別に
・Script Path / 割り当てるスクリプトファイル名
・Enable / 有効・無効 切り替え
の設定が出来ます。有効にすると Sip 一覧に touchkeysip 1, 2 のエントリが表示
され、それぞれが独立した Sip のように振る舞います。

↑EM・ONE S01SH (WM6) の場合

↑Touch Diamond (S21HT) の場合
複数有効にしてもインスタンスは共有されるので、追加のメモリ消費はほとんど
無いはずです。現在選択している SIP 以外のりソースは解放されるので、
メモリに読み込まれているスクリプトも常に 1つだけです。
これで複数のキーボードデータを使い分けることが出来ると思います。
レジストリへ登録する CLSID を増やすだけなので、原理的にはいくらでも増やすことが出来ます。
●回転時の動作
T-01A で画面回転時に位置が不定になるとの報告をいただきました。
SIP を閉じた状態で画面を回転すると、センタリング位置が不定になる問題は修正
しました。
ただし、T-01A で発生している症状は他の機種では再現しないため、根本的に直って
いるかどうかはわかりません。現物がないと原因を特定できないかもしれません。
WindowsMobile 6.x ではタッチ用に UI が変更またはカスタマイズされており、
細かい動作が端末によって異なっている可能性があります。
●消費メモリの軽減
画像読み込み時のみ必要な dll はすぐに解放するようにしました。
bmp 指定時は dll を使わずに古いローダーを用いるように変更しました。
●パネル
スクリプトでパネルを切り替える方法について質問をいただきました。
以下その説明です。
画面(パネル)切り替えという概念は、script の機能を用いて仮想的に実現しています。
各パネルの機能を作るには下記のデータが必要となります。
・ディスプレイリスト
・イベントテーブル
スクリプトでは、この 2つデータを切り替えることでパネルを変更しています。
◎画像データ
パネルの絵は LoadBitmap コマンドで読み込み、必要なタイミングで描画しています。
描画は自分で行う場合と、ウィンドウシステムが必要なときに勝手に描画する場合が
あります。
例えば上に重なった別のウィンドウを閉じたとき、下のウィンドウの絵を復元しなければ
なりません。
このように再描画が必要になった場合に、どのデータを画面に描画するのかあらかじめ
登録しておくのが「ディスプレイリスト」です。
◎ディスプレイリストの登録
SetDisplayList 命令を使います。
画像の転送元や転送範囲、転送先の座標を登録するだけです。
複数登録しておくと順番に描画します。
SetWindowDisplayList 命令を使って、ウィンドウ毎にディスプレイリストを割り付ける
ことが出来ます。
◎直接描画
ディスプレイリストを登録してもすぐには画面が書き換わりません。
再描画が必要なタイミングにならないと呼び出されないからです。
アニメーションの表現や、パネル切り替えなどで即座に画面を書き換えたい場合は
直接描画する命令を使います。
DrawDisplayList は、指定したディスプレイリストをその場で直接描画する命令です。
◎描画のまとめ
ディスプレリストとは描画手順のこと。
SetDisplayList 命令で登録しておくことができます。
描画手順は二通り。この二つを状況に応じて使い分けることになります。
・ディスプレイリストをウィンドウに割り当てる SetWindowDisplayList
再描画が必要になったら勝手に呼び出して描画してくれます。
元の描画に戻す手順です。登録しておかないと再描画で元に戻らなくなります。
・その場で画面に書き込みたいなら DrawDisplayList
すぐ描画します。一度限りなので、他のウィンドウで消されても戻りません。
アニメーションや、パネル切り替えなどその場で更新したい場合に使います。
◎イベントテーブル
どの座標をタッチしたらどの関数を呼び出すのか、このようなアクションを登録して
おけるのがイベントテーブルです。
テーブルは座標範囲と呼び出す関数名、関数に渡す引数で構成されています。
これをボタンの数だけ並べておけば、タッチしたときに任意のスクリプトが走ります。
実際の動作は関数依存なので、任意の文字を送信してもいいし、パネル切り替えなどの
機能を作ることも出来ます。
イベントテーブルは複数作っておくことが出来るので、パネル毎に設定し直すだけで
動作を好きなように変えられるわけです。
テーブルはウィンドウ毎に指定可能で SetEventTable 命令を使います。
SetEventTable には一度に複数のテーブルを与えることが出来ます。
複数のパネルで同じように使うボタンがあれば、イベントテーブルを共通化しておくことが出来ます。
◎ウィンドウ
CommandManual.txt にも説明がありますが、ウィンドウという概念を持っています。
メインパネルはウィンドウの 0 番 (= WIN_MAIN) に相当します。
サブウィンドウを開くことが出来るので、例えばポップアップ小さい画面を重ねて
情報を出すような表現を作ることが出来ます。
WindowsMobile に最初から入っている SIP はメインパネルだけで出来ています。
touchkeysip も複雑なことをしなければ WIN_MAIN だけで sip として機能します。
◎パネルを切り替える方法
ほぼ下記の命令をセットで用いています。
サンプルスクリプトなどで探してみてください。
現在選択しているパネルの状態は、適当なグローバル変数を使って管理しています。
関連エントリ
・WindowsMobile touchkeysip v1.10 加速センサーで文字入力
使用期間が短いため問題ある場合は引き続き旧バージョンをお使いください。
・touchkeysip v1.11 ソフトウエア入力パネル
●複数の sip 登録
オプション画面を拡張しました。オプション画面の開き方は次の通り。
スタートメニューから 設定 → 入力 → 入力方法: touchkeysip → オプション
右上のプルダウンメニューで「Sip 0」~「Sip 2」の切り替えが出来ます。
3 種類それぞれに対して個別に
・Script Path / 割り当てるスクリプトファイル名
・Enable / 有効・無効 切り替え
の設定が出来ます。有効にすると Sip 一覧に touchkeysip 1, 2 のエントリが表示
され、それぞれが独立した Sip のように振る舞います。

↑EM・ONE S01SH (WM6) の場合

↑Touch Diamond (S21HT) の場合
複数有効にしてもインスタンスは共有されるので、追加のメモリ消費はほとんど
無いはずです。現在選択している SIP 以外のりソースは解放されるので、
メモリに読み込まれているスクリプトも常に 1つだけです。
これで複数のキーボードデータを使い分けることが出来ると思います。
レジストリへ登録する CLSID を増やすだけなので、原理的にはいくらでも増やすことが出来ます。
●回転時の動作
T-01A で画面回転時に位置が不定になるとの報告をいただきました。
SIP を閉じた状態で画面を回転すると、センタリング位置が不定になる問題は修正
しました。
ただし、T-01A で発生している症状は他の機種では再現しないため、根本的に直って
いるかどうかはわかりません。現物がないと原因を特定できないかもしれません。
WindowsMobile 6.x ではタッチ用に UI が変更またはカスタマイズされており、
細かい動作が端末によって異なっている可能性があります。
●消費メモリの軽減
画像読み込み時のみ必要な dll はすぐに解放するようにしました。
bmp 指定時は dll を使わずに古いローダーを用いるように変更しました。
●パネル
スクリプトでパネルを切り替える方法について質問をいただきました。
以下その説明です。
画面(パネル)切り替えという概念は、script の機能を用いて仮想的に実現しています。
各パネルの機能を作るには下記のデータが必要となります。
・ディスプレイリスト
・イベントテーブル
スクリプトでは、この 2つデータを切り替えることでパネルを変更しています。
◎画像データ
パネルの絵は LoadBitmap コマンドで読み込み、必要なタイミングで描画しています。
描画は自分で行う場合と、ウィンドウシステムが必要なときに勝手に描画する場合が
あります。
例えば上に重なった別のウィンドウを閉じたとき、下のウィンドウの絵を復元しなければ
なりません。
このように再描画が必要になった場合に、どのデータを画面に描画するのかあらかじめ
登録しておくのが「ディスプレイリスト」です。
◎ディスプレイリストの登録
SetDisplayList 命令を使います。
画像の転送元や転送範囲、転送先の座標を登録するだけです。
複数登録しておくと順番に描画します。
SetWindowDisplayList 命令を使って、ウィンドウ毎にディスプレイリストを割り付ける
ことが出来ます。
◎直接描画
ディスプレイリストを登録してもすぐには画面が書き換わりません。
再描画が必要なタイミングにならないと呼び出されないからです。
アニメーションの表現や、パネル切り替えなどで即座に画面を書き換えたい場合は
直接描画する命令を使います。
DrawDisplayList は、指定したディスプレイリストをその場で直接描画する命令です。
◎描画のまとめ
ディスプレリストとは描画手順のこと。
SetDisplayList 命令で登録しておくことができます。
描画手順は二通り。この二つを状況に応じて使い分けることになります。
・ディスプレイリストをウィンドウに割り当てる SetWindowDisplayList
再描画が必要になったら勝手に呼び出して描画してくれます。
元の描画に戻す手順です。登録しておかないと再描画で元に戻らなくなります。
・その場で画面に書き込みたいなら DrawDisplayList
すぐ描画します。一度限りなので、他のウィンドウで消されても戻りません。
アニメーションや、パネル切り替えなどその場で更新したい場合に使います。
◎イベントテーブル
どの座標をタッチしたらどの関数を呼び出すのか、このようなアクションを登録して
おけるのがイベントテーブルです。
talbe <名前> dataw <ボタンの個数> dataw EVENT_DOWN 0 16 32 32 FuncPushA 0 0 ~ endtable
テーブルは座標範囲と呼び出す関数名、関数に渡す引数で構成されています。
これをボタンの数だけ並べておけば、タッチしたときに任意のスクリプトが走ります。
実際の動作は関数依存なので、任意の文字を送信してもいいし、パネル切り替えなどの
機能を作ることも出来ます。
イベントテーブルは複数作っておくことが出来るので、パネル毎に設定し直すだけで
動作を好きなように変えられるわけです。
テーブルはウィンドウ毎に指定可能で SetEventTable 命令を使います。
SetEventTable には一度に複数のテーブルを与えることが出来ます。
複数のパネルで同じように使うボタンがあれば、イベントテーブルを共通化しておくことが出来ます。
◎ウィンドウ
CommandManual.txt にも説明がありますが、ウィンドウという概念を持っています。
メインパネルはウィンドウの 0 番 (= WIN_MAIN) に相当します。
サブウィンドウを開くことが出来るので、例えばポップアップ小さい画面を重ねて
情報を出すような表現を作ることが出来ます。
WindowsMobile に最初から入っている SIP はメインパネルだけで出来ています。
touchkeysip も複雑なことをしなければ WIN_MAIN だけで sip として機能します。
◎パネルを切り替える方法
ほぼ下記の命令をセットで用いています。
サンプルスクリプトなどで探してみてください。
SetDisplayList ~ # 描画手順の変更、再登録や書き換えなど SetWindowDisplayList ~ # ウィンドウに DisplayList を割り当て(変更無ければ不要) DrawDisplayList ~ # その場で画面を書き換えて表示を更新 SetEventTable ~ # ボタンを押したときの動作を変更する
現在選択しているパネルの状態は、適当なグローバル変数を使って管理しています。
関連エントリ
・WindowsMobile touchkeysip v1.10 加速センサーで文字入力
2009/09/06
OpenGL のはじめ方 (2) wgl
Windows で OpenGL を使う方法がだんだんわかってきました。
DirectX ならとりあえず新しい SDK を入れれば終わりですが、OpenGL の場合は少々違います。
特別な SDK や lib が無くても、ドライバさえ対応していれば使うことができます。
敢えて OpenGL の各種ライブラリは使用していません。便利で容易に任せられる反面、中で何を
やっているのか、最新バージョンを使うにはどうしたらいいのかがわかりにくかったからです。
(1) OS と OpenGL のやりとりは WGL が行う。
(2) Windows SDK には OpenGL 1.1 のヘッダ&lib のみ。最小限。
(3) 新しい OpenGL に対応している GPU ライバをインストールする。
(4) ヘッダファイルは OpenGL Registry からダウンロードできる。
(5) wglGetProcAddress() を使って自分で最新の API を取得する。
API の取得は以前行ったとおり。ここ数日、実際に OpenGL 3.2 で追加された機能を
試すことが出来ました。今度は初期化部分、wgl まわりをもう少し詳しく調べてみます。
・MSDN Using OpenGL on Windows NT/2000 and Windows 95/98
●ピクセルフォーマットと初期化
Direct3D と同じように、とりあえず Win32 API でウィンドウを作っておきます。
OpenGL の Context (HGLRC) を作るには HDC が必要です。
そのまま wglCreateContext() を呼び出してもエラーになります。
OpenGL が対応しているピクセルフォーマットになっていないことが原因でした。
あらかじめフレームバッファのフォーマットを指定しておきます。
現在対応しているフォーマットは下記の方法で取得可能です。
GeForce 190.57 で実際に列挙してみました。126個あります。
・GeForce 190.57 PIXELFORMATDESCRIPTOR 一覧
最後の方に W と GL 両方付いているものが Window 描画対応かつ OpenGL で使える
フォーマットです。
MSDN Choosing and Setting a Best-Match Pixel Format の例では
Color=24, Depth=32 を指定していますが、Direct3D を考えても、上の列挙の結果を見ても、
あまり一般的とはいえません。
今回は下記のピクセルフォーマット指定を行いました。
ChoosePixelFormat() を使うとフォーマットのマッチングを自動で行ってくれるようです。
エラー判定を省いていますが、初期化手順は上記の通りです。
hDC, hGLRC は保存しておきます。終了時のコードは下記の通りです。
●描画ループ
wglMakeCurrent() で hGLRC を指定すれば、以後描画のために gl ~ API を
用いることが出来ます。Double Buffer を指定したので毎フレームの描画の最後に
SwapBuffers() を入れます。Direct3D の Present() に相当します。
●新しい Context の作成
基本的な WGL と OpenGL の関係は上記の通りです。
さらに新しい API を使う場合、いくつか追加の手順が必要となります。
まず拡張 API にはいくつか種類があります。
・新しいバージョンの OpenGL core API
・OpenGL 拡張 API
・WGL 拡張 API
これら拡張 API を使う方法はどれも同じです。ヘッダファイルと対応ドライバを手に入れたなら、
あとは wglGetProcAddress() を用いるだけ。
wglGetProcAddress() 関数は、wglCreateContext() のあと wglMakeCurrent() で
hGLRC を設定した後でないと呼び出すことが出来ません。
(1) OpenGL Registry から wglext.h をダウンロードしておきます。
(2) 通常の手段で Context を作成し wglMakeCurrent() しておきます。
(3) WGL の拡張 API 、wglCreateContextAttribsARB() を取り出します。
(4) wglCreateContextAttribsARB() を使って HGLRC を作り直します。
InitOpenGL() については こちら を参照してください。
なお GeForce で試している分には、特にこの手順を踏まなくても OpenGL 3.2 の命令が
使えるし描画もできています。
上の例では wglCreateContextAttribsARB() だけ個別に取り出していますが、
実際は InitOpenGL() (GLFunction) のテーブルに、gl ~ と同じように wgl 関数
を組み込みました。よって上の (A) のタイミングで InitOpenGL() を用いて
wglCreateContextAttribsARB を含めた一度にすべての拡張関数を取り出しています。
●プロファイルと互換性
OpenGL 3.1~ は DirectX のように、徐々に古い固定機能を無くし新しい機能への
置き換えが進んでいます。それでもアプリケーションが困らないように、従来と互換性を保った
API を使う手段も残されています。
・OpenGL 3.1 + GL_ARB_compatibility
・OpenGL 3.2 + WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB
OpenGL 3.2 では Profile の選択が出来るようになりました。
wglCreateContextAttribsARB() 呼び出し時の WGL_CONTEXT_PROFILE_MASK_ARB
で指定できる Profile は次の 2つ。
・WGL_CONTEXT_CORE_PROFILE_BIT_ARB
・WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB
Core profile はシェーダーを用いた新しい API セット、Compatibility profile は
互換性を持った API です。
テストで GeForce の 190.57 を使っている分には、どちらもほとんど差がありませんでした。
関連エントリ
・OpenGL 3.2 GeometryShader をもう少し使ってみる
・OpenGL GLSL のバージョン
・OpenGL 3.2 の GeometryShader
・OpenGL のはじめ方
・OpenGL ES 2.0 Emulator
・OpenGL ES 2.0
・OpenGLES2.0 DDS テクスチャを読み込む
・OpenGLES2.0 Direct3D とのフォーマット変換
・OpenGLES 2.0 頂点フォーマットの管理
・OpenGLES2.0 の頂点
・OpenGLES2.0 D3D座標系
・OpenGLES2.0 シェーダー管理
DirectX ならとりあえず新しい SDK を入れれば終わりですが、OpenGL の場合は少々違います。
特別な SDK や lib が無くても、ドライバさえ対応していれば使うことができます。
敢えて OpenGL の各種ライブラリは使用していません。便利で容易に任せられる反面、中で何を
やっているのか、最新バージョンを使うにはどうしたらいいのかがわかりにくかったからです。
(1) OS と OpenGL のやりとりは WGL が行う。
(2) Windows SDK には OpenGL 1.1 のヘッダ&lib のみ。最小限。
(3) 新しい OpenGL に対応している GPU ライバをインストールする。
(4) ヘッダファイルは OpenGL Registry からダウンロードできる。
(5) wglGetProcAddress() を使って自分で最新の API を取得する。
API の取得は以前行ったとおり。ここ数日、実際に OpenGL 3.2 で追加された機能を
試すことが出来ました。今度は初期化部分、wgl まわりをもう少し詳しく調べてみます。
・MSDN Using OpenGL on Windows NT/2000 and Windows 95/98
●ピクセルフォーマットと初期化
Direct3D と同じように、とりあえず Win32 API でウィンドウを作っておきます。
OpenGL の Context (HGLRC) を作るには HDC が必要です。
そのまま wglCreateContext() を呼び出してもエラーになります。
OpenGL が対応しているピクセルフォーマットになっていないことが原因でした。
あらかじめフレームバッファのフォーマットを指定しておきます。
現在対応しているフォーマットは下記の方法で取得可能です。
HDC hDC= GetDC( hWnd ); // 現在対応しているフォーマットの数を参照する int format_count= DescribePixelFormat( hDC, 0, 0, NULL ); // 列挙する for( int fi= 1 ; fi<= format_count ; fi++ ){ PIXELFORMATDESCRIPTOR pformat; DescribePixelFormat( hDC, fi, sizeof(PIXELFORMATDESCRIPTOR), &pformat ); }
GeForce 190.57 で実際に列挙してみました。126個あります。
・GeForce 190.57 PIXELFORMATDESCRIPTOR 一覧
最後の方に W と GL 両方付いているものが Window 描画対応かつ OpenGL で使える
フォーマットです。
MSDN Choosing and Setting a Best-Match Pixel Format の例では
Color=24, Depth=32 を指定していますが、Direct3D を考えても、上の列挙の結果を見ても、
あまり一般的とはいえません。
今回は下記のピクセルフォーマット指定を行いました。
ChoosePixelFormat() を使うとフォーマットのマッチングを自動で行ってくれるようです。
static PIXELFORMATDESCRIPTOR pformat= { sizeof(PIXELFORMATDESCRIPTOR), 1, 0 |PFD_DRAW_TO_WINDOW |PFD_SUPPORT_OPENGL |PFD_DOUBLEBUFFER , PFD_TYPE_RGBA, 32, // color 0, 0, // R 0, 0, // G 0, 0, // B 0, 0, // A 0, 0, 0, 0, 0, // AC R G B A 24, // depth 8, // stencil 0, // aux 0, // layertype 0, // reserved 0, // layermask 0, // visiblemask 0 // damagemask }; HDC hDC= GetDC( hWnd ); // ピクセルフォーマットの選択 int pfmt= ChoosePixelFormat( hDC, &pformat ); SetPixelFormat( hDC, pfmt, &pformat ); // OpenGL コンテキストの作成 HGLRC hGLRC= wglCreateContext( hDC ); wglMakeCurrent( hDC, hGLRC );
エラー判定を省いていますが、初期化手順は上記の通りです。
hDC, hGLRC は保存しておきます。終了時のコードは下記の通りです。
if( hGLRC ){ wglMakeCurrent( NULL, NULL ); wglDeleteContext( hGLRC ); hGLRC= NULL; } if( hDC ){ ReleaseDC( hWnd, hDC ); hDC= NULL; }
●描画ループ
wglMakeCurrent() で hGLRC を指定すれば、以後描画のために gl ~ API を
用いることが出来ます。Double Buffer を指定したので毎フレームの描画の最後に
SwapBuffers() を入れます。Direct3D の Present() に相当します。
// フレームバッファクリア glClearColor( 0.0f, 0.0f, 0.3, 0.0f ); glClearDepth( 1.0f ); glClearStencil( 0 ); glClear( GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT ); // 描画など ~ // flip SwapBuffers( hDC );
●新しい Context の作成
基本的な WGL と OpenGL の関係は上記の通りです。
さらに新しい API を使う場合、いくつか追加の手順が必要となります。
まず拡張 API にはいくつか種類があります。
・新しいバージョンの OpenGL core API
・OpenGL 拡張 API
・WGL 拡張 API
これら拡張 API を使う方法はどれも同じです。ヘッダファイルと対応ドライバを手に入れたなら、
あとは wglGetProcAddress() を用いるだけ。
wglGetProcAddress() 関数は、wglCreateContext() のあと wglMakeCurrent() で
hGLRC を設定した後でないと呼び出すことが出来ません。
(1) OpenGL Registry から wglext.h をダウンロードしておきます。
(2) 通常の手段で Context を作成し wglMakeCurrent() しておきます。
(3) WGL の拡張 API 、wglCreateContextAttribsARB() を取り出します。
(4) wglCreateContextAttribsARB() を使って HGLRC を作り直します。
HDC hDC= GetDC( hWnd ); // ピクセルフォーマットの選択 int pfmt= ChoosePixelFormat( hDC, &pformat ); SetPixelFormat( hDC, pfmt, &pformat ); // OpenGL コンテキストの作成 HGLRC hGLRC= wglCreateContext( hDC ); wglMakeCurrent( hDC, hGLRC ); // API 取り出し --- (A) PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB= (PFNWGLCREATECONTEXTATTRIBSARBPROC)wglGetProcAddress( "wglCreateContextAttribsARB" ); // 使用する OpenGL のバージョンとプロファイルの指定 static const int att[]= { WGL_CONTEXT_MAJOR_VERSION_ARB, 3, WGL_CONTEXT_MINOR_VERSION_ARB, 2, WGL_CONTEXT_FLAGS_ARB, 0, WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB, 0, }; // 新しい HGLRC の作成 HGLRC hglrc= wglCreateContextAttribsARB( hDC, NULL, att ); wglMakeCurrent( hDC, hglrc ); // 古い HGLRC の削除と置き換え wglDeleteContext( hGLRC ); hGLRC= hglrc; // 新しい Core API の取り出し InitOpenGL();
InitOpenGL() については こちら を参照してください。
なお GeForce で試している分には、特にこの手順を踏まなくても OpenGL 3.2 の命令が
使えるし描画もできています。
上の例では wglCreateContextAttribsARB() だけ個別に取り出していますが、
実際は InitOpenGL() (GLFunction) のテーブルに、gl ~ と同じように wgl 関数
を組み込みました。よって上の (A) のタイミングで InitOpenGL() を用いて
wglCreateContextAttribsARB を含めた一度にすべての拡張関数を取り出しています。
●プロファイルと互換性
OpenGL 3.1~ は DirectX のように、徐々に古い固定機能を無くし新しい機能への
置き換えが進んでいます。それでもアプリケーションが困らないように、従来と互換性を保った
API を使う手段も残されています。
・OpenGL 3.1 + GL_ARB_compatibility
・OpenGL 3.2 + WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB
OpenGL 3.2 では Profile の選択が出来るようになりました。
wglCreateContextAttribsARB() 呼び出し時の WGL_CONTEXT_PROFILE_MASK_ARB
で指定できる Profile は次の 2つ。
・WGL_CONTEXT_CORE_PROFILE_BIT_ARB
・WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB
Core profile はシェーダーを用いた新しい API セット、Compatibility profile は
互換性を持った API です。
テストで GeForce の 190.57 を使っている分には、どちらもほとんど差がありませんでした。
関連エントリ
・OpenGL 3.2 GeometryShader をもう少し使ってみる
・OpenGL GLSL のバージョン
・OpenGL 3.2 の GeometryShader
・OpenGL のはじめ方
・OpenGL ES 2.0 Emulator
・OpenGL ES 2.0
・OpenGLES2.0 DDS テクスチャを読み込む
・OpenGLES2.0 Direct3D とのフォーマット変換
・OpenGLES 2.0 頂点フォーマットの管理
・OpenGLES2.0 の頂点
・OpenGLES2.0 D3D座標系
・OpenGLES2.0 シェーダー管理
2009/09/05
OpenGL 3.2 GeometryShader をもう少し使ってみる
前々回は VertexShaded から GeometryShader へのパラメータ渡しで
built-in のシステム変数 gl_Position を使いました。
gl_Position を使うメリットは下記の通りです。
・宣言なしに使うことが出来る
・VertexShader の段階で書き込んでいるので GeomteryShader が無くても描画できる
前々回のような単なるスルー出力では GeomteryShader が無くても描画可能です。
VertexShader で gl_Position に値を書き込んでいたので、GeomteryShader を attach
せずにそのまま描画することが出来ました。
ただし、常に VertexShader の段階で座標が確定するとは限りません。
頂点からの座標値も、普通の変数を介して GeomteryShader に渡すことが出来ます。

↑基本の状態
gl_in を使用していません。
面毎に法線と texcoord をまとめてフラットシェーディング風にしてみます。(↓)

きちんと法線を算出している訳じゃないので、本来平面のはずの Quad が Triangle に
分かれて見えてしまいます。今回は気にしないでいきます。
さらに座標もずらしてみます。(↓)

上のスクリーンショットではわからないかもしれませんが、投影後の 2D 座標がずれる
だけなので、形状として厳密に正しい物ではないです。
3D で変形を行うには、Geometry Shader で頂点演算を行う必要があります。
Vertex Shader の方がスルー出力になります。
座標値が vec3 になっている点に注意。任意の型やデータをやりとりできるのが
gl_Position を使わない場合の利点です。
なお正しく面法線を求めていれば、三角形ではなく四角形に押し出されていたはず。
3D 座標(local)でずらした結果(↓)

以前は VertexShader で受け取っていた uniform 変数 World, PView が
GeometryShader に移動しています。
OpenGL + GLSL の場合、Link したあとに uniform の設定を行うので C++ 側のコード
は何も修正しなくて済みます。結構便利です。
Direct3D だと各シェーダー毎に ConstantBuffer の設定が必要なので、
VSSetConstantBuffers() → GSSetConstantBuffers() と C++ の呼び出し側も
変更しなければなりませんでした。
ここまできたら VertexShader は不要な気もします。
一応試してみましたが VertexShader の省略は出来ませんでした。
Direct3D の Effect (FX) だと VertexShader と GeometryShader に同じ内容を
割り当てることで省略できます。
GeometryShader でポリゴンを増やしてみます。中に元の形状が内部に置いてある状態です。
共有頂点分の演算が重複するので、こういうケースでは VertexShader を併用
した方が効率がよいかもしれません。
out の layout で max_vertices= 6 に注意。

関連エントリ
・OpenGL GLSL のバージョン
・OpenGL 3.2 の GeometryShader
・OpenGL のはじめ方
・OpenGL ES 2.0 Emulator
・OpenGL ES 2.0
・OpenGLES2.0 DDS テクスチャを読み込む
・OpenGLES2.0 Direct3D とのフォーマット変換
・OpenGLES 2.0 頂点フォーマットの管理
・OpenGLES2.0 の頂点
・OpenGLES2.0 D3D座標系
・OpenGLES2.0 シェーダー管理
built-in のシステム変数 gl_Position を使いました。
VertexShader: gl_Position= vec4( POSITION.xyz, 1.0 ) * PView; GeomteryShader: position= gl_in[0].gl_Position;
gl_Position を使うメリットは下記の通りです。
・宣言なしに使うことが出来る
・VertexShader の段階で書き込んでいるので GeomteryShader が無くても描画できる
前々回のような単なるスルー出力では GeomteryShader が無くても描画可能です。
VertexShader で gl_Position に値を書き込んでいたので、GeomteryShader を attach
せずにそのまま描画することが出来ました。
ただし、常に VertexShader の段階で座標が確定するとは限りません。
頂点からの座標値も、普通の変数を介して GeomteryShader に渡すことが出来ます。

↑基本の状態
// GLSL 1.5 VertexShader gl_Position を使わない #version 150 uniform vec4 World[3]; uniform mat4 PView; in vec3 POSITION; in vec3 NORMAL; in vec2 TEXCOORD; out vec4 vPosition; out vec3 vNormal; out vec2 vTexcoord; void main() { vPosition= vec4( POSITION.xyz, 1 ) * PView; vNormal.x= dot( NORMAL.xyz, World[0].xyz ); vNormal.y= dot( NORMAL.xyz, World[1].xyz ); vNormal.z= dot( NORMAL.xyz, World[2].xyz ); vTexcoord= TEXCOORD; }
// GLSL 1.5 GeometryShader #version 150 layout(triangles) in; layout(triangle_strip, max_vertices= 3) out; in Inputs { vec4 vPosition; vec3 vNormal; vec2 vTexcoord; } gin[3]; out vec3 vNormal; out vec2 vTexcoord; void main() { for( int i= 0 ; i< 3 ; i++ ){ gl_Position= gin[i].vPosition; vNormal= gin[i].vNormal; vTexcoord= gin[i].vTexcoord; EmitVertex(); } EndPrimitive(); }
gl_in を使用していません。
面毎に法線と texcoord をまとめてフラットシェーディング風にしてみます。(↓)

// GeometryShader フラット化 void main() { vNormal= normalize( gin[0].vNormal + gin[1].vNormal + gin[2].vNormal ); vTexcoord= (gin[0].vTexcoord + gin[1].vTexcoord + gin[2].vTexcoord)/3; for( int i= 0 ; i< 3 ; i++ ){ gl_Position= gin[i].vPosition; EmitVertex(); } EndPrimitive(); }
きちんと法線を算出している訳じゃないので、本来平面のはずの Quad が Triangle に
分かれて見えてしまいます。今回は気にしないでいきます。
さらに座標もずらしてみます。(↓)

// GeometryShader 座標もずらす void main() { vec3 vnormal= normalize(gin[0].vNormal + gin[1].vNormal + gin[2].vNormal); vNormal= vnormal; vTexcoord= ( gin[0].vTexcoord + gin[1].vTexcoord + gin[2].vTexcoord )/3; vec3 offset= vnormal.xyz*2.0; for( int i= 0 ; i< 3 ; i++ ){ gl_Position= gin[i].vPosition + vec4( offset.xy, 0.0, 0.0 ); EmitVertex(); } EndPrimitive(); }
上のスクリーンショットではわからないかもしれませんが、投影後の 2D 座標がずれる
だけなので、形状として厳密に正しい物ではないです。
3D で変形を行うには、Geometry Shader で頂点演算を行う必要があります。
Vertex Shader の方がスルー出力になります。
座標値が vec3 になっている点に注意。任意の型やデータをやりとりできるのが
gl_Position を使わない場合の利点です。
なお正しく面法線を求めていれば、三角形ではなく四角形に押し出されていたはず。
3D 座標(local)でずらした結果(↓)

// GLSL 1.5 VertexShader #version 150 in vec3 POSITION; in vec3 NORMAL; in vec2 TEXCOORD; out vec3 vPosition; // vec4 → vec3 out vec3 vNormal; out vec2 vTexcoord; void main() { vPosition= POSITION; vNormal= NORMAL; vTexcoord= TEXCOORD; }
// GLSL 1.5 GeometryShader #version 150 uniform vec4 World[3]; uniform mat4 PView; layout(triangles) in; layout(triangle_strip, max_vertices= 3) out; in Inputs { vec3 vPosition; // vec4 → vec3 vec3 vNormal; vec2 vTexcoord; } gin[3]; out vec3 vNormal; out vec2 vTexcoord; vec4 transform( vec3 pos ) { return vec4( pos, 1 ) * PView; } void main() { vec3 vnormal= normalize(gin[0].vNormal + gin[1].vNormal + gin[2].vNormal); vNormal.x= dot( vnormal.xyz, World[0].xyz ); vNormal.y= dot( vnormal.xyz, World[1].xyz ); vNormal.z= dot( vnormal.xyz, World[2].xyz ); vTexcoord= ( gin[0].vTexcoord + gin[1].vTexcoord + gin[2].vTexcoord )/3; for( int i= 0 ; i< 3 ; i++ ){ gl_Position= transform( gin[i].vPosition + vnormal * 1.5 ); EmitVertex(); } EndPrimitive(); }
以前は VertexShader で受け取っていた uniform 変数 World, PView が
GeometryShader に移動しています。
OpenGL + GLSL の場合、Link したあとに uniform の設定を行うので C++ 側のコード
は何も修正しなくて済みます。結構便利です。
Direct3D だと各シェーダー毎に ConstantBuffer の設定が必要なので、
VSSetConstantBuffers() → GSSetConstantBuffers() と C++ の呼び出し側も
変更しなければなりませんでした。
ここまできたら VertexShader は不要な気もします。
一応試してみましたが VertexShader の省略は出来ませんでした。
Direct3D の Effect (FX) だと VertexShader と GeometryShader に同じ内容を
割り当てることで省略できます。
GeometryShader でポリゴンを増やしてみます。中に元の形状が内部に置いてある状態です。
共有頂点分の演算が重複するので、こういうケースでは VertexShader を併用
した方が効率がよいかもしれません。
out の layout で max_vertices= 6 に注意。

// GLSL 1.5 GeometryShader #version 150 uniform vec4 World[3]; uniform mat4 PView; layout(triangles) in; layout(triangle_strip, max_vertices= 6) out; in Inputs { vec3 vPosition; vec3 vNormal; vec2 vTexcoord; } gin[3]; out vec3 vNormal; out vec2 vTexcoord; vec4 transform( vec3 pos ) { return vec4( pos, 1 ) * PView; } void setnormal( vec3 normal ) { vNormal.x= dot( normal.xyz, World[0].xyz ); vNormal.y= dot( normal.xyz, World[1].xyz ); vNormal.z= dot( normal.xyz, World[2].xyz ); } void main() { for( int i= 0 ; i< 3 ; i++ ){ setnormal( gin[i].vNormal ); vTexcoord= gin[i].vTexcoord; gl_Position= transform( gin[i].vPosition ); EmitVertex(); } EndPrimitive(); vec3 vnormal= normalize( gin[0].vNormal + gin[1].vNormal + gin[2].vNormal ); setnormal( vnormal ); vTexcoord= ( gin[0].vTexcoord + gin[1].vTexcoord + gin[2].vTexcoord )/3; for( int i= 0 ; i< 3 ; i++ ){ gl_Position= transform( gin[i].vPosition + vnormal * 2.0 ); EmitVertex(); } EndPrimitive(); }
関連エントリ
・OpenGL GLSL のバージョン
・OpenGL 3.2 の GeometryShader
・OpenGL のはじめ方
・OpenGL ES 2.0 Emulator
・OpenGL ES 2.0
・OpenGLES2.0 DDS テクスチャを読み込む
・OpenGLES2.0 Direct3D とのフォーマット変換
・OpenGLES 2.0 頂点フォーマットの管理
・OpenGLES2.0 の頂点
・OpenGLES2.0 D3D座標系
・OpenGLES2.0 シェーダー管理
2009/09/04
OpenGL GLSL のバージョン
GeometryShader 利用時に GLSL のバージョンの違いが問題になったのでまとめてみました。
・Wikipedia GLSL
OpenGL ES 2.0 の GLSL は、GLSL ES または ESSL と呼ばれています。
上の対応表では OpenGL 2.0 / GLSL 1.1 の列にありますが、GLSL ES 1.0 自体は
GLSL 1.2 の機能も含まれています。実際は OpenGL 2.0~2.1 の中間になります。
OpenGL 2.0 で GLSL が core に組み込まれました。
OpenGL 3.0 / GLSL 1.3 で大きな仕様変更があり、シェーダーも固定機能の排除が
進められています。attribute/varying が in/out に変更になったのもここです。
Direct3D との対応付けは難しいですが、おそらく OpenGL 2.0 が Direct3D 9、
OpenGL 3.0 が ShaderModel 4.0 の Direct3D 10 に近い位置づけです。
実際はここまで明確な区別が無く、もっと入り組んでいるし互換性も保たれています。
機能拡張も段階的に進められています。
例えば OpenGL 3.1 で Uniform Block / Uniform Buffer が追加されていて、
これはちょうど Direct3D 10 の ConstantBuffer に相当するものです。
OpenGL 3.2 では Geometry Shader が入りました。
GLES と GLSL ES (ESSL) は「 #ifdef GL_ES 」で区別できます。
昨日はむりやり define して動かしましたが、下記のような定義でシェーダーを共有
することにしました。
OpenGL ES のコンパイラには少々問題があって、ソースの先頭に #version が無いと
エラーになるようです。コンパイルオプションの切り替えのために複数のソースを
渡しているせいか、#version をどこに書いてもエラーとなってしまいました。
上の定義では OpenGL ES 側に #version を書いていないのはそのためです。
関連エントリ
・OpenGL 3.2 の GeometryShader
・OpenGL のはじめ方
・OpenGL ES 2.0 Emulator
・OpenGL ES 2.0
・OpenGLES2.0 DDS テクスチャを読み込む
・OpenGLES2.0 Direct3D とのフォーマット変換
・OpenGLES 2.0 頂点フォーマットの管理
・OpenGLES2.0 の頂点
・OpenGLES2.0 D3D座標系
・OpenGLES2.0 シェーダー管理
OpenGL 1.3 ---- OpenGL ES 1.0 ---- OpenGL 1.5 *1 OpenGL ES 1.1 ---- OpenGL 2.0 GLSL 1.1 OpenGL ES 2.0 GLSL ES 1.0 (ESSL) OpenGL 2.1 GLSL 1.2 OpenGL 3.0 GLSL 1.3 OpenGL 3.1 GLSL 1.4 OpenGL 3.2 GLSL 1.5 *1: Shader 対応。Extension で GLSL1.0 も利用可能。Core API になったのは OpenGL 2.0 から。
・Wikipedia GLSL
OpenGL ES 2.0 の GLSL は、GLSL ES または ESSL と呼ばれています。
上の対応表では OpenGL 2.0 / GLSL 1.1 の列にありますが、GLSL ES 1.0 自体は
GLSL 1.2 の機能も含まれています。実際は OpenGL 2.0~2.1 の中間になります。
OpenGL 2.0 で GLSL が core に組み込まれました。
OpenGL 3.0 / GLSL 1.3 で大きな仕様変更があり、シェーダーも固定機能の排除が
進められています。attribute/varying が in/out に変更になったのもここです。
Direct3D との対応付けは難しいですが、おそらく OpenGL 2.0 が Direct3D 9、
OpenGL 3.0 が ShaderModel 4.0 の Direct3D 10 に近い位置づけです。
実際はここまで明確な区別が無く、もっと入り組んでいるし互換性も保たれています。
機能拡張も段階的に進められています。
例えば OpenGL 3.1 で Uniform Block / Uniform Buffer が追加されていて、
これはちょうど Direct3D 10 の ConstantBuffer に相当するものです。
OpenGL 3.2 では Geometry Shader が入りました。
GLES と GLSL ES (ESSL) は「 #ifdef GL_ES 」で区別できます。
昨日はむりやり define して動かしましたが、下記のような定義でシェーダーを共有
することにしました。
// Vertex Shader #ifdef GL_ES # define IN attribute # define OUT varying # define LOWP lowp # define MEDIUMP mediump precision MEDIUMP float; precision MEDIUMP int; #else # define IN in # define OUT out # version 150 # define LOWP # define MEDIUMP #endif
// Fragment Shader #ifdef GL_ES # define IN varying # define LOWP lowp # define MEDIUMP mediump precision MEDIUMP float; precision MEDIUMP int; precision LOWP sampler2D; #else # define IN in # version 150 # define LOWP # define MEDIUMP #endif
OpenGL ES のコンパイラには少々問題があって、ソースの先頭に #version が無いと
エラーになるようです。コンパイルオプションの切り替えのために複数のソースを
渡しているせいか、#version をどこに書いてもエラーとなってしまいました。
上の定義では OpenGL ES 側に #version を書いていないのはそのためです。
関連エントリ
・OpenGL 3.2 の GeometryShader
・OpenGL のはじめ方
・OpenGL ES 2.0 Emulator
・OpenGL ES 2.0
・OpenGLES2.0 DDS テクスチャを読み込む
・OpenGLES2.0 Direct3D とのフォーマット変換
・OpenGLES 2.0 頂点フォーマットの管理
・OpenGLES2.0 の頂点
・OpenGLES2.0 D3D座標系
・OpenGLES2.0 シェーダー管理
2009/09/03
OpenGL 3.2 の GeometryShader
OpenGL 3.2 では core 機能に Geometry Shader が含まれています。
試してみました。
・OpenGL Registry
GeometryShader はポリゴンの面単位で実行可能なシェーダープログラムです。
面単位なので、プリミティブタイプが Triangle List (GL_TRIANGLES) なら一度に
3頂点を入力として受け取ります。主な用途は下記の通りです。
・頂点演算
・面単位のマテリアル演算
・形状の操作
・出力先の変更
・StreamOutput (Transform Feedback)
わかりやすいところでは面法線の生成など面単位のマテリアル設定が考えられます。
ユニークなのは入力と関係なく出力プリミティブを組み立てられることです。
出力頂点数は任意なので、エッジだけ Line として書き出したり、面を分割したり、
面を消すことも出来ます。
例えば入力を PointList (GL_POINTS) で 1頂点だけ受け取り、Triangle で
2 プリミティブ出力すればポイントスプライトの代わりになるわけです。
出力先の変更は Direct3D だと RenderTarget Array, OpenGL では
Layered Rendering と呼ばれているようです。
Geometry Shader で書き込むフレームバッファの選択が可能で、Cube Map への
レンダリングも一回で出来る仕様になっています。
入力可能なプリミティブタイプも Direct3D 10 同様に増えています。
下記は増えた分のみ。使えるのは GeometryShader が有効な場合だけに限られます。
あまり馴染みがない名称ですが、極端な言い方をすれば 4,6 頂点のプリミティブが
使えるようになったということです。
GL_TRIANGLES だと GeometryShader は 3 頂点単位で受け取りますが、
GL_TRIANGLES_ADJACENCY では一度に 6頂点受け取れることになります。
GL_LINES_ADJACENCY の 4頂点は、QUAD プリミティブの代わりとしても使えます。
ちなみに Direct3D 11 の ShaderModel 5.0 はさらに増えていて、テセレータ用に
32頂点まで任意の数の頂点を入力できるようになっています。
今回使用したビデオカードは GeForce GTX280。ステートを調べると下記の通りです。
頂点の生成が最大 1024 float なのも Direct3D 10 の ShaderModel 4.0 と同じです。
● GeometryShader のコンパイル
Shader の読み込みとコンパイル手順はこれまでの VertexShader, FragmentShader
と同じです。もともとシェーダーしか使えない OpenGL ES 2.0 を使っていたため、
ちょうど GeometryShader の部分が追加された形になります。
エラー判定は省いてあります。
次はコンパイルしたシェーダーをリンクして Program の作成です。
これまで VertexShader, FragmentShader だけ attach していたところに
GeometryShader が加わります。
●ドライバの補足
GLSL の GeometryShader の書き方がわからなかったため、ドキュメント
OpenGL Shadeing Language 1.50.09 と Direct3D の知識を頼りに進めました。
最初はコンパイルすらうまく通らず、EmitVertex を用いると
「#extension GL_EXT_geometry_shader4 : enable」
を宣言しなさいとエラーが出てしまいます。
「#version 150」で GLSL 1.5 を指定すると未対応のバージョンだといわれます。
140 なら通ります。ドライバを調べてみると、最新版 190.62 は OpenGL 3.1 しか
対応していませんでした。
ドライバが OpenGL 3.2 / GLSL 1.5 に対応していなかったことが原因です。
・NVIDIA OpenGL 3.0/3.1/3.2 Support for Windows, Linux, FreeBSD, and Solaris
上のページにある、OpenGL 3.2 対応ドライバ 190.57 を入れたら、#version 150 指定
による GLSL 1.5 も、GeometryShader 専用命令も通るようになりました。
「#version 150」とだけ書いておけばよく、extension 指定は不要です。
● GLSL v1.50
「#version 150」を指定したら VertexShader でもエラーが出るようになりました。
attribute, varying 宣言は古いので、in, out を使えと言われます。
もともと attribute は頂点からの入力、varying はラスタライザの補間パラメータを
意味しています。出力先が GeometryShader かもしれないし、シェーダーパイプラインが
多層化&汎用化されたので名称が変わったものと思われます。
OpenGL ES 2.0 との互換性も残したいのでとりあえず define でごまかしました。
attribute を in に、varying を out に置き換えます。
Matrix 周りが少々不自然なのは、OpenGL ES 2.0 に mat4x3 が無かったことと頂点
アニメーションを削ったためです。もともと Skinning の処理が入っていました。
同じように Fragment Shader も書き換えます。
FragmentShader の場合 VertexShader と逆で varying が in になります。
GeometryShader は最初から in/out で記述します。
プリミティブのタイプは layout() で宣言しています。
入力は block 宣言を使っており、Triangle なので 3頂点分のデータを受け取ります。
VertexShader が書き込んだシステム変数 gl_Position の値は、こちらも builtin
の gl_in[] という配列で受け取れます。
出力はこれまで通り out (varying) 宣言した変数に書き込みます。
必要なパラメータを書き込んだ後に EmitVertex() 命令で頂点が確定します。
プリミティブの区切りは EndPrimitive() 命令です。
このジオメトリシェーダーは何もせずに、頂点の出力をそのままスルーしています。
上の (1) の行を削除すると面に同じ法線が適用されるため、フラットシェーディング
風の見た目になるはずです。
同じシェーダーを DirectX の HLSL で書くとこんな感じです。
書式が違うだけでほとんど同じです。
Direct3D でも、アセンブラ出力すると頂点の生成は emit 命令なのです。
関連エントリ
・OpenGL のはじめ方
・OpenGL ES 2.0 Emulator
・OpenGL ES 2.0
・OpenGLES2.0 DDS テクスチャを読み込む
・OpenGLES2.0 Direct3D とのフォーマット変換
・OpenGLES 2.0 頂点フォーマットの管理
・OpenGLES2.0 の頂点
・OpenGLES2.0 D3D座標系
・OpenGLES2.0 シェーダー管理
試してみました。
・OpenGL Registry
GeometryShader はポリゴンの面単位で実行可能なシェーダープログラムです。
面単位なので、プリミティブタイプが Triangle List (GL_TRIANGLES) なら一度に
3頂点を入力として受け取ります。主な用途は下記の通りです。
・頂点演算
・面単位のマテリアル演算
・形状の操作
・出力先の変更
・StreamOutput (Transform Feedback)
わかりやすいところでは面法線の生成など面単位のマテリアル設定が考えられます。
ユニークなのは入力と関係なく出力プリミティブを組み立てられることです。
出力頂点数は任意なので、エッジだけ Line として書き出したり、面を分割したり、
面を消すことも出来ます。
例えば入力を PointList (GL_POINTS) で 1頂点だけ受け取り、Triangle で
2 プリミティブ出力すればポイントスプライトの代わりになるわけです。
出力先の変更は Direct3D だと RenderTarget Array, OpenGL では
Layered Rendering と呼ばれているようです。
Geometry Shader で書き込むフレームバッファの選択が可能で、Cube Map への
レンダリングも一回で出来る仕様になっています。
入力可能なプリミティブタイプも Direct3D 10 同様に増えています。
下記は増えた分のみ。使えるのは GeometryShader が有効な場合だけに限られます。
GL_LINES_ADJACENCY GL_LINE_STRIP_ADJACENCY GL_TRIANGLES_ADJACENCY GL_TRIANGLE_STRIP_ADJACENCY
あまり馴染みがない名称ですが、極端な言い方をすれば 4,6 頂点のプリミティブが
使えるようになったということです。
GL_TRIANGLES だと GeometryShader は 3 頂点単位で受け取りますが、
GL_TRIANGLES_ADJACENCY では一度に 6頂点受け取れることになります。
GL_LINES_ADJACENCY の 4頂点は、QUAD プリミティブの代わりとしても使えます。
ちなみに Direct3D 11 の ShaderModel 5.0 はさらに増えていて、テセレータ用に
32頂点まで任意の数の頂点を入力できるようになっています。
今回使用したビデオカードは GeForce GTX280。ステートを調べると下記の通りです。
頂点の生成が最大 1024 float なのも Direct3D 10 の ShaderModel 4.0 と同じです。
GL_MAX_GEOMETRY_OUTPUT_VERTICES = 1024 GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS = 32 GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS = 1024
● GeometryShader のコンパイル
Shader の読み込みとコンパイル手順はこれまでの VertexShader, FragmentShader
と同じです。もともとシェーダーしか使えない OpenGL ES 2.0 を使っていたため、
ちょうど GeometryShader の部分が追加された形になります。
GLuint vshader= glCreateShader( GL_VERTEX_SHADER ); glShaderSource( vshader, 1, vshader_source_text, NULL ); glCompileShader( vshader ); GLuint gshader= glCreateShader( GL_GEOMETRY_SHADER ); glShaderSource( gshader, 1, gshader_source_text, NULL ); glCompileShader( gshader ); GLuint pshader= glCreateShader( GL_FRAGMENT_SHADER ); glShaderSource( pshader, 1, pshader_source_text, NULL ); glCompileShader( pshader );
エラー判定は省いてあります。
次はコンパイルしたシェーダーをリンクして Program の作成です。
これまで VertexShader, FragmentShader だけ attach していたところに
GeometryShader が加わります。
GLuint shaderProgram= glCreateProgram(); glAttachShader( shaderProgram, vshader ); glAttachShader( shaderProgram, gshader ); glAttachShader( shaderProgram, pshader ); glLinkProgram( shaderProgram );
●ドライバの補足
GLSL の GeometryShader の書き方がわからなかったため、ドキュメント
OpenGL Shadeing Language 1.50.09 と Direct3D の知識を頼りに進めました。
最初はコンパイルすらうまく通らず、EmitVertex を用いると
「#extension GL_EXT_geometry_shader4 : enable」
を宣言しなさいとエラーが出てしまいます。
「#version 150」で GLSL 1.5 を指定すると未対応のバージョンだといわれます。
140 なら通ります。ドライバを調べてみると、最新版 190.62 は OpenGL 3.1 しか
対応していませんでした。
ドライバが OpenGL 3.2 / GLSL 1.5 に対応していなかったことが原因です。
・NVIDIA OpenGL 3.0/3.1/3.2 Support for Windows, Linux, FreeBSD, and Solaris
上のページにある、OpenGL 3.2 対応ドライバ 190.57 を入れたら、#version 150 指定
による GLSL 1.5 も、GeometryShader 専用命令も通るようになりました。
「#version 150」とだけ書いておけばよく、extension 指定は不要です。
● GLSL v1.50
「#version 150」を指定したら VertexShader でもエラーが出るようになりました。
attribute, varying 宣言は古いので、in, out を使えと言われます。
もともと attribute は頂点からの入力、varying はラスタライザの補間パラメータを
意味しています。出力先が GeometryShader かもしれないし、シェーダーパイプラインが
多層化&汎用化されたので名称が変わったものと思われます。
OpenGL ES 2.0 との互換性も残したいのでとりあえず define でごまかしました。
attribute を in に、varying を out に置き換えます。
// sysdef2.vsh (Vertex Shader) #define attribute in #define varying out #version 150 uniform vec4 World[3]; uniform mat4 PView; attribute vec3 POSITION; attribute vec3 NORMAL; attribute vec2 TEXCOORD; varying vec3 onormal; varying vec2 otexcoord; void main() { gl_Position= vec4( POSITION.xyz, 1 ) * PView; vec3 nvec; nvec.x= dot( NORMAL.xyz, World[0].xyz ); nvec.y= dot( NORMAL.xyz, World[1].xyz ); nvec.z= dot( NORMAL.xyz, World[2].xyz ); onormal= nvec; otexcoord= TEXCOORD; }
Matrix 周りが少々不自然なのは、OpenGL ES 2.0 に mat4x3 が無かったことと頂点
アニメーションを削ったためです。もともと Skinning の処理が入っていました。
同じように Fragment Shader も書き換えます。
// sysdef2.fsh (Fragment Shader) #define varying in #version 150 varying vec3 onormal; varying vec2 otexcoord; uniform sampler2D ColorMap; void main() { vec3 lightdir= vec3( 0.0, 0.0, -1.0 ); float lv= clamp( dot( normalize( onormal ), lightdir ), 0.0, 1.0 ) + 0.5; vec4 color= vec4( 1.0, 1.0, 1.0, 1.0 ) * lv; vec4 tcol= texture2D( ColorMap, otexcoord ); gl_FragColor= color * tcol; }
FragmentShader の場合 VertexShader と逆で varying が in になります。
GeometryShader は最初から in/out で記述します。
// sysdef2.gsh (Geometry Shader) #version 150 layout(triangles) in; layout(triangle_strip, max_vertices= 3) out; in Inputs { vec3 onormal; vec2 otexcoord; } gin[3]; out vec3 onormal; out vec2 otexcoord; void main() { gl_Position= gl_in[0].gl_Position; onormal= gin[0].onormal; otexcoord= gin[0].otexcoord; EmitVertex(); gl_Position= gl_in[1].gl_Position; onormal= gin[1].onormal; // (1) otexcoord= gin[1].otexcoord; EmitVertex(); gl_Position= gl_in[2].gl_Position; onormal= gin[2].onormal; // (1) otexcoord= gin[2].otexcoord; EmitVertex(); EndPrimitive(); }
プリミティブのタイプは layout() で宣言しています。
入力は block 宣言を使っており、Triangle なので 3頂点分のデータを受け取ります。
VertexShader が書き込んだシステム変数 gl_Position の値は、こちらも builtin
の gl_in[] という配列で受け取れます。
出力はこれまで通り out (varying) 宣言した変数に書き込みます。
必要なパラメータを書き込んだ後に EmitVertex() 命令で頂点が確定します。
プリミティブの区切りは EndPrimitive() 命令です。
このジオメトリシェーダーは何もせずに、頂点の出力をそのままスルーしています。
上の (1) の行を削除すると面に同じ法線が適用されるため、フラットシェーディング
風の見た目になるはずです。
同じシェーダーを DirectX の HLSL で書くとこんな感じです。
// HLSL Geometry Shader struct GS_INPUT { float4 Position : POSITION; float3 Normal : NORMAL; float2 Texcoord : TEXCOORD; }; struct GS_OUTPUT { float4 Position : SV_POSITION; float3 Normal : NORMAL; float2 Texcoord : TEXCOORD; }; [maxvertexcount(3)] void GS_Main( triangle GS_INPUT In[3], inout TriangleStream<GS_OUTPUT> gsstream ) { GS_OUTPUT Out; Out.Position= In[0].Position; Out.Texcoord= In[0].Texcoord; Out.Normal = In[0].Normal; gsstream.Append( Out ); Out.Position= In[1].Position; Out.Texcoord= In[1].Texcoord; Out.Normal = In[1].Normal; gsstream.Append( Out ); Out.Position= In[2].Position; Out.Texcoord= In[2].Texcoord; Out.Normal = In[2].Normal; gsstream.Append( Out ); gsstream.RestartStrip(); }
書式が違うだけでほとんど同じです。
Direct3D でも、アセンブラ出力すると頂点の生成は emit 命令なのです。
関連エントリ
・OpenGL のはじめ方
・OpenGL ES 2.0 Emulator
・OpenGL ES 2.0
・OpenGLES2.0 DDS テクスチャを読み込む
・OpenGLES2.0 Direct3D とのフォーマット変換
・OpenGLES 2.0 頂点フォーマットの管理
・OpenGLES2.0 の頂点
・OpenGLES2.0 D3D座標系
・OpenGLES2.0 シェーダー管理
2009/09/01
OpenGL のはじめ方
Windows 上で DirectX ばかり使ってきたので、いざ OpenGL に手をつけてみようと思っても
何を使えばいいのか良くわかりませんでした。DirectX10/11 はすでにシェーダーのみとなって
いるため、OpenGL 入門によく載っているようなレガシーな命令もちょっと違います。
WindowsSDK に付属している gl.h ヘッダは OpenGL v1.1 ですが、すでに OpenGL は
3.2 まで進化しているようです。
Windows の場合、OS との間を取り持つ wgl~ という API 群があります。
wgl と gl は、Direct3D でいえば DXGI と D3D の関係に似ています。
・MSDN Win32 Extensions to OpenGL
以前 Maya plug-in を作ったときも GL_ARB_vertex_program など OpenGL の
Extension 関数を呼び出すために wglGetProcAddress() を使いました。
Core API の場合も全く同じ方法でした。
(1) 最新のヘッダファイルを入手する
(2) wgl 命令で描画の初期化
(3) ヘッダの定義を元に wglGetProcAddress() でアドレスを取り出す
・OpenGL Registry
上のページに gl3.h や glext.h, wglext.h 等が登録されています。
関数インターフェースの定義はこの中で行われており、必要ならプロトタイプ宣言もしてくれます。
wglGetProcAddress() を用いて関数名から実際のエントリアドレスを取得すれば
API を呼び出せるようになります。
たとえば gl3.h の中では、OpenGL 2.0 の命令として glCreateShader() が定義されています。
上がプロトタイプ宣言、下が関数ポインタの型宣言です。APIENTRYP はただの '*'。
今回はエントリアドレスを直接取り出すため、下の関数ポインタ型の宣言しか使いません。
プロトタイプ宣言はデフォルトで無効になっています。
この glCreateShader() を呼び出すには下記のようにすればよいわけです。
もちろん使えるのはディスプレイドライバが対応している場合だけです。
ドライバが対応していなければ wglGetProcAddress() はエラーを返します。
このように関数名からエントリアドレスを取得するやりかたは DLL と同じです。
DirectX の場合は COM なので、関数単独ではなく class 単位で API を取り出しますが
基本は同じです。
上の例のように、OpenGL 1.2~3.2 の膨大な関数を手作業で追加するのは酷です。
自動化します。
ヘッダのプロトタイプ宣言から、必要な関数名だけ抜き出すスクリプトを作っておきます。
関数名を全部大文字にして PFN ~ PROC で囲めばインターフェースの型宣言になります。
上のスクリプトは gl3.h ヘッダから関数名だけ抜き出して下記のような一覧を生成します。
そのまま gl3.h を渡すと OpenGL 1.1 など余計な関数まで再定義してしまうので、
必要な 1.2~3.2 部分だけ切り出してから与えることにします。
Core API だけでなく拡張命令も同じように追加できるでしょう。
出力ファイル名を GLExtensionList.inc としておきます。
これを C ソースで include し、GLDEFPROC() を用途に応じて再定義してして使い分けます。
ヘッダ側
ソース側
これで GLFunction.h を include すれば、OpenGL 3.2 までの命令をそのまま
使えるようになります。追加 lib は WindowsSDK の OpenGL32.lib です。
使用可能なのはドライバが対応している場合だけ。
また起動時は最初に一度 InitOpenGL() を呼び出しておく必要があります。
OpenGL ES 2.0 用に作成した描画コードが、一カ所直しただけでそのままコンパイルできました。
GLSL のシェーダーコードも共有しており、きちんど動作します。
ドライバと環境は GeForce 9800GT + 190.62 + Windows7 x64 。
モデルデータもテクスチャも GL ES 2.0 と全く同じ物です。
修正したのは下記の点
OpenGL 3.2 に厳密に従うには、ピクセルフォーマットなどテクスチャの読み込み部も
手を入れる必要がありそうです。
関連エントリ
・OpenGL ES 2.0 Emulator
・OpenGL ES 2.0
・OpenGLES2.0 DDS テクスチャを読み込む
・OpenGLES2.0 Direct3D とのフォーマット変換
・OpenGLES 2.0 頂点フォーマットの管理
・OpenGLES2.0 の頂点
・OpenGLES2.0 D3D座標系
・OpenGLES2.0 シェーダー管理
何を使えばいいのか良くわかりませんでした。DirectX10/11 はすでにシェーダーのみとなって
いるため、OpenGL 入門によく載っているようなレガシーな命令もちょっと違います。
WindowsSDK に付属している gl.h ヘッダは OpenGL v1.1 ですが、すでに OpenGL は
3.2 まで進化しているようです。
Windows の場合、OS との間を取り持つ wgl~ という API 群があります。
wgl と gl は、Direct3D でいえば DXGI と D3D の関係に似ています。
・MSDN Win32 Extensions to OpenGL
以前 Maya plug-in を作ったときも GL_ARB_vertex_program など OpenGL の
Extension 関数を呼び出すために wglGetProcAddress() を使いました。
Core API の場合も全く同じ方法でした。
(1) 最新のヘッダファイルを入手する
(2) wgl 命令で描画の初期化
(3) ヘッダの定義を元に wglGetProcAddress() でアドレスを取り出す
・OpenGL Registry
上のページに gl3.h や glext.h, wglext.h 等が登録されています。
関数インターフェースの定義はこの中で行われており、必要ならプロトタイプ宣言もしてくれます。
wglGetProcAddress() を用いて関数名から実際のエントリアドレスを取得すれば
API を呼び出せるようになります。
たとえば gl3.h の中では、OpenGL 2.0 の命令として glCreateShader() が定義されています。
#define APIENTRY #define APIENTRYP APIENTRY * #define GLAPI extern GLAPI GLuint APIENTRY glCreateShader (GLenum); ~ typedef GLuint (APIENTRYP PFNGLCREATESHADERPROC) (GLenum type);
上がプロトタイプ宣言、下が関数ポインタの型宣言です。APIENTRYP はただの '*'。
今回はエントリアドレスを直接取り出すため、下の関数ポインタ型の宣言しか使いません。
プロトタイプ宣言はデフォルトで無効になっています。
この glCreateShader() を呼び出すには下記のようにすればよいわけです。
// 取り出し PFNGLCREATESHADERPROC glCreateShader= (PFNGLCREATESHADERPROC)wglGetProcAddress( "glCreateShader" ); // 呼び出し glCreateShader( shader );
もちろん使えるのはディスプレイドライバが対応している場合だけです。
ドライバが対応していなければ wglGetProcAddress() はエラーを返します。
このように関数名からエントリアドレスを取得するやりかたは DLL と同じです。
DirectX の場合は COM なので、関数単独ではなく class 単位で API を取り出しますが
基本は同じです。
上の例のように、OpenGL 1.2~3.2 の膨大な関数を手作業で追加するのは酷です。
自動化します。
ヘッダのプロトタイプ宣言から、必要な関数名だけ抜き出すスクリプトを作っておきます。
import re import sys mp_api= re.compile( "^GLAPI\s+[a-zA-Z0-9_*]+\s+APIENTRY\s+(.*)\s+\(" ) def ProcList( filename ): f= open( filename, 'r' ) for line in f: pat_api= mp_api.search( line ) if pat_api != None: func= pat_api.group(1) print "GLDEFPROC( PFN"+ func.upper() + "PROC, " + func + " )" f.close() ProcList( sys.argv[1] )
関数名を全部大文字にして PFN ~ PROC で囲めばインターフェースの型宣言になります。
上のスクリプトは gl3.h ヘッダから関数名だけ抜き出して下記のような一覧を生成します。
GLDEFPROC( PFNGLATTACHSHADERPROC, glAttachShader ) GLDEFPROC( PFNGLBINDATTRIBLOCATIONPROC, glBindAttribLocation ) GLDEFPROC( PFNGLCOMPILESHADERPROC, glCompileShader ) GLDEFPROC( PFNGLCREATEPROGRAMPROC, glCreateProgram ) GLDEFPROC( PFNGLCREATESHADERPROC, glCreateShader ) GLDEFPROC( PFNGLDELETEPROGRAMPROC, glDeleteProgram ) GLDEFPROC( PFNGLDELETESHADERPROC, glDeleteShader ) GLDEFPROC( PFNGLDETACHSHADERPROC, glDetachShader ) ~
そのまま gl3.h を渡すと OpenGL 1.1 など余計な関数まで再定義してしまうので、
必要な 1.2~3.2 部分だけ切り出してから与えることにします。
Core API だけでなく拡張命令も同じように追加できるでしょう。
出力ファイル名を GLExtensionList.inc としておきます。
これを C ソースで include し、GLDEFPROC() を用途に応じて再定義してして使い分けます。
ヘッダ側
// GLFunction.h #include <WinGDI.h> #include <gl/gl.h> #include <GL3/gl3.h> #define GLDEFPROC(type,name) extern type name; # include "GLExtensionList.inc" #undef GLDEFPROC extern void InitOpenGL();
ソース側
// GLFunction.cpp #define GLDEFPROC(type,name) type name; # include "GLExtensionList.inc" #undef GLDEFPROC struct T_ProcList { const char* Proc; void** Addr; }; static T_ProcList ProcList[]= { #define GLDEFPROC(type,name) { #name, (void**)&name }, # include "GLExtensionList.inc" #undef GLDEFPROC { NULL, NULL, }, }; void InitOpenGL() { const T_ProcList* tp= ProcList; for(; tp->Proc ; tp++ ){ *tp->Addr= wglGetProcAddress( tp->Proc ); if( !*tp->Addr ){ int errcode= GetLastError(); ERROR_UTF8( "'%s' not found %d/%x\n", tp->Proc, errcode, errcode ); //*tp->Addr= _UnknownAPI_Func; } } }
これで GLFunction.h を include すれば、OpenGL 3.2 までの命令をそのまま
使えるようになります。追加 lib は WindowsSDK の OpenGL32.lib です。
使用可能なのはドライバが対応している場合だけ。
また起動時は最初に一度 InitOpenGL() を呼び出しておく必要があります。
OpenGL ES 2.0 用に作成した描画コードが、一カ所直しただけでそのままコンパイルできました。
GLSL のシェーダーコードも共有しており、きちんど動作します。
ドライバと環境は GeForce 9800GT + 190.62 + Windows7 x64 。
モデルデータもテクスチャも GL ES 2.0 と全く同じ物です。
修正したのは下記の点
glClearDepthf( depth ); // GL ES のみ ↓ glClearDepth( depth );
OpenGL 3.2 に厳密に従うには、ピクセルフォーマットなどテクスチャの読み込み部も
手を入れる必要がありそうです。
関連エントリ
・OpenGL ES 2.0 Emulator
・OpenGL ES 2.0
・OpenGLES2.0 DDS テクスチャを読み込む
・OpenGLES2.0 Direct3D とのフォーマット変換
・OpenGLES 2.0 頂点フォーマットの管理
・OpenGLES2.0 の頂点
・OpenGLES2.0 D3D座標系
・OpenGLES2.0 シェーダー管理