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