Wayland: SDL3 改变窗口大小时极其卡顿

Posted on May 23, 2026

SDL3 创建的窗口在改变大小时极其卡顿,测量 while (SDL_PollEvent(&event)) {} 耗时大多 在几百至上千毫秒,严重拖慢了窗口重绘

Gnome 50.1
SDL_GPU Driver: Vulkan
在基于 Gnome 的桌面上存在此问题

问题在 2025 年就已经出现
相关 Issue: Wayland: extreme lag when resizing window

What desktop are you using? This is a known issue with GNOME based desktops, which use the libdecor backend. The root issue is libdecor not passing the resize flag through, which needs a new version of libdecor to be released to be remedied.

原因应为 SDL 使用 libdecor 在 Wayland 下绘制窗口装饰,但是 libdecor 没能向下传递 resize 标志

切换到 XWayland

通过设置 export SDL_VIDEODRIVER=x11 变量可以回退到 X11 后端,临时解决卡顿的问题

自绘标题栏

SDL_SetHint(SDL_HINT_VIDEO_WAYLAND_ALLOW_LIBDECOR, "0");

在 SDL_Init() 前关闭默认的窗口装饰并设置 window flag 为 SDL_WINDOW_BORDERLESS,在 Gnome 下可以用 Super + 鼠标左键 移动, Super + 鼠标右键 调整窗口大小/关闭/最大最小化等

SDL_SetWindowHitTest

SDL 提供了用于控制窗口属性的 API, 只需要创建一个回调函数并进行坐标判断

typedef enum SDL_HitTestResult
{
    SDL_HITTEST_NORMAL,             /**< Region is normal. No special properties. */
    SDL_HITTEST_DRAGGABLE,          /**< Region can drag entire window. */
    SDL_HITTEST_RESIZE_TOPLEFT,     /**< Region is the resizable top-left corner border. */
    SDL_HITTEST_RESIZE_TOP,         /**< Region is the resizable top border. */
    SDL_HITTEST_RESIZE_TOPRIGHT,    /**< Region is the resizable top-right corner border. */
    SDL_HITTEST_RESIZE_RIGHT,       /**< Region is the resizable right border. */
    SDL_HITTEST_RESIZE_BOTTOMRIGHT, /**< Region is the resizable bottom-right corner border. */
    SDL_HITTEST_RESIZE_BOTTOM,      /**< Region is the resizable bottom border. */
    SDL_HITTEST_RESIZE_BOTTOMLEFT,  /**< Region is the resizable bottom-left corner border. */
    SDL_HITTEST_RESIZE_LEFT         /**< Region is the resizable left border. */
} SDL_HitTestResult;
SDL_HitTestResult win_hint_cb(SDL_Window *win, const SDL_Point *area, void *data)
{
    int width, height;
    SDL_GetWindowSize(win, &width, &height);

    if (area->y < 40) {
        if (area->y < 5) {
            if (area->x < 10) return SDL_HITTEST_RESIZE_TOPLEFT;
            else if (width - area->x < 10) return SDL_HITTEST_RESIZE_TOPRIGHT;
            else return SDL_HITTEST_RESIZE_TOP;
        }
        return SDL_HITTEST_DRAGGABLE;
    }
    if (area->x < 10) {
        if (height - area->y < 10) return SDL_HITTEST_RESIZE_BOTTOMLEFT;
        else return SDL_HITTEST_RESIZE_LEFT;
    }
    if (width - area->x < 10) {
        if (height - area->y < 10) return SDL_HITTEST_RESIZE_BOTTOMRIGHT;
        else return SDL_HITTEST_RESIZE_RIGHT;
    }
    if (height - area->y < 10) return SDL_HITTEST_RESIZE_BOTTOM;

    return SDL_HITTEST_NORMAL;
}

...
SDL_SetWindowHitTest(window, win_hint_cb, NULL);
...

这里设置标题栏高度为 40,窗口边缘触发调整大小的区域为 10 (顶部处为 5)
因为关闭了窗口装饰,所以后续还需要自绘标题栏