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

View File

@ -106,7 +106,7 @@ void Session::clLogMessage(const char* format, ...)
bool Session::chooseDecoder(StreamingPreferences::VideoDecoderSelection vds,
SDL_Window* window, int videoFormat, int width, int height,
int frameRate, IVideoDecoder*& chosenDecoder)
int frameRate, bool enableVsync, IVideoDecoder*& chosenDecoder)
{
#ifdef HAVE_SLVIDEO
chosenDecoder = new SLVideoDecoder();
@ -125,7 +125,7 @@ bool Session::chooseDecoder(StreamingPreferences::VideoDecoderSelection vds,
#ifdef HAVE_FFMPEG
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,
"FFmpeg-based video decoder chosen");
return true;
@ -212,7 +212,7 @@ bool Session::isHardwareDecodeAvailable(StreamingPreferences::VideoDecoderSelect
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_QuitSubSystem(SDL_INIT_VIDEO);
return false;
@ -823,6 +823,7 @@ void Session::exec()
if (!chooseDecoder(m_Preferences.videoDecoderSelection,
m_Window, m_ActiveVideoFormat, m_ActiveVideoWidth,
m_ActiveVideoHeight, m_ActiveVideoFrameRate,
true, // TODO: User configuration for V-sync
s_ActiveSession->m_VideoDecoder)) {
SDL_AtomicUnlock(&m_DecoderLock);
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,

View File

@ -54,7 +54,7 @@ private:
static
bool chooseDecoder(StreamingPreferences::VideoDecoderSelection vds,
SDL_Window* window, int videoFormat, int width, int height,
int frameRate, IVideoDecoder*& chosenDecoder);
int frameRate, bool enableVsync, IVideoDecoder*& chosenDecoder);
static
void clStageStarting(int stage);

View File

@ -16,7 +16,8 @@ public:
int videoFormat,
int width,
int height,
int frameRate) = 0;
int frameRate,
bool enableVsync) = 0;
virtual bool isHardwareAccelerated() = 0;
virtual int submitDecodeUnit(PDECODE_UNIT du) = 0;
virtual void renderFrame(SDL_UserEvent* event) = 0;

View File

@ -428,7 +428,7 @@ bool DXVA2Renderer::isDecoderBlacklisted()
return result;
}
bool DXVA2Renderer::initializeDevice(SDL_Window* window)
bool DXVA2Renderer::initializeDevice(SDL_Window* window, bool enableVsync)
{
SDL_SysWMinfo info;
@ -487,13 +487,22 @@ bool DXVA2Renderer::initializeDevice(SDL_Window* window)
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
"Windowed mode with DWM running");
}
else {
// Uncomposited desktop or full-screen exclusive mode
else if (enableVsync) {
// 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;
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
"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,
"Windowed: %d | Present Interval: %x",
@ -540,7 +549,7 @@ bool DXVA2Renderer::initializeDevice(SDL_Window* window)
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_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.Format = (D3DFORMAT)MAKEFOURCC('N','V','1','2');
if (!initializeDevice(window)) {
if (!initializeDevice(window, enableVsync)) {
return false;
}

View File

@ -19,7 +19,8 @@ public:
int videoFormat,
int width,
int height,
int maxFps);
int maxFps,
bool enableVsync);
virtual bool prepareDecoderContext(AVCodecContext* context);
virtual void renderFrameAtVsync(AVFrame* frame);
virtual bool needsTestFrame();
@ -27,7 +28,7 @@ public:
private:
bool initializeDecoder();
bool initializeRenderer();
bool initializeDevice(SDL_Window* window);
bool initializeDevice(SDL_Window* window, bool enableVsync);
bool isDecoderBlacklisted();
static

View File

@ -116,9 +116,10 @@ RenderNextFrame:
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_EnableVsync = enableVsync;
int displayIndex = SDL_GetWindowDisplayIndex(window);
if (displayIndex < 0) {
@ -136,21 +137,28 @@ bool Pacer::initialize(SDL_Window* window, int maxVideoFps)
m_DisplayFps = mode.refresh_rate;
}
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
"Frame pacing: target %d Hz with %d FPS stream",
m_DisplayFps, m_MaxVideoFps);
if (m_EnableVsync) {
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
"Frame pacing in tear-free mode: target %d Hz with %d FPS stream",
m_DisplayFps, m_MaxVideoFps);
#if defined(Q_OS_DARWIN)
m_VsyncSource = new DisplayLinkVsyncSource(this);
#elif defined(Q_OS_WIN32)
m_VsyncSource = new DxVsyncSource(this);
#else
// Platforms without a VsyncSource will just render frames
// immediately like they used to.
#endif
#if defined(Q_OS_DARWIN)
m_VsyncSource = new DisplayLinkVsyncSource(this);
#elif defined(Q_OS_WIN32)
m_VsyncSource = new DxVsyncSource(this);
#else
// Platforms without a VsyncSource will just render frames
// immediately like they used to.
#endif
if (m_VsyncSource != nullptr && !m_VsyncSource->initialize(window, m_DisplayFps)) {
return false;
if (m_VsyncSource != nullptr && !m_VsyncSource->initialize(window, m_DisplayFps)) {
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;

View File

@ -19,7 +19,7 @@ public:
void submitFrame(AVFrame* frame);
bool initialize(SDL_Window* window, int maxVideoFps);
bool initialize(SDL_Window* window, int maxVideoFps, bool enableVsync);
void vsyncCallback(int timeUntilNextVsyncMillis);
@ -34,4 +34,5 @@ private:
IFFmpegRenderer* m_VsyncRenderer;
int m_MaxVideoFps;
int m_DisplayFps;
bool m_EnableVsync;
};

View File

@ -13,7 +13,8 @@ public:
int videoFormat,
int width,
int height,
int maxFps) = 0;
int maxFps,
bool enableVsync) = 0;
virtual bool prepareDecoderContext(AVCodecContext* context) = 0;
virtual void renderFrameAtVsync(AVFrame* frame) = 0;
virtual bool needsTestFrame() = 0;
@ -27,7 +28,8 @@ public:
int videoFormat,
int width,
int height,
int maxFps);
int maxFps,
bool enableVsync);
virtual bool prepareDecoderContext(AVCodecContext* context);
virtual void renderFrameAtVsync(AVFrame* frame);
virtual bool needsTestFrame();

View File

@ -40,9 +40,21 @@ bool SdlRenderer::initialize(SDL_Window* window,
int,
int width,
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) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
"SDL_CreateRenderer() failed: %s",

View File

@ -27,7 +27,7 @@ VAAPIRenderer::~VAAPIRenderer()
}
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;
SDL_SysWMinfo info;

View File

@ -34,7 +34,8 @@ public:
int videoFormat,
int width,
int height,
int maxFps);
int maxFps,
bool enableVsync);
virtual bool prepareDecoderContext(AVCodecContext* context);
virtual void renderFrameAtVsync(AVFrame* frame);
virtual bool needsTestFrame();

View File

@ -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;
VdpStatus status;

View File

@ -17,7 +17,8 @@ public:
int videoFormat,
int width,
int height,
int maxFps);
int maxFps,
bool enableVsync);
virtual bool prepareDecoderContext(AVCodecContext* context);
virtual void renderFrameAtVsync(AVFrame* frame);
virtual bool needsTestFrame();

View File

@ -101,7 +101,8 @@ public:
int videoFormat,
int,
int,
int) override
int,
bool) override
{
int err;

View File

@ -108,10 +108,10 @@ void FFmpegVideoDecoder::reset()
bool FFmpegVideoDecoder::completeInitialization(AVCodec* decoder, SDL_Window* window,
int videoFormat, int width, int height,
int maxFps, bool testOnly)
int maxFps, bool enableVsync, bool testOnly)
{
m_Pacer = new Pacer(m_Renderer);
if (!m_Pacer->initialize(window, maxFps)) {
if (!m_Pacer->initialize(window, maxFps, enableVsync)) {
return false;
}
@ -229,7 +229,8 @@ bool FFmpegVideoDecoder::initialize(
int videoFormat,
int width,
int height,
int maxFps)
int maxFps,
bool enableVsync)
{
AVCodec* decoder;
@ -264,8 +265,8 @@ bool FFmpegVideoDecoder::initialize(
m_HwDecodeCfg = nullptr;
m_Renderer = new SdlRenderer();
if (vds != StreamingPreferences::VDS_FORCE_HARDWARE &&
m_Renderer->initialize(window, videoFormat, width, height, maxFps) &&
completeInitialization(decoder, window, videoFormat, width, height, maxFps, false)) {
m_Renderer->initialize(window, videoFormat, width, height, maxFps, enableVsync) &&
completeInitialization(decoder, window, videoFormat, width, height, maxFps, enableVsync, false)) {
return true;
}
else {
@ -281,14 +282,14 @@ bool FFmpegVideoDecoder::initialize(
m_HwDecodeCfg = config;
// Initialize the hardware codec and submit a test frame if the renderer needs it
if (m_Renderer->initialize(window, videoFormat, width, height, maxFps) &&
completeInitialization(decoder, window, videoFormat, width, height, maxFps, m_Renderer->needsTestFrame())) {
if (m_Renderer->initialize(window, videoFormat, width, height, maxFps, enableVsync) &&
completeInitialization(decoder, window, videoFormat, width, height, maxFps, enableVsync, m_Renderer->needsTestFrame())) {
if (m_Renderer->needsTestFrame()) {
// The test worked, so now let's initialize it for real
reset();
if ((m_Renderer = createAcceleratedRenderer(config)) != nullptr &&
m_Renderer->initialize(window, videoFormat, width, height, maxFps) &&
completeInitialization(decoder, window, videoFormat, width, height, maxFps, false)) {
m_Renderer->initialize(window, videoFormat, width, height, maxFps, enableVsync) &&
completeInitialization(decoder, window, videoFormat, width, height, maxFps, enableVsync, false)) {
return true;
}
else {

View File

@ -17,7 +17,8 @@ public:
int videoFormat,
int width,
int height,
int maxFps) override;
int maxFps,
bool enableVsync) override;
virtual bool isHardwareAccelerated() override;
virtual int submitDecodeUnit(PDECODE_UNIT du) override;
virtual void renderFrame(SDL_UserEvent* event) override;
@ -28,7 +29,7 @@ public:
private:
bool completeInitialization(AVCodec* decoder, SDL_Window* window,
int videoFormat, int width, int height,
int maxFps, bool testOnly);
int maxFps, bool enableVsync, bool testOnly);
IFFmpegRenderer* createAcceleratedRenderer(const AVCodecHWConfig* hwDecodeCfg);

View File

@ -28,7 +28,7 @@ SLVideoDecoder::isHardwareAccelerated()
bool
SLVideoDecoder::initialize(StreamingPreferences::VideoDecoderSelection vds,
SDL_Window*,
int videoFormat, int, int, int frameRate)
int videoFormat, int, int, int frameRate, bool)
{
// SLVideo only supports hardware decoding
if (vds == StreamingPreferences::VDS_FORCE_SOFTWARE) {

View File

@ -14,7 +14,8 @@ public:
int videoFormat,
int width,
int height,
int frameRate);
int frameRate,
bool enableVsync);
virtual bool isHardwareAccelerated();
virtual int submitDecodeUnit(PDECODE_UNIT du);