nitpicker: remove dirty_rect state from view stack

In the presence of potentially multiple output back ends, this
dirty_rect state must be maintained individually per back end. Instead
of storing the dirty_rect as view-stack member, the view stack now calls
a new 'Damage::mark_as_damaged' interface, which allows nitpicker to
propagate this information to multiple back ends. Unfortunately, the
patch must remove the per-view dirty_rect state.

Issue #3812
This commit is contained in:
Norman Feske 2020-06-26 20:06:20 +02:00
parent 067a7ad7e9
commit 795a817a33
4 changed files with 52 additions and 82 deletions

View File

@ -22,6 +22,7 @@
#include <framebuffer_session/connection.h>
#include <os/session_policy.h>
#include <nitpicker_gfx/tff_font.h>
#include <util/dirty_rect.h>
/* local includes */
#include "types.h"
@ -195,7 +196,7 @@ class Nitpicker::Gui_root : public Root_component<Gui_session>,
};
struct Nitpicker::Main : Focus_updater
struct Nitpicker::Main : Focus_updater, View_stack::Damage
{
Env &_env;
@ -225,15 +226,33 @@ struct Nitpicker::Main : Focus_updater
Area size = screen.size();
typedef Genode::Dirty_rect<Rect, 3> Dirty_rect;
Dirty_rect dirty_rect { };
/**
* Constructor
*/
Framebuffer_screen(Region_map &rm, Framebuffer::Session &fb)
: framebuffer(fb), fb_ds(rm, framebuffer.dataspace()) { }
:
framebuffer(fb), fb_ds(rm, framebuffer.dataspace())
{
dirty_rect.mark_as_dirty(Rect(Point(0, 0), size));
}
};
Reconstructible<Framebuffer_screen> _fb_screen = { _env.rm(), _framebuffer };
/**
* View_stack::Damage interface
*/
void mark_as_damaged(Rect rect) override
{
if (_fb_screen.constructed()) {
_fb_screen->dirty_rect.mark_as_dirty(rect);
}
}
Point _initial_pointer_pos()
{
Area const scr_size = _fb_screen->screen.size();
@ -266,7 +285,7 @@ struct Nitpicker::Main : Focus_updater
Tff_font const _font { _binary_default_tff_start, _glyph_buffer };
Focus _focus { };
View_stack _view_stack { _fb_screen->screen.size(), _focus, _font };
View_stack _view_stack { _fb_screen->screen.size(), _focus, _font, *this };
User_state _user_state { _focus, _global_keys, _view_stack, _initial_pointer_pos() };
View_owner _global_view_owner { };
@ -361,16 +380,6 @@ struct Nitpicker::Main : Focus_updater
*/
bool _motion_activity = false;
/**
* Perform redraw and flush pixels to the framebuffer
*/
void _draw_and_flush()
{
_view_stack.draw(_fb_screen->screen).flush([&] (Rect const &rect) {
_framebuffer.refresh(rect.x1(), rect.y1(),
rect.w(), rect.h()); });
}
Main(Env &env) : _env(env)
{
_view_stack.default_background(_builtin_background);
@ -471,13 +480,19 @@ void Nitpicker::Main::_handle_input()
if (result.motion_activity)
_view_stack.geometry(_pointer_origin, Rect(_user_state.pointer_pos(), Area()));
/* perform redraw and flush pixels to the framebuffer */
_view_stack.draw(_fb_screen->screen).flush([&] (Rect const &rect) {
/* perform redraw */
{
/* call 'Dirty_rect::flush' on a copy to preserve the state */
Dirty_rect dirty_rect = _fb_screen->dirty_rect;
dirty_rect.flush([&] (Rect const &rect) {
_view_stack.draw(_fb_screen->screen, rect); });
}
/* flush pixels to the framebuffer, reset dirty_rect */
_fb_screen->dirty_rect.flush([&] (Rect const &rect) {
_framebuffer.refresh(rect.x1(), rect.y1(),
rect.w(), rect.h()); });
_view_stack.mark_all_views_as_clean();
/* deliver framebuffer synchronization events */
for (Gui_session *s = _session_list.first(); s; s = s->next())
s->submit_sync();

View File

@ -17,7 +17,6 @@
/* Genode includes */
#include <util/string.h>
#include <util/list.h>
#include <util/dirty_rect.h>
#include <base/weak_ptr.h>
#include <base/rpc_server.h>
@ -30,8 +29,6 @@ namespace Nitpicker {
class Buffer;
class Focus;
typedef Dirty_rect<Rect, 3> Dirty_rect;
/*
* For each buffer, there is a list of views that belong to this buffer.
*/
@ -104,7 +101,6 @@ class Nitpicker::View : private Same_buffer_list_elem,
Point _buffer_off { }; /* offset to the visible buffer area */
View_owner &_owner;
Title _title { "" };
Dirty_rect _dirty_rect { };
List<View_parent_elem> _children { };
@ -274,23 +270,6 @@ class Nitpicker::View : private Same_buffer_list_elem,
* Return true if input at screen position 'p' refers to the view
*/
bool input_response_at(Point p) const;
/**
* 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

@ -190,9 +190,8 @@ void View_stack::draw_rec(Canvas_base &canvas, Font const &font,
if (next && left.valid()) draw_rec(canvas, font, next, left);
/* draw current view */
view->dirty_rect().flush([&] (Rect const &dirty_rect) {
Clip_guard clip_guard(canvas, Rect::intersect(clipped, dirty_rect));
{
Clip_guard clip_guard(canvas, clipped);
/* draw background if view is transparent */
if (view->uses_alpha())
@ -200,7 +199,7 @@ void View_stack::draw_rec(Canvas_base &canvas, Font const &font,
view->frame(canvas, _focus);
view->draw(canvas, font, _focus);
});
}
/* draw areas at the bottom/right of the current view */
if (next && right.valid()) draw_rec(canvas, font, next, right);
@ -213,8 +212,7 @@ void View_stack::refresh_view(View &view, Rect const rect)
/* rectangle constrained to view geometry */
Rect const view_rect = Rect::intersect(rect, _outline(view));
for (View *v = _first_view(); v; v = v->view_stack_next())
_mark_view_as_dirty(*v, view_rect);
_damage.mark_as_damaged(view_rect);
view.for_each_child([&] (View &child) { refresh_view(child, rect); });
}
@ -286,7 +284,7 @@ void View_stack::title(View &view, const char *title)
view.title(_font, title);
_place_labels(view.abs_geometry());
_mark_view_as_dirty(view, _outline(view));
_damage.mark_as_damaged(_outline(view));
}

View File

@ -23,6 +23,13 @@ namespace Nitpicker { class View_stack; }
class Nitpicker::View_stack
{
public:
struct Damage : Interface, Noncopyable
{
virtual void mark_as_damaged(Rect) = 0;
};
private:
Area _size;
@ -30,7 +37,7 @@ class Nitpicker::View_stack
Font const &_font;
List<View_stack_elem> _views { };
View *_default_background = nullptr;
Dirty_rect mutable _dirty_rect { };
Damage &_damage;
/**
* Return outline geometry of a view
@ -79,27 +86,15 @@ class Nitpicker::View_stack
template <typename VIEW>
VIEW *_next_view(VIEW &view) const;
/**
* Schedule 'rect' to be redrawn
*/
void _mark_view_as_dirty(View &view, Rect rect)
{
_dirty_rect.mark_as_dirty(rect);
view.mark_as_dirty(rect);
}
public:
/**
* Constructor
*/
View_stack(Area size, Focus &focus, Font const &font)
View_stack(Area size, Focus &focus, Font const &font, Damage &damage)
:
_size(size), _focus(focus), _font(font)
{
_dirty_rect.mark_as_dirty(Rect(Point(0, 0), _size));
}
_size(size), _focus(focus), _font(font), _damage(damage)
{ }
/**
* Return size
@ -121,16 +116,11 @@ class Nitpicker::View_stack
void draw_rec(Canvas_base &, Font const &, View const *, Rect) const;
/**
* Draw dirty areas
* Draw specified area
*/
Dirty_rect draw(Canvas_base &canvas) const
void draw(Canvas_base &canvas, Rect rect) const
{
Dirty_rect result = _dirty_rect;
_dirty_rect.flush([&] (Rect const &rect) {
draw_rec(canvas, _font, _first_view(), rect); });
return result;
draw_rec(canvas, _font, _first_view(), rect);
}
/**
@ -141,19 +131,7 @@ class Nitpicker::View_stack
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();
_damage.mark_as_damaged(whole_screen);
}
/**