Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

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

…renderer
  • Loading branch information...
commit dbbb968dbd88ac6db47758442f4b2a95e02f5d68 1 parent 57ba0cb
@FernetMenta FernetMenta authored
View
5 xbmc/ApplicationMessenger.cpp
@@ -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;
View
1  xbmc/ApplicationMessenger.h
@@ -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
View
1  xbmc/cores/VideoRenderers/BaseRenderer.h
@@ -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; }
View
14 xbmc/cores/VideoRenderers/LinuxRendererGL.cpp
@@ -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;
View
1  xbmc/cores/VideoRenderers/LinuxRendererGL.h
@@ -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);
View
29 xbmc/cores/VideoRenderers/RenderManager.cpp
@@ -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);
View
2  xbmc/cores/VideoRenderers/RenderManager.h
@@ -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;
View
79 xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp
@@ -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,6 +399,11 @@ 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);
@@ -396,22 +411,53 @@ void CVDPAU::ReleasePixmap()
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;
}
View
22 xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.h
@@ -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
33 xbmc/guilib/DispResource.h
@@ -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
View
90 xbmc/windowing/X11/WinSystemX11.cpp
@@ -27,9 +27,18 @@
#include "WinSystemX11.h"
#include "settings/Settings.h"
#include "guilib/Texture.h"
+#include "guilib/DispResource.h"
#include "utils/log.h"
#include "XRandR.h"
#include <vector>
+#include "threads/SingleLock.h"
+#include <X11/Xlib.h>
+#include "cores/VideoRenderers/RenderManager.h"
+#include "utils/TimeUtils.h"
+
+#if defined(HAS_XRANDR)
+#include <X11/extensions/Xrandr.h>
+#endif
using namespace std;
@@ -42,6 +51,7 @@ CWinSystemX11::CWinSystemX11() : CWinSystemBase()
m_glWindow = 0;
m_wmWindow = 0;
m_bWasFullScreenBeforeMinimize = false;
+ m_dpyLostTime = 0;
}
CWinSystemX11::~CWinSystemX11()
@@ -126,6 +136,13 @@ bool CWinSystemX11::CreateNewWindow(const CStdString& name, bool fullScreen, RES
SDL_WM_SetIcon(SDL_CreateRGBSurfaceFrom(iconTexture.GetPixels(), iconTexture.GetWidth(), iconTexture.GetHeight(), 32, iconTexture.GetPitch(), 0xff0000, 0x00ff00, 0x0000ff, 0xff000000L), NULL);
SDL_WM_SetCaption("XBMC Media Center", NULL);
+ // register XRandR Events
+#if defined(HAS_XRANDR)
+ int iReturn;
+ XRRQueryExtension(m_dpy, &m_RREventBase, &iReturn);
+ XRRSelectInput(m_dpy, m_wmWindow, RRScreenChangeNotifyMask);
+#endif
+
m_bWindowCreated = true;
return true;
}
@@ -175,7 +192,10 @@ bool CWinSystemX11::SetFullScreen(bool fullScreen, RESOLUTION_INFO& res, bool bl
mode.id = res.strId;
if(m_bFullScreen)
+ {
+ OnLostDevice();
g_xrandr.SetMode(out, mode);
+ }
else
g_xrandr.RestoreState();
#endif
@@ -444,4 +464,74 @@ bool CWinSystemX11::Show(bool raise)
XSync(m_dpy, False);
return true;
}
+
+void CWinSystemX11::CheckDisplayEvents()
+{
+#if defined(HAS_XRANDR)
+ bool bGotEvent(false);
+ bool bTimeout(false);
+ XEvent Event;
+ while (XCheckTypedEvent(m_dpy, m_RREventBase + RRScreenChangeNotify, &Event))
+ {
+ if (Event.type == m_RREventBase + RRScreenChangeNotify)
+ {
+ CLog::Log(LOGDEBUG, "%s: Received RandR event %i", __FUNCTION__, Event.type);
+ bGotEvent = true;
+ }
+ XRRUpdateConfiguration(&Event);
+ }
+
+ // check fail safe timer
+ if (m_dpyLostTime && CurrentHostCounter() - m_dpyLostTime > (uint64_t)3 * CurrentHostFrequency())
+ {
+ CLog::Log(LOGERROR, "%s - no display event after 3 seconds", __FUNCTION__);
+ bTimeout = true;
+ }
+
+ if (bGotEvent || bTimeout)
+ {
+ CLog::Log(LOGDEBUG, "%s - notify display reset event", __FUNCTION__);
+
+ CSingleLock lock(m_resourceSection);
+
+ // tell any shared resources
+ for (vector<IDispResource *>::iterator i = m_resources.begin(); i != m_resources.end(); i++)
+ (*i)->OnResetDevice();
+
+ // reset fail safe timer
+ m_dpyLostTime = 0;
+ }
+#endif
+}
+
+void CWinSystemX11::OnLostDevice()
+{
+ CLog::Log(LOGDEBUG, "%s - notify display change event", __FUNCTION__);
+
+ { CSingleLock lock(m_resourceSection);
+ for (vector<IDispResource *>::iterator i = m_resources.begin(); i != m_resources.end(); i++)
+ (*i)->OnLostDevice();
+ }
+
+ // make sure renderer has no invalid references
+ g_renderManager.Flush();
+
+ // fail safe timer
+ m_dpyLostTime = CurrentHostCounter();
+}
+
+void CWinSystemX11::Register(IDispResource *resource)
+{
+ CSingleLock lock(m_resourceSection);
+ m_resources.push_back(resource);
+}
+
+void CWinSystemX11::Unregister(IDispResource* resource)
+{
+ CSingleLock lock(m_resourceSection);
+ vector<IDispResource*>::iterator i = find(m_resources.begin(), m_resources.end(), resource);
+ if (i != m_resources.end())
+ m_resources.erase(i);
+}
+
#endif
View
11 xbmc/windowing/X11/WinSystemX11.h
@@ -26,6 +26,9 @@
#include "windowing/WinSystem.h"
#include "utils/Stopwatch.h"
#include <GL/glx.h>
+#include "threads/CriticalSection.h"
+
+class IDispResource;
class CWinSystemX11 : public CWinSystemBase
{
@@ -51,6 +54,8 @@ class CWinSystemX11 : public CWinSystemBase
virtual bool Restore() ;
virtual bool Hide();
virtual bool Show(bool raise = true);
+ virtual void Register(IDispResource *resource);
+ virtual void Unregister(IDispResource *resource);
// Local to WinSystemX11 only
Display* GetDisplay() { return m_dpy; }
@@ -58,6 +63,8 @@ class CWinSystemX11 : public CWinSystemBase
protected:
bool RefreshGlxContext();
+ void CheckDisplayEvents();
+ void OnLostDevice();
SDL_Surface* m_SDLSurface;
GLXContext m_glContext;
@@ -65,6 +72,10 @@ class CWinSystemX11 : public CWinSystemBase
Window m_wmWindow;
Display* m_dpy;
bool m_bWasFullScreenBeforeMinimize;
+ int m_RREventBase;
+ CCriticalSection m_resourceSection;
+ std::vector<IDispResource*> m_resources;
+ uint64_t m_dpyLostTime;
private:
bool IsSuitableVisual(XVisualInfo *vInfo);
View
2  xbmc/windowing/X11/WinSystemX11GL.cpp
@@ -43,6 +43,8 @@ CWinSystemX11GL::~CWinSystemX11GL()
bool CWinSystemX11GL::PresentRenderImpl(const CDirtyRegionList& dirty)
{
+ CheckDisplayEvents();
+
if(m_iVSyncMode == 3)
{
glFinish();
Please sign in to comment.
Something went wrong with that request. Please try again.