From 1ac343fabde90d00412f7b97936d9b22c6eed72c Mon Sep 17 00:00:00 2001 From: Norman Feske Date: Mon, 23 Jun 2014 13:15:53 +0200 Subject: [PATCH] nitpicker: Reduce superfluous refresh operations --- .../os/src/server/nitpicker/chunky_menubar.h | 2 + repos/os/src/server/nitpicker/main.cc | 2 + repos/os/src/server/nitpicker/menubar.h | 2 + repos/os/src/server/nitpicker/user_state.cc | 12 ++++- repos/os/src/server/nitpicker/user_state.h | 1 + repos/os/src/server/nitpicker/view.h | 26 ++++++++- repos/os/src/server/nitpicker/view_stack.cc | 54 ++++++++++++++----- repos/os/src/server/nitpicker/view_stack.h | 40 +++++++++++--- 8 files changed, 117 insertions(+), 22 deletions(-) diff --git a/repos/os/src/server/nitpicker/chunky_menubar.h b/repos/os/src/server/nitpicker/chunky_menubar.h index 6fe234f75..abae95c8a 100644 --- a/repos/os/src/server/nitpicker/chunky_menubar.h +++ b/repos/os/src/server/nitpicker/chunky_menubar.h @@ -104,6 +104,8 @@ class Chunky_menubar : public Texture, session_label.string(), WHITE, "", session_color); } + View &view() override { return *this; } + using Menubar::state; }; diff --git a/repos/os/src/server/nitpicker/main.cc b/repos/os/src/server/nitpicker/main.cc index e10e7c837..0a313d9ea 100644 --- a/repos/os/src/server/nitpicker/main.cc +++ b/repos/os/src/server/nitpicker/main.cc @@ -1164,6 +1164,8 @@ void Nitpicker::Main::handle_input(unsigned) framebuffer.refresh(rect.x1(), rect.y1(), rect.w(), rect.h()); }); + user_state.mark_all_views_as_clean(); + /* deliver framebuffer synchronization events */ if (!user_state.kill()) { for (::Session *s = session_list.first(); s; s = s->next()) diff --git a/repos/os/src/server/nitpicker/menubar.h b/repos/os/src/server/nitpicker/menubar.h index ff051100d..eeaaf9d0c 100644 --- a/repos/os/src/server/nitpicker/menubar.h +++ b/repos/os/src/server/nitpicker/menubar.h @@ -43,6 +43,8 @@ struct Menubar : Menubar_state virtual void state(Menubar_state) = 0; Menubar_state state() const { return *this; } + + virtual View &view() = 0; }; #endif diff --git a/repos/os/src/server/nitpicker/user_state.cc b/repos/os/src/server/nitpicker/user_state.cc index 1bdef2ffb..5c4456ebb 100644 --- a/repos/os/src/server/nitpicker/user_state.cc +++ b/repos/os/src/server/nitpicker/user_state.cc @@ -41,7 +41,7 @@ User_state::User_state(Global_keys &global_keys, Area view_stack_size, Menubar & { } -void User_state::_update_all() +void User_state::_update_menubar() { Menubar_state state(*this, "", BLACK); @@ -51,6 +51,14 @@ void User_state::_update_all() _input_receiver->color()); _menubar.state(state); + + refresh_view(_menubar.view(), _menubar.view().abs_geometry()); +} + + +void User_state::_update_all() +{ + _update_menubar(); update_all_views(); } @@ -276,5 +284,5 @@ void User_state::focused_session(::Session *session) if (!_global_key_sequence) _input_receiver = session; - _update_all(); + _update_menubar(); } diff --git a/repos/os/src/server/nitpicker/user_state.h b/repos/os/src/server/nitpicker/user_state.h index c9497b3bc..c875a11c1 100644 --- a/repos/os/src/server/nitpicker/user_state.h +++ b/repos/os/src/server/nitpicker/user_state.h @@ -59,6 +59,7 @@ class User_state : public Mode, public View_stack */ bool _global_key_sequence = false; + void _update_menubar(); void _update_all(); public: diff --git a/repos/os/src/server/nitpicker/view.h b/repos/os/src/server/nitpicker/view.h index 841fbae90..53099a458 100644 --- a/repos/os/src/server/nitpicker/view.h +++ b/repos/os/src/server/nitpicker/view.h @@ -92,6 +92,7 @@ class View : public Same_buffer_list_elem, Point _buffer_off; /* offset to the visible buffer area */ Session &_session; /* session that created the view */ char _title[TITLE_LEN]; + Dirty_rect _dirty_rect; Genode::List _children; @@ -154,7 +155,13 @@ class View : public Same_buffer_list_elem, void remove_child(View const &child) { _children.remove(&child); } template - void for_each_child(FN const &fn) const { + void for_each_child(FN const &fn) { + for (View_parent_elem *e = _children.first(); e; e = e->next()) + fn(*static_cast(e)); + } + + template + void for_each_const_child(FN const &fn) const { for (View_parent_elem const *e = _children.first(); e; e = e->next()) fn(*static_cast(e)); } @@ -242,6 +249,23 @@ class View : public Same_buffer_list_elem, return true; } + + /** + * Mark part of view as dirty + * + * \param rect dirty rectangle in absolute coordinates + */ + void mark_as_dirty(Rect rect) { _dirty_rect.mark_as_dirty(rect); } + + /** + * Return dirty-rectangle information + */ + Dirty_rect dirty_rect() const { return _dirty_rect; } + + /** + * Reset dirty rectangle + */ + void mark_as_clean() { _dirty_rect = Dirty_rect(); } }; #endif /* _VIEW_H_ */ diff --git a/repos/os/src/server/nitpicker/view_stack.cc b/repos/os/src/server/nitpicker/view_stack.cc index 45cb9a3f8..3abb559a9 100644 --- a/repos/os/src/server/nitpicker/view_stack.cc +++ b/repos/os/src/server/nitpicker/view_stack.cc @@ -209,8 +209,9 @@ void View_stack::draw_rec(Canvas_base &canvas, View const *view, Rect rect) cons if (next && left.valid()) draw_rec(canvas, next, left); /* draw current view */ - { - Clip_guard clip_guard(canvas, clipped); + view->dirty_rect().flush([&] (Rect const &dirty_rect) { + + Clip_guard clip_guard(canvas, Rect::intersect(clipped, dirty_rect)); /* draw background if view is transparent */ if (view->uses_alpha()) @@ -218,7 +219,7 @@ void View_stack::draw_rec(Canvas_base &canvas, View const *view, Rect rect) cons view->frame(canvas, _mode); view->draw(canvas, _mode); - } + }); /* draw areas at the bottom/right of the current view */ if (next && right.valid()) draw_rec(canvas, next, right); @@ -226,14 +227,32 @@ void View_stack::draw_rec(Canvas_base &canvas, View const *view, Rect rect) cons } -void View_stack::refresh_view(View const &view, Rect const rect) +void View_stack::refresh_view(View &view, Rect const rect) { - /* clip argument agains view outline */ - Rect const intersection = Rect::intersect(rect, _outline(view)); + /* rectangle constrained to view geometry */ + Rect const view_rect = Rect::intersect(rect, _outline(view)); - _dirty_rect.mark_as_dirty(intersection); + for (View *v = _first_view(); v; v = v->view_stack_next()) { - view.for_each_child([&] (View const &child) { refresh_view(child, rect); }); + Rect const intersection = Rect::intersect(view_rect, _outline(*v)); + + if (intersection.valid()) + _mark_view_as_dirty(*v, intersection); + } + + view.for_each_child([&] (View &child) { refresh_view(child, rect); }); +} + + +void View_stack::refresh(Rect const rect) +{ + for (View *v = _first_view(); v; v = v->view_stack_next()) { + + Rect const intersection = Rect::intersect(rect, _outline(*v)); + + if (intersection.valid()) + refresh_view(*v, intersection); + } } @@ -241,10 +260,19 @@ void View_stack::geometry(View &view, Rect const rect) { Rect const old_outline = _outline(view); + /* + * Refresh area covered by the original view geometry. + * + * We specify the whole geometry to also cover the refresh of child + * views. The 'refresh_view' function takes care to constrain the + * refresh to the actual view geometry. + */ refresh_view(view, Rect(Point(), _size)); + /* change geometry */ view.geometry(Rect(rect)); + /* refresh new view geometry */ refresh_view(view, Rect(Point(), _size)); Rect const compound = Rect::compound(old_outline, _outline(view)); @@ -263,14 +291,14 @@ void View_stack::buffer_offset(View &view, Point const buffer_off) } -void View_stack::stack(View const &view, View const *neighbor, bool behind) +void View_stack::stack(View &view, View const *neighbor, bool behind) { _views.remove(&view); _views.insert(&view, _target_stack_position(neighbor, behind)); _place_labels(view.abs_geometry()); - _dirty_rect.mark_as_dirty(_outline(view)); + _mark_view_as_dirty(view, _outline(view)); } @@ -279,7 +307,7 @@ void View_stack::title(View &view, const char *title) view.title(title); _place_labels(view.abs_geometry()); - _dirty_rect.mark_as_dirty(_outline(view)); + _mark_view_as_dirty(view, _outline(view)); } @@ -298,7 +326,7 @@ View *View_stack::find_view(Point p) void View_stack::remove_view(View const &view, bool redraw) { - view.for_each_child([&] (View const &child) { remove_view(child); }); + view.for_each_const_child([&] (View const &child) { remove_view(child); }); /* remember geometry of view to remove */ Rect rect = _outline(view); @@ -306,5 +334,5 @@ void View_stack::remove_view(View const &view, bool redraw) /* exclude view from view stack */ _views.remove(&view); - _dirty_rect.mark_as_dirty(rect); + refresh(rect); } diff --git a/repos/os/src/server/nitpicker/view_stack.h b/repos/os/src/server/nitpicker/view_stack.h index 82e6562bb..bba89a5f0 100644 --- a/repos/os/src/server/nitpicker/view_stack.h +++ b/repos/os/src/server/nitpicker/view_stack.h @@ -76,6 +76,8 @@ class View_stack void _mark_view_as_dirty(View &view, Rect rect) { _dirty_rect.mark_as_dirty(rect); + + view.mark_as_dirty(rect); } public: @@ -96,7 +98,8 @@ class View_stack void size(Area size) { _size = size; - _dirty_rect.mark_as_dirty(Rect(Point(0, 0), _size)); + + update_all_views(); } /** @@ -124,8 +127,23 @@ class View_stack */ void update_all_views() { - _place_labels(Rect(Point(), _size)); - _dirty_rect.mark_as_dirty(Rect(Point(), _size)); + Rect const whole_screen(Point(), _size); + + _place_labels(whole_screen); + _dirty_rect.mark_as_dirty(whole_screen); + + for (View *view = _first_view(); view; view = view->view_stack_next()) + view->mark_as_dirty(_outline(*view)); + + } + + /** + * mark all view-local dirty rectangles a clean + */ + void mark_all_views_as_clean() + { + for (View *view = _first_view(); view; view = view->view_stack_next()) + view->mark_as_clean(); } /** @@ -150,7 +168,7 @@ class View_stack rect.p2() + offset), view->abs_geometry()); - _mark_view_as_dirty(*view, r); + refresh_view(*view, r); } } @@ -159,7 +177,17 @@ class View_stack * * \param view view that should be updated on screen */ - void refresh_view(View const &view, Rect); + void refresh_view(View &view, Rect); + + /** + * Refresh entire view + */ + void refresh_view(View &view) { refresh_view(view, _outline(view)); } + + /** + * Refresh area + */ + void refresh(Rect); /** * Define view geometry @@ -186,7 +214,7 @@ class View_stack * bottom of the view stack, specify neighbor = 0 and * behind = false. */ - void stack(View const &view, View const *neighbor = 0, bool behind = true); + void stack(View &view, View const *neighbor = 0, bool behind = true); /** * Set view title