genode/repos/libports/src/drivers/framebuffer/vesa/main.cc
Norman Feske 4d442bca30 Streamline exception types
This patch reduces the number of exception types by facilitating
globally defined exceptions for common usage patterns shared by most
services. In particular, RPC functions that demand a session-resource
upgrade not longer reflect this condition via a session-specific
exception but via the 'Out_of_ram' or 'Out_of_caps' types.

Furthermore, the 'Parent::Service_denied', 'Parent::Unavailable',
'Root::Invalid_args', 'Root::Unavailable', 'Service::Invalid_args',
'Service::Unavailable', and 'Local_service::Factory::Denied' types have
been replaced by the single 'Service_denied' exception type defined in
'session/session.h'.

This consolidation eases the error handling (there are fewer exceptions
to handle), alleviates the need to convert exceptions along the
session-creation call chain, and avoids possible aliasing problems
(catching the wrong type with the same name but living in a different
scope).
2017-05-31 13:16:07 +02:00

253 lines
6.3 KiB
C++

/*
* \brief Framebuffer driver front end
* \author Norman Feske
* \author Christian Helmuth
* \author Sebastian Sumpf
* \date 2007-09-11
*/
/*
* Copyright (C) 2007-2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
/* Genode includes */
#include <base/component.h>
#include <base/heap.h>
#include <base/attached_rom_dataspace.h>
#include <base/attached_ram_dataspace.h>
#include <root/component.h>
#include <util/reconstructible.h>
#include <util/arg_string.h>
#include <blit/blit.h>
#include <timer_session/connection.h>
#include <framebuffer_session/framebuffer_session.h>
/* local includes */
#include "framebuffer.h"
namespace Framebuffer {
struct Session_component;
struct Root;
struct Main;
using Genode::size_t;
using Genode::min;
using Genode::max;
using Genode::Dataspace_capability;
using Genode::Attached_rom_dataspace;
using Genode::Attached_ram_dataspace;
}
class Framebuffer::Session_component : public Genode::Rpc_object<Session>
{
private:
Genode::Env &_env;
unsigned const _scr_width, _scr_height, _scr_depth;
Timer::Connection _timer { _env };
/* dataspace of physical frame buffer */
Dataspace_capability _fb_cap;
void *_fb_addr;
/* dataspace uses a back buffer (if '_buffered' is true) */
Genode::Constructible<Attached_ram_dataspace> _bb;
void _refresh_buffered(int x, int y, int w, int h)
{
/* clip specified coordinates against screen boundaries */
int x2 = min(x + w - 1, (int)_scr_width - 1),
y2 = min(y + h - 1, (int)_scr_height - 1);
int x1 = max(x, 0),
y1 = max(y, 0);
if (x1 > x2 || y1 > y2) return;
/* determine bytes per pixel */
int bypp = 0;
if (_scr_depth == 16) bypp = 2;
if (!bypp) return;
/* copy pixels from back buffer to physical frame buffer */
char *src = _bb->local_addr<char>() + bypp*(_scr_width*y1 + x1),
*dst = (char *)_fb_addr + bypp*(_scr_width*y1 + x1);
blit(src, bypp*_scr_width, dst, bypp*_scr_width,
bypp*(x2 - x1 + 1), y2 - y1 + 1);
}
bool _buffered() const { return _bb.constructed(); }
public:
/**
* Constructor
*/
Session_component(Genode::Env &env,
unsigned scr_width, unsigned scr_height, unsigned scr_depth,
Dataspace_capability fb_cap, bool buffered)
:
_env(env),
_scr_width(scr_width), _scr_height(scr_height), _scr_depth(scr_depth),
_fb_cap(fb_cap)
{
if (!buffered) return;
if (_scr_depth != 16) {
Genode::warning("buffered mode not supported for depth ", _scr_depth);
return;
}
size_t const bb_size = _scr_width*_scr_height*_scr_depth/8;
try { _bb.construct(env.ram(), env.rm(), bb_size); }
catch (...) {
Genode::warning("could not allocate back buffer, disabled buffered output");
return;
}
_fb_addr = env.rm().attach(_fb_cap);
Genode::log("using buffered output");
}
/**
* Destructor
*/
~Session_component()
{
if (_buffered()) {
_bb.destruct();
_env.rm().detach(_fb_addr);
}
}
/***********************************
** Framebuffer session interface **
***********************************/
Dataspace_capability dataspace() override
{
return _buffered() ? Dataspace_capability(_bb->cap())
: Dataspace_capability(_fb_cap);
}
Mode mode() const override
{
return Mode(_scr_width, _scr_height,
_scr_depth == 16 ? Mode::RGB565 : Mode::INVALID);
}
void mode_sigh(Genode::Signal_context_capability) override { }
void sync_sigh(Genode::Signal_context_capability sigh) override
{
_timer.sigh(sigh);
_timer.trigger_periodic(10*1000);
}
void refresh(int x, int y, int w, int h) override
{
if (_buffered())
_refresh_buffered(x, y, w, h);
}
};
/**
* Shortcut for single-client root component
*/
typedef Genode::Root_component<Framebuffer::Session_component,
Genode::Single_client> Root_component;
class Framebuffer::Root : public Root_component
{
private:
Genode::Env &_env;
Attached_rom_dataspace const &_config;
unsigned _session_arg(char const *attr_name, char const *args,
char const *arg_name, unsigned default_value)
{
/* try to obtain value from config file */
unsigned result = _config.xml().attribute_value(attr_name,
default_value);
/* check session argument to override value from config file */
return Genode::Arg_string::find_arg(args, arg_name).ulong_value(result);
}
protected:
Session_component *_create_session(char const *args) override
{
unsigned scr_width = _session_arg("width", args, "fb_width", 0);
unsigned scr_height = _session_arg("height", args, "fb_height", 0);
unsigned const scr_depth = _session_arg("depth", args, "fb_mode", 16);
bool const buffered = _config.xml().attribute_value("buffered", false);
if (Framebuffer::set_mode(scr_width, scr_height, scr_depth) != 0) {
Genode::warning("Could not set vesa mode ",
scr_width, "x", scr_height, "@", scr_depth);
throw Genode::Service_denied();
}
Genode::log("using video mode: ",
scr_width, "x", scr_height, "@", scr_depth);
return new (md_alloc()) Session_component(_env,
scr_width, scr_height, scr_depth,
Framebuffer::hw_framebuffer(),
buffered);
}
public:
Root(Genode::Env &env, Genode::Allocator &alloc,
Attached_rom_dataspace const &config)
:
Root_component(&env.ep().rpc_ep(), &alloc),
_env(env), _config(config)
{ }
};
struct Framebuffer::Main
{
Genode::Env &env;
Genode::Heap heap { env.ram(), env.rm() };
Attached_rom_dataspace config { env, "config" };
Root root { env, heap, config };
Main(Genode::Env &env) : env(env)
{
try { Framebuffer::init(env, heap); } catch (...) {
Genode::error("H/W driver init failed");
throw;
}
env.parent().announce(env.ep().manage(root));
}
};
void Component::construct(Genode::Env &env)
{
/* XXX execute constructors of global statics */
env.exec_static_constructors();
static Framebuffer::Main inst(env);
}