Wayland: Remove the 120ms penalty from waiting for window creation
When showing the window we loop in the wayland backend using a temporary buffer of blank pixels to force the compositor to finish setting up the top level surface pronto. TODO: Set the color of the temmporary buffer to the background color
This commit is contained in:
@@ -316,7 +316,6 @@ def generate_wrappers(glfw_header: str) -> None:
|
|||||||
void glfwWaylandRedrawCSDWindowTitle(GLFWwindow *handle)
|
void glfwWaylandRedrawCSDWindowTitle(GLFWwindow *handle)
|
||||||
void glfwWaylandSetupLayerShellForNextWindow(GLFWLayerShellConfig c)
|
void glfwWaylandSetupLayerShellForNextWindow(GLFWLayerShellConfig c)
|
||||||
pid_t glfwWaylandCompositorPID(void)
|
pid_t glfwWaylandCompositorPID(void)
|
||||||
bool glfwWaylandWindowFullyCreated(GLFWwindow *handle)
|
|
||||||
unsigned long long glfwDBusUserNotify(const char *app_name, const char* icon, const char *summary, const char *body, \
|
unsigned long long glfwDBusUserNotify(const char *app_name, const char* icon, const char *summary, const char *body, \
|
||||||
const char *action_text, int32_t timeout, GLFWDBusnotificationcreatedfun callback, void *data)
|
const char *action_text, int32_t timeout, GLFWDBusnotificationcreatedfun callback, void *data)
|
||||||
void glfwDBusSetUserNotificationHandler(GLFWDBusnotificationactivatedfun handler)
|
void glfwDBusSetUserNotificationHandler(GLFWDBusnotificationactivatedfun handler)
|
||||||
|
|||||||
1
glfw/wl_platform.h
vendored
1
glfw/wl_platform.h
vendored
@@ -172,6 +172,7 @@ typedef struct _GLFWwindowWayland
|
|||||||
struct {
|
struct {
|
||||||
bool surface_configured, fractional_scale_received, preferred_scale_received;
|
bool surface_configured, fractional_scale_received, preferred_scale_received;
|
||||||
} once;
|
} once;
|
||||||
|
struct wl_buffer *temp_buffer_used_during_window_creation;
|
||||||
struct {
|
struct {
|
||||||
GLFWLayerShellConfig config;
|
GLFWLayerShellConfig config;
|
||||||
struct zwlr_layer_surface_v1* zwlr_layer_surface_v1;
|
struct zwlr_layer_surface_v1* zwlr_layer_surface_v1;
|
||||||
|
|||||||
69
glfw/wl_window.c
vendored
69
glfw/wl_window.c
vendored
@@ -373,6 +373,10 @@ _glfwWaylandAfterBufferSwap(_GLFWwindow* window) {
|
|||||||
// this is not really needed, since I think eglSwapBuffers() calls wl_surface_commit()
|
// this is not really needed, since I think eglSwapBuffers() calls wl_surface_commit()
|
||||||
// but lets be safe. See https://gitlab.freedesktop.org/mesa/mesa/-/blob/main/src/egl/drivers/dri2/platform_wayland.c#L1510
|
// but lets be safe. See https://gitlab.freedesktop.org/mesa/mesa/-/blob/main/src/egl/drivers/dri2/platform_wayland.c#L1510
|
||||||
wl_surface_commit(window->wl.surface);
|
wl_surface_commit(window->wl.surface);
|
||||||
|
if (window->wl.temp_buffer_used_during_window_creation) {
|
||||||
|
wl_buffer_destroy(window->wl.temp_buffer_used_during_window_creation);
|
||||||
|
window->wl.temp_buffer_used_during_window_creation = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -748,6 +752,51 @@ apply_xdg_configure_changes(_GLFWwindow *window) {
|
|||||||
window->wl.pending_state = 0;
|
window->wl.pending_state = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
attach_temp_buffer_during_window_creation(_GLFWwindow *window) {
|
||||||
|
int width, height;
|
||||||
|
_glfwPlatformGetFramebufferSize(window, &width, &height);
|
||||||
|
const size_t size = 4 * width * height;
|
||||||
|
int fd = createAnonymousFile(size);
|
||||||
|
if (fd < 0) {
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR, "Wayland: failed to create anonymouse file");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
struct wl_shm_pool *pool = wl_shm_create_pool(_glfw.wl.shm, fd, size);
|
||||||
|
if (!pool) {
|
||||||
|
close(fd);
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR, "Wayland: failed to create wl_shm_pool of size: %zu", size);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
struct wl_buffer *buffer = wl_shm_pool_create_buffer(pool, 0, width, height, width * 4, WL_SHM_FORMAT_ARGB8888);
|
||||||
|
wl_shm_pool_destroy(pool); close(fd);
|
||||||
|
if (!buffer) {
|
||||||
|
_glfwInputError(GLFW_PLATFORM_ERROR, "Wayland: failed to create wl_buffer of size: %zu", size);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (window->wl.temp_buffer_used_during_window_creation) wl_buffer_destroy(window->wl.temp_buffer_used_during_window_creation);
|
||||||
|
window->wl.temp_buffer_used_during_window_creation = buffer;
|
||||||
|
wl_surface_set_buffer_scale(window->wl.surface, window->wl.fractional_scale ? 1: _glfwWaylandIntegerWindowScale(window));
|
||||||
|
wl_surface_attach(window->wl.surface, buffer, 0, 0);
|
||||||
|
if (window->wl.wp_viewport) wp_viewport_set_destination(window->wl.wp_viewport, window->wl.width, window->wl.height);
|
||||||
|
wl_surface_commit(window->wl.surface);
|
||||||
|
debug("Attached temp buffer during window creation of size: %dx%d\n", width, height);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
loop_till_window_fully_created(_GLFWwindow *window) {
|
||||||
|
if (!window->wl.window_fully_created) {
|
||||||
|
monotonic_t start = monotonic();
|
||||||
|
while (!window->wl.window_fully_created && monotonic() - start < ms_to_monotonic_t(300)) {
|
||||||
|
if (wl_display_roundtrip(_glfw.wl.display) == -1) {
|
||||||
|
window->wl.window_fully_created = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
window->wl.window_fully_created = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
xdgSurfaceHandleConfigure(void* data, struct xdg_surface* surface, uint32_t serial) {
|
xdgSurfaceHandleConfigure(void* data, struct xdg_surface* surface, uint32_t serial) {
|
||||||
// The poorly documented pattern Wayland requires is:
|
// The poorly documented pattern Wayland requires is:
|
||||||
@@ -763,6 +812,9 @@ xdgSurfaceHandleConfigure(void* data, struct xdg_surface* surface, uint32_t seri
|
|||||||
xdg_surface_ack_configure(surface, serial);
|
xdg_surface_ack_configure(surface, serial);
|
||||||
debug("XDG surface configure event received and acknowledged\n");
|
debug("XDG surface configure event received and acknowledged\n");
|
||||||
apply_xdg_configure_changes(window);
|
apply_xdg_configure_changes(window);
|
||||||
|
if (!window->wl.window_fully_created) {
|
||||||
|
if (!attach_temp_buffer_during_window_creation(window)) window->wl.window_fully_created = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct xdg_surface_listener xdgSurfaceListener = {
|
static const struct xdg_surface_listener xdgSurfaceListener = {
|
||||||
@@ -877,6 +929,9 @@ layer_surface_handle_configure(void* data, struct zwlr_layer_surface_v1* surface
|
|||||||
layer_set_properties(window);
|
layer_set_properties(window);
|
||||||
}
|
}
|
||||||
commit_window_surface_if_safe(window);
|
commit_window_surface_if_safe(window);
|
||||||
|
if (!window->wl.window_fully_created) {
|
||||||
|
if (!attach_temp_buffer_during_window_creation(window)) window->wl.window_fully_created = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -1200,7 +1255,7 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window,
|
|||||||
window->wl.monitors = calloc(1, sizeof(_GLFWmonitor*));
|
window->wl.monitors = calloc(1, sizeof(_GLFWmonitor*));
|
||||||
window->wl.monitorsCount = 0;
|
window->wl.monitorsCount = 0;
|
||||||
window->wl.monitorsSize = 1;
|
window->wl.monitorsSize = 1;
|
||||||
|
if (window->wl.visible) loop_till_window_fully_created(window);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1220,6 +1275,9 @@ void _glfwPlatformDestroyWindow(_GLFWwindow* window)
|
|||||||
_glfw.wl.keyRepeatInfo.keyboardFocusId = 0;
|
_glfw.wl.keyRepeatInfo.keyboardFocusId = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (window->wl.temp_buffer_used_during_window_creation)
|
||||||
|
wl_buffer_destroy(window->wl.temp_buffer_used_during_window_creation);
|
||||||
|
|
||||||
if (window->wl.wp_fractional_scale_v1)
|
if (window->wl.wp_fractional_scale_v1)
|
||||||
wp_fractional_scale_v1_destroy(window->wl.wp_fractional_scale_v1);
|
wp_fractional_scale_v1_destroy(window->wl.wp_fractional_scale_v1);
|
||||||
if (window->wl.wp_viewport)
|
if (window->wl.wp_viewport)
|
||||||
@@ -1422,10 +1480,10 @@ void _glfwPlatformMaximizeWindow(_GLFWwindow* window)
|
|||||||
|
|
||||||
void _glfwPlatformShowWindow(_GLFWwindow* window)
|
void _glfwPlatformShowWindow(_GLFWwindow* window)
|
||||||
{
|
{
|
||||||
if (!window->wl.visible)
|
if (!window->wl.visible) {
|
||||||
{
|
|
||||||
create_window_desktop_surface(window);
|
create_window_desktop_surface(window);
|
||||||
window->wl.visible = true;
|
window->wl.visible = true;
|
||||||
|
loop_till_window_fully_created(window);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2585,8 +2643,3 @@ GLFWAPI void glfwWaylandSetupLayerShellForNextWindow(GLFWLayerShellConfig c) {
|
|||||||
if (layer_shell_config_for_next_window.output_name && !layer_shell_config_for_next_window.output_name[0]) layer_shell_config_for_next_window.output_name = NULL;
|
if (layer_shell_config_for_next_window.output_name && !layer_shell_config_for_next_window.output_name[0]) layer_shell_config_for_next_window.output_name = NULL;
|
||||||
if (layer_shell_config_for_next_window.output_name) layer_shell_config_for_next_window.output_name = strdup(layer_shell_config_for_next_window.output_name);
|
if (layer_shell_config_for_next_window.output_name) layer_shell_config_for_next_window.output_name = strdup(layer_shell_config_for_next_window.output_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
GLFWAPI bool glfwWaylandWindowFullyCreated(GLFWwindow *handle) {
|
|
||||||
_GLFWwindow* window = (_GLFWwindow*) handle;
|
|
||||||
return window->wl.window_fully_created;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1574,5 +1574,4 @@ def replace_c0_codes_except_nl_space_tab(text: str) -> str:...
|
|||||||
def replace_c0_codes_except_nl_space_tab(text: Union[bytes, memoryview, bytearray]) -> bytes:...
|
def replace_c0_codes_except_nl_space_tab(text: Union[bytes, memoryview, bytearray]) -> bytes:...
|
||||||
def terminfo_data() -> bytes:...
|
def terminfo_data() -> bytes:...
|
||||||
def wayland_compositor_pid() -> int:...
|
def wayland_compositor_pid() -> int:...
|
||||||
def window_fully_created(kitty_window_id: int) -> bool: ...
|
|
||||||
def monotonic() -> float: ...
|
def monotonic() -> float: ...
|
||||||
|
|||||||
3
kitty/glfw-wrapper.c
generated
3
kitty/glfw-wrapper.c
generated
@@ -485,9 +485,6 @@ load_glfw(const char* path) {
|
|||||||
*(void **) (&glfwWaylandCompositorPID_impl) = dlsym(handle, "glfwWaylandCompositorPID");
|
*(void **) (&glfwWaylandCompositorPID_impl) = dlsym(handle, "glfwWaylandCompositorPID");
|
||||||
if (glfwWaylandCompositorPID_impl == NULL) dlerror(); // clear error indicator
|
if (glfwWaylandCompositorPID_impl == NULL) dlerror(); // clear error indicator
|
||||||
|
|
||||||
*(void **) (&glfwWaylandWindowFullyCreated_impl) = dlsym(handle, "glfwWaylandWindowFullyCreated");
|
|
||||||
if (glfwWaylandWindowFullyCreated_impl == NULL) dlerror(); // clear error indicator
|
|
||||||
|
|
||||||
*(void **) (&glfwDBusUserNotify_impl) = dlsym(handle, "glfwDBusUserNotify");
|
*(void **) (&glfwDBusUserNotify_impl) = dlsym(handle, "glfwDBusUserNotify");
|
||||||
if (glfwDBusUserNotify_impl == NULL) dlerror(); // clear error indicator
|
if (glfwDBusUserNotify_impl == NULL) dlerror(); // clear error indicator
|
||||||
|
|
||||||
|
|||||||
4
kitty/glfw-wrapper.h
generated
4
kitty/glfw-wrapper.h
generated
@@ -2316,10 +2316,6 @@ typedef pid_t (*glfwWaylandCompositorPID_func)(void);
|
|||||||
GFW_EXTERN glfwWaylandCompositorPID_func glfwWaylandCompositorPID_impl;
|
GFW_EXTERN glfwWaylandCompositorPID_func glfwWaylandCompositorPID_impl;
|
||||||
#define glfwWaylandCompositorPID glfwWaylandCompositorPID_impl
|
#define glfwWaylandCompositorPID glfwWaylandCompositorPID_impl
|
||||||
|
|
||||||
typedef bool (*glfwWaylandWindowFullyCreated_func)(GLFWwindow*);
|
|
||||||
GFW_EXTERN glfwWaylandWindowFullyCreated_func glfwWaylandWindowFullyCreated_impl;
|
|
||||||
#define glfwWaylandWindowFullyCreated glfwWaylandWindowFullyCreated_impl
|
|
||||||
|
|
||||||
typedef unsigned long long (*glfwDBusUserNotify_func)(const char*, const char*, const char*, const char*, const char*, int32_t, GLFWDBusnotificationcreatedfun, void*);
|
typedef unsigned long long (*glfwDBusUserNotify_func)(const char*, const char*, const char*, const char*, const char*, int32_t, GLFWDBusnotificationcreatedfun, void*);
|
||||||
GFW_EXTERN glfwDBusUserNotify_func glfwDBusUserNotify_impl;
|
GFW_EXTERN glfwDBusUserNotify_func glfwDBusUserNotify_impl;
|
||||||
#define glfwDBusUserNotify glfwDBusUserNotify_impl
|
#define glfwDBusUserNotify glfwDBusUserNotify_impl
|
||||||
|
|||||||
11
kitty/glfw.c
11
kitty/glfw.c
@@ -2210,16 +2210,6 @@ make_x11_window_a_dock_window(PyObject *self UNUSED, PyObject *args UNUSED) {
|
|||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject*
|
|
||||||
window_fully_created(PyObject *self UNUSED, PyObject *wid) {
|
|
||||||
// On Wayland a window does not receive its final size by the time glfwCreateWindow returns
|
|
||||||
if (!global_state.is_wayland) Py_RETURN_TRUE;
|
|
||||||
OSWindow *w = os_window_for_kitty_window(PyLong_AsUnsignedLongLong(wid));
|
|
||||||
if (!w || !w->handle) Py_RETURN_FALSE;
|
|
||||||
if (glfwWaylandWindowFullyCreated(w->handle)) Py_RETURN_TRUE;
|
|
||||||
Py_RETURN_FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Boilerplate {{{
|
// Boilerplate {{{
|
||||||
|
|
||||||
static PyMethodDef module_methods[] = {
|
static PyMethodDef module_methods[] = {
|
||||||
@@ -2239,7 +2229,6 @@ static PyMethodDef module_methods[] = {
|
|||||||
METHODB(glfw_window_hint, METH_VARARGS),
|
METHODB(glfw_window_hint, METH_VARARGS),
|
||||||
METHODB(x11_display, METH_NOARGS),
|
METHODB(x11_display, METH_NOARGS),
|
||||||
METHODB(wayland_compositor_pid, METH_NOARGS),
|
METHODB(wayland_compositor_pid, METH_NOARGS),
|
||||||
METHODB(window_fully_created, METH_O),
|
|
||||||
METHODB(get_click_interval, METH_NOARGS),
|
METHODB(get_click_interval, METH_NOARGS),
|
||||||
METHODB(x11_window_id, METH_O),
|
METHODB(x11_window_id, METH_O),
|
||||||
METHODB(make_x11_window_a_dock_window, METH_VARARGS),
|
METHODB(make_x11_window_a_dock_window, METH_VARARGS),
|
||||||
|
|||||||
@@ -86,7 +86,6 @@ from .fast_data_types import (
|
|||||||
update_window_title,
|
update_window_title,
|
||||||
update_window_visibility,
|
update_window_visibility,
|
||||||
wakeup_main_loop,
|
wakeup_main_loop,
|
||||||
window_fully_created,
|
|
||||||
)
|
)
|
||||||
from .keys import keyboard_mode_name, mod_mask
|
from .keys import keyboard_mode_name, mod_mask
|
||||||
from .notify import (
|
from .notify import (
|
||||||
@@ -839,14 +838,14 @@ class Window:
|
|||||||
boss = get_boss()
|
boss = get_boss()
|
||||||
boss.child_monitor.resize_pty(self.id, *current_pty_size)
|
boss.child_monitor.resize_pty(self.id, *current_pty_size)
|
||||||
self.last_resized_at = monotonic()
|
self.last_resized_at = monotonic()
|
||||||
if not self.child_is_launched and window_fully_created(self.id):
|
if not self.child_is_launched:
|
||||||
self.child.mark_terminal_ready()
|
self.child.mark_terminal_ready()
|
||||||
self.child_is_launched = True
|
self.child_is_launched = True
|
||||||
update_ime_position = True
|
update_ime_position = True
|
||||||
if boss.args.debug_rendering:
|
if boss.args.debug_rendering:
|
||||||
now = monotonic()
|
now = monotonic()
|
||||||
print(f'[{now:.3f}] Child launched {now - self.started_at:.2f} seconds after window creation', file=sys.stderr)
|
print(f'[{now:.3f}] Child launched', file=sys.stderr)
|
||||||
if boss.args.debug_rendering and self.child_is_launched:
|
elif boss.args.debug_rendering:
|
||||||
print(f'[{monotonic():.3f}] SIGWINCH sent to child in window: {self.id} with size: {current_pty_size}', file=sys.stderr)
|
print(f'[{monotonic():.3f}] SIGWINCH sent to child in window: {self.id} with size: {current_pty_size}', file=sys.stderr)
|
||||||
self.last_reported_pty_size = current_pty_size
|
self.last_reported_pty_size = current_pty_size
|
||||||
else:
|
else:
|
||||||
|
|||||||
Reference in New Issue
Block a user