mirror of
https://github.com/moonlight-stream/moonlight-qt
synced 2024-12-14 21:32:27 +00:00
Enhance frame pacing logic for HDR renderers
This commit is contained in:
parent
5f682bb45f
commit
2bb2745f91
6 changed files with 47 additions and 18 deletions
|
@ -581,8 +581,8 @@ void D3D11VARenderer::renderFrame(AVFrame* frame)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Otherwise, we'll submit as fast as possible and DWM will discard excess
|
// Otherwise, we'll submit as fast as possible and DWM will discard excess
|
||||||
// frames for us. If frame pacing is also enabled, our Vsync source will keep
|
// frames for us. If frame pacing is also enabled or we're in full-screen,
|
||||||
// us in sync with VBlank.
|
// our Vsync source will keep us in sync with VBlank.
|
||||||
flags = 0;
|
flags = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -993,8 +993,19 @@ bool D3D11VARenderer::checkDecoderSupport(IDXGIAdapter* adapter)
|
||||||
|
|
||||||
int D3D11VARenderer::getRendererAttributes()
|
int D3D11VARenderer::getRendererAttributes()
|
||||||
{
|
{
|
||||||
|
int attributes = 0;
|
||||||
|
|
||||||
// This renderer supports HDR
|
// This renderer supports HDR
|
||||||
return RENDERER_ATTRIBUTE_HDR_SUPPORT;
|
attributes |= RENDERER_ATTRIBUTE_HDR_SUPPORT;
|
||||||
|
|
||||||
|
// This renderer requires frame pacing to synchronize with VBlank when we're
|
||||||
|
// in full-screen. In windowed mode, we will render as fast we can and DWM
|
||||||
|
// will grab whatever is latest at the time unless the user opts for pacing.
|
||||||
|
if (SDL_GetWindowFlags(m_DecoderParams.window) & SDL_WINDOW_FULLSCREEN) {
|
||||||
|
attributes |= RENDERER_ATTRIBUTE_FORCE_PACING;
|
||||||
|
}
|
||||||
|
|
||||||
|
return attributes;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool D3D11VARenderer::needsTestFrame()
|
bool D3D11VARenderer::needsTestFrame()
|
||||||
|
|
|
@ -443,6 +443,9 @@ int DrmRenderer::getRendererAttributes()
|
||||||
// This renderer supports HDR
|
// This renderer supports HDR
|
||||||
attributes |= RENDERER_ATTRIBUTE_HDR_SUPPORT;
|
attributes |= RENDERER_ATTRIBUTE_HDR_SUPPORT;
|
||||||
|
|
||||||
|
// This renderer does not buffer any frames in the graphics pipeline
|
||||||
|
attributes |= RENDERER_ATTRIBUTE_NO_BUFFERING;
|
||||||
|
|
||||||
return attributes;
|
return attributes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -208,6 +208,7 @@ bool Pacer::initialize(SDL_Window* window, int maxVideoFps, bool enablePacing)
|
||||||
{
|
{
|
||||||
m_MaxVideoFps = maxVideoFps;
|
m_MaxVideoFps = maxVideoFps;
|
||||||
m_DisplayFps = StreamUtils::getDisplayRefreshRate(window);
|
m_DisplayFps = StreamUtils::getDisplayRefreshRate(window);
|
||||||
|
m_RendererAttributes = m_VsyncRenderer->getRendererAttributes();
|
||||||
|
|
||||||
if (enablePacing) {
|
if (enablePacing) {
|
||||||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
|
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
|
@ -225,6 +226,8 @@ bool Pacer::initialize(SDL_Window* window, int maxVideoFps, bool enablePacing)
|
||||||
// immediately like they used to.
|
// immediately like they used to.
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
SDL_assert(m_VsyncSource != nullptr || !(m_RendererAttributes & RENDERER_ATTRIBUTE_FORCE_PACING));
|
||||||
|
|
||||||
if (m_VsyncSource != nullptr && !m_VsyncSource->initialize(window, m_DisplayFps)) {
|
if (m_VsyncSource != nullptr && !m_VsyncSource->initialize(window, m_DisplayFps)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -259,22 +262,31 @@ void Pacer::renderFrame(AVFrame* frame)
|
||||||
// Drop frames if we have too many queued up for a while
|
// Drop frames if we have too many queued up for a while
|
||||||
m_FrameQueueLock.lock();
|
m_FrameQueueLock.lock();
|
||||||
|
|
||||||
int frameDropTarget = 0;
|
int frameDropTarget;
|
||||||
for (int queueHistoryEntry : m_RenderQueueHistory) {
|
|
||||||
if (queueHistoryEntry == 0) {
|
if (m_RendererAttributes & RENDERER_ATTRIBUTE_NO_BUFFERING) {
|
||||||
// Be lenient as long as the queue length
|
// Renderers that don't buffer any frames but don't support waitToRender() need us to buffer
|
||||||
// resolves before the end of frame history
|
// an extra frame to ensure they don't starve while waiting to present.
|
||||||
frameDropTarget = 2;
|
frameDropTarget = 1;
|
||||||
break;
|
}
|
||||||
|
else {
|
||||||
|
frameDropTarget = 0;
|
||||||
|
for (int queueHistoryEntry : m_RenderQueueHistory) {
|
||||||
|
if (queueHistoryEntry == 0) {
|
||||||
|
// Be lenient as long as the queue length
|
||||||
|
// resolves before the end of frame history
|
||||||
|
frameDropTarget = 2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Keep a rolling 500 ms window of render queue history
|
// Keep a rolling 500 ms window of render queue history
|
||||||
if (m_RenderQueueHistory.count() == m_MaxVideoFps / 2) {
|
if (m_RenderQueueHistory.count() == m_MaxVideoFps / 2) {
|
||||||
m_RenderQueueHistory.dequeue();
|
m_RenderQueueHistory.dequeue();
|
||||||
}
|
}
|
||||||
|
|
||||||
m_RenderQueueHistory.enqueue(m_RenderQueue.count());
|
m_RenderQueueHistory.enqueue(m_RenderQueue.count());
|
||||||
|
}
|
||||||
|
|
||||||
// Catch up if we're several frames ahead
|
// Catch up if we're several frames ahead
|
||||||
while (m_RenderQueue.count() > frameDropTarget) {
|
while (m_RenderQueue.count() > frameDropTarget) {
|
||||||
|
|
|
@ -52,4 +52,5 @@ private:
|
||||||
int m_MaxVideoFps;
|
int m_MaxVideoFps;
|
||||||
int m_DisplayFps;
|
int m_DisplayFps;
|
||||||
PVIDEO_STATS m_VideoStats;
|
PVIDEO_STATS m_VideoStats;
|
||||||
|
int m_RendererAttributes;
|
||||||
};
|
};
|
||||||
|
|
|
@ -110,7 +110,8 @@ private:
|
||||||
#define RENDERER_ATTRIBUTE_FULLSCREEN_ONLY 0x01
|
#define RENDERER_ATTRIBUTE_FULLSCREEN_ONLY 0x01
|
||||||
#define RENDERER_ATTRIBUTE_1080P_MAX 0x02
|
#define RENDERER_ATTRIBUTE_1080P_MAX 0x02
|
||||||
#define RENDERER_ATTRIBUTE_HDR_SUPPORT 0x04
|
#define RENDERER_ATTRIBUTE_HDR_SUPPORT 0x04
|
||||||
#define RENDERER_ATTRIBUTE_SELF_PACING 0x08
|
#define RENDERER_ATTRIBUTE_NO_BUFFERING 0x08
|
||||||
|
#define RENDERER_ATTRIBUTE_FORCE_PACING 0x10
|
||||||
|
|
||||||
class IFFmpegRenderer : public Overlay::IOverlayRenderer {
|
class IFFmpegRenderer : public Overlay::IOverlayRenderer {
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -290,7 +290,8 @@ bool FFmpegVideoDecoder::completeInitialization(const AVCodec* decoder, PDECODER
|
||||||
// Don't bother initializing Pacer if we're not actually going to render
|
// Don't bother initializing Pacer if we're not actually going to render
|
||||||
if (!testFrame) {
|
if (!testFrame) {
|
||||||
m_Pacer = new Pacer(m_FrontendRenderer, &m_ActiveWndVideoStats);
|
m_Pacer = new Pacer(m_FrontendRenderer, &m_ActiveWndVideoStats);
|
||||||
if (!m_Pacer->initialize(params->window, params->frameRate, params->enableFramePacing)) {
|
if (!m_Pacer->initialize(params->window, params->frameRate,
|
||||||
|
params->enableFramePacing || (params->enableVsync && (m_FrontendRenderer->getRendererAttributes() & RENDERER_ATTRIBUTE_FORCE_PACING)))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue