nitpicker: Reduce superfluous refresh operations

This commit is contained in:
Norman Feske 2014-06-23 13:15:53 +02:00
parent 65e283142a
commit 1ac343fabd
8 changed files with 117 additions and 22 deletions

View File

@ -104,6 +104,8 @@ class Chunky_menubar : public Texture<PT>,
session_label.string(), WHITE, "", session_color);
}
View &view() override { return *this; }
using Menubar::state;
};

View File

@ -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())

View File

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

View File

@ -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();
}

View File

@ -59,6 +59,7 @@ class User_state : public Mode, public View_stack
*/
bool _global_key_sequence = false;
void _update_menubar();
void _update_all();
public:

View File

@ -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<View_parent_elem> _children;
@ -154,7 +155,13 @@ class View : public Same_buffer_list_elem,
void remove_child(View const &child) { _children.remove(&child); }
template <typename FN>
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<View *>(e));
}
template <typename FN>
void for_each_const_child(FN const &fn) const {
for (View_parent_elem const *e = _children.first(); e; e = e->next())
fn(*static_cast<View const *>(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_ */

View File

@ -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);
}

View File

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