mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-19 05:37:54 +00:00
vbox: enable video acceleration (VBVA)
This commit enables the VirtualBox graphics adapter, provides guest mouse pointer integration with Nitpicker using the 'vbox_pointer' application and enhances the VirtualBox run scripts with the configuration of Nitpicker, input merger and network driver. Fixes #1474
This commit is contained in:
parent
0ef20f7ece
commit
af2cd7175c
75
repos/ports/include/vbox_pointer/dither_painter.h
Normal file
75
repos/ports/include/vbox_pointer/dither_painter.h
Normal file
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* \brief Functor for converting pixel formats by applying dithering
|
||||
* \author Norman Feske
|
||||
* \date 2014-09-10
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2014 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.
|
||||
*/
|
||||
|
||||
#ifndef _DITHER_PAINTER_H_
|
||||
#define _DITHER_PAINTER_H_
|
||||
|
||||
#include <util/dither_matrix.h>
|
||||
#include <os/surface.h>
|
||||
|
||||
|
||||
struct Dither_painter
|
||||
{
|
||||
/*
|
||||
* Surface and texture must have the same size
|
||||
*/
|
||||
template <typename DST_PT, typename SRC_PT>
|
||||
static inline void paint(Genode::Surface<DST_PT> &surface,
|
||||
Genode::Texture<SRC_PT> const &texture)
|
||||
{
|
||||
if (surface.size() != texture.size()) return;
|
||||
|
||||
Genode::Surface_base::Rect const clipped = surface.clip();
|
||||
|
||||
if (!clipped.valid()) return;
|
||||
|
||||
unsigned const offset = surface.size().w()*clipped.y1() + clipped.x1();
|
||||
|
||||
DST_PT *dst, *dst_line = surface.addr() + offset;
|
||||
SRC_PT const *src_pixel, *src_pixel_line = texture.pixel() + offset;
|
||||
unsigned char const *src_alpha, *src_alpha_line = texture.alpha() + offset;
|
||||
|
||||
unsigned const line_len = surface.size().w();
|
||||
|
||||
for (int y = clipped.y1(), h = clipped.h() ; h--; y++) {
|
||||
|
||||
src_pixel = src_pixel_line;
|
||||
src_alpha = src_alpha_line;
|
||||
dst = dst_line;
|
||||
|
||||
for (int x = clipped.x1(), w = clipped.w(); w--; x++) {
|
||||
|
||||
int const v = Genode::Dither_matrix::value(x, y) >> 4;
|
||||
|
||||
SRC_PT const pixel = *src_pixel++;
|
||||
unsigned char const alpha = *src_alpha++;
|
||||
|
||||
int const r = pixel.r() - v;
|
||||
int const g = pixel.g() - v;
|
||||
int const b = pixel.b() - v;
|
||||
int const a = alpha ? (int)alpha - v : 0;
|
||||
|
||||
using Genode::min;
|
||||
using Genode::max;
|
||||
|
||||
*dst++ = DST_PT(max(0, r), max(0, g), max(0, b), max(0, a));
|
||||
}
|
||||
|
||||
src_pixel_line += line_len;
|
||||
src_alpha_line += line_len;
|
||||
dst_line += line_len;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* _DITHER_PAINTER_H_ */
|
38
repos/ports/include/vbox_pointer/shape_report.h
Normal file
38
repos/ports/include/vbox_pointer/shape_report.h
Normal file
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* \brief shape report
|
||||
* \author Christian Prochaska
|
||||
* \date 2015-03-20
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2015 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.
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE__VBOX_POINTER__SHAPE_REPORT_H_
|
||||
#define _INCLUDE__VBOX_POINTER__SHAPE_REPORT_H_
|
||||
|
||||
namespace Vbox_pointer {
|
||||
|
||||
enum {
|
||||
MAX_WIDTH = 100,
|
||||
MAX_HEIGHT = 100,
|
||||
MAX_SHAPE_SIZE = MAX_WIDTH*MAX_HEIGHT*4
|
||||
};
|
||||
|
||||
struct Shape_report;
|
||||
}
|
||||
|
||||
struct Vbox_pointer::Shape_report
|
||||
{
|
||||
bool visible;
|
||||
unsigned int x_hot;
|
||||
unsigned int y_hot;
|
||||
unsigned int width;
|
||||
unsigned int height;
|
||||
unsigned char shape[MAX_SHAPE_SIZE];
|
||||
};
|
||||
|
||||
#endif /* _INCLUDE__VBOX_POINTER__SHAPE_REPORT_H_ */
|
@ -1 +1 @@
|
||||
7e0d7dd26169ee60eea603a22fd068bd0b879a79
|
||||
1e49158411c029263f5b29b890ec3f212b2caf29
|
||||
|
@ -8,7 +8,7 @@ URL(virtualbox) := http://download.virtualbox.org/virtualbox/$(VERSION)/$(VIRTUA
|
||||
DIR(virtualbox) := src/app/virtualbox
|
||||
SHA(virtualbox) := e4c23b713e8715b8e0172fa066f2197756e901fe
|
||||
|
||||
PATCHES_LIST := acpi_drv dev_e1000 eminternal fake_pci_vendor iconv mouse
|
||||
PATCHES_LIST := acpi_drv dev_e1000 eminternal iconv mouse
|
||||
PATCHES_LIST += pdm_driver poke sharedfolder_pagelist
|
||||
PATCHES_LIST += time-log-deadlock tm_retries vbox_inc vbox_main network
|
||||
PATCHES_LIST += vga_fb vga_vbva vmdk vmmdev avoid_yield serial rem_irq usb
|
||||
|
@ -7,7 +7,7 @@ set flavor "win7"
|
||||
# Write overlay back to harddisk if set to 0
|
||||
set use_ram_fs 0
|
||||
|
||||
set use_usb 0
|
||||
set use_usb 1
|
||||
set use_ps2 [have_spec ps2]
|
||||
|
||||
source ${genode_dir}/repos/ports/run/vbox_win.inc
|
||||
|
@ -102,7 +102,7 @@ catch { exec dd if=/dev/urandom of=bin/test.bin bs=4096 count=8160 }
|
||||
# Step 1: prepare and start the actual VM
|
||||
#
|
||||
set build_components {
|
||||
server/ram_fs
|
||||
server/ram_fs server/report_rom
|
||||
server/tcp_terminal drivers/nic
|
||||
lib/libc_noux
|
||||
noux/minimal
|
||||
@ -117,7 +117,7 @@ foreach pkg {bash coreutils} {
|
||||
set boot_modules {
|
||||
ram_fs
|
||||
noux libc_noux.lib.so bash.tar coreutils.tar
|
||||
tcp_terminal lwip.lib.so nic_drv
|
||||
tcp_terminal lwip.lib.so nic_drv report_rom
|
||||
test.bin template.bat
|
||||
vm_auto_share.vbox
|
||||
}
|
||||
@ -189,6 +189,12 @@ set config_of_app {
|
||||
</config>
|
||||
</start>
|
||||
|
||||
<start name="report_rom">
|
||||
<resource name="RAM" quantum="1M"/>
|
||||
<provides> <service name="Report"/> <service name="ROM"/> </provides>
|
||||
<config> <rom /> </config>
|
||||
</start>
|
||||
|
||||
<start name="vbox" priority="-2">
|
||||
<binary name="virtualbox" />
|
||||
<resource name="RAM" quantum="1280M"/>
|
||||
|
@ -9,7 +9,7 @@ set flavor "win8"
|
||||
# Write overlay back to harddisk if set to 0
|
||||
set use_ram_fs 0
|
||||
|
||||
set use_usb 0
|
||||
set use_usb 1
|
||||
set use_ps2 [have_spec ps2]
|
||||
|
||||
source ${genode_dir}/repos/ports/run/vbox_win.inc
|
||||
|
@ -10,10 +10,120 @@ set vdi_image "${flavor}.vdi"
|
||||
set vbox_file "vm_${flavor}.vbox"
|
||||
set overlay_image "overlay_${flavor}.vdi"
|
||||
|
||||
set build_components { }
|
||||
set boot_modules { }
|
||||
set build_components {
|
||||
server/input_merger
|
||||
drivers/nic
|
||||
server/nitpicker
|
||||
app/vbox_pointer
|
||||
server/nit_fb
|
||||
server/report_rom
|
||||
}
|
||||
|
||||
set boot_modules {
|
||||
input_merger
|
||||
nic_drv
|
||||
nitpicker
|
||||
vbox_pointer
|
||||
nit_fb
|
||||
report_rom
|
||||
}
|
||||
|
||||
set config_of_app {
|
||||
|
||||
<start name="input_merger">
|
||||
<resource name="RAM" quantum="1M" />
|
||||
<provides>
|
||||
<service name="Input" />
|
||||
</provides>
|
||||
<config>}
|
||||
append_if [expr $use_ps2] config_of_app {
|
||||
<input label="ps2" /> }
|
||||
append_if [expr $use_usb] config_of_app {
|
||||
<input label="usb_hid" />}
|
||||
append config_of_app {
|
||||
</config>
|
||||
<route> }
|
||||
append_if [expr $use_ps2] config_of_app {
|
||||
<service name="Input">
|
||||
<if-arg key="label" value="ps2" /> <child name="ps2_drv" />
|
||||
</service> }
|
||||
append_if [expr $use_usb] config_of_app {
|
||||
<service name="Input">
|
||||
<if-arg key="label" value="usb_hid" /> <child name="usb_drv" />
|
||||
</service> }
|
||||
append config_of_app {
|
||||
<any-service> <parent /> <any-child /> </any-service>
|
||||
</route>
|
||||
</start>
|
||||
|
||||
<!--
|
||||
Note: to get network access in the VM, the virtual network adapter
|
||||
needs to be enabled in the .vbox file (disabled by default)
|
||||
-->
|
||||
<start name="nic_drv" priority="-1">
|
||||
<resource name="RAM" quantum="8M" />
|
||||
<provides>
|
||||
<service name="Nic" />
|
||||
</provides>
|
||||
</start>
|
||||
|
||||
<start name="report_rom">
|
||||
<resource name="RAM" quantum="1M"/>
|
||||
<provides> <service name="Report"/> <service name="ROM"/> </provides>
|
||||
<config>
|
||||
<rom>
|
||||
<policy label="vbox_pointer -> hover" report="nitpicker -> hover"/>
|
||||
<policy label="vbox_pointer -> xray" report="nitpicker -> xray"/>
|
||||
<policy label="vbox_pointer -> shape" report="vbox -> shape"/>
|
||||
</rom>
|
||||
</config>
|
||||
</start>
|
||||
|
||||
<start name="nitpicker" priority="-1">
|
||||
<resource name="RAM" quantum="2M"/>
|
||||
<provides><service name="Nitpicker"/></provides>
|
||||
<route>
|
||||
<service name="Framebuffer"> <child name="fb_drv" /> </service>
|
||||
<service name="Input"> <child name="input_merger" /> </service>
|
||||
<any-service> <parent/> <any-child /> </any-service>
|
||||
</route>
|
||||
<config>
|
||||
<report focus="yes" hover="yes" xray="yes" />
|
||||
|
||||
<domain name="pointer" layer="1" xray="no" origin="pointer" />
|
||||
<domain name="vbox" layer="2" />
|
||||
<domain name="" layer="2" />
|
||||
|
||||
<policy label="vbox_pointer" domain="pointer"/>
|
||||
<policy label="nit_fb" domain="vbox"/>
|
||||
<policy label="" domain=""/>
|
||||
|
||||
<global-key name="KEY_SCROLLLOCK" operation="xray" />
|
||||
<global-key name="KEY_SYSRQ" operation="kill" />
|
||||
<global-key name="KEY_PRINT" operation="kill" />
|
||||
<global-key name="KEY_F11" operation="kill" />
|
||||
<global-key name="KEY_F12" operation="xray" />
|
||||
</config>
|
||||
</start>
|
||||
|
||||
<start name="vbox_pointer" priority="-1">
|
||||
<resource name="RAM" quantum="1M"/>
|
||||
<route>
|
||||
<service name="Nitpicker"> <child name="nitpicker"/> </service>
|
||||
<service name="ROM"> <child name="report_rom"/> </service>
|
||||
<any-service> <parent/> <any-child/> </any-service>
|
||||
</route>
|
||||
</start>
|
||||
|
||||
<start name="nit_fb" priority="-1">
|
||||
<resource name="RAM" quantum="8M" />
|
||||
<provides>
|
||||
<service name="Framebuffer" />
|
||||
<service name="Input" />
|
||||
</provides>
|
||||
<config width="1024" height="768" />
|
||||
</start>
|
||||
|
||||
<start name="vbox" priority="-2">
|
||||
<binary name="virtualbox" />
|
||||
<resource name="RAM" quantum="1280M"/>}
|
||||
@ -44,6 +154,8 @@ append_if [expr $use_ram_fs] config_of_app {
|
||||
|
||||
append config_of_app {
|
||||
<service name="File_system"> <child name="rump_fs"/> </service>
|
||||
<service name="Framebuffer"> <child name="nit_fb" /> </service>
|
||||
<service name="Input"> <child name="nit_fb" /> </service>
|
||||
<any-service> <parent/> <any-child /> </any-service>
|
||||
</route>
|
||||
</start>
|
||||
|
@ -41,7 +41,7 @@ set config {
|
||||
<service name="SIGNAL"/>
|
||||
</parent-provides>
|
||||
<default-route>
|
||||
<any-service> <any-child/> <parent/> </any-service>
|
||||
<any-service> <parent/> <any-child/> </any-service>
|
||||
</default-route>
|
||||
<start name="timer">
|
||||
<resource name="RAM" quantum="1M"/>
|
||||
@ -139,7 +139,7 @@ append_if [have_spec framebuffer] config {
|
||||
<start name="fb_drv" priority="-1">
|
||||
<resource name="RAM" quantum="6M"/>
|
||||
<provides><service name="Framebuffer"/></provides>
|
||||
<config buffered="yes" width="1024" height="768" depth="16" />
|
||||
<config buffered="yes" />
|
||||
</start>}
|
||||
|
||||
append_if [have_spec x86] config {
|
||||
|
36
repos/ports/src/app/vbox_pointer/big_mouse.h
Normal file
36
repos/ports/src/app/vbox_pointer/big_mouse.h
Normal file
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* \brief Mouse cursor pixel data
|
||||
* \author Norman Feske
|
||||
* \date 2006-08-09
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2006-2013 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.
|
||||
*/
|
||||
|
||||
static struct {
|
||||
unsigned short w, h, pixels[16][16];
|
||||
} big_mouse = {
|
||||
16,16,
|
||||
{
|
||||
{0x738E,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000},
|
||||
{0x0000,0x94B2,0x7BCF,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000},
|
||||
{0x0000,0x630C,0xC638,0xC638,0x6B4D,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000},
|
||||
{0x0000,0x0000,0x738E,0x8C71,0xFFFF,0xB5B6,0x6B4D,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000},
|
||||
{0x0000,0x0000,0x630C,0x4A49,0x630C,0xB5B6,0xFFFF,0xB5B6,0x630C,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000},
|
||||
{0x0000,0x0000,0x0000,0x528A,0x528A,0x630C,0x9492,0xB5B6,0xFFFF,0xB5B6,0x630C,0x0000,0x0000,0x0000,0x0000,0x0000},
|
||||
{0x0000,0x0000,0x0000,0x528A,0x39C7,0x4208,0x630C,0x7BCF,0xB5B6,0xFFFF,0xFFFF,0xB5B6,0x630C,0x0000,0x0000,0x0000},
|
||||
{0x0000,0x0000,0x0000,0x0000,0x4208,0x39C7,0x4208,0x630C,0x7BCF,0xB5B6,0xDEFB,0xFFFF,0xFFFF,0xB5B6,0x630C,0x0000},
|
||||
{0x0000,0x0000,0x0000,0x0000,0x4A49,0x1082,0x39C7,0x4208,0x5ACB,0x7BCF,0x8C71,0xAD75,0x630C,0x0000,0x0000,0x0000},
|
||||
{0x0000,0x0000,0x0000,0x0000,0x0000,0x4208,0x1082,0x39C7,0x5ACB,0x630C,0xB5B6,0x0000,0x0000,0x0000,0x0000,0x0000},
|
||||
{0x0000,0x0000,0x0000,0x0000,0x0000,0x4A49,0x1082,0x1082,0x39C7,0x4A49,0x630C,0xAD75,0x0000,0x0000,0x0000,0x0000},
|
||||
{0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x4208,0x1082,0x4A49,0x0000,0x4A49,0x630C,0x8C71,0x0000,0x0000,0x0000},
|
||||
{0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x4A49,0x39C7,0x4A49,0x0000,0x0000,0x4A49,0x630C,0x8C71,0x0000,0x0000},
|
||||
{0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x4A49,0x0000,0x0000,0x0000,0x0000,0x4A49,0x630C,0x8C71,0x0000},
|
||||
{0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x4A49,0x0000,0x0000,0x0000,0x0000,0x0000,0x4A49,0x4A49,0x0000},
|
||||
{0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000},
|
||||
}
|
||||
};
|
410
repos/ports/src/app/vbox_pointer/main.cc
Normal file
410
repos/ports/src/app/vbox_pointer/main.cc
Normal file
@ -0,0 +1,410 @@
|
||||
/*
|
||||
* \brief Nitpicker pointer with support for VirtualBox-defined shapes
|
||||
* \author Norman Feske
|
||||
* \author Christian Helmuth
|
||||
* \author Christian Prochaska
|
||||
* \date 2014-07-02
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2014-2015 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 <base/sleep.h>
|
||||
#include <os/attached_dataspace.h>
|
||||
#include <os/attached_ram_dataspace.h>
|
||||
#include <os/attached_rom_dataspace.h>
|
||||
#include <os/surface.h>
|
||||
#include <os/pixel_alpha8.h>
|
||||
#include <os/pixel_rgb565.h>
|
||||
#include <os/pixel_rgb888.h>
|
||||
#include <os/texture_rgb888.h>
|
||||
#include <os/texture.h>
|
||||
#include <util/xml_node.h>
|
||||
#include <nitpicker_session/connection.h>
|
||||
#include <vbox_pointer/dither_painter.h>
|
||||
#include <vbox_pointer/shape_report.h>
|
||||
|
||||
/* local includes */
|
||||
#include "big_mouse.h"
|
||||
|
||||
/* exception */
|
||||
struct Pointer_shape_too_large { };
|
||||
|
||||
template <typename PT>
|
||||
void convert_default_cursor_data_to_pixels(PT *pixel, Nitpicker::Area size)
|
||||
{
|
||||
unsigned char *alpha = (unsigned char *)(pixel + size.count());
|
||||
|
||||
for (unsigned y = 0; y < size.h(); y++) {
|
||||
for (unsigned x = 0; x < size.w(); x++) {
|
||||
|
||||
/* the source is known to be in RGB565 format */
|
||||
Genode::Pixel_rgb565 src =
|
||||
*(Genode::Pixel_rgb565 *)(&big_mouse.pixels[y][x]);
|
||||
|
||||
unsigned const i = y*size.w() + x;
|
||||
pixel[i] = PT(src.r(), src.g(), src.b());
|
||||
alpha[i] = src.r() ? 255 : 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename PT>
|
||||
void convert_vbox_cursor_data_to_pixels(PT *pixel, unsigned char *shape,
|
||||
Nitpicker::Area size)
|
||||
{
|
||||
Genode::Attached_ram_dataspace texture_pixel_ds { Genode::env()->ram_session(),
|
||||
size.count() *
|
||||
sizeof(Genode::Pixel_rgb888) };
|
||||
|
||||
Genode::Attached_ram_dataspace texture_alpha_ds { Genode::env()->ram_session(),
|
||||
size.count() };
|
||||
|
||||
Genode::Texture<Genode::Pixel_rgb888>
|
||||
texture(texture_pixel_ds.local_addr<Genode::Pixel_rgb888>(),
|
||||
texture_alpha_ds.local_addr<unsigned char>(),
|
||||
size);
|
||||
|
||||
for (unsigned int y = 0; y < size.h(); y++) {
|
||||
|
||||
/* convert the shape data from BGRA encoding to RGBA encoding */
|
||||
unsigned char *bgra_line = &shape[y * size.w() * 4];
|
||||
unsigned char rgba_line[size.w() * 4];
|
||||
for (unsigned int i = 0; i < size.w() * 4; i += 4) {
|
||||
rgba_line[i + 0] = bgra_line[i + 2];
|
||||
rgba_line[i + 1] = bgra_line[i + 1];
|
||||
rgba_line[i + 2] = bgra_line[i + 0];
|
||||
rgba_line[i + 3] = bgra_line[i + 3];
|
||||
}
|
||||
|
||||
/* import the RGBA-encoded line into the texture */
|
||||
texture.rgba(rgba_line, size.w(), y);
|
||||
}
|
||||
|
||||
Genode::Pixel_alpha8 *alpha =
|
||||
reinterpret_cast<Genode::Pixel_alpha8*>(pixel + size.count());
|
||||
|
||||
Genode::Surface<PT> pixel_surface(pixel, size);
|
||||
Genode::Surface<Genode::Pixel_alpha8> alpha_surface(alpha, size);
|
||||
|
||||
Dither_painter::paint(pixel_surface, texture);
|
||||
Dither_painter::paint(alpha_surface, texture);
|
||||
}
|
||||
|
||||
//struct Log { Log(char const *msg) { PINF("Log: %s", msg); } };
|
||||
|
||||
|
||||
typedef Genode::String<64> Domain_name;
|
||||
|
||||
class Domain : public Genode::List<Domain>::Element
|
||||
{
|
||||
public:
|
||||
|
||||
struct Name_too_long { };
|
||||
|
||||
private:
|
||||
|
||||
Domain_name _name;
|
||||
|
||||
public:
|
||||
|
||||
Domain(char const *name) : _name(name)
|
||||
{
|
||||
if (Genode::strlen(name) + 1 > _name.capacity())
|
||||
throw Name_too_long();
|
||||
}
|
||||
|
||||
Domain_name const & name() { return _name; }
|
||||
};
|
||||
|
||||
|
||||
struct Domain_list : private Genode::List<Domain>
|
||||
{
|
||||
void add(char const *name)
|
||||
{
|
||||
Domain *d = new (Genode::env()->heap()) Domain(name);
|
||||
insert(d);
|
||||
}
|
||||
|
||||
bool contains(Domain_name const &name)
|
||||
{
|
||||
for (Domain *d = first(); d; d = d->next())
|
||||
if (d->name() == name)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct Main
|
||||
{
|
||||
Genode::Attached_rom_dataspace hover_ds { "hover" };
|
||||
Genode::Attached_rom_dataspace xray_ds { "xray" };
|
||||
Genode::Attached_rom_dataspace shape_ds { "shape" };
|
||||
|
||||
Genode::Signal_receiver sig_rec;
|
||||
|
||||
void handle_hover(unsigned num = 0);
|
||||
void handle_xray(unsigned num = 0);
|
||||
void handle_shape(unsigned num = 0);
|
||||
|
||||
Genode::Signal_dispatcher<Main> hover_signal_dispatcher {
|
||||
sig_rec, *this, &Main::handle_hover };
|
||||
Genode::Signal_dispatcher<Main> xray_signal_dispatcher {
|
||||
sig_rec, *this, &Main::handle_xray };
|
||||
Genode::Signal_dispatcher<Main> shape_signal_dispatcher {
|
||||
sig_rec, *this, &Main::handle_shape };
|
||||
|
||||
Nitpicker::Connection nitpicker;
|
||||
|
||||
Nitpicker::Session::View_handle view = nitpicker.create_view();
|
||||
|
||||
Domain_list vbox_domains;
|
||||
Domain_name current_domain;
|
||||
|
||||
bool xray = false;
|
||||
bool default_pointer_visible = false;
|
||||
bool vbox_pointer_visible = false;
|
||||
bool vbox_pointer_shape_changed = false;
|
||||
|
||||
Nitpicker::Area current_cursor_size;
|
||||
Genode::Dataspace_capability pointer_ds;
|
||||
|
||||
void resize_nitpicker_buffer_if_needed(Nitpicker::Area cursor_size)
|
||||
{
|
||||
if (cursor_size != current_cursor_size) {
|
||||
|
||||
Framebuffer::Mode const mode { (int)cursor_size.w(), (int)cursor_size.h(),
|
||||
Framebuffer::Mode::RGB565 };
|
||||
|
||||
nitpicker.buffer(mode, true /* use alpha */);
|
||||
|
||||
pointer_ds = nitpicker.framebuffer()->dataspace();
|
||||
|
||||
current_cursor_size = cursor_size;
|
||||
}
|
||||
}
|
||||
|
||||
void show_default_pointer()
|
||||
{
|
||||
if (!default_pointer_visible) {
|
||||
|
||||
Nitpicker::Area const cursor_size { big_mouse.w, big_mouse.h };
|
||||
|
||||
try {
|
||||
resize_nitpicker_buffer_if_needed(cursor_size);
|
||||
} catch (...) {
|
||||
PERR("%s: could not resize the pointer buffer for %u x %u pixels",
|
||||
__func__, cursor_size.w(), cursor_size.h());
|
||||
return;
|
||||
}
|
||||
|
||||
Genode::Attached_dataspace ds { pointer_ds };
|
||||
|
||||
convert_default_cursor_data_to_pixels(ds.local_addr<Genode::Pixel_rgb565>(),
|
||||
cursor_size);
|
||||
nitpicker.framebuffer()->refresh(0, 0, cursor_size.w(), cursor_size.h());
|
||||
|
||||
Nitpicker::Rect geometry(Nitpicker::Point(0, 0), cursor_size);
|
||||
nitpicker.enqueue<Nitpicker::Session::Command::Geometry>(view, geometry);
|
||||
nitpicker.execute();
|
||||
|
||||
default_pointer_visible = true;
|
||||
vbox_pointer_visible = false;
|
||||
}
|
||||
}
|
||||
|
||||
void show_vbox_pointer()
|
||||
{
|
||||
if (!vbox_pointer_visible || vbox_pointer_shape_changed) {
|
||||
|
||||
try {
|
||||
|
||||
Vbox_pointer::Shape_report *shape_report =
|
||||
shape_ds.local_addr<Vbox_pointer::Shape_report>();
|
||||
|
||||
if (shape_report->visible) {
|
||||
|
||||
if ((shape_report->width == 0) || (shape_report->height == 0))
|
||||
return;
|
||||
|
||||
if ((shape_report->width > Vbox_pointer::MAX_WIDTH) ||
|
||||
(shape_report->height > Vbox_pointer::MAX_HEIGHT))
|
||||
throw Pointer_shape_too_large();
|
||||
|
||||
Nitpicker::Area const cursor_size { shape_report->width,
|
||||
shape_report->height };
|
||||
|
||||
resize_nitpicker_buffer_if_needed(cursor_size);
|
||||
|
||||
Genode::Attached_dataspace ds { pointer_ds };
|
||||
|
||||
convert_vbox_cursor_data_to_pixels(ds.local_addr<Genode::Pixel_rgb565>(),
|
||||
shape_report->shape,
|
||||
cursor_size);
|
||||
nitpicker.framebuffer()->refresh(0, 0, cursor_size.w(), cursor_size.h());
|
||||
|
||||
Nitpicker::Rect geometry(Nitpicker::Point(-shape_report->x_hot, -shape_report->y_hot), cursor_size);
|
||||
nitpicker.enqueue<Nitpicker::Session::Command::Geometry>(view, geometry);
|
||||
|
||||
} else {
|
||||
|
||||
Nitpicker::Rect geometry(Nitpicker::Point(0, 0), Nitpicker::Area(0, 0));
|
||||
nitpicker.enqueue<Nitpicker::Session::Command::Geometry>(view, geometry);
|
||||
|
||||
}
|
||||
|
||||
} catch (Genode::Volatile_object<Genode::Attached_dataspace>::Deref_unconstructed_object) {
|
||||
/* no shape has been reported, yet */
|
||||
Nitpicker::Rect geometry(Nitpicker::Point(0, 0), Nitpicker::Area(0, 0));
|
||||
nitpicker.enqueue<Nitpicker::Session::Command::Geometry>(view, geometry);
|
||||
}
|
||||
|
||||
nitpicker.execute();
|
||||
|
||||
vbox_pointer_visible = true;
|
||||
vbox_pointer_shape_changed = false;
|
||||
default_pointer_visible = false;
|
||||
}
|
||||
}
|
||||
|
||||
void update_pointer()
|
||||
{
|
||||
if (xray || !vbox_domains.contains(current_domain))
|
||||
show_default_pointer();
|
||||
else
|
||||
try {
|
||||
show_vbox_pointer();
|
||||
} catch (Pointer_shape_too_large) {
|
||||
PERR("%s: the pointer shape is larger than the maximum supported size of %u x %u",
|
||||
__func__, Vbox_pointer::MAX_WIDTH, Vbox_pointer::MAX_HEIGHT);
|
||||
show_default_pointer();
|
||||
} catch (...) {
|
||||
PERR("%s: an unhandled exception occurred while trying to show \
|
||||
the VirtualBox pointer", __func__);
|
||||
show_default_pointer();
|
||||
}
|
||||
}
|
||||
|
||||
Main()
|
||||
{
|
||||
/*
|
||||
* Try to allocate the Nitpicker buffer for the maximum supported
|
||||
* pointer size to let the user know right from the start if the
|
||||
* RAM quota is too low.
|
||||
*/
|
||||
Framebuffer::Mode const mode { Vbox_pointer::MAX_WIDTH, Vbox_pointer::MAX_HEIGHT,
|
||||
Framebuffer::Mode::RGB565 };
|
||||
|
||||
nitpicker.buffer(mode, true /* use alpha */);
|
||||
|
||||
/* TODO should be read from config */
|
||||
vbox_domains.add("vbox");
|
||||
|
||||
/* register signal handlers */
|
||||
hover_ds.sigh(hover_signal_dispatcher);
|
||||
xray_ds.sigh(xray_signal_dispatcher);
|
||||
shape_ds.sigh(shape_signal_dispatcher);
|
||||
|
||||
nitpicker.enqueue<Nitpicker::Session::Command::To_front>(view);
|
||||
nitpicker.execute();
|
||||
|
||||
/* import initial state */
|
||||
handle_hover();
|
||||
handle_xray();
|
||||
handle_shape();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
static Domain_name read_string_attribute(Genode::Xml_node const &node,
|
||||
char const *attr,
|
||||
Domain_name const &default_value)
|
||||
{
|
||||
try {
|
||||
char buf[Domain_name::capacity()];
|
||||
node.attribute(attr).value(buf, sizeof(buf));
|
||||
return Domain_name(buf);
|
||||
}
|
||||
catch (...) {
|
||||
return default_value; }
|
||||
}
|
||||
|
||||
|
||||
void Main::handle_hover(unsigned)
|
||||
{
|
||||
hover_ds.update();
|
||||
if (!hover_ds.is_valid())
|
||||
return;
|
||||
|
||||
/* read new hover information from nitpicker's hover report */
|
||||
try {
|
||||
Genode::Xml_node node(hover_ds.local_addr<char>());
|
||||
|
||||
current_domain = read_string_attribute(node, "domain", Domain_name());
|
||||
}
|
||||
catch (...) {
|
||||
PWRN("could not parse hover report");
|
||||
}
|
||||
|
||||
update_pointer();
|
||||
}
|
||||
|
||||
|
||||
void Main::handle_xray(unsigned)
|
||||
{
|
||||
xray_ds.update();
|
||||
if (!xray_ds.is_valid())
|
||||
return;
|
||||
|
||||
try {
|
||||
Genode::Xml_node node(xray_ds.local_addr<char>());
|
||||
|
||||
xray = node.has_attribute("enabled")
|
||||
&& node.attribute("enabled").has_value("yes");
|
||||
}
|
||||
catch (...) {
|
||||
PWRN("could not parse xray report");
|
||||
}
|
||||
|
||||
update_pointer();
|
||||
}
|
||||
|
||||
|
||||
void Main::handle_shape(unsigned)
|
||||
{
|
||||
shape_ds.update();
|
||||
|
||||
if (!shape_ds.is_valid())
|
||||
return;
|
||||
|
||||
if (shape_ds.size() < sizeof(Vbox_pointer::Shape_report))
|
||||
return;
|
||||
|
||||
vbox_pointer_shape_changed = true;
|
||||
|
||||
update_pointer();
|
||||
}
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
static Main main;
|
||||
|
||||
/* dispatch signals */
|
||||
for (;;) {
|
||||
|
||||
Genode::Signal sig = main.sig_rec.wait_for_signal();
|
||||
Genode::Signal_dispatcher_base *dispatcher =
|
||||
dynamic_cast<Genode::Signal_dispatcher_base *>(sig.context());
|
||||
|
||||
if (dispatcher)
|
||||
dispatcher->dispatch(sig.num());
|
||||
}
|
||||
}
|
3
repos/ports/src/app/vbox_pointer/target.mk
Normal file
3
repos/ports/src/app/vbox_pointer/target.mk
Normal file
@ -0,0 +1,3 @@
|
||||
TARGET = vbox_pointer
|
||||
SRC_CC = main.cc
|
||||
LIBS += base
|
@ -86,12 +86,9 @@ HRESULT Console::Teleport(unsigned short*, unsigned int, unsigned short*,
|
||||
unsigned int, Progress**) DUMMY(E_FAIL)
|
||||
HRESULT Console::setDiskEncryptionKeys(const Utf8Str &strCfg) DUMMY(E_FAIL)
|
||||
|
||||
void Console::onMouseCapabilityChange(BOOL, BOOL, BOOL, BOOL) TRACE()
|
||||
void Console::onAdditionsStateChange() TRACE()
|
||||
void Console::onAdditionsOutdated() DUMMY()
|
||||
void Console::onMousePointerShapeChange(bool, bool, uint32_t, uint32_t,
|
||||
uint32_t, uint32_t,
|
||||
ComSafeArrayIn(uint8_t, aShape)) DUMMY()
|
||||
|
||||
void Console::onKeyboardLedsChange(bool, bool, bool) TRACE()
|
||||
HRESULT Console::onVideoCaptureChange() DUMMY(E_FAIL)
|
||||
HRESULT Console::onSharedFolderChange(BOOL aGlobal) DUMMY(E_FAIL)
|
||||
|
@ -24,6 +24,9 @@
|
||||
/* VirtualBox includes */
|
||||
#include "ConsoleImpl.h"
|
||||
#include <base/printf.h>
|
||||
#include <os/attached_dataspace.h>
|
||||
#include <report_session/connection.h>
|
||||
#include <vbox_pointer/shape_report.h>
|
||||
|
||||
|
||||
class Scan_code
|
||||
@ -104,12 +107,15 @@ 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;
|
||||
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;
|
||||
|
||||
bool _key_status[Input::KEY_MAX + 1];
|
||||
|
||||
@ -127,7 +133,10 @@ class GenodeConsole : public Console {
|
||||
Console(),
|
||||
_ev_buf(static_cast<Input::Event *>(Genode::env()->rm_session()->attach(_input.dataspace()))),
|
||||
_ax(0), _ay(0),
|
||||
_last_received_motion_event_was_absolute(false)
|
||||
_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<Vbox_pointer::Shape_report>())
|
||||
{
|
||||
for (unsigned i = 0; i <= Input::KEY_MAX; i++)
|
||||
_key_status[i] = 0;
|
||||
@ -284,4 +293,73 @@ class GenodeConsole : public Console {
|
||||
gMouse->PutEventMultiTouch(mt_number, mt_number, mt_events,
|
||||
RTTimeMilliTS());
|
||||
}
|
||||
|
||||
void onMouseCapabilityChange(BOOL supportsAbsolute, BOOL supportsRelative,
|
||||
BOOL supportsMT, BOOL needsHostCursor)
|
||||
{
|
||||
if (supportsAbsolute) {
|
||||
/* let the guest hide the software cursor */
|
||||
Mouse *gMouse = getMouse();
|
||||
gMouse->PutMouseEventAbsolute(-1, -1, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void onMousePointerShapeChange(bool fVisible, bool fAlpha,
|
||||
uint32_t xHot, uint32_t yHot,
|
||||
uint32_t width, uint32_t height,
|
||||
ComSafeArrayIn(BYTE,pShape))
|
||||
{
|
||||
com::SafeArray<BYTE> shape_array(ComSafeArrayInArg(pShape));
|
||||
|
||||
if (fVisible && ((width == 0) || (height == 0)))
|
||||
return;
|
||||
|
||||
_shape_report->visible = fVisible;
|
||||
_shape_report->x_hot = xHot;
|
||||
_shape_report->y_hot = yHot;
|
||||
_shape_report->width = width;
|
||||
_shape_report->height = height;
|
||||
|
||||
unsigned int and_mask_size = (_shape_report->width + 7) / 8 *
|
||||
_shape_report->height;
|
||||
|
||||
unsigned char *and_mask = shape_array.raw();
|
||||
|
||||
unsigned char *shape = and_mask + ((and_mask_size + 3) & ~3);
|
||||
|
||||
size_t shape_size = shape_array.size() - (shape - and_mask);
|
||||
|
||||
if (shape_size > Vbox_pointer::MAX_SHAPE_SIZE) {
|
||||
PERR("%s: shape data buffer is too small for %zu bytes",
|
||||
__func__, shape_size);
|
||||
return;
|
||||
}
|
||||
|
||||
Genode::memcpy(_shape_report->shape,
|
||||
shape,
|
||||
shape_size);
|
||||
|
||||
if (fVisible && !fAlpha) {
|
||||
|
||||
for (unsigned int i = 0; i < width * height; i++) {
|
||||
|
||||
unsigned int *color =
|
||||
&((unsigned int*)_shape_report->shape)[i];
|
||||
|
||||
/* heuristic from VBoxSDL.cpp */
|
||||
|
||||
if (and_mask[i / 8] & (1 << (7 - (i % 8)))) {
|
||||
|
||||
if (*color & 0x00ffffff)
|
||||
*color = 0xff000000;
|
||||
else
|
||||
*color = 0x00000000;
|
||||
|
||||
} else
|
||||
*color |= 0xff000000;
|
||||
}
|
||||
}
|
||||
|
||||
_shape_report_connection.submit(sizeof(Vbox_pointer::Shape_report));
|
||||
}
|
||||
};
|
||||
|
@ -166,7 +166,13 @@ class Genodefb : public Framebuffer
|
||||
|
||||
STDMETHODIMP VideoModeSupported(ULONG width, ULONG height, ULONG bpp, BOOL *supported)
|
||||
{
|
||||
Assert(!"FixMe");
|
||||
if (!supported)
|
||||
return E_POINTER;
|
||||
|
||||
*supported = ((width <= (ULONG)_fb_mode.width()) &&
|
||||
(height <= (ULONG)_fb_mode.height()) &&
|
||||
(bpp == _fb_mode.bytes_per_pixel() * 8));
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
@ -1,10 +0,0 @@
|
||||
+++ src/app/virtualbox/src/VBox/Devices/Graphics/DevVGA.cpp
|
||||
@@ -5946,7 +5946,7 @@
|
||||
else
|
||||
{
|
||||
#endif /* VBOX_WITH_VMSVGA */
|
||||
- PCIDevSetVendorId( &pThis->Dev, 0x80ee); /* PCI vendor, just a free bogus value */
|
||||
+ PCIDevSetVendorId( &pThis->Dev, 0x80ef); /* PCI vendor, just a free bogus value */
|
||||
PCIDevSetDeviceId( &pThis->Dev, 0xbeef);
|
||||
#ifdef VBOX_WITH_VMSVGA
|
||||
}
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user