[RFC Weston 08/10] window: implement per-surface redraws
Pekka Paalanen
ppaalanen at gmail.com
Fri Feb 22 07:07:52 PST 2013
Add redraw_needed flag to all surfaces, in addition to having one in
window.
widget_schedule_redraw() now schedules the redraw only for the surface,
where the widget is on. window_schedule_redraw() is equivalent to
scheduling a redraw for all (sub-)surfaces of the window.
We still use only one deferred task for all redraws.
surface_redraw() will skip the redraw, if the window does not force a
redraw and the surface does not need a redraw. It will also skip the
redraw, if the frame callback from the previous redraw has not triggered
yet. When the frame callback later arrives, the redraw task will be
scheduled, if the surface still needs a redraw.
If the window forces a redraw, the redraw is executed even if there is a
pending frame callback. This is for resizing: resizing should trigger a
window repaint, as it really wants to update all surfaces in one go, to
apply possible sub-surface size and position changes. Resizing is the
only thing that makes a window force a redraw.
With this change, subsurfaces demo can avoid repainting the cairo
sub-surface while still animating the GL sub-surface.
---
clients/window.c | 80 +++++++++++++++++++++++++++++++++++++++++---------------
1 file changed, 59 insertions(+), 21 deletions(-)
diff --git a/clients/window.c b/clients/window.c
index e538da9..4730c89 100644
--- a/clients/window.c
+++ b/clients/window.c
@@ -195,6 +195,8 @@ struct surface {
enum wl_subsurface_commit_mode default_mode;
struct toysurface *toysurface;
struct widget *widget;
+ int redraw_needed;
+ struct wl_callback *frame_cb;
struct rectangle allocation;
struct rectangle server_allocation;
@@ -220,8 +222,8 @@ struct window {
struct rectangle pending_allocation;
int x, y;
int resize_edges;
- int redraw_scheduled;
int redraw_needed;
+ int redraw_task_scheduled;
struct task redraw_task;
int resize_needed;
int type;
@@ -240,7 +242,6 @@ struct window {
struct surface *main_surface;
struct wl_shell_surface *shell_surface;
- struct wl_callback *frame_cb;
struct frame *frame;
@@ -1307,6 +1308,9 @@ static void frame_destroy(struct frame *frame);
static void
surface_destroy(struct surface *surface)
{
+ if (surface->frame_cb)
+ wl_callback_destroy(surface->frame_cb);
+
if (surface->input_region)
wl_region_destroy(surface->input_region);
@@ -1333,8 +1337,7 @@ window_destroy(struct window *window)
struct window_output *window_output;
struct window_output *window_output_tmp;
- if (window->redraw_scheduled)
- wl_list_remove(&window->redraw_task.link);
+ wl_list_remove(&window->redraw_task.link);
wl_list_for_each(input, &display->input_list, link) {
if (input->pointer_focus == window)
@@ -1361,8 +1364,6 @@ window_destroy(struct window *window)
wl_list_remove(&window->link);
- if (window->frame_cb)
- wl_callback_destroy(window->frame_cb);
free(window->title);
free(window);
}
@@ -1589,10 +1590,14 @@ widget_set_axis_handler(struct widget *widget,
widget->axis_handler = handler;
}
+static void
+window_schedule_redraw_task(struct window *window);
+
void
widget_schedule_redraw(struct widget *widget)
{
- window_schedule_redraw(widget->window);
+ widget->surface->redraw_needed = 1;
+ window_schedule_redraw_task(widget->window);
}
cairo_surface_t *
@@ -3329,6 +3334,7 @@ idle_resize(struct window *window)
struct surface *surface;
window->resize_needed = 0;
+ window->redraw_needed = 1;
widget_set_allocation(window->main_surface->widget,
window->pending_allocation.x,
@@ -3445,14 +3451,14 @@ widget_redraw(struct widget *widget)
static void
frame_callback(void *data, struct wl_callback *callback, uint32_t time)
{
- struct window *window = data;
+ struct surface *surface = data;
- assert(callback == window->frame_cb);
+ assert(callback == surface->frame_cb);
wl_callback_destroy(callback);
- window->frame_cb = 0;
- window->redraw_scheduled = 0;
- if (window->redraw_needed)
- window_schedule_redraw(window);
+ surface->frame_cb = NULL;
+
+ if (surface->redraw_needed || surface->window->redraw_needed)
+ window_schedule_redraw_task(surface->window);
}
static const struct wl_callback_listener listener = {
@@ -3460,6 +3466,29 @@ static const struct wl_callback_listener listener = {
};
static void
+surface_redraw(struct surface *surface)
+{
+ if (!surface->window->redraw_needed && !surface->redraw_needed)
+ return;
+
+ /* Whole-window redraw forces a redraw even if the previous has
+ * not yet hit the screen.
+ */
+ if (surface->frame_cb) {
+ if (!surface->window->redraw_needed)
+ return;
+
+ wl_callback_destroy(surface->frame_cb);
+ }
+
+ surface->frame_cb = wl_surface_frame(surface->surface);
+ wl_callback_add_listener(surface->frame_cb, &listener, surface);
+
+ surface->redraw_needed = 0;
+ widget_redraw(surface->widget);
+}
+
+static void
idle_redraw(struct task *task, uint32_t events)
{
struct window *window = container_of(task, struct window, redraw_task);
@@ -3469,30 +3498,39 @@ idle_redraw(struct task *task, uint32_t events)
idle_resize(window);
wl_list_for_each(surface, &window->subsurface_list, link)
- widget_redraw(surface->widget);
+ surface_redraw(surface);
window->redraw_needed = 0;
wl_list_init(&window->redraw_task.link);
+ window->redraw_task_scheduled = 0;
- window->frame_cb = wl_surface_frame(window->main_surface->surface);
- wl_callback_add_listener(window->frame_cb, &listener, window);
window_flush(window);
wl_list_for_each(surface, &window->subsurface_list, link)
surface_set_commit_mode_default(surface);
}
-void
-window_schedule_redraw(struct window *window)
+static void
+window_schedule_redraw_task(struct window *window)
{
- window->redraw_needed = 1;
- if (!window->redraw_scheduled) {
+ if (!window->redraw_task_scheduled) {
window->redraw_task.run = idle_redraw;
display_defer(window->display, &window->redraw_task);
- window->redraw_scheduled = 1;
+ window->redraw_task_scheduled = 1;
}
}
+void
+window_schedule_redraw(struct window *window)
+{
+ struct surface *surface;
+
+ wl_list_for_each(surface, &window->subsurface_list, link)
+ surface->redraw_needed = 1;
+
+ window_schedule_redraw_task(window);
+}
+
int
window_is_fullscreen(struct window *window)
{
--
1.7.12.4
More information about the wayland-devel
mailing list