Plumb the ability to disable V-sync through the video renderers

This commit is contained in:
Cameron Gutman
2018-08-20 18:19:42 -07:00
parent 6b395c816f
commit f7d3c10c9d
18 changed files with 90 additions and 49 deletions
+4 -3
View File
@@ -106,7 +106,7 @@ void Session::clLogMessage(const char* format, ...)
bool Session::chooseDecoder(StreamingPreferences::VideoDecoderSelection vds, bool Session::chooseDecoder(StreamingPreferences::VideoDecoderSelection vds,
SDL_Window* window, int videoFormat, int width, int height, SDL_Window* window, int videoFormat, int width, int height,
int frameRate, IVideoDecoder*& chosenDecoder) int frameRate, bool enableVsync, IVideoDecoder*& chosenDecoder)
{ {
#ifdef HAVE_SLVIDEO #ifdef HAVE_SLVIDEO
chosenDecoder = new SLVideoDecoder(); chosenDecoder = new SLVideoDecoder();
@@ -125,7 +125,7 @@ bool Session::chooseDecoder(StreamingPreferences::VideoDecoderSelection vds,
#ifdef HAVE_FFMPEG #ifdef HAVE_FFMPEG
chosenDecoder = new FFmpegVideoDecoder(); chosenDecoder = new FFmpegVideoDecoder();
if (chosenDecoder->initialize(vds, window, videoFormat, width, height, frameRate)) { if (chosenDecoder->initialize(vds, window, videoFormat, width, height, frameRate, enableVsync)) {
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
"FFmpeg-based video decoder chosen"); "FFmpeg-based video decoder chosen");
return true; return true;
@@ -212,7 +212,7 @@ bool Session::isHardwareDecodeAvailable(StreamingPreferences::VideoDecoderSelect
return false; return false;
} }
if (!chooseDecoder(vds, window, videoFormat, width, height, frameRate, decoder)) { if (!chooseDecoder(vds, window, videoFormat, width, height, frameRate, true, decoder)) {
SDL_DestroyWindow(window); SDL_DestroyWindow(window);
SDL_QuitSubSystem(SDL_INIT_VIDEO); SDL_QuitSubSystem(SDL_INIT_VIDEO);
return false; return false;
@@ -823,6 +823,7 @@ void Session::exec()
if (!chooseDecoder(m_Preferences.videoDecoderSelection, if (!chooseDecoder(m_Preferences.videoDecoderSelection,
m_Window, m_ActiveVideoFormat, m_ActiveVideoWidth, m_Window, m_ActiveVideoFormat, m_ActiveVideoWidth,
m_ActiveVideoHeight, m_ActiveVideoFrameRate, m_ActiveVideoHeight, m_ActiveVideoFrameRate,
true, // TODO: User configuration for V-sync
s_ActiveSession->m_VideoDecoder)) { s_ActiveSession->m_VideoDecoder)) {
SDL_AtomicUnlock(&m_DecoderLock); SDL_AtomicUnlock(&m_DecoderLock);
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
+1 -1
View File
@@ -54,7 +54,7 @@ private:
static static
bool chooseDecoder(StreamingPreferences::VideoDecoderSelection vds, bool chooseDecoder(StreamingPreferences::VideoDecoderSelection vds,
SDL_Window* window, int videoFormat, int width, int height, SDL_Window* window, int videoFormat, int width, int height,
int frameRate, IVideoDecoder*& chosenDecoder); int frameRate, bool enableVsync, IVideoDecoder*& chosenDecoder);
static static
void clStageStarting(int stage); void clStageStarting(int stage);
+2 -1
View File
@@ -16,7 +16,8 @@ public:
int videoFormat, int videoFormat,
int width, int width,
int height, int height,
int frameRate) = 0; int frameRate,
bool enableVsync) = 0;
virtual bool isHardwareAccelerated() = 0; virtual bool isHardwareAccelerated() = 0;
virtual int submitDecodeUnit(PDECODE_UNIT du) = 0; virtual int submitDecodeUnit(PDECODE_UNIT du) = 0;
virtual void renderFrame(SDL_UserEvent* event) = 0; virtual void renderFrame(SDL_UserEvent* event) = 0;
+14 -5
View File
@@ -428,7 +428,7 @@ bool DXVA2Renderer::isDecoderBlacklisted()
return result; return result;
} }
bool DXVA2Renderer::initializeDevice(SDL_Window* window) bool DXVA2Renderer::initializeDevice(SDL_Window* window, bool enableVsync)
{ {
SDL_SysWMinfo info; SDL_SysWMinfo info;
@@ -487,13 +487,22 @@ bool DXVA2Renderer::initializeDevice(SDL_Window* window)
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
"Windowed mode with DWM running"); "Windowed mode with DWM running");
} }
else { else if (enableVsync) {
// Uncomposited desktop or full-screen exclusive mode // Uncomposited desktop or full-screen exclusive mode with V-sync enabled
// We will enable V-sync in this scenario to avoid tearing.
d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_ONE; d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_ONE;
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
"V-Sync enabled"); "V-Sync enabled");
} }
else {
// Uncomposited desktop or full-screen exclusive mode with V-sync disabled
// We will allowing tearing for lowest latency.
d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
"V-Sync disabled in tearing mode");
}
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
"Windowed: %d | Present Interval: %x", "Windowed: %d | Present Interval: %x",
@@ -540,7 +549,7 @@ bool DXVA2Renderer::initializeDevice(SDL_Window* window)
return true; return true;
} }
bool DXVA2Renderer::initialize(SDL_Window* window, int videoFormat, int width, int height, int) bool DXVA2Renderer::initialize(SDL_Window* window, int videoFormat, int width, int height, int, bool enableVsync)
{ {
m_VideoFormat = videoFormat; m_VideoFormat = videoFormat;
m_VideoWidth = width; m_VideoWidth = width;
@@ -569,7 +578,7 @@ bool DXVA2Renderer::initialize(SDL_Window* window, int videoFormat, int width, i
m_Desc.SampleFormat.SampleFormat = DXVA2_SampleProgressiveFrame; m_Desc.SampleFormat.SampleFormat = DXVA2_SampleProgressiveFrame;
m_Desc.Format = (D3DFORMAT)MAKEFOURCC('N','V','1','2'); m_Desc.Format = (D3DFORMAT)MAKEFOURCC('N','V','1','2');
if (!initializeDevice(window)) { if (!initializeDevice(window, enableVsync)) {
return false; return false;
} }
+3 -2
View File
@@ -19,7 +19,8 @@ public:
int videoFormat, int videoFormat,
int width, int width,
int height, int height,
int maxFps); int maxFps,
bool enableVsync);
virtual bool prepareDecoderContext(AVCodecContext* context); virtual bool prepareDecoderContext(AVCodecContext* context);
virtual void renderFrameAtVsync(AVFrame* frame); virtual void renderFrameAtVsync(AVFrame* frame);
virtual bool needsTestFrame(); virtual bool needsTestFrame();
@@ -27,7 +28,7 @@ public:
private: private:
bool initializeDecoder(); bool initializeDecoder();
bool initializeRenderer(); bool initializeRenderer();
bool initializeDevice(SDL_Window* window); bool initializeDevice(SDL_Window* window, bool enableVsync);
bool isDecoderBlacklisted(); bool isDecoderBlacklisted();
static static
@@ -116,9 +116,10 @@ RenderNextFrame:
av_frame_free(&frame); av_frame_free(&frame);
} }
bool Pacer::initialize(SDL_Window* window, int maxVideoFps) bool Pacer::initialize(SDL_Window* window, int maxVideoFps, bool enableVsync)
{ {
m_MaxVideoFps = maxVideoFps; m_MaxVideoFps = maxVideoFps;
m_EnableVsync = enableVsync;
int displayIndex = SDL_GetWindowDisplayIndex(window); int displayIndex = SDL_GetWindowDisplayIndex(window);
if (displayIndex < 0) { if (displayIndex < 0) {
@@ -136,21 +137,28 @@ bool Pacer::initialize(SDL_Window* window, int maxVideoFps)
m_DisplayFps = mode.refresh_rate; m_DisplayFps = mode.refresh_rate;
} }
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, if (m_EnableVsync) {
"Frame pacing: target %d Hz with %d FPS stream", SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
m_DisplayFps, m_MaxVideoFps); "Frame pacing in tear-free mode: target %d Hz with %d FPS stream",
m_DisplayFps, m_MaxVideoFps);
#if defined(Q_OS_DARWIN) #if defined(Q_OS_DARWIN)
m_VsyncSource = new DisplayLinkVsyncSource(this); m_VsyncSource = new DisplayLinkVsyncSource(this);
#elif defined(Q_OS_WIN32) #elif defined(Q_OS_WIN32)
m_VsyncSource = new DxVsyncSource(this); m_VsyncSource = new DxVsyncSource(this);
#else #else
// Platforms without a VsyncSource will just render frames // Platforms without a VsyncSource will just render frames
// immediately like they used to. // immediately like they used to.
#endif #endif
if (m_VsyncSource != nullptr && !m_VsyncSource->initialize(window, m_DisplayFps)) { if (m_VsyncSource != nullptr && !m_VsyncSource->initialize(window, m_DisplayFps)) {
return false; return false;
}
}
else {
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
"Minimal latency tearing mode: target %d Hz with %d FPS stream",
m_DisplayFps, m_MaxVideoFps);
} }
return true; return true;
@@ -19,7 +19,7 @@ public:
void submitFrame(AVFrame* frame); void submitFrame(AVFrame* frame);
bool initialize(SDL_Window* window, int maxVideoFps); bool initialize(SDL_Window* window, int maxVideoFps, bool enableVsync);
void vsyncCallback(int timeUntilNextVsyncMillis); void vsyncCallback(int timeUntilNextVsyncMillis);
@@ -34,4 +34,5 @@ private:
IFFmpegRenderer* m_VsyncRenderer; IFFmpegRenderer* m_VsyncRenderer;
int m_MaxVideoFps; int m_MaxVideoFps;
int m_DisplayFps; int m_DisplayFps;
bool m_EnableVsync;
}; };
@@ -13,7 +13,8 @@ public:
int videoFormat, int videoFormat,
int width, int width,
int height, int height,
int maxFps) = 0; int maxFps,
bool enableVsync) = 0;
virtual bool prepareDecoderContext(AVCodecContext* context) = 0; virtual bool prepareDecoderContext(AVCodecContext* context) = 0;
virtual void renderFrameAtVsync(AVFrame* frame) = 0; virtual void renderFrameAtVsync(AVFrame* frame) = 0;
virtual bool needsTestFrame() = 0; virtual bool needsTestFrame() = 0;
@@ -27,7 +28,8 @@ public:
int videoFormat, int videoFormat,
int width, int width,
int height, int height,
int maxFps); int maxFps,
bool enableVsync);
virtual bool prepareDecoderContext(AVCodecContext* context); virtual bool prepareDecoderContext(AVCodecContext* context);
virtual void renderFrameAtVsync(AVFrame* frame); virtual void renderFrameAtVsync(AVFrame* frame);
virtual bool needsTestFrame(); virtual bool needsTestFrame();
+14 -2
View File
@@ -40,9 +40,21 @@ bool SdlRenderer::initialize(SDL_Window* window,
int, int,
int width, int width,
int height, int height,
int) int,
bool enableVsync)
{ {
m_Renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED); Uint32 rendererFlags = SDL_RENDERER_ACCELERATED;
if ((SDL_GetWindowFlags(window) & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN) {
// In full-screen exclusive mode, we enable V-sync if requested. For other modes, Windows and Mac
// have compositors that make rendering tear-free. Linux compositor varies by distro and user
// configuration but doesn't seem feasible to detect here.
if (enableVsync) {
rendererFlags |= SDL_RENDERER_PRESENTVSYNC;
}
}
m_Renderer = SDL_CreateRenderer(window, -1, rendererFlags);
if (!m_Renderer) { if (!m_Renderer) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
"SDL_CreateRenderer() failed: %s", "SDL_CreateRenderer() failed: %s",
@@ -27,7 +27,7 @@ VAAPIRenderer::~VAAPIRenderer()
} }
bool bool
VAAPIRenderer::initialize(SDL_Window* window, int, int width, int height, int) VAAPIRenderer::initialize(SDL_Window* window, int, int width, int height, int, bool)
{ {
int err; int err;
SDL_SysWMinfo info; SDL_SysWMinfo info;
+2 -1
View File
@@ -34,7 +34,8 @@ public:
int videoFormat, int videoFormat,
int width, int width,
int height, int height,
int maxFps); int maxFps,
bool enableVsync);
virtual bool prepareDecoderContext(AVCodecContext* context); virtual bool prepareDecoderContext(AVCodecContext* context);
virtual void renderFrameAtVsync(AVFrame* frame); virtual void renderFrameAtVsync(AVFrame* frame);
virtual bool needsTestFrame(); virtual bool needsTestFrame();
@@ -54,7 +54,7 @@ VDPAURenderer::~VDPAURenderer()
} }
} }
bool VDPAURenderer::initialize(SDL_Window* window, int, int width, int height, int) bool VDPAURenderer::initialize(SDL_Window* window, int, int width, int height, int, bool)
{ {
int err; int err;
VdpStatus status; VdpStatus status;
+2 -1
View File
@@ -17,7 +17,8 @@ public:
int videoFormat, int videoFormat,
int width, int width,
int height, int height,
int maxFps); int maxFps,
bool enableVsync);
virtual bool prepareDecoderContext(AVCodecContext* context); virtual bool prepareDecoderContext(AVCodecContext* context);
virtual void renderFrameAtVsync(AVFrame* frame); virtual void renderFrameAtVsync(AVFrame* frame);
virtual bool needsTestFrame(); virtual bool needsTestFrame();
+2 -1
View File
@@ -101,7 +101,8 @@ public:
int videoFormat, int videoFormat,
int, int,
int, int,
int) override int,
bool) override
{ {
int err; int err;
+10 -9
View File
@@ -108,10 +108,10 @@ void FFmpegVideoDecoder::reset()
bool FFmpegVideoDecoder::completeInitialization(AVCodec* decoder, SDL_Window* window, bool FFmpegVideoDecoder::completeInitialization(AVCodec* decoder, SDL_Window* window,
int videoFormat, int width, int height, int videoFormat, int width, int height,
int maxFps, bool testOnly) int maxFps, bool enableVsync, bool testOnly)
{ {
m_Pacer = new Pacer(m_Renderer); m_Pacer = new Pacer(m_Renderer);
if (!m_Pacer->initialize(window, maxFps)) { if (!m_Pacer->initialize(window, maxFps, enableVsync)) {
return false; return false;
} }
@@ -229,7 +229,8 @@ bool FFmpegVideoDecoder::initialize(
int videoFormat, int videoFormat,
int width, int width,
int height, int height,
int maxFps) int maxFps,
bool enableVsync)
{ {
AVCodec* decoder; AVCodec* decoder;
@@ -264,8 +265,8 @@ bool FFmpegVideoDecoder::initialize(
m_HwDecodeCfg = nullptr; m_HwDecodeCfg = nullptr;
m_Renderer = new SdlRenderer(); m_Renderer = new SdlRenderer();
if (vds != StreamingPreferences::VDS_FORCE_HARDWARE && if (vds != StreamingPreferences::VDS_FORCE_HARDWARE &&
m_Renderer->initialize(window, videoFormat, width, height, maxFps) && m_Renderer->initialize(window, videoFormat, width, height, maxFps, enableVsync) &&
completeInitialization(decoder, window, videoFormat, width, height, maxFps, false)) { completeInitialization(decoder, window, videoFormat, width, height, maxFps, enableVsync, false)) {
return true; return true;
} }
else { else {
@@ -281,14 +282,14 @@ bool FFmpegVideoDecoder::initialize(
m_HwDecodeCfg = config; m_HwDecodeCfg = config;
// Initialize the hardware codec and submit a test frame if the renderer needs it // Initialize the hardware codec and submit a test frame if the renderer needs it
if (m_Renderer->initialize(window, videoFormat, width, height, maxFps) && if (m_Renderer->initialize(window, videoFormat, width, height, maxFps, enableVsync) &&
completeInitialization(decoder, window, videoFormat, width, height, maxFps, m_Renderer->needsTestFrame())) { completeInitialization(decoder, window, videoFormat, width, height, maxFps, enableVsync, m_Renderer->needsTestFrame())) {
if (m_Renderer->needsTestFrame()) { if (m_Renderer->needsTestFrame()) {
// The test worked, so now let's initialize it for real // The test worked, so now let's initialize it for real
reset(); reset();
if ((m_Renderer = createAcceleratedRenderer(config)) != nullptr && if ((m_Renderer = createAcceleratedRenderer(config)) != nullptr &&
m_Renderer->initialize(window, videoFormat, width, height, maxFps) && m_Renderer->initialize(window, videoFormat, width, height, maxFps, enableVsync) &&
completeInitialization(decoder, window, videoFormat, width, height, maxFps, false)) { completeInitialization(decoder, window, videoFormat, width, height, maxFps, enableVsync, false)) {
return true; return true;
} }
else { else {
+3 -2
View File
@@ -17,7 +17,8 @@ public:
int videoFormat, int videoFormat,
int width, int width,
int height, int height,
int maxFps) override; int maxFps,
bool enableVsync) override;
virtual bool isHardwareAccelerated() override; virtual bool isHardwareAccelerated() override;
virtual int submitDecodeUnit(PDECODE_UNIT du) override; virtual int submitDecodeUnit(PDECODE_UNIT du) override;
virtual void renderFrame(SDL_UserEvent* event) override; virtual void renderFrame(SDL_UserEvent* event) override;
@@ -28,7 +29,7 @@ public:
private: private:
bool completeInitialization(AVCodec* decoder, SDL_Window* window, bool completeInitialization(AVCodec* decoder, SDL_Window* window,
int videoFormat, int width, int height, int videoFormat, int width, int height,
int maxFps, bool testOnly); int maxFps, bool enableVsync, bool testOnly);
IFFmpegRenderer* createAcceleratedRenderer(const AVCodecHWConfig* hwDecodeCfg); IFFmpegRenderer* createAcceleratedRenderer(const AVCodecHWConfig* hwDecodeCfg);
+1 -1
View File
@@ -28,7 +28,7 @@ SLVideoDecoder::isHardwareAccelerated()
bool bool
SLVideoDecoder::initialize(StreamingPreferences::VideoDecoderSelection vds, SLVideoDecoder::initialize(StreamingPreferences::VideoDecoderSelection vds,
SDL_Window*, SDL_Window*,
int videoFormat, int, int, int frameRate) int videoFormat, int, int, int frameRate, bool)
{ {
// SLVideo only supports hardware decoding // SLVideo only supports hardware decoding
if (vds == StreamingPreferences::VDS_FORCE_SOFTWARE) { if (vds == StreamingPreferences::VDS_FORCE_SOFTWARE) {
+2 -1
View File
@@ -14,7 +14,8 @@ public:
int videoFormat, int videoFormat,
int width, int width,
int height, int height,
int frameRate); int frameRate,
bool enableVsync);
virtual bool isHardwareAccelerated(); virtual bool isHardwareAccelerated();
virtual int submitDecodeUnit(PDECODE_UNIT du); virtual int submitDecodeUnit(PDECODE_UNIT du);