14

そこで、GamasutraのJohn Carmackとのこのインタビューを読みました。彼は、彼が「メモリマップトファイルに存在するライブC++オブジェクト」と呼んでいるものについて語っています。ここにいくつかの引用があります:

JC:うん。そして、私は実際にそれから複数の利点を得る...最後のiOS Rageプロジェクトでは、いくつかの巧妙なものを使用して、フラッシュファイルシステムに裏打ちされたメモリマップファイルに存在するライブC++オブジェクトを作成するいくつかの新しいテクノロジーが付属しています。これが、PCでの今後のすべての作業を構成する方法です。

..。

ここでの私の行進命令は、PCプラットフォームで2秒のゲームロードが必要なので、それをはるかに高速に繰り返すことができます。そして現在、ソリッドステートドライブを使用している場合でも、読み込み時に行うすべてのことによって支配されているため、「すべてが間引きされ、相対アドレスで使用される」と言えるようになるには、この異なる分野が必要です。つまり、「ファイルをマッピングすると、すべてのリソースがすぐそこにあり、15ミリ秒で完了します」と言うだけです。

(完全なインタビューはここにあります)

カーマックが何について話しているのか、そしてあなたがこのようなものをどのように設定するのか、誰かが知っていますか?Webで少し検索しましたが、何も見つからないようです。

4

5 に答える 5

7

アイデアは、メモリマッピングを介してそのファイルにアクセスすることにより、プログラム状態のすべてまたは一部を常にファイルにシリアル化することです。ポインタはプロセスが継続している間のみ有効であるため、これには通常のポインタがないことが必要になります。代わりに、プログラムを再起動してファイルを再マップしたときに作業を続行できるように、マッピング開始からのオフセットを保存する必要があります。このスキームの利点は、個別のシリアル化がないことです。つまり、追加のコードがなく、すべての状態を一度に保存する必要がありません。代わりに、プログラムの状態(すべてまたはほとんど)が常にファイルに裏打ちされています。

于 2011-08-23T10:05:45.803 に答える
2

直接またはカスタムアロケータを介して、新しい配置を使用します。

カスタム割り当てスキーム(組み込みシステムやゲームコンソールで実行されるゲームに必要なものなど)でうまく機能するように特別に調整された(サブセット)STLの実装については、EASTLを参照してください。

EASTLの無料サブセットは次のとおりです。

于 2011-08-23T10:07:11.970 に答える
2

私たちは何年もの間、ある種のスマートポインタである「相対ポインタ」と呼ばれるものを使用しています。これは本質的に非標準ですが、ほとんどのプラットフォームでうまく機能します。次のように構成されています。

template<class T>
class rptr
{
    size_t offset;
public:
    T* operator->() { return reinterpret_cast<T*>(reinterpret_cast<char*>(this)+offset); }
};

これには、すべてのオブジェクトが同じ共有メモリ(ファイルマップの場合もあります)に保存されている必要があります。また、通常、互換性のある独自のタイプのみをそこに格納する必要があり、そのメモリを管理するための独自のアロケータを作成する必要があります。

常に一貫性のあるデータを取得するために、COW mmapトリック(Linuxのユーザースペースで機能し、他のOSについてはわかりません)を介してスナップショットを使用します。

64ビットへの大きな移行に伴い、相対ポインターが実行時のオーバーヘッドを発生させるため、固定マッピングを使用することもあります。通常は48ビットのアドレス空間を使用するため、このようなファイルを常にマップするアプリケーション用に予約済みのメモリ領域を選択しました。

于 2011-08-23T10:37:13.317 に答える
1

これは、CDのロードされたレベルのファイルを驚くほど短時間で作成したファイルシステムを思い出させます(ロード時間が数十秒からほぼ瞬時に改善されました)。CD以外のメディアでも機能します。これは、ファイルIO関数をラップするためのクラスの3つのバージョンで構成され、すべて同じインターフェイスを備えています。

class IFile
{
public:
  IFile (class FileSystem &owner);
  virtual Seek (...);
  virtual Read (...);
  virtual GetFilePosition ();
};

および追加のクラス:

class FileSystem
{
public:
  BeginStreaming (filename);
  EndStreaming ();
  IFile *CreateFile ();
};

そして、次のような読み込みコードを記述します。

void LoadLevel (levelname)
{
  FileSystem fs;
  fs.BeginStreaming (levelname);
  IFile *file = fs.CreateFile (level_map_name);
  ReadLevelMap (fs, file);
  delete file;
  fs.EndStreaming ();
}

void ReadLevelMap (FileSystem &fs, IFile *file)
{
  read some data from fs
  get names of other files to load (like textures, object definitions, etc...)
  for each texture file
  {
    IFile *texture_file = fs.CreateFile (some other file name)
    CreateTexture (texture_file);
    delete texture_file;
  }
}

次に、デバッグモード、ストリームファイルビルドモード、リリースモードの3つの操作モードがあります。

各モードで、FileSystemオブジェクトは異なるIFileオブジェクトを作成します。

デバッグモードでは、IFileオブジェクトは標準のIO関数をラップしただけです。

ストリームファイルの構築では、IFileオブジェクトも標準IOをラップしましたが、読み取られたバイトごとにストリームファイル(所有者のFileSystemがストリームファイルを開いた)に書き込み、ファイルポインター位置クエリの戻り値を書き込む追加機能がありました。 (したがって、ファイルサイズを知る必要がある場合は、その情報がストリームファイルに書き込まれます)。これにより、さまざまなファイルが1つの大きなファイルに連結されますが、実際に読み取られたデータのみが連結されます。

リリースモードでは、ファイルを開かず、ファイル内をシークせず、ストリーミングファイルから読み取るだけのIFileが作成されます(所有者のFileSystemオブジェクトによって開かれます)。

これは、リリースモードでは、すべてのデータが、大量のシークと読み取りではなく、1つの連続した一連の読み取りで読み取られることを意味します(OSはそれを適切にバッファリングします)。これは、シーク時間が非常に遅いCDに最適です。言うまでもなく、これはCDベースのコンソールシステム用に開発されました。

副作用として、通常はスキップされる不要なメタデータがデータから削除されます。

これには欠点があります。レベルのすべてのデータが1つのファイルにあります。これらは非常に大きくなる可能性があり、データをファイル間で共有することはできません。たとえば、2つ以上のレベルで共通のテクスチャのセットがある場合、データは各ストリームファイルに複製されます。また、データがロードされるたびにロードプロセスが同じである必要があり、条件付きでスキップしたり、レベルに要素を追加したりすることはできません。

于 2011-08-23T10:52:26.437 に答える
0

Carmackが示すように、多くのゲーム(およびその他のアプリケーション)のロードコードは、多くの小さな読み取りと割り当てで構造化されています。

これを行う代わりにfread、たとえばレベルファイルをメモリに1つ(または同等に)実行し、後でポインタを修正するだけです。

于 2011-08-23T10:13:09.970 に答える