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.
This commit is contained in:
Norman Feske 2013-10-14 21:31:14 +02:00 committed by Christian Helmuth
parent 2322ab202c
commit f82e1a7092
22 changed files with 470 additions and 305 deletions

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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,

View File

@ -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";

View File

@ -17,28 +17,34 @@
#include <nitpicker_session/capability.h>
#include <base/rpc_client.h>
namespace Nitpicker {
namespace Nitpicker { struct Session_client; }
struct Session_client : public Genode::Rpc_client<Session>
{
explicit Session_client(Session_capability session)
: Genode::Rpc_client<Session>(session) { }
Framebuffer::Session_capability framebuffer_session() {
return call<Rpc_framebuffer_session>(); }
struct Nitpicker::Session_client : public Rpc_client<Session>
{
explicit Session_client(Session_capability session)
: Rpc_client<Session>(session) { }
Input::Session_capability input_session() {
return call<Rpc_input_session>(); }
Framebuffer::Session_capability framebuffer_session() {
return call<Rpc_framebuffer_session>(); }
View_capability create_view() {
return call<Rpc_create_view>(); }
Input::Session_capability input_session() {
return call<Rpc_input_session>(); }
void destroy_view(View_capability view) {
call<Rpc_destroy_view>(view); }
View_capability create_view() {
return call<Rpc_create_view>(); }
int background(View_capability view) {
return call<Rpc_background>(view); }
};
}
void destroy_view(View_capability view) {
call<Rpc_destroy_view>(view); }
int background(View_capability view) {
return call<Rpc_background>(view); }
Framebuffer::Mode mode() {
return call<Rpc_mode>(); }
void buffer(Framebuffer::Mode mode, bool alpha) {
call<Rpc_buffer>(mode, alpha); }
};
#endif /* _INCLUDE__NITPICKER_SESSION__CLIENT_H_ */

View File

@ -20,108 +20,76 @@
#include <util/arg_string.h>
#include <base/connection.h>
namespace Nitpicker {
namespace Nitpicker { class Connection; }
class Connection : public Genode::Connection<Session>,
public Session_client
{
private:
Framebuffer::Session_client _framebuffer;
Input::Session_client _input;
class Nitpicker::Connection : public Genode::Connection<Session>,
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<Session>(_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<Session>(_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_ */

View File

@ -22,54 +22,91 @@
#include <nitpicker_view/capability.h>
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_ */

View File

@ -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;
}

View File

@ -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

View File

@ -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());

View File

@ -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);

View File

@ -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)

View File

@ -30,9 +30,11 @@ class Chunky_menubar : public Chunky_texture<PT>,
Chunky_menubar(PT *pixels, Area size)
:
Chunky_texture<PT>(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);
}
/***********************

View File

@ -15,6 +15,7 @@
#include <base/env.h>
#include <base/sleep.h>
#include <base/printf.h>
#include <base/allocator_guard.h>
#include <os/attached_ram_dataspace.h>
#include <input/event.h>
#include <input/keycodes.h>
@ -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 <typename PT>
class Chunky_dataspace_texture : public Buffer, public Chunky_texture<PT>
{
@ -263,37 +276,79 @@ class Framebuffer::Session_component : public Genode::Rpc_object<Session>
{
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<View_component>::Element,
*****************************************/
class Nitpicker::Session_component : public Genode::Rpc_object<Session>,
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<Session>,
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<PT> const *cdt =
static_cast<Chunky_dataspace_texture<PT> const *>(::Session::texture());
::Session::texture(0);
::Session::input_mask(0);
destroy(&_buffer_alloc, const_cast<Chunky_dataspace_texture<PT> *>(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<Session>,
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<Session>,
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<PT>::calc_num_bytes(size, use_alpha);
Chunky_dataspace_texture<PT> * const texture =
new (&_buffer_alloc) Chunky_dataspace_texture<PT>(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_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<Session_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<PT>::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<Session_component>
throw Root::Quota_exceeded();
}
/* allocate texture */
Chunky_dataspace_texture<PT> * const cdt =
new (md_alloc()) Chunky_dataspace_texture<PT>(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<Session_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<PT> const &cdt =
static_cast<Chunky_dataspace_texture<PT> 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<Chunky_dataspace_texture<PT> *>(&cdt));
}
public:
@ -602,15 +731,15 @@ class Nitpicker::Root : public Genode::Root_component<Session_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_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<PT> np_root = { session_list, global_keys, ep.rpc_ep(),
Area(mode.width(), mode.height()),
user_state, sliced_heap, screen,
framebuffer, MENUBAR_HEIGHT };
/*

View File

@ -37,7 +37,7 @@ class Mouse_cursor : public Chunky_texture<PT>, public Session, public View
Mouse_cursor(PT const *pixels, Area size, View_stack const &view_stack)
:
Chunky_texture<PT>(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)

View File

@ -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

View File

@ -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;

View File

@ -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();

View File

@ -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);

View File

@ -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,

View File

@ -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");