From 2772abc8d7e69937da8b5f3157d44665465c0e56 Mon Sep 17 00:00:00 2001 From: Norman Feske Date: Thu, 25 Aug 2022 14:52:49 +0200 Subject: [PATCH] menu_view: configurable alpha channel and bg color This patch enhances menu_view with the optional configuration attributes 'opaque' and 'background'. Setting 'opaque' to "yes" suppresses the use of the alpha channel at the GUI session. This improves the drawing performance by 20% on the PinePhone. Since the menu_view uses the gems/gui_buffer.h utility, the 'Gui_buffer' received a new 'Alpha' argument at construction time. The 'background' attribute can be specified to define the reset color of the GUI buffer. It alleviates the need to create a frame widget for the top level. The patch also switches the optimization level for compiling menu_view to -O3, which increases the drawing performance on the PinePhone by 30%. Fixes #4592 --- repos/gems/include/gems/gui_buffer.h | 109 ++++++++++++++++--------- repos/gems/src/app/menu_view/main.cc | 36 ++++++-- repos/gems/src/app/menu_view/target.mk | 2 + 3 files changed, 101 insertions(+), 46 deletions(-) diff --git a/repos/gems/include/gems/gui_buffer.h b/repos/gems/include/gems/gui_buffer.h index 716a951e6c..e2588faaa9 100644 --- a/repos/gems/include/gems/gui_buffer.h +++ b/repos/gems/include/gems/gui_buffer.h @@ -48,41 +48,49 @@ struct Gui_buffer Framebuffer::Mode const mode; + bool const use_alpha; + + Pixel_rgb888 reset_color { 127, 127, 127, 255 }; + /** * Return dataspace capability for virtual framebuffer */ Genode::Dataspace_capability _ds_cap(Gui::Connection &gui) { /* setup virtual framebuffer mode */ - gui.buffer(mode, true); + gui.buffer(mode, use_alpha); return gui.framebuffer()->dataspace(); } Genode::Attached_dataspace fb_ds { rm, _ds_cap(gui) }; - Genode::size_t pixel_surface_num_bytes() const + size_t pixel_surface_num_bytes() const { return size().count()*sizeof(Pixel_rgb888); } - Genode::size_t alpha_surface_num_bytes() const + size_t alpha_surface_num_bytes() const { - return size().count(); + return use_alpha ? size().count() : 0; } Ram_ds pixel_surface_ds { ram, rm, pixel_surface_num_bytes() }; Ram_ds alpha_surface_ds { ram, rm, alpha_surface_num_bytes() }; + enum class Alpha { OPAQUE, ALPHA }; + /** * Constructor */ Gui_buffer(Gui::Connection &gui, Area size, - Genode::Ram_allocator &ram, Genode::Region_map &rm) + Genode::Ram_allocator &ram, Genode::Region_map &rm, + Alpha alpha = Alpha::ALPHA) : ram(ram), rm(rm), gui(gui), mode({ .area = { Genode::max(1U, size.w()), - Genode::max(1U, size.h()) } }) + Genode::max(1U, size.h()) } }), + use_alpha(alpha == Alpha::ALPHA) { reset_surface(); } @@ -93,33 +101,48 @@ struct Gui_buffer Area size() const { return mode.area; } template - void apply_to_surface(FN const &fn) + void with_alpha_surface(FN const &fn) + { + Area const alpha_size = use_alpha ? size() : Area(0, 0); + Alpha_surface alpha(alpha_surface_ds.local_addr(), alpha_size); + fn(alpha); + } + + template + void with_pixel_surface(FN const &fn) { Pixel_surface pixel(pixel_surface_ds.local_addr(), size()); - Alpha_surface alpha(alpha_surface_ds.local_addr(), size()); - fn(pixel, alpha); + fn(pixel); + } + + template + void apply_to_surface(FN const &fn) + { + with_alpha_surface([&] (Alpha_surface &alpha) { + with_pixel_surface([&] (Pixel_surface &pixel) { + fn(pixel, alpha); }); }); } void reset_surface() { - Pixel_surface pixel(pixel_surface_ds.local_addr(), size()); - Alpha_surface alpha(alpha_surface_ds.local_addr(), size()); + if (use_alpha) + with_alpha_surface([&] (Alpha_surface &alpha) { + Genode::memset(alpha.addr(), 0, alpha_surface_num_bytes()); }); - Genode::size_t const num_pixels = size().count(); - Genode::memset(alpha.addr(), 0, num_pixels); + with_pixel_surface([&] (Pixel_surface &pixel) { - /* - * Initialize color buffer with 50% gray - * - * We do not use black to limit the bleeding of black into antialiased - * drawing operations applied onto an initially transparent background. - */ - Pixel_rgb888 *dst = pixel.addr(); + /* + * Initialize color buffer with 50% gray + * + * We do not use black to limit the bleeding of black into antialiased + * drawing operations applied onto an initially transparent background. + */ + Pixel_rgb888 *dst = pixel.addr(); + Pixel_rgb888 const color = reset_color; - Pixel_rgb888 const gray(127, 127, 127, 255); - - for (size_t n = num_pixels; n; n--) - *dst++ = gray; + for (size_t n = size().count(); n; n--) + *dst++ = color; + }); } template @@ -136,6 +159,9 @@ struct Gui_buffer void _update_input_mask() { + if (!use_alpha) + return; + size_t const num_pixels = size().count(); unsigned char * const alpha_base = fb_ds.local_addr() @@ -159,26 +185,31 @@ struct Gui_buffer void flush_surface() { - /* represent back buffer as texture */ - Genode::Texture - pixel_texture(pixel_surface_ds.local_addr(), - nullptr, size()); - - Genode::Texture - alpha_texture(alpha_surface_ds.local_addr(), - nullptr, size()); - // XXX track dirty rectangles Rect const clip_rect(Genode::Surface_base::Point(0, 0), size()); - Pixel_rgb888 *pixel_base = fb_ds.local_addr(); - Pixel_alpha8 *alpha_base = fb_ds.local_addr() - + mode.bytes_per_pixel()*size().count(); + { + /* represent back buffer as texture */ + Genode::Texture + pixel_texture(pixel_surface_ds.local_addr(), + nullptr, size()); + Pixel_rgb888 *pixel_base = fb_ds.local_addr(); - _convert_back_to_front(pixel_base, pixel_texture, clip_rect); - _convert_back_to_front(alpha_base, alpha_texture, clip_rect); + _convert_back_to_front(pixel_base, pixel_texture, clip_rect); + } - _update_input_mask(); + if (use_alpha) { + Genode::Texture + alpha_texture(alpha_surface_ds.local_addr(), + nullptr, size()); + + Pixel_alpha8 *alpha_base = fb_ds.local_addr() + + mode.bytes_per_pixel()*size().count(); + + _convert_back_to_front(alpha_base, alpha_texture, clip_rect); + + _update_input_mask(); + } } }; diff --git a/repos/gems/src/app/menu_view/main.cc b/repos/gems/src/app/menu_view/main.cc index e27a39909c..a99da574d1 100644 --- a/repos/gems/src/app/menu_view/main.cc +++ b/repos/gems/src/app/menu_view/main.cc @@ -41,6 +41,11 @@ struct Menu_view::Main Constructible _buffer { }; + /** + * Alpha surface used when operating in opaque mode + */ + Surface _no_alpha { nullptr, Area(0,0) }; + Gui::Session::View_handle _view_handle = _gui.create_view(); /** @@ -128,6 +133,10 @@ struct Menu_view::Main Attached_dataspace _input_ds { _env.rm(), _gui.input()->dataspace() }; + bool _opaque = false; + + Color _background_color { }; + Widget::Hovered _last_reported_hovered { }; void _handle_config(); @@ -296,14 +305,20 @@ void Menu_view::Main::_handle_config() { _config.update(); + Xml_node const config = _config.xml(); + try { - _hover_reporter.enabled(_config.xml().sub_node("report") - .attribute_value("hover", false)); + _hover_reporter.enabled(config.sub_node("report") + .attribute_value("hover", false)); } catch (...) { _hover_reporter.enabled(false); } - _config.xml().with_sub_node("vfs", [&] (Xml_node const &vfs_node) { + _opaque = config.attribute_value("opaque", false); + + _background_color = config.attribute_value("background", Color(127, 127, 127, 255)); + + config.with_sub_node("vfs", [&] (Xml_node const &vfs_node) { _vfs_env.root_dir().apply_config(vfs_node); }); _handle_dialog_update(); @@ -389,10 +404,17 @@ void Menu_view::Main::_handle_frame_timer() bool const size_increased = (max_size.w() > buffer_w) || (max_size.h() > buffer_h); - if (!_buffer.constructed() || size_increased) - _buffer.construct(_gui, max_size, _env.ram(), _env.rm()); - else + if (!_buffer.constructed() || size_increased) { + _buffer.construct(_gui, max_size, _env.ram(), _env.rm(), + _opaque ? Gui_buffer::Alpha::OPAQUE + : Gui_buffer::Alpha::ALPHA); + _buffer->reset_color = { _background_color.r, + _background_color.g, + _background_color.b, + _background_color.a }; + } else { _buffer->reset_surface(); + } _root_widget.position(Point(0, 0)); @@ -400,7 +422,7 @@ void Menu_view::Main::_handle_frame_timer() // don't perform a full dialog update _buffer->apply_to_surface([&] (Surface &pixel, Surface &alpha) { - _root_widget.draw(pixel, alpha, Point(0, 0)); + _root_widget.draw(pixel, _opaque ? _no_alpha : alpha, Point(0, 0)); }); _buffer->flush_surface(); diff --git a/repos/gems/src/app/menu_view/target.mk b/repos/gems/src/app/menu_view/target.mk index e9c1be2d79..473b384127 100644 --- a/repos/gems/src/app/menu_view/target.mk +++ b/repos/gems/src/app/menu_view/target.mk @@ -3,6 +3,8 @@ SRC_CC = main.cc LIBS = base libc libm vfs libpng zlib blit file INC_DIR += $(PRG_DIR) +CC_OLEVEL := -O3 + CUSTOM_TARGET_DEPS += menu_view_styles.tar BUILD_ARTIFACTS := $(TARGET) menu_view_styles.tar