From d22cddd1e8308d27d35c75e4bf0e13d8ee0e3d8f Mon Sep 17 00:00:00 2001 From: Norman Feske Date: Wed, 30 Apr 2014 13:51:45 +0200 Subject: [PATCH] nitpicker: Perform redraw asynchronously This patch changes nitpicker's way of redrawing. Originally, redraw operations were triggered immediately by the RPC functions invoked by clients. In the presence of clients that invoked a large number of those functions, the server could become overloaded with processing redraw operations. The new version performs redraw operations out of band with the RPC functions. Similar to the design of the DOpE GUI server, redraw operations are processed periodically. The RPC functions merely modify meta data and track the dirty areas that need to be updated. Consequently, nitpicker's RPC functions become light-weight operations. As a nice collateral effect of this patch, nitpicker's internal structure could be simplified because the drawing backend is no longer needed by the code that dispatches the RPC interface. --- repos/os/src/server/nitpicker/background.h | 18 +- .../os/src/server/nitpicker/chunky_menubar.h | 13 +- repos/os/src/server/nitpicker/input.h | 4 +- repos/os/src/server/nitpicker/main.cc | 197 ++++++------------ repos/os/src/server/nitpicker/mode.h | 2 +- repos/os/src/server/nitpicker/mouse_cursor.h | 11 +- repos/os/src/server/nitpicker/session.h | 2 + repos/os/src/server/nitpicker/user_state.cc | 19 +- repos/os/src/server/nitpicker/user_state.h | 8 +- repos/os/src/server/nitpicker/view.cc | 8 + repos/os/src/server/nitpicker/view.h | 19 +- repos/os/src/server/nitpicker/view_stack.cc | 120 +++++------ repos/os/src/server/nitpicker/view_stack.h | 113 +++++----- 13 files changed, 242 insertions(+), 292 deletions(-) diff --git a/repos/os/src/server/nitpicker/background.h b/repos/os/src/server/nitpicker/background.h index 8355d0182..6adb91b35 100644 --- a/repos/os/src/server/nitpicker/background.h +++ b/repos/os/src/server/nitpicker/background.h @@ -42,20 +42,30 @@ struct Background : private Texture_base, Session, View ** Session interface ** ***********************/ - void submit_input_event(Input::Event) { } + void submit_input_event(Input::Event) override { } + void submit_sync() override { } /******************** ** View interface ** ********************/ - int frame_size(Mode const &mode) const { return 0; } - void frame(Canvas_base &canvas, Mode const &mode) { } + int frame_size(Mode const &mode) const override { return 0; } + void frame(Canvas_base &canvas, Mode const &mode) const override { } - void draw(Canvas_base &canvas, Mode const &mode) const + void draw(Canvas_base &canvas, Mode const &mode) const override { Rect const view_rect = abs_geometry(); Clip_guard clip_guard(canvas, view_rect); + + if (tmp_fb) { + for (unsigned i = 0; i < 7; i++) { + + canvas.draw_box(view_rect, Color(i*2,i*6,i*16*2)); + tmp_fb->refresh(0,0,1024,768); + } + } + canvas.draw_box(view_rect, color); } }; diff --git a/repos/os/src/server/nitpicker/chunky_menubar.h b/repos/os/src/server/nitpicker/chunky_menubar.h index 6e2ddbc59..5c268f360 100644 --- a/repos/os/src/server/nitpicker/chunky_menubar.h +++ b/repos/os/src/server/nitpicker/chunky_menubar.h @@ -49,18 +49,19 @@ class Chunky_menubar : public Texture, ** Session interface ** ***********************/ - void submit_input_event(Input::Event) { } + void submit_input_event(Input::Event) override { } + void submit_sync() override { } /******************** ** View interface ** ********************/ - int frame_size(Mode const &mode) const { return 0; } - void frame(Canvas_base &canvas, Mode const &mode) { } - void draw(Canvas_base &canvas, Mode const &mode) + int frame_size(Mode const &mode) const override { return 0; } + void frame(Canvas_base &canvas, Mode const &mode) const override { } + void draw(Canvas_base &canvas, Mode const &mode) const override { - Clip_guard clip_guard(canvas, *this); + Clip_guard clip_guard(canvas, geometry()); /* draw menubar content */ canvas.draw_texture(abs_position(), *this, Texture_painter::SOLID, BLACK, false); @@ -71,7 +72,7 @@ class Chunky_menubar : public Texture, ** Menubar interface ** ***********************/ - void state(Menubar_state const state) + void state(Menubar_state const state) override { *static_cast(this) = state; diff --git a/repos/os/src/server/nitpicker/input.h b/repos/os/src/server/nitpicker/input.h index 4cc3c9f97..50a396ebd 100644 --- a/repos/os/src/server/nitpicker/input.h +++ b/repos/os/src/server/nitpicker/input.h @@ -63,7 +63,7 @@ static Input::Event merge_motion_events(Input::Event const *ev, unsigned n) static void import_input_events(Input::Event *ev_buf, unsigned num_ev, - User_state &user_state, Canvas_base &canvas) + User_state &user_state) { /* * Take events from input event buffer, merge consecutive motion @@ -91,7 +91,7 @@ static void import_input_events(Input::Event *ev_buf, unsigned num_ev, continue; /* pass event to user state */ - user_state.handle_event(curr, canvas); + user_state.handle_event(curr); } } diff --git a/repos/os/src/server/nitpicker/main.cc b/repos/os/src/server/nitpicker/main.cc index 3ff257fcc..5bd31eef0 100644 --- a/repos/os/src/server/nitpicker/main.cc +++ b/repos/os/src/server/nitpicker/main.cc @@ -49,6 +49,7 @@ namespace Nitpicker { struct Main; } + using Genode::size_t; using Genode::Allocator; using Genode::Rpc_entrypoint; @@ -68,6 +69,9 @@ using Genode::Attached_ram_dataspace; using Genode::Attached_dataspace; +Framebuffer::Session *tmp_fb; + + /*************** ** Utilities ** ***************/ @@ -80,46 +84,10 @@ extern char _binary_default_tff_start; Text_painter::Font default_font(&_binary_default_tff_start); -class Flush_merger -{ - private: - - Rect _to_be_flushed = { Point(), Area() }; - - public: - - bool defer = false; - - Rect to_be_flushed() const { return _to_be_flushed; } - - void merge(Rect rect) - { - if (_to_be_flushed.valid()) - _to_be_flushed = Rect::compound(_to_be_flushed, rect); - else - _to_be_flushed = rect; - } - - void reset() { _to_be_flushed = Rect(Point(), Area()); } -}; - - template -class Screen : public Canvas, public Flush_merger +struct Screen : public Canvas { - protected: - - /** - * Surface_base::Flusher interface - */ - void flush_pixels(Rect rect) { merge(rect); } - - public: - - /** - * Constructor - */ - Screen(PT *base, Area size) : Canvas(base, size) { } + Screen(PT *base, Area size) : Canvas(base, size) { } }; @@ -167,12 +135,6 @@ struct Buffer_provider }; -struct Canvas_accessor -{ - virtual Canvas_base &canvas() = 0; -}; - - template class Chunky_dataspace_texture : public Buffer, public Texture @@ -321,17 +283,13 @@ class Framebuffer::Session_component : public Genode::Rpc_object ::Buffer *_buffer = 0; View_stack &_view_stack; ::Session &_session; - Flush_merger &_flush_merger; Framebuffer::Session &_framebuffer; - Canvas_accessor &_canvas_accessor; Buffer_provider &_buffer_provider; Signal_context_capability _mode_sigh; Signal_context_capability _sync_sigh; Framebuffer::Mode _mode; bool _alpha = false; - Canvas_base &_canvas() { return _canvas_accessor.canvas(); } - public: /** @@ -339,16 +297,12 @@ class Framebuffer::Session_component : public Genode::Rpc_object */ Session_component(View_stack &view_stack, ::Session &session, - Flush_merger &flush_merger, Framebuffer::Session &framebuffer, - Canvas_accessor &canvas_accessor, Buffer_provider &buffer_provider) : _view_stack(view_stack), _session(session), - _flush_merger(flush_merger), _framebuffer(framebuffer), - _canvas_accessor(canvas_accessor), _buffer_provider(buffer_provider) { } @@ -373,6 +327,12 @@ class Framebuffer::Session_component : public Genode::Rpc_object Signal_transmitter(_mode_sigh).submit(); } + void submit_sync() + { + if (_sync_sigh.valid()) + Signal_transmitter(_sync_sigh).submit(); + } + /************************************ ** Framebuffer::Session interface ** @@ -399,19 +359,9 @@ class Framebuffer::Session_component : public Genode::Rpc_object void refresh(int x, int y, int w, int h) override { - _view_stack.update_session_views(_canvas(), _session, - Rect(Point(x, y), Area(w, h))); + Rect const rect(Point(x, y), Area(w, h)); - /* flush dirty pixels to physical frame buffer */ - if (_flush_merger.defer == false) { - Rect r = _flush_merger.to_be_flushed(); - _framebuffer.refresh(r.x1(), r.y1(), r.w(), r.h()); - _flush_merger.reset(); - } - _flush_merger.defer = true; - - if (_sync_sigh.valid()) - Signal_transmitter(_sync_sigh).submit(); + _view_stack.mark_session_views_as_dirty(_session, rect); } }; @@ -425,24 +375,19 @@ class View_component : public Genode::List::Element, View_stack &_view_stack; ::View _view; - Canvas_accessor &_canvas_accessor; Rpc_entrypoint &_ep; - Canvas_base &_canvas() { return _canvas_accessor.canvas(); } - public: /** * Constructor */ View_component(::Session &session, View_stack &view_stack, - Canvas_accessor &canvas_accessor, Rpc_entrypoint &ep, ::View *parent_view): _view_stack(view_stack), _view(session, session.stay_top() ? ::View::STAY_TOP : ::View::NOT_STAY_TOP, ::View::NOT_TRANSPARENT, ::View::NOT_BACKGROUND, parent_view), - _canvas_accessor(canvas_accessor), _ep(ep) { } @@ -454,31 +399,30 @@ class View_component : public Genode::List::Element, ******************************/ int viewport(int x, int y, int w, int h, - int buf_x, int buf_y, bool redraw) + int buf_x, int buf_y, bool) override { /* transpose y position of top-level views by vertical session offset */ if (_view.top_level()) y += _view.session().v_offset(); - _view_stack.viewport(_canvas(), _view, - Rect(Point(x, y), Area(w, h)), - Point(buf_x, buf_y), redraw); + _view_stack.viewport(_view, Rect(Point(x, y), Area(w, h)), + Point(buf_x, buf_y)); return 0; } - int stack(Nitpicker::View_capability neighbor_cap, bool behind, bool redraw) + int stack(Nitpicker::View_capability neighbor_cap, bool behind, bool) override { Object_pool::Guard nvc(_ep.lookup_and_lock(neighbor_cap)); ::View *neighbor_view = nvc ? &nvc->view() : 0; - _view_stack.stack(_canvas(), _view, neighbor_view, behind, redraw); + _view_stack.stack(_view, neighbor_view, behind); return 0; } - int title(Title const &title) + int title(Title const &title) override { - _view_stack.title(_canvas(), _view, title.string()); + _view_stack.title(_view, title.string()); return 0; } }; @@ -501,8 +445,6 @@ class Nitpicker::Session_component : public Genode::Rpc_object, /* Framebuffer_session_component */ Framebuffer::Session_component _framebuffer_session_component; - Canvas_accessor &_canvas_accessor; - /* Input_session_component */ Input::Session_component _input_session_component; @@ -545,8 +487,6 @@ class Nitpicker::Session_component : public Genode::Rpc_object, _buffer_size = 0; } - Canvas_base &_canvas() { return _canvas_accessor.canvas(); } - public: /** @@ -555,9 +495,7 @@ class Nitpicker::Session_component : public Genode::Rpc_object, Session_component(Session_label const &label, View_stack &view_stack, Rpc_entrypoint &ep, - Flush_merger &flush_merger, Framebuffer::Session &framebuffer, - Canvas_accessor &canvas_accessor, int v_offset, bool provides_default_bg, bool stay_top, @@ -567,9 +505,7 @@ class Nitpicker::Session_component : public Genode::Rpc_object, ::Session(label, v_offset, stay_top), _buffer_alloc(&buffer_alloc, ram_quota), _framebuffer(framebuffer), - _framebuffer_session_component(view_stack, *this, flush_merger, - framebuffer, canvas_accessor, *this), - _canvas_accessor(canvas_accessor), + _framebuffer_session_component(view_stack, *this, framebuffer, *this), _ep(ep), _view_stack(view_stack), _framebuffer_session_cap(_ep.manage(&_framebuffer_session_component)), _input_session_cap(_ep.manage(&_input_session_component)), @@ -595,9 +531,9 @@ class Nitpicker::Session_component : public Genode::Rpc_object, void upgrade_ram_quota(size_t ram_quota) { _buffer_alloc.upgrade(ram_quota); } - /****************************************** - ** Nitpicker-internal session interface ** - ******************************************/ + /********************************** + ** Nitpicker-internal interface ** + **********************************/ void submit_input_event(Input::Event e) { @@ -614,6 +550,11 @@ class Nitpicker::Session_component : public Genode::Rpc_object, _input_session_component.submit(&e); } + void submit_sync() override + { + _framebuffer_session_component.submit_sync(); + } + /********************************* ** Nitpicker session interface ** @@ -636,7 +577,7 @@ class Nitpicker::Session_component : public Genode::Rpc_object, * Use a heap partition! */ View_component *view = new (env()->heap()) - View_component(*this, _view_stack, _canvas_accessor, _ep, + View_component(*this, _view_stack, _ep, parent_view ? &parent_view->view() : 0); if (parent_view) @@ -654,7 +595,7 @@ class Nitpicker::Session_component : public Genode::Rpc_object, View_component *vc = dynamic_cast(_ep.lookup_and_lock(view_cap)); if (!vc) return; - _view_stack.remove_view(_canvas(), vc->view()); + _view_stack.remove_view(vc->view()); _ep.dissolve(vc); _view_list.remove(vc); destroy(env()->heap(), vc); @@ -743,9 +684,7 @@ class Nitpicker::Root : public Genode::Root_component Global_keys &_global_keys; Framebuffer::Mode _scr_mode; View_stack &_view_stack; - Flush_merger &_flush_merger; Framebuffer::Session &_framebuffer; - Canvas_accessor &_canvas_accessor; int _default_v_offset; protected: @@ -774,9 +713,8 @@ class Nitpicker::Root : public Genode::Root_component Session_component *session = new (md_alloc()) Session_component(Session_label(args), _view_stack, *ep(), - _flush_merger, _framebuffer, _canvas_accessor, - v_offset, provides_default_bg, stay_top, - *md_alloc(), unused_quota); + _framebuffer, v_offset, provides_default_bg, + stay_top, *md_alloc(), unused_quota); session->apply_session_color(); _session_list.insert(session); @@ -806,14 +744,14 @@ class Nitpicker::Root : public Genode::Root_component */ Root(Session_list &session_list, Global_keys &global_keys, Rpc_entrypoint &session_ep, View_stack &view_stack, - Allocator &md_alloc, Flush_merger &flush_merger, - Framebuffer::Session &framebuffer, Canvas_accessor &canvas_accessor, + Allocator &md_alloc, + Framebuffer::Session &framebuffer, int default_v_offset) : Root_component(&session_ep, &md_alloc), _session_list(session_list), _global_keys(global_keys), - _view_stack(view_stack), _flush_merger(flush_merger), - _framebuffer(framebuffer), _canvas_accessor(canvas_accessor), + _view_stack(view_stack), + _framebuffer(framebuffer), _default_v_offset(default_v_offset) { } }; @@ -877,17 +815,6 @@ struct Nitpicker::Main Genode::Volatile_object fb_screen = { framebuffer }; - struct Canvas_accessor : ::Canvas_accessor - { - Genode::Volatile_object &fb_screen; - - Canvas_accessor(Genode::Volatile_object &fb_screen) - : fb_screen(fb_screen) { } - - Canvas_base &canvas() override { return fb_screen->screen; } - - } canvas_accessor = { fb_screen }; - void handle_fb_mode(unsigned); Signal_rpc_member
fb_mode_dispatcher = { ep, *this, &Main::handle_fb_mode }; @@ -915,10 +842,8 @@ struct Nitpicker::Main */ Genode::Sliced_heap sliced_heap = { env()->ram_session(), env()->rm_session() }; - Root np_root = { session_list, global_keys, ep.rpc_ep(), - user_state, sliced_heap, fb_screen->screen, - framebuffer, canvas_accessor, - Framebuffer_screen::MENUBAR_HEIGHT }; + Root np_root = { session_list, global_keys, ep.rpc_ep(), user_state, + sliced_heap, framebuffer, Framebuffer_screen::MENUBAR_HEIGHT }; Genode::Reporter pointer_reporter = { "pointer" }; @@ -941,18 +866,20 @@ struct Nitpicker::Main Signal_rpc_member
input_dispatcher = { ep, *this, &Main::handle_input }; /* - * Dispatch input on periodic timer signals every 10 milliseconds + * Dispatch input and redraw periodically */ Timer::Connection timer; Main(Server::Entrypoint &ep) : ep(ep) { +// tmp_fb = &framebuffer; + fb_screen->menubar.state(Menubar_state(user_state, "", "", BLACK)); user_state.default_background(background); - user_state.stack(canvas_accessor.canvas(), mouse_cursor); - user_state.stack(canvas_accessor.canvas(), fb_screen->menubar); - user_state.stack(canvas_accessor.canvas(), background); + user_state.stack(mouse_cursor); + user_state.stack(fb_screen->menubar); + user_state.stack(background); config()->sigh(config_dispatcher); Signal_transmitter(config_dispatcher).submit(); @@ -983,8 +910,7 @@ void Nitpicker::Main::handle_input(unsigned) /* handle batch of pending events */ if (input.is_pending()) - import_input_events(ev_buf, input.flush(), user_state, - canvas_accessor.canvas()); + import_input_events(ev_buf, input.flush(), user_state); Point const new_mouse_pos = user_state.mouse_pos(); Point const menubar_offset = Point(0, Framebuffer_screen::MENUBAR_HEIGHT); @@ -1002,18 +928,19 @@ void Nitpicker::Main::handle_input(unsigned) /* update mouse cursor */ if (old_mouse_pos != new_mouse_pos) - user_state.viewport(canvas_accessor.canvas(), mouse_cursor, - Rect(new_mouse_pos, mouse_size), - Point(), true); + user_state.viewport(mouse_cursor, + Rect(new_mouse_pos, mouse_size), Point()); - /* flush dirty pixels to physical frame buffer */ - if (fb_screen->screen.defer == false) { - Rect const r = fb_screen->screen.to_be_flushed(); - if (r.valid()) - framebuffer.refresh(r.x1(), r.y1(), r.w(), r.h()); - fb_screen->screen.reset(); + /* perform redraw and flush pixels to the framebuffer */ + user_state.draw(fb_screen->screen).flush([&] (Rect const &rect) { + framebuffer.refresh(rect.x1(), rect.y1(), + rect.w(), rect.h()); }); + + /* deliver framebuffer synchronization events */ + if (!user_state.kill()) { + for (::Session *s = session_list.first(); s; s = s->next()) + s->submit_sync(); } - fb_screen->screen.defer = false; /* * In kill mode, we do not leave the dispatch function in order to @@ -1054,7 +981,7 @@ void Nitpicker::Main::handle_config(unsigned) s->apply_session_color(); /* redraw */ - user_state.update_all_views(canvas_accessor.canvas()); + user_state.update_all_views(); } @@ -1064,7 +991,7 @@ void Nitpicker::Main::handle_fb_mode(unsigned) Menubar_state menubar_state = fb_screen->menubar.state(); /* remove old version of menu bar from view stack */ - user_state.remove_view(canvas_accessor.canvas(), fb_screen->menubar, false); + user_state.remove_view(fb_screen->menubar, false); /* reconstruct framebuffer screen and menu bar */ fb_screen.construct(framebuffer); @@ -1076,10 +1003,10 @@ void Nitpicker::Main::handle_fb_mode(unsigned) fb_screen->menubar.state(menubar_state); /* re-insert menu bar behind mouse cursor */ - user_state.stack(canvas_accessor.canvas(), fb_screen->menubar, &mouse_cursor); + user_state.stack(fb_screen->menubar, &mouse_cursor); /* redraw */ - user_state.update_all_views(canvas_accessor.canvas()); + user_state.update_all_views(); } diff --git a/repos/os/src/server/nitpicker/mode.h b/repos/os/src/server/nitpicker/mode.h index a6e645760..4cb0e0a1b 100644 --- a/repos/os/src/server/nitpicker/mode.h +++ b/repos/os/src/server/nitpicker/mode.h @@ -54,7 +54,7 @@ class Mode /** * Discard all references to specified view */ - virtual void forget(Canvas_base &, View const &v) { + virtual void forget(View const &v) { if (&v == _focused_view) _focused_view = 0; } }; diff --git a/repos/os/src/server/nitpicker/mouse_cursor.h b/repos/os/src/server/nitpicker/mouse_cursor.h index f4d01174f..5c5726df4 100644 --- a/repos/os/src/server/nitpicker/mouse_cursor.h +++ b/repos/os/src/server/nitpicker/mouse_cursor.h @@ -48,7 +48,8 @@ class Mouse_cursor : public Texture, ** Session interface ** ***********************/ - void submit_input_event(Input::Event) { } + void submit_input_event(Input::Event) override { } + void submit_sync() override { } /******************** @@ -59,18 +60,18 @@ class Mouse_cursor : public Texture, * The mouse cursor is always displayed without a surrounding frame. */ - int frame_size(Mode const &mode) const { return 0; } + int frame_size(Mode const &mode) const override { return 0; } - void frame(Canvas_base &canvas, Mode const &mode) const { } + void frame(Canvas_base &canvas, Mode const &mode) const override { } - void draw(Canvas_base &canvas, Mode const &mode) const + void draw(Canvas_base &canvas, Mode const &mode) const override { Rect const view_rect = abs_geometry(); Clip_guard clip_guard(canvas, view_rect); /* draw area behind the mouse cursor */ - _view_stack.draw_rec(canvas, view_stack_next(), 0, 0, view_rect); + _view_stack.draw_rec(canvas, view_stack_next(), view_rect); /* draw mouse cursor */ canvas.draw_texture(view_rect.p1(), *this, Texture_painter::MASKED, BLACK, true); diff --git a/repos/os/src/server/nitpicker/session.h b/repos/os/src/server/nitpicker/session.h index f9d0267d7..1f797ea8c 100644 --- a/repos/os/src/server/nitpicker/session.h +++ b/repos/os/src/server/nitpicker/session.h @@ -61,6 +61,8 @@ class Session : public Session_list::Element virtual void submit_input_event(Input::Event ev) = 0; + virtual void submit_sync() = 0; + Genode::Session_label const &label() const { return _label; } Texture_base const *texture() const { return _texture; } diff --git a/repos/os/src/server/nitpicker/user_state.cc b/repos/os/src/server/nitpicker/user_state.cc index 7ee395c46..a23d2f31e 100644 --- a/repos/os/src/server/nitpicker/user_state.cc +++ b/repos/os/src/server/nitpicker/user_state.cc @@ -43,7 +43,7 @@ User_state::User_state(Global_keys &global_keys, Area view_stack_size, Menubar & { } -void User_state::handle_event(Input::Event ev, Canvas_base &canvas) +void User_state::handle_event(Input::Event ev) { Input::Keycode const keycode = ev.keycode(); Input::Event::Type const type = ev.type(); @@ -101,13 +101,12 @@ void User_state::handle_event(Input::Event ev, Canvas_base &canvas) struct Update_all_guard { User_state &user_state; - Canvas_base &canvas; bool update_menubar = false; bool update_views = false; char const *menu_title = ""; - Update_all_guard(User_state &user_state, Canvas_base &canvas) - : user_state(user_state), canvas(canvas) { } + Update_all_guard(User_state &user_state) + : user_state(user_state) { } ~Update_all_guard() { @@ -123,9 +122,9 @@ void User_state::handle_event(Input::Event ev, Canvas_base &canvas) user_state._menubar.state(state); if (update_menubar || update_views) - user_state.update_all_views(canvas); + user_state.update_all_views(); } - } update_all_guard(*this, canvas); + } update_all_guard(*this); /* * Handle start of a key sequence @@ -138,7 +137,7 @@ void User_state::handle_event(Input::Event ev, Canvas_base &canvas) */ if (kill() && keycode == Input::BTN_LEFT) { if (pointed_view) - lock_out_session(canvas, pointed_view->session()); + lock_out_session(pointed_view->session()); /* leave kill mode */ update_all_guard.update_menubar = true; @@ -278,12 +277,12 @@ void User_state::handle_event(Input::Event ev, Canvas_base &canvas) ** Mode interface ** ********************/ -void User_state::forget(Canvas_base &canvas, View const &view) +void User_state::forget(View const &view) { if (focused_view() == &view) { - Mode::forget(canvas, view); + Mode::forget(view); _menubar.state(Menubar_state(*this, "", "", BLACK)); - update_all_views(canvas); + update_all_views(); } if (_input_receiver && view.belongs_to(*_input_receiver)) _input_receiver = 0; diff --git a/repos/os/src/server/nitpicker/user_state.h b/repos/os/src/server/nitpicker/user_state.h index 5c412c319..4e6d00d5d 100644 --- a/repos/os/src/server/nitpicker/user_state.h +++ b/repos/os/src/server/nitpicker/user_state.h @@ -76,10 +76,10 @@ class User_state : public Mode, public View_stack /** * Handle input event * - * This function controls the Nitpicker mode and the - * user state variables. + * This function controls the Nitpicker mode and the user state + * variables. */ - void handle_event(Input::Event ev, Canvas_base &); + void handle_event(Input::Event ev); /** * Accessors @@ -89,7 +89,7 @@ class User_state : public Mode, public View_stack /** * Mode interface */ - void forget(Canvas_base &, View const &) override; + void forget(View const &) override; }; #endif diff --git a/repos/os/src/server/nitpicker/view.cc b/repos/os/src/server/nitpicker/view.cc index b79b9c70d..59538daee 100644 --- a/repos/os/src/server/nitpicker/view.cc +++ b/repos/os/src/server/nitpicker/view.cc @@ -108,6 +108,14 @@ void View::draw(Canvas_base &canvas, Mode const &mode) const */ if (!canvas.clip().valid() || !&_session) return; + if (tmp_fb) { + for (unsigned i = 0; i < 7; i++) { + canvas.draw_box(view_rect, Color(i*2,i*6,i*16*2)); + tmp_fb->refresh(0,0,1024,768); + } + } + + /* allow alpha blending only in flat mode */ bool allow_alpha = mode.flat(); diff --git a/repos/os/src/server/nitpicker/view.h b/repos/os/src/server/nitpicker/view.h index 46357957a..19522a5a4 100644 --- a/repos/os/src/server/nitpicker/view.h +++ b/repos/os/src/server/nitpicker/view.h @@ -16,12 +16,19 @@ #include #include +#include #include "mode.h" #include "session.h" class Buffer; +#include +extern Framebuffer::Session *tmp_fb; + + +typedef Genode::Dirty_rect Dirty_rect; + /* * For each buffer, there is a list of views that belong to @@ -57,12 +64,12 @@ class View : public Same_buffer_list_elem, Transparent const _transparent; /* background is partly visible */ Background _background; /* view is a background view */ - View *_parent; /* parent view */ - Rect _geometry; /* position and size relative to parent */ - Rect _label_rect; /* position and size of label */ - Point _buffer_off; /* offset to the visible buffer area */ - Session &_session; /* session that created the view */ - char _title[TITLE_LEN]; + View *_parent; /* parent view */ + Rect _geometry; /* position and size relative to parent */ + Rect _label_rect; /* position and size of label */ + Point _buffer_off; /* offset to the visible buffer area */ + Session &_session; /* session that created the view */ + char _title[TITLE_LEN]; Genode::List _children; diff --git a/repos/os/src/server/nitpicker/view_stack.cc b/repos/os/src/server/nitpicker/view_stack.cc index 89230750a..39a6def48 100644 --- a/repos/os/src/server/nitpicker/view_stack.cc +++ b/repos/os/src/server/nitpicker/view_stack.cc @@ -38,7 +38,7 @@ static View const *last_stay_top_view(View const *view) **************************/ template -VIEW *View_stack::_next_view(VIEW *view) const +VIEW *View_stack::_next_view(VIEW &view) const { Session * const active_session = _mode.focused_view() ? &_mode.focused_view()->session() : 0; @@ -46,16 +46,17 @@ VIEW *View_stack::_next_view(VIEW *view) const View * const active_background = active_session ? active_session->background() : 0; - for (;;) { - view = view ? view->view_stack_next() : 0; + for (VIEW *next_view = &view; ;) { + + next_view = next_view->view_stack_next(); /* check if we hit the bottom of the view stack */ - if (!view) return 0; + if (!next_view) return 0; - if (!view->background()) return view; + if (!next_view->background()) return next_view; - if (is_default_background(view) || view == active_background) - return view; + if (is_default_background(*next_view) || next_view == active_background) + return next_view; /* view is a background view belonging to a non-focused session */ } @@ -82,7 +83,7 @@ View const *View_stack::_target_stack_position(View const *neighbor, bool behind /* find target position in view stack */ View const *cv = last_stay_top_view(_first_view()); - for ( ; cv; cv = _next_view(cv)) { + for ( ; cv; cv = _next_view(*cv)) { /* bring view to front? */ if (behind && !neighbor) @@ -93,11 +94,11 @@ View const *View_stack::_target_stack_position(View const *neighbor, bool behind break; /* insert view in front of cv? */ - if (!behind && (_next_view(cv) == neighbor)) + if (!behind && (_next_view(*cv) == neighbor)) break; /* insert view in front of the background? */ - if (!behind && !neighbor && _next_view(cv)->background()) + if (!behind && !neighbor && _next_view(*cv)->background()) break; } @@ -114,18 +115,18 @@ void View_stack::_optimize_label_rec(View const *cv, View const *lv, Rect rect, /* find next view that intersects with the rectangle or the target view */ Rect clipped; while (cv && cv != lv && !(clipped = Rect::intersect(_outline(*cv), rect)).valid()) - cv = _next_view(cv); + cv = _next_view(*cv); /* reached end of view stack */ if (!cv) return; - if (cv != lv && _next_view(cv)) { + if (cv != lv && _next_view(*cv)) { /* cut current view from rectangle and go into sub rectangles */ Rect r[4]; rect.cut(clipped, &r[0], &r[1], &r[2], &r[3]); for (int i = 0; i < 4; i++) - _optimize_label_rec(_next_view(cv), lv, r[i], optimal); + _optimize_label_rec(_next_view(*cv), lv, r[i], optimal); return; } @@ -150,16 +151,16 @@ void View_stack::_optimize_label_rec(View const *cv, View const *lv, Rect rect, } -void View_stack::_place_labels(Canvas_base &canvas, Rect rect) +void View_stack::_place_labels(Rect rect) { /* do not calculate label positions in flat mode */ if (_mode.flat()) return; /* ignore mouse cursor */ - View const *start = _next_view(_first_view()); - View *view = _next_view(_first_view()); + View const *start = _next_view(*_first_view()); + View *view = _next_view(*_first_view()); - for (; view && _next_view(view); view = _next_view(view)) { + for (; view && _next_view(*view); view = _next_view(*view)) { Rect const view_rect = view->abs_geometry(); if (Rect::intersect(view_rect, rect).valid()) { @@ -167,7 +168,7 @@ void View_stack::_place_labels(Canvas_base &canvas, Rect rect) Rect old = view->label_rect(), best; /* calculate best visible label position */ - Rect rect = Rect::intersect(Rect(Point(), canvas.size()), view_rect); + Rect rect = Rect::intersect(Rect(Point(), _size), view_rect); if (start) _optimize_label_rec(start, view, rect, &best); /* @@ -181,21 +182,20 @@ void View_stack::_place_labels(Canvas_base &canvas, Rect rect) view->label_pos(Point(x, best.y1())); /* refresh old and new label positions */ - refresh_view(canvas, *view, view, old); - refresh_view(canvas, *view, view, view->label_rect()); + refresh_view(*view, old); + refresh_view(*view, view->label_rect()); } } } -void View_stack::draw_rec(Canvas_base &canvas, View const *view, View const *dst_view, - Session const *exclude, Rect rect) const +void View_stack::draw_rec(Canvas_base &canvas, View const *view, Rect rect) const { Rect clipped; /* find next view that intersects with the current clipping rectangle */ for ( ; view && !(clipped = Rect::intersect(_outline(*view), rect)).valid(); ) - view = _next_view(view); + view = _next_view(*view); /* check if we hit the bottom of the view stack */ if (!view) return; @@ -203,94 +203,86 @@ void View_stack::draw_rec(Canvas_base &canvas, View const *view, View const *dst Rect top, left, right, bottom; rect.cut(clipped, &top, &left, &right, &bottom); - View const *next = _next_view(view); + View const *next = _next_view(*view); /* draw areas at the top/left of the current view */ - if (next && top.valid()) draw_rec(canvas, next, dst_view, exclude, top); - if (next && left.valid()) draw_rec(canvas, next, dst_view, exclude, left); + if (next && top.valid()) draw_rec(canvas, next, top); + if (next && left.valid()) draw_rec(canvas, next, left); /* draw current view */ - if (!dst_view || (dst_view == view) || view->transparent()) { - + { Clip_guard clip_guard(canvas, clipped); /* draw background if view is transparent */ if (view->uses_alpha()) - draw_rec(canvas, _next_view(view), 0, 0, clipped); + draw_rec(canvas, _next_view(*view), clipped); view->frame(canvas, _mode); - - if (!exclude || !view->belongs_to(*exclude)) - view->draw(canvas, _mode); + view->draw(canvas, _mode); } /* draw areas at the bottom/right of the current view */ - if (next && right.valid()) draw_rec(canvas, next, dst_view, exclude, right); - if (next && bottom.valid()) draw_rec(canvas, next, dst_view, exclude, bottom); + if (next && right.valid()) draw_rec(canvas, next, right); + if (next && bottom.valid()) draw_rec(canvas, next, bottom); } -void View_stack::refresh_view(Canvas_base &canvas, View const &view, - View const *dst_view, Rect rect) +void View_stack::refresh_view(View const &view, Rect const rect) { /* clip argument agains view outline */ - rect = Rect::intersect(rect, _outline(view)); + Rect const intersection = Rect::intersect(rect, _outline(view)); - draw_rec(canvas, _first_view(), dst_view, 0, rect); + _dirty_rect.mark_as_dirty(intersection); + + view.for_each_child([&] (View const &child) { refresh_view(child, rect); }); } -void View_stack::viewport(Canvas_base &canvas, View &view, Rect rect, - Point buffer_off, bool do_redraw) +void View_stack::viewport(View &view, Rect const rect, Point const buffer_off) { - Rect const old_compound = _compound_outline(view); + Rect const old_outline = _outline(view); + + refresh_view(view, Rect(Point(), _size)); view.geometry(Rect(rect)); view.buffer_off(buffer_off); - Rect const new_compound = _compound_outline(view); + refresh_view(view, Rect(Point(), _size)); - Rect const compound = Rect::compound(old_compound, new_compound); + Rect const compound = Rect::compound(old_outline, _outline(view)); /* update labels (except when moving the mouse cursor) */ if (&view != _first_view()) - _place_labels(canvas, compound); - - if (!_mode.flat()) - do_redraw = true; - - /* update area on screen */ - draw_rec(canvas, _first_view(), 0, do_redraw ? 0 : &view.session(), compound); + _place_labels(compound); } -void View_stack::stack(Canvas_base &canvas, View const &view, - View const *neighbor, bool behind, bool do_redraw) +void View_stack::stack(View const &view, View const *neighbor, bool behind) { _views.remove(&view); _views.insert(&view, _target_stack_position(neighbor, behind)); - _place_labels(canvas, view.abs_geometry()); + _place_labels(view.abs_geometry()); - /* refresh affected screen area */ - refresh_view(canvas, view, 0, _outline(view)); + _dirty_rect.mark_as_dirty(_outline(view)); } -void View_stack::title(Canvas_base &canvas, View &view, const char *title) +void View_stack::title(View &view, const char *title) { view.title(title); - _place_labels(canvas, view.abs_geometry()); - refresh_view(canvas, view, 0, _outline(view)); + _place_labels(view.abs_geometry()); + + _dirty_rect.mark_as_dirty(_outline(view)); } View *View_stack::find_view(Point p) { /* skip mouse cursor */ - View *view = _next_view(_first_view()); + View *view = _next_view(*_first_view()); - for ( ; view; view = _next_view(view)) + for ( ; view; view = _next_view(*view)) if (view->input_response_at(p, _mode)) return view; @@ -298,7 +290,7 @@ View *View_stack::find_view(Point p) } -void View_stack::remove_view(Canvas_base &canvas, View const &view, bool redraw) +void View_stack::remove_view(View const &view, bool redraw) { /* remember geometry of view to remove */ Rect rect = _outline(view); @@ -315,9 +307,7 @@ void View_stack::remove_view(Canvas_base &canvas, View const &view, bool redraw) * the current one, resulting in a dangling pointer right after the view * gets destructed by the caller of 'removed_view'. */ - _mode.forget(canvas, view); + _mode.forget(view); - /* redraw area where the view was visible */ - if (redraw) - draw_rec(canvas, _first_view(), 0, 0, rect); + _dirty_rect.mark_as_dirty(rect); } diff --git a/repos/os/src/server/nitpicker/view_stack.h b/repos/os/src/server/nitpicker/view_stack.h index 7851e3a01..9df9383c7 100644 --- a/repos/os/src/server/nitpicker/view_stack.h +++ b/repos/os/src/server/nitpicker/view_stack.h @@ -19,6 +19,7 @@ class Session; + class View_stack { private: @@ -26,20 +27,23 @@ class View_stack Area _size; Mode &_mode; Genode::List _views; - View *_default_background; + View *_default_background = nullptr; + Dirty_rect mutable _dirty_rect; /** * Return outline geometry of a view * - * This geometry depends on the view geometry and the currently - * active Nitpicker mode. In non-flat modes, we incorporate the - * surrounding frame. + * This geometry depends on the view geometry and the currently active + * Nitpicker mode. In non-flat modes, we incorporate the surrounding + * frame. */ Rect _outline(View const &view) const; /** * Return top-most view of the view stack */ + View const *_first_view_const() const { return static_cast(_views.first()); } + View *_first_view() { return static_cast(_views.first()); } /** @@ -55,20 +59,7 @@ class View_stack /** * Position labels that are affected by specified area */ - void _place_labels(Canvas_base &, Rect); - - /** - * Return compound rectangle covering the view and all of its children - */ - Rect _compound_outline(View const &view) - { - Rect rect = _outline(view); - - view.for_each_child([&] (View const &child) { - rect = Rect::compound(_outline(child), rect); }); - - return rect; - } + void _place_labels(Rect); /** * Return view following the specified view in the view stack @@ -77,57 +68,75 @@ class View_stack * usage. */ template - VIEW *_next_view(VIEW *view) const; + 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); + } public: /** * Constructor */ - View_stack(Area size, Mode &mode) : - _size(size), _mode(mode), _default_background(0) { } + View_stack(Area size, Mode &mode) : _size(size), _mode(mode) + { + _dirty_rect.mark_as_dirty(Rect(Point(0, 0), _size)); + } /** * Return size */ Area size() const { return _size; } - void size(Area size) { _size = size; } + void size(Area size) + { + _size = size; + _dirty_rect.mark_as_dirty(Rect(Point(0, 0), _size)); + } /** * Draw views in specified area (recursivly) * - * \param view current view in view stack - * \param dst_view desired view to draw or NULL - * if all views should be drawn - * \param exclude do not draw views of this session + * \param view current view in view stack */ - void draw_rec(Canvas_base &, View const *view, View const *dst_view, Session const *exclude, Rect) const; + void draw_rec(Canvas_base &, View const *view, Rect) const; /** - * Draw whole view stack + * Draw dirty areas */ - void update_all_views(Canvas_base &canvas) + Dirty_rect draw(Canvas_base &canvas) const { - _place_labels(canvas, Rect(Point(), _size)); - draw_rec(canvas, _first_view(), 0, 0, Rect(Point(), _size)); + Dirty_rect result = _dirty_rect; + + _dirty_rect.flush([&] (Rect const &rect) { + draw_rec(canvas, _first_view_const(), rect); }); + + return result; } /** - * Update all views belonging to the specified session + * Trigger redraw of the whole view stack + */ + void update_all_views() + { + _place_labels(Rect(Point(), _size)); + _dirty_rect.mark_as_dirty(Rect(Point(), _size)); + } + + /** + * Mark all views belonging to the specified session as dirty * * \param Session Session that created the view * \param Rect Buffer area to update - * - * Note: For now, we perform an independent view-stack traversal - * for each view when calling 'refresh_view'. This becomes - * a potentially high overhead with many views. Having - * a tailored 'draw_rec_session' function would overcome - * this problem. */ - void update_session_views(Canvas_base &canvas, Session const &session, Rect rect) + void mark_session_views_as_dirty(Session const &session, Rect rect) { - for (View const *view = _first_view(); view; view = view->view_stack_next()) { + for (View *view = _first_view(); view; view = view->view_stack_next()) { if (!view->belongs_to(session)) continue; @@ -140,7 +149,8 @@ class View_stack Rect const r = Rect::intersect(Rect(rect.p1() + offset, rect.p2() + offset), view->abs_geometry()); - refresh_view(canvas, *view, view, r); + + _mark_view_as_dirty(*view, r); } } @@ -148,20 +158,16 @@ class View_stack * Refresh area within a view * * \param view view that should be updated on screen - * \param dst NULL if all views in the specified area should be - * refreshed or 'view' if the refresh should be limited to - * the specified view. */ - void refresh_view(Canvas_base &, View const &view, View const *dst, Rect); + void refresh_view(View const &view, Rect); /** * Define position and viewport * * \param pos position of view on screen * \param buffer_off view offset of displayed buffer - * \param do_redraw perform screen update immediately */ - void viewport(Canvas_base &, View &view, Rect pos, Point buffer_off, bool do_redraw); + void viewport(View &view, Rect pos, Point buffer_off); /** * Insert view at specified position in view stack @@ -174,13 +180,12 @@ class View_stack * bottom of the view stack, specify neighbor = 0 and * behind = false. */ - void stack(Canvas_base &, View const &view, View const *neighbor = 0, - bool behind = true, bool do_redraw = true); + void stack(View const &view, View const *neighbor = 0, bool behind = true); /** * Set view title */ - void title(Canvas_base &, View &view, char const *title); + void title(View &view, char const *title); /** * Find view at specified position @@ -190,7 +195,7 @@ class View_stack /** * Remove view from view stack */ - void remove_view(Canvas_base &, View const &, bool redraw = true); + void remove_view(View const &, bool redraw = true); /** * Define default background @@ -200,7 +205,7 @@ class View_stack /** * Return true if view is the default background */ - bool is_default_background(View const *view) const { return view == _default_background; } + bool is_default_background(View const &view) const { return &view == _default_background; } /** * Remove all views of specified session from view stack @@ -208,11 +213,11 @@ class View_stack * Rather than removing the views from the view stack, this function moves * the session views out of the visible screen area. */ - void lock_out_session(Canvas_base &canvas, Session const &session) + void lock_out_session(Session const &session) { View const *view = _first_view(), *next_view = view->view_stack_next(); while (view) { - if (view->belongs_to(session)) remove_view(canvas, *view); + if (view->belongs_to(session)) remove_view(*view); view = next_view; next_view = view ? view->view_stack_next() : 0; }