mirror of
https://github.com/moonlight-stream/moonlight-qt
synced 2024-12-13 04:42:27 +00:00
Reset the decoder when D3D state is lost
This commit is contained in:
parent
86874a2e1c
commit
10b5245919
4 changed files with 67 additions and 39 deletions
|
@ -101,6 +101,11 @@ bool Session::chooseDecoder(StreamingPreferences::VideoDecoderSelection vds,
|
|||
|
||||
int Session::drSetup(int videoFormat, int width, int height, int frameRate, void *, int)
|
||||
{
|
||||
s_ActiveSession->m_ActiveVideoFormat = videoFormat;
|
||||
s_ActiveSession->m_ActiveVideoWidth = width;
|
||||
s_ActiveSession->m_ActiveVideoHeight = height;
|
||||
s_ActiveSession->m_ActiveVideoFrameRate = frameRate;
|
||||
|
||||
if (!chooseDecoder(s_ActiveSession->m_Preferences.videoDecoderSelection,
|
||||
s_ActiveSession->m_Window,
|
||||
videoFormat, width, height, frameRate,
|
||||
|
@ -117,7 +122,16 @@ int Session::drSubmitDecodeUnit(PDECODE_UNIT du)
|
|||
// from underneath the session when we initiate destruction.
|
||||
// We need to destroy the decoder on the main thread to satisfy
|
||||
// some API constraints (like DXVA2).
|
||||
|
||||
SDL_AtomicLock(&s_ActiveSession->m_DecoderLock);
|
||||
|
||||
if (s_ActiveSession->m_NeedsIdr) {
|
||||
// If we reset our decoder, we'll need to request an IDR frame
|
||||
s_ActiveSession->m_NeedsIdr = false;
|
||||
SDL_AtomicUnlock(&s_ActiveSession->m_DecoderLock);
|
||||
return DR_NEED_IDR;
|
||||
}
|
||||
|
||||
IVideoDecoder* decoder = s_ActiveSession->m_VideoDecoder;
|
||||
if (decoder != nullptr) {
|
||||
int ret = decoder->submitDecodeUnit(du);
|
||||
|
@ -160,7 +174,8 @@ Session::Session(NvComputer* computer, NvApp& app)
|
|||
m_App(app),
|
||||
m_Window(nullptr),
|
||||
m_VideoDecoder(nullptr),
|
||||
m_DecoderLock(0)
|
||||
m_DecoderLock(0),
|
||||
m_NeedsIdr(false)
|
||||
{
|
||||
LiInitializeVideoCallbacks(&m_VideoCallbacks);
|
||||
m_VideoCallbacks.setup = drSetup;
|
||||
|
@ -510,6 +525,32 @@ void Session::exec()
|
|||
m_VideoDecoder->renderFrame(&event.user);
|
||||
break;
|
||||
}
|
||||
|
||||
case SDL_RENDER_DEVICE_RESET:
|
||||
case SDL_RENDER_TARGETS_RESET:
|
||||
SDL_AtomicLock(&m_DecoderLock);
|
||||
|
||||
// Destroy the old decoder
|
||||
delete m_VideoDecoder;
|
||||
|
||||
// Chose a new decoder (hopefully the same one, but possibly
|
||||
// not if a GPU was removed or something).
|
||||
if (!chooseDecoder(m_Preferences.videoDecoderSelection,
|
||||
m_Window, m_ActiveVideoFormat, m_ActiveVideoWidth,
|
||||
m_ActiveVideoHeight, m_ActiveVideoFrameRate,
|
||||
s_ActiveSession->m_VideoDecoder)) {
|
||||
SDL_AtomicUnlock(&m_DecoderLock);
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"Failed to recreate decoder after reset");
|
||||
goto DispatchDeferredCleanup;
|
||||
}
|
||||
|
||||
// Request an IDR frame to complete the reset
|
||||
m_NeedsIdr = true;
|
||||
|
||||
SDL_AtomicUnlock(&m_DecoderLock);
|
||||
break;
|
||||
|
||||
case SDL_KEYUP:
|
||||
case SDL_KEYDOWN:
|
||||
inputHandler.handleKeyEvent(&event.key);
|
||||
|
|
|
@ -94,6 +94,12 @@ private:
|
|||
SDL_Window* m_Window;
|
||||
IVideoDecoder* m_VideoDecoder;
|
||||
SDL_SpinLock m_DecoderLock;
|
||||
bool m_NeedsIdr;
|
||||
|
||||
int m_ActiveVideoFormat;
|
||||
int m_ActiveVideoWidth;
|
||||
int m_ActiveVideoHeight;
|
||||
int m_ActiveVideoFrameRate;
|
||||
|
||||
static SDL_AudioDeviceID s_AudioDevice;
|
||||
static OpusMSDecoder* s_OpusDecoder;
|
||||
|
|
|
@ -409,28 +409,6 @@ void DXVA2Renderer::renderFrame(AVFrame* frame)
|
|||
IDirect3DSurface9* surface = reinterpret_cast<IDirect3DSurface9*>(frame->data[3]);
|
||||
HRESULT hr;
|
||||
|
||||
hr = m_Device->TestCooperativeLevel();
|
||||
switch (hr) {
|
||||
case D3D_OK:
|
||||
break;
|
||||
case D3DERR_DEVICELOST:
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"D3D device lost!");
|
||||
av_frame_free(&frame);
|
||||
return;
|
||||
case D3DERR_DEVICENOTRESET:
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"D3D device not reset!");
|
||||
av_frame_free(&frame);
|
||||
return;
|
||||
default:
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"Unknown D3D error: %x",
|
||||
hr);
|
||||
av_frame_free(&frame);
|
||||
return;
|
||||
}
|
||||
|
||||
DXVA2_VideoSample sample = {};
|
||||
sample.Start = m_FrameIndex;
|
||||
sample.End = m_FrameIndex + 1;
|
||||
|
@ -473,25 +451,33 @@ void DXVA2Renderer::renderFrame(AVFrame* frame)
|
|||
|
||||
bltParams.Alpha = DXVA2_Fixed32OpaqueAlpha();
|
||||
|
||||
hr = m_Device->Clear(0, nullptr, D3DCLEAR_TARGET, D3DCOLOR_ARGB(255, 0, 0, 0), 0.0f, 0);
|
||||
if (FAILED(hr)) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"Clear() failed: %x",
|
||||
hr);
|
||||
if (SDL_RenderClear(m_SdlRenderer) != 0) {
|
||||
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"SDL_RenderClear() failed: %s",
|
||||
SDL_GetError());
|
||||
av_frame_free(&frame);
|
||||
|
||||
// We're going to cheat a little bit here. It seems SDL's
|
||||
// renderer may flake out in scenarios like moving the window
|
||||
// between monitors, so generate a synthetic reset event for
|
||||
// the main loop to consume.
|
||||
SDL_Event event;
|
||||
event.type = SDL_RENDER_TARGETS_RESET;
|
||||
SDL_PushEvent(&event);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
hr = m_Processor->VideoProcessBlt(m_RenderTarget, &bltParams, &sample, 1, nullptr);
|
||||
av_frame_free(&frame);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"VideoProcessBlt() failed: %x",
|
||||
hr);
|
||||
av_frame_free(&frame);
|
||||
return;
|
||||
}
|
||||
|
||||
m_Device->Present(nullptr, nullptr, nullptr, nullptr);
|
||||
|
||||
av_frame_free(&frame);
|
||||
// We must try to present to trigger SDL's logic to recover the render target,
|
||||
// even if VideoProcessBlt() fails.
|
||||
SDL_RenderPresent(m_SdlRenderer);
|
||||
}
|
||||
|
|
|
@ -128,14 +128,9 @@ FFmpegVideoDecoder::~FFmpegVideoDecoder()
|
|||
}
|
||||
}
|
||||
|
||||
avcodec_close(m_VideoDecoderCtx);
|
||||
av_free(m_VideoDecoderCtx);
|
||||
m_VideoDecoderCtx = nullptr;
|
||||
|
||||
m_HwDecodeCfg = nullptr;
|
||||
avcodec_free_context(&m_VideoDecoderCtx);
|
||||
|
||||
delete m_Renderer;
|
||||
m_Renderer = nullptr;
|
||||
}
|
||||
|
||||
bool FFmpegVideoDecoder::initialize(
|
||||
|
|
Loading…
Reference in a new issue