ID3DX10ThreadPump メモ
非同期にテクスチャなどのロードが行えるID3DX10ThreadPumpというものを知ったのでそれのメモ。
データローダーとデータプロセッサーというクラスを独自に作成することでいろいろなフォーマットのロードに対応できます。
参考URL
http://msdn.microsoft.com/ja-jp/library/ee420231
http://www.gamedev.net/blog/272/entry-1790507-id3dx10threadpump-how-to/
とりあえずためしに作ってみたデータプロセッサ。 そのまま通りませんがとりあえず雰囲気だけでも。
/** * @file ASyncMemLoadProcessor.h * @brief ThreadPumpで使用するデータプロセッサ。ただのメモリ読み込み */ class ASyncMemLoadProcessor : public ID3DX10DataProcessor { public: /** * @brief バッファ情報。メモリ読込先バッファ以外に読み込みが完了しているかのフラグを持つ。 */ class BufInfo { friend ASyncMemLoadProcessor; public: BufInfo(); /** * @param bufSize バッファサイズ * @param buf 読み込みバッファ */ BufInfo( u32 bufSize, void* buf ); void init( u32 bufSize, void* buf ); bool valid() const { return (_buf != NULL); } bool isReady() const { return (valid() && _ready); } // アクセサ const void* getBuf() const { return _buf; } void* getBuf() { return _buf; } void*& getBufRef() { return _buf; } u32 getSize() const { return _bufSize; } private: void setReady() { _ready = true; } void* _buf; //! バッファ u32 _bufSize; //! バッファサイズ bool _ready; //! 準備完了フラグ }; // これらの関数を独自に定義する COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE CreateDeviceObject( void **ppDataObject ); COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE Destroy(); COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE Process( void *pData, SIZE_T cBytes ); /** * @brief 生成関数 * @param bufInfo バッファ情報 */ static ASyncMemLoadProcessor* Create( BufInfo& bufInfo ) { assert( bufInfo.valid() ); return new ASyncMemLoadProcessor( bufInfo ); } private: ASyncMemLoadProcessor( BufInfo& bufInfo ); ASyncMemLoadProcessor(const ASyncMemLoadProcessor& obj) {} ~ASyncMemLoadProcessor(){} BufInfo* _bufInfo; //! 処理対象のバッファ情報 void* _bufCur; //! 現在のバッファ処理位置 };
/** * @file ASyncMemLoadProcessor.cpp */ COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE ASyncMemLoadProcessor::CreateDeviceObject( void **ppDataObject ) { _bufInfo->setReady(); return S_OK; } COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE ASyncMemLoadProcessor::Destroy() { delete this; return S_OK; } COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE ASyncMemLoadProcessor::Process( void *pData, SIZE_T cBytes ) { memcpy( _bufCur, pData, cBytes ); _bufCur = (u8*)_bufCur + cBytes; return S_OK; }
クラスがごちゃごちゃしていますが、最低限必要なことは上の3つの関数を定義です。
CreateDeviceObject,Destroy,Process の3つの関数を独自に定義することで様々な処理が行えます。
実際に使ってみる。
/* * @file testThreadPump.cpp * @brief ID3DX10ThreadPumpのテスト */ class testThreadPump : public Task { public: testThreadPump( void ); virtual ~testThreadPump( void ); virtual void func( void ); ASyncMemLoadProcessor::BufInfo _bufInfo; ID3DX10ThreadPump* _pPump; void* _dat; }; testThreadPump::testThreadPump( void ) { // スレッドポンプの作成 // 引数を0にするとハードウェアに最適なスレッド数で作ってくれる DTrace( D3DX10CreateThreadPump( 0, 0, &_pPump ) ); // コピー元とコピー先作成 u32 datSize = 1024 * 1024 * 250; _dat = myAlc( datSize ); void* buf = myAlc( datSize ); _bufInfo.init( datSize, buf ); // ローダー作成 ID3DX10DataLoader* memLoader; HRESULT hr = D3DX10CreateAsyncMemoryLoader( _dat, datSize, &memLoader ); DTrace( hr ); // プロセッサの作成 ASyncMemLoadProcessor* pProcs = ASyncMemLoadProcessor::Create( _bufInfo ); // スレッドポンプに作業を追加 _pPump->AddWorkItem( memLoader, pProcs, NULL, NULL ); } testThreadPump::~testThreadPump( void ) { SAFE_RELEASE( _pPump ); SAFE_FREE( _bufInfo.getBufRef() ); SAFE_FREE( _dat ); } // 毎フレーム実行される処理 void testThreadPump::func( void ) { _pPump->ProcessDeviceWorkItems(1); gFont.add( _bufInfo.isReady() ? _T("true") : _T("false") ); // デバッグ表示 }