月別アーカイブ: 2007年9月

3D一般 Autodesk Maya2008 と Direct3D

Autodesk Maya 2008 来ました。
保守に入っていればすぐにダウンロードすることができます。
これまでは 7.0、8.0、8.5 のようにナンバリングされていましたが
今回から 2008 です。略して Maya08。Maya8.0 に似てますが違います。

インストールフォルダも 2008 になりました。
起動時の Output Window にはまだ Maya9.0 と表示されています。
内部的には本当は Version 9.0 ?・・いえいえ
API の Version 番号は一気に増えて 200800 になっていました。
以前は ~ 700、800、850 だったので、内部的にも本当に 2008 に
なっているみたいです。

 API 850 → 200800

いろんな機能追加があると思いますが、D3D 関連だと

・mentalray の dds 入力サポート
・hlslShader の追加

あたりが主なトピックでしょうか。
Maya 自体は dds に対応していたものの mentalray では使えなかった
ので、うっかり dds を貼ったシーンをそのままレンダリングして
落ちたり・・。それを回避するために事前に texture path を置き
換える mel を作ったり、なんてことが過去にはありました。

ビューポートで描画できるハードウエアシェーダーは 4.5 あたりから
ついており、今までも CgFx 等を使って表示させることができました。
今度は HLSL の対応です。Direct3D の Effect (fx) フォーマットの
ファイルを読み込み、マテリアルとして適用することができます。
実際に使ってみました。

 ・Plug-in マネージャーで hlslShader.mll を有効にする
 ・Panel の Renderer を Default (High Quality でない) にする
 ・Panel の Shading から Hardware Textureing を ON にする

これで hlslShader のノードを作って描画確認できます。

とりあえず
C:\Program Files\Autodesk\Maya2008\devkit\plug-ins\
に入っている、Maya_fixedFunction.fx を読み込ませると簡単な
描画テストができるようです。

CgFx と違い、OpenGL ではなく本当に Direct3D を使っています。
ついに Maya 上で Direct3D を扱えるようになったわけですね。
API 的には class MD3D9Render が追加されており、ここから
IDirect3DDevice9 のインターフェースを取得することができるようです。

基本的には

World
WorldInverse
View
ViewInverse
Projection
WorldView
WorldViewProjection

などの古くから使われている一般的な Semantic に対応しています。
また Annotation を使った DXSAS にも対応しているようです。
(DXSAS = DirectX Standard Annotations and Semantics)
ただし Maya 内のライトとのリンクはまだ行われておらず、
シェーダーに入力されるパラメータの一種として設定しなければ
ならないようです。

実際に hlslShader を使いながらの開発はまだしないかもしれま
せんが、D3D のインターフェースを直接扱えるようになった点は
かなり大きな変化だと思います。

残念ながら D3D10 ではありません。Direct3D 10 だと Vista に
限定されてしまうし、まだ仕方ないのかもしれません。

Direct3D 10 Buffer Rename を検出してみる

Buffer への書き込みに DISCARD + Map() を使うことで、ドライバが
バッファの Rename を行うことができます。つまりアプリケーション
側では同一のバッファのつもりでも、実際はぜんぜん違うメモリに
書き込んでいたりするわけです。
これは最適化のためで、フレームバッファと同じようにドライバ側で
勝手に SwapChain 化してくれるようなもの。

その代わり Rename 数の上限によってバッファが枯渇する可能性が
あるそうです。(関連は下記エントリ)
Gamefest Japan 2007 (2) Direct3D 10

この Rename の状況を軽く調べてみました。

●同じバッファが割り当てられているかどうか確認する方法

(1) Map() した時のアドレス値 (*ppData の値) を比較する。
(2) D3D10_MAP_WRITE_DISCARD かつ D3D10_CPU_ACCESS_WRITEのみ
  であるにもかかわらず、敢えて前回書き込んだ値を読み出してみる。

(1) だけでも十分かもしれませんが念のため (2) も調べました。

●条件

ConstantBuffer を作成してみます。Map() でアクセスするには
下記の指定が必要です。

 ・D3D10_USAGE_DYNAMIC
 ・D3D10_CPU_ACCESS_WRITE
 ・D3D10_BIND_CONSTANT_BUFFER

使用した GPU は GeForce8800GTS です。

●未使用バッファ 16byte

16byte のバッファを作って、毎フレーム Map() で書き込んでみました。
このバッファは特に ~SetConstantBuffer() していないので、Busy に
なることはないはずです。

左から
・アドレス
・Bufferサイズ
・これから書き込む値
・書き込み前に読み出したメモリの値
と並んでいます。

addr     size    write     read
073eb400 16byte (00000000) 00000000
073eb800 16byte (00000001) 00000000
073eba00 16byte (00000002) 00000000
073ebc00 16byte (00000003) 00000000
073ebe00 16byte (00000004) 00000000
073ec000 16byte (00000005) 00000000
073ec200 16byte (00000006) 00000000
073ec400 16byte (00000007) 00000000 (A)
073ec600 16byte (00000008) 00000000
~
073f4600 16byte (00000042) 00000000
073f4800 16byte (00000043) 00000000
073ec400 16byte (00000044) 00000007 (B) 一周 (A)で書き込んだ 7
073ec600 16byte (00000045) 00000008
~
073f4600 16byte (0000007f) 00000042
073f4800 16byte (00000080) 00000043
073ec400 16byte (00000081) 00000044 (C) 一周 (B)で書き込んだ 44
073ec600 16byte (00000082) 00000045
073ec800 16byte (00000083) 00000046
~

アドレスは 512byte 単位で割り振られています。60個程度のバッファが
順次割り当てられ、繰り返し利用されているように見えます。
未使用バッファでも毎回違うアドレスになるのは予想外でした。

●未使用バッファ 512byte

512byte のバッファではずれが小さくなっています。どちらにしろ
未使用バッファなのでたまたまかもしれません。

addr     size     write     read
0727b600 512byte (00000000) 00000000
0727b800 512byte (00000001) 00000000
0727b600 512byte (00000002) 00000000
0727b800 512byte (00000003) 00000001
0727b600 512byte (00000004) 00000002
~

●実バッファ 1088byte

実際に ~SetConstantBuffer() してシェーダー参照されている
描画に使っているバッファを見てみます。

    addr     size   write read
*L1 0754b000 1088byte (0) 0
*L1 0754b000 1088byte (1) 1
*L1 0754b000 1088byte (2) 2
*L1 0754b000 1088byte (3) 3
*L1 0754b000 1088byte (4) 4
~

ここでの write は、1つ前のフレームで書き込んだ値です。
アドレスも、前回書き込んだ値も一致しています。
同じバッファが割り当てられています。
このプログラムは厳密に CPU と GPU の同期を管理しているため、
次の Map() までに描画が完了してしまっている可能性があります。

●実バッファ 1088byte ×2

1フレーム中、同じバッファに2度転送を行ってみました。
L0/L1 のペアで1フレームです。

    addr     size   write read
*L0 0735b000 1088byte (0) 0
*L1 0735b500 1088byte (1) 0
*L0 0735b000 1088byte (2) 1
*L1 0735b500 1088byte (3) 2
*L0 0735b000 1088byte (4) 3
*L1 0735b500 1088byte (5) 4
~

今度はそれぞれ異なるバッファが割り当てられています。
参照されている Buffer は実際の描画が完了するまで Busy に
なり、アクセスから保護されている様子がわかります。
やっと予想した動作が見えてきました。

●実バッファ 1088byte ×20

今度は1フレーム中、同じバッファに20回書き込みます。

    addr     size   write read
*L0 0719b000 1088byte (0) 0
*L1 0719b500 1088byte (1) 0
*L2 0719ba00 1088byte (2) 0
~
*L17 071a0500 1088byte (17) 0
*L18 071a0a00 1088byte (18) 0
*L19 071a0f00 1088byte (19) 0
*L0 0719b000 1088byte (20) 1
*L1 0719b500 1088byte (21) 2
*L2 0719ba00 1088byte (22) 3
~

Rename の様子が良くわかります。
ちなみに各 Map() と Map() の間に Draw を挟んでいないので、
本来は最後の Map() 以外は破棄してかまわない状況です。
今のところ Map( DISCARD ) を実行した数分だけバッファが
割り当てられているようです。
Busy の情報はリネーム元のバッファ1つ分しか持っていない
のでしょうか。

●実バッファ 1088byte ×20000

2000回では変化無かったので、一気に 20000回行きます。

*L0 071fb000 1088byte (0) 0
*L1 071fb500 1088byte (1) 0
~
*L3916 0aee5c00 1088byte (3916) 0
*L3917 0aee6100 1088byte (3917) 0
*L3918 071fb000 1088byte (3918) 1
*L3919 071fb500 1088byte (3919) 2
*L3920 071fba00 1088byte (3920) 3
~

20000回を待たずに再利用されています。
やっぱり本当は使っていないことがばれているのかもしれません。
ここまでで考えられるバッファサイズはおよそ 8Mbyte でしょうか。
動きは見えましたが、完全に捕まえるためにはきちんとテスト
プログラムを作った方がよさそうです。ちょっと試したくらいでは
まだわからないですね。

Gamefest Japan 2007 (2) Direct3D 10

引き続き Microsoft Gamefest Japan 2007 の話題です。
関連エントリ
Gamefest Japan 2007 (1) Direct3D 10 と Meltdown
Microsoft Gamefest Japan 2007

Direct3D 10 に直接関連するのは下記の 2コマです。

1. Windows Vista グラフィックス 開発の手ほどき: Direct3D 10 and 10.1
2. Windows to Reality : D3D10 グラフィックスのゲームへの投入

メインはたぶん 2. の方でしょう。内容は、D3D9 から D3D10 へ
の移行を促すためのアドバイスです。

・9 から 10 に移行しても API を変えただけでは必ずしも速くならないこと
・どうして API や仕組みを変えたのか
・理由を踏まえてどう使えばいいのか
・Direct3D9 から移行しつつ 10 で想定した使い方を引き出す手法

とはいえ Direct3D10 の SDK に触れたことが無いと、少々
ぴんとこない内容だったかもしれません。
そのため前提となる知識として、Direct3D10 を解説した 1. の
「Windows Vista グラフィックス 開発の手ほどき: Direct3D 10 and 10.1」
が入ります。

逆にすでに D3D10 上で設計し、実際に開発をしている人に
とっては、移行時のテクニックも不要なので参考になる点は
少なかったかもしれません。
現在 D3D9 を使っている人、または移行中の人がターゲットです。

D3D9 から D3D10 への設計の変更や API の大きな変更は、
技術者が新たに使い方を覚え直す必要があり、また移植性や
ソースの互換性を失うリスクがあります。
それでもやる価値があると判断したわけで、その一番の目的は
パフォーマンスの向上でした。

ところが D3D10 の機能変更の意義と、新しい設計の意味を
きちんと理解して使わなければパフォーマンスがさっぱり
あがらなかったものと考えられます。
つまり単なる移植で D3D9 から機械的に API を置き換えた
だけではだめだということです。

そのポイントをいくつか絞って紹介しており、比較的大きな
変更をしなくても D3D10 の設計思想に合わせられる折衷案も
合わせて提示されています。

最終的な結論は、やっぱり D3D10 の機能を活用し、
そのために新たに設計しなおすことが一番とのこと。

以下いくつか気になった点など

バッファを Map(Lock) して CPU がアクセスする場合、
DISCARD や NO_OVERWRITE 指定は高速だということが良く知ら
れています。その理由は GPU/CPU が同期待ちをする必要が
無いからで、特に DISCARD はドライバが必要に応じて
Buffer Rename を行います。

この Rename 数には上限があって、バッファが枯渇する
可能性があることが述べられていました。
なるほど、そこまで考えたことはありませんでした。
ConstantBuffer は DISCARD アクセスしかできないので、
更新手段を選択する判断材料になりそうです。

UpdateSubresourece() に関する説明は、メモリコピーの負荷が
アプリケーション側しか考慮していないように見えたので
少々わかりにくかったかもしれません。

Clear~() 系はフレームバッファ全体なので、ステートに
基づいたクリアが必要ならシェーダーを作ってポリゴンを
書けとのこと。

cbuffer より tbuffer の方がランダムアクセスに適している
場合があるそうです。index によるアクセスなど。
これは意外でした。
そもそも cbuffer が速くないのか、
インデックスのアドレッシングが苦手なのか、
texture cache のおかげなのか、
いつか検証してみたいポイントです。

[unroll(n)] は n 回までのアンロールを強制して、最適化
のヒントに使える、と書かれています。
でも以前試した限りでは、回数指定をつけると n 回で
ループ自体を打ち切ってしまうのでプログラムの動作その
ものが変化してしまいます。もしかしたらこれは意図した
動作では無いのかもしれません。

ConstantBuffer は自前で管理せよとのこと。
この辺は構造からしてやっぱり、といった感じ。

Direct3D 10.1 に関しては特に目新しい情報はありませんでした。
ShaderModel4.1 の変更は思ったより小さいかもしれません。
単に 10.1 用の新しいリソース命令が追加されただけ、とか
十分ありえます。ps1.0→1.3 と同じような感じで。

Gamefest Japan 2007 (1) Direct3D 10 と Meltdown

Microsoft の Gamefest Japan 2007 に参加してきました。
Direct3D 10 に直接関連するセッションは 2つ。

2007/09/06
1. Windows Vista グラフィックス 開発の手ほどき: Direct3D 10 and 10.1
2. Windows to Reality : D3D10 グラフィックスのゲームへの投入

DirectX のイベントといえば Meltdown です。
ここしばらくの間、Meltdown は単独開催ではなく CEDEC 協賛
セッションとして行われてきた印象があります。
調べてみました。
実際に Meltdown という名前で CEDEC の中で行われたのは
2回だけだったようです。

●Meltdown Tokyo 1997
●Meltdown Tokyo 98 SUMMER
●Meltdown Tokyo 1999
●Meltdown Tokyo 2000
●Meltdown Tokyo 2001
●CEDEC 2002 DirectX Day
 http://www.microsoft.com/japan/msdn/directx/techarts_dx8.aspx
●Meltdown in CEDEC 2003
 http://www.microsoft.com/japan/msdn/directx/meltdown2003/default.aspx
●CEDEC Meltdown 2004
●Micrtosoft Game Developers Day CEDEC 2005
●2006 無し

Meltdown の初期のころは互換性テストが目的で、developer
は各社の新しいビデオカードにいち早く触れる良い機会でも
ありました。
初参加はたぶん 1997 頃だと思います。Mystique や
PERMEDIA2 など、DirectX にあわせた 2世代目 GPU が揃って
登場してきたあたりです。

開発中でまだドライバが不安定なものもありましたが、
それまで使ってきたビデオカードと比べると、どれも非常に
パフォーマンスがあがっています。
そして Direct3D との相性もよくなり、対応機能が増えている
ことに素直に感動してました。
が、それも最後のブースを見るまでのこと。

たまたま最後にスケジューリングしていたのは、当時はまだ
無名だった NVIDIA です。横倒しで机の上にむき出しのまま
組まれた PC に不安を覚えながら、プロトタイプの RIVA128 で
手持ちのプログラムを起動してびっくり。
口からでた感想は一言 「今までで一番速い」。

CEDEC と一緒になってからは、互換性よりも新しい概念である
shader をどう活用するのか、という点にフォーカスが変わります。
ちょうど shader によってリアルタイムCG は非常にホットな
時代を迎えています。
必然的に現行または将来可能となる技術的な内容が多く、
トレンドを反映した高度な shader 論と、急激に変化する
API や GPU 機能の解説が多くなります。
密度の高い内容となりました。

多少落ち着いてきた 2004 年あたりからは、また若干方向に
変化が見られます。急に高度化した内容に対するより戻しか、
開発者向けの救済路線が徐々に登場してきます。
XNA というキーワードが出たものの一体それは何なのか、
ミドルウエアなのか、リソースマネージャなのか、
グループウエアなのか。
「開発コストを下げるため」の1点以外良くわからない混乱の
時期でもありました。

XNA の路線が固まってからは現状のとおりです。
Gamefest Japan 2007 もこの流れを反映しており、おそらく
開催の中心は XNA にあったものと思われます。

最初にあげた Direct3D 10 の 2つのセッションに関しては、
未経験者に対する API や違いの紹介、Direct3D 9 から
移行する方への変化の説明、乗り換え時の注意点等といった、
ポイントを絞った最小限のものとなっていました。
表現など shader 技術的な話ではなく、まずは API の乗換えが
最重要課題なのかもしれません。

内容については次回でもう少し詳しく書いてみます。

小型 Bluetooth アダプタ Princeton PTM-UBT3S

届きました。
Princeton PTM-UBT3S 1

プリンストンの超小型 Bluetooth アダプタです。
Princeton PTM-UBT3S

確かに小さいです。出っ張り部分は約 8mm。想像よりは出っ張る感じ。
Princeton PTM-UBT3S 2
Princeton PTM-UBT3S 3

早速ドライバを入れて、emobile EM・ONE をペアリングして、
Bluetooth でダイヤルアップできるようになりました。
USB 直結よりは遅くなるけどやっぱり無線は便利です。

あっ
Princeton PTM-UBT3S 4

USB コネクタから引き抜こうとしたら早速壊れました。
せっかくなので裏の写真も。
Princeton PTM-UBT3S 5

コネクタの真裏に基板が収まっていました。

組み立てたら一応動いたようです。
コネクタから引き抜く時はくれぐれもご注意ください。