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