GENIVI-fying Chromium, part 3: multi-seat

In the previous blog posts, we described the work to bring the Chromium browser to the GENIVI Development Platform (GDP) using the latest version of the Ozone-Wayland project. We also introduced our intention to develop multi-seat capabilities on that version of the Chromium browser. This post covers the details of the multi-seat implementation.

Goal

The GENIVI stack is supposed to allow applications run in multi-seat mode. A seat is a set of input/output devices like, for example, a touchscreen and a keyboard; one computer (the head unit) connected to several seats should be able to assing applications to each seat and let them run independently. Hence, our goal is to let one Chromium instance manage several browser windows at the same time and independently, getting their input from different seats.

Renesas Salvator-X board running Chromium on two seats

Problem

We started with an analysis of the browser on a multi-seat environment, comparing its behavior with other applications, and we identified some problems. In first place, we noticed that keyboard focus could be stolen by other browser windows; in second place, we found that only one browser window was receiving all input events regardless of seat configuration.

Let me first illustrate the flow of events between Chromium process in Ozone-Wayland:

All browser window surfaces belong to the GPU process, events that affect those surfaces arrive to this process and then they are sent to the browser process via internal IPC. There, events would be processed and their effects sent to the render processes if necessary.

The concept of “focus”, as implemented in Ozone-Wayland, means there can only be one focused window, and that window would receive all kinds of events. All events that are received by the GPU process that belonged to different surfaces/windows are merged and received by the focused window in the browser process. Important information is lost in the process, like the original device ids. Besides, there is no awareness of the different seats in the browser process, and the GPU process ignores that info despite having it.

Solution

The basis of the solution is to break the assumption of having only one focused window and integrate seat information in the event flow.

We started by creating separate concepts of keyboard and pointer focus, which fixed the first issue for the most part. For the complete solution, we also had to add extra wires to link seats and devices in the GPU process using already existing information, and transfer the required information to the browser process. In particular, we added extra information to the internal IPC messages related to the device ids that produce every event. We also added the concept of seats in the browser process, with new IPC signals to sync the seat objects and seat assignment information. This information is obtained using the ivi-input interface from the Wayland IVI Extension project.

You can see a class diagram with the highlighted changes (blue: added, red: removed) below:

The multi-seat implementation of Ozone-Wayland described above is available in my GitHub fork, branch wip/multi-seat.

Testing it

Patches haven’t been merged yet into genivi-dev-platform master, but there is a chromium branch with all the integration work so far. The last PR has been recently merged, which includes multi-seat, patches to support the Salvator-X board and a backported fix for the Wayland IVI Extensions.

You can already do your own builds by cloning the genivi-dev-platform chromium branch. Then, just follow the GDP instructions. We have successfully tested the multi-seat implementation on Intel hardware and also on Renesas R-Car generation 3 boards like the Salvator-X shown above.

If you are building your own HMI controller, you have to use the Wayland IVI Extension APIs to properly setup the screens, layers, surfaces and seat assignment. Seat configuration is done via udev (see Advanced use). For testing purposes, you may want to use the LayerManagerControl command-line tool to simulate the HMI controller; I can share with you the commands I used to setup the Salvator-X with two seats: two keyboards and two touchscreens, one of them plugged via VGA and another one through HDMI.

In first place, this is my udev configuration to create the seats, in the file /etc/udev/rules.d/seats.rules. Touchscreens are identified with their physical USB address because they are the same brand and model:

ATTRS{name}=="Dell Dell USB Keyboard", ENV{WL_SEAT}="seat_1"
ATTRS{name}=="Logitech USB Keyboard", ENV{WL_SEAT}="seat_2"

ATTRS{phys}=="usb-ee0a0100.usb-1.1/input0", ENV{WL_SEAT}="seat_1", ENV{WL_OUTPUT}="VGA-1"
ATTRS{phys}=="usb-ee0a0100.usb-1.2/input0", ENV{WL_SEAT}="seat_2", ENV{WL_OUTPUT}="HDMI-A-1"

To manage layers, surfaces and focus on my own, I had to stop the GENIVI HMI:

systemctl --user stop gdp-new-hmi

I started by setting up one layer for each screen, with sizes that match the screen resolutions:

LayerManagerControl create layer 1000 1024 768
LayerManagerControl set layer 1000 visibility 1
LayerManagerControl set screen 0 render order 1000

LayerManagerControl create layer 2000 1280 720
LayerManagerControl set layer 2000 visibility 1
LayerManagerControl set screen 1 render order 2000

Then I ran the chromium browser (you will probably want to have several terminals open into the device for convenience), I ran the command twice to get two browser windows with surfaces 7001 and 7002. I configured the surface sizes and assigned them to each layer:

LayerManagerControl set surface 7001 visibility 1
LayerManagerControl set surface 7001 source region 0 0 1728 1080
LayerManagerControl set surface 7001 destination region 0 0 1024 768

LayerManagerControl set surface 7002 visibility 1
LayerManagerControl set surface 7002 source region 0 0 1728 1080
LayerManagerControl set surface 7002 destination region 0 0 1280 720

LayerManagerControl set layer 1000 render order 7001
LayerManagerControl set layer 2000 render order 7002

Finally, configured seat acceptances for each surface to receive events from only one seat, and gave keyboard focus to both:

LayerManagerControl set surface 7001 input acceptance to seat_1
LayerManagerControl set surface 7002 input acceptance to seat_2
LayerManagerControl set surfaces 7001,7002 input focus keyboard

This work is performed by Igalia and has been made possible by the funding provided by the GENIVI Alliance through the Challenge Grant Program. Thank you!

GENIVI logo

2 thoughts on “GENIVI-fying Chromium, part 3: multi-seat

  1. Great post Jacobo! Here’s a nitpick.

    > Patches haven’t been merged yet into upstream genivi-dev-platform

    More correctly: Patches haven’t yet been merged to the *master* branch, due to
    that the feature is not yet supported on all our supported platforms.

Leave a Reply

Your email address will not be published. Required fields are marked *