Enable transparent resizing and display changes for supported renderers

This commit is contained in:
Cameron Gutman 2023-12-17 21:15:27 -06:00
parent 481f23b6e9
commit 2a05b890d8
14 changed files with 116 additions and 4 deletions

View file

@ -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,

View file

@ -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;
};

View file

@ -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

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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,

View file

@ -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));
}

View file

@ -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);

View file

@ -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)
{

View file

@ -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;

View file

@ -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;

View file

@ -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();

View file

@ -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);