mirror of
https://github.com/moonlight-stream/moonlight-qt
synced 2025-01-22 23:55:02 +00:00
Enable transparent resizing and display changes for supported renderers
This commit is contained in:
parent
481f23b6e9
commit
2a05b890d8
14 changed files with 116 additions and 4 deletions
|
@ -1915,6 +1915,52 @@ void Session::execInternal()
|
|||
break;
|
||||
}
|
||||
|
||||
// Allow the renderer to handle the state change without being recreated
|
||||
if (m_VideoDecoder) {
|
||||
bool forceRecreation = false;
|
||||
|
||||
WINDOW_STATE_CHANGE_INFO windowChangeInfo = {};
|
||||
windowChangeInfo.window = m_Window;
|
||||
|
||||
if (event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED) {
|
||||
windowChangeInfo.stateChangeFlags |= WINDOW_STATE_CHANGE_SIZE;
|
||||
|
||||
windowChangeInfo.width = event.window.data1;
|
||||
windowChangeInfo.height = event.window.data2;
|
||||
}
|
||||
|
||||
int newDisplayIndex = SDL_GetWindowDisplayIndex(m_Window);
|
||||
if (newDisplayIndex != currentDisplayIndex) {
|
||||
windowChangeInfo.stateChangeFlags |= WINDOW_STATE_CHANGE_DISPLAY;
|
||||
|
||||
windowChangeInfo.displayIndex = newDisplayIndex;
|
||||
|
||||
// If the refresh rates have changed, we will need to go through the full
|
||||
// decoder recreation path to ensure Pacer is switched to the new display
|
||||
// and that we apply any V-Sync disablement rules that may be needed for
|
||||
// this display.
|
||||
SDL_DisplayMode oldMode, newMode;
|
||||
if (SDL_GetCurrentDisplayMode(currentDisplayIndex, &oldMode) < 0 ||
|
||||
SDL_GetCurrentDisplayMode(newDisplayIndex, &newMode) < 0 ||
|
||||
oldMode.refresh_rate != newMode.refresh_rate) {
|
||||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"Forcing renderer recreation due to refresh rate change between displays");
|
||||
forceRecreation = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!forceRecreation && m_VideoDecoder->notifyWindowChanged(&windowChangeInfo)) {
|
||||
// Update the window display mode based on our current monitor
|
||||
// NB: Avoid a useless modeset by only doing this if it changed.
|
||||
if (newDisplayIndex != currentDisplayIndex) {
|
||||
currentDisplayIndex = newDisplayIndex;
|
||||
updateOptimalWindowDisplayMode();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"Recreating renderer for window event: %d (%d %d)",
|
||||
event.window.event,
|
||||
|
|
|
@ -45,6 +45,21 @@ typedef struct _DECODER_PARAMETERS {
|
|||
bool testOnly;
|
||||
} DECODER_PARAMETERS, *PDECODER_PARAMETERS;
|
||||
|
||||
#define WINDOW_STATE_CHANGE_SIZE 0x01
|
||||
#define WINDOW_STATE_CHANGE_DISPLAY 0x02
|
||||
|
||||
typedef struct _WINDOW_STATE_CHANGE_INFO {
|
||||
SDL_Window* window;
|
||||
uint32_t stateChangeFlags;
|
||||
|
||||
// Populated if WINDOW_STATE_CHANGE_SIZE is set
|
||||
int width;
|
||||
int height;
|
||||
|
||||
// Populated if WINDOW_STATE_CHANGE_DISPLAY is set
|
||||
int displayIndex;
|
||||
} WINDOW_STATE_CHANGE_INFO, *PWINDOW_STATE_CHANGE_INFO;
|
||||
|
||||
class IVideoDecoder {
|
||||
public:
|
||||
virtual ~IVideoDecoder() {}
|
||||
|
@ -59,4 +74,5 @@ public:
|
|||
virtual int submitDecodeUnit(PDECODE_UNIT du) = 0;
|
||||
virtual void renderFrameOnMainThread() = 0;
|
||||
virtual void setHdrMode(bool enabled) = 0;
|
||||
virtual bool notifyWindowChanged(PWINDOW_STATE_CHANGE_INFO info) = 0;
|
||||
};
|
||||
|
|
|
@ -168,6 +168,12 @@ void EGLRenderer::notifyOverlayUpdated(Overlay::OverlayType type)
|
|||
}
|
||||
}
|
||||
|
||||
bool EGLRenderer::notifyWindowChanged(PWINDOW_STATE_CHANGE_INFO info)
|
||||
{
|
||||
// We can transparently handle size and display changes
|
||||
return !(info->stateChangeFlags & ~(WINDOW_STATE_CHANGE_SIZE | WINDOW_STATE_CHANGE_DISPLAY));
|
||||
}
|
||||
|
||||
bool EGLRenderer::isPixelFormatSupported(int videoFormat, AVPixelFormat pixelFormat)
|
||||
{
|
||||
// Pixel format support should be determined by the backend renderer
|
||||
|
|
|
@ -17,6 +17,7 @@ public:
|
|||
virtual void renderFrame(AVFrame* frame) override;
|
||||
virtual bool testRenderFrame(AVFrame* frame) override;
|
||||
virtual void notifyOverlayUpdated(Overlay::OverlayType) override;
|
||||
virtual bool notifyWindowChanged(PWINDOW_STATE_CHANGE_INFO) override;
|
||||
virtual bool isPixelFormatSupported(int videoFormat, enum AVPixelFormat pixelFormat) override;
|
||||
virtual AVPixelFormat getPreferredPixelFormat(int videoFormat) override;
|
||||
|
||||
|
|
|
@ -320,6 +320,8 @@ bool PlVkRenderer::isExtensionSupportedByPhysicalDevice(VkPhysicalDevice device,
|
|||
|
||||
bool PlVkRenderer::initialize(PDECODER_PARAMETERS params)
|
||||
{
|
||||
m_Window = params->window;
|
||||
|
||||
unsigned int instanceExtensionCount = 0;
|
||||
if (!SDL_Vulkan_GetInstanceExtensions(params->window, &instanceExtensionCount, nullptr)) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||
|
@ -429,10 +431,6 @@ bool PlVkRenderer::initialize(PDECODER_PARAMETERS params)
|
|||
return false;
|
||||
}
|
||||
|
||||
int vkDrawableW, vkDrawableH;
|
||||
SDL_Vulkan_GetDrawableSize(params->window, &vkDrawableW, &vkDrawableH);
|
||||
pl_swapchain_resize(m_Swapchain, &vkDrawableW, &vkDrawableH);
|
||||
|
||||
m_Renderer = pl_renderer_create(m_Log, m_Vulkan->gpu);
|
||||
if (m_Renderer == nullptr) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||
|
@ -599,6 +597,11 @@ bool PlVkRenderer::isSurfacePresentationSupportedByPhysicalDevice(VkPhysicalDevi
|
|||
|
||||
void PlVkRenderer::waitToRender()
|
||||
{
|
||||
// Handle the swapchain being resized
|
||||
int vkDrawableW, vkDrawableH;
|
||||
SDL_Vulkan_GetDrawableSize(m_Window, &vkDrawableW, &vkDrawableH);
|
||||
pl_swapchain_resize(m_Swapchain, &vkDrawableW, &vkDrawableH);
|
||||
|
||||
// Get the next swapchain buffer for rendering. If this fails, renderFrame()
|
||||
// will try again.
|
||||
//
|
||||
|
@ -866,6 +869,12 @@ void PlVkRenderer::notifyOverlayUpdated(Overlay::OverlayType type)
|
|||
SDL_AtomicUnlock(&m_OverlayLock);
|
||||
}
|
||||
|
||||
bool PlVkRenderer::notifyWindowChanged(PWINDOW_STATE_CHANGE_INFO info)
|
||||
{
|
||||
// We can transparently handle size and display changes
|
||||
return !(info->stateChangeFlags & ~(WINDOW_STATE_CHANGE_SIZE | WINDOW_STATE_CHANGE_DISPLAY));
|
||||
}
|
||||
|
||||
int PlVkRenderer::getRendererAttributes()
|
||||
{
|
||||
int attributes = 0;
|
||||
|
|
|
@ -17,6 +17,7 @@ public:
|
|||
virtual void waitToRender() override;
|
||||
virtual void cleanupRenderContext() override;
|
||||
virtual void notifyOverlayUpdated(Overlay::OverlayType) override;
|
||||
virtual bool notifyWindowChanged(PWINDOW_STATE_CHANGE_INFO) override;
|
||||
virtual int getRendererAttributes() override;
|
||||
virtual int getDecoderCapabilities() override;
|
||||
virtual bool needsTestFrame() override;
|
||||
|
@ -41,6 +42,9 @@ private:
|
|||
// The backend renderer if we're frontend-only
|
||||
IFFmpegRenderer* m_Backend;
|
||||
|
||||
// SDL state
|
||||
SDL_Window* m_Window = nullptr;
|
||||
|
||||
// The libplacebo rendering state
|
||||
pl_log m_Log = nullptr;
|
||||
pl_vk_inst m_PlVkInstance = nullptr;
|
||||
|
|
|
@ -233,6 +233,11 @@ public:
|
|||
return true;
|
||||
}
|
||||
|
||||
virtual bool notifyWindowChanged(PWINDOW_STATE_CHANGE_INFO) {
|
||||
// Assume the renderer cannot handle window state changes
|
||||
return false;
|
||||
}
|
||||
|
||||
// Allow renderers to expose their type
|
||||
enum class RendererType {
|
||||
Unknown,
|
||||
|
|
|
@ -492,3 +492,9 @@ bool SdlRenderer::testRenderFrame(AVFrame* frame)
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SdlRenderer::notifyWindowChanged(PWINDOW_STATE_CHANGE_INFO info)
|
||||
{
|
||||
// We can transparently handle size and display changes
|
||||
return !(info->stateChangeFlags & ~(WINDOW_STATE_CHANGE_SIZE | WINDOW_STATE_CHANGE_DISPLAY));
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ public:
|
|||
virtual bool isRenderThreadSupported() override;
|
||||
virtual bool isPixelFormatSupported(int videoFormat, enum AVPixelFormat pixelFormat) override;
|
||||
virtual bool testRenderFrame(AVFrame* frame) override;
|
||||
virtual bool notifyWindowChanged(PWINDOW_STATE_CHANGE_INFO) override;
|
||||
|
||||
private:
|
||||
void renderOverlay(Overlay::OverlayType type);
|
||||
|
|
|
@ -681,6 +681,12 @@ void VAAPIRenderer::notifyOverlayUpdated(Overlay::OverlayType type)
|
|||
}
|
||||
}
|
||||
|
||||
bool VAAPIRenderer::notifyWindowChanged(PWINDOW_STATE_CHANGE_INFO info)
|
||||
{
|
||||
// We can transparently handle size and display changes
|
||||
return !(info->stateChangeFlags & ~(WINDOW_STATE_CHANGE_SIZE | WINDOW_STATE_CHANGE_DISPLAY));
|
||||
}
|
||||
|
||||
void
|
||||
VAAPIRenderer::renderFrame(AVFrame* frame)
|
||||
{
|
||||
|
|
|
@ -66,6 +66,7 @@ public:
|
|||
virtual int getDecoderColorspace() override;
|
||||
virtual int getDecoderCapabilities() override;
|
||||
virtual void notifyOverlayUpdated(Overlay::OverlayType) override;
|
||||
virtual bool notifyWindowChanged(PWINDOW_STATE_CHANGE_INFO) override;
|
||||
|
||||
#ifdef HAVE_EGL
|
||||
virtual bool canExportEGL() override;
|
||||
|
|
|
@ -99,6 +99,11 @@ void FFmpegVideoDecoder::setHdrMode(bool enabled)
|
|||
m_FrontendRenderer->setHdrMode(enabled);
|
||||
}
|
||||
|
||||
bool FFmpegVideoDecoder::notifyWindowChanged(PWINDOW_STATE_CHANGE_INFO info)
|
||||
{
|
||||
return m_FrontendRenderer->notifyWindowChanged(info);
|
||||
}
|
||||
|
||||
int FFmpegVideoDecoder::getDecoderCapabilities()
|
||||
{
|
||||
bool ok;
|
||||
|
|
|
@ -26,6 +26,7 @@ public:
|
|||
virtual int submitDecodeUnit(PDECODE_UNIT du) override;
|
||||
virtual void renderFrameOnMainThread() override;
|
||||
virtual void setHdrMode(bool enabled) override;
|
||||
virtual bool notifyWindowChanged(PWINDOW_STATE_CHANGE_INFO info) override;
|
||||
|
||||
virtual IFFmpegRenderer* getBackendRenderer();
|
||||
|
||||
|
|
|
@ -29,6 +29,11 @@ public:
|
|||
return false;
|
||||
}
|
||||
|
||||
// Window state changes are not supported by SLVideo
|
||||
virtual bool notifyWindowChanged(PWINDOW_STATE_CHANGE_INFO) {
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
static void slLogCallback(void* context, ESLVideoLog logLevel, const char* message);
|
||||
|
||||
|
|
Loading…
Reference in a new issue