2 * Copyright (C) 2005-2013 Team XBMC
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)
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.
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/>.
23 #include "system_gl.h"
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"
34 #include "Application.h"
35 #include "ApplicationMessenger.h"
36 #include "settings/AdvancedSettings.h"
37 #include "settings/MediaSettings.h"
38 #include "settings/Settings.h"
39 #include "guilib/GUIFontManager.h"
42 #include "LinuxRendererGL.h"
44 #include "LinuxRendererGLES.h"
46 #include "WinRenderer.h"
47 #elif defined(HAS_SDL)
48 #include "LinuxRenderer.h"
51 #include "RenderCapture.h"
53 /* to use the same as player */
54 #include "../dvdplayer/DVDClock.h"
55 #include "../dvdplayer/DVDCodecs/Video/DVDVideoCodec.h"
56 #include "../dvdplayer/DVDCodecs/DVDCodecUtils.h"
58 #define MAXPRESENTDELAY 0.500
60 /* at any point we want an exclusive lock on rendermanager */
61 /* we must make sure we don't have a graphiccontext lock */
62 /* these two functions allow us to step out from that lock */
63 /* and reaquire it after having the exclusive lock */
69 CRetakeLock(CSharedSection §ion, CCriticalSection &owned = g_graphicsContext)
70 : m_count(owned.exit())
74 m_owned.restore(m_count);
77 void Leave() { m_lock.Leave(); }
80 m_count = m_owned.exit();
82 m_owned.restore(m_count);
88 CCriticalSection &m_owned;
91 static void requeue(std::deque<int> &trg, std::deque<int> &src)
93 trg.push_back(src.front());
97 CXBMCRenderManager::CXBMCRenderManager()
100 m_bIsStarted = false;
102 m_presentstep = PRESENT_IDLE;
105 m_bReconfigured = false;
106 m_hasCaptures = false;
107 m_displayLatency = 0.0f;
110 memset(&m_errorbuff, 0, ERRORBUFFSIZE);
114 m_format = RENDER_FMT_NONE;
117 CXBMCRenderManager::~CXBMCRenderManager()
123 void CXBMCRenderManager::GetVideoRect(CRect &source, CRect &dest)
125 CSharedLock lock(m_sharedSection);
127 m_pRenderer->GetVideoRect(source, dest);
130 float CXBMCRenderManager::GetAspectRatio()
132 CSharedLock lock(m_sharedSection);
134 return m_pRenderer->GetAspectRatio();
139 /* These is based on CurrentHostCounter() */
140 double CXBMCRenderManager::GetPresentTime()
142 return CDVDClock::GetAbsoluteClock(false) / DVD_TIME_BASE;
145 static double wrap(double x, double minimum, double maximum)
150 x = fmod(x - minimum, maximum - minimum) + minimum;
152 x += maximum - minimum;
154 x -= maximum - minimum;
158 void CXBMCRenderManager::WaitPresentTime(double presenttime)
161 int fps = g_VideoReferenceClock.GetRefreshRate(&frametime);
164 /* smooth video not enabled */
165 CDVDClock::WaitAbsoluteClock(presenttime * DVD_TIME_BASE);
169 bool ismaster = CDVDClock::IsMasterClock();
171 //the videoreferenceclock updates its clock on every vertical blank
172 //we want every frame's presenttime to end up in the middle of two vblanks
173 //if CDVDPlayerAudio is the master clock, we add a correction to the presenttime
175 presenttime += m_presentcorr * frametime;
177 double clock = CDVDClock::WaitAbsoluteClock(presenttime * DVD_TIME_BASE) / DVD_TIME_BASE;
179 double error = ( clock - presenttime ) / frametime - target;
181 m_presenterr = error;
183 // correct error so it targets the closest vblank
184 error = wrap(error, 0.0 - target, 1.0 - target);
186 // scale the error used for correction,
187 // based on how much buffer we have on
188 // that side of the target
190 error /= 2.0 * (1.0 - target);
192 error /= 2.0 * (0.0 + target);
194 //save error in the buffer
195 m_errorindex = (m_errorindex + 1) % ERRORBUFFSIZE;
196 m_errorbuff[m_errorindex] = error;
198 //get the average error from the buffer
199 double avgerror = 0.0;
200 for (int i = 0; i < ERRORBUFFSIZE; i++)
201 avgerror += m_errorbuff[i];
203 avgerror /= ERRORBUFFSIZE;
206 //if CDVDPlayerAudio is not the master clock, we change the clock speed slightly
207 //to make every frame's presenttime end up in the middle of two vblanks
210 //integral correction, clamp to -0.5:0.5 range
211 m_presentcorr = std::max(std::min(m_presentcorr + avgerror * 0.01, 0.1), -0.1);
212 g_VideoReferenceClock.SetFineAdjust(1.0 - avgerror * 0.01 - m_presentcorr * 0.01);
216 //integral correction, wrap to -0.5:0.5 range
217 m_presentcorr = wrap(m_presentcorr + avgerror * 0.01, target - 1.0, target);
218 g_VideoReferenceClock.SetFineAdjust(1.0);
221 //printf("%f %f % 2.0f%% % f % f\n", presenttime, clock, m_presentcorr * 100, error, error_org);
224 CStdString CXBMCRenderManager::GetVSyncState()
226 double avgerror = 0.0;
227 for (int i = 0; i < ERRORBUFFSIZE; i++)
228 avgerror += m_errorbuff[i];
229 avgerror /= ERRORBUFFSIZE;
232 state.Format("sync:%+3d%% avg:%3d%% error:%2d%%"
233 , MathUtils::round_int(m_presentcorr * 100)
234 , MathUtils::round_int(avgerror * 100)
235 , abs(MathUtils::round_int(m_presenterr * 100)));
239 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)
242 CSingleLock lock2(m_presentlock);
244 /* make sure any queued frame was fully presented */
245 XbmcThreads::EndTime endtime(5000);
246 while(m_presentstep != PRESENT_IDLE)
248 if(endtime.IsTimePast())
250 CLog::Log(LOGWARNING, "CRenderManager::Configure - timeout waiting for state");
253 m_presentevent.wait(lock2, endtime.MillisLeft());
257 CExclusiveLock lock(m_sharedSection);
260 CLog::Log(LOGERROR, "%s called without a valid Renderer object", __FUNCTION__);
265 bool result = m_pRenderer->Configure(width, height, d_width, d_height, fps, flags, format, extended_format, orientation);
268 if( flags & CONF_FLAGS_FULLSCREEN )
271 CApplicationMessenger::Get().SwitchToFullscreen();
277 int processor = m_pRenderer->GetProcessorSize();
279 m_QueueSize = buffers - processor + 1; /* respect maximum refs */
281 m_QueueSize = m_pRenderer->GetMaxBufferSize(); /* no refs to data */
283 m_QueueSize = std::min(m_QueueSize, (int)m_pRenderer->GetMaxBufferSize());
284 m_QueueSize = std::min(m_QueueSize, NUM_BUFFERS);
288 CLog::Log(LOGWARNING, "CXBMCRenderManager::Configure - queue size too small (%d, %d, %d)", m_QueueSize, processor, buffers);
291 m_pRenderer->SetBufferSize(m_QueueSize);
292 m_pRenderer->Update();
298 for (int i=1; i < m_QueueSize; i++)
302 m_bReconfigured = true;
303 m_presentstep = PRESENT_IDLE;
304 m_presentevent.notifyAll();
306 m_firstFlipPage = false; // tempfix
308 CLog::Log(LOGDEBUG, "CXBMCRenderManager::Configure - %d", m_QueueSize);
314 bool CXBMCRenderManager::RendererHandlesPresent() const
316 return IsConfigured() && (m_firstFlipPage || m_format != RENDER_FMT_BYPASS);
319 bool CXBMCRenderManager::IsConfigured() const
323 return m_pRenderer->IsConfigured();
326 void CXBMCRenderManager::Update()
328 CRetakeLock<CExclusiveLock> lock(m_sharedSection);
331 m_pRenderer->Update();
334 bool CXBMCRenderManager::FrameWait(int ms)
336 XbmcThreads::EndTime timeout(ms);
337 CSingleLock lock(m_presentlock);
338 while(m_presentstep == PRESENT_IDLE && !timeout.IsTimePast())
339 m_presentevent.wait(lock, timeout.MillisLeft());
340 return m_presentstep != PRESENT_IDLE;
343 void CXBMCRenderManager::FrameMove()
345 { CSharedLock lock(m_sharedSection);
346 CSingleLock lock2(m_presentlock);
351 if (m_presentstep == PRESENT_FRAME2)
353 if(!m_queued.empty())
355 double timestamp = GetPresentTime();
356 SPresent& m = m_Queue[m_presentsource];
357 SPresent& q = m_Queue[m_queued.front()];
358 if(timestamp > m.timestamp + (q.timestamp - m.timestamp) * 0.5)
360 m_presentstep = PRESENT_READY;
361 m_presentevent.notifyAll();
366 if (m_presentstep == PRESENT_READY)
369 if(m_presentstep == PRESENT_FLIP)
371 m_pRenderer->FlipPage(m_presentsource);
372 m_presentstep = PRESENT_FRAME;
373 m_presentevent.notifyAll();
376 /* release all previous */
377 for(std::deque<int>::iterator it = m_discard.begin(); it != m_discard.end(); )
379 // TODO check for fence
380 m_pRenderer->ReleaseBuffer(*it);
381 m_overlays.Release(*it);
382 m_free.push_back(*it);
383 it = m_discard.erase(it);
388 void CXBMCRenderManager::FrameFinish()
390 /* wait for this present to be valid */
391 SPresent& m = m_Queue[m_presentsource];
393 if(g_graphicsContext.IsFullScreenVideo())
394 WaitPresentTime(m.timestamp);
396 { CSingleLock lock(m_presentlock);
398 if(m_presentstep == PRESENT_FRAME)
400 if( m.presentmethod == PRESENT_METHOD_BOB
401 || m.presentmethod == PRESENT_METHOD_WEAVE)
402 m_presentstep = PRESENT_FRAME2;
404 m_presentstep = PRESENT_IDLE;
406 else if(m_presentstep == PRESENT_FRAME2)
407 m_presentstep = PRESENT_IDLE;
410 if(m_presentstep == PRESENT_IDLE)
412 if(!m_queued.empty())
413 m_presentstep = PRESENT_READY;
416 m_presentevent.notifyAll();
420 unsigned int CXBMCRenderManager::PreInit()
422 CRetakeLock<CExclusiveLock> lock(m_sharedSection);
427 memset(m_errorbuff, 0, sizeof(m_errorbuff));
429 m_bIsStarted = false;
433 m_pRenderer = new CLinuxRendererGL();
435 m_pRenderer = new CLinuxRendererGLES();
436 #elif defined(HAS_DX)
437 m_pRenderer = new CWinRenderer();
438 #elif defined(HAS_SDL)
439 m_pRenderer = new CLinuxRenderer();
443 UpdateDisplayLatency();
448 return m_pRenderer->PreInit();
451 void CXBMCRenderManager::UnInit()
453 CRetakeLock<CExclusiveLock> lock(m_sharedSection);
455 m_bIsStarted = false;
458 g_fontManager.Unload("__subtitle__");
459 g_fontManager.Unload("__subtitleborder__");
461 // free renderer resources.
462 // TODO: we may also want to release the renderer here.
464 m_pRenderer->UnInit();
467 bool CXBMCRenderManager::Flush()
472 if (g_application.IsCurrentThread())
474 CLog::Log(LOGDEBUG, "%s - flushing renderer", __FUNCTION__);
476 CRetakeLock<CExclusiveLock> lock(m_sharedSection);
477 m_pRenderer->Flush();
483 ThreadMessage msg = {TMSG_RENDERER_FLUSH};
484 m_flushEvent.Reset();
485 CApplicationMessenger::Get().SendMessage(msg, false);
486 if (!m_flushEvent.WaitMSec(1000))
488 CLog::Log(LOGERROR, "%s - timed out waiting for renderer to flush", __FUNCTION__);
497 void CXBMCRenderManager::SetupScreenshot()
499 CSharedLock lock(m_sharedSection);
501 m_pRenderer->SetupScreenshot();
504 CRenderCapture* CXBMCRenderManager::AllocRenderCapture()
506 return new CRenderCapture;
509 void CXBMCRenderManager::ReleaseRenderCapture(CRenderCapture* capture)
511 CSingleLock lock(m_captCritSect);
513 RemoveCapture(capture);
515 //because a CRenderCapture might have some gl things allocated, it can only be deleted from app thread
516 if (g_application.IsCurrentThread())
522 capture->SetState(CAPTURESTATE_NEEDSDELETE);
523 m_captures.push_back(capture);
526 if (!m_captures.empty())
527 m_hasCaptures = true;
530 void CXBMCRenderManager::Capture(CRenderCapture* capture, unsigned int width, unsigned int height, int flags)
532 CSingleLock lock(m_captCritSect);
534 RemoveCapture(capture);
536 capture->SetState(CAPTURESTATE_NEEDSRENDER);
537 capture->SetUserState(CAPTURESTATE_WORKING);
538 capture->SetWidth(width);
539 capture->SetHeight(height);
540 capture->SetFlags(flags);
541 capture->GetEvent().Reset();
543 if (g_application.IsCurrentThread())
545 if (flags & CAPTUREFLAG_IMMEDIATELY)
547 //render capture and read out immediately
548 RenderCapture(capture);
549 capture->SetUserState(capture->GetState());
550 capture->GetEvent().Set();
553 if ((flags & CAPTUREFLAG_CONTINUOUS) || !(flags & CAPTUREFLAG_IMMEDIATELY))
555 //schedule this capture for a render and readout
556 m_captures.push_back(capture);
561 //schedule this capture for a render and readout
562 m_captures.push_back(capture);
565 if (!m_captures.empty())
566 m_hasCaptures = true;
569 void CXBMCRenderManager::ManageCaptures()
571 //no captures, return here so we don't do an unnecessary lock
575 CSingleLock lock(m_captCritSect);
577 std::list<CRenderCapture*>::iterator it = m_captures.begin();
578 while (it != m_captures.end())
580 CRenderCapture* capture = *it;
582 if (capture->GetState() == CAPTURESTATE_NEEDSDELETE)
585 it = m_captures.erase(it);
589 if (capture->GetState() == CAPTURESTATE_NEEDSRENDER)
590 RenderCapture(capture);
591 else if (capture->GetState() == CAPTURESTATE_NEEDSREADOUT)
594 if (capture->GetState() == CAPTURESTATE_DONE || capture->GetState() == CAPTURESTATE_FAILED)
596 //tell the thread that the capture is done or has failed
597 capture->SetUserState(capture->GetState());
598 capture->GetEvent().Set();
600 if (capture->GetFlags() & CAPTUREFLAG_CONTINUOUS)
602 capture->SetState(CAPTURESTATE_NEEDSRENDER);
604 //if rendering this capture continuously, and readout is async, render a new capture immediately
605 if (capture->IsAsync() && !(capture->GetFlags() & CAPTUREFLAG_IMMEDIATELY))
606 RenderCapture(capture);
612 it = m_captures.erase(it);
621 if (m_captures.empty())
622 m_hasCaptures = false;
625 void CXBMCRenderManager::RenderCapture(CRenderCapture* capture)
627 CSharedLock lock(m_sharedSection);
628 if (!m_pRenderer || !m_pRenderer->RenderCapture(capture))
629 capture->SetState(CAPTURESTATE_FAILED);
632 void CXBMCRenderManager::RemoveCapture(CRenderCapture* capture)
634 //remove this CRenderCapture from the list
635 std::list<CRenderCapture*>::iterator it;
636 while ((it = find(m_captures.begin(), m_captures.end(), capture)) != m_captures.end())
637 m_captures.erase(it);
640 void CXBMCRenderManager::SetViewMode(int iViewMode)
642 CSharedLock lock(m_sharedSection);
644 m_pRenderer->SetViewMode(iViewMode);
647 void CXBMCRenderManager::FlipPage(volatile bool& bStop, double timestamp /* = 0LL*/, int source /*= -1*/, EFIELDSYNC sync /*= FS_NONE*/)
649 { CSharedLock lock(m_sharedSection);
654 if(!m_pRenderer) return;
656 m_firstFlipPage = true; // tempfix
658 EPRESENTMETHOD presentmethod;
660 EDEINTERLACEMODE deinterlacemode = CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode;
661 EINTERLACEMETHOD interlacemethod = AutoInterlaceMethodInternal(CMediaSettings::Get().GetCurrentVideoSettings().m_InterlaceMethod);
663 if(g_advancedSettings.m_videoDisableBackgroundDeinterlace && !g_graphicsContext.IsFullScreenVideo())
664 deinterlacemode = VS_DEINTERLACEMODE_OFF;
666 if (deinterlacemode == VS_DEINTERLACEMODE_OFF)
667 presentmethod = PRESENT_METHOD_SINGLE;
670 if (deinterlacemode == VS_DEINTERLACEMODE_AUTO && sync == FS_NONE)
671 presentmethod = PRESENT_METHOD_SINGLE;
675 if (interlacemethod == VS_INTERLACEMETHOD_RENDER_BLEND) presentmethod = PRESENT_METHOD_BLEND;
676 else if (interlacemethod == VS_INTERLACEMETHOD_RENDER_WEAVE) presentmethod = PRESENT_METHOD_WEAVE;
677 else if (interlacemethod == VS_INTERLACEMETHOD_RENDER_WEAVE_INVERTED) { presentmethod = PRESENT_METHOD_WEAVE ; invert = true; }
678 else if (interlacemethod == VS_INTERLACEMETHOD_RENDER_BOB) presentmethod = PRESENT_METHOD_BOB;
679 else if (interlacemethod == VS_INTERLACEMETHOD_RENDER_BOB_INVERTED) { presentmethod = PRESENT_METHOD_BOB; invert = true; }
680 else if (interlacemethod == VS_INTERLACEMETHOD_DXVA_BOB) presentmethod = PRESENT_METHOD_BOB;
681 else if (interlacemethod == VS_INTERLACEMETHOD_DXVA_BEST) presentmethod = PRESENT_METHOD_BOB;
682 else presentmethod = PRESENT_METHOD_SINGLE;
684 /* default to odd field if we want to deinterlace and don't know better */
685 if (deinterlacemode == VS_DEINTERLACEMODE_FORCE && sync == FS_NONE)
688 /* invert present field */
699 /* failsafe for invalid timestamps, to make sure queue always empties */
700 if(timestamp > GetPresentTime() + 5.0)
701 timestamp = GetPresentTime() + 5.0;
703 CSingleLock lock2(m_presentlock);
709 source = m_free.front();
711 SPresent& m = m_Queue[source];
712 m.timestamp = timestamp;
713 m.presentfield = sync;
714 m.presentmethod = presentmethod;
715 requeue(m_queued, m_free);
717 /* signal to any waiters to check state */
718 if(m_presentstep == PRESENT_IDLE)
720 m_presentstep = PRESENT_READY;
721 m_presentevent.notifyAll();
726 void CXBMCRenderManager::Reset()
728 CSharedLock lock(m_sharedSection);
730 m_pRenderer->Reset();
733 RESOLUTION CXBMCRenderManager::GetResolution()
735 CSharedLock lock(m_sharedSection);
737 return m_pRenderer->GetResolution();
742 float CXBMCRenderManager::GetMaximumFPS()
746 if (CSettings::Get().GetInt("videoscreen.vsync") != VSYNC_DISABLED)
748 fps = (float)g_VideoReferenceClock.GetRefreshRate();
749 if (fps <= 0) fps = g_graphicsContext.GetFPS();
757 void CXBMCRenderManager::RegisterRenderUpdateCallBack(const void *ctx, RenderUpdateCallBackFn fn)
760 m_pRenderer->RegisterRenderUpdateCallBack(ctx, fn);
763 void CXBMCRenderManager::RegisterRenderFeaturesCallBack(const void *ctx, RenderFeaturesCallBackFn fn)
766 m_pRenderer->RegisterRenderFeaturesCallBack(ctx, fn);
769 void CXBMCRenderManager::Render(bool clear, DWORD flags, DWORD alpha)
771 CSharedLock lock(m_sharedSection);
773 SPresent& m = m_Queue[m_presentsource];
775 if( m.presentmethod == PRESENT_METHOD_BOB )
776 PresentFields(clear, flags, alpha);
777 else if( m.presentmethod == PRESENT_METHOD_WEAVE )
778 PresentFields(clear, flags | RENDER_FLAG_WEAVE, alpha);
779 else if( m.presentmethod == PRESENT_METHOD_BLEND )
780 PresentBlend(clear, flags, alpha);
782 PresentSingle(clear, flags, alpha);
784 g_graphicsContext.SetRenderingResolution(g_graphicsContext.GetVideoResolution(), false);
785 m_overlays.Render(m_presentsource);
788 /* simple present method */
789 void CXBMCRenderManager::PresentSingle(bool clear, DWORD flags, DWORD alpha)
791 CSingleLock lock(g_graphicsContext);
793 m_pRenderer->RenderUpdate(clear, flags, alpha);
796 /* new simpler method of handling interlaced material, *
797 * we just render the two fields right after eachother */
798 void CXBMCRenderManager::PresentFields(bool clear, DWORD flags, DWORD alpha)
800 CSingleLock lock(g_graphicsContext);
801 SPresent& m = m_Queue[m_presentsource];
803 if(m_presentstep == PRESENT_FRAME)
805 if( m.presentfield == FS_BOT)
806 m_pRenderer->RenderUpdate(clear, flags | RENDER_FLAG_BOT | RENDER_FLAG_FIELD0, alpha);
808 m_pRenderer->RenderUpdate(clear, flags | RENDER_FLAG_TOP | RENDER_FLAG_FIELD0, alpha);
812 if( m.presentfield == FS_TOP)
813 m_pRenderer->RenderUpdate(clear, flags | RENDER_FLAG_BOT | RENDER_FLAG_FIELD1, alpha);
815 m_pRenderer->RenderUpdate(clear, flags | RENDER_FLAG_TOP | RENDER_FLAG_FIELD1, alpha);
819 void CXBMCRenderManager::PresentBlend(bool clear, DWORD flags, DWORD alpha)
821 CSingleLock lock(g_graphicsContext);
822 SPresent& m = m_Queue[m_presentsource];
824 if( m.presentfield == FS_BOT )
826 m_pRenderer->RenderUpdate(clear, flags | RENDER_FLAG_BOT | RENDER_FLAG_NOOSD, alpha);
827 m_pRenderer->RenderUpdate(false, flags | RENDER_FLAG_TOP, alpha / 2);
831 m_pRenderer->RenderUpdate(clear, flags | RENDER_FLAG_TOP | RENDER_FLAG_NOOSD, alpha);
832 m_pRenderer->RenderUpdate(false, flags | RENDER_FLAG_BOT, alpha / 2);
836 void CXBMCRenderManager::Recover()
838 #if defined(HAS_GL) && !defined(TARGET_DARWIN)
839 glFlush(); // attempt to have gpu done with pixmap and vdpau
842 UpdateDisplayLatency();
845 void CXBMCRenderManager::UpdateDisplayLatency()
847 float refresh = g_graphicsContext.GetFPS();
848 if (g_graphicsContext.GetVideoResolution() == RES_WINDOW)
849 refresh = 0; // No idea about refresh rate when windowed, just get the default latency
850 m_displayLatency = (double) g_advancedSettings.GetDisplayLatency(refresh);
851 CLog::Log(LOGDEBUG, "CRenderManager::UpdateDisplayLatency - Latency set to %1.0f msec", m_displayLatency * 1000.0f);
854 void CXBMCRenderManager::UpdateResolution()
858 CRetakeLock<CExclusiveLock> lock(m_sharedSection);
859 if (g_graphicsContext.IsFullScreenVideo() && g_graphicsContext.IsFullScreenRoot())
861 RESOLUTION res = GetResolution();
862 g_graphicsContext.SetVideoResolution(res);
864 m_bReconfigured = false;
869 unsigned int CXBMCRenderManager::GetProcessorSize()
871 CSharedLock lock(m_sharedSection);
872 return std::max(4, NUM_BUFFERS);
875 // Supported pixel formats, can be called before configure
876 std::vector<ERenderFormat> CXBMCRenderManager::SupportedFormats()
878 CSharedLock lock(m_sharedSection);
880 return m_pRenderer->SupportedFormats();
881 return std::vector<ERenderFormat>();
884 int CXBMCRenderManager::AddVideoPicture(DVDVideoPicture& pic)
886 CSharedLock lock(m_sharedSection);
892 CSingleLock lock(m_presentlock);
895 index = m_free.front();
898 if(m_pRenderer->AddVideoPicture(&pic, index))
902 if (m_pRenderer->GetImage(&image, index) < 0)
905 if(pic.format == RENDER_FMT_YUV420P
906 || pic.format == RENDER_FMT_YUV420P10
907 || pic.format == RENDER_FMT_YUV420P16)
909 CDVDCodecUtils::CopyPicture(&image, &pic);
911 else if(pic.format == RENDER_FMT_NV12)
913 CDVDCodecUtils::CopyNV12Picture(&image, &pic);
915 else if(pic.format == RENDER_FMT_YUYV422
916 || pic.format == RENDER_FMT_UYVY422)
918 CDVDCodecUtils::CopyYUV422PackedPicture(&image, &pic);
920 else if(pic.format == RENDER_FMT_DXVA)
922 CDVDCodecUtils::CopyDXVA2Picture(&image, &pic);
925 else if(pic.format == RENDER_FMT_VDPAU
926 || pic.format == RENDER_FMT_VDPAU_420)
927 m_pRenderer->AddProcessor(pic.vdpau, index);
929 #ifdef HAVE_LIBOPENMAX
930 else if(pic.format == RENDER_FMT_OMXEGL)
931 m_pRenderer->AddProcessor(pic.openMax, &pic, index);
934 else if(pic.format == RENDER_FMT_CVBREF)
935 m_pRenderer->AddProcessor(pic.cvBufferRef, index);
938 else if(pic.format == RENDER_FMT_VAAPI)
939 m_pRenderer->AddProcessor(*pic.vaapi, index);
941 #ifdef HAS_LIBSTAGEFRIGHT
942 else if(pic.format == RENDER_FMT_EGLIMG)
943 m_pRenderer->AddProcessor(pic.stf, pic.eglimg, index);
945 #if defined(TARGET_ANDROID)
946 else if(pic.format == RENDER_FMT_MEDIACODEC)
947 m_pRenderer->AddProcessor(pic.mediacodec, index);
950 m_pRenderer->ReleaseImage(index, false);
955 bool CXBMCRenderManager::Supports(ERENDERFEATURE feature)
957 CSharedLock lock(m_sharedSection);
959 return m_pRenderer->Supports(feature);
964 bool CXBMCRenderManager::Supports(EDEINTERLACEMODE method)
966 CSharedLock lock(m_sharedSection);
968 return m_pRenderer->Supports(method);
973 bool CXBMCRenderManager::Supports(EINTERLACEMETHOD method)
975 CSharedLock lock(m_sharedSection);
977 return m_pRenderer->Supports(method);
982 bool CXBMCRenderManager::Supports(ESCALINGMETHOD method)
984 CSharedLock lock(m_sharedSection);
986 return m_pRenderer->Supports(method);
991 EINTERLACEMETHOD CXBMCRenderManager::AutoInterlaceMethod(EINTERLACEMETHOD mInt)
993 CSharedLock lock(m_sharedSection);
994 return AutoInterlaceMethodInternal(mInt);
997 EINTERLACEMETHOD CXBMCRenderManager::AutoInterlaceMethodInternal(EINTERLACEMETHOD mInt)
999 if (mInt == VS_INTERLACEMETHOD_NONE)
1000 return VS_INTERLACEMETHOD_NONE;
1002 if(!m_pRenderer->Supports(mInt))
1003 mInt = VS_INTERLACEMETHOD_AUTO;
1005 if (mInt == VS_INTERLACEMETHOD_AUTO)
1006 return m_pRenderer->AutoInterlaceMethod();
1011 int CXBMCRenderManager::WaitForBuffer(volatile bool& bStop, int timeout)
1013 CSingleLock lock2(m_presentlock);
1015 XbmcThreads::EndTime endtime(timeout);
1016 while(m_free.empty())
1018 m_presentevent.wait(lock2, std::min(50, timeout));
1019 if(endtime.IsTimePast() || bStop)
1021 if (timeout != 0 && !bStop)
1022 CLog::Log(LOGWARNING, "CRenderManager::WaitForBuffer - timeout waiting for buffer");
1027 // make sure overlay buffer is released, this won't happen on AddOverlay
1028 m_overlays.Release(m_free.front());
1030 // return buffer level
1031 return m_queued.size() + m_discard.size();;
1034 void CXBMCRenderManager::PrepareNextRender()
1036 CSingleLock lock(m_presentlock);
1038 if (m_queued.empty())
1040 CLog::Log(LOGERROR, "CRenderManager::PrepareNextRender - asked to prepare with nothing available");
1041 m_presentstep = PRESENT_IDLE;
1042 m_presentevent.notifyAll();
1046 double clocktime = GetPresentTime();
1047 double frametime = 1.0 / GetMaximumFPS();
1049 /* see if any future queued frames are already due */
1050 std::deque<int>::reverse_iterator curr, prev;
1052 curr = prev = m_queued.rbegin();
1054 while (prev != m_queued.rend())
1056 if(clocktime > m_Queue[*prev].timestamp /* previous frame is late */
1057 && clocktime > m_Queue[*curr].timestamp - frametime) /* selected frame is close to it's display time */
1064 /* in fullscreen we will block after render, but only for MAXPRESENTDELAY */
1066 if(g_graphicsContext.IsFullScreenVideo())
1067 next = (m_Queue[idx].timestamp <= clocktime + MAXPRESENTDELAY);
1069 next = (m_Queue[idx].timestamp <= clocktime + frametime);
1073 /* skip late frames */
1074 while(m_queued.front() != idx)
1076 requeue(m_discard, m_queued);
1080 m_presentstep = PRESENT_FLIP;
1081 m_discard.push_back(m_presentsource);
1082 m_presentsource = idx;
1083 m_queued.pop_front();
1084 m_presentevent.notifyAll();
1088 void CXBMCRenderManager::DiscardBuffer()
1090 CSharedLock lock(m_sharedSection);
1091 CSingleLock lock2(m_presentlock);
1093 while(!m_queued.empty())
1094 requeue(m_discard, m_queued);
1096 if(m_presentstep == PRESENT_READY)
1097 m_presentstep = PRESENT_IDLE;
1098 m_presentevent.notifyAll();