From 320387db8998b73238786c3404ba25679c87fb3d Mon Sep 17 00:00:00 2001 From: Norman Feske Date: Thu, 2 Jul 2020 15:20:43 +0200 Subject: [PATCH] nitpicker: improve GUI client resize handling This patch replaces meta-data allocation during the resize handling by a new 'Resizeable_texture' type that has all meta data preallocated. It also replaces the use of pointer return values with the 'Resizeable_texture::with_texture' method. Issue #3812 --- repos/os/src/server/nitpicker/background.h | 4 +- repos/os/src/server/nitpicker/buffer.h | 2 +- .../os/src/server/nitpicker/chunky_texture.h | 6 +- .../server/nitpicker/framebuffer_session.h | 5 +- repos/os/src/server/nitpicker/gui_session.cc | 109 ++++++------------ repos/os/src/server/nitpicker/gui_session.h | 23 ++-- .../os/src/server/nitpicker/pointer_origin.h | 4 +- .../src/server/nitpicker/resizeable_texture.h | 109 ++++++++++++++++++ repos/os/src/server/nitpicker/types.h | 2 + repos/os/src/server/nitpicker/view.cc | 11 +- repos/os/src/server/nitpicker/view.h | 9 +- repos/os/src/server/nitpicker/view_owner.h | 5 - 12 files changed, 178 insertions(+), 111 deletions(-) create mode 100644 repos/os/src/server/nitpicker/resizeable_texture.h diff --git a/repos/os/src/server/nitpicker/background.h b/repos/os/src/server/nitpicker/background.h index 6e9fda7ea..8cc084896 100644 --- a/repos/os/src/server/nitpicker/background.h +++ b/repos/os/src/server/nitpicker/background.h @@ -28,6 +28,8 @@ struct Nitpicker::Background : private Texture_base, View Color color = default_color(); + Resizeable_texture _texture { }; + /* * The background uses no texture. Therefore we can pass a null pointer as * texture argument to the Session constructor. @@ -35,7 +37,7 @@ struct Nitpicker::Background : private Texture_base, View Background(View_owner &owner, Area size) : Texture_base(Area(0, 0)), - View(owner, View::NOT_TRANSPARENT, View::BACKGROUND, 0) + View(owner, _texture, View::NOT_TRANSPARENT, View::BACKGROUND, 0) { View::geometry(Rect(Point(0, 0), size)); } diff --git a/repos/os/src/server/nitpicker/buffer.h b/repos/os/src/server/nitpicker/buffer.h index 30927fe09..71ff17b89 100644 --- a/repos/os/src/server/nitpicker/buffer.h +++ b/repos/os/src/server/nitpicker/buffer.h @@ -65,7 +65,7 @@ namespace Nitpicker { struct Buffer_provider; } */ struct Nitpicker::Buffer_provider : Interface { - virtual Buffer *realloc_buffer(Framebuffer::Mode mode, bool use_alpha) = 0; + virtual Dataspace_capability realloc_buffer(Framebuffer::Mode mode, bool use_alpha) = 0; }; #endif /* _BUFFER_H_ */ diff --git a/repos/os/src/server/nitpicker/chunky_texture.h b/repos/os/src/server/nitpicker/chunky_texture.h index 8ed7de4b0..fb703ed6b 100644 --- a/repos/os/src/server/nitpicker/chunky_texture.h +++ b/repos/os/src/server/nitpicker/chunky_texture.h @@ -59,15 +59,15 @@ class Nitpicker::Chunky_texture : public Buffer, public Texture return bytes_per_pixel*size.w()*size.h(); } - unsigned char *input_mask_buffer() + unsigned char const *input_mask_buffer() const { if (!Texture::alpha()) return 0; Area const size = Texture::size(); /* input-mask values come right after the alpha values */ - return (unsigned char *)local_addr() + calc_num_bytes(size, false) - + size.count(); + return (unsigned char const *)local_addr() + calc_num_bytes(size, false) + + size.count(); } }; diff --git a/repos/os/src/server/nitpicker/framebuffer_session.h b/repos/os/src/server/nitpicker/framebuffer_session.h index 13fece73c..a1d03fa1c 100644 --- a/repos/os/src/server/nitpicker/framebuffer_session.h +++ b/repos/os/src/server/nitpicker/framebuffer_session.h @@ -38,7 +38,6 @@ class Framebuffer::Session_component : public Rpc_object Session_component(Session_component const &); Session_component &operator = (Session_component const &); - Buffer *_buffer = 0; View_stack &_view_stack; Nitpicker::Gui_session &_session; Buffer_provider &_buffer_provider; @@ -94,9 +93,7 @@ class Framebuffer::Session_component : public Rpc_object Dataspace_capability dataspace() override { - _buffer = _buffer_provider.realloc_buffer(_mode, _alpha); - - return _buffer ? _buffer->ds_cap() : Ram_dataspace_capability(); + return _buffer_provider.realloc_buffer(_mode, _alpha); } Mode mode() const override { return _mode; } diff --git a/repos/os/src/server/nitpicker/gui_session.cc b/repos/os/src/server/nitpicker/gui_session.cc index 76806ac60..0e2f18d41 100644 --- a/repos/os/src/server/nitpicker/gui_session.cc +++ b/repos/os/src/server/nitpicker/gui_session.cc @@ -16,26 +16,6 @@ using namespace Nitpicker; -void Gui_session::_release_buffer() -{ - if (!_texture) - return; - - typedef Pixel_rgb888 PT; - - Chunky_texture const *cdt = static_cast const *>(_texture); - - _texture = nullptr; - _uses_alpha = false; - _input_mask = nullptr; - - destroy(&_session_alloc, const_cast *>(cdt)); - - replenish(Ram_quota{_buffer_size}); - _buffer_size = 0; -} - - bool Gui_session::_views_are_equal(View_handle v1, View_handle v2) { if (!v1.valid() || !v2.valid()) @@ -266,7 +246,7 @@ Gui_session::View_handle Gui_session::create_view(View_handle parent_handle) return View_handle(); view = new (_view_alloc) - View(*this, View::NOT_TRANSPARENT, View::NOT_BACKGROUND, &(*parent)); + View(*this, _texture, View::NOT_TRANSPARENT, View::NOT_BACKGROUND, &(*parent)); parent->add_child(*view); } @@ -280,7 +260,7 @@ Gui_session::View_handle Gui_session::create_view(View_handle parent_handle) else { try { view = new (_view_alloc) - View(*this, View::NOT_TRANSPARENT, View::NOT_BACKGROUND, nullptr); + View(*this, _texture, View::NOT_TRANSPARENT, View::NOT_BACKGROUND, nullptr); } catch (Allocator::Out_of_memory) { throw Out_of_ram(); } } @@ -462,79 +442,60 @@ void Gui_session::session_control(Label suffix, Session_control control) } -Buffer *Gui_session::realloc_buffer(Framebuffer::Mode mode, bool use_alpha) +Dataspace_capability Gui_session::realloc_buffer(Framebuffer::Mode mode, bool use_alpha) { - typedef Pixel_rgb888 PT; - - size_t const buffer_size = Chunky_texture::calc_num_bytes(mode.area, use_alpha); + Ram_quota const next_buffer_size { Chunky_texture::calc_num_bytes(mode.area, use_alpha) }; + Ram_quota const orig_buffer_size { _buffer_size }; /* * Preserve the content of the original buffer if nitpicker has * enough slack memory to temporarily keep the original pixels. */ - Texture const *src_texture = nullptr; - if (texture()) { - enum { PRESERVED_RAM = 128*1024 }; - if (_env.pd().avail_ram().value > buffer_size + PRESERVED_RAM) { - src_texture = static_cast const *>(texture()); - } else { - warning("not enough RAM to preserve buffer content during resize"); - _release_buffer(); - } + enum { PRESERVED_RAM = 128*1024 }; + bool const preserve_content = + (_env.pd().avail_ram().value > next_buffer_size.value + PRESERVED_RAM); + + if (!preserve_content) { + warning("not enough RAM to preserve buffer content during resize"); + _texture.release_current(); + replenish(orig_buffer_size); } - /* set new buffer_size after _release_buffer(), which changes _buffer_size also */ - _buffer_size = buffer_size; + _buffer_size = 0; + _uses_alpha = false; + _input_mask = nullptr; - Ram_quota const temporary_ram_upgrade = src_texture - ? Ram_quota{_buffer_size} : Ram_quota{0}; + Ram_quota const temporary_ram_upgrade = _texture.valid() + ? next_buffer_size : Ram_quota{0}; _ram_quota_guard().upgrade(temporary_ram_upgrade); - auto try_alloc_texture = [&] () - { - try { - return new (&_session_alloc) - Chunky_texture(_env.ram(), _env.rm(), mode.area, use_alpha); - } catch (...) { - return (Chunky_texture*)nullptr; - } - }; - - Chunky_texture * const texture = try_alloc_texture(); - - if (!texture) { - _release_buffer(); + if (!_texture.try_construct_next(_env.ram(), _env.rm(), mode.area, use_alpha)) { + _texture.release_current(); + replenish(orig_buffer_size); _ram_quota_guard().try_downgrade(temporary_ram_upgrade); - return nullptr; + return Dataspace_capability(); } - /* copy old buffer content into new buffer and release old buffer */ - if (src_texture) { + _texture.switch_to_next(); - Surface surface(texture->pixel(), - texture->Texture_base::size()); + /* 'switch_to_next' has released the current texture */ + if (preserve_content) + replenish(orig_buffer_size); - Texture_painter::paint(surface, *src_texture, Color(), Point(0, 0), - Texture_painter::SOLID, false); - _release_buffer(); + if (!_ram_quota_guard().try_downgrade(temporary_ram_upgrade)) + warning("accounting error during framebuffer realloc"); - if (!_ram_quota_guard().try_downgrade(temporary_ram_upgrade)) - warning("accounting error during framebuffer realloc"); - - } - - try { withdraw(Ram_quota{_buffer_size}); } + try { withdraw(next_buffer_size); } catch (...) { - destroy(&_session_alloc, texture); - _buffer_size = 0; - return nullptr; + _texture.release_current(); + return Dataspace_capability(); } - _texture = texture; - _uses_alpha = use_alpha; - _input_mask = texture->input_mask_buffer(); + _buffer_size = next_buffer_size.value; + _uses_alpha = use_alpha; + _input_mask = _texture.input_mask_buffer(); - return texture; + return _texture.dataspace(); } diff --git a/repos/os/src/server/nitpicker/gui_session.h b/repos/os/src/server/nitpicker/gui_session.h index b6b48e15f..bac1fdb03 100644 --- a/repos/os/src/server/nitpicker/gui_session.h +++ b/repos/os/src/server/nitpicker/gui_session.h @@ -21,6 +21,7 @@ #include #include #include +#include #include /* local includes */ @@ -29,7 +30,6 @@ #include "framebuffer_session.h" #include "input_session.h" #include "focus.h" -#include "chunky_texture.h" #include "view.h" namespace Nitpicker { @@ -73,8 +73,9 @@ class Nitpicker::Gui_session : public Session_object, Constrained_ram_allocator _ram; + Resizeable_texture _texture { }; + Domain_registry::Entry const *_domain = nullptr; - Texture_base const *_texture = nullptr; View *_background = nullptr; /* @@ -152,8 +153,6 @@ class Nitpicker::Gui_session : public Session_object, return _domain ? _domain->phys_pos(pos, screen_area) : Point(0, 0); } - void _release_buffer(); - /** * Helper for performing sanity checks in OP_TO_FRONT and OP_TO_BACK * @@ -203,8 +202,6 @@ class Nitpicker::Gui_session : public Session_object, _env.ep().dissolve(_input_session_component); destroy_all_views(); - - _release_buffer(); } using Session_list::Element::next; @@ -261,9 +258,7 @@ class Nitpicker::Gui_session : public Session_object, View const *background() const override { return _background; } - Texture_base const *texture() const override { return _texture; } - - bool uses_alpha() const override { return _texture && _uses_alpha; } + bool uses_alpha() const override { return _texture.valid() && _uses_alpha; } unsigned layer() const override { return _domain ? _domain->layer() : ~0UL; } @@ -274,14 +269,14 @@ class Nitpicker::Gui_session : public Session_object, */ unsigned char input_mask_at(Point p) const override { - if (!_input_mask || !_texture) return 0; + if (!_input_mask || !_texture.valid()) return 0; /* check boundaries */ - if ((unsigned)p.x() >= _texture->size().w() - || (unsigned)p.y() >= _texture->size().h()) + if ((unsigned)p.x() >= _texture.size().w() + || (unsigned)p.y() >= _texture.size().h()) return 0; - return _input_mask[p.y()*_texture->size().w() + p.x()]; + return _input_mask[p.y()*_texture.size().w() + p.x()]; } void submit_input_event(Input::Event e) override; @@ -392,7 +387,7 @@ class Nitpicker::Gui_session : public Session_object, ** Buffer_provider interface ** *******************************/ - Buffer *realloc_buffer(Framebuffer::Mode mode, bool use_alpha) override; + Dataspace_capability realloc_buffer(Framebuffer::Mode mode, bool use_alpha) override; }; #endif /* _GUI_SESSION_H_ */ diff --git a/repos/os/src/server/nitpicker/pointer_origin.h b/repos/os/src/server/nitpicker/pointer_origin.h index 8f58bca2b..409cdea30 100644 --- a/repos/os/src/server/nitpicker/pointer_origin.h +++ b/repos/os/src/server/nitpicker/pointer_origin.h @@ -22,9 +22,11 @@ namespace Nitpicker { struct Pointer_origin; } struct Nitpicker::Pointer_origin : View { + Resizeable_texture _texture { }; + Pointer_origin(View_owner &owner) : - View(owner, View::TRANSPARENT, View::NOT_BACKGROUND, 0) + View(owner, _texture, View::TRANSPARENT, View::NOT_BACKGROUND, 0) { } diff --git a/repos/os/src/server/nitpicker/resizeable_texture.h b/repos/os/src/server/nitpicker/resizeable_texture.h new file mode 100644 index 000000000..2907f6c53 --- /dev/null +++ b/repos/os/src/server/nitpicker/resizeable_texture.h @@ -0,0 +1,109 @@ +/* + * \brief Texture that preserves content across resize + * \author Norman Feske + * \date 2020-07-02 + */ + +/* + * Copyright (C) 2020 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _RESIZEABLE_TEXTURE_H_ +#define _RESIZEABLE_TEXTURE_H_ + +/* Genode includes */ +#include + +/* local includes */ +#include "chunky_texture.h" + +namespace Nitpicker { template class Resizeable_texture; } + + +template +class Nitpicker::Resizeable_texture +{ + private: + + unsigned _current = 0; + + using Constructible_texture = Constructible>; + + struct Element : Constructible_texture + { + Element() : Constructible_texture() { } + }; + + Element _textures[2]; + + public: + + bool valid() const { return _textures[_current].constructed(); } + + Area size() const + { + return valid() ? _textures[_current]->Texture_base::size() + : Area { }; + } + + void release_current() { _textures[_current].destruct(); } + + bool try_construct_next(Ram_allocator &ram, Region_map &rm, + Area size, bool use_alpha) + { + try { + unsigned const next = !_current; + _textures[next].construct(ram, rm, size, use_alpha); + return true; + } catch (...) { } + return false; + } + + /** + * Make the next texture the current one + * + * This method destructs the previous current one. + */ + void switch_to_next() + { + unsigned const next = !_current; + + /* copy content from current to next texture */ + if (_textures[next].constructed() && _textures[_current].constructed()) { + + Surface surface(_textures[next]->pixel(), + _textures[next]->Texture_base::size()); + + Texture const &texture = *_textures[_current]; + + Blit_painter::paint(surface, texture, Point(0, 0)); + } + + _textures[_current].destruct(); + + _current = next; + } + + template + void with_texture(FN const &fn) const + { + if (valid()) + fn(*_textures[_current]); + } + + Dataspace_capability dataspace() + { + return valid() ? _textures[_current]->ds_cap() : Ram_dataspace_capability(); + } + + unsigned char const *input_mask_buffer() const + { + return valid() ? _textures[_current]->input_mask_buffer() + : nullptr; + } +}; + +#endif /* _RESIZEABLE_TEXTURE_H_ */ diff --git a/repos/os/src/server/nitpicker/types.h b/repos/os/src/server/nitpicker/types.h index 92735e04a..41aea275a 100644 --- a/repos/os/src/server/nitpicker/types.h +++ b/repos/os/src/server/nitpicker/types.h @@ -20,6 +20,7 @@ #include #include #include +#include namespace Gui { } @@ -27,6 +28,7 @@ namespace Nitpicker { using namespace Genode; using namespace Gui; + using Pixel = Pixel_rgb888; typedef Surface_base::Point Point; typedef Surface_base::Area Area; diff --git a/repos/os/src/server/nitpicker/view.cc b/repos/os/src/server/nitpicker/view.cc index ec468e519..82285a6d2 100644 --- a/repos/os/src/server/nitpicker/view.cc +++ b/repos/os/src/server/nitpicker/view.cc @@ -125,13 +125,12 @@ void Nitpicker::View::draw(Canvas_base &canvas, Font const &font, Focus const &f owner_color.g >> 1, owner_color.b >> 1); - Texture_base const *texture = _owner.texture(); - if (texture) { - canvas.draw_texture(_buffer_off + view_rect.p1(), *texture, op, - mix_color, allow_alpha); - } else { + _texture.with_texture([&] (Texture_base const &texture) { + canvas.draw_texture(_buffer_off + view_rect.p1(), texture, op, + mix_color, allow_alpha); }); + + if (!_texture.valid()) canvas.draw_box(view_rect, black()); - } if (!_owner.label_visible()) return; diff --git a/repos/os/src/server/nitpicker/view.h b/repos/os/src/server/nitpicker/view.h index 25fe2f711..98b1f507c 100644 --- a/repos/os/src/server/nitpicker/view.h +++ b/repos/os/src/server/nitpicker/view.h @@ -23,6 +23,7 @@ /* local includes */ #include "canvas.h" #include "view_owner.h" +#include "resizeable_texture.h" namespace Nitpicker { @@ -102,6 +103,8 @@ class Nitpicker::View : private Same_buffer_list_elem, View_owner &_owner; Title _title { "" }; + Resizeable_texture const &_texture; + List _children { }; /** @@ -127,9 +130,11 @@ class Nitpicker::View : private Same_buffer_list_elem, public: - View(View_owner &owner, Transparent transparent, Background bg, View *parent) + View(View_owner &owner, Resizeable_texture const &texture, + Transparent transparent, Background bg, View *parent) : - _transparent(transparent), _background(bg), _parent(parent), _owner(owner) + _transparent(transparent), _background(bg), _parent(parent), + _owner(owner), _texture(texture) { } virtual ~View() diff --git a/repos/os/src/server/nitpicker/view_owner.h b/repos/os/src/server/nitpicker/view_owner.h index fdecae63b..a35aa766b 100644 --- a/repos/os/src/server/nitpicker/view_owner.h +++ b/repos/os/src/server/nitpicker/view_owner.h @@ -79,11 +79,6 @@ struct Nitpicker::View_owner : Interface */ virtual View const *background() const { return nullptr; } - /** - * Teturn texture containing the owners virtual frame buffer - */ - virtual Texture_base const *texture() const { return nullptr; } - /** * Return input-mask value at given position */