From a801976727bc0d456cf049c5cda73bbf7403ae85 Mon Sep 17 00:00:00 2001 From: Christian Prochaska Date: Thu, 4 Jun 2015 13:47:42 +0200 Subject: [PATCH] vbox: dynamic adaptation to screen-size changes Fixes #1554 --- .../ports/src/virtualbox/frontend/console.cc | 79 ++++++++---- repos/ports/src/virtualbox/frontend/console.h | 34 +++-- repos/ports/src/virtualbox/frontend/fb.h | 117 ++++++++++++------ repos/ports/src/virtualbox/frontend/main.cc | 5 +- 4 files changed, 160 insertions(+), 75 deletions(-) diff --git a/repos/ports/src/virtualbox/frontend/console.cc b/repos/ports/src/virtualbox/frontend/console.cc index 4b7746330..81c42bc64 100644 --- a/repos/ports/src/virtualbox/frontend/console.cc +++ b/repos/ports/src/virtualbox/frontend/console.cc @@ -133,21 +133,21 @@ void GenodeConsole::update_video_mode() d->SetVideoModeHint(0 /*=display*/, true /*=enabled*/, false /*=changeOrigin*/, 0 /*=originX*/, 0 /*=originY*/, - fb->w(), fb->h(), fb->depth()); + fb->w(), fb->h(), + /* Windows 8 only accepts 32-bpp modes */ + 32); } -void GenodeConsole::eventWait(IKeyboard * gKeyboard, IMouse * gMouse) +void GenodeConsole::handle_input(unsigned) { static LONG64 mt_events [64]; unsigned mt_number = 0; - _receiver.wait_for_signal(); - /* read out input capabilities of guest */ bool guest_abs = false, guest_rel = false, guest_multi = false; - gMouse->COMGETTER(AbsoluteSupported)(&guest_abs); - gMouse->COMGETTER(RelativeSupported)(&guest_rel); - gMouse->COMGETTER(MultiTouchSupported)(&guest_multi); + _vbox_mouse->COMGETTER(AbsoluteSupported)(&guest_abs); + _vbox_mouse->COMGETTER(RelativeSupported)(&guest_rel); + _vbox_mouse->COMGETTER(MultiTouchSupported)(&guest_multi); for (int i = 0, num_ev = _input.flush(); i < num_ev; ++i) { Input::Event &ev = _ev_buf[i]; @@ -166,11 +166,11 @@ void GenodeConsole::eventWait(IKeyboard * gKeyboard, IMouse * gMouse) (ev.type() == Input::Event::RELEASE) ? 0x80 : 0; if (scan_code.is_normal()) - gKeyboard->PutScancode(scan_code.code() | release_bit); + _vbox_keyboard->PutScancode(scan_code.code() | release_bit); if (scan_code.is_ext()) { - gKeyboard->PutScancode(0xe0); - gKeyboard->PutScancode(scan_code.ext() | release_bit); + _vbox_keyboard->PutScancode(0xe0); + _vbox_keyboard->PutScancode(scan_code.ext() | release_bit); } } @@ -204,10 +204,10 @@ void GenodeConsole::eventWait(IKeyboard * gKeyboard, IMouse * gMouse) int ry = ev.ay() - _ay; rx = Genode::min(boundary, Genode::max(-boundary, rx)); ry = Genode::min(boundary, Genode::max(-boundary, ry)); - gMouse->PutMouseEvent(rx, ry, 0, 0, buttons); + _vbox_mouse->PutMouseEvent(rx, ry, 0, 0, buttons); } else - gMouse->PutMouseEventAbsolute(ev.ax(), ev.ay(), 0, - 0, buttons); + _vbox_mouse->PutMouseEventAbsolute(ev.ax(), ev.ay(), 0, + 0, buttons); _ax = ev.ax(); _ay = ev.ay(); @@ -218,11 +218,11 @@ void GenodeConsole::eventWait(IKeyboard * gKeyboard, IMouse * gMouse) /* prefer relative motion event */ if (guest_rel) - gMouse->PutMouseEvent(ev.rx(), ev.ry(), 0, 0, buttons); + _vbox_mouse->PutMouseEvent(ev.rx(), ev.ry(), 0, 0, buttons); else if (guest_abs) { _ax += ev.rx(); _ay += ev.ry(); - gMouse->PutMouseEventAbsolute(_ax, _ay, 0, 0, buttons); + _vbox_mouse->PutMouseEventAbsolute(_ax, _ay, 0, 0, buttons); } } /* only the buttons changed */ @@ -231,28 +231,28 @@ void GenodeConsole::eventWait(IKeyboard * gKeyboard, IMouse * gMouse) if (_last_received_motion_event_was_absolute) { /* prefer absolute button event */ if (guest_abs) - gMouse->PutMouseEventAbsolute(_ax, _ay, 0, 0, buttons); + _vbox_mouse->PutMouseEventAbsolute(_ax, _ay, 0, 0, buttons); else if (guest_rel) - gMouse->PutMouseEvent(0, 0, 0, 0, buttons); + _vbox_mouse->PutMouseEvent(0, 0, 0, 0, buttons); } else { /* prefer relative button event */ if (guest_rel) - gMouse->PutMouseEvent(0, 0, 0, 0, buttons); + _vbox_mouse->PutMouseEvent(0, 0, 0, 0, buttons); else if (guest_abs) - gMouse->PutMouseEventAbsolute(_ax, _ay, 0, 0, buttons); + _vbox_mouse->PutMouseEventAbsolute(_ax, _ay, 0, 0, buttons); } } } if (is_wheel) - gMouse->PutMouseEvent(0, 0, ev.rx(), ev.ry(), 0); + _vbox_mouse->PutMouseEvent(0, 0, ev.rx(), ev.ry(), 0); if (is_touch) { /* if multitouch queue is full - send it */ if (mt_number >= sizeof(mt_events) / sizeof(mt_events[0])) { - gMouse->PutEventMultiTouch(mt_number, mt_number, - mt_events, RTTimeMilliTS()); + _vbox_mouse->PutEventMultiTouch(mt_number, mt_number, + mt_events, RTTimeMilliTS()); mt_number = 0; } @@ -282,8 +282,39 @@ void GenodeConsole::eventWait(IKeyboard * gKeyboard, IMouse * gMouse) /* if there are elements - send it */ if (mt_number) - gMouse->PutEventMultiTouch(mt_number, mt_number, mt_events, - RTTimeMilliTS()); + _vbox_mouse->PutEventMultiTouch(mt_number, mt_number, mt_events, + RTTimeMilliTS()); +} + +void GenodeConsole::handle_mode_change(unsigned) +{ + Display *d = getDisplay(); + Genodefb *fb = dynamic_cast(d->getFramebuffer()); + + fb->update_mode(); + update_video_mode(); +} + +void GenodeConsole::event_loop(IKeyboard * gKeyboard, IMouse * gMouse) +{ + _vbox_keyboard = gKeyboard; + _vbox_mouse = gMouse; + + /* register the mode change signal dispatcher at the framebuffer */ + Display *d = getDisplay(); + Genodefb *fb = dynamic_cast(d->getFramebuffer()); + fb->mode_sigh(_mode_change_signal_dispatcher); + + for (;;) { + + Genode::Signal sig = _receiver.wait_for_signal(); + Genode::Signal_dispatcher_base *dispatcher = + dynamic_cast(sig.context()); + + if (dispatcher) + dispatcher->dispatch(sig.num()); + } + } void GenodeConsole::onMouseCapabilityChange(BOOL supportsAbsolute, BOOL supportsRelative, diff --git a/repos/ports/src/virtualbox/frontend/console.h b/repos/ports/src/virtualbox/frontend/console.h index 5851f71ab..193005c98 100644 --- a/repos/ports/src/virtualbox/frontend/console.h +++ b/repos/ports/src/virtualbox/frontend/console.h @@ -107,15 +107,18 @@ class GenodeConsole : public Console { private: - Input::Connection _input; - Genode::Signal_receiver _receiver; - Genode::Signal_context _context; - Input::Event *_ev_buf; - unsigned _ax, _ay; - bool _last_received_motion_event_was_absolute; - Report::Connection _shape_report_connection; - Genode::Attached_dataspace _shape_report_ds; - Vbox_pointer::Shape_report *_shape_report; + Input::Connection _input; + Genode::Signal_receiver _receiver; + Input::Event *_ev_buf; + unsigned _ax, _ay; + bool _last_received_motion_event_was_absolute; + Report::Connection _shape_report_connection; + Genode::Attached_dataspace _shape_report_ds; + Vbox_pointer::Shape_report *_shape_report; + IKeyboard *_vbox_keyboard; + IMouse *_vbox_mouse; + Genode::Signal_dispatcher _input_signal_dispatcher; + Genode::Signal_dispatcher _mode_change_signal_dispatcher; bool _key_status[Input::KEY_MAX + 1]; @@ -136,15 +139,19 @@ class GenodeConsole : public Console { _last_received_motion_event_was_absolute(false), _shape_report_connection("shape", sizeof(Vbox_pointer::Shape_report)), _shape_report_ds(_shape_report_connection.dataspace()), - _shape_report(_shape_report_ds.local_addr()) + _shape_report(_shape_report_ds.local_addr()), + _vbox_keyboard(0), + _vbox_mouse(0), + _input_signal_dispatcher(_receiver, *this, &GenodeConsole::handle_input), + _mode_change_signal_dispatcher(_receiver, *this, &GenodeConsole::handle_mode_change) { for (unsigned i = 0; i <= Input::KEY_MAX; i++) _key_status[i] = 0; - _input.sigh(_receiver.manage(&_context)); + _input.sigh(_input_signal_dispatcher); } - void eventWait(IKeyboard * gKeyboard, IMouse * gMouse); + void event_loop(IKeyboard * gKeyboard, IMouse * gMouse); void onMouseCapabilityChange(BOOL supportsAbsolute, BOOL supportsRelative, BOOL supportsMT, BOOL needsHostCursor); @@ -209,4 +216,7 @@ class GenodeConsole : public Console { } void update_video_mode(); + + void handle_input(unsigned); + void handle_mode_change(unsigned); }; diff --git a/repos/ports/src/virtualbox/frontend/fb.h b/repos/ports/src/virtualbox/frontend/fb.h index 3a3051310..867d7649c 100644 --- a/repos/ports/src/virtualbox/frontend/fb.h +++ b/repos/ports/src/virtualbox/frontend/fb.h @@ -26,46 +26,76 @@ class Genodefb : { private: - Fb_Genode::Connection _fb; - Fb_Genode::Mode const _fb_mode; - void * _fb_base; - RTCRITSECT _fb_lock; + Fb_Genode::Connection _fb; - unsigned long _width; - unsigned long _height; + /* The mode matching the currently attached dataspace */ + Fb_Genode::Mode _fb_mode; + + /* The mode at the time when the mode change signal was received */ + Fb_Genode::Mode _next_fb_mode; + + /* + * The mode currently used by the VM. Can be smaller than the + * framebuffer mode. + */ + Fb_Genode::Mode _virtual_fb_mode; + + void *_fb_base; + RTCRITSECT _fb_lock; + + void _clear_screen() + { + size_t const num_pixels = _fb_mode.width() * _virtual_fb_mode.height(); + memset(_fb_base, 0, num_pixels * _fb_mode.bytes_per_pixel()); + _fb.refresh(0, 0, _virtual_fb_mode.width(), _virtual_fb_mode.height()); + } public: Genodefb () : _fb_mode(_fb.mode()), - _fb_base(Genode::env()->rm_session()->attach(_fb.dataspace())), - _width(_fb_mode.width()), - _height(_fb_mode.height()) + _next_fb_mode(_fb_mode), + _virtual_fb_mode(_fb_mode), + _fb_base(Genode::env()->rm_session()->attach(_fb.dataspace())) { int rc = RTCritSectInit(&_fb_lock); Assert(rc == VINF_SUCCESS); } - int w() const { return _fb_mode.width(); } - int h() const { return _fb_mode.height(); } - int depth() const { return 16; /* XXX */ } + /* Return the next mode of the framebuffer */ + int w() const { return _next_fb_mode.width(); } + int h() const { return _next_fb_mode.height(); } + + void mode_sigh(Genode::Signal_context_capability sigh) + { + _fb.mode_sigh(sigh); + } + + void update_mode() + { + Lock(); + _next_fb_mode = _fb.mode(); + Unlock(); + } STDMETHODIMP COMGETTER(Width)(ULONG *width) { if (!width) return E_INVALIDARG; - *width = (int)_width > _fb_mode.width() ? _fb_mode.width() : _width; + *width = _virtual_fb_mode.width(); + return S_OK; } - + STDMETHODIMP COMGETTER(Height)(ULONG *height) { if (!height) return E_INVALIDARG; - *height = (int)_height > _fb_mode.height() ? _fb_mode.height() : _height; + *height = _virtual_fb_mode.height(); + return S_OK; } @@ -90,7 +120,8 @@ class Genodefb : if (!bits) return E_INVALIDARG; - *bits = _fb_mode.bytes_per_pixel() * 8; + *bits = _virtual_fb_mode.bytes_per_pixel() * 8; + return S_OK; } @@ -111,29 +142,44 @@ class Genodefb : ULONG bytesPerLine, ULONG w, ULONG h, BOOL *finished) { - /* clear screen to avoid artefacts during resize */ - size_t const num_pixels = _fb_mode.width() * _fb_mode.height(); - memset(_fb_base, 0, num_pixels * _fb_mode.bytes_per_pixel()); + HRESULT result = E_FAIL; - _fb.refresh(0, 0, _fb_mode.width(), _fb_mode.height()); + Lock(); - /* bitsPerPixel == 0 is set by DevVGA when in text mode */ - bool ok = ((bitsPerPixel == 16) || (bitsPerPixel == 0)) && - (w <= (ULONG)_fb_mode.width()) && - (h <= (ULONG)_fb_mode.height()); - if (ok) - PINF("fb resize : %lux%lu@%zu -> %ux%u@%u", _width, _height, - _fb_mode.bytes_per_pixel() * 8, w, h, bitsPerPixel); - else - PWRN("fb resize : %lux%lu@%zu -> %ux%u@%u ignored", _width, _height, - _fb_mode.bytes_per_pixel() * 8, w, h, bitsPerPixel); + bool ok = (w <= (ULONG)_next_fb_mode.width()) && + (h <= (ULONG)_next_fb_mode.height()); - _width = w; - _height = h; + if (ok) { + PINF("fb resize : %dx%d@%zu -> %ux%u@%u", + _virtual_fb_mode.width(), _virtual_fb_mode.height(), + _virtual_fb_mode.bytes_per_pixel() * 8, w, h, bitsPerPixel); + + if ((w < (ULONG)_next_fb_mode.width()) || + (h < (ULONG)_next_fb_mode.height())) { + /* clear the old content around the new, smaller area. */ + _clear_screen(); + } + + _fb_mode = _next_fb_mode; + + _virtual_fb_mode = Fb_Genode::Mode(w, h, Fb_Genode::Mode::RGB565); + + Genode::env()->rm_session()->detach(_fb_base); + + _fb_base = Genode::env()->rm_session()->attach(_fb.dataspace()); + + result = S_OK; + + } else + PWRN("fb resize : %dx%d@%zu -> %ux%u@%u ignored", + _virtual_fb_mode.width(), _virtual_fb_mode.height(), + _virtual_fb_mode.bytes_per_pixel() * 8, w, h, bitsPerPixel); *finished = true; - return S_OK; + Unlock(); + + return result; } STDMETHODIMP COMGETTER(PixelFormat) (ULONG *format) @@ -177,9 +223,8 @@ class Genodefb : if (!supported) return E_POINTER; - *supported = ((width <= (ULONG)_fb_mode.width()) && - (height <= (ULONG)_fb_mode.height()) && - (bpp == _fb_mode.bytes_per_pixel() * 8)); + *supported = ((width <= (ULONG)_next_fb_mode.width()) && + (height <= (ULONG)_next_fb_mode.height())); return S_OK; } diff --git a/repos/ports/src/virtualbox/frontend/main.cc b/repos/ports/src/virtualbox/frontend/main.cc index 41076e8e3..ee3cea31d 100644 --- a/repos/ports/src/virtualbox/frontend/main.cc +++ b/repos/ports/src/virtualbox/frontend/main.cc @@ -198,9 +198,8 @@ HRESULT setupmachine() /* handle input of Genode and forward it to VMM layer */ ComPtr genodeConsole = gConsole; RTLogPrintf("genodeConsole = %p\n", genodeConsole); - while (true) { - genodeConsole->eventWait(gKeyboard, gMouse); - } + + genodeConsole->event_loop(gKeyboard, gMouse); Assert(!"return not expected"); return E_FAIL;