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:
David Herrmann 2012-09-27 10:45:20 +02:00
parent 01c97de5bd
commit e5855f8b61

View File

@ -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,