mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-23 23:42:32 +00:00
fb_sdl: move SDL event loop to dedicated thread
This patch is a preparatory step for relaxing the strictly periodic operation of fb_sdl. With the new design, the SDL event loop can block for events while Genode's main entrypoint stays receptive for I/O. The main entrypoint can interact with the SDL thread by injecting SDL user events. The patch also replaces the full-screen clearing and update of the SDL window by an update of the captured bounding box only. This reduces the CPU load of fb_sdl when idle. When updating a small part of the screen (e.g., when moving the mouse only), the load is still rather heavy though. Issue #5344
This commit is contained in:
parent
3f1759a4d1
commit
2d3c2fc258
@ -6,7 +6,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2006-2017 Genode Labs GmbH
|
* Copyright (C) 2006-2024 Genode Labs GmbH
|
||||||
*
|
*
|
||||||
* This file is part of the Genode OS framework, which is distributed
|
* This file is part of the Genode OS framework, which is distributed
|
||||||
* under the terms of the GNU Affero General Public License version 3.
|
* under the terms of the GNU Affero General Public License version 3.
|
||||||
@ -31,63 +31,100 @@
|
|||||||
|
|
||||||
namespace Fb_sdl {
|
namespace Fb_sdl {
|
||||||
class Main;
|
class Main;
|
||||||
|
class Sdl;
|
||||||
|
|
||||||
using namespace Genode;
|
using namespace Genode;
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* fatal exceptions */
|
|
||||||
struct Sdl_init_failed : Genode::Exception { };
|
|
||||||
struct Sdl_videodriver_not_supported : Genode::Exception { };
|
|
||||||
struct Sdl_createwindow_failed : Genode::Exception { };
|
|
||||||
struct Sdl_createrenderer_failed : Genode::Exception { };
|
|
||||||
struct Sdl_creatergbsurface_failed : Genode::Exception { };
|
|
||||||
struct Sdl_createtexture_failed : Genode::Exception { };
|
|
||||||
|
|
||||||
|
|
||||||
struct Fb_sdl::Main
|
|
||||||
{
|
|
||||||
Env &_env;
|
|
||||||
|
|
||||||
Attached_rom_dataspace _config { _env, "config" };
|
|
||||||
|
|
||||||
Timer::Connection _timer { _env };
|
|
||||||
Event::Connection _event { _env };
|
|
||||||
|
|
||||||
using Area = Capture::Area;
|
using Area = Capture::Area;
|
||||||
using Point = Capture::Area;
|
using Rect = Capture::Rect;
|
||||||
using Pixel = Capture::Pixel;
|
using Pixel = Capture::Pixel;
|
||||||
using Affected_rects = Capture::Session::Affected_rects;
|
using Affected_rects = Capture::Session::Affected_rects;
|
||||||
using Event_batch = Event::Session_client::Batch;
|
using Event_batch = Event::Session_client::Batch;
|
||||||
|
|
||||||
void _init_sdl()
|
static constexpr int USER_EVENT_CAPTURE_WAKEUP = 99;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interplay with libSDL
|
||||||
|
*/
|
||||||
|
struct Fb_sdl::Sdl : Noncopyable
|
||||||
|
{
|
||||||
|
Event::Connection &_event;
|
||||||
|
Capture::Connection &_capture;
|
||||||
|
Region_map &_rm;
|
||||||
|
|
||||||
|
struct Ticks { Uint32 ms; };
|
||||||
|
|
||||||
|
struct Attr
|
||||||
{
|
{
|
||||||
/*
|
Area initial_size;
|
||||||
* Initialize libSDL window
|
|
||||||
*/
|
double fps; /* frames per second */
|
||||||
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
|
unsigned idle; /* disable capturing after 'idle' frames of no progress */
|
||||||
error("SDL_Init failed (", Genode::Cstring(SDL_GetError()), ")");
|
|
||||||
throw Sdl_init_failed();
|
static Attr from_xml(Xml_node const &node)
|
||||||
|
{
|
||||||
|
return {
|
||||||
|
.initial_size = { .w = node.attribute_value("width", 1024u),
|
||||||
|
.h = node.attribute_value("height", 768u) },
|
||||||
|
.fps = node.attribute_value("fps", 60.0),
|
||||||
|
.idle = node.attribute_value("idle", ~0U)
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_ShowCursor(0);
|
Ticks period() const
|
||||||
|
{
|
||||||
|
return { (fps > 0) ? unsigned(1000.0/fps) : 20u };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Attr const _attr;
|
||||||
|
|
||||||
|
/* fatal exceptions */
|
||||||
|
struct Init_failed : Exception { };
|
||||||
|
struct Createthread_failed : Exception { };
|
||||||
|
struct Videodriver_not_supported : Exception { };
|
||||||
|
struct Createwindow_failed : Exception { };
|
||||||
|
struct Createrenderer_failed : Exception { };
|
||||||
|
struct Creatergbsurface_failed : Exception { };
|
||||||
|
struct Createtexture_failed : Exception { };
|
||||||
|
|
||||||
|
void _thread();
|
||||||
|
|
||||||
|
static int _entry(void *data_ptr)
|
||||||
|
{
|
||||||
|
((Sdl *)data_ptr)->_thread();
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool const _sdl_initialized = ( _init_sdl(), true );
|
SDL_Thread &_init_thread()
|
||||||
|
{
|
||||||
|
SDL_Thread *ptr = SDL_CreateThread(_entry, "SDL", this);
|
||||||
|
if (ptr)
|
||||||
|
return *ptr;
|
||||||
|
|
||||||
struct Sdl_window
|
throw Createthread_failed();
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_Thread &_sdl_thread = _init_thread();
|
||||||
|
|
||||||
|
struct Window
|
||||||
{
|
{
|
||||||
Area const _initial_size;
|
Area const _initial_size;
|
||||||
|
|
||||||
SDL_Renderer &_sdl_renderer = _init_sdl_renderer();
|
SDL_Renderer &renderer = _init_renderer();
|
||||||
|
|
||||||
SDL_Renderer &_init_sdl_renderer()
|
SDL_Renderer &_init_renderer()
|
||||||
{
|
{
|
||||||
unsigned const window_flags = 0;
|
unsigned const window_flags = 0;
|
||||||
|
|
||||||
SDL_Window *window_ptr = SDL_CreateWindow("fb_sdl", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, _initial_size.w, _initial_size.h, window_flags);
|
SDL_Window * const window_ptr =
|
||||||
|
SDL_CreateWindow("fb_sdl", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
|
||||||
|
_initial_size.w, _initial_size.h, window_flags);
|
||||||
if (!window_ptr) {
|
if (!window_ptr) {
|
||||||
error("SDL_CreateWindow failed (", Genode::Cstring(SDL_GetError()), ")");
|
error("SDL_CreateWindow failed (", Cstring(SDL_GetError()), ")");
|
||||||
throw Sdl_createwindow_failed();
|
throw Createwindow_failed();
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_SetWindowResizable(window_ptr, SDL_TRUE);
|
SDL_SetWindowResizable(window_ptr, SDL_TRUE);
|
||||||
@ -96,35 +133,30 @@ struct Fb_sdl::Main
|
|||||||
unsigned const renderer_flags = SDL_RENDERER_SOFTWARE;
|
unsigned const renderer_flags = SDL_RENDERER_SOFTWARE;
|
||||||
SDL_Renderer *renderer_ptr = SDL_CreateRenderer(window_ptr, index, renderer_flags);
|
SDL_Renderer *renderer_ptr = SDL_CreateRenderer(window_ptr, index, renderer_flags);
|
||||||
if (!renderer_ptr) {
|
if (!renderer_ptr) {
|
||||||
error("SDL_CreateRenderer failed (", Genode::Cstring(SDL_GetError()), ")");
|
error("SDL_CreateRenderer failed (", Cstring(SDL_GetError()), ")");
|
||||||
throw Sdl_createrenderer_failed();
|
throw Createrenderer_failed();
|
||||||
}
|
}
|
||||||
|
|
||||||
return *renderer_ptr;
|
return *renderer_ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Sdl_window(Area size) : _initial_size(size) { }
|
Window(Area size) : _initial_size(size) { }
|
||||||
|
|
||||||
~Sdl_window()
|
~Window()
|
||||||
{
|
{
|
||||||
SDL_DestroyRenderer(&_sdl_renderer);
|
SDL_DestroyRenderer(&renderer);
|
||||||
}
|
|
||||||
|
|
||||||
SDL_Renderer &renderer()
|
|
||||||
{
|
|
||||||
return _sdl_renderer;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Sdl_screen
|
struct Screen
|
||||||
{
|
{
|
||||||
Area const size;
|
Area const size;
|
||||||
SDL_Renderer &renderer;
|
SDL_Renderer &renderer;
|
||||||
|
|
||||||
SDL_Surface &_sdl_surface = _init_sdl_surface();
|
SDL_Surface &_surface = _init_surface();
|
||||||
SDL_Texture &_sdl_texture = _init_sdl_texture();
|
SDL_Texture &_texture = _init_texture();
|
||||||
|
|
||||||
SDL_Surface &_init_sdl_surface()
|
SDL_Surface &_init_surface()
|
||||||
{
|
{
|
||||||
unsigned const flags = 0;
|
unsigned const flags = 0;
|
||||||
unsigned const bpp = 32;
|
unsigned const bpp = 32;
|
||||||
@ -133,132 +165,215 @@ struct Fb_sdl::Main
|
|||||||
unsigned const blue_mask = 0x000000FF;
|
unsigned const blue_mask = 0x000000FF;
|
||||||
unsigned const alpha_mask = 0xFF000000;
|
unsigned const alpha_mask = 0xFF000000;
|
||||||
|
|
||||||
SDL_Surface *surface_ptr = SDL_CreateRGBSurface(flags, size.w, size.h, bpp, red_mask, green_mask, blue_mask, alpha_mask);
|
SDL_Surface * const surface_ptr =
|
||||||
|
SDL_CreateRGBSurface(flags, size.w, size.h, bpp,
|
||||||
|
red_mask, green_mask, blue_mask, alpha_mask);
|
||||||
if (!surface_ptr) {
|
if (!surface_ptr) {
|
||||||
error("SDL_CreateRGBSurface failed (", Genode::Cstring(SDL_GetError()), ")");
|
error("SDL_CreateRGBSurface failed (", Cstring(SDL_GetError()), ")");
|
||||||
throw Sdl_creatergbsurface_failed();
|
throw Creatergbsurface_failed();
|
||||||
}
|
}
|
||||||
|
|
||||||
return *surface_ptr;
|
return *surface_ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_Texture &_init_sdl_texture()
|
SDL_Texture &_init_texture()
|
||||||
{
|
{
|
||||||
SDL_Texture *texture_ptr = SDL_CreateTexture(&renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, size.w, size.h);
|
SDL_Texture * const texture_ptr =
|
||||||
|
SDL_CreateTexture(&renderer, SDL_PIXELFORMAT_ARGB8888,
|
||||||
|
SDL_TEXTUREACCESS_STREAMING, size.w, size.h);
|
||||||
if (!texture_ptr) {
|
if (!texture_ptr) {
|
||||||
error("SDL_CreateTexture failed (", Genode::Cstring(SDL_GetError()), ")");
|
error("SDL_CreateTexture failed (", Cstring(SDL_GetError()), ")");
|
||||||
throw Sdl_createtexture_failed();
|
throw Createtexture_failed();
|
||||||
}
|
}
|
||||||
|
|
||||||
return *texture_ptr;
|
return *texture_ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Sdl_screen(Area size, SDL_Renderer &renderer) : size(size), renderer(renderer) { }
|
Screen(Area size, SDL_Renderer &renderer) : size(size), renderer(renderer) { }
|
||||||
|
|
||||||
~Sdl_screen()
|
~Screen()
|
||||||
{
|
{
|
||||||
SDL_FreeSurface(&_sdl_surface);
|
SDL_FreeSurface(&_surface);
|
||||||
SDL_DestroyTexture(&_sdl_texture);
|
SDL_DestroyTexture(&_texture);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename FN>
|
void with_surface(auto const &fn)
|
||||||
void with_surface(FN const &fn)
|
|
||||||
{
|
{
|
||||||
Surface<Pixel> surface { (Pixel *)_sdl_surface.pixels, size };
|
Surface<Pixel> surface { (Pixel *)_surface.pixels, size };
|
||||||
fn(surface);
|
fn(surface);
|
||||||
}
|
}
|
||||||
|
|
||||||
void flush()
|
void flush(Capture::Rect const bounding_box)
|
||||||
{
|
{
|
||||||
SDL_UpdateTexture(&_sdl_texture, nullptr, _sdl_surface.pixels, _sdl_surface.pitch);
|
SDL_Rect const rect { .x = bounding_box.at.x,
|
||||||
SDL_RenderClear(&renderer);
|
.y = bounding_box.at.y,
|
||||||
SDL_RenderCopy(&renderer, &_sdl_texture, nullptr, nullptr);
|
.w = int(bounding_box.area.w),
|
||||||
|
.h = int(bounding_box.area.h) };
|
||||||
|
|
||||||
|
SDL_UpdateTexture(&_texture, nullptr, _surface.pixels, _surface.pitch);
|
||||||
|
SDL_RenderCopy(&renderer, &_texture, &rect, &rect);
|
||||||
SDL_RenderPresent(&renderer);
|
SDL_RenderPresent(&renderer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void flush_all() { flush(Rect { { 0, 0 }, size }); }
|
||||||
};
|
};
|
||||||
|
|
||||||
Constructible<Sdl_window> _sdl_window { };
|
Constructible<Window> _window { };
|
||||||
Constructible<Sdl_screen> _sdl_screen { };
|
Constructible<Screen> _screen { };
|
||||||
|
|
||||||
Capture::Connection _capture { _env };
|
|
||||||
|
|
||||||
Constructible<Capture::Connection::Screen> _captured_screen { };
|
Constructible<Capture::Connection::Screen> _captured_screen { };
|
||||||
|
|
||||||
Signal_handler<Main> _timer_handler {
|
|
||||||
_env.ep(), *this, &Main::_handle_timer };
|
|
||||||
|
|
||||||
int _mx = 0, _my = 0;
|
int _mx = 0, _my = 0;
|
||||||
|
|
||||||
void _handle_sdl_event(Event_batch &, SDL_Event const &);
|
unsigned _capture_woken_up = 0;
|
||||||
void _handle_sdl_events();
|
|
||||||
|
|
||||||
void _update_sdl_screen_from_capture()
|
struct Previous_frame
|
||||||
{
|
{
|
||||||
Affected_rects const affected = _capture.capture_at(Capture::Point(0, 0));
|
Ticks timestamp;
|
||||||
|
Ticks remaining; /* remaining ticks to next frame */
|
||||||
|
unsigned idle; /* capture attempts without progress */
|
||||||
|
|
||||||
_sdl_screen->with_surface([&] (Surface<Pixel> &surface) {
|
Ticks age() const { return { SDL_GetTicks() - timestamp.ms }; }
|
||||||
|
};
|
||||||
|
|
||||||
_captured_screen->with_texture([&] (Texture<Pixel> const &texture) {
|
/* if constructed, the processing of a next frame is scheduled */
|
||||||
|
Constructible<Previous_frame> _previous_frame { };
|
||||||
|
|
||||||
affected.for_each_rect([&] (Capture::Rect const rect) {
|
void _schedule_next_frame()
|
||||||
|
{
|
||||||
|
_previous_frame.construct(
|
||||||
|
Previous_frame { .timestamp = { SDL_GetTicks() },
|
||||||
|
.remaining = { _attr.period() },
|
||||||
|
.idle = { } });
|
||||||
|
}
|
||||||
|
|
||||||
surface.clip(rect);
|
void _handle_event(Event_batch &, SDL_Event const &);
|
||||||
|
|
||||||
Blit_painter::paint(surface, texture, Capture::Point(0, 0));
|
bool _update_screen_from_capture()
|
||||||
});
|
{
|
||||||
});
|
bool progress = false;
|
||||||
|
_screen->with_surface([&] (Surface<Pixel> &surface) {
|
||||||
|
|
||||||
|
Rect const bounding_box = _captured_screen->apply_to_surface(surface);
|
||||||
|
|
||||||
|
progress = (bounding_box.area.count() > 0);
|
||||||
|
|
||||||
|
if (progress)
|
||||||
|
_screen->flush(bounding_box);
|
||||||
});
|
});
|
||||||
|
return progress;
|
||||||
/* flush pixels in SDL window */
|
|
||||||
_sdl_screen->flush();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void _handle_timer()
|
void _resize(Area const size)
|
||||||
{
|
{
|
||||||
_handle_sdl_events();
|
_screen.construct(size, _window->renderer);
|
||||||
|
|
||||||
_update_sdl_screen_from_capture();
|
|
||||||
}
|
|
||||||
|
|
||||||
void _resize(Area size)
|
|
||||||
{
|
|
||||||
_sdl_screen.construct(size, _sdl_window->renderer());
|
|
||||||
|
|
||||||
using Attr = Capture::Connection::Screen::Attr;
|
using Attr = Capture::Connection::Screen::Attr;
|
||||||
_captured_screen.construct(_capture, _env.rm(), Attr {
|
_captured_screen.construct(_capture, _rm, Attr {
|
||||||
.px = size,
|
.px = size,
|
||||||
.mm = { } });
|
.mm = { } });
|
||||||
|
|
||||||
_update_sdl_screen_from_capture();
|
_update_screen_from_capture();
|
||||||
|
_schedule_next_frame();
|
||||||
}
|
}
|
||||||
|
|
||||||
Main(Env &env) : _env(env)
|
/*
|
||||||
{
|
* Construction executed by the main thread
|
||||||
Area size = Area(_config.xml().attribute_value("width", 1024U),
|
*/
|
||||||
_config.xml().attribute_value("height", 768U));
|
Sdl(Event::Connection &event, Capture::Connection &capture, Region_map &rm,
|
||||||
_sdl_window.construct(size);
|
Attr const attr)
|
||||||
_resize(size);
|
:
|
||||||
|
_event(event), _capture(capture), _rm(rm), _attr(attr)
|
||||||
_timer.sigh(_timer_handler);
|
{ }
|
||||||
_timer.trigger_periodic(100000000 / 5994); /* 59.94Hz */
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
void Fb_sdl::Main::_handle_sdl_event(Event_batch &batch, SDL_Event const &event)
|
void Fb_sdl::Sdl::_thread()
|
||||||
|
{
|
||||||
|
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
|
||||||
|
error("SDL_Init failed (", Cstring(SDL_GetError()), ")");
|
||||||
|
throw Init_failed();
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_ShowCursor(0);
|
||||||
|
|
||||||
|
_window.construct(_attr.initial_size);
|
||||||
|
_resize(_attr.initial_size);
|
||||||
|
|
||||||
|
/* mainloop */
|
||||||
|
for (;;) {
|
||||||
|
|
||||||
|
if (_previous_frame.constructed())
|
||||||
|
SDL_WaitEventTimeout(nullptr, _previous_frame->remaining.ms);
|
||||||
|
else
|
||||||
|
SDL_WaitEvent(nullptr);
|
||||||
|
|
||||||
|
unsigned const orig_capture_woken_up = _capture_woken_up;
|
||||||
|
|
||||||
|
_event.with_batch([&] (Event_batch &batch) {
|
||||||
|
SDL_Event event { };
|
||||||
|
while (SDL_PollEvent(&event))
|
||||||
|
_handle_event(batch, event); });
|
||||||
|
|
||||||
|
Ticks const period = _attr.period();
|
||||||
|
|
||||||
|
bool const woken_up = (_capture_woken_up != orig_capture_woken_up);
|
||||||
|
bool const frame_elapsed = _previous_frame.constructed()
|
||||||
|
&& _previous_frame->age().ms >= period.ms;
|
||||||
|
|
||||||
|
if (woken_up || frame_elapsed) {
|
||||||
|
|
||||||
|
bool const progress = _update_screen_from_capture();
|
||||||
|
bool const idle = !progress && !woken_up;
|
||||||
|
|
||||||
|
if (idle) {
|
||||||
|
if (_previous_frame.constructed()) {
|
||||||
|
_previous_frame->idle++;
|
||||||
|
if ((_attr.idle < ~0u) && (_previous_frame->idle > _attr.idle))
|
||||||
|
_previous_frame.destruct(); /* stop capturing */
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
_schedule_next_frame();
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* Events occurred in-between two frames.
|
||||||
|
* Update timeout for next call of 'SDL_WaitEventTimeout'.
|
||||||
|
*/
|
||||||
|
if (_previous_frame.constructed())
|
||||||
|
_previous_frame->remaining = {
|
||||||
|
min(period.ms, period.ms - _previous_frame->age().ms) };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Fb_sdl::Sdl::_handle_event(Event_batch &batch, SDL_Event const &event)
|
||||||
{
|
{
|
||||||
using namespace Input;
|
using namespace Input;
|
||||||
|
|
||||||
if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_RESIZED) {
|
if (event.type == SDL_WINDOWEVENT) {
|
||||||
|
|
||||||
int w = event.window.data1;
|
if (event.window.event == SDL_WINDOWEVENT_RESIZED) {
|
||||||
int h = event.window.data2;
|
|
||||||
if (w < 0 || h < 0) {
|
int const w = event.window.data1,
|
||||||
warning("attempt to resize to negative size");
|
h = event.window.data2;
|
||||||
return;
|
|
||||||
|
if (w <= 0 || h <= 0) {
|
||||||
|
warning("attempt to resize to invalid size");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_resize({ unsigned(w), unsigned(h) });
|
||||||
}
|
}
|
||||||
|
|
||||||
_resize(Area((unsigned)w, (unsigned)h));
|
_screen->flush_all();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.type == SDL_USEREVENT) {
|
||||||
|
if (event.user.code == USER_EVENT_CAPTURE_WAKEUP)
|
||||||
|
_capture_woken_up++;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -299,7 +414,6 @@ void Fb_sdl::Main::_handle_sdl_event(Event_batch &batch, SDL_Event const &event)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* determine event type */
|
|
||||||
switch (event.type) {
|
switch (event.type) {
|
||||||
|
|
||||||
case SDL_KEYUP:
|
case SDL_KEYUP:
|
||||||
@ -328,16 +442,33 @@ void Fb_sdl::Main::_handle_sdl_event(Event_batch &batch, SDL_Event const &event)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Fb_sdl::Main::_handle_sdl_events()
|
struct Fb_sdl::Main
|
||||||
{
|
{
|
||||||
SDL_Event event { };
|
Env &_env;
|
||||||
|
|
||||||
_event.with_batch([&] (Event_batch &batch) {
|
Attached_rom_dataspace _config { _env, "config" };
|
||||||
|
|
||||||
while (SDL_PollEvent(&event))
|
Event::Connection _event { _env };
|
||||||
_handle_sdl_event(batch, event);
|
Capture::Connection _capture { _env };
|
||||||
});
|
|
||||||
}
|
void _handle_capture_wakeup()
|
||||||
|
{
|
||||||
|
SDL_Event ev { };
|
||||||
|
ev.user = SDL_UserEvent { .type = SDL_USEREVENT,
|
||||||
|
.timestamp = SDL_GetTicks(),
|
||||||
|
.windowID = { },
|
||||||
|
.code = USER_EVENT_CAPTURE_WAKEUP,
|
||||||
|
.data1 = { },
|
||||||
|
.data2 = { } };
|
||||||
|
|
||||||
|
if (SDL_PushEvent(&ev) == 0)
|
||||||
|
warning("SDL_PushEvent failed (", Cstring(SDL_GetError()), ")");
|
||||||
|
}
|
||||||
|
|
||||||
|
Sdl _sdl { _event, _capture, _env.rm(), Sdl::Attr::from_xml(_config.xml()) };
|
||||||
|
|
||||||
|
Main(Env &env) : _env(env) { }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
void Component::construct(Genode::Env &env) { static Fb_sdl::Main inst(env); }
|
void Component::construct(Genode::Env &env) { static Fb_sdl::Main inst(env); }
|
||||||
|
Loading…
Reference in New Issue
Block a user