PageRenderTime 61ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/MultiVideo/MultiVMR9/RenderEngine.cpp

http://game-ui-solution.googlecode.com/
C++ | 1074 lines | 744 code | 117 blank | 213 comment | 109 complexity | a0bf8d5e1c2766f2bf4c1727be705012 MD5 | raw file
Possible License(s): BSD-2-Clause, LGPL-2.1, ISC, Unlicense, MPL-2.0-no-copyleft-exception, GPL-2.0, BSD-3-Clause, MIT, LGPL-3.0
  1. //------------------------------------------------------------------------------
  2. // File: RenderEngine.cpp
  3. //
  4. // Desc: DirectShow sample code - Implementation of CMultiVMR9RenderEngine
  5. //
  6. // Copyright (c) Microsoft Corporation. All rights reserved.
  7. //------------------------------------------------------------------------------
  8. #include "stdafx.h"
  9. #include "RenderEngine.h"
  10. #include <d3dx9.h>
  11. #define LEADINGTIME 0 //????
  12. /******************************Public*Routine******************************\
  13. * CMultiVMR9RenderEngine
  14. *
  15. * constructor
  16. \**************************************************************************/
  17. CMultiVMR9RenderEngine::CMultiVMR9RenderEngine(LPUNKNOWN pUnk, HRESULT *phr)
  18. : CUnknown(NAME("MultiVMR9 Render Engine"), pUnk)
  19. , m_hWnd( NULL )
  20. , m_pDevice( NULL)
  21. , m_pUILayer( NULL )
  22. , m_pMixerControl( NULL )
  23. , m_pOwner( NULL )
  24. , m_pRenderTarget( NULL )
  25. , m_bInitialized( FALSE )
  26. , m_Timer( NULL )
  27. , m_setFPS( 100000 )
  28. , m_getFPS( 0 )
  29. , m_interframe( 33)
  30. , m_interframeInstant( 0L )
  31. , m_dwFramesDrawn( 0)
  32. , m_dwStart(0)
  33. , m_dwLastRender( 0)
  34. , m_dwNextRender(0)
  35. , m_lBottom(0)
  36. , m_lTop(0)
  37. ,m_hWndCpy(0)
  38. {
  39. // make sure timer is at least 2 ms accurate
  40. timeBeginPeriod(2);
  41. }
  42. /******************************Public*Routine******************************\
  43. * CMultiVMR9RenderEngine
  44. *
  45. * destructor
  46. \**************************************************************************/
  47. CMultiVMR9RenderEngine::~CMultiVMR9RenderEngine()
  48. {
  49. HRESULT hr = S_OK;
  50. CAutoLock Lock(&m_ObjectLock);
  51. // here we have to disconnect child IMultiVMR9UILayer and IMultiVMR9MixerControl
  52. if( m_pUILayer )
  53. {
  54. hr = m_pUILayer->SetRenderEngineOwner( NULL);
  55. if( FAILED(hr))
  56. {
  57. ::DbgMsg("~CMultiVMR9RenderEngine: failed to disconnect child UILayer, he = 0x%08x", hr);
  58. }
  59. }
  60. if( m_pMixerControl )
  61. {
  62. hr = m_pMixerControl->SetRenderEngineOwner(NULL);
  63. if( FAILED(hr))
  64. {
  65. ::DbgMsg("~CMultiVMR9RenderEngine: failed to disconnect child mixer control, he = 0x%08x", hr);
  66. }
  67. }
  68. Clean_();
  69. // call off the timer
  70. timeEndPeriod(2);
  71. }
  72. ///////////////////////// IUnknown /////////////////////////////////////////
  73. /******************************Public*Routine******************************\
  74. * CreateInstance
  75. \**************************************************************************/
  76. CUnknown* CMultiVMR9RenderEngine::CreateInstance(LPUNKNOWN pUnk, HRESULT *phr)
  77. {
  78. return new CMultiVMR9RenderEngine(pUnk, phr);
  79. }
  80. /******************************Public*Routine******************************\
  81. * NonDelegatingQueryInterface
  82. \**************************************************************************/
  83. STDMETHODIMP
  84. CMultiVMR9RenderEngine::NonDelegatingQueryInterface(
  85. REFIID riid,
  86. void ** ppv)
  87. {
  88. HRESULT hr = E_NOINTERFACE;
  89. *ppv = NULL;
  90. if (riid == IID_IMultiVMR9RenderEngine)
  91. {
  92. hr = GetInterface((IMultiVMR9RenderEngine *)this, ppv);
  93. }
  94. else
  95. {
  96. hr = CUnknown::NonDelegatingQueryInterface(riid,ppv);
  97. }
  98. return hr;
  99. }
  100. ///////////////////////// IMultiVMR9RenderEngine //////////////////////////////
  101. /******************************Public*Routine******************************\
  102. * Initialize
  103. *
  104. * Call this method right after IMultiVMR9Wizard object is created to configure
  105. * and initialize internal structures as well as D3D environment.
  106. *
  107. * hWnd - handle to valid video window
  108. * dwFlags - Configuration flags
  109. * lViewWidth - desired width of the view port. If <=0, render engine will use
  110. * default backbuffer width
  111. * lVieweHeight - desired height of the view port. if <=0, render engine
  112. * will use default value of backbuffer height
  113. * pMixerControl - customized IMultiVMR9MixerControl, use NULL for the default
  114. * pUILayer - customized IMultiVMR9UILayer, use NULL if there is no UI layer
  115. *
  116. * Return error codes: E_INVALIDARG (invalid config flags or hWnd),
  117. * VFW_E_WRONG_STATE (method was already called before)
  118. * E_FAIL (unexpected error),
  119. *
  120. \**************************************************************************/
  121. STDMETHODIMP CMultiVMR9RenderEngine::Initialize(
  122. HWND hWnd,
  123. DWORD dwFlags,
  124. IMultiVMR9MixerControl* pMixerControl,
  125. IMultiVMR9UILayer* pUILayer,
  126. D3DFORMAT format
  127. )
  128. {
  129. HRESULT hr = S_OK;
  130. D3DPRESENT_PARAMETERS pp;
  131. IDirect3D9* pD3D9 = NULL;
  132. if( FALSE == IsWindow( hWnd ))
  133. {
  134. ::DbgMsg("CMultiVMR9RenderEngine::Initialize: received invalid window handle");
  135. return E_INVALIDARG;
  136. }
  137. if( m_bInitialized )
  138. {
  139. ::DbgMsg("CMultiVMR9RenderEngine::Initialize: method was already called");
  140. return VFW_E_WRONG_STATE;
  141. }
  142. CAutoLock Lock(&m_ObjectLock);
  143. try
  144. {
  145. m_hWnd = hWnd;
  146. // TODO: check flags
  147. m_dwCfgFlags = dwFlags;
  148. if( pMixerControl )
  149. {
  150. m_pMixerControl = pMixerControl;
  151. m_pMixerControl->AddRef();
  152. }
  153. else // create default mixer control
  154. {
  155. CHECK_HR(
  156. hr = CoCreateInstance( CLSID_MultiVMR9MixerControl,
  157. NULL, CLSCTX_INPROC_SERVER,
  158. IID_IMultiVMR9MixerControl,
  159. (void**)&m_pMixerControl),
  160. ::DbgMsg("CMultiVMR9RenderEngine::Initialize: failed to create default MultiVMR9MixerControl, "\
  161. "hr = 0x%08x", hr));
  162. }
  163. CHECK_HR(
  164. m_pMixerControl->SetRenderEngineOwner( this ),
  165. ::DbgMsg("CMultiVMR9RenderEngine::Initialize: failed to advise 'this' owner to the mixer control"));
  166. if( pUILayer )
  167. {
  168. m_pUILayer = pUILayer;
  169. m_pUILayer->AddRef();
  170. CHECK_HR(
  171. m_pUILayer->SetRenderEngineOwner( this ),
  172. ::DbgMsg("CMultiVMR9RenderEngine::Initialize: failed to advise 'this' owner to the UI layer"));
  173. }
  174. // create Direct3D
  175. pD3D9 = Direct3DCreate9(D3D_SDK_VERSION);
  176. CHECK_HR(
  177. pD3D9 ? S_OK : E_FAIL,
  178. ::DbgMsg("CMultiVMR9RenderEngine::Initialize: failed to create Direct3D9 object"));
  179. // create device
  180. D3DFORMAT D3DFormatAlternatives[] =
  181. {
  182. D3DFMT_X8R8G8B8,
  183. D3DFMT_R5G6B5,
  184. D3DFMT_A8B8G8R8,
  185. D3DFMT_X4R4G4B4,
  186. D3DFMT_A4R4G4B4,
  187. D3DFMT_A1R5G5B5,
  188. D3DFMT_X1R5G5B5,
  189. };
  190. int nD3DFormatAlternatives = sizeof(D3DFormatAlternatives) / sizeof(D3DFORMAT);
  191. // try different alternatives
  192. for( int nFmt = 0; nFmt < nD3DFormatAlternatives; nFmt++)
  193. {
  194. D3DFORMAT fmt ;
  195. if(format != D3DFMT_UNKNOWN)
  196. {
  197. fmt = format;
  198. nFmt = nD3DFormatAlternatives;
  199. }
  200. else fmt = D3DFormatAlternatives[ nFmt ];
  201. ZeroMemory( &pp, sizeof(D3DPRESENT_PARAMETERS));
  202. pp.Windowed = TRUE;
  203. pp.hDeviceWindow = m_hWnd;
  204. pp.SwapEffect = D3DSWAPEFFECT_COPY ;
  205. pp.BackBufferCount = 1;
  206. pp.BackBufferFormat = fmt;
  207. pp.EnableAutoDepthStencil = TRUE;
  208. pp.AutoDepthStencilFormat = D3DFMT_D16;
  209. pp.Flags = D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL;
  210. pp.PresentationInterval = 0x80000000;
  211. hr = pD3D9->CreateDevice(D3DADAPTER_DEFAULT ,//D3DADAPTER_DEFAULT ,
  212. D3DDEVTYPE_HAL,//D3DDEVTYPE_HAL,
  213. m_hWnd,
  214. D3DCREATE_SOFTWARE_VERTEXPROCESSING | D3DCREATE_MULTITHREADED,
  215. &pp,
  216. &m_pDevice);
  217. if( SUCCEEDED(hr) && m_pDevice ){
  218. m_CreateFmt = fmt;
  219. break;
  220. }
  221. }// for
  222. hr = m_pDevice ? S_OK : hr;
  223. CHECK_HR(
  224. hr,
  225. ::DbgMsg("CMultiVMR9RenderEngine::Initialize: failed to create device, error code 0x%08x", hr));
  226. //maximum ambient light
  227. CHECK_HR(
  228. m_pDevice->SetRenderState(D3DRS_AMBIENT,RGB(255,255,255)),
  229. ::DbgMsg("CMultiVMR9RenderEngine::Initialize: failed in SetRenderState(D3DRS_AMBIENT...)"));
  230. //lighting disabled
  231. CHECK_HR(
  232. m_pDevice->SetRenderState(D3DRS_LIGHTING,FALSE),
  233. ::DbgMsg("CMultiVMR9RenderEngine::Initialize: failed in SetRenderState(D3DRS_LIGHTING...)"));
  234. //don't cull backside
  235. CHECK_HR(
  236. m_pDevice->SetRenderState(D3DRS_CULLMODE,D3DCULL_NONE),
  237. ::DbgMsg("CMultiVMR9RenderEngine::Initialize: failed in SetRenderState(D3DRS_CULLMODE...)"));
  238. //DISABLE depth buffering
  239. CHECK_HR(
  240. m_pDevice->SetRenderState(D3DRS_ZENABLE,D3DZB_FALSE),
  241. ::DbgMsg("CMultiVMR9RenderEngine::Initialize: failed in SetRenderState(D3DRS_ZENABLE...)"));
  242. // enable dithering
  243. CHECK_HR(
  244. m_pDevice->SetRenderState(D3DRS_DITHERENABLE, TRUE),
  245. ::DbgMsg("CMultiVMR9RenderEngine::Initialize: failed in SetRenderState(D3DRS_DITHERENABLE...)"));
  246. // disable stensil
  247. CHECK_HR(
  248. m_pDevice->SetRenderState(D3DRS_STENCILENABLE, FALSE),
  249. ::DbgMsg("CMultiVMR9RenderEngine::Initialize: failed in SetRenderState(D3DRS_STENCILENABLE...)"));
  250. // manage blending
  251. CHECK_HR(
  252. m_pDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE),
  253. ::DbgMsg("CMultiVMR9RenderEngine::Initialize: failed in SetRenderState(D3DRS_ALPHABLENDENABLE...)"));
  254. CHECK_HR(
  255. m_pDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA),
  256. ::DbgMsg("CMultiVMR9RenderEngine::Initialize: failed in SetRenderState(D3DRS_SRCBLEND...)"));
  257. CHECK_HR(
  258. m_pDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA),
  259. ::DbgMsg("CMultiVMR9RenderEngine::Initialize: failed in SetRenderState(D3DRS_DESTBLEND...)"));
  260. CHECK_HR(
  261. m_pDevice->SetRenderState(D3DRS_ALPHATESTENABLE, TRUE),
  262. ::DbgMsg("CMultiVMR9RenderEngine::Initialize: failed in SetRenderState(D3DRS_ALPHATESTENABLE...)"));
  263. CHECK_HR(
  264. m_pDevice->SetRenderState(D3DRS_ALPHAREF, 0x10),
  265. ::DbgMsg("CMultiVMR9RenderEngine::Initialize: failed in SetRenderState(D3DRS_ALPHAREF...)"));
  266. CHECK_HR(
  267. m_pDevice->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATER),
  268. ::DbgMsg("CMultiVMR9RenderEngine::Initialize: failed in SetRenderState(D3DRS_ALPHAFUNC...)"));
  269. // set up sampler
  270. CHECK_HR(
  271. m_pDevice->SetSamplerState( 0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP),
  272. ::DbgMsg("CMultiVMR9RenderEngine::Initialize: failed in SetSamplerState(D3DSAMP_ADDRESSU...)"));
  273. CHECK_HR(
  274. m_pDevice->SetSamplerState( 0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP),
  275. ::DbgMsg("CMultiVMR9RenderEngine::Initialize: failed in SetSamplerState(D3DSAMP_ADDRESSV...)"));
  276. CHECK_HR(
  277. m_pDevice->SetSamplerState( 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR),
  278. ::DbgMsg("CMultiVMR9RenderEngine::Initialize: failed in SetSamplerState(D3DSAMP_MAGFILTER...)"));
  279. CHECK_HR(
  280. m_pDevice->SetSamplerState( 0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR),
  281. ::DbgMsg("CMultiVMR9RenderEngine::Initialize: failed in SetSamplerState(D3DSAMP_MINFILTER...)"));
  282. CHECK_HR(
  283. hr = m_pMixerControl->Initialize( m_pDevice ),
  284. ::DbgMsg("CMultiVMR9RenderEngine::Initialize: failed to initialize mixer control, hr = 0x%08x", hr));
  285. if( m_pUILayer )
  286. {
  287. CHECK_HR(
  288. hr = m_pUILayer->Initialize( m_pDevice ),
  289. ::DbgMsg("CMultiVMR9RenderEngine::Initialize: failed to initialize UI Layer, hr = 0x%08x", hr));
  290. }
  291. m_bInitialized = TRUE;
  292. }// try
  293. catch( HRESULT hr1 )
  294. {
  295. hr = hr1;
  296. }
  297. if(IsWindow(m_hWnd)){
  298. RECT rc,rcW;
  299. GetWindowRect(m_hWnd ,&rc);
  300. GetClientRect(m_hWnd,&rcW);
  301. m_lTop = rc.top + rcW.top;
  302. m_lBottom = rc.top + rcW.bottom;
  303. }
  304. RELEASE( pD3D9 );
  305. return hr;
  306. }
  307. STDMETHODIMP CMultiVMR9RenderEngine::InitializeEx(
  308. HWND hWnd,
  309. HWND hWndCpy,
  310. DWORD dwFlags,
  311. IMultiVMR9MixerControl* pMixerControl,
  312. IMultiVMR9UILayer* pUILayer,
  313. D3DFORMAT format
  314. )
  315. {
  316. if( FALSE == IsWindow( hWndCpy ))
  317. {
  318. ::DbgMsg("CMultiVMR9RenderEngine::InitializeEx: received invalid window handle");
  319. return E_INVALIDARG;
  320. }
  321. HRESULT hr = S_OK;
  322. hr = Initialize(hWnd,dwFlags,pMixerControl,pUILayer,format);
  323. if(FAILED(hr)) return hr;
  324. CAutoLock Lock(&m_ObjectLock);
  325. m_hWndCpy = hWndCpy;
  326. return S_OK;
  327. }
  328. /******************************Public*Routine******************************\
  329. * Terminate
  330. *
  331. \**************************************************************************/
  332. STDMETHODIMP CMultiVMR9RenderEngine::Terminate( void )
  333. {
  334. HRESULT hr = S_OK;
  335. if( m_pMixerControl )
  336. {
  337. hr = m_pMixerControl->SetRenderEngineOwner(NULL);
  338. if( FAILED(hr))
  339. {
  340. ::DbgMsg("CMultiVMR9RenderEngine::Terminate: failed to unadvise RenderEngineOwner for mixer control, hr = 0x%08x", hr);
  341. return hr;
  342. }
  343. RELEASE( m_pMixerControl );
  344. }
  345. if( m_pUILayer )
  346. {
  347. hr = m_pUILayer->SetRenderEngineOwner(NULL);
  348. if( FAILED(hr))
  349. {
  350. ::DbgMsg("CMultiVMR9RenderEngine::Terminate: failed to unadvise RenderEngineOwner for UI layer, hr = 0x%08x", hr);
  351. return hr;
  352. }
  353. RELEASE( m_pUILayer );
  354. }
  355. return S_OK;
  356. }
  357. /******************************Public*Routine******************************\
  358. * Render
  359. *
  360. * This method is called from a separate thread asynchronously from VMR calls
  361. * First, method checks internal timer, and if it is time to render new scene,
  362. * method calls mixer control's methods Compose() and Render(). After that, if
  363. * UI layer is present, we also call for its Render() method. We also keep track on
  364. * actual FPS rate here
  365. *
  366. * Return error codes: E_INVALIDARG (invalid config flags or hWnd),
  367. * VFW_E_WRONG_STATE (method was already called before)
  368. * E_FAIL (unexpected error),
  369. *
  370. \**************************************************************************/
  371. STDMETHODIMP CMultiVMR9RenderEngine::RenderNow(BOOL bStreamOut)
  372. {
  373. HRESULT hr = S_OK;
  374. HRESULT hrMC = S_OK;
  375. HRESULT hrUI = S_OK;
  376. COLORREF clr = RGB(0,0,0);
  377. D3DCOLOR backgroundColor;
  378. if( FALSE == m_bInitialized )
  379. {
  380. ::DbgMsg("CMultiVMR9RenderEngine::Render: object is not initialized");
  381. return VFW_E_WRONG_STATE;
  382. }
  383. if(!m_hWnd)
  384. {
  385. ::DbgMsg("CMultiVMR9RenderEngine::Render: object is not initialized");
  386. return VFW_E_WRONG_STATE;
  387. }
  388. CAutoLock Lock(&m_ObjectLock);
  389. if( !m_pMixerControl )
  390. {
  391. ::DbgMsg("CMultiVMR9RenderEngine::Render: FATAL, cannot find IMultiVMR9MixerControl");
  392. return E_UNEXPECTED;
  393. }
  394. hr = m_pMixerControl->GetBackgroundColor( &clr );
  395. if( FAILED(hr))
  396. {
  397. backgroundColor = D3DCOLOR_XRGB( 0x00, 0x00, 0x00);
  398. }
  399. else
  400. {
  401. backgroundColor = D3DCOLOR_XRGB( GetRValue( clr), GetGValue( clr), GetBValue( clr));
  402. }
  403. try
  404. {
  405. hr = m_pMixerControl->Compose( (void*)m_Timer );
  406. if( FAILED(hr))
  407. {
  408. ::DbgMsg("CMultiVMR9RenderEngine::Render: failed in IMultiVMR9MixerControl::Compose, hr = 0x%08x", hr);
  409. return hr;
  410. }
  411. //???
  412. {
  413. //render the scene
  414. CAutoLock BackLock(&m_BackBufferLock);
  415. CHECK_HR(
  416. hr = m_pDevice->Clear( 0L, // no rects (clear all)
  417. NULL, // clear entire viewport
  418. D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER,// clear render target
  419. backgroundColor,
  420. 1.0f, // clear all the depth
  421. 0L ), // no stencil
  422. ::DbgMsg("CMultiVMR9RenderEngine::Render: failed in IDirect3DDevice9::Clear, hr = 0x%08x", hr));
  423. CHECK_HR(
  424. hr = m_pDevice->BeginScene(),
  425. ::DbgMsg("CMultiVMR9RenderEngine::Render: failed in BeginScene(), hr = 0x%08x",hr));
  426. // first, render all the video source by means of mixer control
  427. hrMC = m_pMixerControl->Render( m_pDevice, (void*)m_Timer );
  428. /*if(m_pDeviceCpy){
  429. CHECK_HR(
  430. hr = m_pDeviceCpy->BeginScene(),
  431. ::DbgMsg("CMultiVMR9RenderEngine::Render: failed in BeginScene(), hr = 0x%08x",hr));
  432. CopyImage();
  433. CHECK_HR(
  434. hr = m_pDeviceCpy->EndScene(),
  435. ::DbgMsg("CMultiVMR9RenderEngine::Render: failed in EndScene(), hr = 0x%08x",hr));
  436. }*/
  437. if( m_pUILayer )
  438. {
  439. hrUI = m_pUILayer->Render( m_pDevice );
  440. }
  441. if(m_pOwner&& bStreamOut){
  442. TransformProc pProc = 0;
  443. IDirect3DSurface9 * pSurface = 0;
  444. m_pOwner->GetGlobalTransformProc(&pProc);
  445. hr = m_pDevice->GetBackBuffer(0,0,D3DBACKBUFFER_TYPE_MONO,&pSurface);
  446. m_pOwner->Transform(pSurface,CRefTime((LONG)m_Timer), CRefTime(LONG(m_Timer+m_interframe)) );
  447. m_pOwner->StreamOut(pSurface,CRefTime((LONG)m_Timer), CRefTime(LONG(m_Timer+m_interframe)));
  448. RELEASE(pSurface);
  449. }
  450. }
  451. CHECK_HR(
  452. hr = m_pDevice->EndScene(),
  453. ::DbgMsg("CMultiVMR9RenderEngine::Render: failed in EndScene(), hr = 0x%08x",hr));
  454. //wait fot vertical blank ??????
  455. //WaitForVerticalBlank();
  456. /*WaitForVerticalBlank32();*/
  457. D3DRASTER_STATUS status;
  458. CHECK_HR(
  459. hr = m_pDevice->GetRasterStatus(0,&status),
  460. ::DbgMsg("CMultiVMR9MixerControl::Render: failed to get raster status "\
  461. "hr = 0x%08x", hr));
  462. if(m_lTop >= m_lBottom - m_lTop){
  463. while(!status.InVBlank && status.ScanLine<m_lBottom-1){
  464. Sleep(1);
  465. m_pDevice->GetRasterStatus(0,&status);
  466. }
  467. }
  468. else{
  469. while( status.ScanLine < m_lBottom -1 ){
  470. Sleep(1);
  471. m_pDevice->GetRasterStatus(0,&status);
  472. }
  473. }
  474. CHECK_HR(
  475. hr = m_pDevice->Present(NULL,NULL,NULL,NULL),
  476. ::DbgMsg("CMultiVMR9RenderEngine::Render: failed in IDirect3DDevice9::Present(), hr = 0x%08x",hr));
  477. if(m_hWndCpy){
  478. CHECK_HR(
  479. hr = m_pDevice->Present(NULL,NULL,m_hWndCpy,NULL),
  480. ::DbgMsg("CMultiVMR9RenderEngine::Render: failed in IDirect3DDevice9::Present(), hr = 0x%08x",hr));
  481. }
  482. if( FAILED( hrMC ))
  483. {
  484. ::DbgMsg("CMultiVMR9RenderEngine::Render: failed in IMultiVMR9MixerControl::Render, error code 0x%08x", hrMC);
  485. hr = hrMC;
  486. }
  487. if( FAILED( hrUI ))
  488. {
  489. ::DbgMsg("CMultiVMR9RenderEngine::Render: failed in IMultiVMR9UILayer::Render, error code 0x%08x", hrUI);
  490. hr = FAILED(hr) ? hrUI : hr;
  491. }
  492. m_dwFramesDrawn++;
  493. if( m_dwFramesDrawn == ULONG_MAX ) // we have been running renderer for sooo long
  494. {
  495. // flush counters
  496. m_dwFramesDrawn = 0;
  497. }
  498. if( m_dwFramesDrawn > 1 )
  499. {
  500. m_interframeAvg = m_interframeAvg *(m_dwFramesDrawn-1) + (m_Timer - m_dwLastRender);
  501. m_interframeAvg /= m_dwFramesDrawn;
  502. }
  503. else
  504. {
  505. m_interframeAvg = m_interframeInstant;
  506. }
  507. } // try
  508. catch( HRESULT hr1 )
  509. {
  510. hr = hr1;
  511. }
  512. m_dwLastRender = m_Timer;
  513. return hr;
  514. }
  515. STDMETHODIMP CMultiVMR9RenderEngine::Render(void)
  516. {
  517. HRESULT hr = S_OK;
  518. HRESULT hrMC = S_OK;
  519. HRESULT hrUI = S_OK;
  520. COLORREF clr = RGB(0,0,0);
  521. D3DCOLOR backgroundColor;
  522. if( FALSE == m_bInitialized )
  523. {
  524. ::DbgMsg("CMultiVMR9RenderEngine::Render: object is not initialized");
  525. return VFW_E_WRONG_STATE;
  526. }
  527. DWORD dwCurTime = timeGetTime();
  528. if( 0 == m_dwStart )
  529. {
  530. m_dwStart = timeGetTime();
  531. }
  532. if(dwCurTime /*+ (double)m_interframe * LEADINGTIME*/ < m_dwNextRender + m_dwStart )
  533. {
  534. return S_OK;
  535. }
  536. // time is up: render
  537. m_interframeInstant = dwCurTime - (m_dwStart + m_Timer);
  538. m_Timer = dwCurTime - m_dwStart;
  539. m_dwNextRender += m_interframe;
  540. return RenderNow(TRUE);
  541. }
  542. /******************************Public*Routine******************************\
  543. * GetBackBuffer
  544. *
  545. * ?????IDirect3DSurface9*??
  546. \**************************************************************************/
  547. STDMETHODIMP CMultiVMR9RenderEngine::GetBackBuffer(UINT iSwapChain,UINT BackBuffer, D3DBACKBUFFER_TYPE Type,IDirect3DSurface9** pBackBuff,BOOL bCopy)
  548. {
  549. HRESULT hr = S_OK;
  550. if( FALSE == m_bInitialized )
  551. {
  552. ::DbgMsg("CMultiVMR9RenderEngine::GetUILayer: object is not initialized");
  553. return VFW_E_WRONG_STATE;
  554. }
  555. if( !pBackBuff )
  556. {
  557. ::DbgMsg("CMultiVMR9RenderEngine::Get3DDevice: received NULL pointer");
  558. return E_POINTER;
  559. }
  560. CAutoLock BackLock(&m_BackBufferLock);
  561. *pBackBuff = NULL;
  562. if(!m_pDevice) return VFW_E_WRONG_STATE;
  563. IDirect3DSurface9 *pTexturePrivSurf = 0;
  564. IDirect3DSurface9 *pBUFF = 0;
  565. try
  566. {
  567. hr = m_pDevice->GetBackBuffer(iSwapChain,BackBuffer,Type,&pTexturePrivSurf);
  568. //????????????
  569. if(!bCopy)
  570. {
  571. *pBackBuff = pTexturePrivSurf;
  572. if(pTexturePrivSurf) {pTexturePrivSurf->Release();pTexturePrivSurf = 0;}
  573. throw hr;
  574. }
  575. //??????
  576. if(FAILED(hr)) {
  577. if(pTexturePrivSurf) {pTexturePrivSurf->Release();pTexturePrivSurf = 0;}
  578. *pBackBuff = 0;
  579. throw hr;
  580. }
  581. D3DSURFACE_DESC dest;
  582. hr = pTexturePrivSurf->GetDesc(&dest);
  583. if(FAILED(hr)) {
  584. if(pTexturePrivSurf) {pTexturePrivSurf->Release();pTexturePrivSurf = 0;}
  585. *pBackBuff = 0;
  586. throw hr;
  587. }
  588. //????
  589. hr = m_pDevice->CreateOffscreenPlainSurface(
  590. dest.Width,
  591. dest.Height,
  592. dest.Format,
  593. D3DPOOL_SYSTEMMEM,
  594. &pBUFF,0);
  595. if(FAILED(hr)) {
  596. if(pTexturePrivSurf) {pTexturePrivSurf->Release();pTexturePrivSurf = 0;}
  597. if(pBUFF){pBUFF->Release();pBUFF = 0;}
  598. *pBackBuff = 0;
  599. throw hr;
  600. }
  601. if(!pBUFF){
  602. if(pTexturePrivSurf) {pTexturePrivSurf->Release();pTexturePrivSurf = 0;}
  603. *pBackBuff = 0;
  604. throw E_OUTOFMEMORY;
  605. }
  606. //????
  607. hr = m_pDevice->GetRenderTargetData(pTexturePrivSurf,pBUFF);
  608. if(FAILED(hr)) {
  609. if(pTexturePrivSurf) {pTexturePrivSurf->Release();pTexturePrivSurf = 0;}
  610. if(pBUFF){pBUFF->Release();pBUFF = 0;}
  611. *pBackBuff = 0;
  612. throw hr;
  613. }
  614. *pBackBuff = pBUFF;
  615. (*pBackBuff)->AddRef();
  616. //??????pBUFF->Release()
  617. }
  618. catch(HRESULT hr1)
  619. {
  620. hr = hr1;
  621. }
  622. RELEASE(pTexturePrivSurf);
  623. RELEASE(pBUFF);
  624. return hr;
  625. }
  626. /******************************Public*Routine******************************\
  627. * GetUILayer
  628. *
  629. * Call this method to obtain pointer to currently used UI layer.
  630. * if there is no UI Layer involved, method returns *ppUILayer = NULL;
  631. *
  632. * Return error codes: E_POINTER (ppUILayer is NULL)
  633. * VFW_E_WRONG_STATE (method Initialize() was never called)
  634. \**************************************************************************/
  635. STDMETHODIMP CMultiVMR9RenderEngine::GetUILayer(IMultiVMR9UILayer** ppUILayer)
  636. {
  637. HRESULT hr = S_OK;
  638. if( FALSE == m_bInitialized )
  639. {
  640. ::DbgMsg("CMultiVMR9RenderEngine::GetUILayer: object is not initialized");
  641. return VFW_E_WRONG_STATE;
  642. }
  643. if( !ppUILayer )
  644. {
  645. return E_POINTER;
  646. }
  647. if( m_pUILayer )
  648. {
  649. *ppUILayer = m_pUILayer;
  650. (*ppUILayer)->AddRef();
  651. }
  652. else
  653. {
  654. *ppUILayer = NULL;
  655. }
  656. return hr;
  657. }
  658. /******************************Public*Routine******************************\
  659. * SetFrameRate
  660. *
  661. * Call this method to specify desired frame rate, in (frames per sec)x100
  662. * Render engine will try to keep desired rate, but does not guarantee it,
  663. * use GetFrameRate() to get actual frame rate
  664. *
  665. * Return error codes: E_INVALIDARG (nFramesPerSecBy100 is less than 1 or bigger than 100000)
  666. * VFW_E_WRONG_STATE (method Initialize() was never called)
  667. \**************************************************************************/
  668. STDMETHODIMP CMultiVMR9RenderEngine::SetFrameRate(int nFramesPerSecBy100)
  669. {
  670. HRESULT hr = S_OK;
  671. if( FALSE == m_bInitialized )
  672. {
  673. ::DbgMsg("CMultiVMR9RenderEngine::SetFrameRate: object is not initialized");
  674. return VFW_E_WRONG_STATE;
  675. }
  676. if( nFramesPerSecBy100 <1 ||
  677. nFramesPerSecBy100 >100000 )
  678. {
  679. ::DbgMsg("CMultiVMR9RenderEngine::SetFrameRate: desired rate must be between 1 and 100000");
  680. return E_INVALIDARG;
  681. }
  682. CAutoLock Lock(&m_ObjectLock);
  683. m_setFPS = nFramesPerSecBy100;
  684. // update m_interframe which is inverse of FPS
  685. m_interframe = 100000 / m_setFPS;
  686. // we also have to flush counters for actual FPS
  687. m_interframeAvg = m_interframe;
  688. return hr;
  689. }
  690. STDMETHODIMP CMultiVMR9RenderEngine::GetSetedFrameRate(int *nFramesPerSecBy100)
  691. {
  692. if(nFramesPerSecBy100)
  693. {
  694. *nFramesPerSecBy100 = m_setFPS;
  695. return S_OK;
  696. }
  697. else
  698. {
  699. return E_POINTER;
  700. }
  701. }
  702. /******************************Public*Routine******************************\
  703. * GetFrameRate
  704. *
  705. * Call this method to obtain actual frame rate (instanteneous from the last rendering),
  706. * in (frames per sec)x100. Once started, renderer stops only when destroyed
  707. * (and if all the subgraphs are idle, it will be drawing last available images),
  708. *
  709. * Return error codes: E_POINTER (pnFramesPerSecBy100 is NULL)
  710. * VFW_E_WRONG_STATE (method Initialize() was never called)
  711. \**************************************************************************/
  712. STDMETHODIMP CMultiVMR9RenderEngine::GetFrameRate(int* pnFramesPerSecBy100)
  713. {
  714. if( FALSE == m_bInitialized )
  715. {
  716. ::DbgMsg("CMultiVMR9RenderEngine::GetFrameRate: object is not initialized");
  717. return VFW_E_WRONG_STATE;
  718. }
  719. if( !pnFramesPerSecBy100 )
  720. {
  721. ::DbgMsg("CMultiVMR9RenderEngine::GetFrameRate: received NULL pointer");
  722. return E_POINTER;
  723. }
  724. if( m_interframeInstant )
  725. {
  726. m_getFPS = 100000L / m_interframeInstant;
  727. }
  728. else
  729. {
  730. m_getFPS = 0L;
  731. }
  732. *pnFramesPerSecBy100 = m_getFPS;
  733. return S_OK;
  734. }
  735. /******************************Public*Routine******************************\
  736. * GetFrameRateAvg
  737. *
  738. * Call this method to obtain actual frame rate, smoothed and averaged in time,
  739. * in (frames per sec)x100. Once started, renderer stops only when destroyed
  740. * (and if all the subgraphs are idle, it will be drawing last available images),
  741. * so we calculate actual frame rate as
  742. *
  743. * InterFrameTime_ms = (InterFrameTime_ms *(FramesDrawn-1) + (time_from_the_last_rendering_ms)) / FramesDrawn;
  744. * FrameRateAvg = 100000 / InterFrameTime_ms;
  745. *
  746. * Actual calculations are performed in Render().
  747. *
  748. * Return error codes: E_POINTER (pnFramesPerSecBy100 is NULL)
  749. * VFW_E_WRONG_STATE (method Initialize() was never called)
  750. \**************************************************************************/
  751. STDMETHODIMP CMultiVMR9RenderEngine::GetFrameRateAvg( int* pnFramesPerSecBy100 )
  752. {
  753. if( FALSE == m_bInitialized )
  754. {
  755. ::DbgMsg("CMultiVMR9RenderEngine::GetFrameRate: object is not initialized");
  756. return VFW_E_WRONG_STATE;
  757. }
  758. if( !pnFramesPerSecBy100 )
  759. {
  760. ::DbgMsg("CMultiVMR9RenderEngine::GetFrameRate: received NULL pointer");
  761. return E_POINTER;
  762. }
  763. if( m_interframeAvg )
  764. {
  765. *pnFramesPerSecBy100 = 100000L / m_interframeAvg;
  766. }
  767. else
  768. {
  769. *pnFramesPerSecBy100 = 0L;
  770. }
  771. return S_OK;
  772. }
  773. /******************************Public*Routine******************************\
  774. * GetMixingPrefs
  775. *
  776. * Call this method to obtain flags with which this render engine was initialized
  777. *
  778. * Return error codes: E_POINTER (pdwPrefs is NULL)
  779. * VFW_E_WRONG_STATE (method Initialize() was never called)
  780. \**************************************************************************/
  781. STDMETHODIMP CMultiVMR9RenderEngine::GetMixingPrefs(DWORD* pdwPrefs)
  782. {
  783. if( FALSE == m_bInitialized )
  784. {
  785. ::DbgMsg("CMultiVMR9RenderEngine::GetMixingPrefs: object is not initialized");
  786. return VFW_E_WRONG_STATE;
  787. }
  788. if( !pdwPrefs )
  789. {
  790. ::DbgMsg("CMultiVMR9RenderEngine::GetMixingPrefs: received NULL pointer");
  791. return E_POINTER;
  792. }
  793. *pdwPrefs = m_dwCfgFlags;
  794. return S_OK;
  795. }
  796. /******************************Public*Routine******************************\
  797. * SetWizardOwner
  798. *
  799. * This method is called by IMultiVMR9Wizard when it takes 'this' as a render engine
  800. *
  801. * Return error codes:
  802. * VFW_E_WRONG_STATE (method Initialize() was never called)
  803. \**************************************************************************/
  804. STDMETHODIMP CMultiVMR9RenderEngine::SetWizardOwner(IMultiVMR9Wizard* pWizard)
  805. {
  806. HRESULT hr = S_OK;
  807. if( FALSE == m_bInitialized )
  808. {
  809. ::DbgMsg("CMultiVMR9RenderEngine::SetWizardOwner: object is not initialized");
  810. return VFW_E_WRONG_STATE;
  811. }
  812. CAutoLock Lock(&m_ObjectLock);
  813. RELEASE( m_pOwner );
  814. if( pWizard )
  815. {
  816. m_pOwner = pWizard;
  817. m_pOwner->AddRef();
  818. }
  819. return hr;
  820. }
  821. /******************************Public*Routine******************************\
  822. * GetWizardOwner
  823. *
  824. * Call this method to obtain pointer to IMultiVMR9Wizard that owns
  825. * 'this' as a render engine
  826. *
  827. * Return error codes: E_POINTER ( ppWizard is NULL )
  828. * VFW_E_WRONG_STATE (method Initialize() was never called)
  829. \**************************************************************************/
  830. STDMETHODIMP CMultiVMR9RenderEngine::GetWizardOwner(IMultiVMR9Wizard** ppWizard)
  831. {
  832. if( FALSE == m_bInitialized )
  833. {
  834. ::DbgMsg("CMultiVMR9RenderEngine::GetWizardOwner: object is not initialized");
  835. return VFW_E_WRONG_STATE;
  836. }
  837. if( !ppWizard )
  838. {
  839. ::DbgMsg("CMultiVMR9RenderEngine::GetWizardOwner: received NULL pointer");
  840. return E_POINTER;
  841. }
  842. if( m_pOwner )
  843. {
  844. *ppWizard = m_pOwner;
  845. (*ppWizard)->AddRef();
  846. }
  847. else
  848. {
  849. *ppWizard = NULL;
  850. }
  851. return S_OK;
  852. }
  853. /******************************Public*Routine******************************\
  854. * GetMixerControl
  855. *
  856. * Call this method to obtain pointer to IMultiVMR9MixerControl that is used by
  857. * 'this' render engine. Mixer Control is advised in Initialize() method.
  858. *
  859. * Return error codes: E_POINTER ( ppMixerControl is NULL )
  860. * VFW_E_WRONG_STATE (method Initialize() was never called)
  861. \**************************************************************************/
  862. STDMETHODIMP CMultiVMR9RenderEngine::GetMixerControl(IMultiVMR9MixerControl** ppMixerControl)
  863. {
  864. if( FALSE == m_bInitialized )
  865. {
  866. ::DbgMsg("CMultiVMR9RenderEngine::GetMixerControl: object is not initialized");
  867. return VFW_E_WRONG_STATE;
  868. }
  869. if( !ppMixerControl )
  870. {
  871. ::DbgMsg("CMultiVMR9RenderEngine::GetMixerControl: received NULL pointer");
  872. return E_POINTER;
  873. }
  874. if( m_pMixerControl )
  875. {
  876. *ppMixerControl = m_pMixerControl;
  877. (*ppMixerControl)->AddRef();
  878. }
  879. else
  880. {
  881. *ppMixerControl = NULL;
  882. }
  883. return S_OK;
  884. }
  885. /******************************Public*Routine******************************\
  886. * Get3DDevice
  887. *
  888. * Call this method to obtain Direct3DDevice9 used for rendering.
  889. * This device is created by 'Initialize()' method
  890. *
  891. * Return error codes: E_POINTER ( ppDevice is NULL )
  892. * VFW_E_WRONG_STATE (method Initialize() was never called)
  893. \**************************************************************************/
  894. STDMETHODIMP CMultiVMR9RenderEngine::Get3DDevice(IDirect3DDevice9 ** ppDevice)
  895. {
  896. if( FALSE == m_bInitialized )
  897. {
  898. ::DbgMsg("CMultiVMR9RenderEngine::Get3DDevice: object is not initialized");
  899. return VFW_E_WRONG_STATE;
  900. }
  901. if( !ppDevice )
  902. {
  903. ::DbgMsg("CMultiVMR9RenderEngine::Get3DDevice: received NULL pointer");
  904. return E_POINTER;
  905. }
  906. if( m_pDevice )
  907. {
  908. *ppDevice = m_pDevice;
  909. (*ppDevice)->AddRef();
  910. }
  911. else
  912. {
  913. *ppDevice = NULL;
  914. }
  915. return S_OK;
  916. }
  917. /******************************Public*Routine******************************\
  918. * GetVideoWindow
  919. *
  920. * Call this method to obtain handle to the video window.
  921. * This handle is sent to 'Initialize()' method
  922. *
  923. * Return error codes: E_POINTER ( phwnd is NULL )
  924. * VFW_E_WRONG_STATE (method Initialize() was never called)
  925. \**************************************************************************/
  926. STDMETHODIMP CMultiVMR9RenderEngine::GetVideoWindow(HWND *phwnd)
  927. {
  928. if( FALSE == m_bInitialized )
  929. {
  930. ::DbgMsg("CMultiVMR9RenderEngine::GetVideoWindow: object is not initialized");
  931. return VFW_E_WRONG_STATE;
  932. }
  933. if( !phwnd )
  934. {
  935. ::DbgMsg("CMultiVMR9RenderEngine::GetVideoWindow: received NULL pointer");
  936. return E_POINTER;
  937. }
  938. *phwnd = m_hWnd;
  939. return S_OK;
  940. }
  941. /////////////////////// Private routine ///////////////////////////////////////
  942. /******************************Private*Routine******************************\
  943. * Clean_
  944. *
  945. * clean all the data, release all interfaces
  946. \**************************************************************************/
  947. void CMultiVMR9RenderEngine::Clean_()
  948. {
  949. if( m_pOwner ) { m_pOwner->Release(); m_pOwner = NULL; }
  950. if( m_pMixerControl ) { m_pMixerControl->Release(); m_pMixerControl = NULL; }
  951. if( m_pUILayer ){ m_pUILayer->Release(); m_pUILayer = NULL; }
  952. if( m_pDevice ){ m_pDevice->Release(); m_pDevice = NULL; }
  953. if( m_pRenderTarget ){ m_pRenderTarget->Release(); m_pRenderTarget = NULL;}
  954. }