wlt: toolkit: fix sending two surface.attach() reqs in one frame
The need_frame and idle_frame logic was slightly wrong. We ended up not correctly requesting the frame-cb after a _real_ frame-cb. Hence, the idle-cb did simply send the next attach() request. This fixes this small race and adds a comment how all this is supposed to work. Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
This commit is contained in:
parent
01c97de5bd
commit
e5855f8b61
@ -1056,24 +1056,38 @@ static int resize_window(struct wlt_window *wnd, unsigned int width,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void frame_callback(void *data, struct wl_callback *w_callback,
|
||||
uint32_t time);
|
||||
static void idle_frame(struct ev_eloop *eloop, void *unused, void *data);
|
||||
|
||||
static const struct wl_callback_listener frame_callback_listener = {
|
||||
.done = frame_callback,
|
||||
};
|
||||
|
||||
static void do_frame(struct wlt_window *wnd)
|
||||
{
|
||||
wnd->idle_pending = false;
|
||||
ev_eloop_unregister_idle_cb(wnd->disp->eloop, idle_frame, wnd);
|
||||
|
||||
if (wnd->need_resize) {
|
||||
wnd->need_frame = true;
|
||||
wnd->need_resize = false;
|
||||
wnd->need_redraw = false;
|
||||
resize_window(wnd, wnd->new_width, wnd->new_height);
|
||||
}
|
||||
|
||||
if (wnd->need_redraw) {
|
||||
wnd->need_frame = true;
|
||||
wnd->need_redraw = false;
|
||||
wlt_window_do_redraw(wnd, wnd->buffer.width,
|
||||
wnd->buffer.height);
|
||||
}
|
||||
|
||||
if (wnd->need_frame) {
|
||||
wnd->w_frame = wl_surface_frame(wnd->w_surface);
|
||||
wl_callback_add_listener(wnd->w_frame,
|
||||
&frame_callback_listener, wnd);
|
||||
}
|
||||
}
|
||||
|
||||
static void frame_callback(void *data, struct wl_callback *w_callback,
|
||||
@ -1092,27 +1106,49 @@ static void idle_frame(struct ev_eloop *eloop, void *unused, void *data)
|
||||
{
|
||||
struct wlt_window *wnd = data;
|
||||
|
||||
wnd->need_frame = true;
|
||||
do_frame(wnd);
|
||||
}
|
||||
|
||||
static const struct wl_callback_listener frame_callback_listener = {
|
||||
.done = frame_callback,
|
||||
};
|
||||
|
||||
/*
|
||||
* Buffer Handling and Frame Scheduling
|
||||
* We use wl_shm for buffer allocation. This means, we have a single buffer
|
||||
* client side and the server loads it into its backbuffer for rendering. If the
|
||||
* server does not do this, we are screwed anyway, but that's on behalf of the
|
||||
* server, so we don't care.
|
||||
*
|
||||
* However, this means, when we create a buffer, we need to notify the
|
||||
* compositor and then wait until the compositor has created its back-buffer,
|
||||
* before we continue using this buffer. We can use the "frame" callback to get
|
||||
* notified about this.
|
||||
*
|
||||
* The logic we have is:
|
||||
* You set the boolean flags what action is needed in wlt_window and then call
|
||||
* "schedule_frame()". If we didn't already do any buffer operations in this
|
||||
* frame, then this function schedules an idle-callback which then performs
|
||||
* the requested functions (flags in wlt_window). Afterwards, it sets a marker
|
||||
* that this frame was already used and schedules a frame-callback.
|
||||
* If during this time another call to schedule_frame() is made, we do nothing
|
||||
* but wait for the frame-callback. It will then directly perform all the
|
||||
* requested functions and reschedule a frame-callback.
|
||||
* If nothing was schedule for one frame, we have no more interest in
|
||||
* frame-callbacks and thus we set "need_frame" to false again and don't
|
||||
* schedule any more frame-callbacks.
|
||||
*/
|
||||
static void schedule_frame(struct wlt_window *wnd)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!wnd || wnd->w_frame)
|
||||
return;
|
||||
|
||||
if (!wnd->need_frame && !wnd->idle_pending) {
|
||||
if (wnd->need_frame || wnd->idle_pending)
|
||||
return;
|
||||
|
||||
ret = ev_eloop_register_idle_cb(wnd->disp->eloop, idle_frame, wnd);
|
||||
if (ret)
|
||||
log_error("cannot schedule idle callback: %d", ret);
|
||||
else
|
||||
wnd->idle_pending = true;
|
||||
ev_eloop_register_idle_cb(wnd->disp->eloop,
|
||||
idle_frame, wnd);
|
||||
wnd->w_frame = wl_surface_frame(wnd->w_surface);
|
||||
wl_callback_add_listener(wnd->w_frame,
|
||||
&frame_callback_listener, wnd);
|
||||
}
|
||||
}
|
||||
|
||||
static void shell_surface_configure(void *data, struct wl_shell_surface *s,
|
||||
|
Loading…
x
Reference in New Issue
Block a user