From f82e1a709238f446e1b89a1c449f47675a5886aa Mon Sep 17 00:00:00 2001 From: Norman Feske Date: Mon, 14 Oct 2013 21:31:14 +0200 Subject: [PATCH] nitpicker: Late allocation of virtual framebuffer This patch changes the interface of Nitpicker to support dynamically dimensioned virtual frame buffers. This solves two problems: First, it enables a client to create a connection to nitpicker without donating much session quota in advance. The old interface required each screen-size-dependent client to donate as much memory as needed to allocate a screen-sized virtual framebuffer. For clients that are interested int the screen size but cover just a small portion of the screen (e.g., a banner, a menu, an applet that sits in the screen corner), this overprovisioning is painful. The new interface allows such clients to upgrade the session quota for an existing session as needed. Second, because each nitpicker session used to have a virtual frame buffer with a fixed size over the lifetime of the session, a client that wanted to implement a variable-sized window had to either vastly overprovide resources (by opening a session as large as the screen just in order to be prepared for the worst case of a maximized window), or it had to replace the session by a new one (thereby discarding the stacking order of the old views) each time the window changes its dimensions. The new interface accommodates such clients much better. --- demo/src/app/backdrop/main.cc | 12 +- demo/src/app/scout/genode/platform_genode.cc | 19 +- demo/src/server/nitlog/main.cc | 4 +- .../framebuffer_session_component.cc | 9 +- .../platforms/nitpicker/qnitpickerscreen.h | 3 +- os/include/nitpicker_session/client.h | 40 +-- os/include/nitpicker_session/connection.h | 146 ++++------ .../nitpicker_session/nitpicker_session.h | 133 +++++---- os/src/app/xvfb/main.cc | 12 +- os/src/app/xvfb/target.mk | 2 +- os/src/server/loader/nitpicker.h | 25 +- os/src/server/nit_fb/main.cc | 11 +- os/src/server/nitpicker/background.h | 2 +- os/src/server/nitpicker/chunky_menubar.h | 6 +- os/src/server/nitpicker/main.cc | 252 +++++++++++++----- os/src/server/nitpicker/mouse_cursor.h | 2 +- os/src/server/nitpicker/session.h | 55 ++-- os/src/server/nitpicker/view.cc | 5 +- os/src/test/loader/main.cc | 18 +- os/src/test/nitpicker/test.cc | 6 +- .../framebuffer_session_component.cc | 9 +- .../src/gui/embedded/qscreennitpicker_qws.cpp | 4 +- 22 files changed, 470 insertions(+), 305 deletions(-) diff --git a/demo/src/app/backdrop/main.cc b/demo/src/app/backdrop/main.cc index 8548a3990..ec6e2797f 100644 --- a/demo/src/app/backdrop/main.cc +++ b/demo/src/app/backdrop/main.cc @@ -232,14 +232,18 @@ int main(int argc, char **argv) return -2; } - static Nitpicker::Connection nitpicker; + static Nitpicker::Connection nitpicker; + + /* obtain physical screen size */ + Framebuffer::Mode const mode = nitpicker.mode(); + + /* setup virtual framebuffer mode */ + nitpicker.buffer(mode, false); + static Framebuffer::Session_client framebuffer(nitpicker.framebuffer_session()); Nitpicker::View_capability view_cap = nitpicker.create_view(); static Nitpicker::View_client view(view_cap); - /* obtain screen size */ - Framebuffer::Mode const mode = framebuffer.mode(); - if (mode.format() != Framebuffer::Mode::RGB565) { printf("Error: Color mode %d not supported\n", (int)mode.format()); return -3; diff --git a/demo/src/app/scout/genode/platform_genode.cc b/demo/src/app/scout/genode/platform_genode.cc index f74b9bd89..2fb14d1d7 100644 --- a/demo/src/app/scout/genode/platform_genode.cc +++ b/demo/src/app/scout/genode/platform_genode.cc @@ -215,28 +215,19 @@ Platform::Platform(unsigned vx, unsigned vy, unsigned vw, unsigned vh, Config::browser_attr = 7; /* - * Create temporary nitpicker session just to determine the screen size - * - * NOTE: This approach has the disadvantage creating the nitpicker session - * is not an atomic operation. In theory, both session requests may be - * propagated to different nitpicker instances. + * Allocate a nitpicker buffer double as high as the physical screen to + * use the upper/lower halves for double-buffering. */ - _nitpicker = new (env()->heap()) Nitpicker::Connection(); - Framebuffer::Mode const query_mode = _nitpicker->framebuffer()->mode(); + _nitpicker = new (env()->heap()) Nitpicker::Connection; + Framebuffer::Mode const query_mode = _nitpicker->mode(); _scr_w = query_mode.width(); _scr_h = query_mode.height(); _scr_format = query_mode.format(); - destroy(env()->heap(), _nitpicker); if (_max_vw) _scr_w = min(_max_vw, _scr_w); if (_max_vh) _scr_h = min(_max_vh, _scr_h); - /* - * Allocate a nitpicker buffer double as high as the physical screen to - * use the upper/lower halves for double-buffering. - */ - _nitpicker = new (env()->heap()) - Nitpicker::Connection(_scr_w, _scr_h*2, false, _scr_format); + _nitpicker->buffer(Framebuffer::Mode(_scr_w, _scr_h*2, _scr_format), false); static Timer::Connection timer; _timer = &timer; diff --git a/demo/src/server/nitlog/main.cc b/demo/src/server/nitlog/main.cc index e327a8c62..b4d00719d 100644 --- a/demo/src/server/nitlog/main.cc +++ b/demo/src/server/nitlog/main.cc @@ -342,9 +342,11 @@ int main(int argc, char **argv) int log_win_h = default_font.str_h(" ") * LOG_H + 2; /* init sessions to the required external services */ - static Nitpicker::Connection nitpicker(log_win_w, log_win_h); + static Nitpicker::Connection nitpicker; static Timer::Connection timer; + nitpicker.buffer(Framebuffer::Mode(LOG_W, LOG_H, Framebuffer::Mode::RGB565), false); + /* initialize entry point that serves the root interface */ enum { STACK_SIZE = 4096 }; static Cap_connection cap; diff --git a/libports/src/app/qt5/qt_avplay/framebuffer_session_component.cc b/libports/src/app/qt5/qt_avplay/framebuffer_session_component.cc index f12b48ad5..ea97849bc 100644 --- a/libports/src/app/qt5/qt_avplay/framebuffer_session_component.cc +++ b/libports/src/app/qt5/qt_avplay/framebuffer_session_component.cc @@ -41,11 +41,14 @@ namespace Framebuffer { QNitpickerViewWidget &nitpicker_view_widget, int max_width, int max_height) - : _nitpicker(Nitpicker::Connection( - _limited_size(session_arg(args, "fb_width"), max_width), - _limited_size(session_arg(args, "fb_height"), max_height))), + : _framebuffer(_nitpicker.framebuffer_session()) { + Framebuffer::Mode const + mode(_limited_size(session_arg(args, "fb_width"), max_width), + _limited_size(session_arg(args, "fb_height"), max_height), + _nitpicker.mode().format()); + _nitpicker.buffer(mode, false); Nitpicker::View_capability nitpicker_view_cap = _nitpicker.create_view(); Mode _mode = _framebuffer.mode(); nitpicker_view_widget.setNitpickerView(nitpicker_view_cap, diff --git a/libports/src/lib/qt5/qtbase/src/plugins/platforms/nitpicker/qnitpickerscreen.h b/libports/src/lib/qt5/qtbase/src/plugins/platforms/nitpicker/qnitpickerscreen.h index f58011eb9..05d98e7c5 100644 --- a/libports/src/lib/qt5/qtbase/src/plugins/platforms/nitpicker/qnitpickerscreen.h +++ b/libports/src/lib/qt5/qtbase/src/plugins/platforms/nitpicker/qnitpickerscreen.h @@ -38,7 +38,8 @@ class QNitpickerScreen : public QPlatformScreen QNitpickerScreen() : _framebuffer(_nitpicker.framebuffer_session()) { - Framebuffer::Mode const scr_mode = _framebuffer.mode(); + Framebuffer::Mode const scr_mode = _nitpicker.mode(); + _nitpicker.buffer(scr_mode, false); if (scr_mode.format() != Framebuffer::Mode::RGB565) qCritical() << "Nitpicker screen format is not RGB565"; diff --git a/os/include/nitpicker_session/client.h b/os/include/nitpicker_session/client.h index 07523db71..ef10e53cd 100644 --- a/os/include/nitpicker_session/client.h +++ b/os/include/nitpicker_session/client.h @@ -17,28 +17,34 @@ #include #include -namespace Nitpicker { +namespace Nitpicker { struct Session_client; } - struct Session_client : public Genode::Rpc_client - { - explicit Session_client(Session_capability session) - : Genode::Rpc_client(session) { } - Framebuffer::Session_capability framebuffer_session() { - return call(); } +struct Nitpicker::Session_client : public Rpc_client +{ + explicit Session_client(Session_capability session) + : Rpc_client(session) { } - Input::Session_capability input_session() { - return call(); } + Framebuffer::Session_capability framebuffer_session() { + return call(); } - View_capability create_view() { - return call(); } + Input::Session_capability input_session() { + return call(); } - void destroy_view(View_capability view) { - call(view); } + View_capability create_view() { + return call(); } - int background(View_capability view) { - return call(view); } - }; -} + void destroy_view(View_capability view) { + call(view); } + + int background(View_capability view) { + return call(view); } + + Framebuffer::Mode mode() { + return call(); } + + void buffer(Framebuffer::Mode mode, bool alpha) { + call(mode, alpha); } +}; #endif /* _INCLUDE__NITPICKER_SESSION__CLIENT_H_ */ diff --git a/os/include/nitpicker_session/connection.h b/os/include/nitpicker_session/connection.h index bffe79762..e45571edb 100644 --- a/os/include/nitpicker_session/connection.h +++ b/os/include/nitpicker_session/connection.h @@ -20,108 +20,76 @@ #include #include -namespace Nitpicker { +namespace Nitpicker { class Connection; } - class Connection : public Genode::Connection, - public Session_client - { - private: - Framebuffer::Session_client _framebuffer; - Input::Session_client _input; +class Nitpicker::Connection : public Genode::Connection, + public Session_client +{ + private: - /** - * Create session and return typed session capability + Framebuffer::Session_client _framebuffer; + Input::Session_client _input; + + /** + * Create session and return typed session capability + */ + Session_capability _connect(bool stay_top) + { + enum { ARGBUF_SIZE = 128 }; + char argbuf[ARGBUF_SIZE]; + argbuf[0] = 0; + + /* + * Declare ram-quota donation */ - Session_capability - _connect(unsigned width, unsigned height, bool alpha, - Framebuffer::Mode::Format format, bool stay_top) - { - using namespace Genode; + enum { SESSION_METADATA = 20*1024 }; + Arg_string::set_arg(argbuf, sizeof(argbuf), "ram_quota", SESSION_METADATA); - enum { ARGBUF_SIZE = 128 }; - char argbuf[ARGBUF_SIZE]; - argbuf[0] = 0; + if (stay_top) + Arg_string::set_arg(argbuf, sizeof(argbuf), "stay_top", "yes"); - /* by default, donate as much as needed for a 1024x768 RGB565 screen */ - Genode::size_t ram_quota = 1600*1024; + return session(argbuf); + } - /* - * NOTE: When specifying an INVALID mode as argument, we could - * probe for any valid video mode. For now, we just probe for - * RGB565. - */ - if (format == Framebuffer::Mode::INVALID) - format = Framebuffer::Mode::RGB565; + public: - /* if buffer dimensions are specified, calculate ram quota to donate */ - if (width && height) - ram_quota = width*height*Framebuffer::Mode::bytes_per_pixel(format); + /** + * Constructor + */ + Connection(bool stay_top = false) + : + /* establish nitpicker session */ + Genode::Connection(_connect(stay_top)), + Session_client(cap()), - /* account for alpha and input-mask buffers */ - if (alpha) - ram_quota += width*height*2; + /* request frame-buffer and input sub sessions */ + _framebuffer(framebuffer_session()), + _input(input_session()) + { } - /* add quota for storing server-side meta data */ - enum { SESSION_METADATA = 16*1024 }; - ram_quota += SESSION_METADATA; + void buffer(Framebuffer::Mode mode, bool use_alpha) + { + enum { ARGBUF_SIZE = 128 }; + char argbuf[ARGBUF_SIZE]; + argbuf[0] = 0; - /* declare ram-quota donation */ - Arg_string::set_arg(argbuf, sizeof(argbuf), "ram_quota", ram_quota); + Arg_string::set_arg(argbuf, sizeof(argbuf), "ram_quota", + ram_quota(mode, use_alpha)); - /* set optional session-constructor arguments */ - if (width) - Arg_string::set_arg(argbuf, sizeof(argbuf), "fb_width", width); - if (height) - Arg_string::set_arg(argbuf, sizeof(argbuf), "fb_height", height); - if (format != Framebuffer::Mode::INVALID) - Arg_string::set_arg(argbuf, sizeof(argbuf), "fb_format", format); - if (alpha) - Arg_string::set_arg(argbuf, sizeof(argbuf), "alpha", "yes"); - if (stay_top) - Arg_string::set_arg(argbuf, sizeof(argbuf), "stay_top", "yes"); + env()->parent()->upgrade(cap(), argbuf); + Session_client::buffer(mode, use_alpha); + } - return session(argbuf); - } + /** + * Return sub session for Nitpicker's input service + */ + Input::Session *input() { return &_input; } - public: - - /** - * Constructor - * - * \param width desired buffer width - * \param height desired buffer height - * \param alpha true for using a buffer with alpha channel - * \param format desired pixel format - * - * The specified value for 'format' is not enforced. After creating - * the session, you should validate the actual pixel format of the - * buffer by its 'mode'. - */ - Connection(unsigned width = 0, unsigned height = 0, bool alpha = false, - Framebuffer::Mode::Format format = Framebuffer::Mode::INVALID, - bool stay_top = false) - : - /* establish nitpicker session */ - Genode::Connection(_connect(width, height, alpha, - format, stay_top)), - Session_client(cap()), - - /* request frame-buffer and input sub sessions */ - _framebuffer(framebuffer_session()), - _input(input_session()) - { } - - /** - * Return sub session for Nitpicker's input service - */ - Input::Session *input() { return &_input; } - - /** - * Return sub session for session's frame buffer - */ - Framebuffer::Session *framebuffer() { return &_framebuffer; } - }; -} + /** + * Return sub session for session's frame buffer + */ + Framebuffer::Session *framebuffer() { return &_framebuffer; } +}; #endif /* _INCLUDE__NITPICKER_SESSION__CONNECTION_H_ */ diff --git a/os/include/nitpicker_session/nitpicker_session.h b/os/include/nitpicker_session/nitpicker_session.h index a636bfd3e..8cc62c83a 100644 --- a/os/include/nitpicker_session/nitpicker_session.h +++ b/os/include/nitpicker_session/nitpicker_session.h @@ -22,54 +22,91 @@ #include namespace Nitpicker { - - struct Session : Genode::Session - { - static const char *service_name() { return "Nitpicker"; } - - virtual ~Session() { } - - /** - * Request framebuffer sub-session - */ - virtual Framebuffer::Session_capability framebuffer_session() = 0; - - /** - * Request input sub-session - */ - virtual Input::Session_capability input_session() = 0; - - /** - * Create a new view at the buffer - * - * \return capability to a new view - */ - virtual View_capability create_view() = 0; - - /** - * Destroy view - */ - virtual void destroy_view(View_capability view) = 0; - - /** - * Define view that is used as desktop background - */ - virtual int background(View_capability view) = 0; - - - /********************* - ** RPC declaration ** - *********************/ - - GENODE_RPC(Rpc_framebuffer_session, Framebuffer::Session_capability, framebuffer_session); - GENODE_RPC(Rpc_input_session, Input::Session_capability, input_session); - GENODE_RPC(Rpc_create_view, View_capability, create_view); - GENODE_RPC(Rpc_destroy_view, void, destroy_view, View_capability); - GENODE_RPC(Rpc_background, int, background, View_capability); - - GENODE_RPC_INTERFACE(Rpc_framebuffer_session, Rpc_input_session, - Rpc_create_view, Rpc_destroy_view, Rpc_background); - }; + using namespace Genode; + struct Session; } + +struct Nitpicker::Session : Genode::Session +{ + static const char *service_name() { return "Nitpicker"; } + + /** + * Exception type + */ + struct Out_of_metadata : Genode::Exception { }; + + virtual ~Session() { } + + /** + * Request framebuffer sub-session + */ + virtual Framebuffer::Session_capability framebuffer_session() = 0; + + /** + * Request input sub-session + */ + virtual Input::Session_capability input_session() = 0; + + /** + * Create a new view at the buffer + * + * \return capability to a new view + */ + virtual View_capability create_view() = 0; + + /** + * Destroy view + */ + virtual void destroy_view(View_capability view) = 0; + + /** + * Define view that is used as desktop background + */ + virtual int background(View_capability view) = 0; + + /** + * Return physical screen mode + */ + virtual Framebuffer::Mode mode() = 0; + + /** + * Define dimensions of virtual framebuffer + * + * \throw Out_of_metadata session quota does not suffice for specified + * buffer dimensions + */ + virtual void buffer(Framebuffer::Mode mode, bool use_alpha) = 0; + + /** + * Return number of bytes needed for virtual framebuffer of specified size + */ + static size_t ram_quota(Framebuffer::Mode mode, bool use_alpha) + { + /* + * If alpha blending is used, each pixel requires an additional byte + * for the alpha value and a byte holding the input mask. + */ + return (mode.bytes_per_pixel() + 2*use_alpha)*mode.width()*mode.height(); + } + + + /********************* + ** RPC declaration ** + *********************/ + + GENODE_RPC(Rpc_framebuffer_session, Framebuffer::Session_capability, framebuffer_session); + GENODE_RPC(Rpc_input_session, Input::Session_capability, input_session); + GENODE_RPC(Rpc_create_view, View_capability, create_view); + GENODE_RPC(Rpc_destroy_view, void, destroy_view, View_capability); + GENODE_RPC(Rpc_background, int, background, View_capability); + GENODE_RPC(Rpc_mode, Framebuffer::Mode, mode); + GENODE_RPC_THROW(Rpc_buffer, void, buffer, GENODE_TYPE_LIST(Out_of_metadata), + Framebuffer::Mode, bool); + + GENODE_RPC_INTERFACE(Rpc_framebuffer_session, Rpc_input_session, + Rpc_create_view, Rpc_destroy_view, Rpc_background, + Rpc_mode, Rpc_buffer); +}; + #endif /* _INCLUDE__NITPICKER_SESSION__NITPICKER_SESSION_H_ */ diff --git a/os/src/app/xvfb/main.cc b/os/src/app/xvfb/main.cc index 22bf60442..3cc4adea9 100644 --- a/os/src/app/xvfb/main.cc +++ b/os/src/app/xvfb/main.cc @@ -60,8 +60,16 @@ static Pixel *fb_addr; static Nitpicker::Session *nitpicker() { - static Nitpicker::Connection nitpicker_connection; - return &nitpicker_connection; + struct Connection : Nitpicker::Connection + { + Connection() + { + Nitpicker::Connection::buffer(mode(), false); + } + }; + + static Connection connection; + return &connection; } diff --git a/os/src/app/xvfb/target.mk b/os/src/app/xvfb/target.mk index d456edf93..4429cc0f0 100644 --- a/os/src/app/xvfb/target.mk +++ b/os/src/app/xvfb/target.mk @@ -1,6 +1,6 @@ TARGET = xvfb REQUIRES = linux x11 xtest xdamage SRC_CC = main.cc inject_input.cc -LIBS = base_hybrid syscall blit xev_track config +LIBS = lx_hybrid syscall blit xev_track config EXT_OBJECTS += -lX11 -lXdamage /usr/lib/libXtst.so.6 diff --git a/os/src/server/loader/nitpicker.h b/os/src/server/loader/nitpicker.h index 571431f56..b89217951 100644 --- a/os/src/server/loader/nitpicker.h +++ b/os/src/server/loader/nitpicker.h @@ -161,8 +161,6 @@ namespace Nitpicker { Rpc_entrypoint &_ep; - int _fb_width, _fb_height; - Nitpicker::Connection _nitpicker; View_capability _nitpicker_view; @@ -189,13 +187,6 @@ namespace Nitpicker { : _ep(ep), - /* store the framebuffer size for view size constraining */ - _fb_width(_session_arg(args, "fb_width")), - _fb_height(_session_arg(args, "fb_height")), - - /* connect to the "real" Nitpicker service */ - _nitpicker(_fb_width, _fb_height), - /* create Nitpicker view */ _nitpicker_view(_nitpicker.create_view()), @@ -242,6 +233,16 @@ namespace Nitpicker { return 0; } + Framebuffer::Mode mode() + { + return _nitpicker.mode(); + } + + void buffer(Framebuffer::Mode mode, bool use_alpha) + { + _nitpicker.buffer(mode, use_alpha); + } + /********************************** ** Input::Transformer interface ** @@ -270,9 +271,11 @@ namespace Nitpicker { */ Loader::Session::View_geometry loader_view_geometry() { + Framebuffer::Session_client framebuffer(framebuffer_session()); + Framebuffer::Mode const mode = framebuffer.mode(); Loader::Session::View_geometry result( - min(_proxy_view.w(), _fb_width), - min(_proxy_view.h(), _fb_height), + min(_proxy_view.w(), mode.width()), + min(_proxy_view.h(), mode.height()), _proxy_view.buf_x(), _proxy_view.buf_y()); diff --git a/os/src/server/nit_fb/main.cc b/os/src/server/nit_fb/main.cc index 702eb5cc9..b1bc2e59d 100644 --- a/os/src/server/nit_fb/main.cc +++ b/os/src/server/nit_fb/main.cc @@ -149,17 +149,22 @@ int main(int argc, char **argv) /* * Open Nitpicker session */ - static Nitpicker::Connection nitpicker(view_w, view_h); + static Nitpicker::Connection nitpicker; /* * If no config was provided, use screen size of Nitpicker */ if (view_w == 0 || view_h == 0) { - Framebuffer::Session_client nit_fb(nitpicker.framebuffer_session()); - Framebuffer::Mode const mode = nit_fb.mode(); + Framebuffer::Mode const mode = nitpicker.mode(); view_w = mode.width(), view_h = mode.height(); } + /* + * Setup virtual framebuffer + */ + Framebuffer::Mode const mode(view_w, view_h, Framebuffer::Mode::RGB565); + nitpicker.buffer(mode, false); + PINF("using xywh=(%ld,%ld,%ld,%ld) refresh_rate=%u", view_x, view_y, view_w, view_h, cfg.refresh_rate); diff --git a/os/src/server/nitpicker/background.h b/os/src/server/nitpicker/background.h index b7a8b1c18..4959d2f8e 100644 --- a/os/src/server/nitpicker/background.h +++ b/os/src/server/nitpicker/background.h @@ -28,7 +28,7 @@ struct Background : private Texture, Session, View */ Background(Area size) : - Texture(Area(0, 0)), Session(Genode::Session_label(""), *this, 0), + Texture(Area(0, 0)), Session(Genode::Session_label(""), 0, false), View(*this, View::NOT_STAY_TOP, View::NOT_TRANSPARENT, View::BACKGROUND, Rect(Point(0, 0), size)), color(25, 37, 50) diff --git a/os/src/server/nitpicker/chunky_menubar.h b/os/src/server/nitpicker/chunky_menubar.h index 2ea781649..638cba97e 100644 --- a/os/src/server/nitpicker/chunky_menubar.h +++ b/os/src/server/nitpicker/chunky_menubar.h @@ -30,9 +30,11 @@ class Chunky_menubar : public Chunky_texture, Chunky_menubar(PT *pixels, Area size) : Chunky_texture(pixels, 0, size), - Session(Genode::Session_label(""), *this, 0), + Session(Genode::Session_label(""), 0, false), Menubar(_chunky_canvas, size, *this), _chunky_canvas(pixels, size) - { } + { + Session::texture(this); + } /*********************** diff --git a/os/src/server/nitpicker/main.cc b/os/src/server/nitpicker/main.cc index 62824e89d..31c287049 100644 --- a/os/src/server/nitpicker/main.cc +++ b/os/src/server/nitpicker/main.cc @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -136,6 +137,18 @@ class Buffer }; +/** + * Interface for triggering the re-allocation of a virtual framebuffer + * + * Used by 'Framebuffer::Session_component', + * implemented by 'Nitpicker::Session_component' + */ +struct Buffer_provider +{ + virtual Buffer *realloc_buffer(Framebuffer::Mode mode, bool use_alpha) = 0; +}; + + template class Chunky_dataspace_texture : public Buffer, public Chunky_texture { @@ -263,37 +276,79 @@ class Framebuffer::Session_component : public Genode::Rpc_object { private: - ::Buffer &_buffer; - View_stack &_view_stack; - ::Session &_session; - Flush_merger &_flush_merger; - Framebuffer::Session &_framebuffer; + ::Buffer *_buffer = 0; + View_stack &_view_stack; + ::Session &_session; + Flush_merger &_flush_merger; + Framebuffer::Session &_framebuffer; + Buffer_provider &_buffer_provider; + Signal_context_capability _mode_sigh; + Framebuffer::Mode _mode; + bool _alpha = false; public: /** * Constructor - * - * \param session Nitpicker session */ - Session_component(::Buffer &buffer, View_stack &view_stack, - ::Session &session, Flush_merger &flush_merger, - Framebuffer::Session &framebuffer) + Session_component(View_stack &view_stack, + ::Session &session, + Flush_merger &flush_merger, + Framebuffer::Session &framebuffer, + Buffer_provider &buffer_provider) : - _buffer(buffer), _view_stack(view_stack), _session(session), - _flush_merger(flush_merger), _framebuffer(framebuffer) { } + _view_stack(view_stack), + _session(session), + _flush_merger(flush_merger), + _framebuffer(framebuffer), + _buffer_provider(buffer_provider) + { } - Dataspace_capability dataspace() { return _buffer.ds_cap(); } + + /** + * Change virtual framebuffer mode + * + * Called by Nitpicker::Session_component when re-dimensioning the + * buffer. + * + * The new mode does not immediately become active. The client can + * keep using an already obtained framebuffer dataspace. However, + * we inform the client about the mode change via a signal. If the + * client calls 'dataspace' the next time, the new mode becomes + * effective. + */ + void notify_mode_change(Framebuffer::Mode mode, bool alpha) + { + _mode = mode; + _alpha = alpha; + + if (_mode_sigh.valid()) + Signal_transmitter(_mode_sigh).submit(); + } + + + /************************************ + ** Framebuffer::Session interface ** + ************************************/ + + Dataspace_capability dataspace() + { + _buffer = _buffer_provider.realloc_buffer(_mode, _alpha); + + return _buffer ? _buffer->ds_cap() : Ram_dataspace_capability(); + } void release() { } Mode mode() const { - return Mode(_buffer.size().w(), _buffer.size().h(), - _buffer.format()); + return _mode; } - void mode_sigh(Signal_context_capability) { } + void mode_sigh(Signal_context_capability mode_sigh) + { + _mode_sigh = mode_sigh; + } void refresh(int x, int y, int w, int h) { @@ -378,10 +433,15 @@ class View_component : public Genode::List::Element, *****************************************/ class Nitpicker::Session_component : public Genode::Rpc_object, - public ::Session + public ::Session, + public Buffer_provider { private: + Allocator_guard _buffer_alloc; + + Framebuffer::Session &_framebuffer; + /* Framebuffer_session_component */ Framebuffer::Session_component _framebuffer_session_component; @@ -404,30 +464,57 @@ class Nitpicker::Session_component : public Genode::Rpc_object, bool const _provides_default_bg; + /* size of currently allocated virtual framebuffer, in bytes */ + size_t _buffer_size = 0; + + void _release_buffer() + { + if (!::Session::texture()) + return; + + typedef Pixel_rgb565 PT; + + /* retrieve pointer to texture from session */ + Chunky_dataspace_texture const *cdt = + static_cast const *>(::Session::texture()); + + ::Session::texture(0); + ::Session::input_mask(0); + + destroy(&_buffer_alloc, const_cast *>(cdt)); + + _buffer_alloc.upgrade(_buffer_size); + _buffer_size = 0; + } + public: /** * Constructor */ - Session_component(Session_label const &label, - ::Buffer &buffer, - Texture const &texture, - View_stack &view_stack, - Rpc_entrypoint &ep, - Flush_merger &flush_merger, - Framebuffer::Session &framebuffer, - int v_offset, - unsigned char const *input_mask, - bool provides_default_bg, - bool stay_top) + Session_component(Session_label const &label, + View_stack &view_stack, + Rpc_entrypoint &ep, + Flush_merger &flush_merger, + Framebuffer::Session &framebuffer, + int v_offset, + bool provides_default_bg, + bool stay_top, + Allocator &buffer_alloc, + size_t ram_quota) : - ::Session(label, texture, v_offset, input_mask, stay_top), - _framebuffer_session_component(buffer, view_stack, *this, flush_merger, framebuffer), + ::Session(label, v_offset, stay_top), + _buffer_alloc(&buffer_alloc, ram_quota), + _framebuffer(framebuffer), + _framebuffer_session_component(view_stack, *this, flush_merger, + framebuffer, *this), _ep(ep), _view_stack(view_stack), _framebuffer_session_cap(_ep.manage(&_framebuffer_session_component)), _input_session_cap(_ep.manage(&_input_session_component)), _provides_default_bg(provides_default_bg) - { } + { + _buffer_alloc.upgrade(ram_quota); + } /** * Destructor @@ -439,8 +526,12 @@ class Nitpicker::Session_component : public Genode::Rpc_object, while (View_component *vc = _view_list.first()) destroy_view(vc->cap()); + + _release_buffer(); } + void upgrade_ram_quota(size_t ram_quota) { _buffer_alloc.upgrade(ram_quota); } + /****************************************** ** Nitpicker-internal session interface ** @@ -517,6 +608,56 @@ class Nitpicker::Session_component : public Genode::Rpc_object, return 0; } + + Framebuffer::Mode mode() + { + unsigned const width = _framebuffer.mode().width(); + unsigned const height = _framebuffer.mode().height() + - ::Session::v_offset(); + + return Framebuffer::Mode(width, height, + _framebuffer.mode().format()); + } + + void buffer(Framebuffer::Mode mode, bool use_alpha) + { + /* check if the session quota suffices for the specified mode */ + if (_buffer_alloc.quota() < ram_quota(mode, use_alpha)) + throw Nitpicker::Session::Out_of_metadata(); + + _framebuffer_session_component.notify_mode_change(mode, use_alpha); + } + + + /******************************* + ** Buffer_provider interface ** + *******************************/ + + Buffer *realloc_buffer(Framebuffer::Mode mode, bool use_alpha) + { + _release_buffer(); + + Area const size(mode.width(), mode.height()); + + typedef Pixel_rgb565 PT; + + _buffer_size = + Chunky_dataspace_texture::calc_num_bytes(size, use_alpha); + + Chunky_dataspace_texture * const texture = + new (&_buffer_alloc) Chunky_dataspace_texture(size, use_alpha); + + if (!_buffer_alloc.withdraw(_buffer_size)) { + destroy(&_buffer_alloc, texture); + _buffer_size = 0; + return 0; + } + + ::Session::texture(texture); + ::Session::input_mask(texture->input_mask_buffer()); + + return texture; + } }; @@ -527,7 +668,7 @@ class Nitpicker::Root : public Genode::Root_component Session_list &_session_list; Global_keys &_global_keys; - Area _scr_size; + Framebuffer::Mode _scr_mode; View_stack &_view_stack; Flush_merger &_flush_merger; Framebuffer::Session &_framebuffer; @@ -542,17 +683,9 @@ class Nitpicker::Root : public Genode::Root_component int const v_offset = _default_v_offset; - /* determine buffer size of the session */ - Area const size(Arg_string::find_arg(args, "fb_width" ).long_value(_scr_size.w()), - Arg_string::find_arg(args, "fb_height").long_value(_scr_size.h() - v_offset)); - - bool const use_alpha = Arg_string::find_arg(args, "alpha").bool_value(false); bool const stay_top = Arg_string::find_arg(args, "stay_top").bool_value(false); - size_t const texture_num_bytes = Chunky_dataspace_texture::calc_num_bytes(size, use_alpha); - - size_t const required_quota = texture_num_bytes - + Input::Session_component::ev_ds_size(); + size_t const required_quota = Input::Session_component::ev_ds_size(); if (ram_quota < required_quota) { PWRN("Insufficient dontated ram_quota (%zd bytes), require %zd bytes", @@ -560,19 +693,16 @@ class Nitpicker::Root : public Genode::Root_component throw Root::Quota_exceeded(); } - /* allocate texture */ - Chunky_dataspace_texture * const cdt = - new (md_alloc()) Chunky_dataspace_texture(size, use_alpha); + size_t const unused_quota = ram_quota - required_quota; Session_label const label(args); bool const provides_default_bg = (strcmp(label.string(), "backdrop") == 0); Session_component *session = new (md_alloc()) - Session_component(Session_label(args), *cdt, *cdt, - _view_stack, *ep(), _flush_merger, - _framebuffer, v_offset, - cdt->input_mask_buffer(), - provides_default_bg, stay_top); + Session_component(Session_label(args), _view_stack, *ep(), + _flush_merger, _framebuffer, v_offset, + provides_default_bg, stay_top, + *md_alloc(), unused_quota); session->apply_session_color(); _session_list.insert(session); @@ -581,19 +711,18 @@ class Nitpicker::Root : public Genode::Root_component return session; } + void _upgrade_session(Session_component *s, const char *args) + { + size_t ram_quota = Arg_string::find_arg(args, "ram_quota").long_value(0); + s->upgrade_ram_quota(ram_quota); + } + void _destroy_session(Session_component *session) { - /* retrieve pointer to texture from session */ - Chunky_dataspace_texture const &cdt = - static_cast const &>(session->texture()); - _session_list.remove(session); _global_keys.apply_config(_session_list); destroy(md_alloc(), session); - - /* cast away constness just for destruction of the texture */ - destroy(md_alloc(), const_cast *>(&cdt)); } public: @@ -602,15 +731,15 @@ class Nitpicker::Root : public Genode::Root_component * Constructor */ Root(Session_list &session_list, Global_keys &global_keys, - Rpc_entrypoint &session_ep, Area scr_size, - View_stack &view_stack, Allocator &md_alloc, - Flush_merger &flush_merger, + Rpc_entrypoint &session_ep, View_stack &view_stack, + Allocator &md_alloc, Flush_merger &flush_merger, Framebuffer::Session &framebuffer, int default_v_offset) : Root_component(&session_ep, &md_alloc), _session_list(session_list), _global_keys(global_keys), - _scr_size(scr_size), _view_stack(view_stack), _flush_merger(flush_merger), - _framebuffer(framebuffer), _default_v_offset(default_v_offset) { } + _view_stack(view_stack), _flush_merger(flush_merger), + _framebuffer(framebuffer), _default_v_offset(default_v_offset) + { } }; @@ -673,7 +802,6 @@ struct Nitpicker::Main Sliced_heap sliced_heap = { env()->ram_session(), env()->rm_session() }; Root np_root = { session_list, global_keys, ep.rpc_ep(), - Area(mode.width(), mode.height()), user_state, sliced_heap, screen, framebuffer, MENUBAR_HEIGHT }; /* diff --git a/os/src/server/nitpicker/mouse_cursor.h b/os/src/server/nitpicker/mouse_cursor.h index 412cf2056..ea6647e42 100644 --- a/os/src/server/nitpicker/mouse_cursor.h +++ b/os/src/server/nitpicker/mouse_cursor.h @@ -37,7 +37,7 @@ class Mouse_cursor : public Chunky_texture, public Session, public View Mouse_cursor(PT const *pixels, Area size, View_stack const &view_stack) : Chunky_texture(pixels, 0, size), - Session(Genode::Session_label(""), *this, 0), + Session(Genode::Session_label(""), 0, false), View(*this, View::STAY_TOP, View::TRANSPARENT, View::NOT_BACKGROUND, Rect()), _view_stack(view_stack) diff --git a/os/src/server/nitpicker/session.h b/os/src/server/nitpicker/session.h index 3535d4b48..ab470f4d4 100644 --- a/os/src/server/nitpicker/session.h +++ b/os/src/server/nitpicker/session.h @@ -37,7 +37,7 @@ class Session : public Session_list::Element Genode::Session_label const _label; Color _color; - Texture const &_texture; + Texture const *_texture; View *_background = 0; int _v_offset; unsigned char const *_input_mask; @@ -48,26 +48,14 @@ class Session : public Session_list::Element /** * Constructor * - * \param label session label - * \param texture texture containing the session's pixel - * representation - * \param v_offset vertical screen offset of session - * \param input_mask input mask buffer containing a byte value per - * texture pixel, which describes the policy of - * handling user input referring to the pixel. - * If set to zero, the input is passed through - * the view such that it can be handled by one of - * the subsequent views in the view stack. If set - * to one, the input is consumed by the view. If - * 'input_mask' is a null pointer, user input is - * unconditionally consumed by the view. + * \param label session label + * \param v_offset vertical screen offset of session + * \param stay_top true for views that stay always in front */ - Session(Genode::Session_label const &label, Texture const &texture, - int v_offset, unsigned char const *input_mask = 0, - bool stay_top = false) + Session(Genode::Session_label const &label, int v_offset, bool stay_top) : - _label(label), _texture(texture), _v_offset(v_offset), - _input_mask(input_mask), _stay_top(stay_top) + _label(label), _texture(0), _v_offset(v_offset), + _input_mask(0), _stay_top(stay_top) { } virtual ~Session() { } @@ -76,7 +64,23 @@ class Session : public Session_list::Element Genode::Session_label const &label() const { return _label; } - Texture const &texture() const { return _texture; } + Texture const *texture() const { return _texture; } + + void texture(Texture const *texture) { _texture = texture; } + + /** + * Set input mask buffer + * + * \param mask input mask buffer containing a byte value per texture + * pixel, which describes the policy of handling user + * input referring to the pixel. If set to zero, the input + * is passed through the view such that it can be handled + * by one of the subsequent views in the view stack. If + * set to one, the input is consumed by the view. If + * 'input_mask' is a null pointer, user input is + * unconditionally consumed by the view. + */ + void input_mask(unsigned char const *mask) { _input_mask = mask; } Color color() const { return _color; } @@ -89,7 +93,7 @@ class Session : public Session_list::Element /** * Return true if session uses an alpha channel */ - bool uses_alpha() const { return _texture.alpha(); } + bool uses_alpha() const { return _texture ? _texture->alpha() : 0; } /** * Return vertical offset of session @@ -101,14 +105,14 @@ class Session : public Session_list::Element */ unsigned char input_mask_at(Point p) const { - if (!_input_mask) return 0; + if (!_input_mask || !_texture) return 0; /* check boundaries */ - if (p.x() < 0 || p.x() >= _texture.w() - || p.y() < 0 || p.y() >= _texture.h()) + if (p.x() < 0 || p.x() >= _texture->w() + || p.y() < 0 || p.y() >= _texture->h()) return 0; - return _input_mask[p.y()*_texture.w() + p.x()]; + return _input_mask[p.y()*_texture->w() + p.x()]; } /** @@ -129,7 +133,6 @@ class Session : public Session_list::Element policy.attribute("color").value(&_color); } catch (...) { } } - }; #endif diff --git a/os/src/server/nitpicker/view.cc b/os/src/server/nitpicker/view.cc index a1abc4d3d..8254a2e72 100644 --- a/os/src/server/nitpicker/view.cc +++ b/os/src/server/nitpicker/view.cc @@ -109,8 +109,9 @@ void View::draw(Canvas &canvas, Mode const &mode) const _session.color().g >> 1, _session.color().b >> 1); - canvas.draw_texture(_session.texture(), mix_color, _buffer_off + p1(), - op, allow_alpha); + if (_session.texture()) + canvas.draw_texture(*_session.texture(), mix_color, _buffer_off + p1(), + op, allow_alpha); if (mode.flat()) return; diff --git a/os/src/test/loader/main.cc b/os/src/test/loader/main.cc index f2ecfe7db..1acfbf930 100644 --- a/os/src/test/loader/main.cc +++ b/os/src/test/loader/main.cc @@ -33,12 +33,8 @@ int main(int argc, char **argv) sig_rec.wait_for_signal(); - Nitpicker::View_capability view_cap = loader.view(); - Loader::Session::View_geometry geometry = loader.view_geometry(); - - PDBG("w = %d, h = %d, buf_x = %d, buf_y = %d", - geometry.width, geometry.height, geometry.buf_x, geometry.buf_y); + Nitpicker::View_capability view_cap = loader.view(); Nitpicker::View_client view(view_cap); view.stack(Nitpicker::View_capability(), true, false); @@ -46,12 +42,12 @@ int main(int argc, char **argv) Timer::Connection timer; while(1) { - view.viewport(0, 0, geometry.width, geometry.height, - geometry.buf_x, geometry.buf_y, true); - timer.msleep(1000); - view.viewport(50, 50, geometry.width, geometry.height, - geometry.buf_x, geometry.buf_y, true); - timer.msleep(1000); + + for (unsigned i = 0; i < 10; i++) { + view.viewport(50*i, 50*i, geometry.width, geometry.height, + geometry.buf_x, geometry.buf_y, true); + timer.msleep(1000); + } } sleep_forever(); diff --git a/os/src/test/nitpicker/test.cc b/os/src/test/nitpicker/test.cc index da7df0877..048b68890 100644 --- a/os/src/test/nitpicker/test.cc +++ b/os/src/test/nitpicker/test.cc @@ -112,10 +112,12 @@ int main(int argc, char **argv) * Init sessions to the required external services */ enum { CONFIG_ALPHA = false }; - static Nitpicker::Connection nitpicker(256, 256, CONFIG_ALPHA); + static Nitpicker::Connection nitpicker; static Timer::Connection timer; - Framebuffer::Mode const mode = nitpicker.framebuffer()->mode(); + Framebuffer::Mode const mode(256, 256, Framebuffer::Mode::RGB565); + nitpicker.buffer(mode, false); + int const scr_w = mode.width(), scr_h = mode.height(); printf("screen is %dx%d\n", scr_w, scr_h); diff --git a/qt4/src/app/qt_avplay/framebuffer_session_component.cc b/qt4/src/app/qt_avplay/framebuffer_session_component.cc index f12b48ad5..28ca4ab58 100644 --- a/qt4/src/app/qt_avplay/framebuffer_session_component.cc +++ b/qt4/src/app/qt_avplay/framebuffer_session_component.cc @@ -41,11 +41,14 @@ namespace Framebuffer { QNitpickerViewWidget &nitpicker_view_widget, int max_width, int max_height) - : _nitpicker(Nitpicker::Connection( - _limited_size(session_arg(args, "fb_width"), max_width), - _limited_size(session_arg(args, "fb_height"), max_height))), + : _framebuffer(_nitpicker.framebuffer_session()) { + Framebuffer::Mode const + mode(_limited_size(session_arg(args, "fb_width"), max_width), + _limited_size(session_arg(args, "fb_height"), max_height), + _nitpicker.mode().format()); + _nitpicker.buffer(mode, false); Nitpicker::View_capability nitpicker_view_cap = _nitpicker.create_view(); Mode _mode = _framebuffer.mode(); nitpicker_view_widget.setNitpickerView(nitpicker_view_cap, diff --git a/qt4/src/lib/qt4/src/gui/embedded/qscreennitpicker_qws.cpp b/qt4/src/lib/qt4/src/gui/embedded/qscreennitpicker_qws.cpp index 439485048..f66333aae 100644 --- a/qt4/src/lib/qt4/src/gui/embedded/qscreennitpicker_qws.cpp +++ b/qt4/src/lib/qt4/src/gui/embedded/qscreennitpicker_qws.cpp @@ -173,9 +173,11 @@ bool QNitpickerScreen::connect(const QString &displaySpec) nitpicker = new Nitpicker::Connection(); framebuffer = new Framebuffer::Session_client(nitpicker->framebuffer_session()); - Framebuffer::Mode const scr_mode = framebuffer->mode(); + Framebuffer::Mode const scr_mode = nitpicker->mode(); int const scr_w = scr_mode.width(), scr_h = scr_mode.height(); + nitpicker->buffer(scr_mode, false); + qDebug() << "screen is " << scr_w << "x" << scr_h; if (!scr_w || !scr_h) { qDebug("got invalid screen - spinning");