コンプレッサが動かない状態であったため、エアコンの取り外しをあきらめました。
こうなると業者に頼まないと中の冷媒が解体時に漏れることになるので手の出しようが無くなりました・・・。
はいいとして、五回目です。そろそろ終わりです。
今回は描画処理の中枢となるGetSurfaceからPresentImageへの流れです。
GetSurfaceの処理
STDMETHODIMP CVMRSurfaceAllocator::GetSurface(DWORD_PTR dwUserID,DWORD dwSurfaceIndex,DWORD dwSurfaceFlags,IDirect3DSurface9 far **lplpSurface) { CheckPointer(lplpSurface,E_POINTER); if(dwSurfaceIndex >= m_veclpDirect3DSurface.size()) return E_FAIL; *lplpSurface = m_veclpDirect3DSurface[dwSurfaceIndex]; if(*lplpSurface == NULL) return E_POINTER; (*lplpSurface)->AddRef(); return S_OK; }
確保したVMRの描画用サーフェイスを引き渡す処理です。ほとんど見たまんまですが、エラー処理はきっかりとやっています。
dwSurfaceIndexでインデックス番号を指定してくるのでその番号のサーフェイスを返します。返すときは参照カウントをあげて返すのでその処理が必要です。
書いたとおり、この処理はPresentImageの前に必ず呼ばれるので描画との同期処理があるときはここで同期を強制的にとるのもありです。
PresentImageの処理
int m_nFilpTexNum,m_nTextureNum; STDMETHODIMP CVMRSurfaceAllocator::PresentImage(DWORD_PTR dwUserID,VMR9PresentationInfo *lpPresInfo) { HRESULT hr; IDirect3DTexture9 *lpTexture; CheckPointer(lpPresInfo,E_POINTER); CheckPointer(lpPresInfo->lpSurf,E_POINTER); hr = PresentToTexture(lpPresInfo); if(hr == D3D_OK){ if(m_nTextureNum < 0){ hr = lpPresInfo->lpSurf->GetContainer(IID_IDirect3DTexture9,(void **)&lpTexture); } else{ lpTexture = m_alpDirect3DTexture[m_nTextureNum]; lpTexture->AddRef(); hr = D3D_OK; } if(hr == D3D_OK){ //...ここで必要であればテクスチャを使っての描画処理を行う lpTexture->Release(); } } if(hr == D3DERR_DEVICELOST){ OnLostDevice(); hr = m_lpDirect3DDevice->TestCooperativeLevel(); if(hr == D3DERR_DEVICENOTRESET) OnResetDevice(); } return hr; }
メンバ関数を一つ増やします。PresentToTextureという関数で、引数と戻り値は見たまんまです。今回の描画対象のテクスチャに確実に描画する、という処理です。
描画に成功したときはテクスチャを取得します。描画対象のテクスチャ番号としてm_nTextureNumという変数に登場してもらいます。
この変数に代入されている番号のテクスチャにビデオが描画されている、という意味です。負であるときはlpPresInfoのlpSurfはテクスチャサーフェイスとして
VMR9で描画がされた、という意味になりますのでGetContainerを使ってテクスチャを取得します。そうでないときは内部のテクスチャを取得します。
あとはコメント部でテクスチャを使って必要な描画処理を行えばOKです。・・・実はちょっとここに問題がある場合があるのですが、このターンではすっ飛ばします。
デバイスロストになっているときはデバイスの復旧作業を行います。別の場所でロストとリセットが行われるときはちょっと処理に細工がいります。
PresentToTextureの処理
HRESULT CVMRSurfaceAllocator::PresentToTexture(VMR9PresentationInfo *lpPresInfo) { HRESULT hr; IDirect3DTexture9 far *lpTexture; IDirect3DSurface9 far *lpSurface; if(m_alpDirect3DTexture[0] != NULL){ lpTexture = m_alpDirect3DTexture[m_nFilpTexNum]; hr = lpTexture->GetSurfaceLevel(0,&lpSurface); if(hr != S_OK) return hr; hr = m_lpDirect3DDevice->StretchRect(lpPresInfo->lpSurf,NULL,lpSurface,NULL,D3DTEXF_NONE); if(hr != S_OK){ lpSurface->Release(); return hr; } lpSurface->Release(); m_nTextureNum = m_nFilpTexNum; m_nFilpTexNum = m_nFilpTexNum ^ 0x01; } else{ m_nFilpTexNum = -1; } return S_OK; }
自前で確保したときに確保したテクスチャに描画された絵を変換転送するという作業を行います。
なお、StretchRectにはおもしろい作用があって、テクスチャフォーマットを変換できる、という効果があります。
この効果を使って、フォーマットが描画フォーマットとなっていない場合などでサーフェイス=>テクスチャ変換が必要な場合の
変換処理をこの場所で行います。変換が必要でない場合もありますのでそのときは処理を行いません。
とまあ、それほど難しくないのですが、PresentImageが呼ばれたときにグラフィックボードによっては不思議な状態になっています。
それは、デバイスのレンダリングターゲットを一時的に乗っ取られて、VMR9の描画を行うようになっている、という状態です。
つまり、この瞬間には元々デバイスがレンダリングターゲットとしていたサーフェイスはどっかに消えていて、
InitializeDeviceによって確保してGetSurfaceで引き渡したサーフェイスがいつの間にかレンダリングターゲットになっていたりします。
びっくりです。なので、PresentImageのコメント部で普通にテクスチャの描画処理を書いても画面に描画することはできないわけです。
この辺にはいろいろと処理を追加しないと思った通りに動いてくれません。
あっさりと書いてみました。後何回あるのかな・・・。