mirror of
https://github.com/kovidgoyal/kitty.git
synced 2024-09-21 19:47:21 +03:00
Wayland: swap buffers immediately on scale change to ensure attached buffer is a multiple of the new scale
Earlier we were only swapping buffers when ready to draw, but the Wayland protocol requires the attached buffer to be a multiple of the scale. We cannot guarantee an application side swap will be triggered before the next commit, so instead we blank the new buffer swap it in the GLFW backend itself. Fixes #5467
This commit is contained in:
parent
23d73ec933
commit
29b3a92ffc
@ -49,6 +49,8 @@ Detailed list of changes
|
||||
- Wayland: Fix for a bug that could cause kitty to become non-responsive when
|
||||
using multiple OS windows in a single instance on some compositors (:iss:`5495`)
|
||||
|
||||
- Wayland: Fix for a bug preventing kitty from starting on Hyprland when using a non-unit scale (:iss:`5467`)
|
||||
|
||||
0.26.2 [2022-09-05]
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
44
glfw/wl_window.c
vendored
44
glfw/wl_window.c
vendored
@ -199,7 +199,7 @@ static bool checkScaleChange(_GLFWwindow* window)
|
||||
}
|
||||
|
||||
// Makes the surface considered as XRGB instead of ARGB.
|
||||
static void setOpaqueRegion(_GLFWwindow* window)
|
||||
static void setOpaqueRegion(_GLFWwindow* window, bool commit_surface)
|
||||
{
|
||||
struct wl_region* region;
|
||||
|
||||
@ -209,10 +209,22 @@ static void setOpaqueRegion(_GLFWwindow* window)
|
||||
|
||||
wl_region_add(region, 0, 0, window->wl.width, window->wl.height);
|
||||
wl_surface_set_opaque_region(window->wl.surface, region);
|
||||
wl_surface_commit(window->wl.surface);
|
||||
if (commit_surface) wl_surface_commit(window->wl.surface);
|
||||
wl_region_destroy(region);
|
||||
}
|
||||
|
||||
static void
|
||||
swap_buffers(_GLFWwindow *window) {
|
||||
// this will attach the buffer to the surface,
|
||||
// the client is responsible for clearing the buffer to an appropriate blank
|
||||
window->swaps_disallowed = false;
|
||||
GLFWwindow *current = glfwGetCurrentContext();
|
||||
bool context_is_current = ((_GLFWwindow*)current)->id == window->id;
|
||||
if (!context_is_current) glfwMakeContextCurrent((GLFWwindow*)window);
|
||||
window->context.swapBuffers(window);
|
||||
if (!context_is_current) glfwMakeContextCurrent(current);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
resizeFramebuffer(_GLFWwindow* window) {
|
||||
@ -221,7 +233,7 @@ resizeFramebuffer(_GLFWwindow* window) {
|
||||
int scaledHeight = window->wl.height * scale;
|
||||
debug("Resizing framebuffer to: %dx%d at scale: %d\n", window->wl.width, window->wl.height, scale);
|
||||
wl_egl_window_resize(window->wl.native, scaledWidth, scaledHeight, 0, 0);
|
||||
if (!window->wl.transparent) setOpaqueRegion(window);
|
||||
if (!window->wl.transparent) setOpaqueRegion(window, false);
|
||||
_glfwInputFramebufferSize(window, scaledWidth, scaledHeight);
|
||||
}
|
||||
|
||||
@ -236,9 +248,9 @@ clipboard_mime(void) {
|
||||
}
|
||||
|
||||
static bool
|
||||
dispatchChangesAfterConfigure(_GLFWwindow *window, int32_t width, int32_t height) {
|
||||
dispatchChangesAfterConfigure(_GLFWwindow *window, int32_t width, int32_t height, bool *scale_changed) {
|
||||
bool size_changed = width != window->wl.width || height != window->wl.height;
|
||||
bool scale_changed = checkScaleChange(window);
|
||||
*scale_changed = checkScaleChange(window);
|
||||
|
||||
if (size_changed) {
|
||||
_glfwInputWindowSize(window, width, height);
|
||||
@ -246,7 +258,7 @@ dispatchChangesAfterConfigure(_GLFWwindow *window, int32_t width, int32_t height
|
||||
resizeFramebuffer(window);
|
||||
}
|
||||
|
||||
if (scale_changed) {
|
||||
if (*scale_changed) {
|
||||
debug("Scale changed to %d in dispatchChangesAfterConfigure\n", window->wl.scale);
|
||||
if (!size_changed) resizeFramebuffer(window);
|
||||
_glfwInputWindowContentScale(window, window->wl.scale, window->wl.scale);
|
||||
@ -254,7 +266,7 @@ dispatchChangesAfterConfigure(_GLFWwindow *window, int32_t width, int32_t height
|
||||
|
||||
_glfwInputWindowDamage(window);
|
||||
|
||||
return size_changed || scale_changed;
|
||||
return size_changed || *scale_changed;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -383,7 +395,7 @@ static bool createSurface(_GLFWwindow* window,
|
||||
window->wl.scale = 1;
|
||||
|
||||
if (!window->wl.transparent)
|
||||
setOpaqueRegion(window);
|
||||
setOpaqueRegion(window, false);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -498,14 +510,7 @@ static void xdgSurfaceHandleConfigure(void* data,
|
||||
int height = window->wl.pending.height;
|
||||
if (!window->wl.surface_configured_once) {
|
||||
window->wl.surface_configured_once = true;
|
||||
// this will attach the buffer to the surface, the client is responsible for clearing the buffer to an appropriate blank
|
||||
window->swaps_disallowed = false;
|
||||
GLFWwindow *current = glfwGetCurrentContext();
|
||||
bool context_is_current = ((_GLFWwindow*)current)->id == window->id;
|
||||
if (!context_is_current) glfwMakeContextCurrent(data);
|
||||
window->context.swapBuffers(window);
|
||||
if (!context_is_current) glfwMakeContextCurrent(current);
|
||||
|
||||
swap_buffers(window);
|
||||
if (!width && !height && !new_states && !window->wl.decorations.serverSide && getenv("XAUTHORITY") && strstr(getenv("XAUTHORITY"), "mutter")) {
|
||||
// https://github.com/kovidgoyal/kitty/issues/4802
|
||||
debug("Ignoring first empty surface configure event on mutter.\n");
|
||||
@ -534,10 +539,11 @@ static void xdgSurfaceHandleConfigure(void* data,
|
||||
}
|
||||
|
||||
bool resized = false;
|
||||
bool scale_changed = false;
|
||||
if (window->wl.pending_state) {
|
||||
int width = window->wl.pending.width, height = window->wl.pending.height;
|
||||
set_csd_window_geometry(window, &width, &height);
|
||||
resized = dispatchChangesAfterConfigure(window, width, height);
|
||||
resized = dispatchChangesAfterConfigure(window, width, height, &scale_changed);
|
||||
if (window->wl.decorations.serverSide) {
|
||||
free_csd_surfaces(window);
|
||||
} else {
|
||||
@ -548,6 +554,10 @@ static void xdgSurfaceHandleConfigure(void* data,
|
||||
|
||||
inform_compositor_of_window_geometry(window, "configure");
|
||||
|
||||
// we need to swap buffers here to ensure the buffer attached to the surface is a multiple
|
||||
// of the new scale. See https://github.com/kovidgoyal/kitty/issues/5467
|
||||
if (scale_changed) swap_buffers(window);
|
||||
|
||||
// if a resize happened there will be a commit at the next render frame so
|
||||
// dont commit here, GNOME doesnt like it and its not really needed anyway
|
||||
if (!resized) wl_surface_commit(window->wl.surface);
|
||||
|
@ -312,6 +312,14 @@ dpi_change_callback(GLFWwindow *w, float x_scale UNUSED, float y_scale UNUSED) {
|
||||
window->live_resize.last_resize_event_at = monotonic();
|
||||
global_state.callback_os_window = NULL;
|
||||
request_tick_callback();
|
||||
if (global_state.is_wayland) {
|
||||
// because of the stupidity of Wayland design, the GLFW wayland backend
|
||||
// will need to swap buffers immediately after a scale change to ensure
|
||||
// the buffer size is a multiple of the scale. So blank the new buffer to
|
||||
// ensure we dont leak any unintialized pixels to the screen. The OpenGL viewport
|
||||
// will already have been resized to its new size in framebuffer_size_callback
|
||||
blank_os_window(window);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
|
Loading…
Reference in New Issue
Block a user