diff --git a/repos/os/include/capture_session/capture_session.h b/repos/os/include/capture_session/capture_session.h new file mode 100644 index 0000000000..6e17db7976 --- /dev/null +++ b/repos/os/include/capture_session/capture_session.h @@ -0,0 +1,134 @@ +/* + * \brief 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__CAPTURE_SESSION_H_ +#define _INCLUDE__CAPTURE_SESSION__CAPTURE_SESSION_H_ + +#include +#include +#include +#include +#include + +namespace Capture { + + using namespace Genode; + + struct Session_client; + struct Session; + + using Rect = Surface_base::Rect; + using Point = Surface_base::Point; + using Area = Surface_base::Area; + using Pixel = Pixel_rgb888; + +} + + +struct Capture::Session : Genode::Session +{ + /** + * \noapi + */ + static const char *service_name() { return "Capture"; } + + /* + * A capture session consumes a dataspace capability for the server's + * session-object allocation, a session capability, and a dataspace + * capability for the pixel buffer. + */ + enum { CAP_QUOTA = 3 }; + + /** + * Return number of bytes needed for pixel buffer of specified size + */ + static size_t buffer_bytes(Area size) + { + size_t const bytes_per_pixel = 4; + return bytes_per_pixel*size.count(); + } + + /** + * Request current screen size + */ + virtual Area screen_size() const = 0; + + /** + * Register signal handler to be notified whenever the screen size changes + */ + virtual void screen_size_sigh(Signal_context_capability) = 0; + + /** + * 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 + */ + virtual void buffer(Area size) = 0; + + /** + * Request dataspace of the shared pixel buffer defined via 'buffer' + */ + virtual Dataspace_capability dataspace() = 0; + + /** + * Result type of 'capture_at' + * + * The geometry information are relative to the viewport specified for the + * 'capture_at' call. + */ + struct Affected_rects + { + enum { NUM_RECTS = 3U }; + + Rect rects[NUM_RECTS]; + + template + void for_each_rect(FN const &fn) const + { + for (unsigned i = 0; i < NUM_RECTS; i++) + if (rects[i].valid()) + fn(rects[i]); + } + }; + + /** + * Update the pixel-buffer with content at the specified screen position + * + * \return geometry information about the content that changed since the + * previous call of 'capture_at' + */ + virtual Affected_rects capture_at(Point) = 0; + + + /********************* + ** RPC declaration ** + *********************/ + + 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_dataspace, Dataspace_capability, dataspace); + GENODE_RPC(Rpc_capture_at, Affected_rects, capture_at, Point); + + GENODE_RPC_INTERFACE(Rpc_screen_size, Rpc_screen_size_sigh, Rpc_buffer, + Rpc_dataspace, Rpc_capture_at); +}; + +#endif /* _INCLUDE__CAPTURE_SESSION__CAPTURE_SESSION_H_ */ diff --git a/repos/os/include/capture_session/client.h b/repos/os/include/capture_session/client.h new file mode 100644 index 0000000000..bf032d8d9f --- /dev/null +++ b/repos/os/include/capture_session/client.h @@ -0,0 +1,47 @@ +/* + * \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 +#include + +namespace Capture { struct Session_client; } + + +struct Capture::Session_client : public Genode::Rpc_client +{ + /** + * Constructor + */ + Session_client(Capability session) : Rpc_client(session) { } + + Area screen_size() const override { return call(); } + + void screen_size_sigh(Signal_context_capability sigh) override + { + call(sigh); + } + + void buffer(Area size) override { call(size); } + + Dataspace_capability dataspace() override { return call(); } + + Affected_rects capture_at(Point pos) override + { + return call(pos); + } +}; + +#endif /* _INCLUDE__CAPTURE_SESSION__CLIENT_H_ */ diff --git a/repos/os/include/capture_session/connection.h b/repos/os/include/capture_session/connection.h new file mode 100644 index 0000000000..5123702cdb --- /dev/null +++ b/repos/os/include/capture_session/connection.h @@ -0,0 +1,114 @@ +/* + * \brief Connection to capture service + * \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__CONNECTION_H_ +#define _INCLUDE__CAPTURE_SESSION__CONNECTION_H_ + +#include +#include +#include +#include +#include + +namespace Capture { class Connection; } + + +class Capture::Connection : public Genode::Connection, + public Session_client +{ + public: + + enum { RAM_QUOTA = 36*1024UL }; + + private: + + size_t _session_quota = 0; + + public: + + /** + * Constructor + */ + Connection(Genode::Env &env, char const *label = "") + : + Genode::Connection( + env, session(env.parent(), + "ram_quota=%u, cap_quota=%u, label=\"%s\"", + RAM_QUOTA, CAP_QUOTA, label)), + Session_client(cap()) + { } + + void buffer(Area size) override + { + size_t const needed = buffer_bytes(size); + size_t const upgrade = needed > _session_quota + ? needed - _session_quota + : 0; + if (upgrade > 0) { + this->upgrade_ram(upgrade); + _session_quota += upgrade; + } + + Session_client::buffer(size); + } + + struct Screen; +}; + + +class Capture::Connection::Screen +{ + public: + + Area const size; + + private: + + Capture::Connection &_connection; + + bool const _buffer_initialized = ( _connection.buffer(size), true ); + + Attached_dataspace _ds; + + Texture const _texture { _ds.local_addr(), nullptr, size }; + + public: + + Screen(Capture::Connection &connection, Region_map &rm, Area size) + : + size(size), _connection(connection), _ds(rm, _connection.dataspace()) + { } + + template + void with_texture(FN const &fn) const + { + fn(_texture); + } + + void apply_to_surface(Surface &surface) + { + Affected_rects const affected = _connection.capture_at(Capture::Point(0, 0)); + + with_texture([&] (Texture const &texture) { + + affected.for_each_rect([&] (Capture::Rect const rect) { + + surface.clip(rect); + + Blit_painter::paint(surface, texture, Capture::Point(0, 0)); + }); + }); + } +}; + +#endif /* _INCLUDE__CAPTURE_SESSION__CONNECTION_H_ */ diff --git a/repos/os/recipes/api/capture_session/content.mk b/repos/os/recipes/api/capture_session/content.mk new file mode 100644 index 0000000000..8852654dfa --- /dev/null +++ b/repos/os/recipes/api/capture_session/content.mk @@ -0,0 +1,2 @@ +MIRRORED_FROM_REP_DIR := include/capture_session +include $(REP_DIR)/recipes/api/session.inc diff --git a/repos/os/recipes/api/capture_session/hash b/repos/os/recipes/api/capture_session/hash new file mode 100644 index 0000000000..39062a819a --- /dev/null +++ b/repos/os/recipes/api/capture_session/hash @@ -0,0 +1 @@ +2020-07-01 0d69d596b5fa9020478a318eb6751f5f25aebedb