{"id":754,"date":"2017-06-16T11:01:46","date_gmt":"2017-06-16T09:01:46","guid":{"rendered":"http:\/\/blogs.igalia.com\/jaragunde\/?p=754"},"modified":"2022-10-03T16:14:05","modified_gmt":"2022-10-03T14:14:05","slug":"genivi-fying-chromium-part-3-multi-seat","status":"publish","type":"post","link":"https:\/\/blogs.igalia.com\/jaragunde\/2017\/06\/genivi-fying-chromium-part-3-multi-seat\/","title":{"rendered":"GENIVI-fying Chromium, part 3: multi-seat"},"content":{"rendered":"<p>In the <a href=\"http:\/\/blogs.igalia.com\/jaragunde\/tag\/chromium-on-genivi\/\">previous blog posts<\/a>, we described the work to bring the Chromium browser to the <a href=\"https:\/\/at.projects.genivi.org\/wiki\/pages\/viewpage.action?pageId=11567210\">GENIVI Development Platform<\/a> (GDP) using the latest version of the <a href=\"https:\/\/github.com\/01org\/ozone-wayland\">Ozone-Wayland<\/a> 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.<\/p>\n<h3>Goal<\/h3>\n<p>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.<\/p>\n<div id=\"attachment_758\" style=\"width: 594px\" class=\"wp-caption alignnone\"><a href=\"https:\/\/blogs.igalia.com\/jaragunde\/files\/2017\/06\/IMG_20170612_184101.jpg\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-758\" src=\"https:\/\/blogs.igalia.com\/jaragunde\/files\/2017\/06\/IMG_20170612_184101-1024x576.jpg\" alt=\"\" width=\"584\" height=\"329\" class=\"size-large wp-image-758\" srcset=\"https:\/\/blogs.igalia.com\/jaragunde\/files\/2017\/06\/IMG_20170612_184101-1024x576.jpg 1024w, https:\/\/blogs.igalia.com\/jaragunde\/files\/2017\/06\/IMG_20170612_184101-300x169.jpg 300w, https:\/\/blogs.igalia.com\/jaragunde\/files\/2017\/06\/IMG_20170612_184101-768x432.jpg 768w, https:\/\/blogs.igalia.com\/jaragunde\/files\/2017\/06\/IMG_20170612_184101-500x281.jpg 500w\" sizes=\"auto, (max-width: 584px) 100vw, 584px\" \/><\/a><p id=\"caption-attachment-758\" class=\"wp-caption-text\">Renesas Salvator-X board running Chromium on two seats<\/p><\/div>\n<p><!--more--><\/p>\n<h3>Problem<\/h3>\n<p>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.<\/p>\n<p>Let me first illustrate the flow of events between Chromium process in Ozone-Wayland:<\/p>\n<p><a href=\"http:\/\/blogs.igalia.com\/jaragunde\/files\/2017\/06\/events-flow.png\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/blogs.igalia.com\/jaragunde\/files\/2017\/06\/events-flow-1024x226.png\" alt=\"\" width=\"584\" height=\"129\" class=\"alignnone size-large wp-image-755\" srcset=\"https:\/\/blogs.igalia.com\/jaragunde\/files\/2017\/06\/events-flow-1024x226.png 1024w, https:\/\/blogs.igalia.com\/jaragunde\/files\/2017\/06\/events-flow-300x66.png 300w, https:\/\/blogs.igalia.com\/jaragunde\/files\/2017\/06\/events-flow-768x169.png 768w, https:\/\/blogs.igalia.com\/jaragunde\/files\/2017\/06\/events-flow-500x110.png 500w, https:\/\/blogs.igalia.com\/jaragunde\/files\/2017\/06\/events-flow.png 1335w\" sizes=\"auto, (max-width: 584px) 100vw, 584px\" \/><\/a><\/p>\n<p>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.<\/p>\n<p>The concept of &#8220;focus&#8221;, 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.<\/p>\n<h3>Solution<\/h3>\n<p>The basis of the solution is to break the assumption of having only one focused window and integrate seat information in the event flow.<\/p>\n<p>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 <a href=\"https:\/\/github.com\/GENIVI\/wayland-ivi-extension\">Wayland IVI Extension project<\/a>.<\/p>\n<p>You can see a class diagram with the highlighted changes (blue: added, red: removed) below:<\/p>\n<p><a href=\"https:\/\/blogs.igalia.com\/jaragunde\/files\/2017\/06\/ozone-wayland-class-diagram-modified.png\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/blogs.igalia.com\/jaragunde\/files\/2017\/06\/ozone-wayland-class-diagram-modified-1024x955.png\" alt=\"\" width=\"584\" height=\"545\" class=\"alignnone size-large wp-image-756\" srcset=\"https:\/\/blogs.igalia.com\/jaragunde\/files\/2017\/06\/ozone-wayland-class-diagram-modified-1024x955.png 1024w, https:\/\/blogs.igalia.com\/jaragunde\/files\/2017\/06\/ozone-wayland-class-diagram-modified-300x280.png 300w, https:\/\/blogs.igalia.com\/jaragunde\/files\/2017\/06\/ozone-wayland-class-diagram-modified-768x716.png 768w, https:\/\/blogs.igalia.com\/jaragunde\/files\/2017\/06\/ozone-wayland-class-diagram-modified-322x300.png 322w, https:\/\/blogs.igalia.com\/jaragunde\/files\/2017\/06\/ozone-wayland-class-diagram-modified.png 1410w\" sizes=\"auto, (max-width: 584px) 100vw, 584px\" \/><\/a><\/p>\n<p>The multi-seat implementation of Ozone-Wayland described above is available in my <a href=\"https:\/\/github.com\/jaragunde\/ozone-wayland\">GitHub fork<\/a>, branch <a href=\"https:\/\/github.com\/jaragunde\/ozone-wayland\/tree\/wip\/multi-seat\">wip\/multi-seat<\/a>.<\/p>\n<h3>Testing it<\/h3>\n<p>Patches haven&#8217;t been merged yet into <a href=\"https:\/\/github.com\/GENIVI\/genivi-dev-platform\/\">genivi-dev-platform<\/a> master, but there is a <a href=\"https:\/\/github.com\/GENIVI\/genivi-dev-platform\/tree\/chromium\">chromium branch<\/a> with all the integration work so far. The last PR has been <a href=\"https:\/\/github.com\/GENIVI\/genivi-dev-platform\/pull\/93\">recently merged<\/a>, which includes multi-seat, patches to support the Salvator-X board and a backported fix for the Wayland IVI Extensions.<\/p>\n<p>You can already do your own builds by cloning the genivi-dev-platform <a href=\"https:\/\/github.com\/GENIVI\/genivi-dev-platform\/tree\/chromium\">chromium branch<\/a>. Then, just follow the <a href=\"https:\/\/at.projects.genivi.org\/wiki\/display\/GDP\/GDP+Master\">GDP instructions<\/a>. 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.<\/p>\n<p>If you are building your own HMI controller, you have to use the <a href=\"https:\/\/at.projects.genivi.org\/wiki\/display\/PROJ\/Wayland+IVI+Extension+Design#WaylandIVIExtensionDesign-Interfaces\">Wayland IVI Extension APIs<\/a> to properly setup the screens, layers, surfaces and seat assignment. Seat configuration is done <a href=\"https:\/\/at.projects.genivi.org\/wiki\/display\/WIE\/10.+Getting+Started+with+new+Input+Handling+APIs\">via udev<\/a> (see <em>Advanced use<\/em>). For testing purposes, you may want to use the <code>LayerManagerControl<\/code> 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.<\/p>\n<p>In first place, this is my udev configuration to create the seats, in the file <code>\/etc\/udev\/rules.d\/seats.rules<\/code>. Touchscreens are identified with their physical USB address because they are the same brand and model:<\/p>\n<pre><code>ATTRS{name}==\"Dell Dell USB Keyboard\", ENV{WL_SEAT}=\"seat_1\"\nATTRS{name}==\"Logitech USB Keyboard\", ENV{WL_SEAT}=\"seat_2\"\n\nATTRS{phys}==\"usb-ee0a0100.usb-1.1\/input0\", ENV{WL_SEAT}=\"seat_1\", ENV{WL_OUTPUT}=\"VGA-1\"\nATTRS{phys}==\"usb-ee0a0100.usb-1.2\/input0\", ENV{WL_SEAT}=\"seat_2\", ENV{WL_OUTPUT}=\"HDMI-A-1\"\n<\/code><\/pre>\n<p>To manage layers, surfaces and focus on my own, I had to stop the GENIVI HMI:<\/p>\n<pre><code>systemctl --user stop gdp-new-hmi\n<\/code><\/pre>\n<p>I started by setting up one layer for each screen, with sizes that match the screen resolutions:<\/p>\n<pre><code>LayerManagerControl create layer 1000 1024 768\nLayerManagerControl set layer 1000 visibility 1\nLayerManagerControl set screen 0 render order 1000\n\nLayerManagerControl create layer 2000 1280 720\nLayerManagerControl set layer 2000 visibility 1\nLayerManagerControl set screen 1 render order 2000\n<\/code><\/pre>\n<p>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:<\/p>\n<pre><code>LayerManagerControl set surface 7001 visibility 1\nLayerManagerControl set surface 7001 source region 0 0 1728 1080\nLayerManagerControl set surface 7001 destination region 0 0 1024 768\n\nLayerManagerControl set surface 7002 visibility 1\nLayerManagerControl set surface 7002 source region 0 0 1728 1080\nLayerManagerControl set surface 7002 destination region 0 0 1280 720\n\nLayerManagerControl set layer 1000 render order 7001\nLayerManagerControl set layer 2000 render order 7002\n<\/code><\/pre>\n<p>Finally, configured seat acceptances for each surface to receive events from only one seat, and gave keyboard focus to both:<\/p>\n<pre><code>LayerManagerControl set surface 7001 input acceptance to seat_1\nLayerManagerControl set surface 7002 input acceptance to seat_2\nLayerManagerControl set surfaces 7001,7002 input focus keyboard\n<\/code><\/pre>\n<p>This work is performed by <a href=\"https:\/\/www.igalia.com\/\">Igalia<\/a> and has been made possible by the funding provided by the <a href=\"https:\/\/www.genivi.org\/\">GENIVI Alliance<\/a> through the Challenge Grant Program. Thank you!<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/blogs.igalia.com\/jaragunde\/files\/2017\/01\/GENIVI_Black_Logo-no_background-300x263.png\" alt=\"GENIVI logo\" width=\"300\" height=\"263\" class=\"aligncenter size-medium wp-image-681\" srcset=\"https:\/\/blogs.igalia.com\/jaragunde\/files\/2017\/01\/GENIVI_Black_Logo-no_background-300x263.png 300w, https:\/\/blogs.igalia.com\/jaragunde\/files\/2017\/01\/GENIVI_Black_Logo-no_background-342x300.png 342w, https:\/\/blogs.igalia.com\/jaragunde\/files\/2017\/01\/GENIVI_Black_Logo-no_background.png 500w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/p>\n","protected":false},"excerpt":{"rendered":"<p>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 &hellip; <a href=\"https:\/\/blogs.igalia.com\/jaragunde\/2017\/06\/genivi-fying-chromium-part-3-multi-seat\/\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":17,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[22,23,24,3],"tags":[26,25],"class_list":["post-754","post","type-post","status-publish","format-standard","hentry","category-automotive","category-browsers","category-chromium","category-igalia","tag-chromium-on-genivi","tag-genivi"],"_links":{"self":[{"href":"https:\/\/blogs.igalia.com\/jaragunde\/wp-json\/wp\/v2\/posts\/754","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blogs.igalia.com\/jaragunde\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blogs.igalia.com\/jaragunde\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blogs.igalia.com\/jaragunde\/wp-json\/wp\/v2\/users\/17"}],"replies":[{"embeddable":true,"href":"https:\/\/blogs.igalia.com\/jaragunde\/wp-json\/wp\/v2\/comments?post=754"}],"version-history":[{"count":18,"href":"https:\/\/blogs.igalia.com\/jaragunde\/wp-json\/wp\/v2\/posts\/754\/revisions"}],"predecessor-version":[{"id":1127,"href":"https:\/\/blogs.igalia.com\/jaragunde\/wp-json\/wp\/v2\/posts\/754\/revisions\/1127"}],"wp:attachment":[{"href":"https:\/\/blogs.igalia.com\/jaragunde\/wp-json\/wp\/v2\/media?parent=754"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.igalia.com\/jaragunde\/wp-json\/wp\/v2\/categories?post=754"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.igalia.com\/jaragunde\/wp-json\/wp\/v2\/tags?post=754"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}