diff --git a/platform/linuxbsd/wayland/display_server_wayland.cpp b/platform/linuxbsd/wayland/display_server_wayland.cpp index 4208922392..fc2ffee38b 100644 --- a/platform/linuxbsd/wayland/display_server_wayland.cpp +++ b/platform/linuxbsd/wayland/display_server_wayland.cpp @@ -1901,7 +1901,23 @@ void DisplayServerWayland::process_events() { Ref winrect_msg = msg; if (winrect_msg.is_valid()) { + int scale = winrect_msg->buffer_scale; + + WaylandThread::WindowState *ws = wayland_thread.window_get_state(winrect_msg->id); + ERR_CONTINUE(ws == nullptr); + + if (scale == 0) { + // This should *never* happen. We fallback to the latest scale but it might + // have changed in the meantime to something invalid (non-integer divisor), + // leading to a protocol error. + ERR_PRINT("Wayland Thread did not report buffer scale at the time of resize."); + scale = wayland_thread.window_state_get_preferred_buffer_scale(ws); + } + + wayland_thread.window_state_set_buffer_scale(ws, scale); + _update_window_rect(winrect_msg->rect, winrect_msg->id); + continue; } diff --git a/platform/linuxbsd/wayland/wayland_thread.cpp b/platform/linuxbsd/wayland/wayland_thread.cpp index 6bd9f5228e..dbd15243a5 100644 --- a/platform/linuxbsd/wayland/wayland_thread.cpp +++ b/platform/linuxbsd/wayland/wayland_thread.cpp @@ -1314,17 +1314,6 @@ void WaylandThread::_frame_wl_callback_on_done(void *data, struct wl_callback *w ws->frame_callback = wl_surface_frame(ws->wl_surface); wl_callback_add_listener(ws->frame_callback, &frame_wl_callback_listener, ws); - - if (ws->wl_surface && ws->buffer_scale_changed) { - // NOTE: We're only now setting the buffer scale as the idea is to get this - // data committed together with the new frame, all by the rendering driver. - // This is important because we might otherwise set an invalid combination of - // buffer size and scale (e.g. odd size and 2x scale). We're pretty much - // guaranteed to get a proper buffer in the next render loop as the rescaling - // method also informs the engine of a "window rect change", triggering - // rendering if needed. - wl_surface_set_buffer_scale(ws->wl_surface, window_state_get_preferred_buffer_scale(ws)); - } } void WaylandThread::_wl_surface_on_leave(void *data, struct wl_surface *wl_surface, struct wl_output *wl_output) { @@ -1597,6 +1586,7 @@ void WaylandThread::_xdg_popup_on_configure(void *data, struct xdg_popup *xdg_po rect_msg->id = ws->id; rect_msg->rect.position = scale_vector2i(ws->rect.position, parent_scale); rect_msg->rect.size = scale_vector2i(ws->rect.size, parent_scale); + rect_msg->buffer_scale = window_state_get_preferred_buffer_scale(ws); ws->wayland_thread->push_message(rect_msg); } @@ -3788,7 +3778,6 @@ void WaylandThread::window_state_update_size(WindowState *p_ws, int p_width, int if (p_ws->buffer_scale != preferred_buffer_scale) { // The buffer scale is always important, even if we use frac scaling. p_ws->buffer_scale = preferred_buffer_scale; - p_ws->buffer_scale_changed = true; if (!using_fractional) { // We don't bother updating everything else if it's turned on though. @@ -3833,6 +3822,7 @@ void WaylandThread::window_state_update_size(WindowState *p_ws, int p_width, int rect_msg->id = p_ws->id; rect_msg->rect.position = scale_vector2i(p_ws->rect.position, win_scale); rect_msg->rect.size = scaled_size; + rect_msg->buffer_scale = preferred_buffer_scale; p_ws->wayland_thread->push_message(rect_msg); } @@ -3845,6 +3835,18 @@ void WaylandThread::window_state_update_size(WindowState *p_ws, int p_width, int } } +void WaylandThread::window_state_set_buffer_scale(WindowState *p_ws, int p_buffer_scale) { + ERR_FAIL_NULL(p_ws); + ERR_FAIL_COND(p_buffer_scale <= 0); + + ERR_FAIL_NULL(p_ws->wl_surface); + + if (p_ws->buffer_scale != p_buffer_scale) { + p_ws->buffer_scale = p_buffer_scale; + wl_surface_set_buffer_scale(p_ws->wl_surface, p_buffer_scale); + } +} + // Scales a vector according to wp_fractional_scale's rules, where coordinates // must be scaled with away from zero half-rounding. Vector2i WaylandThread::scale_vector2i(const Vector2i &p_vector, double p_amount) { diff --git a/platform/linuxbsd/wayland/wayland_thread.h b/platform/linuxbsd/wayland/wayland_thread.h index 1f2c71dadd..bc9f175bcb 100644 --- a/platform/linuxbsd/wayland/wayland_thread.h +++ b/platform/linuxbsd/wayland/wayland_thread.h @@ -133,9 +133,17 @@ public: GDSOFTCLASS(WindowRectMessage, WindowMessage); public: - // NOTE: This is in "scaled" terms. For example, if there's a 1920x1080 rect - // with a scale factor of 2, the actual value of `rect` will be 3840x2160. + // The window size in "absolute units" (pre-scaled). Basically the desired + // resolution of the underlying buffer. Rect2i rect; + + // Used to synchronize buffer size and scale together, otherwise we risk a + // protocol error. Note that this doesn't control scaling in general, only the + // concept of "surface buffer scale". See the protocol documentation of + // `wl_surface::set_buffer_scale` for more details. + // + // Defaults to 0 so that we can catch malformed messages. + int buffer_scale = 0; }; class WindowEventMessage : public WindowMessage { @@ -333,12 +341,6 @@ public: // Currently applied buffer scale. int buffer_scale = 1; - // Buffer scale must be applied right before rendering but _after_ committing - // everything else or otherwise we might have an inconsistent state (e.g. - // double scale and odd resolution). This flag assists with that; when set, - // on the next frame, we'll commit whatever is set in `buffer_scale`. - bool buffer_scale_changed = false; - // NOTE: The preferred buffer scale is currently only dynamically calculated. // It can be accessed by calling `window_state_get_preferred_buffer_scale`. @@ -1206,6 +1208,7 @@ public: static int window_state_get_preferred_buffer_scale(WindowState *p_ws); static double window_state_get_scale_factor(const WindowState *p_ws); static void window_state_update_size(WindowState *p_ws, int p_width, int p_height); + static void window_state_set_buffer_scale(WindowState *p_ws, int p_buffer_scale); static Vector2i scale_vector2i(const Vector2i &p_vector, double p_amount);