Permalink
Browse files

vdpau: notify decoder when refresh rate is going to change and flush …

…renderer
  • Loading branch information...
FernetMenta committed Oct 8, 2011
1 parent 57ba0cb commit dbbb968dbd88ac6db47758442f4b2a95e02f5d68
@@ -43,6 +43,7 @@
#include "windowing/WindowingFactory.h"
#include "GUIInfoManager.h"
#include "utils/Splash.h"
+#include "cores/VideoRenderers/RenderManager.h"
#include "powermanagement/PowerManager.h"
@@ -232,6 +233,10 @@ void CApplicationMessenger::ProcessMessage(ThreadMessage *pMsg)
case POWERSTATE_MINIMIZE:
Minimize();
break;
+
+ case TMSG_RENDERER_FLUSH:
+ g_renderManager.Flush();
+ break;
}
}
break;
@@ -76,6 +76,7 @@ class CGUIWindow;
#define TMSG_MINIMIZE 309
#define TMSG_TOGGLEFULLSCREEN 310
#define TMSG_SETLANGUAGE 311
+#define TMSG_RENDERER_FLUSH 312
#define TMSG_HTTPAPI 400
@@ -64,6 +64,7 @@ class CBaseRenderer
float GetAspectRatio() const;
virtual bool AddVideoPicture(DVDVideoPicture* picture) { return false; }
+ virtual void Flush() {};
virtual unsigned int GetProcessorSize() { return 0; }
@@ -554,6 +554,20 @@ void CLinuxRendererGL::Reset()
}
}
+void CLinuxRendererGL::Flush()
+{
+ if (!m_bValidated)
+ return;
+
+ glFinish();
+
+ for (int i = 0 ; i < m_NumYV12Buffers ; i++)
+ (this->*m_textureDelete)(i);
+
+ glFinish();
+ m_bValidated = false;
+}
+
void CLinuxRendererGL::Update(bool bPauseDrawing)
{
if (!m_bConfigured) return;
@@ -140,6 +140,7 @@ class CLinuxRendererGL : public CBaseRenderer
virtual unsigned int PreInit();
virtual void UnInit();
virtual void Reset(); /* resets renderer after seek for example */
+ virtual void Flush();
#ifdef HAVE_LIBVDPAU
virtual void AddProcessor(CVDPAU* vdpau);
@@ -337,6 +337,35 @@ void CXBMCRenderManager::UnInit()
m_pRenderer->UnInit();
}
+bool CXBMCRenderManager::Flush()
+{
+ if (!m_pRenderer)
+ return true;
+
+ if (g_application.IsCurrentThread())
+ {
+ CLog::Log(LOGDEBUG, "%s - flushing renderer", __FUNCTION__);
+
+ CRetakeLock<CExclusiveLock> lock(m_sharedSection);
+ m_pRenderer->Flush();
+ m_flushEvent.Set();
+ }
+ else
+ {
+ ThreadMessage msg = {TMSG_RENDERER_FLUSH};
+ m_flushEvent.Reset();
+ g_application.getApplicationMessenger().SendMessage(msg, false);
+ if (!m_flushEvent.WaitMSec(1000))
+ {
+ CLog::Log(LOGERROR, "%s - timed out waiting for renderer to flush", __FUNCTION__);
+ return false;
+ }
+ else
+ return true;
+ }
+ return true;
+}
+
void CXBMCRenderManager::SetupScreenshot()
{
CSharedLock lock(m_sharedSection);
@@ -76,6 +76,7 @@ class CXBMCRenderManager
void FlipPage(volatile bool& bStop, double timestamp = 0.0, int source = -1, EFIELDSYNC sync = FS_NONE);
unsigned int PreInit();
void UnInit();
+ bool Flush();
void AddOverlay(CDVDOverlay* o, double pts)
{
@@ -227,6 +228,7 @@ class CXBMCRenderManager
EPRESENTSTEP m_presentstep;
int m_presentsource;
CEvent m_presentevent;
+ CEvent m_flushEvent;
OVERLAY::CRenderer m_overlays;
@@ -95,6 +95,7 @@ CVDPAU::CVDPAU()
recover = false;
m_mixerfield = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME;
m_mixerstep = 0;
+ m_DisplayState = VDPAU_OPEN;
m_glPixmap = 0;
m_Pixmap = 0;
@@ -191,6 +192,8 @@ bool CVDPAU::Open(AVCodecContext* avctx, const enum PixelFormat, unsigned int su
avctx->release_buffer = CVDPAU::FFReleaseBuffer;
avctx->draw_horiz_band = CVDPAU::FFDrawSlice;
avctx->slice_flags=SLICE_FLAG_CODED_ORDER|SLICE_FLAG_ALLOW_FIELD;
+
+ g_Windowing.Register(this);
return true;
}
return false;
@@ -208,6 +211,8 @@ void CVDPAU::Close()
FiniVDPAUOutput();
FiniVDPAUProcs();
+ g_Windowing.Unregister(this);
+
if (m_glPixmap)
{
CLog::Log(LOGINFO, "GLX: Destroying glPixmap");
@@ -363,6 +368,11 @@ bool CVDPAU::MakePixmap(int width, int height)
void CVDPAU::BindPixmap()
{
+ { CSingleLock lock(m_DisplaySection);
+ if (m_DisplayState != VDPAU_OPEN)
+ return;
+ }
+
if (m_glPixmap)
{
if(presentSurface != VDP_INVALID_HANDLE)
@@ -389,29 +399,65 @@ void CVDPAU::BindPixmap()
void CVDPAU::ReleasePixmap()
{
+ { CSingleLock lock(m_DisplaySection);
+ if (m_DisplayState != VDPAU_OPEN)
+ return;
+ }
+
if (m_glPixmap)
{
glXReleaseTexImageEXT(m_Display, m_glPixmap, GLX_FRONT_LEFT_EXT);
}
else CLog::Log(LOGERROR,"(VDPAU) ReleasePixmap called without valid pixmap");
}
-bool CVDPAU::CheckRecover(bool force)
+void CVDPAU::OnLostDevice()
+{
+ CSingleLock lock(m_DisplaySection);
+ m_DisplayState = VDPAU_LOST;
+ m_DisplayEvent.Reset();
+}
+
+void CVDPAU::OnResetDevice()
+{
+ CSingleLock lock(m_DisplaySection);
+
+ if (m_DisplayState == VDPAU_LOST)
+ {
+ m_DisplayState = VDPAU_RESET;
+ m_DisplayEvent.Set();
+ }
+}
+
+int CVDPAU::Check(AVCodecContext* avctx)
{
- if (recover || force)
+ CSingleLock lock(m_DisplaySection);
+
+ if (m_DisplayState == VDPAU_LOST)
+ {
+ lock.Leave();
+ if (!m_DisplayEvent.WaitMSec(2000))
+ {
+ CLog::Log(LOGERROR, "CVDPAU::Check - device didn't reset in reasonable time");
+ return VC_ERROR;
+ }
+ lock.Enter();
+ }
+ if (recover || m_DisplayState == VDPAU_RESET)
{
CLog::Log(LOGNOTICE,"Attempting recovery");
FiniVDPAUOutput();
FiniVDPAUProcs();
- recover = false;
-
InitVDPAUProcs();
- return true;
+ recover = false;
+ m_DisplayState = VDPAU_OPEN;
+
+ return VC_FLUSHED;
}
- return false;
+ return 0;
}
bool CVDPAU::IsVDPAUFormat(PixelFormat format)
@@ -750,6 +796,9 @@ void CVDPAU::InitVDPAUProcs()
&VDPPreemptionCallbackFunction,
(void*)this);
CheckStatus(vdp_st, __LINE__);
+
+ CSingleLock lock(m_DisplaySection);
+ m_DisplayState = VDPAU_OPEN;
}
void CVDPAU::FiniVDPAUProcs()
@@ -1132,8 +1181,9 @@ int CVDPAU::Decode(AVCodecContext *avctx, AVFrame *pFrame)
VdpStatus vdp_st;
VdpTime time;
- if (CheckRecover(false))
- return VC_FLUSHED;
+ int result = Check(avctx);
+ if (result)
+ return result;
if (!vdpauConfigured)
return VC_ERROR;
@@ -1318,6 +1368,11 @@ int CVDPAU::Decode(AVCodecContext *avctx, AVFrame *pFrame)
bool CVDPAU::GetPicture(AVCodecContext* avctx, AVFrame* frame, DVDVideoPicture* picture)
{
+ { CSingleLock lock(m_DisplaySection);
+ if (m_DisplayState != VDPAU_OPEN)
+ return false;
+ }
+
*picture = m_DVDVideoPics.front();
// if this is the first field of an interlaced frame, we'll need
// this same picture for the second field later
@@ -1358,6 +1413,12 @@ void CVDPAU::Present()
{
//CLog::Log(LOGNOTICE,"%s",__FUNCTION__);
VdpStatus vdp_st;
+
+ { CSingleLock lock(m_DisplaySection);
+ if (m_DisplayState != VDPAU_OPEN)
+ return;
+ }
+
presentSurface = outputSurface;
vdp_st = vdp_presentation_queue_display(vdp_flip_queue,
@@ -1370,7 +1431,7 @@ void CVDPAU::Present()
void CVDPAU::VDPPreemptionCallbackFunction(VdpDevice device, void* context)
{
- CLog::Log(LOGERROR,"VDPAU Device Preempted - attempting recovery");
+ CLog::Log(LOGDEBUG,"VDPAU Device Preempted - attempting recovery");
CVDPAU* pCtx = (CVDPAU*)context;
pCtx->recover = true;
}
@@ -33,6 +33,8 @@
#include <queue>
#include "threads/CriticalSection.h"
#include "settings/VideoSettings.h"
+#include "guilib/DispResource.h"
+#include "threads/Event.h"
namespace Surface { class CSurface; }
#define NUM_OUTPUT_SURFACES 4
@@ -44,6 +46,7 @@ namespace Surface { class CSurface; }
class CVDPAU
: public CDVDVideoCodecFFmpeg::IHardwareDecoder
+ , public IDispResource
{
public:
@@ -69,13 +72,8 @@ class CVDPAU
virtual void Reset();
virtual void Close();
- virtual int Check(AVCodecContext* avctx)
- {
- if(CheckRecover(false))
- return VC_FLUSHED;
- else
- return 0;
- }
+ virtual int Check(AVCodecContext* avctx);
+
virtual const std::string Name() { return "vdpau"; }
bool MakePixmap(int width, int height);
@@ -227,4 +225,14 @@ class CVDPAU
, VdpChromaType &chroma_type);
std::vector<vdpau_render_state*> m_videoSurfaces;
+
+ enum EDisplayState
+ { VDPAU_OPEN
+ , VDPAU_RESET
+ , VDPAU_LOST
+ } m_DisplayState;
+ CCriticalSection m_DisplaySection;
+ CEvent m_DisplayEvent;
+ virtual void OnLostDevice();
+ virtual void OnResetDevice();
};
View
@@ -0,0 +1,33 @@
+/*
+* Copyright (C) 2005-2008 Team XBMC
+* http://www.xbmc.org
+*
+* This Program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation; either version 2, or (at your option)
+* any later version.
+*
+* This Program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with XBMC; see the file COPYING. If not, write to
+* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+* http://www.gnu.org/copyleft/gpl.html
+*
+*/
+
+#pragma once
+
+#ifdef HAS_GLX
+class IDispResource
+{
+public:
+ virtual ~IDispResource() {};
+ virtual void OnLostDevice() {};
+ virtual void OnResetDevice() {};
+};
+
+#endif
Oops, something went wrong.

0 comments on commit dbbb968

Please sign in to comment.