capture_session: propagate physical size in mm

This patch adds the physical screen size as argument to the
Capture::Session::buffer RPC function, which allows drivers to
propagate DPI information to the GUI server. While changing the
the interface, the patch replaces the former use of C++ exceptions
by a result type. The 'Buffer_result' is handled transparently by the
Capture::Connection. The client.h code is now integrated in
connection.h.

Issue #5344
This commit is contained in:
Norman Feske 2024-09-16 14:28:05 +02:00 committed by Christian Helmuth
parent 6d79a44c46
commit 6d68d3297d
17 changed files with 124 additions and 103 deletions

View File

@ -150,7 +150,11 @@ void Vesa_driver::Main::_handle_config()
/* enable pixel capturing */
_fb_ds.construct(_env.rm(), Framebuffer::hw_framebuffer());
_captured_screen.construct(_capture, _env.rm(), _size);
using Attr = Capture::Connection::Screen::Attr;
_captured_screen.construct(_capture, _env.rm(), Attr {
.px = _size,
.mm = { } });
unsigned long const period_ms = config.attribute_value("period_ms", 20U);
_timer.trigger_periodic(period_ms*1000);

View File

@ -130,7 +130,7 @@ struct Capture_webcam
/* construct/destruct capture connection and dataspace */
if (on) {
_capture.construct(_env, "webcam");
_capture->buffer(_area);
_capture->buffer({ .px = _area, .mm = { } });
_ds.construct(_env.rm(), _capture->dataspace());
} else {
_ds.destruct();

View File

@ -68,18 +68,21 @@ struct Capture::Session : Genode::Session
*/
virtual void screen_size_sigh(Signal_context_capability) = 0;
enum class Buffer_result { OK, OUT_OF_RAM, OUT_OF_CAPS };
struct Buffer_attr
{
Area px; /* buffer area in pixels */
Area mm; /* physical size in millimeters */
};
/**
* Define dimensions of the shared pixel buffer
*
* The 'size' controls the server-side allocation of the shared pixel
* buffer and may affect the screen size of the GUI server. The screen
* size is bounding box of the pixel buffers of all capture clients.
*
* \throw Out_of_ram session quota does not suffice for specified
* buffer dimensions
* \throw Out_of_caps
* buffer and may affect the screen size of the GUI server.
*/
virtual void buffer(Area size) = 0;
virtual Buffer_result buffer(Buffer_attr) = 0;
/**
* Request dataspace of the shared pixel buffer defined via 'buffer'
@ -121,8 +124,7 @@ struct Capture::Session : Genode::Session
GENODE_RPC(Rpc_screen_size, Area, screen_size);
GENODE_RPC(Rpc_screen_size_sigh, void, screen_size_sigh, Signal_context_capability);
GENODE_RPC_THROW(Rpc_buffer, void, buffer,
GENODE_TYPE_LIST(Out_of_ram, Out_of_caps), Area);
GENODE_RPC(Rpc_buffer, Buffer_result, buffer, Buffer_attr);
GENODE_RPC(Rpc_dataspace, Dataspace_capability, dataspace);
GENODE_RPC(Rpc_capture_at, Affected_rects, capture_at, Point);

View File

@ -1,47 +0,0 @@
/*
* \brief Client-side capture session interface
* \author Norman Feske
* \date 2020-06-26
*/
/*
* Copyright (C) 2020 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.
*/
#ifndef _INCLUDE__CAPTURE_SESSION__CLIENT_H_
#define _INCLUDE__CAPTURE_SESSION__CLIENT_H_
#include <capture_session/capture_session.h>
#include <base/rpc_client.h>
namespace Capture { struct Session_client; }
struct Capture::Session_client : public Genode::Rpc_client<Session>
{
/**
* Constructor
*/
Session_client(Capability<Session> session) : Rpc_client<Session>(session) { }
Area screen_size() const override { return call<Rpc_screen_size>(); }
void screen_size_sigh(Signal_context_capability sigh) override
{
call<Rpc_screen_size_sigh>(sigh);
}
void buffer(Area size) override { call<Rpc_buffer>(size); }
Dataspace_capability dataspace() override { return call<Rpc_dataspace>(); }
Affected_rects capture_at(Point pos) override
{
return call<Rpc_capture_at>(pos);
}
};
#endif /* _INCLUDE__CAPTURE_SESSION__CLIENT_H_ */

View File

@ -14,7 +14,7 @@
#ifndef _INCLUDE__CAPTURE_SESSION__CONNECTION_H_
#define _INCLUDE__CAPTURE_SESSION__CONNECTION_H_
#include <capture_session/client.h>
#include <capture_session/capture_session.h>
#include <base/connection.h>
#include <base/attached_dataspace.h>
#include <os/texture.h>
@ -23,8 +23,7 @@
namespace Capture { class Connection; }
class Capture::Connection : public Genode::Connection<Session>,
public Session_client
class Capture::Connection : private Genode::Connection<Session>
{
private:
@ -32,19 +31,20 @@ class Capture::Connection : public Genode::Connection<Session>,
public:
using Label = Genode::Session_label;
/**
* Constructor
*/
Connection(Genode::Env &env, Label const &label = Label())
:
Genode::Connection<Capture::Session>(env, label,
Ram_quota { 36*1024 }, Args()),
Session_client(cap())
Ram_quota { 36*1024 }, Args())
{ }
void buffer(Area size) override
void buffer(Session::Buffer_attr attr)
{
size_t const needed = buffer_bytes(size);
size_t const needed = Session::buffer_bytes(attr.px);
size_t const upgrade = needed > _session_quota
? needed - _session_quota
: 0;
@ -53,10 +53,35 @@ class Capture::Connection : public Genode::Connection<Session>,
_session_quota += upgrade;
}
Session_client::buffer(size);
for (;;) {
using Result = Session::Buffer_result;
switch (cap().call<Session::Rpc_buffer>(attr)) {
case Result::OUT_OF_RAM: upgrade_ram(8*1024); break;
case Result::OUT_OF_CAPS: upgrade_caps(2); break;
case Result::OK:
return;
}
}
}
struct Screen;
Area screen_size() const { return cap().call<Session::Rpc_screen_size>(); }
void screen_size_sigh(Signal_context_capability sigh)
{
cap().call<Session::Rpc_screen_size_sigh>(sigh);
}
Genode::Dataspace_capability dataspace()
{
return cap().call<Session::Rpc_dataspace>();
}
Session::Affected_rects capture_at(Point pos)
{
return cap().call<Session::Rpc_capture_at>(pos);
}
};
@ -64,29 +89,38 @@ class Capture::Connection::Screen
{
public:
Area const size;
struct Attr
{
Area px; /* buffer area in pixels */
Area mm; /* physical size in millimeters */
};
Attr const attr;
private:
Capture::Connection &_connection;
bool const _buffer_initialized = ( _connection.buffer(size), true );
bool const _buffer_initialized = (
_connection.buffer({ .px = attr.px, .mm = attr.mm }), true );
Attached_dataspace _ds;
Texture<Pixel> const _texture { _ds.local_addr<Pixel>(), nullptr, size };
Texture<Pixel> const _texture { _ds.local_addr<Pixel>(), nullptr, attr.px };
public:
Screen(Capture::Connection &connection, Region_map &rm, Area size)
Screen(Capture::Connection &connection, Region_map &rm, Attr attr)
:
size(size), _connection(connection), _ds(rm, _connection.dataspace())
attr(attr), _connection(connection), _ds(rm, _connection.dataspace())
{ }
void with_texture(auto const &fn) const { fn(_texture); }
void apply_to_surface(Surface<Pixel> &surface)
{
using Affected_rects = Session::Affected_rects;
Affected_rects const affected = _connection.capture_at(Capture::Point(0, 0));
with_texture([&] (Texture<Pixel> const &texture) {

View File

@ -87,8 +87,9 @@ struct Framebuffer::Main
Capture::Connection _capture { _env };
Capture::Connection::Screen _captured_screen { _capture, _env.rm(), _info.size };
Capture::Connection::Screen _captured_screen { _capture, _env.rm(), {
.px = _info.size,
.mm = { } } };
Timer::Connection _timer { _env };
Signal_handler<Main> _timer_handler { _env.ep(), *this, &Main::_handle_timer };

View File

@ -59,7 +59,9 @@ struct Pl11x_driver::Main
Capture::Connection _capture { _env };
Capture::Connection::Screen _captured_screen { _capture, _env.rm(), _size };
Capture::Connection::Screen _captured_screen { _capture, _env.rm(), {
.px = _size,
.mm = { } } };
/*

View File

@ -65,8 +65,9 @@ class Main
Capture::Area const _size { SCR_WIDTH, SCR_HEIGHT };
Capture::Connection _capture { _env };
Capture::Connection::Screen _captured_screen { _capture, _env.rm(), _size };
Capture::Connection::Screen _captured_screen { _capture, _env.rm(), {
.px = _size,
.mm = { } } };
Timer::Connection _timer { _env };
Signal_handler<Main> _timer_handler { _env.ep(), *this, &Main::_handle_timer };

View File

@ -223,7 +223,12 @@ struct Fb_sdl::Main
void _resize(Area size)
{
_sdl_screen.construct(size, _sdl_window->renderer());
_captured_screen.construct(_capture, _env.rm(), size);
using Attr = Capture::Connection::Screen::Attr;
_captured_screen.construct(_capture, _env.rm(), Attr {
.px = size,
.mm = { } });
_update_sdl_screen_from_capture();
}

View File

@ -355,7 +355,10 @@ class Virtio_fb::Driver
throw Display_init_failed();
}
_captured_screen.construct(_capture, _env.rm(), _display_area);
using Attr = Capture::Connection::Screen::Attr;
_captured_screen.construct(_capture, _env.rm(), Attr {
.px = _display_area,
.mm = { } });
}
void _shutdown_display()

View File

@ -121,7 +121,7 @@ class Vfs_capture::Data_file_system : public Single_file_system
} catch (Genode::Service_denied) {
return OPEN_ERR_UNACCESSIBLE;
}
_capture->buffer(_capture_area);
_capture->buffer({ .px = _capture_area, .mm = { } });
_capture_ds.construct(_env.rm(), _capture->dataspace());
}

View File

@ -67,14 +67,19 @@ class Capture::Session_component : public Session_object<Capture::Session>
void screen_size_sigh(Signal_context_capability) override { }
void buffer(Area size) override
Buffer_result buffer(Buffer_attr attr) override
{
if (size.count() == 0) {
if (attr.px.count() == 0) {
_buffer.destruct();
return;
return Buffer_result::OK;
}
_buffer.construct(_ram, _env.rm(), buffer_bytes(size));
try {
_buffer.construct(_ram, _env.rm(), buffer_bytes(attr.px));
}
catch (Out_of_ram) { return Buffer_result::OUT_OF_RAM; }
catch (Out_of_caps) { return Buffer_result::OUT_OF_CAPS; }
return Buffer_result::OK;
}
Dataspace_capability dataspace() override

View File

@ -44,7 +44,7 @@ class Nitpicker::Capture_session : public Session_object<Capture::Session>
View_stack const &_view_stack;
Area _buffer_size { };
Buffer_attr _buffer_attr { };
Constructible<Attached_ram_dataspace> _buffer { };
@ -79,7 +79,7 @@ class Nitpicker::Capture_session : public Session_object<Capture::Session>
** Interface used by 'Nitpicker::Main' **
*****************************************/
Area buffer_size() const { return _buffer_size; }
Area buffer_size() const { return _buffer_attr.px; }
void mark_as_damaged(Rect rect)
{
@ -104,23 +104,26 @@ class Nitpicker::Capture_session : public Session_object<Capture::Session>
_screen_size_sigh = sigh;
}
void buffer(Area size) override
Buffer_result buffer(Buffer_attr const attr) override
{
_buffer_size = Area { };
Buffer_result result = Buffer_result::OK;
if (size.count() == 0) {
_buffer_attr = { };
if (attr.px.count() == 0) {
_buffer.destruct();
return;
return result;
}
try {
_buffer.construct(_ram, _env.rm(), buffer_bytes(size));
_buffer_size = size;
_handler.capture_buffer_size_changed();
} catch (...) {
_handler.capture_buffer_size_changed();
throw;
_buffer.construct(_ram, _env.rm(), buffer_bytes(attr.px));
_buffer_attr = attr;
}
catch (Out_of_ram) { result = Buffer_result::OUT_OF_RAM; }
catch (Out_of_caps) { result = Buffer_result::OUT_OF_CAPS; }
_handler.capture_buffer_size_changed();
return result;
}
Dataspace_capability dataspace() override
@ -138,9 +141,9 @@ class Nitpicker::Capture_session : public Session_object<Capture::Session>
using Pixel = Pixel_rgb888;
Canvas<Pixel> canvas = { _buffer->local_addr<Pixel>(), pos, _buffer_size };
Canvas<Pixel> canvas = { _buffer->local_addr<Pixel>(), pos, _buffer_attr.px };
Rect const buffer_rect(Point(0, 0), _buffer_size);
Rect const buffer_rect(Point(0, 0), _buffer_attr.px);
Affected_rects affected { };
unsigned i = 0;

View File

@ -261,7 +261,9 @@ class Black_hole_test::Capture_test
Capture::Area _screen_size { 1, 1 };
Capture::Pixel _pixels[1];
Surface<Capture::Pixel> _surface { _pixels, _screen_size };
Capture::Connection::Screen _screen { _connection, _env.rm(), _screen_size };
Capture::Connection::Screen _screen { _connection, _env.rm(),
{ .px = _screen_size,
.mm = { } } };
bool _finished { false };
public:

View File

@ -113,7 +113,7 @@ struct Test::Main
Capture::Connection _capture { _env, "" };
bool _capture_buffer_init = ( _capture.buffer(_area), true );
bool _capture_buffer_init = ( _capture.buffer({ .px = _area, .mm = { }}), true );
Attached_dataspace _capture_ds { _env.rm(), _capture.dataspace() };

View File

@ -72,11 +72,17 @@ struct Test::Capture_session : Rpc_object<Capture::Session>
void screen_size_sigh(Signal_context_capability) override { }
void buffer(Area size) override
Buffer_result buffer(Buffer_attr attr) override
{
_ds.construct(_env.ram(), _env.rm(), buffer_bytes(size));
_size = size;
try {
_ds.construct(_env.ram(), _env.rm(), buffer_bytes(attr.px));
}
catch (Out_of_ram) { return Buffer_result::OUT_OF_RAM; }
catch (Out_of_caps) { return Buffer_result::OUT_OF_CAPS; }
_size = attr.px;
_draw();
return Buffer_result::OK;
}
Dataspace_capability dataspace() override

View File

@ -110,7 +110,7 @@ struct Framebuffer::Driver
_capture(env),
_size(size),
_size_phys(size_phys),
_captured_screen(_capture, env.rm(), _size),
_captured_screen(_capture, env.rm(), { .px = _size, .mm = { } }),
_base(base) {}
bool same_setup(void * base, Capture::Area &size,