From b4150b1e4cd4554800cc571a91acbc0d91377584 Mon Sep 17 00:00:00 2001 From: TellowKrinkle Date: Sun, 25 Jun 2023 16:51:52 -0500 Subject: [PATCH 01/10] VideoCommon:Presenter: Surface resizes include window dimensions Many graphics APIs don't have a way to get the backend scale, and wayland doesn't have a way to get the surface size either --- Source/Core/Common/WindowSystemInfo.h | 5 +++ Source/Core/DolphinNoGUI/PlatformFBDev.cpp | 3 ++ Source/Core/DolphinNoGUI/PlatformMacos.mm | 32 +++++++++------- Source/Core/DolphinNoGUI/PlatformWin32.cpp | 6 ++- Source/Core/DolphinNoGUI/PlatformX11.cpp | 6 ++- Source/Core/DolphinQt/Host.cpp | 29 ++++++--------- Source/Core/DolphinQt/Host.h | 3 +- Source/Core/DolphinQt/MainWindow.cpp | 5 ++- Source/Core/DolphinQt/RenderWidget.cpp | 36 +++++++++++------- Source/Core/DolphinQt/RenderWidget.h | 5 +-- Source/Core/VideoBackends/Metal/MTLGfx.h | 1 - Source/Core/VideoBackends/Metal/MTLGfx.mm | 18 +++------ Source/Core/VideoBackends/OGL/OGLGfx.cpp | 34 ++++++----------- Source/Core/VideoBackends/OGL/OGLGfx.h | 1 - Source/Core/VideoBackends/Software/SWGfx.cpp | 12 +++--- Source/Core/VideoBackends/Vulkan/VKGfx.cpp | 39 ++++++-------------- Source/Core/VideoBackends/Vulkan/VKGfx.h | 1 - Source/Core/VideoCommon/Present.cpp | 31 ++++++++++------ Source/Core/VideoCommon/Present.h | 32 ++++++++++++---- 19 files changed, 158 insertions(+), 141 deletions(-) diff --git a/Source/Core/Common/WindowSystemInfo.h b/Source/Core/Common/WindowSystemInfo.h index 9d154776f6..8c6920fe15 100644 --- a/Source/Core/Common/WindowSystemInfo.h +++ b/Source/Core/Common/WindowSystemInfo.h @@ -41,6 +41,11 @@ struct WindowSystemInfo // during video backend startup the surface pointer may change (MoltenVK). void* render_surface = nullptr; + // Width of the render surface + int render_surface_width = 0; + // Height of the render surface + int render_surface_height = 0; + // Scale of the render surface. For hidpi systems, this will be >1. float render_surface_scale = 1.0f; }; diff --git a/Source/Core/DolphinNoGUI/PlatformFBDev.cpp b/Source/Core/DolphinNoGUI/PlatformFBDev.cpp index 249ef20a03..719d959c20 100644 --- a/Source/Core/DolphinNoGUI/PlatformFBDev.cpp +++ b/Source/Core/DolphinNoGUI/PlatformFBDev.cpp @@ -85,6 +85,9 @@ WindowSystemInfo PlatformFBDev::GetWindowSystemInfo() const wsi.display_connection = nullptr; // EGL_DEFAULT_DISPLAY wsi.render_window = nullptr; wsi.render_surface = nullptr; + wsi.render_surface_width = 0; + wsi.render_surface_height = 0; + wsi.render_surface_scale = 1.f; return wsi; } } // namespace diff --git a/Source/Core/DolphinNoGUI/PlatformMacos.mm b/Source/Core/DolphinNoGUI/PlatformMacos.mm index b941858013..7838eae527 100644 --- a/Source/Core/DolphinNoGUI/PlatformMacos.mm +++ b/Source/Core/DolphinNoGUI/PlatformMacos.mm @@ -80,12 +80,13 @@ } @end -@interface AppDelegate : NSObject +@interface AppDelegate : NSObject @property(readonly) Platform* platform; - (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication*)sender; - (id)initWithPlatform:(Platform*)platform; +- (void)windowDidResize:(NSNotification*)notification; @end @implementation AppDelegate @@ -103,20 +104,20 @@ } return self; } -@end - -@interface WindowDelegate : NSObject - -- (void)windowDidResize:(NSNotification*)notification; -@end - -@implementation WindowDelegate - (void)windowDidResize:(NSNotification*)notification { + WindowSystemInfo info = _platform->GetWindowSystemInfo(); if (g_presenter) - g_presenter->ResizeSurface(); + g_presenter->ResizeSurface(info.render_surface_width, info.render_surface_height, + info.render_surface_scale); } + +- (void)windowDidChangeScreen:(NSNotification *)notification +{ + [self windowDidResize:notification]; +} + @end namespace @@ -142,7 +143,6 @@ private: NSWindow* m_window; NSMenu* menuBar; AppDelegate* m_app_delegate; - WindowDelegate* m_window_delegate; int m_window_x = Config::Get(Config::MAIN_RENDER_WINDOW_XPOS); int m_window_y = Config::Get(Config::MAIN_RENDER_WINDOW_YPOS); @@ -176,8 +176,7 @@ bool PlatformMacOS::Init() styleMask:styleMask backing:NSBackingStoreBuffered defer:NO]; - m_window_delegate = [[WindowDelegate alloc] init]; - [m_window setDelegate:m_window_delegate]; + [m_window setDelegate:m_app_delegate]; NSNotificationCenter* c = [NSNotificationCenter defaultCenter]; [c addObserver:NSApp @@ -237,10 +236,15 @@ WindowSystemInfo PlatformMacOS::GetWindowSystemInfo() const { @autoreleasepool { + NSRect frame = [m_window contentRectForFrameRect:[m_window frame]]; + CGFloat scale = [m_window backingScaleFactor]; WindowSystemInfo wsi; wsi.type = WindowSystemType::MacOS; - wsi.render_window = (void*)CFBridgingRetain([m_window contentView]); + wsi.render_window = (__bridge void*)[m_window contentView]; wsi.render_surface = wsi.render_window; + wsi.render_surface_width = frame.size.width * scale; + wsi.render_surface_height = frame.size.height * scale; + wsi.render_surface_scale = scale; return wsi; } } diff --git a/Source/Core/DolphinNoGUI/PlatformWin32.cpp b/Source/Core/DolphinNoGUI/PlatformWin32.cpp index ff07698115..b7fb456447 100644 --- a/Source/Core/DolphinNoGUI/PlatformWin32.cpp +++ b/Source/Core/DolphinNoGUI/PlatformWin32.cpp @@ -137,6 +137,9 @@ WindowSystemInfo PlatformWin32::GetWindowSystemInfo() const wsi.type = WindowSystemType::Windows; wsi.render_window = reinterpret_cast(m_hwnd); wsi.render_surface = reinterpret_cast(m_hwnd); + wsi.render_surface_width = m_window_width; + wsi.render_surface_height = m_window_height; + wsi.render_surface_scale = 1.f; return wsi; } @@ -192,8 +195,9 @@ LRESULT PlatformWin32::WndProc(const HWND hwnd, const UINT msg, const WPARAM wPa case WM_SIZE: { + UpdateWindowPosition(); if (g_presenter) - g_presenter->ResizeSurface(); + g_presenter->ResizeSurface(m_window_width, m_window_height, 1.f); } break; diff --git a/Source/Core/DolphinNoGUI/PlatformX11.cpp b/Source/Core/DolphinNoGUI/PlatformX11.cpp index 090fadf77e..8151e18516 100644 --- a/Source/Core/DolphinNoGUI/PlatformX11.cpp +++ b/Source/Core/DolphinNoGUI/PlatformX11.cpp @@ -167,6 +167,10 @@ WindowSystemInfo PlatformX11::GetWindowSystemInfo() const wsi.display_connection = static_cast(m_display); wsi.render_window = reinterpret_cast(m_window); wsi.render_surface = reinterpret_cast(m_window); + // TODO: Actually get these (currently both the X11 Vulkan and OGL backends ignore this) + wsi.render_surface_width = 0; + wsi.render_surface_height = 0; + wsi.render_surface_scale = 1.f; return wsi; } @@ -267,7 +271,7 @@ void PlatformX11::ProcessEvents() case ConfigureNotify: { if (g_presenter) - g_presenter->ResizeSurface(); + g_presenter->ResizeSurface(0, 0, 1.f); } break; } diff --git a/Source/Core/DolphinQt/Host.cpp b/Source/Core/DolphinQt/Host.cpp index e2f1b21884..ca3b2c47a0 100644 --- a/Source/Core/DolphinQt/Host.cpp +++ b/Source/Core/DolphinQt/Host.cpp @@ -56,21 +56,6 @@ Host* Host::GetInstance() return s_instance; } -void Host::SetRenderHandle(void* handle) -{ - m_render_to_main = Config::Get(Config::MAIN_RENDER_TO_MAIN); - - if (m_render_handle == handle) - return; - - m_render_handle = handle; - if (g_presenter) - { - g_presenter->ChangeSurface(handle); - g_controller_interface.ChangeWindow(handle); - } -} - void Host::SetMainWindowHandle(void* handle) { m_main_window_handle = handle; @@ -185,10 +170,20 @@ void Host::SetTASInputFocus(const bool focus) m_tas_input_focus = focus; } -void Host::ResizeSurface(int new_width, int new_height) +void Host::SetRenderWindowInfo(void* new_handle, int new_width, int new_height, float new_scale) { + if (new_handle) + { + m_render_to_main = Config::Get(Config::MAIN_RENDER_TO_MAIN); + if (m_render_handle == new_handle) + new_handle = nullptr; + else + m_render_handle = new_handle; + } if (g_presenter) - g_presenter->ResizeSurface(); + g_presenter->ChangeSurface(new_handle, new_width, new_height, new_scale); + if (g_presenter && new_handle) + g_controller_interface.ChangeWindow(new_handle); } std::vector Host_GetPreferredLocales() diff --git a/Source/Core/DolphinQt/Host.h b/Source/Core/DolphinQt/Host.h index 0eacfe646d..43b777dabd 100644 --- a/Source/Core/DolphinQt/Host.h +++ b/Source/Core/DolphinQt/Host.h @@ -28,10 +28,11 @@ public: bool GetTASInputFocus() const; void SetMainWindowHandle(void* handle); - void SetRenderHandle(void* handle); void SetRenderFocus(bool focus); void SetRenderFullFocus(bool focus); void SetRenderFullscreen(bool fullscreen); + // null new_handle => resize + void SetRenderWindowInfo(void* new_handle, int new_width, int new_height, float new_scale); void SetTASInputFocus(bool focus); void ResizeSurface(int new_width, int new_height); diff --git a/Source/Core/DolphinQt/MainWindow.cpp b/Source/Core/DolphinQt/MainWindow.cpp index 688ae6ffcd..ecf1511cfc 100644 --- a/Source/Core/DolphinQt/MainWindow.cpp +++ b/Source/Core/DolphinQt/MainWindow.cpp @@ -197,7 +197,10 @@ static WindowSystemInfo GetWindowSystemInfo(QWindow* window) wsi.render_window = window ? reinterpret_cast(window->winId()) : nullptr; wsi.render_surface = wsi.render_window; #endif - wsi.render_surface_scale = window ? static_cast(window->devicePixelRatio()) : 1.0f; + float dpr = window ? static_cast(window->devicePixelRatio()) : 1.f; + wsi.render_surface_width = window ? static_cast(window->width() * dpr) : 0; + wsi.render_surface_height = window ? static_cast(window->height() * dpr) : 0; + wsi.render_surface_scale = dpr; return wsi; } diff --git a/Source/Core/DolphinQt/RenderWidget.cpp b/Source/Core/DolphinQt/RenderWidget.cpp index 9b5026d5fb..af383fe267 100644 --- a/Source/Core/DolphinQt/RenderWidget.cpp +++ b/Source/Core/DolphinQt/RenderWidget.cpp @@ -66,9 +66,7 @@ RenderWidget::RenderWidget(QWidget* parent) : QWidget(parent) // (which results in them not getting called) connect(this, &RenderWidget::StateChanged, Host::GetInstance(), &Host::SetRenderFullscreen, Qt::DirectConnection); - connect(this, &RenderWidget::HandleChanged, this, &RenderWidget::OnHandleChanged, - Qt::DirectConnection); - connect(this, &RenderWidget::SizeChanged, Host::GetInstance(), &Host::ResizeSurface, + connect(this, &RenderWidget::WindowChanged, Host::GetInstance(), &Host::SetRenderWindowInfo, Qt::DirectConnection); connect(this, &RenderWidget::FocusChanged, Host::GetInstance(), &Host::SetRenderFocus, Qt::DirectConnection); @@ -130,6 +128,7 @@ void RenderWidget::dropEvent(QDropEvent* event) State::LoadAs(Core::System::GetInstance(), path.toStdString()); } +<<<<<<< HEAD void RenderWidget::OnHandleChanged(void* handle) { if (handle) @@ -144,6 +143,8 @@ void RenderWidget::OnHandleChanged(void* handle) Host::GetInstance()->SetRenderHandle(handle); } +======= +>>>>>>> 780f8e1d17 (VideoCommon:Presenter: Surface resizes include window dimensions) void RenderWidget::OnHideCursorChanged() { UpdateCursor(); @@ -212,7 +213,7 @@ void RenderWidget::showFullScreen() const auto dpr = screen->devicePixelRatio(); - emit SizeChanged(width() * dpr, height() * dpr); + emit WindowChanged(nullptr, width() * dpr, height() * dpr, dpr); } // Lock the cursor within the window/widget internal borders, including the aspect ratio if wanted @@ -402,9 +403,6 @@ bool RenderWidget::event(QEvent* event) m_mouse_timer->start(MOUSE_HIDE_DELAY); } break; - case QEvent::WinIdChange: - emit HandleChanged(reinterpret_cast(winId())); - break; case QEvent::Show: // Don't do if "stay on top" changed (or was true) if (Settings::Instance().GetLockCursor() && @@ -469,27 +467,37 @@ bool RenderWidget::event(QEvent* event) // According to https://bugreports.qt.io/browse/QTBUG-95925 the recommended practice for // handling DPI change is responding to paint events + case QEvent::WinIdChange: case QEvent::Paint: case QEvent::Resize: { - SetCursorLocked(m_cursor_locked); + void* handle = nullptr; + if (event->type() == QEvent::WinIdChange) + { + handle = reinterpret_cast(winId()); +#ifdef _WIN32 + // Remove rounded corners from the render window on Windows 11 + const DWM_WINDOW_CORNER_PREFERENCE corner_preference = DWMWCP_DONOTROUND; + DwmSetWindowAttribute(reinterpret_cast(handle), DWMWA_WINDOW_CORNER_PREFERENCE, + &corner_preference, sizeof(corner_preference)); +#endif + } - const QResizeEvent* se = static_cast(event); - QSize new_size = se->size(); + SetCursorLocked(m_cursor_locked); QScreen* screen = window()->windowHandle()->screen(); const float dpr = screen->devicePixelRatio(); - const int width = new_size.width() * dpr; - const int height = new_size.height() * dpr; + const int width = this->width() * dpr; + const int height = this->height() * dpr; - if (m_last_window_width != width || m_last_window_height != height || + if (handle || m_last_window_width != width || m_last_window_height != height || m_last_window_scale != dpr) { m_last_window_width = width; m_last_window_height = height; m_last_window_scale = dpr; - emit SizeChanged(width, height); + emit WindowChanged(handle, width, height, dpr); } break; } diff --git a/Source/Core/DolphinQt/RenderWidget.h b/Source/Core/DolphinQt/RenderWidget.h index d828bf36d1..54c973e71f 100644 --- a/Source/Core/DolphinQt/RenderWidget.h +++ b/Source/Core/DolphinQt/RenderWidget.h @@ -27,14 +27,13 @@ public: signals: void EscapePressed(); void Closed(); - void HandleChanged(void* handle); void StateChanged(bool fullscreen); - void SizeChanged(int new_width, int new_height); + // null new_handle => resize only + void WindowChanged(void* new_handle, int new_width, int new_height, float new_scale); void FocusChanged(bool focus); private: void HandleCursorTimer(); - void OnHandleChanged(void* handle); void OnHideCursorChanged(); void OnNeverHideCursorChanged(); void OnLockCursorChanged(); diff --git a/Source/Core/VideoBackends/Metal/MTLGfx.h b/Source/Core/VideoBackends/Metal/MTLGfx.h index fc9fca0c68..abaf845403 100644 --- a/Source/Core/VideoBackends/Metal/MTLGfx.h +++ b/Source/Core/VideoBackends/Metal/MTLGfx.h @@ -84,7 +84,6 @@ private: std::array m_shader_counter = {}; void CheckForSurfaceChange(); - void CheckForSurfaceResize(); void SetupSurface(); }; } // namespace Metal diff --git a/Source/Core/VideoBackends/Metal/MTLGfx.mm b/Source/Core/VideoBackends/Metal/MTLGfx.mm index 4b744fe511..d93860786a 100644 --- a/Source/Core/VideoBackends/Metal/MTLGfx.mm +++ b/Source/Core/VideoBackends/Metal/MTLGfx.mm @@ -453,7 +453,6 @@ bool Metal::Gfx::BindBackbuffer(const ClearColor& clear_color) @autoreleasepool { CheckForSurfaceChange(); - CheckForSurfaceResize(); m_drawable = MRCRetain([m_layer nextDrawable]); m_backbuffer->UpdateBackbufferTexture([m_drawable texture]); SetAndClearFramebuffer(m_backbuffer.get(), clear_color); @@ -488,17 +487,12 @@ void Metal::Gfx::PresentBackbuffer() void Metal::Gfx::CheckForSurfaceChange() { - if (!g_presenter->SurfaceChangedTestAndClear()) - return; - m_layer = MRCRetain(static_cast(g_presenter->GetNewSurfaceHandle())); - SetupSurface(); -} - -void Metal::Gfx::CheckForSurfaceResize() -{ - if (!g_presenter->SurfaceResizedTestAndClear()) - return; - SetupSurface(); + if (auto change_info = g_presenter->SurfaceChangedTestAndClear()) + { + if (void* handle = change_info->new_handle) + m_layer = MRCRetain(static_cast(handle)); + SetupSurface(); + } } void Metal::Gfx::SetupSurface() diff --git a/Source/Core/VideoBackends/OGL/OGLGfx.cpp b/Source/Core/VideoBackends/OGL/OGLGfx.cpp index ff5402ba03..50087a2f84 100644 --- a/Source/Core/VideoBackends/OGL/OGLGfx.cpp +++ b/Source/Core/VideoBackends/OGL/OGLGfx.cpp @@ -410,7 +410,6 @@ void OGLGfx::ClearRegion(const MathUtil::Rectangle& target_rc, bool colorEn bool OGLGfx::BindBackbuffer(const ClearColor& clear_color) { CheckForSurfaceChange(); - CheckForSurfaceResize(); SetAndClearFramebuffer(m_system_framebuffer.get(), clear_color); return true; } @@ -459,29 +458,20 @@ void OGLGfx::WaitForGPUIdle() void OGLGfx::CheckForSurfaceChange() { - if (!g_presenter->SurfaceChangedTestAndClear()) - return; + if (auto change_info = g_presenter->SurfaceChangedTestAndClear()) + { + if (void* handle = change_info->new_handle) + m_main_gl_context->UpdateSurface(handle); + else + m_main_gl_context->Update(); - m_main_gl_context->UpdateSurface(g_presenter->GetNewSurfaceHandle()); + u32 width = m_main_gl_context->GetBackBufferWidth(); + u32 height = m_main_gl_context->GetBackBufferHeight(); - u32 width = m_main_gl_context->GetBackBufferWidth(); - u32 height = m_main_gl_context->GetBackBufferHeight(); - - // With a surface change, the window likely has new dimensions. - g_presenter->SetBackbuffer(width, height); - m_system_framebuffer->UpdateDimensions(width, height); -} - -void OGLGfx::CheckForSurfaceResize() -{ - if (!g_presenter->SurfaceResizedTestAndClear()) - return; - - m_main_gl_context->Update(); - u32 width = m_main_gl_context->GetBackBufferWidth(); - u32 height = m_main_gl_context->GetBackBufferHeight(); - g_presenter->SetBackbuffer(width, height); - m_system_framebuffer->UpdateDimensions(width, height); + // With a surface change, the window likely has new dimensions. + g_presenter->SetBackbuffer(width, height); + m_system_framebuffer->UpdateDimensions(width, height); + } } void OGLGfx::BeginUtilityDrawing() diff --git a/Source/Core/VideoBackends/OGL/OGLGfx.h b/Source/Core/VideoBackends/OGL/OGLGfx.h index a76008fdc9..1fb376af6a 100644 --- a/Source/Core/VideoBackends/OGL/OGLGfx.h +++ b/Source/Core/VideoBackends/OGL/OGLGfx.h @@ -96,7 +96,6 @@ public: private: void CheckForSurfaceChange(); - void CheckForSurfaceResize(); void ApplyRasterizationState(const RasterizationState state); void ApplyDepthState(const DepthState state); diff --git a/Source/Core/VideoBackends/Software/SWGfx.cpp b/Source/Core/VideoBackends/Software/SWGfx.cpp index 7004c50864..241c76ca54 100644 --- a/Source/Core/VideoBackends/Software/SWGfx.cpp +++ b/Source/Core/VideoBackends/Software/SWGfx.cpp @@ -58,12 +58,12 @@ SWGfx::CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* dep bool SWGfx::BindBackbuffer(const ClearColor& clear_color) { // Look for framebuffer resizes - if (!g_presenter->SurfaceResizedTestAndClear()) - return true; - - GLContext* context = m_window->GetContext(); - context->Update(); - g_presenter->SetBackbuffer(context->GetBackBufferWidth(), context->GetBackBufferHeight()); + if (auto change_info = g_presenter->SurfaceChangedTestAndClear()) + { + GLContext* context = m_window->GetContext(); + context->Update(); + g_presenter->SetBackbuffer(context->GetBackBufferWidth(), context->GetBackBufferHeight()); + } return true; } diff --git a/Source/Core/VideoBackends/Vulkan/VKGfx.cpp b/Source/Core/VideoBackends/Vulkan/VKGfx.cpp index c88e422c98..09aaced21c 100644 --- a/Source/Core/VideoBackends/Vulkan/VKGfx.cpp +++ b/Source/Core/VideoBackends/Vulkan/VKGfx.cpp @@ -225,7 +225,6 @@ bool VKGfx::BindBackbuffer(const ClearColor& clear_color) // Handle host window resizes. CheckForSurfaceChange(); - CheckForSurfaceResize(); // Check for exclusive fullscreen request. if (m_swap_chain->GetCurrentFullscreenState() != m_swap_chain->GetNextFullscreenState() && @@ -358,7 +357,8 @@ void VKGfx::ExecuteCommandBuffer(bool submit_off_thread, bool wait_for_completio void VKGfx::CheckForSurfaceChange() { - if (!g_presenter->SurfaceChangedTestAndClear() || !m_swap_chain) + std::optional change_info; + if (!(change_info = g_presenter->SurfaceChangedTestAndClear()) || !m_swap_chain) return; // Submit the current draws up until rendering the XFB. @@ -367,35 +367,18 @@ void VKGfx::CheckForSurfaceChange() // Clear the present failed flag, since we don't want to resize after recreating. g_command_buffer_mgr->CheckLastPresentFail(); - // Recreate the surface. If this fails we're in trouble. - if (!m_swap_chain->RecreateSurface(g_presenter->GetNewSurfaceHandle())) - PanicAlertFmt("Failed to recreate Vulkan surface. Cannot continue."); - - // Handle case where the dimensions are now different. - OnSwapChainResized(); -} - -void VKGfx::CheckForSurfaceResize() -{ - if (!g_presenter->SurfaceResizedTestAndClear()) - return; - - // If we don't have a surface, how can we resize the swap chain? - // CheckForSurfaceChange should handle this case. - if (!m_swap_chain) + if (change_info->new_handle) { - WARN_LOG_FMT(VIDEO, "Surface resize event received without active surface, ignoring"); - return; + // Recreate the surface. If this fails we're in trouble. + if (!m_swap_chain->RecreateSurface(change_info->new_handle)) + PanicAlertFmt("Failed to recreate Vulkan surface. Cannot continue."); + } + else + { + m_swap_chain->RecreateSwapChain(); } - // Wait for the GPU to catch up since we're going to destroy the swap chain. - ExecuteCommandBuffer(false, true); - - // Clear the present failed flag, since we don't want to resize after recreating. - g_command_buffer_mgr->CheckLastPresentFail(); - - // Resize the swap chain. - m_swap_chain->RecreateSwapChain(); + // Handle case where the dimensions are now different. OnSwapChainResized(); } diff --git a/Source/Core/VideoBackends/Vulkan/VKGfx.h b/Source/Core/VideoBackends/Vulkan/VKGfx.h index e044bf59ca..05e8a671ed 100644 --- a/Source/Core/VideoBackends/Vulkan/VKGfx.h +++ b/Source/Core/VideoBackends/Vulkan/VKGfx.h @@ -89,7 +89,6 @@ public: private: void CheckForSurfaceChange(); - void CheckForSurfaceResize(); void ResetSamplerStates(); diff --git a/Source/Core/VideoCommon/Present.cpp b/Source/Core/VideoCommon/Present.cpp index 0691323c54..6427cd7fdb 100644 --- a/Source/Core/VideoCommon/Present.cpp +++ b/Source/Core/VideoCommon/Present.cpp @@ -534,24 +534,33 @@ void Presenter::ReleaseXFBContentLock() m_xfb_entry->ReleaseContentLock(); } -void Presenter::ChangeSurface(void* new_surface_handle) +void Presenter::ChangeSurface(void* new_surface_handle, u32 width, u32 height, float scale) { std::lock_guard lock(m_swap_mutex); - m_new_surface_handle = new_surface_handle; - m_surface_changed.Set(); + // If you ChangeSurface then ResizeSurface, don't forget about the surface change + // (null new_surface_handle => ResizeSurface) + if (new_surface_handle) + m_new_surface_handle = new_surface_handle; + m_new_surface_width = width; + m_new_surface_height = height; + m_new_surface_scale = scale; + // Actual data is accessed under the mutex, so this can be relaxed + m_surface_changed.store(true, std::memory_order_relaxed); } -void Presenter::ResizeSurface() +Presenter::SurfaceChangedInfo Presenter::SurfaceChangedGetAndClear() { std::lock_guard lock(m_swap_mutex); - m_surface_resized.Set(); -} - -void* Presenter::GetNewSurfaceHandle() -{ - void* handle = m_new_surface_handle; + SurfaceChangedInfo info = {}; + // clang-format off + info.new_handle = m_new_surface_handle; + info.new_width = m_new_surface_width; + info.new_height = m_new_surface_height; + info.new_scale = m_new_surface_scale; + // clang-format on m_new_surface_handle = nullptr; - return handle; + m_surface_changed.store(false, std::memory_order_relaxed); + return info; } u32 Presenter::AutoIntegralScale() const diff --git a/Source/Core/VideoCommon/Present.h b/Source/Core/VideoCommon/Present.h index 7e5ce651e3..9cff46cc3b 100644 --- a/Source/Core/VideoCommon/Present.h +++ b/Source/Core/VideoCommon/Present.h @@ -14,6 +14,8 @@ #include #include #include +#include +#include #include class AbstractTexture; @@ -82,11 +84,23 @@ public: VideoCommon::PostProcessing* GetPostProcessor() const { return m_post_processor.get(); } // Final surface changing // This is called when the surface is resized (WX) or the window changes (Android). - void ChangeSurface(void* new_surface_handle); - void ResizeSurface(); - bool SurfaceResizedTestAndClear() { return m_surface_resized.TestAndClear(); } - bool SurfaceChangedTestAndClear() { return m_surface_changed.TestAndClear(); } - void* GetNewSurfaceHandle(); + void ChangeSurface(void* new_surface_handle, u32 width, u32 height, float scale); + void ResizeSurface(u32 width, u32 height, float scale) + { + ChangeSurface(nullptr, width, height, scale); + } + struct SurfaceChangedInfo { + void* new_handle; ///< New surface handle if changed, else null + int new_width; ///< New surface width + int new_height; ///< New surface height + float new_scale; ///< New surface scale + }; + std::optional SurfaceChangedTestAndClear() + { + if (!m_surface_changed.load(std::memory_order_relaxed)) + return std::nullopt; + return SurfaceChangedGetAndClear(); + } void SetKeyMap(const DolphinKeyMap& key_map); @@ -132,8 +146,12 @@ private: AbstractTextureFormat m_backbuffer_format = AbstractTextureFormat::Undefined; void* m_new_surface_handle = nullptr; - Common::Flag m_surface_changed; - Common::Flag m_surface_resized; + int m_new_surface_width = 0; + int m_new_surface_height = 0; + float m_new_surface_scale = 1.f; + // note: Atomic for anti-tearing / anti-compiler-optimization only, write only under m_swap_mutex + std::atomic_bool m_surface_changed; + SurfaceChangedInfo SurfaceChangedGetAndClear(); // The presentation rectangle. // Width and height correspond to the final output resolution. From 7c685a863a5a6cd3c30d878642e9f5c275fc49d1 Mon Sep 17 00:00:00 2001 From: TellowKrinkle Date: Sun, 25 Jun 2023 19:06:11 -0500 Subject: [PATCH 02/10] VideoBackends:Metal: Use passed-in surface dimensions --- Source/Core/VideoBackends/Metal/MTLGfx.h | 6 ++++-- Source/Core/VideoBackends/Metal/MTLGfx.mm | 25 +++++++++++----------- Source/Core/VideoBackends/Metal/MTLMain.mm | 4 ++-- 3 files changed, 19 insertions(+), 16 deletions(-) diff --git a/Source/Core/VideoBackends/Metal/MTLGfx.h b/Source/Core/VideoBackends/Metal/MTLGfx.h index abaf845403..49de5f1c9f 100644 --- a/Source/Core/VideoBackends/Metal/MTLGfx.h +++ b/Source/Core/VideoBackends/Metal/MTLGfx.h @@ -10,6 +10,8 @@ #include "VideoBackends/Metal/MRCHelpers.h" +struct WindowSystemInfo; + namespace Metal { class Framebuffer; @@ -18,7 +20,7 @@ class Texture; class Gfx final : public ::AbstractGfx { public: - Gfx(MRCOwned layer); + Gfx(MRCOwned layer, const WindowSystemInfo& wsi); ~Gfx() override; bool IsHeadless() const override; @@ -84,6 +86,6 @@ private: std::array m_shader_counter = {}; void CheckForSurfaceChange(); - void SetupSurface(); + void SetupSurface(u32 width, u32 height, float scale); }; } // namespace Metal diff --git a/Source/Core/VideoBackends/Metal/MTLGfx.mm b/Source/Core/VideoBackends/Metal/MTLGfx.mm index d93860786a..f6f399b252 100644 --- a/Source/Core/VideoBackends/Metal/MTLGfx.mm +++ b/Source/Core/VideoBackends/Metal/MTLGfx.mm @@ -18,12 +18,13 @@ #include -Metal::Gfx::Gfx(MRCOwned layer) : m_layer(std::move(layer)) +Metal::Gfx::Gfx(MRCOwned layer, const WindowSystemInfo& wsi) + : m_layer(std::move(layer)) { UpdateActiveConfig(); [m_layer setDisplaySyncEnabled:g_ActiveConfig.bVSyncActive]; - SetupSurface(); + SetupSurface(wsi.render_surface_width, wsi.render_surface_height, wsi.render_surface_scale); g_state_tracker->FlushEncoders(); } @@ -491,24 +492,24 @@ void Metal::Gfx::CheckForSurfaceChange() { if (void* handle = change_info->new_handle) m_layer = MRCRetain(static_cast(handle)); - SetupSurface(); + SetupSurface(change_info->new_width, change_info->new_height, change_info->new_scale); } } -void Metal::Gfx::SetupSurface() +void Metal::Gfx::SetupSurface(u32 width, u32 height, float scale) { - auto info = GetSurfaceInfo(); + AbstractTextureFormat format = Util::ToAbstract([m_layer pixelFormat]); + [m_layer setContentsScale:scale]; + [m_layer setDrawableSize:{static_cast(width), static_cast(height)}]; - [m_layer setDrawableSize:{static_cast(info.width), static_cast(info.height)}]; - - TextureConfig cfg(info.width, info.height, 1, 1, 1, info.format, AbstractTextureFlag_RenderTarget, + TextureConfig cfg(width, height, 1, 1, 1, format, AbstractTextureFlag_RenderTarget, AbstractTextureType::Texture_2DArray); m_bb_texture = std::make_unique(nullptr, cfg); m_backbuffer = std::make_unique( - m_bb_texture.get(), nullptr, std::vector{}, info.width, info.height, 1, 1); + m_bb_texture.get(), nullptr, std::vector{}, width, height, 1, 1); if (g_presenter) - g_presenter->SetBackbuffer(info); + g_presenter->SetBackbuffer({ width, height, scale, format }); } SurfaceInfo Metal::Gfx::GetSurfaceInfo() const @@ -516,9 +517,9 @@ SurfaceInfo Metal::Gfx::GetSurfaceInfo() const if (!m_layer) // Headless return {}; - CGSize size = [m_layer bounds].size; + CGSize size = [m_layer drawableSize]; const float scale = [m_layer contentsScale]; - return {static_cast(size.width * scale), static_cast(size.height * scale), scale, + return {static_cast(size.width), static_cast(size.height), scale, Util::ToAbstract([m_layer pixelFormat])}; } diff --git a/Source/Core/VideoBackends/Metal/MTLMain.mm b/Source/Core/VideoBackends/Metal/MTLMain.mm index ff8480edda..3bec851536 100644 --- a/Source/Core/VideoBackends/Metal/MTLMain.mm +++ b/Source/Core/VideoBackends/Metal/MTLMain.mm @@ -126,8 +126,8 @@ bool Metal::VideoBackend::Initialize(const WindowSystemInfo& wsi) g_state_tracker = std::make_unique(); return InitializeShared( - std::make_unique(std::move(layer)), std::make_unique(), - std::make_unique(), std::make_unique()); + std::make_unique(std::move(layer), wsi), std::make_unique(), + std::make_unique(), std::make_unique()); } } From f545b49d12e84edd4c482111afc306024c3be598 Mon Sep 17 00:00:00 2001 From: TellowKrinkle Date: Sun, 25 Jun 2023 20:08:43 -0500 Subject: [PATCH 03/10] PlatformMacOS: Update layer scale on screen change Qt seems to do this, and if you don't, MVK doesn't realize it needs to resize things --- Source/Core/DolphinNoGUI/PlatformMacos.mm | 73 ++++++++++++----------- 1 file changed, 38 insertions(+), 35 deletions(-) diff --git a/Source/Core/DolphinNoGUI/PlatformMacos.mm b/Source/Core/DolphinNoGUI/PlatformMacos.mm index 7838eae527..18406040cd 100644 --- a/Source/Core/DolphinNoGUI/PlatformMacos.mm +++ b/Source/Core/DolphinNoGUI/PlatformMacos.mm @@ -21,6 +21,39 @@ #include #include +@class AppDelegate; + +class PlatformMacOS : public Platform +{ +public: + ~PlatformMacOS() override; + + bool Init() override; + void SetTitle(const std::string& title) override; + void MainLoop() override; + + WindowSystemInfo GetWindowSystemInfo() const override; + + NSWindow* Window() const { return m_window; } + +private: + void ProcessEvents(); + void UpdateWindowPosition(); + void HandleSaveStates(NSUInteger key, NSUInteger flags); + void SetupMenu(); + + NSRect m_window_rect; + NSWindow* m_window; + NSMenu* menuBar; + AppDelegate* m_app_delegate; + + int m_window_x = Config::Get(Config::MAIN_RENDER_WINDOW_XPOS); + int m_window_y = Config::Get(Config::MAIN_RENDER_WINDOW_YPOS); + unsigned int m_window_width = Config::Get(Config::MAIN_RENDER_WINDOW_WIDTH); + unsigned int m_window_height = Config::Get(Config::MAIN_RENDER_WINDOW_HEIGHT); + bool m_window_fullscreen = Config::Get(Config::MAIN_FULLSCREEN); +}; + @interface Application : NSApplication @property Platform* platform; - (void)shutdown; @@ -82,7 +115,7 @@ @interface AppDelegate : NSObject -@property(readonly) Platform* platform; +@property(readonly) PlatformMacOS* platform; - (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication*)sender; - (id)initWithPlatform:(Platform*)platform; @@ -95,7 +128,7 @@ return YES; } -- (id)initWithPlatform:(Platform*)platform +- (id)initWithPlatform:(PlatformMacOS*)platform { self = [super init]; if (self) @@ -115,42 +148,14 @@ - (void)windowDidChangeScreen:(NSNotification *)notification { + if (NSWindow* window = _platform->Window()) + if (CALayer* layer = [[window contentView] layer]) + [layer setContentsScale:[window backingScaleFactor]]; [self windowDidResize:notification]; } @end -namespace -{ -class PlatformMacOS : public Platform -{ -public: - ~PlatformMacOS() override; - - bool Init() override; - void SetTitle(const std::string& title) override; - void MainLoop() override; - - WindowSystemInfo GetWindowSystemInfo() const override; - -private: - void ProcessEvents(); - void UpdateWindowPosition(); - void HandleSaveStates(NSUInteger key, NSUInteger flags); - void SetupMenu(); - - NSRect m_window_rect; - NSWindow* m_window; - NSMenu* menuBar; - AppDelegate* m_app_delegate; - - int m_window_x = Config::Get(Config::MAIN_RENDER_WINDOW_XPOS); - int m_window_y = Config::Get(Config::MAIN_RENDER_WINDOW_YPOS); - unsigned int m_window_width = Config::Get(Config::MAIN_RENDER_WINDOW_WIDTH); - unsigned int m_window_height = Config::Get(Config::MAIN_RENDER_WINDOW_HEIGHT); - bool m_window_fullscreen = Config::Get(Config::MAIN_FULLSCREEN); -}; - PlatformMacOS::~PlatformMacOS() { [m_window close]; @@ -425,8 +430,6 @@ void PlatformMacOS::SetupMenu() } } -} // namespace - std::unique_ptr Platform::CreateMacOSPlatform() { return std::make_unique(); From d38c20cc1655c8ef62b7b6e46d6cc596c3c9baea Mon Sep 17 00:00:00 2001 From: TellowKrinkle Date: Sun, 25 Jun 2023 20:10:18 -0500 Subject: [PATCH 04/10] VideoBackends:Vulkan: Use external dimensions if driver doesn't give us any --- Source/Core/VideoBackends/Vulkan/VKGfx.cpp | 20 +++++++++------ .../Core/VideoBackends/Vulkan/VKSwapChain.cpp | 25 +++++++++++-------- .../Core/VideoBackends/Vulkan/VKSwapChain.h | 8 +++--- 3 files changed, 30 insertions(+), 23 deletions(-) diff --git a/Source/Core/VideoBackends/Vulkan/VKGfx.cpp b/Source/Core/VideoBackends/Vulkan/VKGfx.cpp index 09aaced21c..42b7e52965 100644 --- a/Source/Core/VideoBackends/Vulkan/VKGfx.cpp +++ b/Source/Core/VideoBackends/Vulkan/VKGfx.cpp @@ -262,18 +262,18 @@ bool VKGfx::BindBackbuffer(const ClearColor& clear_color) { // The present keeps returning exclusive mode lost unless we re-create the swap chain. INFO_LOG_FMT(VIDEO, "Lost exclusive fullscreen."); - m_swap_chain->RecreateSwapChain(); + m_swap_chain->RecreateSwapChain(0, 0); } else if (res == VK_SUBOPTIMAL_KHR || res == VK_ERROR_OUT_OF_DATE_KHR) { INFO_LOG_FMT(VIDEO, "Resizing swap chain due to suboptimal/out-of-date"); - m_swap_chain->ResizeSwapChain(); + m_swap_chain->ResizeSwapChain(0, 0); } else { ERROR_LOG_FMT(VIDEO, "Unknown present error {:#010X} {}, please report.", - std::to_underlying(res), VkResultToString(res)); - m_swap_chain->RecreateSwapChain(); + Common::ToUnderlying(res), VkResultToString(res)); + m_swap_chain->RecreateSwapChain(0, 0); } res = m_swap_chain->AcquireNextImage(); @@ -370,13 +370,17 @@ void VKGfx::CheckForSurfaceChange() if (change_info->new_handle) { // Recreate the surface. If this fails we're in trouble. - if (!m_swap_chain->RecreateSurface(change_info->new_handle)) + if (!m_swap_chain->RecreateSurface(change_info->new_handle, // + change_info->new_width, change_info->new_height)) + { PanicAlertFmt("Failed to recreate Vulkan surface. Cannot continue."); + } } else { - m_swap_chain->RecreateSwapChain(); + m_swap_chain->RecreateSwapChain(change_info->new_width, change_info->new_height); } + m_backbuffer_scale = change_info->new_scale; // Handle case where the dimensions are now different. OnSwapChainResized(); @@ -400,7 +404,7 @@ void VKGfx::OnConfigChanged(u32 bits) if (m_swap_chain && ((bits & CONFIG_CHANGE_BIT_STEREO_MODE) || (bits & CONFIG_CHANGE_BIT_HDR))) { ExecuteCommandBuffer(false, true); - m_swap_chain->RecreateSwapChain(); + m_swap_chain->RecreateSwapChain(0, 0); } // Wipe sampler cache if force texture filtering or anisotropy changes. @@ -413,7 +417,7 @@ void VKGfx::OnConfigChanged(u32 bits) void VKGfx::OnSwapChainResized() { - g_presenter->SetBackbuffer(m_swap_chain->GetWidth(), m_swap_chain->GetHeight()); + g_presenter->SetBackbuffer(GetSurfaceInfo()); } void VKGfx::BindFramebuffer(VKFramebuffer* fb) diff --git a/Source/Core/VideoBackends/Vulkan/VKSwapChain.cpp b/Source/Core/VideoBackends/Vulkan/VKSwapChain.cpp index 370e22d15c..e4944ad5fb 100644 --- a/Source/Core/VideoBackends/Vulkan/VKSwapChain.cpp +++ b/Source/Core/VideoBackends/Vulkan/VKSwapChain.cpp @@ -132,8 +132,11 @@ std::unique_ptr SwapChain::Create(const WindowSystemInfo& wsi, VkSurf bool vsync) { std::unique_ptr swap_chain = std::make_unique(wsi, surface, vsync); - if (!swap_chain->CreateSwapChain() || !swap_chain->SetupSwapChainImages()) + if (!swap_chain->CreateSwapChain(wsi.render_surface_width, wsi.render_surface_height) + || !swap_chain->SetupSwapChainImages()) + { return nullptr; + } return swap_chain; } @@ -271,7 +274,7 @@ bool SwapChain::SelectPresentMode() return true; } -bool SwapChain::CreateSwapChain() +bool SwapChain::CreateSwapChain(u32 width, u32 height) { // Look up surface properties to determine image count and dimensions VkSurfaceCapabilitiesKHR surface_capabilities; @@ -299,8 +302,8 @@ bool SwapChain::CreateSwapChain() VkExtent2D size = surface_capabilities.currentExtent; if (size.width == UINT32_MAX) { - size.width = std::max(g_presenter->GetBackbufferWidth(), 1); - size.height = std::max(g_presenter->GetBackbufferHeight(), 1); + size.width = width == 0 ? m_width : width; + size.height = height == 0 ? m_height : height; } size.width = std::clamp(size.width, surface_capabilities.minImageExtent.width, surface_capabilities.maxImageExtent.width); @@ -500,10 +503,10 @@ VkResult SwapChain::AcquireNextImage() return res; } -bool SwapChain::ResizeSwapChain() +bool SwapChain::ResizeSwapChain(u32 width, u32 height) { DestroySwapChainImages(); - if (!CreateSwapChain() || !SetupSwapChainImages()) + if (!CreateSwapChain(width, height) || !SetupSwapChainImages()) { PanicAlertFmt("Failed to re-configure swap chain images, this is fatal (for now)"); return false; @@ -512,11 +515,11 @@ bool SwapChain::ResizeSwapChain() return true; } -bool SwapChain::RecreateSwapChain() +bool SwapChain::RecreateSwapChain(u32 width, u32 height) { DestroySwapChainImages(); DestroySwapChain(); - if (!CreateSwapChain() || !SetupSwapChainImages()) + if (!CreateSwapChain(width, height) || !SetupSwapChainImages()) { PanicAlertFmt("Failed to re-configure swap chain images, this is fatal (for now)"); return false; @@ -532,7 +535,7 @@ bool SwapChain::SetVSync(bool enabled) // Recreate the swap chain with the new present mode. m_vsync_enabled = enabled; - return RecreateSwapChain(); + return RecreateSwapChain(m_width, m_height); } bool SwapChain::SetFullscreenState(bool state) @@ -568,7 +571,7 @@ bool SwapChain::SetFullscreenState(bool state) #endif } -bool SwapChain::RecreateSurface(void* native_handle) +bool SwapChain::RecreateSurface(void* native_handle, u32 width, u32 height) { // Destroy the old swap chain, images, and surface. DestroySwapChainImages(); @@ -604,7 +607,7 @@ bool SwapChain::RecreateSurface(void* native_handle) m_next_fullscreen_state = false; // Finally re-create the swap chain - if (!CreateSwapChain() || !SetupSwapChainImages()) + if (!CreateSwapChain(width, height) || !SetupSwapChainImages()) return false; return true; diff --git a/Source/Core/VideoBackends/Vulkan/VKSwapChain.h b/Source/Core/VideoBackends/Vulkan/VKSwapChain.h index 17334dbf97..99d39f8261 100644 --- a/Source/Core/VideoBackends/Vulkan/VKSwapChain.h +++ b/Source/Core/VideoBackends/Vulkan/VKSwapChain.h @@ -54,9 +54,9 @@ public: } VkResult AcquireNextImage(); - bool RecreateSurface(void* native_handle); - bool ResizeSwapChain(); - bool RecreateSwapChain(); + bool RecreateSurface(void* native_handle, u32 width, u32 height); + bool ResizeSwapChain(u32 width, u32 height); + bool RecreateSwapChain(u32 width, u32 height); // Change vsync enabled state. This may fail as it causes a swapchain recreation. bool SetVSync(bool enabled); @@ -76,7 +76,7 @@ private: bool SelectSurfaceFormat(); bool SelectPresentMode(); - bool CreateSwapChain(); + bool CreateSwapChain(u32 width, u32 height); void DestroySwapChain(); bool SetupSwapChainImages(); From 75c80d0520da304496a604679322c304fbcdd5bb Mon Sep 17 00:00:00 2001 From: TellowKrinkle Date: Sun, 25 Jun 2023 20:40:44 -0500 Subject: [PATCH 05/10] VideoBackends:OGL: Use provided dimensions --- Source/Core/Common/GL/GLContext.cpp | 7 ++- Source/Core/Common/GL/GLContext.h | 4 +- Source/Core/Common/GL/GLInterface/AGL.h | 2 +- Source/Core/Common/GL/GLInterface/AGL.mm | 43 ++++--------------- Source/Core/Common/GL/GLInterface/BGL.cpp | 2 +- Source/Core/Common/GL/GLInterface/BGL.h | 2 +- Source/Core/Common/GL/GLInterface/EGL.cpp | 5 ++- Source/Core/Common/GL/GLInterface/EGL.h | 2 +- .../Core/Common/GL/GLInterface/EGLAndroid.cpp | 2 - Source/Core/Common/GL/GLInterface/EGLX11.cpp | 2 +- Source/Core/Common/GL/GLInterface/EGLX11.h | 2 +- Source/Core/Common/GL/GLInterface/WGL.cpp | 11 ----- Source/Core/Common/GL/GLInterface/WGL.h | 2 - Source/Core/VideoBackends/OGL/OGLGfx.cpp | 7 +-- Source/Core/VideoBackends/Software/SWGfx.cpp | 4 +- .../VideoBackends/Software/SWOGLWindow.cpp | 1 - 16 files changed, 31 insertions(+), 67 deletions(-) diff --git a/Source/Core/Common/GL/GLContext.cpp b/Source/Core/Common/GL/GLContext.cpp index eef689616e..d2b0ae0076 100644 --- a/Source/Core/Common/GL/GLContext.cpp +++ b/Source/Core/Common/GL/GLContext.cpp @@ -54,12 +54,15 @@ bool GLContext::ClearCurrent() return false; } -void GLContext::Update() +void GLContext::Update(u32 width, u32 height) { + m_backbuffer_width = width; + m_backbuffer_height = height; } -void GLContext::UpdateSurface(void* window_handle) +void GLContext::UpdateSurface(void* window_handle, u32 width, u32 height) { + Update(width, height); } void GLContext::Swap() diff --git a/Source/Core/Common/GL/GLContext.h b/Source/Core/Common/GL/GLContext.h index b1619a647f..78f9083992 100644 --- a/Source/Core/Common/GL/GLContext.h +++ b/Source/Core/Common/GL/GLContext.h @@ -36,8 +36,8 @@ public: virtual bool MakeCurrent(); virtual bool ClearCurrent(); - virtual void Update(); - virtual void UpdateSurface(void* window_handle); + virtual void Update(u32 width, u32 height); + virtual void UpdateSurface(void* window_handle, u32 width, u32 height); virtual void Swap(); virtual void SwapInterval(int interval); diff --git a/Source/Core/Common/GL/GLInterface/AGL.h b/Source/Core/Common/GL/GLInterface/AGL.h index dda9fee0e3..41d5e199aa 100644 --- a/Source/Core/Common/GL/GLInterface/AGL.h +++ b/Source/Core/Common/GL/GLInterface/AGL.h @@ -28,7 +28,7 @@ public: bool MakeCurrent() override; bool ClearCurrent() override; - void Update() override; + void Update(u32 width, u32 height) override; void Swap() override; void SwapInterval(int interval) override; diff --git a/Source/Core/Common/GL/GLInterface/AGL.mm b/Source/Core/Common/GL/GLInterface/AGL.mm index 1b8ff224d1..407ea2407f 100644 --- a/Source/Core/Common/GL/GLInterface/AGL.mm +++ b/Source/Core/Common/GL/GLInterface/AGL.mm @@ -5,27 +5,7 @@ #include "Common/Logging/Log.h" -// UpdateCachedDimensions and AttachContextToView contain calls to UI APIs, so they must only be -// called from the main thread or they risk crashing! - -static bool UpdateCachedDimensions(NSView* view, u32* width, u32* height) -{ - NSWindow* window = [view window]; - NSSize size = [view frame].size; - - const CGFloat scale = [window backingScaleFactor]; - u32 new_width = static_cast(size.width * scale); - u32 new_height = static_cast(size.height * scale); - - if (*width == new_width && *height == new_height) - return false; - - *width = new_width; - *height = new_height; - return true; -} - -static bool AttachContextToView(NSOpenGLContext* context, NSView* view, u32* width, u32* height) +static bool AttachContextToView(NSOpenGLContext* context, NSView* view) { // Enable high-resolution display support. [view setWantsBestResolutionOpenGLSurface:YES]; @@ -37,8 +17,6 @@ static bool AttachContextToView(NSOpenGLContext* context, NSView* view, u32* wid return false; } - (void)UpdateCachedDimensions(view, width, height); - [context setView:view]; return true; @@ -98,16 +76,18 @@ bool GLContextAGL::Initialize(const WindowSystemInfo& wsi, bool stereo, bool cor m_view = static_cast(wsi.render_surface); m_opengl_mode = Mode::OpenGL; + m_backbuffer_width = wsi.render_surface_width; + m_backbuffer_height = wsi.render_surface_height; __block bool success; if ([NSThread isMainThread]) { - success = AttachContextToView(m_context, m_view, &m_backbuffer_width, &m_backbuffer_height); + success = AttachContextToView(m_context, m_view); } else { dispatch_sync(dispatch_get_main_queue(), ^{ - success = AttachContextToView(m_context, m_view, &m_backbuffer_width, &m_backbuffer_height); + success = AttachContextToView(m_context, m_view); }); } @@ -150,17 +130,10 @@ bool GLContextAGL::ClearCurrent() return true; } -void GLContextAGL::Update() +void GLContextAGL::Update(u32 width, u32 height) { - if (!m_view) - return; - - dispatch_sync(dispatch_get_main_queue(), ^{ - if (UpdateCachedDimensions(m_view, &m_backbuffer_width, &m_backbuffer_height)) - { - [m_context update]; - } - }); + GLContext::Update(width, height); + dispatch_sync(dispatch_get_main_queue(), ^{ [m_context update]; }); } void GLContextAGL::SwapInterval(int interval) diff --git a/Source/Core/Common/GL/GLInterface/BGL.cpp b/Source/Core/Common/GL/GLInterface/BGL.cpp index ac03e698a4..f9a06f36dd 100644 --- a/Source/Core/Common/GL/GLInterface/BGL.cpp +++ b/Source/Core/Common/GL/GLInterface/BGL.cpp @@ -70,7 +70,7 @@ void GLContextBGL::Swap() m_gl->SwapBuffers(); } -void GLContextBGL::Update() +void GLContextBGL::Update(u32, u32) { m_gl->LockLooper(); BRect size = m_gl->Frame(); diff --git a/Source/Core/Common/GL/GLInterface/BGL.h b/Source/Core/Common/GL/GLInterface/BGL.h index c36f2602dc..ef7c378f27 100644 --- a/Source/Core/Common/GL/GLInterface/BGL.h +++ b/Source/Core/Common/GL/GLInterface/BGL.h @@ -18,7 +18,7 @@ public: bool MakeCurrent() override; bool ClearCurrent() override; - void Update() override; + void Update(u32, u32) override; void Swap() override; diff --git a/Source/Core/Common/GL/GLInterface/EGL.cpp b/Source/Core/Common/GL/GLInterface/EGL.cpp index a0bf6dcbab..0d2017c9a3 100644 --- a/Source/Core/Common/GL/GLInterface/EGL.cpp +++ b/Source/Core/Common/GL/GLInterface/EGL.cpp @@ -145,6 +145,8 @@ bool GLContextEGL::Initialize(const WindowSystemInfo& wsi, bool stereo, bool cor bool supports_core_profile = false; m_wsi = wsi; + m_backbuffer_width = wsi.render_surface_width; + m_backbuffer_height = wsi.render_surface_height; m_egl_display = OpenEGLDisplay(); if (!m_egl_display) { @@ -346,8 +348,9 @@ bool GLContextEGL::MakeCurrent() return eglMakeCurrent(m_egl_display, m_egl_surface, m_egl_surface, m_egl_context); } -void GLContextEGL::UpdateSurface(void* window_handle) +void GLContextEGL::UpdateSurface(void* window_handle, u32 width, u32 height) { + GLContext::UpdateSurface(window_handle, width, height); m_wsi.render_surface = window_handle; ClearCurrent(); DestroyWindowSurface(); diff --git a/Source/Core/Common/GL/GLInterface/EGL.h b/Source/Core/Common/GL/GLInterface/EGL.h index bed1b31ecc..54cc5d11fe 100644 --- a/Source/Core/Common/GL/GLInterface/EGL.h +++ b/Source/Core/Common/GL/GLInterface/EGL.h @@ -22,7 +22,7 @@ public: bool MakeCurrent() override; bool ClearCurrent() override; - void UpdateSurface(void* window_handle) override; + void UpdateSurface(void* window_handle, u32 width, u32 height) override; void Swap() override; void SwapInterval(int interval) override; diff --git a/Source/Core/Common/GL/GLInterface/EGLAndroid.cpp b/Source/Core/Common/GL/GLInterface/EGLAndroid.cpp index 873387f7e9..d5419df352 100644 --- a/Source/Core/Common/GL/GLInterface/EGLAndroid.cpp +++ b/Source/Core/Common/GL/GLInterface/EGLAndroid.cpp @@ -15,7 +15,5 @@ EGLNativeWindowType GLContextEGLAndroid::GetEGLNativeWindow(EGLConfig config) EGLint format; eglGetConfigAttrib(m_egl_display, config, EGL_NATIVE_VISUAL_ID, &format); ANativeWindow_setBuffersGeometry(static_cast(m_wsi.render_surface), 0, 0, format); - m_backbuffer_width = ANativeWindow_getWidth(static_cast(m_wsi.render_surface)); - m_backbuffer_height = ANativeWindow_getHeight(static_cast(m_wsi.render_surface)); return static_cast(m_wsi.render_surface); } diff --git a/Source/Core/Common/GL/GLInterface/EGLX11.cpp b/Source/Core/Common/GL/GLInterface/EGLX11.cpp index f430898361..7d86402877 100644 --- a/Source/Core/Common/GL/GLInterface/EGLX11.cpp +++ b/Source/Core/Common/GL/GLInterface/EGLX11.cpp @@ -11,7 +11,7 @@ GLContextEGLX11::~GLContextEGLX11() m_render_window.reset(); } -void GLContextEGLX11::Update() +void GLContextEGLX11::Update(u32, u32) { m_render_window->UpdateDimensions(); m_backbuffer_width = m_render_window->GetWidth(); diff --git a/Source/Core/Common/GL/GLInterface/EGLX11.h b/Source/Core/Common/GL/GLInterface/EGLX11.h index 6f30333341..d7dc2fd3bc 100644 --- a/Source/Core/Common/GL/GLInterface/EGLX11.h +++ b/Source/Core/Common/GL/GLInterface/EGLX11.h @@ -13,7 +13,7 @@ class GLContextEGLX11 final : public GLContextEGL public: ~GLContextEGLX11() override; - void Update() override; + void Update(u32, u32) override; protected: EGLDisplay OpenEGLDisplay() override; diff --git a/Source/Core/Common/GL/GLInterface/WGL.cpp b/Source/Core/Common/GL/GLInterface/WGL.cpp index a85a27a79d..5bdd3bdb87 100644 --- a/Source/Core/Common/GL/GLInterface/WGL.cpp +++ b/Source/Core/Common/GL/GLInterface/WGL.cpp @@ -478,14 +478,3 @@ bool GLContextWGL::ClearCurrent() { return wglMakeCurrent(m_dc, nullptr) == TRUE; } - -// Update window width, size and etc. Called from Render.cpp -void GLContextWGL::Update() -{ - RECT rcWindow; - GetClientRect(m_window_handle, &rcWindow); - - // Get the new window width and height - m_backbuffer_width = rcWindow.right - rcWindow.left; - m_backbuffer_height = rcWindow.bottom - rcWindow.top; -} diff --git a/Source/Core/Common/GL/GLInterface/WGL.h b/Source/Core/Common/GL/GLInterface/WGL.h index 2f5a81e075..7068e14cca 100644 --- a/Source/Core/Common/GL/GLInterface/WGL.h +++ b/Source/Core/Common/GL/GLInterface/WGL.h @@ -19,8 +19,6 @@ public: bool MakeCurrent() override; bool ClearCurrent() override; - void Update() override; - void Swap() override; void SwapInterval(int interval) override; diff --git a/Source/Core/VideoBackends/OGL/OGLGfx.cpp b/Source/Core/VideoBackends/OGL/OGLGfx.cpp index 50087a2f84..7ffb7e5b89 100644 --- a/Source/Core/VideoBackends/OGL/OGLGfx.cpp +++ b/Source/Core/VideoBackends/OGL/OGLGfx.cpp @@ -461,15 +461,16 @@ void OGLGfx::CheckForSurfaceChange() if (auto change_info = g_presenter->SurfaceChangedTestAndClear()) { if (void* handle = change_info->new_handle) - m_main_gl_context->UpdateSurface(handle); + m_main_gl_context->UpdateSurface(handle, change_info->new_width, change_info->new_height); else - m_main_gl_context->Update(); + m_main_gl_context->Update(change_info->new_width, change_info->new_height); u32 width = m_main_gl_context->GetBackBufferWidth(); u32 height = m_main_gl_context->GetBackBufferHeight(); + m_backbuffer_scale = change_info->new_scale; // With a surface change, the window likely has new dimensions. - g_presenter->SetBackbuffer(width, height); + g_presenter->SetBackbuffer(GetSurfaceInfo()); m_system_framebuffer->UpdateDimensions(width, height); } } diff --git a/Source/Core/VideoBackends/Software/SWGfx.cpp b/Source/Core/VideoBackends/Software/SWGfx.cpp index 241c76ca54..f9dca07450 100644 --- a/Source/Core/VideoBackends/Software/SWGfx.cpp +++ b/Source/Core/VideoBackends/Software/SWGfx.cpp @@ -61,8 +61,8 @@ bool SWGfx::BindBackbuffer(const ClearColor& clear_color) if (auto change_info = g_presenter->SurfaceChangedTestAndClear()) { GLContext* context = m_window->GetContext(); - context->Update(); - g_presenter->SetBackbuffer(context->GetBackBufferWidth(), context->GetBackBufferHeight()); + context->Update(change_info->new_width, change_info->new_height); + g_presenter->SetBackbuffer(GetSurfaceInfo()); } return true; } diff --git a/Source/Core/VideoBackends/Software/SWOGLWindow.cpp b/Source/Core/VideoBackends/Software/SWOGLWindow.cpp index a002e3e519..61cf6cded2 100644 --- a/Source/Core/VideoBackends/Software/SWOGLWindow.cpp +++ b/Source/Core/VideoBackends/Software/SWOGLWindow.cpp @@ -88,7 +88,6 @@ void SWOGLWindow::ShowImage(const AbstractTexture* image, const MathUtil::Rectangle& xfb_region) { const SW::SWTexture* sw_image = static_cast(image); - m_gl_context->Update(); // just updates the render window position and the backbuffer size GLsizei glWidth = (GLsizei)m_gl_context->GetBackBufferWidth(); GLsizei glHeight = (GLsizei)m_gl_context->GetBackBufferHeight(); From cf77f97b2db7c595da3da9ec0fcc79364638ae00 Mon Sep 17 00:00:00 2001 From: TellowKrinkle Date: Sun, 18 Jun 2023 21:35:09 -0500 Subject: [PATCH 06/10] CMake: Wayland support --- CMake/FindWayland.cmake | 68 +++++++++++++++++++++++++++++++++++++++++ CMakeLists.txt | 6 ++++ 2 files changed, 74 insertions(+) create mode 100644 CMake/FindWayland.cmake diff --git a/CMake/FindWayland.cmake b/CMake/FindWayland.cmake new file mode 100644 index 0000000000..8b7e1863ca --- /dev/null +++ b/CMake/FindWayland.cmake @@ -0,0 +1,68 @@ +# Try to find Wayland on a Unix system +# +# This will define: +# +# Wayland_FOUND - True if Wayland is found +# +# The following imported targets: +# Wayland::Client - Imported Client +# Wayland::Server - Imported Server +# Wayland::Egl - Imported Egl +# Wayland::Cursor - Imported Cursor +# +# Copyright (c) 2013 Martin Gräßlin +# +# Redistribution and use is allowed according to the terms of the BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. + +IF (NOT WIN32) + IF (WAYLAND_INCLUDE_DIR AND WAYLAND_LIBRARIES) + # In the cache already + SET(WAYLAND_FIND_QUIETLY TRUE) + ENDIF () + + FIND_PATH(WAYLAND_CLIENT_INCLUDE_DIR NAMES wayland-client.h) + FIND_PATH(WAYLAND_SERVER_INCLUDE_DIR NAMES wayland-server.h) + FIND_PATH(WAYLAND_EGL_INCLUDE_DIR NAMES wayland-egl.h) + FIND_PATH(WAYLAND_CURSOR_INCLUDE_DIR NAMES wayland-cursor.h) + + FIND_LIBRARY(WAYLAND_CLIENT_LIBRARIES NAMES wayland-client) + FIND_LIBRARY(WAYLAND_SERVER_LIBRARIES NAMES wayland-server) + FIND_LIBRARY(WAYLAND_EGL_LIBRARIES NAMES wayland-egl) + FIND_LIBRARY(WAYLAND_CURSOR_LIBRARIES NAMES wayland-cursor) + + include(FindPackageHandleStandardArgs) + + # FIND_PACKAGE_HANDLE_STANDARD_ARGS is just meant to find the main package and set package found. Not set variables or find individual libs + FIND_PACKAGE_HANDLE_STANDARD_ARGS(Wayland REQUIRED_VARS + WAYLAND_CLIENT_LIBRARIES WAYLAND_CLIENT_INCLUDE_DIR + WAYLAND_SERVER_LIBRARIES WAYLAND_SERVER_INCLUDE_DIR + WAYLAND_EGL_LIBRARIES WAYLAND_EGL_INCLUDE_DIR + WAYLAND_CURSOR_LIBRARIES WAYLAND_CURSOR_INCLUDE_DIR + ) + + if (WAYLAND_CLIENT_INCLUDE_DIR AND WAYLAND_CLIENT_LIBRARIES AND NOT TARGET Wayland::Client) + add_library(Wayland::Client UNKNOWN IMPORTED) + set_target_properties(Wayland::Client PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${WAYLAND_CLIENT_INCLUDE_DIR}" IMPORTED_LOCATION "${WAYLAND_CLIENT_LIBRARIES}") + endif() + if (WAYLAND_SERVER_INCLUDE_DIR AND WAYLAND_SERVER_LIBRARIES AND NOT TARGET Wayland::Server) + add_library(Wayland::Server UNKNOWN IMPORTED) + set_target_properties(Wayland::Server PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${WAYLAND_SERVER_INCLUDE_DIR}" IMPORTED_LOCATION "${WAYLAND_SERVER_LIBRARIES}") + endif() + if (WAYLAND_EGL_INCLUDE_DIR AND WAYLAND_EGL_LIBRARIES AND NOT TARGET Wayland::Egl) + add_library(Wayland::Egl UNKNOWN IMPORTED) + set_target_properties(Wayland::Egl PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${WAYLAND_EGL_INCLUDE_DIR}" IMPORTED_LOCATION "${WAYLAND_EGL_LIBRARIES}") + endif() + if (WAYLAND_CURSOR_INCLUDE_DIR AND WAYLAND_CURSOR_LIBRARIES AND NOT TARGET Wayland::Cursor) + add_library(Wayland::Cursor UNKNOWN IMPORTED) + set_target_properties(Wayland::Cursor PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${WAYLAND_CURSOR_INCLUDE_DIR}" IMPORTED_LOCATION "${WAYLAND_CURSOR_LIBRARIES}") + endif() + + MARK_AS_ADVANCED( + WAYLAND_CLIENT_INCLUDE_DIR WAYLAND_CLIENT_LIBRARIES + WAYLAND_SERVER_INCLUDE_DIR WAYLAND_SERVER_LIBRARIES + WAYLAND_EGL_INCLUDE_DIR WAYLAND_EGL_LIBRARIES + WAYLAND_CURSOR_INCLUDE_DIR WAYLAND_CURSOR_LIBRARIES + ) + +ENDIF () \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index f07566c044..0c07af1811 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -67,6 +67,7 @@ set(DOLPHIN_DEFAULT_UPDATE_TRACK "" CACHE STRING "Name of the default update tra if(UNIX AND NOT APPLE AND NOT ANDROID) option(ENABLE_X11 "Enables X11 Support" ON) + option(ENABLE_WAYLAND "Enables Wayland support" ON) endif() if(NOT WIN32 AND NOT APPLE AND NOT HAIKU) option(ENABLE_EGL "Enables EGL OpenGL Interface" ON) @@ -514,6 +515,11 @@ if(ENABLE_X11) endif() endif() +if(ENABLE_WAYLAND) + find_package(Wayland REQUIRED) + add_definitions(-DHAVE_WAYLAND=1) +endif() + if(ENABLE_EGL) find_package(EGL) if(EGL_FOUND) From fe74d85dafb64f972c0fb789f3b6f6a4821e71f4 Mon Sep 17 00:00:00 2001 From: TellowKrinkle Date: Sun, 18 Jun 2023 21:42:46 -0500 Subject: [PATCH 07/10] VideoBackends:Vulkan: Wayland support --- .../Core/VideoBackends/Vulkan/VKSwapChain.cpp | 23 +++++++++++++++++++ .../VideoBackends/Vulkan/VulkanContext.cpp | 6 +++++ .../Vulkan/VulkanEntryPoints.inl | 4 ++++ .../Core/VideoBackends/Vulkan/VulkanLoader.h | 4 ++++ 4 files changed, 37 insertions(+) diff --git a/Source/Core/VideoBackends/Vulkan/VKSwapChain.cpp b/Source/Core/VideoBackends/Vulkan/VKSwapChain.cpp index e4944ad5fb..e65903ccd9 100644 --- a/Source/Core/VideoBackends/Vulkan/VKSwapChain.cpp +++ b/Source/Core/VideoBackends/Vulkan/VKSwapChain.cpp @@ -84,6 +84,29 @@ VkSurfaceKHR SwapChain::CreateVulkanSurface(VkInstance instance, const WindowSys } #endif +#if defined(VK_USE_PLATFORM_WAYLAND_KHR) + if (wsi.type == WindowSystemType::Wayland) + { + VkWaylandSurfaceCreateInfoKHR surface_create_info = { + VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR, // VkStructureType sType + nullptr, // const void* pNext + 0, // VkWaylandSurfaceCreateFlagsKHR flags + static_cast(wsi.display_connection), // struct wl_display* display + static_cast(wsi.render_surface) // struct wl_surface* surface + }; + + VkSurfaceKHR surface; + VkResult res = vkCreateWaylandSurfaceKHR(instance, &surface_create_info, nullptr, &surface); + if (res != VK_SUCCESS) + { + LOG_VULKAN_ERROR(res, "vkCreateWaylandSurfaceKHR failed: "); + return VK_NULL_HANDLE; + } + + return surface; + } +#endif + #if defined(VK_USE_PLATFORM_ANDROID_KHR) if (wsi.type == WindowSystemType::Android) { diff --git a/Source/Core/VideoBackends/Vulkan/VulkanContext.cpp b/Source/Core/VideoBackends/Vulkan/VulkanContext.cpp index d388300b6e..a4d3150d62 100644 --- a/Source/Core/VideoBackends/Vulkan/VulkanContext.cpp +++ b/Source/Core/VideoBackends/Vulkan/VulkanContext.cpp @@ -362,6 +362,12 @@ bool VulkanContext::SelectInstanceExtensions(std::vector* extension return false; } #endif +#if defined(VK_USE_PLATFORM_WAYLAND_KHR) + if (wstype == WindowSystemType::Wayland && !AddExtension(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME, true)) + { + return false; + } +#endif #if defined(VK_USE_PLATFORM_ANDROID_KHR) if (wstype == WindowSystemType::Android && !AddExtension(VK_KHR_ANDROID_SURFACE_EXTENSION_NAME, true)) diff --git a/Source/Core/VideoBackends/Vulkan/VulkanEntryPoints.inl b/Source/Core/VideoBackends/Vulkan/VulkanEntryPoints.inl index d716ce49d2..7d58e112d8 100644 --- a/Source/Core/VideoBackends/Vulkan/VulkanEntryPoints.inl +++ b/Source/Core/VideoBackends/Vulkan/VulkanEntryPoints.inl @@ -49,6 +49,10 @@ VULKAN_INSTANCE_ENTRY_POINT(vkCreateXlibSurfaceKHR, false) VULKAN_INSTANCE_ENTRY_POINT(vkGetPhysicalDeviceXlibPresentationSupportKHR, false) #endif +#if defined(VK_USE_PLATFORM_WAYLAND_KHR) +VULKAN_INSTANCE_ENTRY_POINT(vkCreateWaylandSurfaceKHR, false) +#endif + #if defined(VK_USE_PLATFORM_ANDROID_KHR) VULKAN_INSTANCE_ENTRY_POINT(vkCreateAndroidSurfaceKHR, false) #endif diff --git a/Source/Core/VideoBackends/Vulkan/VulkanLoader.h b/Source/Core/VideoBackends/Vulkan/VulkanLoader.h index 33784d5d2e..af7427b9bd 100644 --- a/Source/Core/VideoBackends/Vulkan/VulkanLoader.h +++ b/Source/Core/VideoBackends/Vulkan/VulkanLoader.h @@ -13,6 +13,10 @@ #define VK_USE_PLATFORM_XLIB_KHR #endif +#if defined(HAVE_WAYLAND) +#define VK_USE_PLATFORM_WAYLAND_KHR +#endif + #if defined(ANDROID) #define VK_USE_PLATFORM_ANDROID_KHR #endif From 4fb515a86d744e11f33ef058512a2d98ea8bc917 Mon Sep 17 00:00:00 2001 From: TellowKrinkle Date: Sun, 25 Jun 2023 22:37:15 -0500 Subject: [PATCH 08/10] VideoBackends:OGL: Wayland support --- Source/Core/Common/CMakeLists.txt | 7 +++ Source/Core/Common/GL/GLContext.cpp | 10 ++++ .../Core/Common/GL/GLInterface/EGLWayland.cpp | 47 +++++++++++++++++++ .../Core/Common/GL/GLInterface/EGLWayland.h | 28 +++++++++++ 4 files changed, 92 insertions(+) create mode 100644 Source/Core/Common/GL/GLInterface/EGLWayland.cpp create mode 100644 Source/Core/Common/GL/GLInterface/EGLWayland.h diff --git a/Source/Core/Common/CMakeLists.txt b/Source/Core/Common/CMakeLists.txt index 894fd38128..49d8402b1d 100644 --- a/Source/Core/Common/CMakeLists.txt +++ b/Source/Core/Common/CMakeLists.txt @@ -308,6 +308,13 @@ if(ENABLE_EGL AND EGL_FOUND) target_link_libraries(common PUBLIC ${EGL_LIBRARIES}) endif() +if(ENABLE_WAYLAND) + target_sources(common PRIVATE + GL/GLInterface/EGLWayland.cpp + GL/GLInterface/EGLWayland.h + ) +endif() + if(WIN32) target_sources(common PRIVATE CompatPatches.cpp diff --git a/Source/Core/Common/GL/GLContext.cpp b/Source/Core/Common/GL/GLContext.cpp index d2b0ae0076..67372c4f73 100644 --- a/Source/Core/Common/GL/GLContext.cpp +++ b/Source/Core/Common/GL/GLContext.cpp @@ -19,6 +19,9 @@ #if HAVE_X11 #include "Common/GL/GLInterface/EGLX11.h" #endif +#if HAVE_WAYLAND +#include "Common/GL/GLInterface/EGLWayland.h" +#endif #if defined(ANDROID) #include "Common/GL/GLInterface/EGLAndroid.h" #endif @@ -103,6 +106,13 @@ std::unique_ptr GLContext::Create(const WindowSystemInfo& wsi, bool s if (wsi.type == WindowSystemType::X11) context = std::make_unique(); #endif + +#endif +#if HAVE_WAYLAND && HAVE_EGL + if (wsi.type == WindowSystemType::Wayland) + context = std::make_unique(); +#endif +#if HAVE_EGL if (wsi.type == WindowSystemType::Headless || wsi.type == WindowSystemType::FBDev) context = std::make_unique(); #endif diff --git a/Source/Core/Common/GL/GLInterface/EGLWayland.cpp b/Source/Core/Common/GL/GLInterface/EGLWayland.cpp new file mode 100644 index 0000000000..1571f2de6f --- /dev/null +++ b/Source/Core/Common/GL/GLInterface/EGLWayland.cpp @@ -0,0 +1,47 @@ +// Copyright 2023 Dolphin Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "Common/GL/GLInterface/EGLWayland.h" +#include "Common/MsgHandler.h" + +GLContextEGLWayland::~GLContextEGLWayland() +{ + if (m_window) + m_wl_egl_window_destroy(m_window); +} + +void GLContextEGLWayland::Update(u32 width, u32 height) +{ + GLContext::Update(width, height); + if (m_window) + m_wl_egl_window_resize(m_window, width, height, 0, 0); +} + +EGLDisplay GLContextEGLWayland::OpenEGLDisplay() +{ + return eglGetDisplay(static_cast(m_wsi.display_connection)); +} + +EGLNativeWindowType GLContextEGLWayland::GetEGLNativeWindow(EGLConfig config) +{ + if (!m_wayland_lib.IsOpen()) + { + std::string name = Common::DynamicLibrary::GetVersionedFilename("wayland-egl", 1); + m_wayland_lib.Open(name.c_str()); + if (!m_wayland_lib.IsOpen()) + { + PanicAlertFmt("Failed to load {}", name); + return reinterpret_cast(m_window); + } +#define LOAD(x) m_wayland_lib.GetSymbol(#x, &m_##x) + LOAD(wl_egl_window_create); + LOAD(wl_egl_window_destroy); + LOAD(wl_egl_window_resize); +#undef LOAD + } + if (m_window) + m_wl_egl_window_destroy(m_window); + m_window = m_wl_egl_window_create(static_cast(m_wsi.render_surface), + m_wsi.render_surface_width, m_wsi.render_surface_height); + return reinterpret_cast(m_window); +} diff --git a/Source/Core/Common/GL/GLInterface/EGLWayland.h b/Source/Core/Common/GL/GLInterface/EGLWayland.h new file mode 100644 index 0000000000..73cc90064b --- /dev/null +++ b/Source/Core/Common/GL/GLInterface/EGLWayland.h @@ -0,0 +1,28 @@ +// Copyright 2023 Dolphin Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include +#include "Common/DynamicLibrary.h" +#include "Common/GL/GLInterface/EGL.h" + +struct wl_egl_window; +struct wl_surface; + +class GLContextEGLWayland final : public GLContextEGL +{ +public: + ~GLContextEGLWayland() override; + + void Update(u32 width, u32 height) override; + +protected: + EGLDisplay OpenEGLDisplay() override; + EGLNativeWindowType GetEGLNativeWindow(EGLConfig config) override; + Common::DynamicLibrary m_wayland_lib; + wl_egl_window* (*m_wl_egl_window_create)(wl_surface* surface, int width, int height); + void (*m_wl_egl_window_destroy)(wl_egl_window* window); + void (*m_wl_egl_window_resize)(wl_egl_window* window, int width, int height, int dx, int dy); + wl_egl_window* m_window = nullptr; +}; From 1ef814ef2849b834d009189fc335093a2566a837 Mon Sep 17 00:00:00 2001 From: BeezBumba <130922034+BeezBumba@users.noreply.github.com> Date: Wed, 13 May 2026 23:55:02 +0000 Subject: [PATCH 09/10] Fix merge errors --- Source/Core/Common/CMakeLists.txt | 2 +- Source/Core/Common/GL/GLContext.cpp | 4 ++-- Source/Core/DolphinQt/Main.cpp | 8 ++++---- Source/Core/DolphinQt/MainWindow.cpp | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Source/Core/Common/CMakeLists.txt b/Source/Core/Common/CMakeLists.txt index 49d8402b1d..b233b24e14 100644 --- a/Source/Core/Common/CMakeLists.txt +++ b/Source/Core/Common/CMakeLists.txt @@ -308,7 +308,7 @@ if(ENABLE_EGL AND EGL_FOUND) target_link_libraries(common PUBLIC ${EGL_LIBRARIES}) endif() -if(ENABLE_WAYLAND) +if(ENABLE_WAYLAND AND ENABLE_EGL AND EGL_FOUND) target_sources(common PRIVATE GL/GLInterface/EGLWayland.cpp GL/GLInterface/EGLWayland.h diff --git a/Source/Core/Common/GL/GLContext.cpp b/Source/Core/Common/GL/GLContext.cpp index 67372c4f73..2cf2d32a5a 100644 --- a/Source/Core/Common/GL/GLContext.cpp +++ b/Source/Core/Common/GL/GLContext.cpp @@ -19,7 +19,7 @@ #if HAVE_X11 #include "Common/GL/GLInterface/EGLX11.h" #endif -#if HAVE_WAYLAND +#if HAVE_EGL && HAVE_WAYLAND #include "Common/GL/GLInterface/EGLWayland.h" #endif #if defined(ANDROID) @@ -108,7 +108,7 @@ std::unique_ptr GLContext::Create(const WindowSystemInfo& wsi, bool s #endif #endif -#if HAVE_WAYLAND && HAVE_EGL +#if HAVE_EGL && HAVE_WAYLAND if (wsi.type == WindowSystemType::Wayland) context = std::make_unique(); #endif diff --git a/Source/Core/DolphinQt/Main.cpp b/Source/Core/DolphinQt/Main.cpp index b223819e7a..e731392ae7 100644 --- a/Source/Core/DolphinQt/Main.cpp +++ b/Source/Core/DolphinQt/Main.cpp @@ -149,14 +149,14 @@ int main(int argc, char* argv[]) #if (QT_VERSION >= QT_VERSION_CHECK(6, 3, 0)) setenv("QT_XCB_NO_XI2", "1", true); #endif - // Dolphin currently doesn't work on Wayland (Only the UI does, games do not launch.) This makes - // XCB the default and forces it on if the platform is specified to be wayland, to prevent this - // from happening. - // For more information: https://bugs.dolphin-emu.org/issues/11807 +#if !HAVE_WAYLAND + // If Dolphin was built without Wayland support, force XCB when the platform is explicitly set to + // Wayland so users get a working backend. const char* current_qt_platform = getenv("QT_QPA_PLATFORM"); const bool replace_qt_platform = current_qt_platform != nullptr && Common::CaseInsensitiveContains(current_qt_platform, "wayland"); setenv("QT_QPA_PLATFORM", "xcb", replace_qt_platform); +#endif #endif QCoreApplication::setOrganizationName(QStringLiteral("Dolphin Emulator")); diff --git a/Source/Core/DolphinQt/MainWindow.cpp b/Source/Core/DolphinQt/MainWindow.cpp index ecf1511cfc..89a7b1a93a 100644 --- a/Source/Core/DolphinQt/MainWindow.cpp +++ b/Source/Core/DolphinQt/MainWindow.cpp @@ -168,7 +168,7 @@ static WindowSystemType GetWindowSystemType() return WindowSystemType::MacOS; else if (platform_name == QStringLiteral("xcb")) return WindowSystemType::X11; - else if (platform_name == QStringLiteral("wayland")) + else if (platform_name.startsWith(QStringLiteral("wayland"))) return WindowSystemType::Wayland; else if (platform_name == QStringLiteral("haiku")) return WindowSystemType::Haiku; From a6b4f8720a152d57da51ce08cbd5b912664836eb Mon Sep 17 00:00:00 2001 From: BeezBumba <130922034+BeezBumba@users.noreply.github.com> Date: Tue, 19 May 2026 11:05:09 +0000 Subject: [PATCH 10/10] added dev feedback --- CMakeLists.txt | 9 +++++++-- Source/Android/jni/MainAndroid.cpp | 14 ++++++++++++-- Source/Core/Common/CMakeLists.txt | 2 +- Source/Core/Common/GL/GLContext.cpp | 1 - Source/Core/Common/GL/GLInterface/AGL.mm | 4 +++- Source/Core/Common/GL/GLInterface/EGLWayland.h | 2 +- Source/Core/DolphinNoGUI/PlatformMacos.mm | 2 +- Source/Core/DolphinQt/RenderWidget.cpp | 17 ----------------- Source/Core/VideoBackends/D3D/D3DGfx.cpp | 15 +++++++++------ Source/Core/VideoBackends/D3D12/D3D12Gfx.cpp | 15 +++++++++------ Source/Core/VideoBackends/Metal/MTLGfx.mm | 4 ++-- Source/Core/VideoBackends/Metal/MTLMain.mm | 6 +++--- Source/Core/VideoBackends/Vulkan/VKGfx.cpp | 2 +- .../Core/VideoBackends/Vulkan/VKSwapChain.cpp | 4 ++-- .../Core/VideoBackends/Vulkan/VulkanContext.cpp | 3 ++- Source/Core/VideoCommon/Present.h | 3 ++- 16 files changed, 55 insertions(+), 48 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0c07af1811..6fac75cbb4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -516,8 +516,13 @@ if(ENABLE_X11) endif() if(ENABLE_WAYLAND) - find_package(Wayland REQUIRED) - add_definitions(-DHAVE_WAYLAND=1) + find_package(Wayland) + if(Wayland_FOUND) + add_definitions(-DHAVE_WAYLAND=1) + message(STATUS "Wayland support enabled") + else() + message(WARNING "Wayland support enabled but not found. This build will not support Wayland.") + endif() endif() if(ENABLE_EGL) diff --git a/Source/Android/jni/MainAndroid.cpp b/Source/Android/jni/MainAndroid.cpp index a25d4a1d4a..95101c6a54 100644 --- a/Source/Android/jni/MainAndroid.cpp +++ b/Source/Android/jni/MainAndroid.cpp @@ -85,6 +85,8 @@ Common::Flag s_is_booting; bool s_game_metadata_is_valid = false; } // Anonymous namespace +static float GetRenderSurfaceScale(JNIEnv* env); + void UpdatePointer() { // Update touch pointer @@ -447,7 +449,11 @@ JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SurfaceChang __android_log_print(ANDROID_LOG_ERROR, DOLPHIN_TAG, "Error: Surface is null."); if (g_presenter) - g_presenter->ChangeSurface(s_surf); + { + const u32 width = s_surf ? static_cast(ANativeWindow_getWidth(s_surf)) : 0; + const u32 height = s_surf ? static_cast(ANativeWindow_getHeight(s_surf)) : 0; + g_presenter->ChangeSurface(s_surf, width, height, GetRenderSurfaceScale(env)); + } s_surface_cv.notify_all(); } @@ -470,7 +476,11 @@ JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SurfaceDestr std::lock_guard surface_guard(s_surface_lock); if (g_presenter) - g_presenter->ChangeSurface(nullptr); + { + g_presenter->ChangeSurface(nullptr, g_presenter->GetBackbufferWidth(), + g_presenter->GetBackbufferHeight(), + g_presenter->GetBackbufferScale()); + } if (s_surf) { diff --git a/Source/Core/Common/CMakeLists.txt b/Source/Core/Common/CMakeLists.txt index b233b24e14..39e9821fa0 100644 --- a/Source/Core/Common/CMakeLists.txt +++ b/Source/Core/Common/CMakeLists.txt @@ -308,7 +308,7 @@ if(ENABLE_EGL AND EGL_FOUND) target_link_libraries(common PUBLIC ${EGL_LIBRARIES}) endif() -if(ENABLE_WAYLAND AND ENABLE_EGL AND EGL_FOUND) +if(ENABLE_WAYLAND AND WAYLAND_FOUND AND ENABLE_EGL AND EGL_FOUND) target_sources(common PRIVATE GL/GLInterface/EGLWayland.cpp GL/GLInterface/EGLWayland.h diff --git a/Source/Core/Common/GL/GLContext.cpp b/Source/Core/Common/GL/GLContext.cpp index 2cf2d32a5a..3c0f251bfb 100644 --- a/Source/Core/Common/GL/GLContext.cpp +++ b/Source/Core/Common/GL/GLContext.cpp @@ -106,7 +106,6 @@ std::unique_ptr GLContext::Create(const WindowSystemInfo& wsi, bool s if (wsi.type == WindowSystemType::X11) context = std::make_unique(); #endif - #endif #if HAVE_EGL && HAVE_WAYLAND if (wsi.type == WindowSystemType::Wayland) diff --git a/Source/Core/Common/GL/GLInterface/AGL.mm b/Source/Core/Common/GL/GLInterface/AGL.mm index 407ea2407f..e3d8d216e5 100644 --- a/Source/Core/Common/GL/GLInterface/AGL.mm +++ b/Source/Core/Common/GL/GLInterface/AGL.mm @@ -133,7 +133,9 @@ bool GLContextAGL::ClearCurrent() void GLContextAGL::Update(u32 width, u32 height) { GLContext::Update(width, height); - dispatch_sync(dispatch_get_main_queue(), ^{ [m_context update]; }); + dispatch_sync(dispatch_get_main_queue(), ^{ + [m_context update]; + }); } void GLContextAGL::SwapInterval(int interval) diff --git a/Source/Core/Common/GL/GLInterface/EGLWayland.h b/Source/Core/Common/GL/GLInterface/EGLWayland.h index 73cc90064b..b0ef09ce4d 100644 --- a/Source/Core/Common/GL/GLInterface/EGLWayland.h +++ b/Source/Core/Common/GL/GLInterface/EGLWayland.h @@ -3,7 +3,7 @@ #pragma once -#include +#include #include "Common/DynamicLibrary.h" #include "Common/GL/GLInterface/EGL.h" diff --git a/Source/Core/DolphinNoGUI/PlatformMacos.mm b/Source/Core/DolphinNoGUI/PlatformMacos.mm index 18406040cd..3c22b23bae 100644 --- a/Source/Core/DolphinNoGUI/PlatformMacos.mm +++ b/Source/Core/DolphinNoGUI/PlatformMacos.mm @@ -146,7 +146,7 @@ private: info.render_surface_scale); } -- (void)windowDidChangeScreen:(NSNotification *)notification +- (void)windowDidChangeScreen:(NSNotification*)notification { if (NSWindow* window = _platform->Window()) if (CALayer* layer = [[window contentView] layer]) diff --git a/Source/Core/DolphinQt/RenderWidget.cpp b/Source/Core/DolphinQt/RenderWidget.cpp index af383fe267..7231732d42 100644 --- a/Source/Core/DolphinQt/RenderWidget.cpp +++ b/Source/Core/DolphinQt/RenderWidget.cpp @@ -128,23 +128,6 @@ void RenderWidget::dropEvent(QDropEvent* event) State::LoadAs(Core::System::GetInstance(), path.toStdString()); } -<<<<<<< HEAD -void RenderWidget::OnHandleChanged(void* handle) -{ - if (handle) - { -#ifdef _WIN32 - // Remove rounded corners from the render window on Windows 11 - const DWM_WINDOW_CORNER_PREFERENCE corner_preference = DWMWCP_DONOTROUND; - DwmSetWindowAttribute(static_cast(handle), DWMWA_WINDOW_CORNER_PREFERENCE, - &corner_preference, sizeof(corner_preference)); -#endif - } - Host::GetInstance()->SetRenderHandle(handle); -} - -======= ->>>>>>> 780f8e1d17 (VideoCommon:Presenter: Surface resizes include window dimensions) void RenderWidget::OnHideCursorChanged() { UpdateCursor(); diff --git a/Source/Core/VideoBackends/D3D/D3DGfx.cpp b/Source/Core/VideoBackends/D3D/D3DGfx.cpp index dc7ee37908..3254832758 100644 --- a/Source/Core/VideoBackends/D3D/D3DGfx.cpp +++ b/Source/Core/VideoBackends/D3D/D3DGfx.cpp @@ -184,22 +184,25 @@ void Gfx::OnConfigChanged(u32 bits) void Gfx::CheckForSwapChainChanges() { - const bool surface_changed = g_presenter->SurfaceChangedTestAndClear(); + const auto change_info = g_presenter->SurfaceChangedTestAndClear(); const bool surface_resized = - g_presenter->SurfaceResizedTestAndClear() || m_swap_chain->CheckForFullscreenChange(); - if (!surface_changed && !surface_resized) + (change_info && !change_info->new_handle) || m_swap_chain->CheckForFullscreenChange(); + if (!change_info && !surface_resized) return; - if (surface_changed) + if (change_info && change_info->new_handle) { - m_swap_chain->ChangeSurface(g_presenter->GetNewSurfaceHandle()); + m_swap_chain->ChangeSurface(change_info->new_handle); } else { m_swap_chain->ResizeSwapChain(); } - g_presenter->SetBackbuffer(m_swap_chain->GetWidth(), m_swap_chain->GetHeight()); + if (change_info) + m_backbuffer_scale = change_info->new_scale; + + g_presenter->SetBackbuffer(GetSurfaceInfo()); } void Gfx::SetFramebuffer(AbstractFramebuffer* framebuffer) diff --git a/Source/Core/VideoBackends/D3D12/D3D12Gfx.cpp b/Source/Core/VideoBackends/D3D12/D3D12Gfx.cpp index cc89b492e6..69e36b102d 100644 --- a/Source/Core/VideoBackends/D3D12/D3D12Gfx.cpp +++ b/Source/Core/VideoBackends/D3D12/D3D12Gfx.cpp @@ -374,24 +374,27 @@ bool Gfx::BindBackbuffer(const ClearColor& clear_color) void Gfx::CheckForSwapChainChanges() { - const bool surface_changed = g_presenter->SurfaceChangedTestAndClear(); + const auto change_info = g_presenter->SurfaceChangedTestAndClear(); const bool surface_resized = - g_presenter->SurfaceResizedTestAndClear() || m_swap_chain->CheckForFullscreenChange(); - if (!surface_changed && !surface_resized) + (change_info && !change_info->new_handle) || m_swap_chain->CheckForFullscreenChange(); + if (!change_info && !surface_resized) return; // The swap chain could be in use from a previous frame. WaitForGPUIdle(); - if (surface_changed) + if (change_info && change_info->new_handle) { - m_swap_chain->ChangeSurface(g_presenter->GetNewSurfaceHandle()); + m_swap_chain->ChangeSurface(change_info->new_handle); } else { m_swap_chain->ResizeSwapChain(); } - g_presenter->SetBackbuffer(m_swap_chain->GetWidth(), m_swap_chain->GetHeight()); + if (change_info) + m_backbuffer_scale = change_info->new_scale; + + g_presenter->SetBackbuffer(GetSurfaceInfo()); } void Gfx::PresentBackbuffer() diff --git a/Source/Core/VideoBackends/Metal/MTLGfx.mm b/Source/Core/VideoBackends/Metal/MTLGfx.mm index f6f399b252..dcbe6cc3d2 100644 --- a/Source/Core/VideoBackends/Metal/MTLGfx.mm +++ b/Source/Core/VideoBackends/Metal/MTLGfx.mm @@ -19,7 +19,7 @@ #include Metal::Gfx::Gfx(MRCOwned layer, const WindowSystemInfo& wsi) - : m_layer(std::move(layer)) + : m_layer(std::move(layer)) { UpdateActiveConfig(); [m_layer setDisplaySyncEnabled:g_ActiveConfig.bVSyncActive]; @@ -509,7 +509,7 @@ void Metal::Gfx::SetupSurface(u32 width, u32 height, float scale) m_bb_texture.get(), nullptr, std::vector{}, width, height, 1, 1); if (g_presenter) - g_presenter->SetBackbuffer({ width, height, scale, format }); + g_presenter->SetBackbuffer({width, height, scale, format}); } SurfaceInfo Metal::Gfx::GetSurfaceInfo() const diff --git a/Source/Core/VideoBackends/Metal/MTLMain.mm b/Source/Core/VideoBackends/Metal/MTLMain.mm index 3bec851536..9ef0fd90c5 100644 --- a/Source/Core/VideoBackends/Metal/MTLMain.mm +++ b/Source/Core/VideoBackends/Metal/MTLMain.mm @@ -125,9 +125,9 @@ bool Metal::VideoBackend::Initialize(const WindowSystemInfo& wsi) ObjectCache::Initialize(std::move(adapter)); g_state_tracker = std::make_unique(); - return InitializeShared( - std::make_unique(std::move(layer), wsi), std::make_unique(), - std::make_unique(), std::make_unique()); + return InitializeShared(std::make_unique(std::move(layer), wsi), + std::make_unique(), std::make_unique(), + std::make_unique()); } } diff --git a/Source/Core/VideoBackends/Vulkan/VKGfx.cpp b/Source/Core/VideoBackends/Vulkan/VKGfx.cpp index 42b7e52965..22e6e5c74c 100644 --- a/Source/Core/VideoBackends/Vulkan/VKGfx.cpp +++ b/Source/Core/VideoBackends/Vulkan/VKGfx.cpp @@ -272,7 +272,7 @@ bool VKGfx::BindBackbuffer(const ClearColor& clear_color) else { ERROR_LOG_FMT(VIDEO, "Unknown present error {:#010X} {}, please report.", - Common::ToUnderlying(res), VkResultToString(res)); + std::to_underlying(res), VkResultToString(res)); m_swap_chain->RecreateSwapChain(0, 0); } diff --git a/Source/Core/VideoBackends/Vulkan/VKSwapChain.cpp b/Source/Core/VideoBackends/Vulkan/VKSwapChain.cpp index e65903ccd9..7e42ec654b 100644 --- a/Source/Core/VideoBackends/Vulkan/VKSwapChain.cpp +++ b/Source/Core/VideoBackends/Vulkan/VKSwapChain.cpp @@ -155,8 +155,8 @@ std::unique_ptr SwapChain::Create(const WindowSystemInfo& wsi, VkSurf bool vsync) { std::unique_ptr swap_chain = std::make_unique(wsi, surface, vsync); - if (!swap_chain->CreateSwapChain(wsi.render_surface_width, wsi.render_surface_height) - || !swap_chain->SetupSwapChainImages()) + if (!swap_chain->CreateSwapChain(wsi.render_surface_width, wsi.render_surface_height) || + !swap_chain->SetupSwapChainImages()) { return nullptr; } diff --git a/Source/Core/VideoBackends/Vulkan/VulkanContext.cpp b/Source/Core/VideoBackends/Vulkan/VulkanContext.cpp index a4d3150d62..641b54216c 100644 --- a/Source/Core/VideoBackends/Vulkan/VulkanContext.cpp +++ b/Source/Core/VideoBackends/Vulkan/VulkanContext.cpp @@ -363,7 +363,8 @@ bool VulkanContext::SelectInstanceExtensions(std::vector* extension } #endif #if defined(VK_USE_PLATFORM_WAYLAND_KHR) - if (wstype == WindowSystemType::Wayland && !AddExtension(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME, true)) + if (wstype == WindowSystemType::Wayland && + !AddExtension(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME, true)) { return false; } diff --git a/Source/Core/VideoCommon/Present.h b/Source/Core/VideoCommon/Present.h index 9cff46cc3b..37f327a299 100644 --- a/Source/Core/VideoCommon/Present.h +++ b/Source/Core/VideoCommon/Present.h @@ -89,7 +89,8 @@ public: { ChangeSurface(nullptr, width, height, scale); } - struct SurfaceChangedInfo { + struct SurfaceChangedInfo + { void* new_handle; ///< New surface handle if changed, else null int new_width; ///< New surface width int new_height; ///< New surface height