SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

特集記事

DirectX Graphicsの隠し設定を利用した開発テクニック

APIフックとレジストリ操作によるDirectXのデバッギング技法


  • このエントリーをはてなブックマークに追加

Windows OSにはコントロールパネルから変更できない多くの設定が存在し、それらの設定の多くはレジストリやiniファイルに格納されています。これと同じように、DirectX Runtimeにもいくつかのシステムレベルの設定が存在します。この記事ではこれらDirectX Graphicsの隠れた設定について、実装上のテクニックを交えながら紹介してゆきます。

  • このエントリーをはてなブックマークに追加

はじめに

 Windows OSにはコントロールパネルから変更できない多くの設定が存在し、それらの設定の多くはレジストリやiniファイルに格納されています。これと同じように、DirectX Runtimeにもいくつかのシステムレベルの設定が存在します。これらの設定は、エンドユーザにとってはあまり役立つものではありませんが、開発者が用いればデバッグや問題解決に利用できる有用なパラメータとなります。この記事ではこれらDirectX Graphicsの隠れた設定について、実装上のテクニックを交えながら紹介してゆきます。なお、以下で特に注釈がない場合、「DirectX」はDirectX 9.0cのDirectX Graphicsを指すと考えてください。

 今回紹介するテクニックは、DirectX開発者のみに送るものではありません。デバッグで困ったときや既存ライブラリに機能を追加したいときなど、さまざまな使い道があると信じています。実のところ、私が全く予想もつかなかった分野で、この記事が役立つことが一番楽しみです。

目次

サンプルプログラム
  1. アプリケーション起動時にRetail/Debug Runtimeを選択する
  2. DirectXランタイムが出力するデバッグメッセージのログを作成する
  3. DirectXランタイムのProcessor Specific Graphics Pipeline(PSGP)を無効化する
コラム
  1. DirectXランタイムライブラリ
  2. DirectXのコンポーネントとサブシステム
  3. DirectXのフィーチャとユースケース
  4. マルチスレッドCRT
  5. フックの解放
  6. APIにブレークポイントを設定する
  7. フックハンドラと再入・再帰
  8. DirectX DLLを遅延ロードする
  9. プロセス終了処理とDLL_PROCESS_DETACH
  10. 浮動小数点演算とFP-strict

対象読者

  • DirectXを利用したアプリケーションを開発されている方
  • Windows APIを頻繁に利用されている方
  • Windows OSの設計やWindows環境でのデバッグ技術に興味がある方
  • Windowsでマルチスレッドアプリケーションを開発されている方
  • クロスプラットフォームでの数値計算を行われている方

必要な環境

 DirectX 9.0cをインストールした以下のOSで動作確認を行いました。

  • Windows 98 Second Edition 日本語版
  • Windows XP Professional SP2 日本語版
  • Windows XP Professional x64 Edition 日本語版

 サンプルコードは、以下のコンパイラでコンパイルできることを確認しています。

  • Visual C++ .NET 2003 Professional Editon
  • Visual C++ 2005 Express Editon
  • Visual C++ 2005 Professional Editon

注意

 今回紹介する設定は、公式ヘルプに記載されていないものも含まれています。これらの設定が今後リリースされるDirectXによってサポートされる保障はありません。また、サンプルコードは、既存の全ての環境でのテストは行っておりません。互換性の検証は十分に注意してください。

セットアップ

DirectX SDK

 サンプルコードをコンパイルするには、DirectX SDKをインストールする必要があります。DirectX 9.0ダウンロードページからSDKをダウンロードしてください。サンプルコードの作成には、DirectX 9.0 SDK (December 2005)を使用しています。これ以降のSDKでコンパイルできるかどうかは不明ですが、大きな変更がない限りは対応できると思います。コンパイルに失敗する場合は、DirectX SDKのインクルードファイルディレクトリとライブラリディレクトリが、正しくVisual C++に設定されているか確かめてみてください。

Microsoft Platform SDK

 Visual C++ .NET 2003またはVisual C++ 2005 Express Editionを使用している場合は、最新のPlatform SDKをインストールする必要があります。

 Visual C++ 2005 Express Editionユーザの方については高萩 俊行さんの書かれた『Visual Studio 2005/Visual C++ 2005 Express EditionにPlatformSDKを統合する(改訂版) 』が参考になるでしょう。

 サンプルコードの作成には、Windows Server 2003 SP1 Platform SDKを使用しています。

その他に準備しておいた方が良いもの

RegMon

 「RegMon」(参考資料1)は、Sysinternals社が公開しているリアルタイムのレジストリアクセスモニタリングツールです。

 解説で使用するので、Sysinternalsのサイトからダウンロードしておいてください。RegMonの使い方については、@ITの『レジストリへのアクセスをモニタする方法』を参照してください。

FileMon

 「FileMon」(参考資料1)は、Sysinternals社が公開しているリアルタイムのファイルアクセスモニタリングツールです。

 解説で使用するので、Sysinternalsのサイトからダウンロードしておいてください。

DebugView

 「DebugView」は、Sysinternals社が公開しているリアルタイムのデバッグメッセージモニタリングツールです。

 Visual C++などのデバッガを持たない環境でも、デバッグメッセージをモニタリングすることができます。

シンボルファイル

 記事中に出てくるデバッガ上のコールスタックを再現するには、シンボルファイルが必要です。『シンボル サーバーの使用』に従って、シンボルサーバを導入しておくと良いでしょう。

予備知識

 DirectX Graphicsにあまり馴染みがない方のために、本稿に関係するポイントをいくつかピックアップしてみました。本稿では3D技術については取り扱わないので、ライブラリとしての側面から見たDirectXについて見ていくことにします。

コラム1 DirectXランタイムライブラリ
 まず、アプリケーションがDirectX Graphicsに依存するというのはどういうことかを、簡単に説明しておきましょう。
 普段開発者がDirectX Graphicsと呼んでいるものは、大きく2種類に分けることができます。1つはDirectX Graphicsを使用するために最低限必要な機能セットで、これはドライバとDLLから構成されています。現在Windows Updateでダウンロードできたり、OSに標準で導入されていたりするDirectXランタイムライブラリ(以下では単に「ランタイム」と呼びます)とは、これらのバイナリ群のことを指しています。本稿ではこのランタイムのことを、特に「コアランタイム」と呼ぶことにします。
 もうひとつのDirectX Graphicsの意味として、開発者が「DirectX Graphicsを使う」と言った場合、Microsoftが提供する各開発言語用の中間ライブラリのことを指すことがあります。これらの中間ライブラリはDirectX SDKに付属し、ソースコード・静的リンクライブラリ・DLLなどの形態で提供されています。C++言語用のD3DXや、.NET言語用のManaged DirectXなどがこれにあたります。開発者は、これらのライブラリを利用することで、既に提供されている機能を自分で実装することなく、製品を開発することができます。
図1 さまざまなDirectX
図1 さまざまなDirectX
 アプリケーションから見たDirectX Graphicsコアランタイムの機能は、WINAPI呼び出し規約に従うDLLのエクスポート関数と、それをファクトリメソッドとしてアクセス可能な、COM ABI(Application Binary Interface)に従うコンポーネント群によって提供されています。ある言語からDirectXを使用できるかどうかは、ほとんどの場合このCOM ABIに対応できるかどうかで決まります。ちなみに、図2では省略されていますが、初期化時にD3D_DEBUG_INFOフラグを追加することでCOM ABIが一部拡張され、デバッグ変数がvtblのアドレスの後に配置されるようになります。これにより条件付ブレークポイントやデバッガからの状態評価が容易になります。
図2 DirectXのABI
図2 DirectXのABI
 DirectXコアランタイムは、アップデート時にも以前のバージョンを引き続きサポートすることになっています。通例では、メジャーバージョンが上がる場合、新しいDLLが追加されます。例えばDirectX 8からDirectX 9へのアップデートでは、従来の「d3d8.dll」に加えて「d3d9.dll」が提供されるようになりました。表1はDirectXコアランタイムが更新された時期を示しています。この結果が示すとおり、近年DirectXコアランタイムの更新頻度は低下しています。
表1 DirectXコアランタイムリリース時期
リリース年月バージョン
2002年3月DirectX 9.0
2003年3月DirectX 9.0a
2003年7月DirectX 9.0b
2004年7月DirectX 9.0c
 一方、中間ライブラリは最近非常に速いペースで更新が行われています。ここしばらくMicrosoftは、2ヶ月ごとという驚異的なペースでDirectX SDKをリリースしています。これらのリリースで中間ライブラリは、ほぼ毎回更新されていますが、コアランタイムのバージョンに変化はありません。開発者は中間ライブラリを使用することで、最新の技術をいち早く利用したり、迅速に不具合の修正を受けたりすることができます。反面、ソースコードレベルの互換性が失われる更新も頻繁に行われるため、開発者のコードとのマージは深刻な問題です。また、DLLの形で提供される中間ライブラリはコアランタイムには付属しないため、エンドユーザは別途ランタイムライブラリのインストールを行う必要があります。
コラム2 DirectXのコンポーネントとサブシステム
 DirectX Graphicsのコンポーネント間の関係をもう少し詳しく見ていきましょう。図3にDirectX Graphicsに含まれるライブラリ間の依存関係を現しています。A→Bは要素AがBに依存するという意味です。
図3 ライブラリ間の依存関係
図3 ライブラリ間の依存関係
 一方、図4はC++言語で開発を行ったと仮定した場合の、典型的なDirectXアプリケーションについて、バイナリレベルでどのモジュールがどのモジュールと結合することになるかを示しています。
図4 モジュール間の結合関係
図4 モジュール間の結合関係
 開発者向けの環境では、設定によって「d3d9.dll」は「d3d9d.dll」を内部的にロードし、処理の一部を移譲します。いずれにせよ開発者は通常「d3d9d.dll」の存在を意識する必要はありません。一方「d3dx9_28.dll」とそのデバッグバージョンである「d3dx9_28d.dll」の間にはインターフェイスの互換性があって、開発者はどちらか一方と明示的にリンクすることで機能を切り替えます。
 なお「d3dx9_28.dll」の28は、DirectX 9.0 SDK(December 2005)のSDKバージョンを示します。SDKがアップデートされるたびに数字が増えてゆき、新しいバージョンのDLLによって上書きされてしまわないようになっています。
 図5は、コンポーネントの更新頻度という視点でDirectXを見たものです。コンポーネントごとの大まかな更新頻度を、主観的な印象を基にいくつかポイントしてみました。ただし、作成にあたってきちんと統計をとったわけではなく、あくまで主観的な印象に基づいたものであることをご了承ください。
図5 コンポーネント更新頻度(イメージ図)
図5 コンポーネント更新頻度(イメージ図)
 このように、図1から図5を通して見ることで、DirectX Graphicsと呼ばれるものの色々な内部構造が見えてきます。注目する点の違いでDirectXに正反対の印象を持つというのはよくある話です。
  • 一口にDirectXと言っても、その内部には性質の異なるサブシステムが存在すること。
  • 中間ライブラリを構成するコンポーネントの間にも依存関係が存在すること。
  • 多くの中間ライブラリはC++言語で実装され、ソースコードレベルの依存関係が存在すること(実際、インターフェイスの絶縁が不完全なため、一部のコンポーネントのみを更新することは困難です。バージョンの変更はしばしば中間ライブラリのサブシステム全体を置き換える必要があります)。
  • コアランタイムのコンポーネント更新周期は、おおよそ一年から数年にわたる期間に分布していること。
  • 中間ライブラリのコンポーネント更新周期は、2ヶ月程度から数年の間と非常に広い期間に分布していること。
コラム3 DirectXのフィーチャとユースケース
 フィーチャモデル(参考資料2)の言葉を借りれば、コアランタイムは3D描画デバイスのフィーチャ(アーキテクチャ要求)を定義していると言えます。アプリケーションはコアランタイムの定める各フィーチャを通してハードウェアを操作します。フィーチャ定義はMicrosoftが各ハードウェアベンダーと共同で行い、ほとんどの開発者はフィーチャ定義には関わりません。Richard Thomson氏が作成した『The Direct3D 9.0 Graphics Pipeline Poster』というポスターは、コアランタイムが定めるフィーチャを端的にあらわしています。
 一方、中間ライブラリには、具体的なユースケースを想定したコンポーネントと、コアランタイムがカバーしないフィーチャを提供するコンポーネントが混在しています。残念ながら現状の中間ライブラリは適切な分割が行われないまま肥大化が続いているため、何らかのタイミングで適切な分離が行われるべきと考えます。
 D3DXに含まれる、ファイルからテクスチャを作成するという機能は前者のユースケースに該当します。例えばD3DXCreateTextureFromFile API(参考資料3)は、よく知られたデータフォーマットの画像ファイルから、3D描画デバイスで使用可能なテクスチャを作成するというユースケースをカバーします。この機能は内部的に「空のテクスチャの作成」と「テクスチャへのデータ転送」というコアランタイムのフィーチャを用いて実装されています。
 一方、D3DXには興味深いフィーチャを提供するコンポーネントも存在します。ID3DXEffectインターフェイスによって提供される『エフェクトシステム』は、近年注目を浴びているDomain Specific Language(DSL)を用いて可変性を実現する野心的なコンポーネントです。このようなDSLが登場した理由のひとつとして、3D描画デバイスが非常に大量の描画設定を必要とするということが挙げられるでしょう。ゲーム開発の大規模化に伴い、多数の描画設定のセットを管理したり、頻繁な要求の変化(描画方式の変化)に対応することが重要となってきました。これに対しMicrosoftは、『エフェクトファイル』(参考資料4)と呼ばれる専用言語を定義しています。エフェクトファイルはコアランタイムの使用する設定の記述に加え、プログラマブルシェーダ記述言語として知られるHLSLやシェーダアセンブリを格納することができます。さらにエフェクトファイルは、構成要素に『アノテーション』と呼ばれるメタデータの付加を行うこともできます。C/C++言語側からは、リフレクションAPIを通してエフェクトファイルの内部要素にアクセスすることができ、実行時複合化を容易にしています。
 フィーチャとユースケースの視点でDirectXを解説した記事はまだ少ないので、機会があれば、いずれ詳しく取り上げてみたいと思います。

サンプルプログラムの概要

 「src.zip」のアーカイブには、次のようなファイルとフォルダが格納されています。

  • apihook.h
  • apihook.cpp
  • Sample1
  • Sample2
  • Sample3
  • Column4
  • Column8

 「apihook.h」と「apihook.cpp」はAPI Hookの実装部で、プロジェクトにそのまま組み込んで使えるようになっています。その他のフォルダの中には、サンプルプログラムが入っています。各フォルダにはVisual C++ .NET 2003およびVisual C++ 2005用のソリューションファイルを用意しました。

 サンプルプログラムが格納されたフォルダの「bin」以下には、こちらでビルド済みの実行ファイルが格納されています。32bit版と64bit版がありますので、ご使用の環境に合わせてお試し下さい。

 なお、同梱したビルド済みの実行ファイルの実行には、D3DXランタイムライブラリが必要です。はじめに、コラム8「DirectX DLLを遅延ロードする」で紹介する「CheckD3DX.exe」サンプルを実行して、D3DXランタイムライブラリがインストールされているか確認を行うとよいでしょう。

会員登録無料すると、続きをお読みいただけます

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

次のページ
サンプル1. アプリケーション起動時にRetail/Debug Runtimeを選択する

修正履歴

この記事は参考になりましたか?

  • このエントリーをはてなブックマークに追加
特集記事連載記事一覧

もっと読む

この記事の著者

NyaRuRu(ニャルル)

趣味としてDirectXを嗜んでいたところをMicrosoft MVPとして拾われる。Microsoft MVP for DirectX (Jan 2004-Dec 2006) ここしばらく.NETに浮気中.

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/235 2007/01/15 10:09

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング