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

Direct3D11 影の設定 ShadowMap

久しぶりに影を扱ったのでメモです。

Direct3D 10 以降、ShaderModel 4.0 以降はハードウエアシャドウマップが当たり前に
使えるようになっているので比較的簡単になりました。
Direct3D8 ~ Direct3D9、ShaderModel 1.0 ~ 3.0 までは NVIDIA GeForce
独自の拡張機能でした。ハードウエアシャドウマップは

・DepthBuffer を直接参照するため他にバッファを用意することがないこと
・通常のサンプリングと違い、比較した結果の Bool 値 1.0 or 0.0 を返すこと
・比較結果をバイリニア補間するため、追加コストなしにハードウエアでフィルタリング可能なこと

等の利点があります。
ShaderModel 2.0 以降なら同等の機能をシェーダーで記述することができます。
旧 RADEON 向けシェーダーでは必須となりますが、追加バッファが必要でバイリニア
用サンプリングのコストがゼロにならないので完全に同じとはいえませんでした。

Direct3D 10 では標準機能の一部になったので、ShaderModel 4.0 に対応した
RADEON HD 2900XT 以降はハードウエアシャドウマップが使えます。
下位の ShaderModel でも利用可能で、RADEON HD 2900XT では
ShaderModel 3.0 を使っても GeForce 向けシェーダーがそのまま動作しました。
最初試したときは感動。

ShaderModel 4.0 以降は値を比較しながらサンプリングできる汎用機能として用意されて
いるので、GeForce 用、RADEON 用とシェーダーやプログラムを分ける必要がなくなりました。

バッファの作成

// depth buffer 用リソースの作成
CD3D11_TEXTURE2D_DESC	ddesc(
		DXGI_FORMAT_R24G8_TYPELESS,
		width,
		height,
		1,	// array
		1,	// mip
		D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_DEPTH_STENCIL,
		D3D11_USAGE_DEFAULT,
		0,	// cpu
		1,	// sample count
		0,	// quality
		0	// misc
		);

iDevice->CreateTexture2D( &ddesc, NULL, &iShadowDepth );


// Depth Buffer 用 View の作成
// レンダリング時はこちら
CD3D11_DEPTH_STENCIL_VIEW_DESC	dsdesc(
		D3D11_DSV_DIMENSION_TEXTURE2D,
		DXGI_FORMAT_D24_UNORM_S8_UINT,
		0,	// mipSlice
		0,	// firstArraySlice
		1,	// arraySize
		0	// flags
		);

iDevice->CreateDepthStencilView( iShadowDepth, &dsdesc, &iShadowDepthView );

// Shader Resource 用 View の作成
// サンプリング時はこちら
CD3D11_SHADER_RESOURCE_VIEW_DESC	sdesc(
		D3D11_SRV_DIMENSION_TEXTURE2D,
		DXGI_FORMAT_R24_UNORM_X8_TYPELESS,
		0,	// mostDetailedMip
		1,	// mipLevels
		0,	// firstArraySlice
		1	// arraySize
		);

iDevice->CreateShaderResourceView( iShadowDepth, &sdesc, &iShadowView );

使用している CD3D11_TEXTURE2D_DESC や CD3D11_DEPTH_STENCIL_VIEW_DESC
等は DirectX SDK March 2009 以降使えるようになった新機能です。
各種構造体を初期化してくれるヘルパーで、D3D11.h で定義されています。
ヘッダを見て発見しました。

サンプラーの作成

CD3D11_SAMPLER_DESC	desc( D3D11_DEFAULT );

desc.AddressU= D3D11_TEXTURE_ADDRESS_CLAMP;
desc.AddressV= D3D11_TEXTURE_ADDRESS_CLAMP;
desc.AddressW= D3D11_TEXTURE_ADDRESS_CLAMP;

desc.Filter= D3D11_FILTER_COMPARISON_MIN_MAG_LINEAR_MIP_POINT;
desc.ComparisonFunc= D3D11_COMPARISON_LESS;

iDevice->CreateSamplerState( &desc, &iShadowSampler );

比較結果のフィルタリングなので、D3D11_FILTER_COMPARISON_~ と
COMPARISON 付きのフィルタを指定します。
CD3D11_SAMPLER_DESC に渡している D3D11_DEFAULT は、デフォルト値で構造体を
初期化することを意味しています。

クリアと RenderTarget の設定

void __fastcall
ShadowBuffer::Clear( ID3D11DeviceContext* iContext )
{
	iContext->ClearDepthStencilView( iShadowDepthView,
		D3D11_CLEAR_DEPTH|D3D11_CLEAR_STENCIL, DVF(1), 0 );
}

void __fastcall
ShadowBuffer::SetRenderTarget( ID3D11DeviceContext* iContext )
{
	ID3D11RenderTargetView*	irtv= NULL;
	iContext->OMSetRenderTargets( 1, &irtv, iShadowDepthView );

	CD3D11_VIEWPORT	view( DVF(0), DVF(0), ShadowWidth, ShadowHeight );
	iContext->RSSetViewports( 1, &view );
}

ShadowBuffer にレンダリングする場合の前処理です。
OMSetRenderTargets() では DepthBuffer のみ指定します。
RenderTarget が NULL の場合書き込みが行われません。

リソースの設定

void __fastcall
ShadowBuffer::SetResources( ID3D11DeviceContext* iContext )
{
	iContext->PSSetShaderResources( SHADOW_REGISTER_ID, 1, &iShadowView );
	iContext->PSSetSamplers( SHADOW_REGISTER_ID, 1, &iShadowSampler );
}

作成した ShadowBuffer を用いて影描画する場合の前設定です。
シェーダーとのバインドを簡略化するために、ShadowBuffer 用のレジスタ番号を
決めうちにしています。

シェーダー

struct VS_INPUT {
	float3	vPos	: POSITION;
	float3	vNormal	: NORMAL;
	float2	vTex0	: TEXCOORD;
#if CF_WEIGHT
	float4	vWeight	: WEIGHT;
	uint4	vIndex	: INDEX;
#endif
};

struct VS_OUTPUT {
	float4	vPos	: SV_Position;
	float2	vTex0	: TEXCOORD;
};

VS_OUTPUT vmain( VS_INPUT idata )
{
	VS_OUTPUT	odata;
	float4x4	world;

#if CF_WEIGHT
	world=  World[idata.vIndex.x] * idata.vWeight.x;
	world+= World[idata.vIndex.y] * idata.vWeight.y;
	world+= World[idata.vIndex.z] * idata.vWeight.z;
	world+= World[idata.vIndex.w] * idata.vWeight.w;
#else
	world= World[0];
#endif

	float4	wpos= mul( float4( idata.vPos.xyz, 1 ), world );
	odata.vPos= mul( wpos, PV );
	odata.vTex0= idata.vTex0;

	return	odata;
}

typedef VS_OUTPUT	PS_INPUT;

Texture2D	tex0		: register( t0 );
SamplerState	sample0		: register( s0 );

float pmain( PS_INPUT idata ) : SV_Target
{
#if CF_ALPHA1BIT
	float	alpha= tex0.Sample( sample0, idata.vTex0.xy ).w;
	if( alpha < 0.8f ){
		clip( -1 );
	}
#endif
	return	0;
}

ShadowBuffer を生成する場合は特別なことが何もありません。
カラーを書かないので不要に見えますが、テクスチャの Alpah 抜きに対応する場合は
テクスチャも読み込まなければならなくなります。

今回は特別なことを何もしてないので大丈夫ですが、影の合成を効率化しようと
凝ったことをし出すとテクスチャの扱いが結構負担になってきます。
パス毎にフィルタリングや Mip 指定、uv の計算等を厳密にあわせておかないと、
ちょっとしたレンダーステートの差がテクスチャの隙間を生み出してしまうからです。
例えば DepthBuffer の事前生成など。

描画用シェーダー

struct VS_INPUT {
	float3	vPos	: POSITION;
	float3	vNormal	: NORMAL;
	float2	vTex0	: TEXCOORD;
#if CF_WEIGHT
	float4	vWeight	: WEIGHT;
	uint4	vIndex	: INDEX;
#endif
};

struct VS_OUTPUT {
	float4	vPos	: SV_Position;
	float3	vNormal	: NORMAL;
	float2	vTex0	: TEXCOORD;
	float4	vShadow	: SHADOW;
};

VS_OUTPUT vmain( VS_INPUT idata )
{
	VS_OUTPUT	odata;
	float4x4	world;

#if CF_WEIGHT
	world=  World[idata.vIndex.x] * idata.vWeight.x;
	world+= World[idata.vIndex.y] * idata.vWeight.y;
	world+= World[idata.vIndex.z] * idata.vWeight.z;
	world+= World[idata.vIndex.w] * idata.vWeight.w;
#else
	world= World[0];
#endif

	float4	wpos= mul( float4( idata.vPos.xyz, 1 ), world );
	odata.vPos= mul( wpos, PV );
	odata.vNormal.xyz= mul( idata.vNormal, (float3x3)world );
	odata.vTex0= idata.vTex0;

	odata.vShadow= mul( wpos, ShadowMatrix );

	return	odata;
}

typedef VS_OUTPUT	PS_INPUT;

Texture2D	tex0		: register( t0 );
SamplerState	sample0		: register( s0 );

Texture2D		shadowTex0	: register( t8 );
SamplerComparisonState	shadowSample0	: register( s8 );

float4 pmain( PS_INPUT idata ) : SV_Target
{
	float3	diffuse= Ambient.xyz;
	float3	specular= float3( 0, 0, 0 );
	float4	color= float4( 0, 0, 0, 0 );

	float3	sh_uv= idata.vShadow.xyz;
	sh_uv.xyz/= idata.vShadow.w;
	sh_uv.x=  sh_uv.x * 0.5f + 0.5f;
	sh_uv.y= -sh_uv.y * 0.5f + 0.5f;
	sh_uv.z-= 0.000004f; // 適当

	float	shdepth= shadowTex0.SampleCmpLevelZero( shadowSample0, sh_uv.xy, sh_uv.z );
//	float	shdepth= shadow_pcf( sh_uv );
	lightMask= saturate( shdepth + 0.0f );

	float3	normal= normalize( idata.vNormal.xyz );
	diffuse.xyz+= saturate( dot( normal, _LightDir ) ) * Diffuse.xyz * lightMask;
	specular.xyz+= pow( saturate( dot( normal,
		normalize(idata.vEyeVec + _LightDir ) )), Specular.w )
				* Specular.xyz * lightMask;

	float4	texcol= tex0.Sample( sample0, idata.vTex0.xy );
	color.xyz+= texcol.xyz * diffuse.xyz + specular.xyz;
	color.w= texcol.w * Ambient.w;

#if CF_ALPHA1BIT
	if( color.w < 0.8f ){
		clip( -1 );
	}
#endif
	return	color;
}

VertexShader では描画用の Matrix と影用の Matrix、2つの座標系へ変換します。
実際の PixelShader は非常に長いので光源演算を大幅に削りました。

影のサンプリングは SampleCmpLevelZero() を使っています。
Depth を読み込み、指定した z 値と比較した結果をフィルタリングして返すので、
対応する光源に対して影の中かどうかわかります。
影用 uv への変換は効率化するなら Matrix に埋め込んでおくことができます。
埋め込むと影を落とすときと完全に同じ Matrix にならないことが難点。

基本的な描画手順

// Shadow Buffer の作成
ShadowBuffer->Clear( iContext );
ShadowBuffer->SetRenderTarget( iContext );
iContext->OMSetDepthStencilState( iDSS_ZEnable, 0 );

 // shadow レンダリング用 matrix の設定など
 // shadow buffer 生成のシェーダーで描画


// 影をサンプリングしながらレンダリング
 // 本来の RenderTarget の設定
 // レンダリング用 matrix の設定
ShadowBuffer->SetResources();

 // 描画用シェーダーで描画

影、不透明、半透明 といった順番になります。
DepthBuffer の事前生成を行う場合や、複数の光源の影を落とす場合は描画パスが増加していきます。
alpha 抜きを使う場合は半透明と同じように、さらに別グループに分類した方が良いかもしれません。

関連エントリ
DirectX SDK March 2009
Direct3D 10 DXGI_FORMAT の機能対応一覧
D3D10/DX10 D3D10_FILTER の新機能
D3D10/DX10 RADEON HD2900XT

メビウス PC-NJ70A 画面解像度とタッチ

SHARP メビウスのモニターに当選してしまいました。

募集がすぐ終わったとか倍率高いとか新しいセンサーを使っているとか、
ちょうどその話をしていた直後だったので目を疑いました。
なにせ「募集時点ではスペックや詳細が未発表だったので、自分はもっと小型の
デバイスを期待してた・・」とかその場で興味なさそうに発言してた本人が
当たってしまったのだから尚更です。

すでに発売されているようですが、モニター自体は来週以降なので少々待たされます。

SHARP Mebius PC-NJ70A

スペック的にはほぼ一般的な Atom N270 PC です。
特徴的なのは独自のタッチパッド。
液晶画面がついているだけでなくセンサーも兼ねた代物で、画素一つ一つが光を
読み取っているようです。
この新しいデバイス&センサーは使ってみたいところです。

もう1つ興味あるのは、タッチパッド部の液晶も結構解像度が高いこと。
854×480 ドットというと初代 EeePC 701 とほぼ同じ広さな訳ですから
この中でデスクトップやらブラウザやら普通に動かしていたことになります。
タッチパネル部のサブ画面をウィンドウズでどこまで自由に使えるかわかりませんが、
画面を広くするためのひとつの方法かもしれません。

思い返すと初めて買ったノート PC がSHARP メビウス ワイド PC-W100 でした。
メビウスワイドの画面は偶然にも同じ 1024×600 ドットです。

ネットブックが出てから 1024×600 ドットはごく普通のありふれたサイズに
なりましたが、13年前の当時は大変珍しいものだったのです。
横をのばしたというよりも 1024×768 から縦を削ってキーボードを圧迫せずに
本体サイズを小さくしようとしたもの。

当時のスペックをあらためて見ると Windows95 で RAM は 16MByte に HDD 1GByte。
CPU も Pentium 133MHz。さすがに 13年の年月を感じます。
これでも当時は DirectX3~5 を入れて Direct3D の RampDriver でプログラムを書いていました。

メビウスワイドから今まで、この間に使ってきたノート PC は
1024×600~1024×768 が圧倒的に多かったことに気がつきます。
記憶容量も演算速度もバス速度も描画速度も著しく向上しているはずなのに、
意外なほど長期間にわたって小型ノート PC の解像度が変化しませんでした。

もちろん最近は LOOX U の 1280×800 や VAIO type P の 1600×768 のように、
より詳細な液晶画面を搭載するものも出てきています。

PC-NJ70A を見て思ったのは、高解像度化に消極的なメインの液晶画面の代わりに
サブモニタを増やしてマルチ画面化するのも小型ノートパソコンの方向の 1つとして
ありなのかもしれないということ。
CPU が Multi core 化するように。

あとはサブ画面をどこまで自由に使えるか。
もしかしたら Windows SideShow でしょうか。
無理かもしれないけど理想はデスクトップの延長として使えることです。
Windows7 だと multi touch API が整備されているので、もしドライバがあるなら
すぐにでも使いたいところです。
現在 Multitouch 対応 PC として HP TouchSmart PC IQ800 を触っていますが
外周にセンサーを配置した光学式で 2点まで同時に識別することができます。
PC-NJ70A ではもっと自由に点を取れたらいいですね。

期待点まとめ
・タッチパッドとして
・画面の拡張、サブ画面として
・マルチタッチ対応センサー付きモニタとして
・別の入力手段として、位置的に親指シフトキーを配置できたりするかも

関連エントリ
Windows7 とマルチタッチ / HP TouchSmart PC IQ800

Direct3D10/11 DXGI1.1 とリモート GPU (アダプタ)

DXGI1.1 のアダプタ列挙を試します。

●EeePC901-X で実行した場合 (Windows7 RC x86)

// EeePC 901-X
[Mobile Intel(R) 945 Express Chipset Family (Microsoft Corporation - WDDM 1.0)]
   vmem:0MB sysmem:64MB shmem:192MB
   flag=0 

945 内蔵 GPU が列挙できています。
実際に Direct3D10 / 11 デバイスを作るとエラーなので、ドライバがまだ D3D10 Level9
に対応していないことがわかります。

●デスクトップ PC で実行した場合 (Windows7 RC x64)

// Desktop PC
[ATI Radeon HD 4800 Series ]
   vmem:504MB sysmem:0MB shmem:2811MB
   flag=0 
  (Direct3D11)
   *HARDWARE  = 10.1 (a100)
[ATI Radeon HD 4670]
   vmem:504MB sysmem:0MB shmem:2811MB
   flag=0 
  (Direct3D11)
   *HARDWARE  = 10.1 (a100)

2枚差したビデオカードが両方とも列挙されています。
それぞれ 10.1 でデバイスの作成ができます。

●リモートデスクトップ経由で実行した場合

[Mobile Intel(R) 945 Express Chipset Family (Microsoft Corporation - WDDM 1.0)]
   vmem:0MB sysmem:64MB shmem:192MB
   flag=1 REMOTE
[ATI Radeon HD 4800 Series ]
   vmem:504MB sysmem:0MB shmem:2811MB
   flag=0 
  (Direct3D11)
   *HARDWARE  = 10.1 (a100)
[ATI Radeon HD 4670]
   vmem:504MB sysmem:0MB shmem:2811MB
   flag=0 
  (Direct3D11)
   *HARDWARE  = 10.1 (a100)

EeePC 901 からデスクトップ PC に接続しています。

予想通り両方のマシン、すべてのアダプタが見えていることがわかります。
EeePC の 945 では DXGI_ADAPTER_DESC1 の Flags に DXGI_ADAPTER_FLAG_REMOTE bit が立っており、このデバイスを区別することが可能です。
プログラム自体はホスト側のデスクトップ PC で走っているので、プログラムから見れば
クライアントである EeePC の方がリモートです。

もし Remote のアダプタが Command Remoting に対応していれば
ネットワークを経由していてもクライアント側の PC でリアルタイムに
レンダリングすることが可能となります。

ちなみに DXGI1.0 で列挙するとホスト側の最初のアダプタ “RADEON HD4850” しか
見えませんでした。

● Feature

各アダプタの詳細を調べると下記の通り。
いわば Direct3D11 における caps です。

[DEFAULT]
  (Direct3D11)
   *HARDWARE  = 10.1 (a100)
     feature threading  DriverConcurrentCreates=0
     feature threading  DriverCommandLists=0
     feature d3d10_x ComputeShaders_Plus_RawAndStructuredBuffers_Via_Shader_4_x=0
     feature doubles  DoublePrecisionFloatShaderOps=0
   *REFERENCE = 11.0 (b000)
     feature threading  DriverConcurrentCreates=0
     feature threading  DriverCommandLists=0
     feature d3d10_x ComputeShaders_Plus_RawAndStructuredBuffers_Via_Shader_4_x=1
     feature doubles  DoublePrecisionFloatShaderOps=1
   *WARP      = 10.1 (a100)
     feature threading  DriverConcurrentCreates=0
     feature threading  DriverCommandLists=0
     feature d3d10_x ComputeShaders_Plus_RawAndStructuredBuffers_Via_Shader_4_x=0
     feature doubles  DoublePrecisionFloatShaderOps=0

[ATI Radeon HD 4800 Series ] (V:4098 D:37954 S:84021250 R:0)
   luid:000097b2 00000000
   vmem:504MB sysmem:0MB shmem:2811MB
   flag=0 
  (Direct3D11)
   *HARDWARE  = 10.1 (a100)
     feature threading  DriverConcurrentCreates=0
     feature threading  DriverCommandLists=0
     feature d3d10_x ComputeShaders_Plus_RawAndStructuredBuffers_Via_Shader_4_x=0
     feature doubles  DoublePrecisionFloatShaderOps=0

[ATI Radeon HD 4670] (V:4098 D:38032 S:625086466 R:0)
   luid:0000b18e 00000000
   vmem:504MB sysmem:0MB shmem:2811MB
   flag=0 
  (Direct3D11)
   *HARDWARE  = 10.1 (a100)
     feature threading  DriverConcurrentCreates=0
     feature threading  DriverCommandLists=0
     feature d3d10_x ComputeShaders_Plus_RawAndStructuredBuffers_Via_Shader_4_x=0
     feature doubles  DoublePrecisionFloatShaderOps=0

以前 DirectX SDK Nov2008 時点で調べた結果はこちら
ほとんどのオプションは 0 のままですが、よく見ると REFERENCE で
DoublePrecisionFloatShaderOps が 1 になっていました。
REFERENCE を使えばシェーダーの double 演算命令もテストできるようになったということです。

同記事 でも触れていますが ComputeShader 4.0/4.1 については November の時点ですでに対応していますね。

関連エントリ
Direct3D DXGI とマルチ GPU (アダプタ)
Windows7 リモートデスクトップと Direct3D
Direct3D11/DirectX11 (4) FeatureLevel と旧 GPU の互換性、テクスチャ形式など

Direct3D DXGI とマルチ GPU (アダプタ)

PC を入れ替えて複数のビデオカードを同時に使えるようになりました。
対応マザーとそれなりの電源が必要です。
いろいろ試しています。

マルチ GPU といっても SLI や CrossFire のことではなく、
それぞれ独立した GPU として使います。

例えば GeForce と RADEON の 2枚差しで、それぞれにモニタをつないで
マルチモニタのように使用することができます。

・GeForce GTX260 → モニタ1
・RADEON HD4670 → モニタ2

GeForce は モニタ1 の描画を行い、RADEON は モニタ2 へ出力を行っています。
Windows から使っている分には 1枚のビデオカードに複数モニタをつないだ状態と
何も変わりません。
広いデスクトップとして使用可能で双方にまたがったウィンドウも配置できます。

ここまでは理解できますが Direct3D を使った場合はどうなるでしょうか。
D3D10CreateDevice / D3D11CreateDevice 時に PC につながっている任意のアダプタ
(GPU)を与えることが可能です。
どちらの GPU でも同じように使えるし、どちらのモニタにも描画することができました。
行き来もできるし中間に配置しても動いています。

このあたりをコントロールするのが DXGI で、非常に柔軟な使い方が可能となっています。

・IDXGIAdapter = GPU
・IDXGIOutput = モニタ

現在利用可能なアダプタとモニタは

IDXGIFactory::EnumAdapters()
IDXGIAdapter::EnumOutputs()

で列挙可能です。モニタに接続されていないアダプタも描画に使うことができます。
DXGI1.1 ではこれにさらに Command Remoting が加わります。
リモートデスクトップでアクセスしている場合に、ホストとクライアントどちらの
アダプタでレンダリングするか選択できるわけです。

●サンプルで確認

DirectX SDK 付属の Direct3D 11 のサンプルプログラムを起動するとウィンドウに
アダプタ名 (GPU名) が表示されています。
モニタ間 (アダプタ間) を行き来するとアダプタ名が切り替わるので違いがよくわかります。
プログラム的にはわざわざアダプタを切り替える必要は無いのですが、
DXUT では敢えてこのような仕様になっているようです。(理由は後述)

●プログラムで確認

実際にプログラムを書いて任意のアダプタで動かしてみました。

・RADEON HD4850 → モニタ1
・RADEON HD4670 → モニタ2

IDXGIFactory::EnumAdapters() でアダプタを列挙して、任意のアダプタを使って
デバイスを作成します。

// 列挙
IDXGIAdapter1*	iAdapter= NULL;
IDXGIFactory1*	iFactory= NULL;
CreateDXGIFactory1( __uuidof(IDXGIFactory1), reinterpret_cast( &iFactory ) );
for( unsigned int index= 0 ;; index++ ){
	HRESULT	ret= iFactory->EnumAdapters1( index, &iAdapter );
	if( ret == DXGI_ERROR_NOT_FOUND ){
		break;
	}
	// ~ アダプタの選択
	// iAdapter->Release();
}
iFactory->Release();


// 作成
HRESULT	hr= D3D11CreateDeviceAndSwapChain(
		iAdapter,
		iAdapter ? D3D_DRIVER_TYPE_UNKNOWN : DriverType,
		NULL,	// software
		D3D11_CREATE_DEVICE_DEBUG,// flags
		NULL,	// featurelevels
		0,	// featurelevels
		D3D11_SDK_VERSION,
		&SwapChainDesc,
		&iSwapChain,
		&iDevice,
		&FeatureLevel,
		&iContext
	);

アダプタは IDXGIFactory::EnumAdapters() で列挙したハードウエアアダプタ、
もしくは IDXGIFactory::CreateSoftwareAdapter() で作成したソフトウエアアダプタです。
すでに TYPE を特定できるので、DriverType には D3D_DRIVER_TYPE_UNKNOWN を
与えなければなりません。(最初ここではまりました)

結果

RADEON HD4850 → モニタ1  : 257fps
RADEON HD4850 → モニタ2  : 205fps

RADEON HD4670 → モニタ1  : 140fps
RADEON HD4670 → モニタ2  : 164fps

HD4850 ではモニタ1 の方が高速、HD4670 ではモニタ2 の方が高速です。
アダプタから直接出力した方が速く、予想通りの結果といえます。
同時にたとえ直結されていなくても、モニタ2 の描画も HD4850 が行った方が速いこともわかります。

DirectX SDK 付属サンプルの DXUT がウィンドウの位置を監視して、モニタに応じて
デバイスを作り直しているのは少しでも高速に動作するためだと考えられます。

昔はビデオカードを何度も何度も差し直して開発していました。
GeForce と RADEON の挙動を同時に確認できるなんて、大変便利になったものです。
上のテストの最中、途中で GeForce GTX260(192sp) から HD4850 に差し直したのは
本日非常に暑かったからです。

関連エントリ
Windows7 リモートデスクトップと Direct3D

Windows SDK for Windows7 RC と Multitouch / Direct3D 11

Windows7 RC と同時に WindowsSDK の RC 版も出ています。

Microsoft Windows SDK for Windows 7 and .NET Framework 3.5 SP1: RC
Microsoft Windows SDK for Windows 7 and .NET Framework 3.5 SP1: RC (ISO)

BETA 時点からタッチ周りの API など変更されているところがあるので要注意です。
たとえば WM_TOUCHDOWN, WM_TOUCHUP, WM_TOUCHMOVE 等は無くなり
WM_TOUCH に統一されているようです。

マニュアルも更新されています。
以前 User Interface の下にあった Touch 関連が Windows Touch
という新項目にまとめられています。このあたり力が入ってます。

MSDN Windows Touch

Direct3D11 関連も DirectX SDK March 2009 より新しいものが含まれていました。
ただし d3d11.lib などの lib 名に _beta がついていないので include の順番に
注意した方が良さそうです。
Vista で使う場合は DXSDK の方を。

関連エントリ
Windows7 Multitouch API その(2) WM_GESTURE 系
Windows7 Multitouch API
DirectX SDK March 2009