mirror of
https://github.com/moonlight-stream/moonlight-qt
synced 2024-12-15 13:52:28 +00:00
Wait on our D3D11 swapchain before rendering to reduce latency
This commit is contained in:
parent
474591c6a5
commit
6d3d51553b
4 changed files with 27 additions and 20 deletions
|
@ -464,10 +464,6 @@ bool D3D11VARenderer::initialize(PDECODER_PARAMETERS params)
|
|||
|
||||
m_FrameWaitableObject = m_SwapChain->GetFrameLatencyWaitableObject();
|
||||
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 {
|
||||
IDXGIDevice1* dxgiDevice;
|
||||
|
@ -582,6 +578,22 @@ void D3D11VARenderer::setHdrMode(bool enabled)
|
|||
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)
|
||||
{
|
||||
// Acquire the context lock for rendering to prevent concurrent
|
||||
|
@ -669,22 +681,6 @@ void D3D11VARenderer::renderFrame(AVFrame* frame)
|
|||
SDL_PushEvent(&event);
|
||||
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)
|
||||
|
|
|
@ -19,6 +19,7 @@ public:
|
|||
virtual bool prepareDecoderContext(AVCodecContext* context, AVDictionary**) override;
|
||||
virtual bool prepareDecoderContextInGetFormat(AVCodecContext* context, AVPixelFormat pixelFormat) override;
|
||||
virtual void renderFrame(AVFrame* frame) override;
|
||||
virtual void waitToRender() override;
|
||||
virtual void notifyOverlayUpdated(Overlay::OverlayType) override;
|
||||
virtual void setHdrMode(bool enabled) override;
|
||||
virtual int getRendererAttributes() override;
|
||||
|
|
|
@ -91,6 +91,9 @@ int Pacer::renderThread(void* context)
|
|||
}
|
||||
|
||||
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
|
||||
// the not empty condition
|
||||
me->m_FrameQueueLock.lock();
|
||||
|
|
|
@ -102,6 +102,13 @@ public:
|
|||
virtual bool prepareDecoderContext(AVCodecContext* context, AVDictionary** options) = 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
|
||||
virtual void cleanupRenderContext() {
|
||||
// Nothing
|
||||
|
|
Loading…
Reference in a new issue