構成システムのサンプル

構成システムのサンプルでは、ハードウェア デバイス モデルのデータベースを使用して、構成システムの例を示します。このサンプルはシステムにあるハードウェアを検出し、次に、これらの既存のデバイスに定義されているカスタム動作を見つけるデータベースを検索します。

Ee416337.ConfigSystem(ja-jp,VS.85).jpg

Path

ソース SDK ルート\Samples\C++\Direct3D\ConfigSystem
実行可能ファイル SDK ルート\Samples\C++\Direct3D\Bin\<x86 または x64>\ConfigSystem.exe

サンプルの概要

構成システムのサンプルでは、データベース主導型アプリケーションの構成システムの例を説明します。現在、市販されている Halo PC、Microsoft Flight Simulator、Microsoft Combat Flight Simulator、および Rise of Nations などのゲームは、この汎用性が高く、パワフルなシステムを既に活用しています。3D グラフィック カードは、画像をより鮮明に表示するための機能セットを備えています。実際には、すべてのカードがまったく同じ機能をサポートしている訳ではありません。そのため、アプリケーションは、各グラフィック カードがどの機能をサポートしているかを確認する必要があります。Direct3D では、デバイス機能は機能の構造体に通知されます。そうでない場合、CAP ビットは IDirect3DDevice9::GetDeviceCaps を呼び出すことで取得されます。CAP ビット構造体は、デバイスがサポートしている機能とサポートしてない機能の詳細を示します。通常、CAP ビットによって、アプリケーションが利用できるレンダリング機能をすばやく簡単に確認することができます。

ただし、CAP ビットは常に正確ではなく、完全でもありません。デバイスから CAP ビットに間違った情報 (実際にはサポートしていない、またはレポートが完全ではない) が伝えられることがあります。さらに、機能を有効にすると、サーバーのパフォーマンスが大幅に低下することがあります。この場合、大半の開発者は特定の機能を利用することよりも、安定したパフォーマンスを優先します。これらの CAP ビットに関する問題を解決するには、アプリケーション開発者が開発時にすべてのサポートされているハードウェア モデルをテストし、アプリケーションで問題が発生したハードウェアのリストをデータベースに記録しておく必要があります (各デバイス固有の問題も含む)。これによって、アプリケーションは実行時にホスト システムのハードウェアを検出できるようになります。ハードウェア モデルが見つかったら、データベースはアプリケーションがハードウェアを利用するために行う必要がある特別な処理の詳細を伝えます。

サンプルが動作するしくみ

このサンプルは、次の 3 つのコード コンポーネントを持つ、データベース主導型構成システムを示しています。

  • 構成システムのクライアントは、システムを利用するだけでなく、レンダリングやアニメーション ルーチンなどの必要なサンプル コードの処理も行います。これは Main.cpp にあります。

  • 構成データベースは、コンポーネント オブジェクト モデル (COM) オブジェクトとして構成データベースを実装します。データベース オブジェクトは、構成ファイルの解析を処理します。これは、ConfigDatabase.cpp にあります。

  • 構成マネージャーは、データベースへのアクセスをカプセル化し、プロパティへの効率的なアクセスを提供します。これは、ConfigManager.cpp にあります。

このサンプルは、簡単なゲームの例を示しています。サンプルでは、ユーザーは複数のボールが地面に置かれている閉じられた空間にいます。ユーザーが次々とボールを打つと、これらが跳ね返ってきます。画面の下部には、プロパティのリストが表示されます。これらのプロパティは、サンプルが検出するディスプレイやオーディオ デバイスをベースにした構成データベース ファイルから読み込まれ、解析されます。これらのプロパティは、レンダリング方法やサウンドの処理方法などのサンプルの実行方法に影響を与えます。

グラフィック カード機能

現在市販されているグラフィック ハードウェアの現在のドライバーによって公開されている一連の機能は、DirectX SDK の個別のファイルとして利用できます。

詳細については、DirectX のサンプル ブラウザーにある「グラフィック カード機能」のサンプルを参照してください。

データベース

サンプルでは、構成データベース ファイルはテキスト ファイルです。各行は、解析、プロパティ定義、またはダブル スラッシュで始まるコメントに関係するステートメントまたはキーワードのいずれかです。データベースを解析する場合、テキストの大文字小文字は区別されません。ファイルには次の 3 つのセクションがあります。

セクション 1: ハードウェア要件

最初のセクションでは、サンプルのハードウェア要件がリスト表示されています。最初に要件ステートメント、その後に 1 つまたは複数のプロパティまたはプロパティ値の割り当てが記述されています。このセクションは、以下のように break ステートメントで終了します。

Requirements    OS=Win98    CpuSpeed=733    Memory=128    VideoMemory=64    DirectX=4.9.0.902    DiskSpace=100    break

ここでは、要件の値はそれぞれ次のようになります。

要件のプロパティ 説明
OS オペレーティング システムのバージョン。使用できる値は次のとおりです (昇順): Win95、Win98、WinME、Win2k、WinXP、および Win2003。
CpuSpeed プロセッサの速度 (MHz)。
Memory システムのメモリーの量 (MB)。
VideoMemory ビデオ メモリーの量 (MB)。
DirectX 次の形式で表したシステム上の DirectX バージョン: #.#.#.# (# は 10 進数字)
DiskSpace 利用できるディスク領域の量 (MB)。この要件は、説明用のものであり、サンプルによってチェックされることはありません。

セクション 2: 名前付きプロパティ セット

次のセクションには、名前付きプロパティ セットがリスト表示されています。プロパティ セットのグループは、統一された名前でカスタム プロパティに関連付けられています。各プロパティ セットは、複数のカスタム プロパティのセットになっており、その後に break ステートメントが続きます。最初に PropertySet ステートメント、その後に 1 つまたは複数のプロパティまたはプロパティ値の割り当てが記述されています。このセクションは、以下のように break ステートメントで終了します。

PropertySet = "MyPropSet"    CustomPropertyName1          // Name    CustomPropertyName2 = Value  // Name/Value    break

各プロパティ セットは、引用符で囲まれたプロパティ セットの名前で始まります。この例には、2 つのカスタム プロパティがあります。カスタム プロパティは、名前と値のペア、または名前のみです。これはアプリケーションによって定義され、デバイスに割り当てられます。また、これはこのカスタム プロパティが割り当てられたデバイスで処理するときに、実行する必要がある特別な動作を行うことをアプリケーションに伝えるフラグとして提供されます。

注意

前述の例で示したように、ダブル スラッシュ (//) を使用してコメントを含めることができます。

プロパティ セットは、次のように、他のプロパティ セットを参照することもできます。

PropertySet = "SmallPropSet"    CustomPropertyName1          // Name    CustomPropertyName2 = Value  // Name/Value    breakPropertySet = "BigPropSet"    PropertySet = "SmallPropSet" // BigPropSet includes SmallPropSet's properties    CustomPropertyName3          // Name    CustomPropertyName4 = Value  // Name/Value    break

PropertySet ステートメントは、カスタム プロパティ名の代わりに使用されます。またその値は、引用符で囲んだプロパティ セットの名前になります。BigPropSet は次のように定義されます。

PropertySet = "BigPropSet"    CustomPropertyName1          // Name    CustomPropertyName2 = Value  // Name/Value    CustomPropertyName3          // Name    CustomPropertyName4 = Value  // Name/Value    break

セクション 3: データベース内のハードウェア デバイス

最後のセクションでは、データベースに含まれているハードウェア デバイスのエントリをリスト表示しています。このサンプルでは、データベースにはオーディオ デバイスとディスプレイ デバイスが含まれています。デバイスのエントリは、ベンダー ID およびデバイス ID で構成されています。各エントリは、次の 4 つの形式のいずれかである必要があります。

形式 1: ベンダー定義

ベンダー定義は次のようになります。

AudioVendor = 0x1102 "Audio card vendor name"       // For audio vendorDisplayVendor = 0x10b4  "Display card vendor name"  // For display vendor

16 進数のベンダー ID の後に、ベンダー名が続きます。

形式 2: デバイス定義

デバイス定義は次のようになります。

0x1015 = "Device Name"

デバイスの 16 進数の数字の後に、デバイス名の文字列が続きます。現在のベンダーがデータベースに見つからない場合は、その他のすべてのデバイスを表す「unknown」をデバイス文字列に使用できます。

形式 3: カスタム プロパティ定義

名前の付いたプロパティのカスタム プロパティまたはリファレンスは、次のように定義されている必要があります。

PropertyName1             // NamePropertyName2 = Value     // Name/ValuePropertySet = "MyPropSet" // Apply all properties included in MyPropSet

値のペアを持たない最初の例は、スペキュラ ライティングなどの特定の機能を有効または無効にするのに使用します。値のペアを持つ 2 番目のプロパティは、パラメーターが複数のデバイスに異なる値を設定する必要がある場合に使用します。3 番目の形式は、以前に名前の付けられたプロパティ セット MyPropSet へのリファレンスです。以前に名前の付けられたプロパティ セットのすべてのプロパティが一覧表示されます。

形式 4: 条件付きプロパティ定義

条件付きプロパティは、if ブロックに埋め込まれているカスタム プロパティ (または名前の付いたプロパティ セット リファレンス) であり、指定された条件が TRUE の場合にのみ適用されます。また、if ブロックをネストすることもできます。次に、1 つの例を示します。

if identifier operator value    PropertyName3 = Value    PropertySet = "MyPropSet"endif

識別子は次のいずれかになります。

識別子 説明
ram 10 進数または 16 進数の数字 (0x で始まる) システム メモリーの量
videoram 10 進数または 16 進数の数字 (0x で始まる) ビデオ メモリーの量
SubSysID 10 進数または 16 進数の数字 (0x で始まる) ハードウェア デバイスのサブシステム ID
Revision 10 進数または 16 進数の数字 (0x で始まる) ハードウェア デバイスのリビジョン番号
driver #.#.#.# として定義されるフルバージョン形式。ここで、# は 10 進数または 16 進数の数字を表します。 デバイスのドライバー バージョン
guid ########-####-####-####-############ 形式のグローバル一意識別子 (GUID)。ここで、各 # は 16 進数の数字を表します。 デバイスの GUID
OS 次の OS のいずれか: Win95、Win98、Win98SE、WinME、Win2k、WinXP コンピューターのオペレーティング システム
D3DCAPS9 の任意の DWORD メンバー 10 進数または 16 進数の数字 (0x で始まる) 値は Caps、Caps2 など

また、ここでは演算子は次のいずれかになります。

= または == 2 つのオペランドの値が等しい場合に TRUE
<> または != 2 つのオペランドの値が等しくない場合に TRUE
>= 左のオペランドの値が右のオペランドの値よりも大きいか、等しい場合に TRUE
<= 左のオペランドの値が右のオペランドの値よりも小さいか、等しい場合に TRUE
> 左のオペランドの値が右のオペランドの値よりも大きい場合に TURE
< 左のオペランドの値が右のオペランドの値よりも小さい場合に TURE
& 2 つのオペランドでビット単位の AND 操作を実行し、結果を返す

識別子または値は引用符で囲まないでください。

デバイス データベースの解析

このサンプルでは、データベースからのデバイスのオーディオとディスプレイのプロパティを個別に解析します。続いて、ディスプレイ デバイスのプロパティおよびオーディオ デバイスのプロパティの解析について説明します。

特定のハードウェア デバイスに対して一致させるために、パーサーはまず一致するベンダー ID が指定された DisplayVendor ステートメントを検索します。一致するベンダー定義が見つかったら、パーサーはこの一致する定義の後ろのベンダー定義をスキップします。これは、ベンダーが複数のベンダー ID を持ち、複数のベンダー定義行で定義されていることがあるために実行されるものです。次に、パーサーはベンダー定義の後、デバイス定義の前にあるすべてのカスタム プロパティを探します。ここで見つかったプロパティは、そのベンダーからのすべてのデバイスに適用されます。そのため、特定のベンダーからすべてのデバイスに適用されるプロパティは、データベース構築時にベンダー定義のすぐ後に置く必要があります。

ベンダー全体のプロパティの解析後、パーサーはデバイス定義行の検索を引き続き行います。次に、パーサーはすべてのプロパティを検索します。パーサーは、break ステートメントを検出すると停止します。他のデバイス定義を検出しても停止しません。これらによって、複数のデバイスに適用されるプロパティを簡単に追加できるようになっています。

次は、特定のベンダーからのデバイスにプロパティを定義するデータベースの例です。

DisplayVendor = 0x1101 "Display Vendor Name"DisplayVendor = 0x1102 "Display Vendor Name"    DisableSpecular        // Disable specular lighting0x1001 = "Card Model 1"    ForceShader=14         // Restrict shader to 1.4 or lower0x1002 = "Card Model 2"    MaximumResolution=1024 // Max resolution 1024x768    break0x1003 = "Card Model 3"Unknown = "Unknown"    UseAnisotropicFilter   // Use anisotropic filtering    break

上記の例では、ディスプレイ ベンダーからの 3 つのデバイスが定義されています。このベンダーは 0x1101 および 0x1102 という 2 つの既知のベンダー ID を持っています。このベンダーのデバイス定義の前には、DisableSpecular があります。そのため、このベンダーからのすべてのデバイスにこれが適用されます。

すべてのデバイスに対するデフォルトを指定する

データベースは、それらがデータベースに含まれているかどうかに関係なく、すべてのベンダーからのすべてのデバイスに適用されるプロパティのデフォルト セットを指定できます。これを実行するには、データベースに 2 つの ApplyToAll プロパティ セットを含める必要があります。1 つはハードウェア ベンダー定義の前に、もう 1 つはその後に表示されます。ApplyToAll プロパティ セットの構文は次のようになります。

ApplyToAll    Property1    Property2    break

ApplyToAll プロパティ セットは、ほかのプロパティ セットと同様に、break ステートメントで終了します。最初の ApplyToAll ブロックは、ハードウェア ベンダー セクションの前に解析されます。そのため、最初のブロックはベンダー固有またはデバイス固有のプロパティで上書きされるデフォルト プロパティを定義します。2 つ目の ApplyToAll はハードウェア ベンダー セクションの解析の後に解析されるので、2 つ目のブロックは上書きされないデフォルト プロパティを定義します。

サンプルで実装されているカスタム プロパティ

カスタム プロパティは、アプリケーションによって設計され、サポートされています。このサンプルでは、一般的に使用される共通カスタムプロパティ、およびアプリケーションの動作に影響を与えるプロパティの一覧を示しています。また、このサンプルでは実装されていませんが、以前にリリースされたアプリケーションで利用できる、その他の多くのプロパティについても一覧表示しています。これらによって、問題が発生するハードウェアとドライバーの種類がわかるようになっています。

このサンプルで実装されているカスタム プロパティは以下のとおりです。

プロパティ 説明
MaximumResolution 640、800、1024 など 解像度の幅を指定して、サンプルが使用する最高解像度を制限します。たとえば、解像度を 800 x 600 にする場合、MaximumResolution=800 を使用します。
UseFixedFunction なし 固定機能パイプラインを使用します。このプロパティが存在しない場合、レンダラーはプログラム可能なシェーダーを使用します。このサンプルでは、固定機能は頂点単位のライティングを使用しますが、ピクセル シェーダー 2.0 以上はピクセル単位のライティングを使用します。表示は大幅に異なります。
ForceShader 0、11、12、13、14、20、A2、B2、30 グラフィック デバイスが新しいバージョンをサポートしている場合でも、特定のピクセル シェーダー バージョンを使用します。たとえば、レンダラーに ps_1_4 を強制的に使用させるには、ForceShader=14 を使用します。このサンプルでは、ピクセル シェーダー 2.0 以降はピクセル単位のライティングを使用します。表示は大幅に異なります。
UseAnisotropicFilter なし テクスチャーには異方性フィルタリングを使用します。
DisableSpecular なし 既知のプロトタイプ カードの存在をユーザーに警告します。これが存在する場合、ユーザーに通知するメッセージ ボックスが表示されます。
UnsupportedCard なし このプロパティは、サンプルが以下の仕様のカードで実行されないようにします。これが存在する場合、ユーザーに通知するメッセージ ボックスが表示され、サンプルは終了します。
OldDriver なし このプロパティは、アプリケーション ユーザーに、ディスプレイ ドライバーのバージョンが開発者がテストしたものよりも古いことを伝えます。メッセージ ボックスが表示され、ユーザーに通知されます。
InvalidDriver なし このプロパティは、アプリケーションで重大な問題が発生することがわかっているため、このディスプレイ ドライバーでのサンプルの実行を無効にします。これが存在する場合、ユーザーに通知するメッセージ ボックスが表示され、サンプルは終了します。
OldSoundDriver なし このプロパティは、アプリケーション ユーザーに、サウンド ドライバーのバージョンが開発者がテストしたものよりも古いことを伝えます。メッセージ ボックスが表示され、ユーザーに通知されます。
InvalidSoundDriver なし このプロパティは、アプリケーションで重大な問題が発生することがわかっているため、このサウンド ドライバーでのサンプルの実行を無効にします。これが存在する場合、ユーザーに通知するメッセージ ボックスが表示され、サンプルは終了します。
UMA なし このプロパティは、システムにあるディスプレイ カードがユニファイド メモリー アーキテクチャ (UMA) カードであることをアプリケーションに警告します。UMA ディスプレイ カードは、システム メモリーの一部をビデオ メモリーとして使用します。このプロパティが存在する場合、システムで利用できるビデオ メモリーの量は、システムのメモリー サイズから計算されます。

次のプロパティは、データベースに含まれており、そこから解析が行われます。ただし、このサンプルでは実装されていません。

プロパティ 説明
LinearTextureAddressing なし これが定義されている場合、正方形以外のテクスチャーは、正規化されていないテクスチャー座標を使用します。
DoNotUseMinMaxBlendOp なし これが定義されている場合、ディスプレイ デバイスは最小または最大ブレンディング モードを適切に処理しません。そのため、これらは削除されます。
DisableDriverManagement なし このプロパティを使用すると、デバイスは D3DCREATE_DISABLE_DRIVER_MANAGEMENT で作成する必要があります。そのため、リソース管理はドライバーではなく、Direct3D によって行われます。
DisableAlphaRenderTargets なし これが定義されている場合、アプリケーションはターゲットをアルファ チャンネルでレンダリングできません。
DisableRenderTargets なし すべてのレンダー ターゲットは無効になります。
EnableStopStart なし サウンド カードは、高周波数での IDirectSoundCaptureBuffer8::Start または IDirectSoundCaptureBuffer8::Stop メソッドの呼び出しをサポートしています。

データベースの読み込みとアクセス

アプリケーションがデータベースの内容にアクセスする場合、静的メソッドの IConfigDatabase::Create を呼び出します。これは、IConfigDatabase オブジェクトを初期化し、返します。次に、アプリケーションは IConfigDatabase::Load メソッドを呼び出し、次のパラメーターで渡します。

  • 構成データベースのファイル パス

  • システムにあるサウンド デバイスに関する情報を持つ SOUND_DEVICE 構造体

  • システムにあるディスプレイ デバイスに関する同様の情報を持つ D3DADAPTER_IDENTIFIER9 構造体

  • Direct3D によって返されるディスプレイ CAP ビット

  • システムおよびビデオ メモリーの量

  • プロセッサの速度

IConfigDatabase::Load は構成データベース ファイルを解析し、検出されたディスプレイ デバイスおよびサウンド デバイスをベースにして、要件と関連するカスタム プロパティを保存します。内部的には、IConfigDatabase はこの情報をプロパティ名と値のペアとして保存します。操作が完了すると、アプリケーションは利用できる要件またはカスタム プロパティを問い合わせ、文字列のペアを取得できるようになります。

プロパティはアプリケーションのレンダリング方法を制御するため、アプリケーションはレンダリング ループにあるプロパティの値の確認が必要になる可能性があります。文字列の比較は 2 つの数字の比較よりも効率的でないため、レンダリング ループが IConfigDatabase から直接プロパティを問い合わせることはお勧めしません。CConfigManager ヘルパー クラスは、IConfigDatabase の上部にあるコード レイヤーとして動作します。このアプリケーションによってカスタマイズされたクラスは、システムにあるハードウェアの検出を行います。また、これはプロパティの IConfigDatabase を問い合わせ、メンバー変数にプロパティ値を格納します。レンダリング中に、アプリケーションはメンバー変数の値を確認して、IConfigDatabase から文字列ペアの問い合わせをする代わりに、適切な動作が行われているかどうかを判断します。

セーフモードでの起動

また、このサンプルではセーフモードの簡単な実装について説明しています。セーフ モードとは、アプリケーションを最小限必要な設定だけで起動するモードのことです。たとえば、解像度が最小限だったり、すべてのビデオ カードがサポートしていない機能は使えないなどの制限があります。セーフ モードでは、サンプルはアプリケーションが予期せず終了した場合に、アプリケーションの状態をファイルに保存します。ステータス データはアプリケーションの有効期間を過ぎても保持されます。これを実行するには、起動時に空白のファイル (Launch.sta と呼ばれる) を作成し、これを終了前に削除します。サンプルはこのファイルを次のパスに書き込みます。

Drive:\Document and Settings\username\Local Settings\Application Data\ConfigSystem

以前のパスで使用されていたユーザー名は、現在のユーザーのログイン名です。システムに対してローカルなアプリケーションによって使用される次のフォルダーは、現在のユーザーの情報を格納します。

Drive\Document and Settings\username\Local Settings\Application Data

このパスを取得するには、CSIDL_LOCAL_APPDATA を指定して SHGetFolderPath を呼び出します。サンプルは、アプリケーションの実行可能ディレクトリの代わりにこのパス使用します。これはユーザー固有データをユーザーに固有な場所に書き込むに最適な方法だからです。すべてのユーザーが常に実行可能ディレクトリにアクセスできるわけではありません。そのため、ユーザー固有データの実行可能ディレクトリへの書き込みは避けてください。

サンプルが起動され、それが Launch.sta に書き込みを行う前に、Launch.sta が既に存在しているかどうかを確認します。存在しない場合は、前の起動時にアプリケーションに回復不能なエラーが発生し、正常に終了しなかったことを意味します。この場合、セーフモードに切り替えることが適切であり、それによってアプリケーションで問題が再び発生する可能性を減らすことができます。

まとめ

データベースを使用する構成システムは、固有のハードウェア デバイスに対する動作をアプリケーションに正確に定義させることができます。注目に値することとしては、データベースのプロパティがクライアント アプリケーションによって定義されること、必要に応じてプロパティを追加してデータベースを拡張できること、ハードウェア ベンダーやデバイスを新しいハードウェアとして追加できることが挙げられます。アプリケーションのパッチや更新を取得できるように、最新の構成データベース ファイルにはパッチが含まれており、ユーザーは常に最新の状態でハードウェアを使用できるようになっています。