PageRenderTime 76ms CodeModel.GetById 2ms app.highlight 64ms RepoModel.GetById 1ms app.codeStats 0ms

/xbmc/cores/VideoRenderers/RenderManager.cpp

http://github.com/xbmc/xbmc
C++ | 1095 lines | 855 code | 173 blank | 67 comment | 229 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
  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
  64template<class T>
  65class CRetakeLock
  66{
  67public:
  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
  84private:
  85  DWORD             m_count;
  86  T                 m_lock;
  87  CCriticalSection &m_owned;
  88};
  89
  90static void requeue(std::deque<int> &trg, std::deque<int> &src)
  91{
  92  trg.push_back(src.front());
  93  src.pop_front();
  94}
  95
  96CXBMCRenderManager::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
 116CXBMCRenderManager::~CXBMCRenderManager()
 117{
 118  delete m_pRenderer;
 119  m_pRenderer = NULL;
 120}
 121
 122void CXBMCRenderManager::GetVideoRect(CRect &source, CRect &dest)
 123{
 124  CSharedLock lock(m_sharedSection);
 125  if (m_pRenderer)
 126    m_pRenderer->GetVideoRect(source, dest);
 127}
 128
 129float 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() */
 139double CXBMCRenderManager::GetPresentTime()
 140{
 141  return CDVDClock::GetAbsoluteClock(false) / DVD_TIME_BASE;
 142}
 143
 144static 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
 157void 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
 223CStdString 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
 238bool 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
 313bool CXBMCRenderManager::RendererHandlesPresent() const
 314{
 315  return IsConfigured() && (m_firstFlipPage || m_format != RENDER_FMT_BYPASS);
 316}
 317
 318bool CXBMCRenderManager::IsConfigured() const
 319{
 320  if (!m_pRenderer)
 321    return false;
 322  return m_pRenderer->IsConfigured();
 323}
 324
 325void CXBMCRenderManager::Update()
 326{
 327  CRetakeLock<CExclusiveLock> lock(m_sharedSection);
 328
 329  if (m_pRenderer)
 330    m_pRenderer->Update();
 331}
 332
 333bool 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
 342void 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
 387void 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
 419unsigned 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
 450void 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
 464bool 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
 494void CXBMCRenderManager::SetupScreenshot()
 495{
 496  CSharedLock lock(m_sharedSection);
 497  if (m_pRenderer)
 498    m_pRenderer->SetupScreenshot();
 499}
 500
 501CRenderCapture* CXBMCRenderManager::AllocRenderCapture()
 502{
 503  return new CRenderCapture;
 504}
 505
 506void 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
 527void 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
 566void 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
 622void 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
 629void 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
 637void CXBMCRenderManager::SetViewMode(int iViewMode)
 638{
 639  CSharedLock lock(m_sharedSection);
 640  if (m_pRenderer)
 641    m_pRenderer->SetViewMode(iViewMode);
 642}
 643
 644void 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
 723void CXBMCRenderManager::Reset()
 724{
 725  CSharedLock lock(m_sharedSection);
 726  if (m_pRenderer)
 727    m_pRenderer->Reset();
 728}
 729
 730RESOLUTION 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
 739float 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
 754void CXBMCRenderManager::RegisterRenderUpdateCallBack(const void *ctx, RenderUpdateCallBackFn fn)
 755{
 756  if (m_pRenderer)
 757    m_pRenderer->RegisterRenderUpdateCallBack(ctx, fn);
 758}
 759
 760void CXBMCRenderManager::RegisterRenderFeaturesCallBack(const void *ctx, RenderFeaturesCallBackFn fn)
 761{
 762  if (m_pRenderer)
 763    m_pRenderer->RegisterRenderFeaturesCallBack(ctx, fn);
 764}
 765
 766void 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 */
 785void 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 */
 794void 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
 815void 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
 832void 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
 841void 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
 850void 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
 865unsigned 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
 872std::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
 880int 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
 951bool 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
 960bool 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
 969bool 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
 978bool 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
 987EINTERLACEMETHOD CXBMCRenderManager::AutoInterlaceMethod(EINTERLACEMETHOD mInt)
 988{
 989  CSharedLock lock(m_sharedSection);
 990  return AutoInterlaceMethodInternal(mInt);
 991}
 992
 993EINTERLACEMETHOD 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
1007int 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
1030void 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
1084void 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}