mirror of
https://github.com/moonlight-stream/moonlight-qt.git
synced 2026-06-17 14:11:33 +00:00
Wait on our D3D11 swapchain before rendering to reduce latency
This commit is contained in:
@@ -464,10 +464,6 @@ bool D3D11VARenderer::initialize(PDECODER_PARAMETERS params)
|
|||||||
|
|
||||||
m_FrameWaitableObject = m_SwapChain->GetFrameLatencyWaitableObject();
|
m_FrameWaitableObject = m_SwapChain->GetFrameLatencyWaitableObject();
|
||||||
SDL_assert(m_FrameWaitableObject != nullptr);
|
SDL_assert(m_FrameWaitableObject != nullptr);
|
||||||
|
|
||||||
// Wait for the swap chain to be ready. This is required because we don't
|
|
||||||
// we're waiting after presenting in the general case, not before.
|
|
||||||
WaitForSingleObjectEx(m_FrameWaitableObject, 1000, FALSE);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
IDXGIDevice1* dxgiDevice;
|
IDXGIDevice1* dxgiDevice;
|
||||||
@@ -582,6 +578,22 @@ void D3D11VARenderer::setHdrMode(bool enabled)
|
|||||||
unlockContext(this);
|
unlockContext(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void D3D11VARenderer::waitToRender()
|
||||||
|
{
|
||||||
|
if (m_FrameWaitableObject != nullptr) {
|
||||||
|
SDL_assert(m_Windowed);
|
||||||
|
SDL_assert(m_DecoderParams.enableVsync);
|
||||||
|
|
||||||
|
// Wait for the pipeline to be ready for the next frame in V-Sync mode.
|
||||||
|
//
|
||||||
|
// This callback happens before selecting the next frame to render, so
|
||||||
|
// we can wait for the previous frame to finish prior to picking the
|
||||||
|
// next one to display. This reduces the effective display latency
|
||||||
|
// by ensuring we always render the most recent frame immediately.
|
||||||
|
WaitForSingleObjectEx(m_FrameWaitableObject, 500, FALSE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void D3D11VARenderer::renderFrame(AVFrame* frame)
|
void D3D11VARenderer::renderFrame(AVFrame* frame)
|
||||||
{
|
{
|
||||||
// Acquire the context lock for rendering to prevent concurrent
|
// Acquire the context lock for rendering to prevent concurrent
|
||||||
@@ -669,22 +681,6 @@ void D3D11VARenderer::renderFrame(AVFrame* frame)
|
|||||||
SDL_PushEvent(&event);
|
SDL_PushEvent(&event);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_FrameWaitableObject != nullptr) {
|
|
||||||
SDL_assert(m_Windowed);
|
|
||||||
SDL_assert(m_DecoderParams.enableVsync);
|
|
||||||
|
|
||||||
// Wait for the pipeline to be ready for the next frame in V-Sync mode.
|
|
||||||
//
|
|
||||||
// MSDN advises us to wait *before* doing any rendering operations,
|
|
||||||
// however that assumes the a typical game which will latch inputs,
|
|
||||||
// run the engine, draw, etc. after WaitForSingleObjectEx(). In our case,
|
|
||||||
// we actually want wait *after* our rendering operations, because our AVFrame
|
|
||||||
// is already set in stone by the time we enter this function. Waiting after
|
|
||||||
// presenting allows a more recent frame to be received before renderFrame()
|
|
||||||
// is called again.
|
|
||||||
WaitForSingleObjectEx(m_FrameWaitableObject, 1000, FALSE);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void D3D11VARenderer::renderOverlay(Overlay::OverlayType type)
|
void D3D11VARenderer::renderOverlay(Overlay::OverlayType type)
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ public:
|
|||||||
virtual bool prepareDecoderContext(AVCodecContext* context, AVDictionary**) override;
|
virtual bool prepareDecoderContext(AVCodecContext* context, AVDictionary**) override;
|
||||||
virtual bool prepareDecoderContextInGetFormat(AVCodecContext* context, AVPixelFormat pixelFormat) override;
|
virtual bool prepareDecoderContextInGetFormat(AVCodecContext* context, AVPixelFormat pixelFormat) override;
|
||||||
virtual void renderFrame(AVFrame* frame) override;
|
virtual void renderFrame(AVFrame* frame) override;
|
||||||
|
virtual void waitToRender() override;
|
||||||
virtual void notifyOverlayUpdated(Overlay::OverlayType) override;
|
virtual void notifyOverlayUpdated(Overlay::OverlayType) override;
|
||||||
virtual void setHdrMode(bool enabled) override;
|
virtual void setHdrMode(bool enabled) override;
|
||||||
virtual int getRendererAttributes() override;
|
virtual int getRendererAttributes() override;
|
||||||
|
|||||||
@@ -91,6 +91,9 @@ int Pacer::renderThread(void* context)
|
|||||||
}
|
}
|
||||||
|
|
||||||
while (!me->m_Stopping) {
|
while (!me->m_Stopping) {
|
||||||
|
// Wait for the renderer to be ready for the next frame
|
||||||
|
me->m_VsyncRenderer->waitToRender();
|
||||||
|
|
||||||
// Acquire the frame queue lock to protect the queue and
|
// Acquire the frame queue lock to protect the queue and
|
||||||
// the not empty condition
|
// the not empty condition
|
||||||
me->m_FrameQueueLock.lock();
|
me->m_FrameQueueLock.lock();
|
||||||
|
|||||||
@@ -102,6 +102,13 @@ public:
|
|||||||
virtual bool prepareDecoderContext(AVCodecContext* context, AVDictionary** options) = 0;
|
virtual bool prepareDecoderContext(AVCodecContext* context, AVDictionary** options) = 0;
|
||||||
virtual void renderFrame(AVFrame* frame) = 0;
|
virtual void renderFrame(AVFrame* frame) = 0;
|
||||||
|
|
||||||
|
// Called for threaded renderers to allow them to wait prior to us latching
|
||||||
|
// the next frame for rendering (as opposed to waiting on buffer swap with
|
||||||
|
// an older frame already queued for display).
|
||||||
|
virtual void waitToRender() {
|
||||||
|
// Don't wait by default
|
||||||
|
}
|
||||||
|
|
||||||
// Called on the same thread as renderFrame() during destruction of the renderer
|
// Called on the same thread as renderFrame() during destruction of the renderer
|
||||||
virtual void cleanupRenderContext() {
|
virtual void cleanupRenderContext() {
|
||||||
// Nothing
|
// Nothing
|
||||||
|
|||||||
Reference in New Issue
Block a user