/xbmc/cores/VideoRenderers/RenderManager.cpp

http://github.com/xbmc/xbmc · C++ · 1095 lines · 855 code · 173 blank · 67 comment · 234 complexity · 48a0484ac23ca1dd303cecf9fb32d1b7 MD5 · raw file

  1. /*
  2. * Copyright (C) 2005-2013 Team XBMC
  3. * http://xbmc.org
  4. *
  5. * This Program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 2, or (at your option)
  8. * any later version.
  9. *
  10. * This Program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with XBMC; see the file COPYING. If not, see
  17. * <http://www.gnu.org/licenses/>.
  18. *
  19. */
  20. #include "system.h"
  21. #if defined(HAS_GL)
  22. #include "system_gl.h"
  23. #endif
  24. #include "RenderManager.h"
  25. #include "threads/CriticalSection.h"
  26. #include "video/VideoReferenceClock.h"
  27. #include "utils/MathUtils.h"
  28. #include "threads/Atomics.h"
  29. #include "threads/SingleLock.h"
  30. #include "utils/log.h"
  31. #include "utils/TimeUtils.h"
  32. #include "Application.h"
  33. #include "ApplicationMessenger.h"
  34. #include "settings/AdvancedSettings.h"
  35. #include "settings/MediaSettings.h"
  36. #include "settings/Settings.h"
  37. #if defined(HAS_GL)
  38. #include "LinuxRendererGL.h"
  39. #elif HAS_GLES == 2
  40. #include "LinuxRendererGLES.h"
  41. #elif defined(HAS_DX)
  42. #include "WinRenderer.h"
  43. #elif defined(HAS_SDL)
  44. #include "LinuxRenderer.h"
  45. #endif
  46. #include "RenderCapture.h"
  47. /* to use the same as player */
  48. #include "../dvdplayer/DVDClock.h"
  49. #include "../dvdplayer/DVDCodecs/Video/DVDVideoCodec.h"
  50. #include "../dvdplayer/DVDCodecs/DVDCodecUtils.h"
  51. #define MAXPRESENTDELAY 0.500
  52. /* at any point we want an exclusive lock on rendermanager */
  53. /* we must make sure we don't have a graphiccontext lock */
  54. /* these two functions allow us to step out from that lock */
  55. /* and reaquire it after having the exclusive lock */
  56. template<class T>
  57. class CRetakeLock
  58. {
  59. public:
  60. CRetakeLock(CSharedSection &section, CCriticalSection &owned = g_graphicsContext)
  61. : m_count(owned.exit())
  62. , m_lock (section),
  63. m_owned(owned)
  64. {
  65. m_owned.restore(m_count);
  66. }
  67. void Leave() { m_lock.Leave(); }
  68. void Enter()
  69. {
  70. m_count = m_owned.exit();
  71. m_lock.Enter();
  72. m_owned.restore(m_count);
  73. }
  74. private:
  75. DWORD m_count;
  76. T m_lock;
  77. CCriticalSection &m_owned;
  78. };
  79. static void requeue(std::deque<int> &trg, std::deque<int> &src)
  80. {
  81. trg.push_back(src.front());
  82. src.pop_front();
  83. }
  84. CXBMCRenderManager::CXBMCRenderManager()
  85. {
  86. m_pRenderer = NULL;
  87. m_bIsStarted = false;
  88. m_presentstep = PRESENT_IDLE;
  89. m_rendermethod = 0;
  90. m_presentsource = 0;
  91. m_bReconfigured = false;
  92. m_hasCaptures = false;
  93. m_displayLatency = 0.0f;
  94. m_presentcorr = 0.0;
  95. m_presenterr = 0.0;
  96. memset(&m_errorbuff, 0, ERRORBUFFSIZE);
  97. m_errorindex = 0;
  98. m_QueueSize = 2;
  99. m_QueueSkip = 0;
  100. m_format = RENDER_FMT_NONE;
  101. }
  102. CXBMCRenderManager::~CXBMCRenderManager()
  103. {
  104. delete m_pRenderer;
  105. m_pRenderer = NULL;
  106. }
  107. void CXBMCRenderManager::GetVideoRect(CRect &source, CRect &dest)
  108. {
  109. CSharedLock lock(m_sharedSection);
  110. if (m_pRenderer)
  111. m_pRenderer->GetVideoRect(source, dest);
  112. }
  113. float CXBMCRenderManager::GetAspectRatio()
  114. {
  115. CSharedLock lock(m_sharedSection);
  116. if (m_pRenderer)
  117. return m_pRenderer->GetAspectRatio();
  118. else
  119. return 1.0f;
  120. }
  121. /* These is based on CurrentHostCounter() */
  122. double CXBMCRenderManager::GetPresentTime()
  123. {
  124. return CDVDClock::GetAbsoluteClock(false) / DVD_TIME_BASE;
  125. }
  126. static double wrap(double x, double minimum, double maximum)
  127. {
  128. if(x >= minimum
  129. && x <= maximum)
  130. return x;
  131. x = fmod(x - minimum, maximum - minimum) + minimum;
  132. if(x < minimum)
  133. x += maximum - minimum;
  134. if(x > maximum)
  135. x -= maximum - minimum;
  136. return x;
  137. }
  138. void CXBMCRenderManager::WaitPresentTime(double presenttime)
  139. {
  140. double frametime;
  141. int fps = g_VideoReferenceClock.GetRefreshRate(&frametime);
  142. if(fps <= 0)
  143. {
  144. /* smooth video not enabled */
  145. CDVDClock::WaitAbsoluteClock(presenttime * DVD_TIME_BASE);
  146. return;
  147. }
  148. bool ismaster = CDVDClock::IsMasterClock();
  149. //the videoreferenceclock updates its clock on every vertical blank
  150. //we want every frame's presenttime to end up in the middle of two vblanks
  151. //if CDVDPlayerAudio is the master clock, we add a correction to the presenttime
  152. if (ismaster)
  153. presenttime += m_presentcorr * frametime;
  154. double clock = CDVDClock::WaitAbsoluteClock(presenttime * DVD_TIME_BASE) / DVD_TIME_BASE;
  155. double target = 0.5;
  156. double error = ( clock - presenttime ) / frametime - target;
  157. m_presenterr = error;
  158. // correct error so it targets the closest vblank
  159. error = wrap(error, 0.0 - target, 1.0 - target);
  160. // scale the error used for correction,
  161. // based on how much buffer we have on
  162. // that side of the target
  163. if(error > 0)
  164. error /= 2.0 * (1.0 - target);
  165. if(error < 0)
  166. error /= 2.0 * (0.0 + target);
  167. //save error in the buffer
  168. m_errorindex = (m_errorindex + 1) % ERRORBUFFSIZE;
  169. m_errorbuff[m_errorindex] = error;
  170. //get the average error from the buffer
  171. double avgerror = 0.0;
  172. for (int i = 0; i < ERRORBUFFSIZE; i++)
  173. avgerror += m_errorbuff[i];
  174. avgerror /= ERRORBUFFSIZE;
  175. //if CDVDPlayerAudio is not the master clock, we change the clock speed slightly
  176. //to make every frame's presenttime end up in the middle of two vblanks
  177. if (!ismaster)
  178. {
  179. //integral correction, clamp to -0.5:0.5 range
  180. m_presentcorr = std::max(std::min(m_presentcorr + avgerror * 0.01, 0.1), -0.1);
  181. g_VideoReferenceClock.SetFineAdjust(1.0 - avgerror * 0.01 - m_presentcorr * 0.01);
  182. }
  183. else
  184. {
  185. //integral correction, wrap to -0.5:0.5 range
  186. m_presentcorr = wrap(m_presentcorr + avgerror * 0.01, target - 1.0, target);
  187. g_VideoReferenceClock.SetFineAdjust(1.0);
  188. }
  189. //printf("%f %f % 2.0f%% % f % f\n", presenttime, clock, m_presentcorr * 100, error, error_org);
  190. }
  191. CStdString CXBMCRenderManager::GetVSyncState()
  192. {
  193. double avgerror = 0.0;
  194. for (int i = 0; i < ERRORBUFFSIZE; i++)
  195. avgerror += m_errorbuff[i];
  196. avgerror /= ERRORBUFFSIZE;
  197. CStdString state;
  198. state.Format("sync:%+3d%% avg:%3d%% error:%2d%%"
  199. , MathUtils::round_int(m_presentcorr * 100)
  200. , MathUtils::round_int(avgerror * 100)
  201. , abs(MathUtils::round_int(m_presenterr * 100)));
  202. return state;
  203. }
  204. bool CXBMCRenderManager::Configure(unsigned int width, unsigned int height, unsigned int d_width, unsigned int d_height, float fps, unsigned flags, ERenderFormat format, unsigned extended_format, unsigned int orientation, int buffers)
  205. {
  206. CSingleLock lock2(m_presentlock);
  207. /* make sure any queued frame was fully presented */
  208. XbmcThreads::EndTime endtime(5000);
  209. while(m_presentstep != PRESENT_IDLE)
  210. {
  211. if(endtime.IsTimePast())
  212. {
  213. CLog::Log(LOGWARNING, "CRenderManager::Configure - timeout waiting for state");
  214. return false;
  215. }
  216. m_presentevent.wait(lock2, endtime.MillisLeft());
  217. };
  218. lock2.Leave();
  219. CExclusiveLock lock(m_sharedSection);
  220. if(!m_pRenderer)
  221. {
  222. CLog::Log(LOGERROR, "%s called without a valid Renderer object", __FUNCTION__);
  223. return false;
  224. }
  225. bool result = m_pRenderer->Configure(width, height, d_width, d_height, fps, flags, format, extended_format, orientation);
  226. if(result)
  227. {
  228. if( flags & CONF_FLAGS_FULLSCREEN )
  229. {
  230. lock.Leave();
  231. CApplicationMessenger::Get().SwitchToFullscreen();
  232. lock.Enter();
  233. }
  234. lock2.Enter();
  235. m_format = format;
  236. int processor = m_pRenderer->GetProcessorSize();
  237. if(processor)
  238. m_QueueSize = buffers - processor + 1; /* respect maximum refs */
  239. else
  240. m_QueueSize = m_pRenderer->GetMaxBufferSize(); /* no refs to data */
  241. m_QueueSize = std::min(m_QueueSize, (int)m_pRenderer->GetMaxBufferSize());
  242. m_QueueSize = std::min(m_QueueSize, NUM_BUFFERS);
  243. if(m_QueueSize < 2)
  244. {
  245. m_QueueSize = 2;
  246. CLog::Log(LOGWARNING, "CXBMCRenderManager::Configure - queue size too small (%d, %d, %d)", m_QueueSize, processor, buffers);
  247. }
  248. m_pRenderer->SetBufferSize(m_QueueSize);
  249. m_pRenderer->Update();
  250. m_queued.clear();
  251. m_discard.clear();
  252. m_free.clear();
  253. m_presentsource = 0;
  254. for (int i=1; i < m_QueueSize; i++)
  255. m_free.push_back(i);
  256. m_bIsStarted = true;
  257. m_bReconfigured = true;
  258. m_presentstep = PRESENT_IDLE;
  259. m_presentevent.notifyAll();
  260. m_firstFlipPage = false; // tempfix
  261. CLog::Log(LOGDEBUG, "CXBMCRenderManager::Configure - %d", m_QueueSize);
  262. }
  263. return result;
  264. }
  265. bool CXBMCRenderManager::RendererHandlesPresent() const
  266. {
  267. return IsConfigured() && (m_firstFlipPage || m_format != RENDER_FMT_BYPASS);
  268. }
  269. bool CXBMCRenderManager::IsConfigured() const
  270. {
  271. if (!m_pRenderer)
  272. return false;
  273. return m_pRenderer->IsConfigured();
  274. }
  275. void CXBMCRenderManager::Update()
  276. {
  277. CRetakeLock<CExclusiveLock> lock(m_sharedSection);
  278. if (m_pRenderer)
  279. m_pRenderer->Update();
  280. }
  281. bool CXBMCRenderManager::FrameWait(int ms)
  282. {
  283. XbmcThreads::EndTime timeout(ms);
  284. CSingleLock lock(m_presentlock);
  285. while(m_presentstep == PRESENT_IDLE && !timeout.IsTimePast())
  286. m_presentevent.wait(lock, timeout.MillisLeft());
  287. return m_presentstep != PRESENT_IDLE;
  288. }
  289. void CXBMCRenderManager::FrameMove()
  290. {
  291. { CSharedLock lock(m_sharedSection);
  292. CSingleLock lock2(m_presentlock);
  293. if (!m_pRenderer)
  294. return;
  295. if (m_presentstep == PRESENT_FRAME2)
  296. {
  297. if(!m_queued.empty())
  298. {
  299. double timestamp = GetPresentTime();
  300. SPresent& m = m_Queue[m_presentsource];
  301. SPresent& q = m_Queue[m_queued.front()];
  302. if(timestamp > m.timestamp + (q.timestamp - m.timestamp) * 0.5)
  303. {
  304. m_presentstep = PRESENT_READY;
  305. m_presentevent.notifyAll();
  306. }
  307. }
  308. }
  309. if (m_presentstep == PRESENT_READY)
  310. PrepareNextRender();
  311. if(m_presentstep == PRESENT_FLIP)
  312. {
  313. m_pRenderer->FlipPage(m_presentsource);
  314. m_presentstep = PRESENT_FRAME;
  315. m_presentevent.notifyAll();
  316. }
  317. /* release all previous */
  318. for(std::deque<int>::iterator it = m_discard.begin(); it != m_discard.end(); )
  319. {
  320. // TODO check for fence
  321. m_pRenderer->ReleaseBuffer(*it);
  322. m_overlays.Release(*it);
  323. m_free.push_back(*it);
  324. it = m_discard.erase(it);
  325. }
  326. }
  327. }
  328. void CXBMCRenderManager::FrameFinish()
  329. {
  330. /* wait for this present to be valid */
  331. SPresent& m = m_Queue[m_presentsource];
  332. if(g_graphicsContext.IsFullScreenVideo())
  333. WaitPresentTime(m.timestamp);
  334. { CSingleLock lock(m_presentlock);
  335. if(m_presentstep == PRESENT_FRAME)
  336. {
  337. if( m.presentmethod == PRESENT_METHOD_BOB
  338. || m.presentmethod == PRESENT_METHOD_WEAVE)
  339. m_presentstep = PRESENT_FRAME2;
  340. else
  341. m_presentstep = PRESENT_IDLE;
  342. }
  343. else if(m_presentstep == PRESENT_FRAME2)
  344. m_presentstep = PRESENT_IDLE;
  345. if(m_presentstep == PRESENT_IDLE)
  346. {
  347. if(!m_queued.empty())
  348. m_presentstep = PRESENT_READY;
  349. }
  350. m_presentevent.notifyAll();
  351. }
  352. }
  353. unsigned int CXBMCRenderManager::PreInit()
  354. {
  355. CRetakeLock<CExclusiveLock> lock(m_sharedSection);
  356. m_presentcorr = 0.0;
  357. m_presenterr = 0.0;
  358. m_errorindex = 0;
  359. memset(m_errorbuff, 0, sizeof(m_errorbuff));
  360. m_bIsStarted = false;
  361. if (!m_pRenderer)
  362. {
  363. #if defined(HAS_GL)
  364. m_pRenderer = new CLinuxRendererGL();
  365. #elif HAS_GLES == 2
  366. m_pRenderer = new CLinuxRendererGLES();
  367. #elif defined(HAS_DX)
  368. m_pRenderer = new CWinRenderer();
  369. #elif defined(HAS_SDL)
  370. m_pRenderer = new CLinuxRenderer();
  371. #endif
  372. }
  373. UpdateDisplayLatency();
  374. m_QueueSize = 2;
  375. m_QueueSkip = 0;
  376. return m_pRenderer->PreInit();
  377. }
  378. void CXBMCRenderManager::UnInit()
  379. {
  380. CRetakeLock<CExclusiveLock> lock(m_sharedSection);
  381. m_bIsStarted = false;
  382. m_overlays.Flush();
  383. // free renderer resources.
  384. // TODO: we may also want to release the renderer here.
  385. if (m_pRenderer)
  386. m_pRenderer->UnInit();
  387. }
  388. bool CXBMCRenderManager::Flush()
  389. {
  390. if (!m_pRenderer)
  391. return true;
  392. if (g_application.IsCurrentThread())
  393. {
  394. CLog::Log(LOGDEBUG, "%s - flushing renderer", __FUNCTION__);
  395. CRetakeLock<CExclusiveLock> lock(m_sharedSection);
  396. m_pRenderer->Flush();
  397. m_overlays.Flush();
  398. m_flushEvent.Set();
  399. }
  400. else
  401. {
  402. ThreadMessage msg = {TMSG_RENDERER_FLUSH};
  403. m_flushEvent.Reset();
  404. CApplicationMessenger::Get().SendMessage(msg, false);
  405. if (!m_flushEvent.WaitMSec(1000))
  406. {
  407. CLog::Log(LOGERROR, "%s - timed out waiting for renderer to flush", __FUNCTION__);
  408. return false;
  409. }
  410. else
  411. return true;
  412. }
  413. return true;
  414. }
  415. void CXBMCRenderManager::SetupScreenshot()
  416. {
  417. CSharedLock lock(m_sharedSection);
  418. if (m_pRenderer)
  419. m_pRenderer->SetupScreenshot();
  420. }
  421. CRenderCapture* CXBMCRenderManager::AllocRenderCapture()
  422. {
  423. return new CRenderCapture;
  424. }
  425. void CXBMCRenderManager::ReleaseRenderCapture(CRenderCapture* capture)
  426. {
  427. CSingleLock lock(m_captCritSect);
  428. RemoveCapture(capture);
  429. //because a CRenderCapture might have some gl things allocated, it can only be deleted from app thread
  430. if (g_application.IsCurrentThread())
  431. {
  432. delete capture;
  433. }
  434. else
  435. {
  436. capture->SetState(CAPTURESTATE_NEEDSDELETE);
  437. m_captures.push_back(capture);
  438. }
  439. if (!m_captures.empty())
  440. m_hasCaptures = true;
  441. }
  442. void CXBMCRenderManager::Capture(CRenderCapture* capture, unsigned int width, unsigned int height, int flags)
  443. {
  444. CSingleLock lock(m_captCritSect);
  445. RemoveCapture(capture);
  446. capture->SetState(CAPTURESTATE_NEEDSRENDER);
  447. capture->SetUserState(CAPTURESTATE_WORKING);
  448. capture->SetWidth(width);
  449. capture->SetHeight(height);
  450. capture->SetFlags(flags);
  451. capture->GetEvent().Reset();
  452. if (g_application.IsCurrentThread())
  453. {
  454. if (flags & CAPTUREFLAG_IMMEDIATELY)
  455. {
  456. //render capture and read out immediately
  457. RenderCapture(capture);
  458. capture->SetUserState(capture->GetState());
  459. capture->GetEvent().Set();
  460. }
  461. if ((flags & CAPTUREFLAG_CONTINUOUS) || !(flags & CAPTUREFLAG_IMMEDIATELY))
  462. {
  463. //schedule this capture for a render and readout
  464. m_captures.push_back(capture);
  465. }
  466. }
  467. else
  468. {
  469. //schedule this capture for a render and readout
  470. m_captures.push_back(capture);
  471. }
  472. if (!m_captures.empty())
  473. m_hasCaptures = true;
  474. }
  475. void CXBMCRenderManager::ManageCaptures()
  476. {
  477. //no captures, return here so we don't do an unnecessary lock
  478. if (!m_hasCaptures)
  479. return;
  480. CSingleLock lock(m_captCritSect);
  481. std::list<CRenderCapture*>::iterator it = m_captures.begin();
  482. while (it != m_captures.end())
  483. {
  484. CRenderCapture* capture = *it;
  485. if (capture->GetState() == CAPTURESTATE_NEEDSDELETE)
  486. {
  487. delete capture;
  488. it = m_captures.erase(it);
  489. continue;
  490. }
  491. if (capture->GetState() == CAPTURESTATE_NEEDSRENDER)
  492. RenderCapture(capture);
  493. else if (capture->GetState() == CAPTURESTATE_NEEDSREADOUT)
  494. capture->ReadOut();
  495. if (capture->GetState() == CAPTURESTATE_DONE || capture->GetState() == CAPTURESTATE_FAILED)
  496. {
  497. //tell the thread that the capture is done or has failed
  498. capture->SetUserState(capture->GetState());
  499. capture->GetEvent().Set();
  500. if (capture->GetFlags() & CAPTUREFLAG_CONTINUOUS)
  501. {
  502. capture->SetState(CAPTURESTATE_NEEDSRENDER);
  503. //if rendering this capture continuously, and readout is async, render a new capture immediately
  504. if (capture->IsAsync() && !(capture->GetFlags() & CAPTUREFLAG_IMMEDIATELY))
  505. RenderCapture(capture);
  506. ++it;
  507. }
  508. else
  509. {
  510. it = m_captures.erase(it);
  511. }
  512. }
  513. else
  514. {
  515. ++it;
  516. }
  517. }
  518. if (m_captures.empty())
  519. m_hasCaptures = false;
  520. }
  521. void CXBMCRenderManager::RenderCapture(CRenderCapture* capture)
  522. {
  523. CSharedLock lock(m_sharedSection);
  524. if (!m_pRenderer || !m_pRenderer->RenderCapture(capture))
  525. capture->SetState(CAPTURESTATE_FAILED);
  526. }
  527. void CXBMCRenderManager::RemoveCapture(CRenderCapture* capture)
  528. {
  529. //remove this CRenderCapture from the list
  530. std::list<CRenderCapture*>::iterator it;
  531. while ((it = find(m_captures.begin(), m_captures.end(), capture)) != m_captures.end())
  532. m_captures.erase(it);
  533. }
  534. void CXBMCRenderManager::SetViewMode(int iViewMode)
  535. {
  536. CSharedLock lock(m_sharedSection);
  537. if (m_pRenderer)
  538. m_pRenderer->SetViewMode(iViewMode);
  539. }
  540. void CXBMCRenderManager::FlipPage(volatile bool& bStop, double timestamp /* = 0LL*/, int source /*= -1*/, EFIELDSYNC sync /*= FS_NONE*/)
  541. {
  542. { CSharedLock lock(m_sharedSection);
  543. if(bStop)
  544. return;
  545. if(!m_pRenderer) return;
  546. m_firstFlipPage = true; // tempfix
  547. EPRESENTMETHOD presentmethod;
  548. EDEINTERLACEMODE deinterlacemode = CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode;
  549. EINTERLACEMETHOD interlacemethod = AutoInterlaceMethodInternal(CMediaSettings::Get().GetCurrentVideoSettings().m_InterlaceMethod);
  550. if(g_advancedSettings.m_videoDisableBackgroundDeinterlace && !g_graphicsContext.IsFullScreenVideo())
  551. deinterlacemode = VS_DEINTERLACEMODE_OFF;
  552. if (deinterlacemode == VS_DEINTERLACEMODE_OFF)
  553. presentmethod = PRESENT_METHOD_SINGLE;
  554. else
  555. {
  556. if (deinterlacemode == VS_DEINTERLACEMODE_AUTO && sync == FS_NONE)
  557. presentmethod = PRESENT_METHOD_SINGLE;
  558. else
  559. {
  560. bool invert = false;
  561. if (interlacemethod == VS_INTERLACEMETHOD_RENDER_BLEND) presentmethod = PRESENT_METHOD_BLEND;
  562. else if (interlacemethod == VS_INTERLACEMETHOD_RENDER_WEAVE) presentmethod = PRESENT_METHOD_WEAVE;
  563. else if (interlacemethod == VS_INTERLACEMETHOD_RENDER_WEAVE_INVERTED) { presentmethod = PRESENT_METHOD_WEAVE ; invert = true; }
  564. else if (interlacemethod == VS_INTERLACEMETHOD_RENDER_BOB) presentmethod = PRESENT_METHOD_BOB;
  565. else if (interlacemethod == VS_INTERLACEMETHOD_RENDER_BOB_INVERTED) { presentmethod = PRESENT_METHOD_BOB; invert = true; }
  566. else if (interlacemethod == VS_INTERLACEMETHOD_DXVA_BOB) presentmethod = PRESENT_METHOD_BOB;
  567. else if (interlacemethod == VS_INTERLACEMETHOD_DXVA_BEST) presentmethod = PRESENT_METHOD_BOB;
  568. else presentmethod = PRESENT_METHOD_SINGLE;
  569. /* default to odd field if we want to deinterlace and don't know better */
  570. if (deinterlacemode == VS_DEINTERLACEMODE_FORCE && sync == FS_NONE)
  571. sync = FS_TOP;
  572. /* invert present field */
  573. if(invert)
  574. {
  575. if( sync == FS_BOT )
  576. sync = FS_TOP;
  577. else
  578. sync = FS_BOT;
  579. }
  580. }
  581. }
  582. /* failsafe for invalid timestamps, to make sure queue always empties */
  583. if(timestamp > GetPresentTime() + 5.0)
  584. timestamp = GetPresentTime() + 5.0;
  585. CSingleLock lock2(m_presentlock);
  586. if(m_free.empty())
  587. return;
  588. if(source < 0)
  589. source = m_free.front();
  590. SPresent& m = m_Queue[source];
  591. m.timestamp = timestamp;
  592. m.presentfield = sync;
  593. m.presentmethod = presentmethod;
  594. requeue(m_queued, m_free);
  595. /* signal to any waiters to check state */
  596. if(m_presentstep == PRESENT_IDLE)
  597. {
  598. m_presentstep = PRESENT_READY;
  599. m_presentevent.notifyAll();
  600. }
  601. }
  602. }
  603. void CXBMCRenderManager::Reset()
  604. {
  605. CSharedLock lock(m_sharedSection);
  606. if (m_pRenderer)
  607. m_pRenderer->Reset();
  608. }
  609. RESOLUTION CXBMCRenderManager::GetResolution()
  610. {
  611. CSharedLock lock(m_sharedSection);
  612. if (m_pRenderer)
  613. return m_pRenderer->GetResolution();
  614. else
  615. return RES_INVALID;
  616. }
  617. float CXBMCRenderManager::GetMaximumFPS()
  618. {
  619. float fps;
  620. if (CSettings::Get().GetInt("videoscreen.vsync") != VSYNC_DISABLED)
  621. {
  622. fps = (float)g_VideoReferenceClock.GetRefreshRate();
  623. if (fps <= 0) fps = g_graphicsContext.GetFPS();
  624. }
  625. else
  626. fps = 1000.0f;
  627. return fps;
  628. }
  629. void CXBMCRenderManager::RegisterRenderUpdateCallBack(const void *ctx, RenderUpdateCallBackFn fn)
  630. {
  631. if (m_pRenderer)
  632. m_pRenderer->RegisterRenderUpdateCallBack(ctx, fn);
  633. }
  634. void CXBMCRenderManager::RegisterRenderFeaturesCallBack(const void *ctx, RenderFeaturesCallBackFn fn)
  635. {
  636. if (m_pRenderer)
  637. m_pRenderer->RegisterRenderFeaturesCallBack(ctx, fn);
  638. }
  639. void CXBMCRenderManager::Render(bool clear, DWORD flags, DWORD alpha)
  640. {
  641. CSharedLock lock(m_sharedSection);
  642. SPresent& m = m_Queue[m_presentsource];
  643. if( m.presentmethod == PRESENT_METHOD_BOB )
  644. PresentFields(clear, flags, alpha);
  645. else if( m.presentmethod == PRESENT_METHOD_WEAVE )
  646. PresentFields(clear, flags | RENDER_FLAG_WEAVE, alpha);
  647. else if( m.presentmethod == PRESENT_METHOD_BLEND )
  648. PresentBlend(clear, flags, alpha);
  649. else
  650. PresentSingle(clear, flags, alpha);
  651. m_overlays.Render(m_presentsource);
  652. }
  653. /* simple present method */
  654. void CXBMCRenderManager::PresentSingle(bool clear, DWORD flags, DWORD alpha)
  655. {
  656. CSingleLock lock(g_graphicsContext);
  657. m_pRenderer->RenderUpdate(clear, flags, alpha);
  658. }
  659. /* new simpler method of handling interlaced material, *
  660. * we just render the two fields right after eachother */
  661. void CXBMCRenderManager::PresentFields(bool clear, DWORD flags, DWORD alpha)
  662. {
  663. CSingleLock lock(g_graphicsContext);
  664. SPresent& m = m_Queue[m_presentsource];
  665. if(m_presentstep == PRESENT_FRAME)
  666. {
  667. if( m.presentfield == FS_BOT)
  668. m_pRenderer->RenderUpdate(clear, flags | RENDER_FLAG_BOT | RENDER_FLAG_FIELD0, alpha);
  669. else
  670. m_pRenderer->RenderUpdate(clear, flags | RENDER_FLAG_TOP | RENDER_FLAG_FIELD0, alpha);
  671. }
  672. else
  673. {
  674. if( m.presentfield == FS_TOP)
  675. m_pRenderer->RenderUpdate(clear, flags | RENDER_FLAG_BOT | RENDER_FLAG_FIELD1, alpha);
  676. else
  677. m_pRenderer->RenderUpdate(clear, flags | RENDER_FLAG_TOP | RENDER_FLAG_FIELD1, alpha);
  678. }
  679. }
  680. void CXBMCRenderManager::PresentBlend(bool clear, DWORD flags, DWORD alpha)
  681. {
  682. CSingleLock lock(g_graphicsContext);
  683. SPresent& m = m_Queue[m_presentsource];
  684. if( m.presentfield == FS_BOT )
  685. {
  686. m_pRenderer->RenderUpdate(clear, flags | RENDER_FLAG_BOT | RENDER_FLAG_NOOSD, alpha);
  687. m_pRenderer->RenderUpdate(false, flags | RENDER_FLAG_TOP, alpha / 2);
  688. }
  689. else
  690. {
  691. m_pRenderer->RenderUpdate(clear, flags | RENDER_FLAG_TOP | RENDER_FLAG_NOOSD, alpha);
  692. m_pRenderer->RenderUpdate(false, flags | RENDER_FLAG_BOT, alpha / 2);
  693. }
  694. }
  695. void CXBMCRenderManager::Recover()
  696. {
  697. #if defined(HAS_GL) && !defined(TARGET_DARWIN)
  698. glFlush(); // attempt to have gpu done with pixmap and vdpau
  699. #endif
  700. UpdateDisplayLatency();
  701. }
  702. void CXBMCRenderManager::UpdateDisplayLatency()
  703. {
  704. float refresh = g_graphicsContext.GetFPS();
  705. if (g_graphicsContext.GetVideoResolution() == RES_WINDOW)
  706. refresh = 0; // No idea about refresh rate when windowed, just get the default latency
  707. m_displayLatency = (double) g_advancedSettings.GetDisplayLatency(refresh);
  708. CLog::Log(LOGDEBUG, "CRenderManager::UpdateDisplayLatency - Latency set to %1.0f msec", m_displayLatency * 1000.0f);
  709. }
  710. void CXBMCRenderManager::UpdateResolution()
  711. {
  712. if (m_bReconfigured)
  713. {
  714. CRetakeLock<CExclusiveLock> lock(m_sharedSection);
  715. if (g_graphicsContext.IsFullScreenVideo() && g_graphicsContext.IsFullScreenRoot())
  716. {
  717. RESOLUTION res = GetResolution();
  718. g_graphicsContext.SetVideoResolution(res);
  719. }
  720. m_bReconfigured = false;
  721. }
  722. }
  723. unsigned int CXBMCRenderManager::GetProcessorSize()
  724. {
  725. CSharedLock lock(m_sharedSection);
  726. return std::max(4, NUM_BUFFERS);
  727. }
  728. // Supported pixel formats, can be called before configure
  729. std::vector<ERenderFormat> CXBMCRenderManager::SupportedFormats()
  730. {
  731. CSharedLock lock(m_sharedSection);
  732. if (m_pRenderer)
  733. return m_pRenderer->SupportedFormats();
  734. return std::vector<ERenderFormat>();
  735. }
  736. int CXBMCRenderManager::AddVideoPicture(DVDVideoPicture& pic)
  737. {
  738. CSharedLock lock(m_sharedSection);
  739. if (!m_pRenderer)
  740. return -1;
  741. int index;
  742. {
  743. CSingleLock lock(m_presentlock);
  744. if (m_free.empty())
  745. return -1;
  746. index = m_free.front();
  747. }
  748. if(m_pRenderer->AddVideoPicture(&pic, index))
  749. return 1;
  750. YV12Image image;
  751. if (m_pRenderer->GetImage(&image, index) < 0)
  752. return -1;
  753. if(pic.format == RENDER_FMT_YUV420P
  754. || pic.format == RENDER_FMT_YUV420P10
  755. || pic.format == RENDER_FMT_YUV420P16)
  756. {
  757. CDVDCodecUtils::CopyPicture(&image, &pic);
  758. }
  759. else if(pic.format == RENDER_FMT_NV12)
  760. {
  761. CDVDCodecUtils::CopyNV12Picture(&image, &pic);
  762. }
  763. else if(pic.format == RENDER_FMT_YUYV422
  764. || pic.format == RENDER_FMT_UYVY422)
  765. {
  766. CDVDCodecUtils::CopyYUV422PackedPicture(&image, &pic);
  767. }
  768. else if(pic.format == RENDER_FMT_DXVA)
  769. {
  770. CDVDCodecUtils::CopyDXVA2Picture(&image, &pic);
  771. }
  772. #ifdef HAVE_LIBVDPAU
  773. else if(pic.format == RENDER_FMT_VDPAU
  774. || pic.format == RENDER_FMT_VDPAU_420)
  775. m_pRenderer->AddProcessor(pic.vdpau, index);
  776. #endif
  777. #ifdef HAVE_LIBOPENMAX
  778. else if(pic.format == RENDER_FMT_OMXEGL)
  779. m_pRenderer->AddProcessor(pic.openMax, &pic, index);
  780. #endif
  781. #ifdef TARGET_DARWIN
  782. else if(pic.format == RENDER_FMT_CVBREF)
  783. m_pRenderer->AddProcessor(pic.cvBufferRef, index);
  784. #endif
  785. #ifdef HAVE_LIBVA
  786. else if(pic.format == RENDER_FMT_VAAPI)
  787. m_pRenderer->AddProcessor(*pic.vaapi, index);
  788. #endif
  789. #ifdef HAS_LIBSTAGEFRIGHT
  790. else if(pic.format == RENDER_FMT_EGLIMG)
  791. m_pRenderer->AddProcessor(pic.stf, pic.eglimg, index);
  792. #endif
  793. #if defined(TARGET_ANDROID)
  794. else if(pic.format == RENDER_FMT_MEDIACODEC)
  795. m_pRenderer->AddProcessor(pic.mediacodec, index);
  796. #endif
  797. m_pRenderer->ReleaseImage(index, false);
  798. return index;
  799. }
  800. bool CXBMCRenderManager::Supports(ERENDERFEATURE feature)
  801. {
  802. CSharedLock lock(m_sharedSection);
  803. if (m_pRenderer)
  804. return m_pRenderer->Supports(feature);
  805. else
  806. return false;
  807. }
  808. bool CXBMCRenderManager::Supports(EDEINTERLACEMODE method)
  809. {
  810. CSharedLock lock(m_sharedSection);
  811. if (m_pRenderer)
  812. return m_pRenderer->Supports(method);
  813. else
  814. return false;
  815. }
  816. bool CXBMCRenderManager::Supports(EINTERLACEMETHOD method)
  817. {
  818. CSharedLock lock(m_sharedSection);
  819. if (m_pRenderer)
  820. return m_pRenderer->Supports(method);
  821. else
  822. return false;
  823. }
  824. bool CXBMCRenderManager::Supports(ESCALINGMETHOD method)
  825. {
  826. CSharedLock lock(m_sharedSection);
  827. if (m_pRenderer)
  828. return m_pRenderer->Supports(method);
  829. else
  830. return false;
  831. }
  832. EINTERLACEMETHOD CXBMCRenderManager::AutoInterlaceMethod(EINTERLACEMETHOD mInt)
  833. {
  834. CSharedLock lock(m_sharedSection);
  835. return AutoInterlaceMethodInternal(mInt);
  836. }
  837. EINTERLACEMETHOD CXBMCRenderManager::AutoInterlaceMethodInternal(EINTERLACEMETHOD mInt)
  838. {
  839. if (mInt == VS_INTERLACEMETHOD_NONE)
  840. return VS_INTERLACEMETHOD_NONE;
  841. if(!m_pRenderer->Supports(mInt))
  842. mInt = VS_INTERLACEMETHOD_AUTO;
  843. if (mInt == VS_INTERLACEMETHOD_AUTO)
  844. return m_pRenderer->AutoInterlaceMethod();
  845. return mInt;
  846. }
  847. int CXBMCRenderManager::WaitForBuffer(volatile bool& bStop, int timeout)
  848. {
  849. CSingleLock lock2(m_presentlock);
  850. XbmcThreads::EndTime endtime(timeout);
  851. while(m_free.empty())
  852. {
  853. m_presentevent.wait(lock2, std::min(50, timeout));
  854. if(endtime.IsTimePast() || bStop)
  855. {
  856. if (timeout != 0 && !bStop)
  857. CLog::Log(LOGWARNING, "CRenderManager::WaitForBuffer - timeout waiting for buffer");
  858. return -1;
  859. }
  860. }
  861. // make sure overlay buffer is released, this won't happen on AddOverlay
  862. m_overlays.Release(m_free.front());
  863. // return buffer level
  864. return m_queued.size() + m_discard.size();;
  865. }
  866. void CXBMCRenderManager::PrepareNextRender()
  867. {
  868. CSingleLock lock(m_presentlock);
  869. if (m_queued.empty())
  870. {
  871. CLog::Log(LOGERROR, "CRenderManager::PrepareNextRender - asked to prepare with nothing available");
  872. m_presentstep = PRESENT_IDLE;
  873. m_presentevent.notifyAll();
  874. return;
  875. }
  876. double clocktime = GetPresentTime();
  877. double frametime = 1.0 / GetMaximumFPS();
  878. /* see if any future queued frames are already due */
  879. std::deque<int>::reverse_iterator curr, prev;
  880. int idx;
  881. curr = prev = m_queued.rbegin();
  882. ++prev;
  883. while (prev != m_queued.rend())
  884. {
  885. if(clocktime > m_Queue[*prev].timestamp /* previous frame is late */
  886. && clocktime > m_Queue[*curr].timestamp - frametime) /* selected frame is close to it's display time */
  887. break;
  888. ++curr;
  889. ++prev;
  890. }
  891. idx = *curr;
  892. /* in fullscreen we will block after render, but only for MAXPRESENTDELAY */
  893. bool next;
  894. if(g_graphicsContext.IsFullScreenVideo())
  895. next = (m_Queue[idx].timestamp <= clocktime + MAXPRESENTDELAY);
  896. else
  897. next = (m_Queue[idx].timestamp <= clocktime + frametime);
  898. if (next)
  899. {
  900. /* skip late frames */
  901. while(m_queued.front() != idx)
  902. {
  903. requeue(m_discard, m_queued);
  904. m_QueueSkip++;
  905. }
  906. m_presentstep = PRESENT_FLIP;
  907. m_discard.push_back(m_presentsource);
  908. m_presentsource = idx;
  909. m_queued.pop_front();
  910. m_presentevent.notifyAll();
  911. }
  912. }
  913. void CXBMCRenderManager::DiscardBuffer()
  914. {
  915. CSharedLock lock(m_sharedSection);
  916. CSingleLock lock2(m_presentlock);
  917. while(!m_queued.empty())
  918. requeue(m_discard, m_queued);
  919. if(m_presentstep == PRESENT_READY)
  920. m_presentstep = PRESENT_IDLE;
  921. m_presentevent.notifyAll();
  922. }