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 {
|
||||
// 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
|
||||
// us in sync with VBlank.
|
||||
// frames for us. If frame pacing is also enabled or we're in full-screen,
|
||||
// our Vsync source will keep us in sync with VBlank.
|
||||
flags = 0;
|
||||
}
|
||||
|
||||
|
@ -993,8 +993,19 @@ bool D3D11VARenderer::checkDecoderSupport(IDXGIAdapter* adapter)
|
|||
|
||||
int D3D11VARenderer::getRendererAttributes()
|
||||
{
|
||||
int attributes = 0;
|
||||
|
||||
// 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()
|
||||
|
|
|
@ -443,6 +443,9 @@ int DrmRenderer::getRendererAttributes()
|
|||
// This renderer supports HDR
|
||||
attributes |= RENDERER_ATTRIBUTE_HDR_SUPPORT;
|
||||
|
||||
// This renderer does not buffer any frames in the graphics pipeline
|
||||
attributes |= RENDERER_ATTRIBUTE_NO_BUFFERING;
|
||||
|
||||
return attributes;
|
||||
}
|
||||
|
||||
|
|
|
@ -208,6 +208,7 @@ bool Pacer::initialize(SDL_Window* window, int maxVideoFps, bool enablePacing)
|
|||
{
|
||||
m_MaxVideoFps = maxVideoFps;
|
||||
m_DisplayFps = StreamUtils::getDisplayRefreshRate(window);
|
||||
m_RendererAttributes = m_VsyncRenderer->getRendererAttributes();
|
||||
|
||||
if (enablePacing) {
|
||||
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.
|
||||
#endif
|
||||
|
||||
SDL_assert(m_VsyncSource != nullptr || !(m_RendererAttributes & RENDERER_ATTRIBUTE_FORCE_PACING));
|
||||
|
||||
if (m_VsyncSource != nullptr && !m_VsyncSource->initialize(window, m_DisplayFps)) {
|
||||
return false;
|
||||
}
|
||||
|
@ -259,22 +262,31 @@ void Pacer::renderFrame(AVFrame* frame)
|
|||
// Drop frames if we have too many queued up for a while
|
||||
m_FrameQueueLock.lock();
|
||||
|
||||
int 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;
|
||||
int frameDropTarget;
|
||||
|
||||
if (m_RendererAttributes & RENDERER_ATTRIBUTE_NO_BUFFERING) {
|
||||
// Renderers that don't buffer any frames but don't support waitToRender() need us to buffer
|
||||
// an extra frame to ensure they don't starve while waiting to present.
|
||||
frameDropTarget = 1;
|
||||
}
|
||||
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
|
||||
if (m_RenderQueueHistory.count() == m_MaxVideoFps / 2) {
|
||||
m_RenderQueueHistory.dequeue();
|
||||
}
|
||||
// Keep a rolling 500 ms window of render queue history
|
||||
if (m_RenderQueueHistory.count() == m_MaxVideoFps / 2) {
|
||||
m_RenderQueueHistory.dequeue();
|
||||
}
|
||||
|
||||
m_RenderQueueHistory.enqueue(m_RenderQueue.count());
|
||||
m_RenderQueueHistory.enqueue(m_RenderQueue.count());
|
||||
}
|
||||
|
||||
// Catch up if we're several frames ahead
|
||||
while (m_RenderQueue.count() > frameDropTarget) {
|
||||
|
|
|
@ -52,4 +52,5 @@ private:
|
|||
int m_MaxVideoFps;
|
||||
int m_DisplayFps;
|
||||
PVIDEO_STATS m_VideoStats;
|
||||
int m_RendererAttributes;
|
||||
};
|
||||
|
|
|
@ -110,7 +110,8 @@ private:
|
|||
#define RENDERER_ATTRIBUTE_FULLSCREEN_ONLY 0x01
|
||||
#define RENDERER_ATTRIBUTE_1080P_MAX 0x02
|
||||
#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 {
|
||||
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
|
||||
if (!testFrame) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue