committed by
Norman Feske
parent
10a42e8c14
commit
bf93d7a9f0
4
src/server/fb_upscale/README
Normal file
4
src/server/fb_upscale/README
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
The 'fb_upscale' server scales a fixed-resolution framebuffer client session
|
||||||
|
to a larger parent framebuffer session. The scaling is linear at a ratio of
|
||||||
|
1:1 across the x and y axis. Clients must supply their native resolution at
|
||||||
|
the time of session creation.
|
||||||
223
src/server/fb_upscale/component.cc
Normal file
223
src/server/fb_upscale/component.cc
Normal file
@@ -0,0 +1,223 @@
|
|||||||
|
/*
|
||||||
|
* \brief Linear framebuffer upscaler
|
||||||
|
* \author Emery Hemingway
|
||||||
|
* \date 2016-07-20
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2016 Genode Labs GmbH
|
||||||
|
*
|
||||||
|
* This file is part of the Genode OS framework, which is distributed
|
||||||
|
* under the terms of the GNU General Public License version 2.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Genode includes */
|
||||||
|
#include <framebuffer_session/connection.h>
|
||||||
|
#include <base/attached_ram_dataspace.h>
|
||||||
|
#include <base/attached_dataspace.h>
|
||||||
|
#include <root/component.h>
|
||||||
|
#include <base/component.h>
|
||||||
|
#include <base/log.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace Fb_scaler {
|
||||||
|
|
||||||
|
using namespace Framebuffer;
|
||||||
|
|
||||||
|
class Session_component;
|
||||||
|
class Root_component;
|
||||||
|
|
||||||
|
typedef
|
||||||
|
Genode::Root_component<Session_component, Genode::Single_client>
|
||||||
|
Root_component_base;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class Fb_scaler::Session_component : public Genode::Rpc_object<Framebuffer::Session>
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
|
||||||
|
Genode::Env &_env;
|
||||||
|
|
||||||
|
Framebuffer::Connection _parent_fb { _env, Framebuffer::Mode() };
|
||||||
|
Framebuffer::Mode _parent_mode = _parent_fb.mode();
|
||||||
|
Framebuffer::Mode _client_mode;
|
||||||
|
|
||||||
|
Genode::Attached_ram_dataspace _client_ds
|
||||||
|
{ _env.ram(), _env.rm(),
|
||||||
|
Genode::size_t(_client_mode.width()*_client_mode.height())*2
|
||||||
|
};
|
||||||
|
|
||||||
|
Genode::Lazy_volatile_object<Genode::Attached_dataspace> _parent_ds;
|
||||||
|
|
||||||
|
Genode::Signal_context_capability _client_sig_cap;
|
||||||
|
|
||||||
|
enum { SHIFT = 16 };
|
||||||
|
|
||||||
|
int _scale_factor;
|
||||||
|
int _scale_ratio;
|
||||||
|
int _x_offset;
|
||||||
|
int _y_offset;
|
||||||
|
|
||||||
|
void _rescale()
|
||||||
|
{
|
||||||
|
/* get a new dataspace */
|
||||||
|
if (_parent_ds.constructed())
|
||||||
|
_parent_ds.destruct();
|
||||||
|
_parent_ds.construct(_env.rm(), _parent_fb.dataspace());
|
||||||
|
Genode::memset(_parent_ds->local_addr<char>(),
|
||||||
|
0x00, _parent_ds->size());
|
||||||
|
|
||||||
|
/* calculate the scaling using the FPU */
|
||||||
|
float x_factor =
|
||||||
|
float(_parent_mode.width()) /
|
||||||
|
float(_client_mode.width());
|
||||||
|
|
||||||
|
float y_factor =
|
||||||
|
float(_parent_mode.height()) /
|
||||||
|
float(_client_mode.height());
|
||||||
|
|
||||||
|
float factor = Genode::min(x_factor, y_factor);
|
||||||
|
|
||||||
|
_x_offset =
|
||||||
|
(_parent_mode.width() -
|
||||||
|
(_client_mode.width()*factor)) / 2;
|
||||||
|
_y_offset =
|
||||||
|
(_parent_mode.height() -
|
||||||
|
(_client_mode.height()*factor)) / 2;
|
||||||
|
|
||||||
|
/* shift so the scaling can be done with integeral math */
|
||||||
|
_scale_factor = (1<<SHIFT)*factor;
|
||||||
|
_scale_ratio = ((1 << SHIFT) / factor)+1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _handle_mode()
|
||||||
|
{
|
||||||
|
_parent_mode = _parent_fb.mode();
|
||||||
|
|
||||||
|
if (_parent_mode.width() && _parent_mode.height()) {
|
||||||
|
_rescale();
|
||||||
|
} else {
|
||||||
|
/* notify the client of the null mode */
|
||||||
|
if (_client_sig_cap.valid())
|
||||||
|
Genode::Signal_transmitter(_client_sig_cap).submit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Genode::Signal_handler<Session_component> _mode_handler
|
||||||
|
{ _env.ep(), *this, &Session_component::_handle_mode };
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
Session_component(Genode::Env &env, Mode client_mode)
|
||||||
|
:
|
||||||
|
_env(env),
|
||||||
|
_client_mode(client_mode.width() && client_mode.height() ?
|
||||||
|
client_mode : _parent_mode)
|
||||||
|
{
|
||||||
|
if (!(_client_mode.width() && _client_mode.height())) {
|
||||||
|
/* use the parent mode maybe enlarge later */
|
||||||
|
_client_mode = _parent_mode;
|
||||||
|
_handle_mode();
|
||||||
|
}
|
||||||
|
|
||||||
|
_rescale();
|
||||||
|
_parent_fb.mode_sigh(_mode_handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/***********************************
|
||||||
|
** Framebuffer session interface **
|
||||||
|
***********************************/
|
||||||
|
|
||||||
|
Genode::Dataspace_capability dataspace() override {
|
||||||
|
return _client_ds.cap(); }
|
||||||
|
|
||||||
|
Mode mode() const override
|
||||||
|
{
|
||||||
|
Mode parent_mode = _parent_fb.mode();
|
||||||
|
return (!parent_mode.width() && !parent_mode.height()) ?
|
||||||
|
parent_mode : _client_mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
void refresh(int cx, int cy, int cw, int ch) override
|
||||||
|
{
|
||||||
|
using Genode::uint16_t;
|
||||||
|
|
||||||
|
/* the shifting is to round down by dropping bits */
|
||||||
|
|
||||||
|
int px = (cx * _scale_factor)>>SHIFT;
|
||||||
|
int py = (cy * _scale_factor)>>SHIFT;
|
||||||
|
int pw = (cw * _scale_factor)>>SHIFT;
|
||||||
|
int ph = (ch * _scale_factor)>>SHIFT;
|
||||||
|
|
||||||
|
uint16_t const *src = _client_ds.local_addr<uint16_t const>();
|
||||||
|
uint16_t *dst = _parent_ds->local_addr<uint16_t>();
|
||||||
|
|
||||||
|
for (int y = py; y < ph; ++y) {
|
||||||
|
int src_y = ((y*_scale_ratio) >> SHIFT)*_client_mode.width();
|
||||||
|
|
||||||
|
for (int x = px; x < pw; ++x) {
|
||||||
|
dst[(_y_offset+y)*_parent_mode.width()+x+_x_offset] =
|
||||||
|
src[src_y+((x*_scale_ratio) >> SHIFT)];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_parent_fb.refresh(_x_offset+px, _y_offset+py,
|
||||||
|
_y_offset+pw, _x_offset+ph);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void mode_sigh(Genode::Signal_context_capability sig_cap) override {
|
||||||
|
_client_sig_cap = sig_cap; }
|
||||||
|
|
||||||
|
/* client gets sync signals from parent session */
|
||||||
|
void sync_sigh(Genode::Signal_context_capability sig_cap) override {
|
||||||
|
_parent_fb.sync_sigh(sig_cap); }
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class Fb_scaler::Root_component : Root_component_base
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
|
||||||
|
Genode::Env &_env;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
Session_component *_create_session(char const *args) override
|
||||||
|
{
|
||||||
|
using namespace Genode;
|
||||||
|
|
||||||
|
unsigned width = Arg_string::find_arg(args, "fb_width").ulong_value(0);
|
||||||
|
unsigned height = Arg_string::find_arg(args, "fb_width").ulong_value(0);
|
||||||
|
|
||||||
|
return new (md_alloc())
|
||||||
|
Session_component(_env, Mode(width, height, Mode::INVALID));
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
Root_component(Genode::Env &env, Genode::Allocator &md_alloc)
|
||||||
|
: Root_component_base(env.ep(), md_alloc),
|
||||||
|
_env(env)
|
||||||
|
{
|
||||||
|
env.parent().announce(env.ep().manage(*this));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/***************
|
||||||
|
** Component **
|
||||||
|
***************/
|
||||||
|
|
||||||
|
Genode::size_t Component::stack_size() { return 4*1024*sizeof(Genode::addr_t); }
|
||||||
|
|
||||||
|
void Component::construct(Genode::Env &env)
|
||||||
|
{
|
||||||
|
static Genode::Sliced_heap sliced_heap(env.ram(), env.rm());
|
||||||
|
|
||||||
|
static Fb_scaler::Root_component root(env, sliced_heap);
|
||||||
|
}
|
||||||
3
src/server/fb_upscale/target.mk
Normal file
3
src/server/fb_upscale/target.mk
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
TARGET = fb_upscale
|
||||||
|
SRC_CC = component.cc
|
||||||
|
LIBS = base
|
||||||
Reference in New Issue
Block a user