From cf9eedca472f6ce5c7154440e684d9ec88dfb9c4 Mon Sep 17 00:00:00 2001 From: Norman Feske Date: Wed, 22 May 2013 19:24:20 +0200 Subject: [PATCH] Window-resize support for liquid_fb Related to #740. --- demo/src/app/scout/include/canvas_rgb565.h | 27 ++- demo/src/app/scout/include/elements.h | 5 + .../liquid_framebuffer/framebuffer_window.h | 32 ++- demo/src/server/liquid_framebuffer/main.cc | 5 +- .../src/server/liquid_framebuffer/services.cc | 221 +++++++++++++----- demo/src/server/liquid_framebuffer/services.h | 2 + 6 files changed, 221 insertions(+), 71 deletions(-) diff --git a/demo/src/app/scout/include/canvas_rgb565.h b/demo/src/app/scout/include/canvas_rgb565.h index d061ac734..2d960b6ac 100644 --- a/demo/src/app/scout/include/canvas_rgb565.h +++ b/demo/src/app/scout/include/canvas_rgb565.h @@ -86,9 +86,10 @@ class Texture_rgb565 : public Canvas::Texture { private: - int _w, _h; /* size of texture */ - unsigned char *_alpha; /* alpha channel */ - Pixel_rgb565 *_pixel; /* pixel data */ + int _w, _h; /* size of texture */ + unsigned char *_alpha; /* alpha channel */ + Pixel_rgb565 *_pixel; /* pixel data */ + bool _preallocated; public: @@ -96,23 +97,25 @@ class Texture_rgb565 : public Canvas::Texture * Constructor */ Texture_rgb565(int w, int h) - { - _w = w; - _h = h; - _alpha = (unsigned char *)scout_malloc(w*h); - _pixel = (Pixel_rgb565 *)scout_malloc(w*h*sizeof(Pixel_rgb565)); - } + : + _w(w), _h(h), + _alpha((unsigned char *)scout_malloc(w*h)), + _pixel((Pixel_rgb565 *)scout_malloc(w*h*sizeof(Pixel_rgb565))), + _preallocated(false) + { } Texture_rgb565(Pixel_rgb565 *pixel, unsigned char *alpha, int w, int h): - _w(w), _h(h), _alpha(alpha), _pixel(pixel) { } + _w(w), _h(h), _alpha(alpha), _pixel(pixel), _preallocated(true) { } /** * Destructor */ ~Texture_rgb565() { - scout_free(_alpha); - scout_free(_pixel); + if (!_preallocated) { + scout_free(_alpha); + scout_free(_pixel); + } _w = _h = 0; } diff --git a/demo/src/app/scout/include/elements.h b/demo/src/app/scout/include/elements.h index af2d6ce4b..0ef131f82 100644 --- a/demo/src/app/scout/include/elements.h +++ b/demo/src/app/scout/include/elements.h @@ -164,6 +164,11 @@ class Element */ virtual void format_fixed_width(int w) { } + /** + * Format element and all child elements to specified width and height + */ + virtual void format_fixed_size(int w, int h) { } + /** * Draw function * diff --git a/demo/src/server/liquid_framebuffer/framebuffer_window.h b/demo/src/server/liquid_framebuffer/framebuffer_window.h index 5ff066a8a..96e22eb6e 100644 --- a/demo/src/server/liquid_framebuffer/framebuffer_window.h +++ b/demo/src/server/liquid_framebuffer/framebuffer_window.h @@ -17,10 +17,13 @@ #include "window.h" #include "titlebar.h" #include "sky_texture.h" +#include "fade_icon.h" #define TITLEBAR_RGBA _binary_titlebar_rgba_start +#define SIZER_RGBA _binary_sizer_rgba_start extern unsigned char TITLEBAR_RGBA[]; +extern unsigned char SIZER_RGBA[]; template @@ -39,7 +42,9 @@ class Framebuffer_window : public Window Titlebar _titlebar; Sky_texture _bg_texture; int _bg_offset; + Fade_icon _sizer; Element *_content; + bool _config_alpha; public: @@ -49,7 +54,8 @@ class Framebuffer_window : public Window Framebuffer_window(Platform *pf, Redraw_manager *redraw, Element *content, - const char *name) + const char *name, + bool config_alpha) : Window(pf, redraw, content->min_w() + 2, content->min_h() + 1 + _TH), _bg_offset(0), _content(content) @@ -59,8 +65,14 @@ class Framebuffer_window : public Window _titlebar.text(name); _titlebar.event_handler(new Mover_event_handler(this)); + /* resize handle */ + _sizer.rgba(SIZER_RGBA); + _sizer.event_handler(new Sizer_event_handler(this)); + _sizer.alpha(100); + append(&_titlebar); append(_content); + append(&_sizer); _min_w = max_w(); _min_h = max_h(); @@ -71,10 +83,23 @@ class Framebuffer_window : public Window */ void format(int w, int h) { + w = (w > max_w()) ? max_w() : w; + h = (h > max_h()) ? max_h() : h; _w = w; _h = h; - Parent_element::_format_children(1, w); + int y = 0; + + _titlebar.format_fixed_width(w); + _titlebar.geometry(1, y, _titlebar.min_w(), _titlebar.min_h()); + y += _titlebar.min_h(); + + int const content_h = (h > y + 1) ? (h - y - 1) : 0; + int const content_w = w - 2; + _content->format_fixed_size(content_w, content_h); + _content->geometry(1, y, content_w, content_h); + + _sizer.geometry(_w - 32, _h - 32, 32, 32); pf()->view_geometry(pf()->vx(), pf()->vy(), _w, _h); redraw()->size(_w, _h); @@ -91,7 +116,8 @@ class Framebuffer_window : public Window */ void draw(Canvas *c, int x, int y) { - _bg_texture.draw(c, 0, - _bg_offset); + if (_config_alpha) + _bg_texture.draw(c, 0, - _bg_offset); ::Parent_element::draw(c, x, y); diff --git a/demo/src/server/liquid_framebuffer/main.cc b/demo/src/server/liquid_framebuffer/main.cc index 7ed43d3d2..dfba4be63 100644 --- a/demo/src/server/liquid_framebuffer/main.cc +++ b/demo/src/server/liquid_framebuffer/main.cc @@ -162,7 +162,7 @@ int main(int argc, char **argv) /* create instance of browser window */ static Framebuffer_window - fb_win(&pf, &redraw, window_content(), config_title); + fb_win(&pf, &redraw, window_content(), config_title, config_alpha); if (config_animate) { static Background_animator fb_win_bg_anim(&fb_win); @@ -181,8 +181,11 @@ int main(int argc, char **argv) Event ev; unsigned long curr_time, old_time; curr_time = old_time = pf.timer_ticks(); + lock_window_content(); do { + unlock_window_content(); pf.get_event(&ev); + lock_window_content(); if (ev.type != Event::WHEEL) { ev.mx -= user_state.vx(); diff --git a/demo/src/server/liquid_framebuffer/services.cc b/demo/src/server/liquid_framebuffer/services.cc index 7b1bab597..49a7c5081 100644 --- a/demo/src/server/liquid_framebuffer/services.cc +++ b/demo/src/server/liquid_framebuffer/services.cc @@ -90,15 +90,21 @@ class Window_content : public Element { private: - Event_queue *_ev_queue; - int _omx, _omy; - Element *_element; + Genode::Lock &_lock; + Event_queue *_ev_queue; + int _omx, _omy; + Element *_element; public: - Content_event_handler(Event_queue *ev_queue, Element *element): - _ev_queue(ev_queue), _element(element) { } + Content_event_handler(Event_queue *ev_queue, Element *element, + Genode::Lock &lock) + : + _lock(lock), _ev_queue(ev_queue), _element(element) { } + /* + * Called from main program with taken lock for window content + */ void handle(Event &ev) { int mx = ev.mx - _element->abs_x(); @@ -124,60 +130,143 @@ class Window_content : public Element } }; - unsigned _fb_w, _fb_h; - Genode::Attached_ram_dataspace _fb_ds; - Pixel_rgb565 *_pixel; - unsigned char *_alpha; - Texture_rgb565 _fb_texture; - Content_event_handler _ev_handler; + struct Fb_texture + { + unsigned w, h; + Genode::Attached_ram_dataspace ds; + Pixel_rgb565 *pixel; + unsigned char *alpha; + Texture_rgb565 texture; + + Fb_texture(unsigned w, unsigned h, bool config_alpha) + : + w(w), h(h), + ds(Genode::env()->ram_session(), w*h*sizeof(Pixel_rgb565)), + pixel(ds.local_addr()), + alpha((unsigned char *)Genode::env()->heap()->alloc(w*h)), + texture(pixel, alpha, w, h) + { + int alpha_min = config_alpha ? 0 : 255; + + /* init alpha channel */ + for (unsigned y = 0; y < h; y++) + for (unsigned x = 0; x < w; x++) { + + int v = (x * y + (w*h)/4) / w; + v = v + (x + y)/2; + int a = v & 0xff; + if (v & 0x100) + a = 255 - a; + + a += (dither_matrix[y % dither_size][x % dither_size] - 127) >> 4; + + alpha[y*w + x] = Genode::max(alpha_min, Genode::min(a, 255)); + } + } + + ~Fb_texture() + { + Genode::env()->heap()->free(alpha, w*h); + } + + }; + + Genode::Lock _lock; + bool _config_alpha; + Content_event_handler _ev_handler; + Fb_texture *_fb; + unsigned _new_w, _new_h; + Genode::Signal_context_capability _mode_sigh; + bool _wait_for_refresh; public: Window_content(unsigned fb_w, unsigned fb_h, Event_queue *ev_queue, bool config_alpha) : - _fb_w(fb_w), _fb_h(fb_h), - _fb_ds(Genode::env()->ram_session(), _fb_w*_fb_h*sizeof(Pixel_rgb565)), - _pixel(_fb_ds.local_addr()), - _alpha((unsigned char *)Genode::env()->heap()->alloc(_fb_w*_fb_h)), - _fb_texture(_pixel, _alpha, _fb_w, _fb_h), - _ev_handler(ev_queue, this) + _config_alpha(config_alpha), + _ev_handler(ev_queue, this, _lock), + _fb(new (Genode::env()->heap()) Fb_texture(fb_w, fb_h, _config_alpha)), + _new_w(fb_w), _new_h(fb_h), + _wait_for_refresh(false) { - _min_w = _fb_w; - _min_h = _fb_h; - - int alpha_min = config_alpha ? 0 : 255; - - /* init alpha channel */ - for (unsigned y = 0; y < _fb_h; y++) - for (unsigned x = 0; x < _fb_w; x++) { - - int v = (x * y + (_fb_w*_fb_h)/4) / _fb_w; - v = v + (x + y)/2; - int a = v & 0xff; - if (v & 0x100) - a = 255 - a; - - a += (dither_matrix[y % dither_size][x % dither_size] - 127) >> 4; - - _alpha[y*_fb_w + x] = Genode::max(alpha_min, Genode::min(a, 255)); - } + _min_w = _fb->w; + _min_h = _fb->h; event_handler(&_ev_handler); } - /** - * Accessors + /* + * Accessors, called by the RPC entrypoint. Hence, the need for + * locking. */ - Genode::Dataspace_capability fb_ds_cap() { return _fb_ds.cap(); } - unsigned fb_w() { return _fb_w; } - unsigned fb_h() { return _fb_h; } + + Genode::Dataspace_capability fb_ds_cap() { + Genode::Lock::Guard guard(_lock); + return _fb->ds.cap(); + } + + unsigned fb_w() { + Genode::Lock::Guard guard(_lock); + return _fb->w; + } + unsigned fb_h() { + Genode::Lock::Guard guard(_lock); + return _fb->h; + } + + void mode_sigh(Genode::Signal_context_capability sigh) + { + Genode::Lock::Guard guard(_lock); + _mode_sigh = sigh; + } + + void realloc_framebuffer() + { + Genode::Lock::Guard guard(_lock); + + /* skip reallocation if size has not changed */ + if (_new_w == _fb->w && _new_h == _fb->h) + return; + + Genode::destroy(Genode::env()->heap(), _fb); + + _fb = new (Genode::env()->heap()) + Fb_texture(_new_w, _new_h, _config_alpha); + + /* + * Suppress drawing of the texture until we received the next + * refresh call from the client. This way, we avoid flickering + * artifacts while continuously resizing the window. + */ + _wait_for_refresh = true; + } + + void client_called_refresh() { _wait_for_refresh = false; } /** * Element interface + * + * Called indirectly by the Content_event_handler thread, which has + * already taken the lock. */ - void draw(Canvas *c, int x, int y) { - c->draw_texture(&_fb_texture, _x + x, _y + y); } + void draw(Canvas *c, int x, int y) + { + if (!_wait_for_refresh) + c->draw_texture(&_fb->texture, _x + x, _y + y); + } + + void format_fixed_size(int w, int h) + { + _new_w = w, _new_h = h; + + /* notify framebuffer client about mode change */ + if (_mode_sigh.valid()) + Genode::Signal_transmitter(_mode_sigh).submit(); + } + + void lock() { _lock.lock(); } + void unlock() { _lock.unlock(); } }; @@ -185,6 +274,9 @@ static Window_content *_window_content; Element *window_content() { return _window_content; } +void lock_window_content() { _window_content->lock(); } +void unlock_window_content() { _window_content->unlock(); } + /*********************************************** ** Implementation of the framebuffer service ** @@ -194,39 +286,58 @@ namespace Framebuffer { class Session_component : public Genode::Rpc_object { + private: + + Window_content &_window_content; + public: - Genode::Dataspace_capability dataspace() { - return _window_content->fb_ds_cap(); } + Session_component(Window_content &window_content) + : _window_content(window_content) { } - void release() { } + Genode::Dataspace_capability dataspace() { + return _window_content.fb_ds_cap(); } + + void release() { + _window_content.realloc_framebuffer(); } Mode mode() const { - return Mode(_window_content->fb_w(), _window_content->fb_h(), + return Mode(_window_content.fb_w(), _window_content.fb_h(), Mode::RGB565); } - void mode_sigh(Genode::Signal_context_capability) { } + void mode_sigh(Genode::Signal_context_capability sigh) { + _window_content.mode_sigh(sigh); } - void refresh(int x, int y, int w, int h) { - window_content()->redraw_area(x, y, w, h); } + void refresh(int x, int y, int w, int h) + { + _window_content.client_called_refresh(); + _window_content.redraw_area(x, y, w, h); + } }; class Root : public Genode::Root_component { + private: + + Window_content &_window_content; + protected: Session_component *_create_session(const char *args) { - PDBG("creating framebuffer session"); - return new (md_alloc()) Session_component(); } + return new (md_alloc()) Session_component(_window_content); } public: Root(Genode::Rpc_entrypoint *session_ep, - Genode::Allocator *md_alloc) - : Genode::Root_component(session_ep, md_alloc) { } + Genode::Allocator *md_alloc, + Window_content &window_content) + : + Genode::Root_component(session_ep, md_alloc), + _window_content(window_content) + { } }; } @@ -248,7 +359,7 @@ void init_services(unsigned fb_w, unsigned fb_h, bool config_alpha) /* * Let the entry point serve the framebuffer and input root interfaces */ - static Framebuffer::Root fb_root(&ep, env()->heap()); + static Framebuffer::Root fb_root(&ep, env()->heap(), content); static Input::Root input_root(&ep, env()->heap()); /* diff --git a/demo/src/server/liquid_framebuffer/services.h b/demo/src/server/liquid_framebuffer/services.h index d847d26af..94e075314 100644 --- a/demo/src/server/liquid_framebuffer/services.h +++ b/demo/src/server/liquid_framebuffer/services.h @@ -19,5 +19,7 @@ extern Element *window_content(); extern void init_services(unsigned fb_w, unsigned fb_h, bool config_alpha); +extern void lock_window_content(); +extern void unlock_window_content(); #endif