Раздвоение личности или еще раз о MultiseatX

в 15:01, , рубрики: linux, multihead, xen, виртуализация, Настольные компьютеры

Хочу рассказать одну историю успеха, произошедшую в моей семье.

Как известно, производительность типичного домашнего компьютера, даже без дорогих компонентов уже настолько высока, что для обычной «офисной» работы его хватает с большим запасом, так что идея сделать один компьютер с несколькими терминалами родилась сама собой. И тут я задумался: а что насчет игр? Ведь на домашнем компьютере, в отличии от офисного обычно еще и играют.

И если сделать multiseat для офисного применения очень просто, а также существует много способов (начиная от терминального подключения к серверу, заканчивая запуском нескольких виртуальных машин с жесткой ассоциацией локального железа с ними).
Когда-то, очень давно, меня посещала эта идея, но в то время в компьютерах еще был разъем AGP, который не подразумевал установку более одной полноценной видеокарты. Сейчас в ходу PCIe, а материнской платой с несколькими разъёмами PCIe никого не удивишь, так что проблема с установкой нескольких полноценных видеокарт уже не стоит.

Так что ограничений по линии железа нет(хотя подводные камни есть, их я опишу позже), осталось разобраться какой софт для этого использовать.
Последние 8 лет на моем домашнем компьютере установлена Linux, так что я буду использовать ее, конкретно — kubuntu, но для интереса поискал решения для Windows. Судя по отзывам, программа АСТЕР позволяет это сделать, но я пока не тестировал ее, так что конкретно сказать не могу. Кстати ПО платное — около 2000 руб. Не забыт также Windows MultiPoint Server, но видео там не используешь. Делать это на OS X как минимум нецелесообразно из-за цены, как максимум из-за того что просто нет компьютеров Apple с мощной игровой графикой (даже две самые мощные FirePro последнего Mac Pro проигрывают одной GTX780).

Итак, первой идеей было использовать гипервизор XEN.

XEN

Идея была такая: в dom0 работает Linux, на нем сразу же нативно играют, в domU пробрасывается видеокарта, USB-контроллер и там уже можно запускать что угодно, интереснее конечно же Windows. Задумано — сделано!

Для работы xen нужна материнская плата и процессор с поддержкой VT-d, процессор у меня уже был — Core i5-2500, а плату так или иначе пришлось бы менять, так как она была mini-ITX и соответственно всего с одним разъемом PCIe. Со списками карт, поддерживающими VT-d большие проблемы, так что гуглить придется конкретно для каждой модели, которая есть в магазине. Скажу только что платы MSI почти все не поддерживают VT-d, ASRock показалось что чаще. В итоге выбор пал на ASRock H77 Pro4-M. Настоящей игровой карты у меня тогда не было, поэтому был куплен GeForce GTX780 от ASUS. Люблю необычные корпуса, поэтому купил стильный и компактный SilverStone SG-09.
Вот так выглядел компьютер после сборки:

Раздвоение личности или еще раз о MultiseatX

Пробрасываются лучше всего карты Radeon, поэтому для domU была куплена именно она.
Описывать настройку xen для pci-passtrough не буду по одной простой причине — не взлетело. Причина в том, что проприетарный драйвер nVidia не работает с xen. После запуска — просто черный экран. Хотел для теста запустить это дело хотя бы на встроенной в процессор карте, но та также не хотела запускаться с драйвером intel. Работал только vesa для интела и nouveau для нвидии, проверить можно было, но играть на этом никак нельзя. Так что эксперименты с xen были заброшены до лучших времен (как-никак возможность проброса видеокарты это скорее техническая случайность, работающая на энтузиазме разработчиков xen).

MultiseatX

MultiseatX — очень давняя возможность X-сервера привязываться к нужной видеокарте, появившаяся еще во времена PCI-видеокарт. После прихода AGP возможностей для ее использования было мало, разве что на нескольких выходах карт nVidia можно было запускать по отдельному X-серверу.
Хорошая инструкция есть тут.
Так как карта от ATI мне больше не была нужна, я заменил ее на мой старый GeForce GT 620. Особой необходимости в этом не было, но как русский человек, до сих пор верю в миф о том что ATI плохо работает в Linux. К тому же в случае двух карт nVidia они будут няшно отображаться обе в программе настройки.
На самом деле, настроить MultiseatX в такой конфигурации оказалось очень просто. Фактически, отредактировать надо всего 2 файла.

Итак, ставим карты, подключаем мониторы, клавиатуры, мыши, включаем компьютер. X-сервер без файла xorg.conf запустится на одной из карт. Не всегда это будет карта, которую выбрал BIOS, так что приготовьтесь сидеть за любым монитором. Либо можно подключиться удаленно по ssh.

Первое, что необходимо выяснить — это адреса устройств.
Начнем с видеокарт:

$ lspci |grep VGA
01:00.0 VGA compatible controller: NVIDIA Corporation GK110 [GeForce GTX 780] (rev a1)
02:00.0 VGA compatible controller: NVIDIA Corporation GF108 [GeForce GT 620] (rev a1)

Значащими для нас значениями будут 01:00.0 и 02:00.0 — это есть адреса карт на шине PCIe. Они не меняются и зависят только от физического разъёма PCIe на матплате, так что при перестановке карт их надо будет корректировать.
Далее — надо определить статические адреса устройств ввода. Почему-то в гайде ubuntu они используют адресацию по пути для клавиатур, а для мышек и вовсе «символические» пути к /dev/input/mouse*. Я крайне не рекомендую это, так как в таком случае при подключении клавиатуры к другому порту ее придется перепрописывать, а уж в каком порядке назначаться имена мышкам — известно только великому рандому. Так что единственно верным способом будет использовать настоящие статические пути в /dev/input/by-id/.

$ ls -l /dev/input/by-id/
итого 0
lrwxrwxrwx 1 root root  9 мая   18 14:33 usb-04f3_0103-event-if01 -> ../event7
lrwxrwxrwx 1 root root  9 мая   18 14:33 usb-04f3_0103-event-kbd -> ../event6
lrwxrwxrwx 1 root root  9 мая   18 14:33 usb-Logitech_USB_Laser_Mouse-event-mouse -> ../event2
lrwxrwxrwx 1 root root  9 мая   18 14:33 usb-Logitech_USB_Laser_Mouse-mouse -> ../mouse0
lrwxrwxrwx 1 root root  9 мая   18 14:33 usb-Microsoft_Microsoft®_Nano_Transceiver_v1.0-event-kbd -> ../event8
lrwxrwxrwx 1 root root  9 мая   18 14:33 usb-Microsoft_Microsoft®_Nano_Transceiver_v1.0-if01-event-mouse -> ../event9
lrwxrwxrwx 1 root root  9 мая   18 14:33 usb-Microsoft_Microsoft®_Nano_Transceiver_v1.0-if01-mouse -> ../mouse2
lrwxrwxrwx 1 root root 10 мая   18 14:33 usb-Microsoft_Microsoft®_Nano_Transceiver_v1.0-if02-event-kbd -> ../event10
lrwxrwxrwx 1 root root  6 мая   18 14:33 usb-Microsoft_Microsoft®_Nano_Transceiver_v1.0-if02-kbd -> ../js0
lrwxrwxrwx 1 root root  9 мая   18 14:33 usb-Razer_Razer_BlackWidow_2013-event-kbd -> ../event3
lrwxrwxrwx 1 root root  9 мая   18 14:33 usb-Razer_Razer_BlackWidow_2013-if01-event-kbd -> ../event4
lrwxrwxrwx 1 root root  9 мая   18 14:33 usb-Razer_Razer_BlackWidow_2013-if02-event-mouse -> ../event5
lrwxrwxrwx 1 root root  9 мая   18 14:33 usb-Razer_Razer_BlackWidow_2013-if02-mouse -> ../mouse1

В приведенном выше примере 2 клавиатуры и 2 мышки. Эти пути будут статичны и не будут меняться при перезагрузке или подключении в другой порт. Для мультимедийных клавиатур будут видеться как минимум 2 устройства — сама клавиатура и дополнительные клавиши. То же самое и для мышек с кнопками. Единственная странность — мышь с названием Microsoft_Microsoft®_Nano_Transceiver — просто беспроводная мышь, без кнопок, а создает аж 5 устройств. Возможно у них универсальный приемник на всю серию, чем и обуславливается наличие нескольких логических устройств. В нашем случае нужно только устройство, которое ссылается на mouse2.
Для того чтобы на всякий случай убедиться что есть что, можно запускать cat. При нажатии кнопок или движении мышки будут появляться символы на экране.

Можно приступать к созданию (ведь в современных дистрибутивах его давно нет) файла /etc/X11/xorg.conf. Я не буду здесь комментировать все опции, так как множество стандартных в данной конфигурации флагов уже описано в приведенном мной гайде ubuntu.com.

/etc/X11/xorg.conf
Section "ServerFlags"
    Option         "DefaultServerLayout" "seat0"
    Option         "AllowMouseOpenFail"  "true"
    Option         "AutoAddDevices"      "false"
    Option         "AutoEnableDevices"   "false"
    Option         "AllowEmptyInput"     "true"
    Option         "DontZap"             "false"
    Option         "AutoAddGPU"          "false"
    Option         "DontVTSwitch"        "false"
EndSection

Section "ServerLayout"
    Identifier     "seat0"
    Screen      0  "Screen0" 0 0
//Перечисляем все устройства ввода. Обычно это одна мышь(даже если она с кнопками) и две клавиатуры (сама клава и мультимедиа клавиши)
    InputDevice    "Mouse0" "CorePointer"
    InputDevice    "Keyboard0" "CoreKeyboard"
    InputDevice    "Keyboard1" "CoreKeyboard"
    Option         "Xinerama" "0"
EndSection
 
Section "ServerLayout"
    Identifier     "seat1"
    Screen      0  "Screen1" 0 0
    InputDevice    "Mouse1" "CorePointer"
    InputDevice    "Keyboard2" "CoreKeyboard"
    InputDevice    "Keyboard3" "CoreKeyboard"
    Option         "Xinerama" "0"
EndSection

Section "InputDevice"
    Identifier     "Mouse0"
    Driver         "mouse"
//Даже не знаю какая разница между протоколами. С этим все работает, включая дополнительные кнопки.
    Option         "Protocol" "ExplorerPS/2"
//Используем путь в /dev/input/by-id/ который ведет к какой-либо /dev/input/mouse* (смотрим листинг выше)
    Option         "Device" "/dev/input/by-id/usb-Logitech_USB_Laser_Mouse-mouse"
EndSection
 
#razer kbd:
Section "InputDevice"
    Identifier     "Keyboard0"
//Для клавиатур нужен этот драйвер. Работает все как обычно, никаких изменений.
    Driver         "evdev"
//Это сама клавиатура
    Option         "Device" "/dev/input/by-id/usb-Razer_Razer_BlackWidow_2013-event-kbd"
    Option         "XkbRules" "xorg"
    Option         "XkbModel" "evdev"
    Option         "XkbLayout" "us"
    Option         "GrabDevice" "yes"
EndSection

Section "InputDevice"
    Identifier     "Keyboard1"
    Driver         "evdev"
//Это ее дополнительные клавиши. Зачем нужны остальные устройства и почему клавиатура "видится" еще и как мышь - я не знаю.
    Option         "Device" "/dev/input/by-id/usb-Razer_Razer_BlackWidow_2013-if01-event-kbd"
    Option         "XkbRules" "xorg"
    Option         "XkbModel" "evdev"
    Option         "XkbLayout" "us"
    Option         "GrabDevice" "yes"
EndSection

Section "InputDevice"
    Identifier     "Mouse1"
    Driver         "mouse"
    Option         "Protocol" "ExplorerPS/2"
//Мышка слишком чувствительная, я решил сразу понизить ей сэнс тут.
    Option         "Sensitivity" "0.7"
    Option         "Device" "/dev/input/by-id/usb-Microsoft_Microsoft®_Nano_Transceiver_v1.0-if01-mouse"
EndSection
 
Section "InputDevice"
    Identifier     "Keyboard2"
    Driver         "evdev"
    Option         "Device" "/dev/input/by-id/usb-04f3_0103-event-kbd"
    Option         "XkbRules" "xorg"
    Option         "XkbModel" "evdev"
    Option         "XkbLayout" "us"
    Option         "GrabDevice" "yes"
EndSection

Section "InputDevice"
    Identifier     "Keyboard3"
    Driver         "evdev"
    Option         "Device" "/dev/input/by-id/usb-04f3_0103-event-if01"
    Option         "XkbRules" "xorg"
    Option         "XkbModel" "evdev"
    Option         "XkbLayout" "us"
    Option         "GrabDevice" "yes"
EndSection

//На самом деле эти секции мне сгенерировала программа настройки nvidia-settings, рекомендую и вам поступить так же
Section "Monitor"
    # HorizSync source: edid, VertRefresh source: edid
    Identifier     "Monitor0"
    VendorName     "Unknown"
    ModelName      "RX_ HD270 DVI"
    HorizSync       15.0 - 99.0
    VertRefresh     23.0 - 76.0
    Option      "CalcAlgorithm" "XServerPool"
    Option      "DPMS"
EndSection

Section "Monitor"
    # HorizSync source: unknown, VertRefresh source: unknown
    Identifier     "Monitor1"
    VendorName     "Unknown"
    ModelName      "HP L1955"
    HorizSync       0.0 - 0.0
    VertRefresh     0.0
    Option      "CalcAlgorithm" "XServerPool"
    Option      "DPMS"
EndSection

// Эту секцию тоже корректно генерирует nvidia-settings
Section "Device"
    Identifier     "Device0"
    Driver         "nvidia"
    VendorName     "NVIDIA Corporation"
    BoardName      "GeForce GTX 780"
//Адрес на шине. Обратите внимание на формат записи, он немного отличается от вывода lspci.
    BusID          "PCI:1:0:0"
EndSection

Section "Device"
    Identifier     "Device1"
    Driver         "nvidia"
    VendorName     "NVIDIA Corporation"
    BoardName      "GeForce GT 620"
    BusID          "PCI:2:0:0"
EndSection

//И эти секции генерируются
Section "Screen"
    Identifier     "Screen0"
    Device         "Device0"
    Monitor        "Monitor0"
    DefaultDepth    24
//Добавьте эту опцию и тиринга в opengl приложенииях с включенной синхронизацией не будет
    Option         "TripleBuffer" "true"
//Добавляем вкладки для регулировки частоты и скорости вращения вентилятора
    Option         "Coolbits" "5"
    SubSection     "Display"
        Depth       24
    EndSubSection
EndSection

Section "Screen"
    Identifier     "Screen1"
    Device         "Device1"
    Monitor        "Monitor1"
    DefaultDepth    24
    Option         "TripleBuffer" "True"
    Option         "Coolbits" "5"
    SubSection     "Display"
        Depth       24
    EndSubSection
EndSection

Остался всего один файл и настройки завершена:

/etc/lightdm/lightdm.conf

[LightDM]
minimum-display-number=0
minimum-vt=7

[SeatDefaults]
xserver-command=/usr/bin/X
user-session=kde-plasma
greeter-session=lightdm-kde-greeter
exit-on-failure=true

[Seat:0]
autologin-guest=false
autologin-user=gordon01
autologin-user-timeout=0
autologin-session=lightdm-autologin
xserver-layout=seat0

[Seat:1]
xserver-command=/usr/bin/X :1 -sharevts
xserver-layout=seat1

По нему все должно быть ясно сразу. Пишут что есть баг и в multi-seat конфигурациях нужен хотя бы один юзер с автологином.
И еще, сколько я ни экспериментировал, lightdm всегда запускает иксы на разных vt, поэтому при логине второго юзера vt переключается на 8й и у первого появляется черный экран с курсором. Решение — нажать ctrl+alt+F7.

Вобщем-то, все. Переключаемся на первую консоль, вводим

sudo service lightdm restart

Должны засветиться оба монитора. Логинимся и можно играть!

Подводные камни

  • Если будете ставить несколько мощных видеокарт — на забудьте о питании!
  • Современные настольные процессоры имеют не более 16 PCIe полос (англ. lane), поэтому на обычной настольной матплате будет всего один разъем с 16 полосами, а другие хоть и физически имеют размер 16-полосного, но имеют как максимум 8 полос. По-видимому, в зависимости от модели матплаты стоят разные мультиплексоры (те же что используютcя на двухпроцессорных видеокартах, вроде GTX690). На моей матплате 1 разъём на 16х, второй на 4х и последний на 1х. Но что самое удивительное — хоть у меня и процессор поддерживает только PCIe v2, даже его более чем достаточно! При игре в Dota 2 на максимальных настройках с разрешением 2560x1440 использование шины едва доходило до 50%. Слабая же карта не загружает и на 10, поэтому ей достаточно даже 1х. Так что советую особо не заморачиваться по этому поводу.

Раздвоение личности или еще раз о MultiseatX

А рабочую ширину шины и скорость передачи, здесь:

Раздвоение личности или еще раз о MultiseatX

  • pulseaudio. Он не запускается у второго пользователя. Решение проблемы — запустить как системный демон. Я так пробовал, работает, но не очень хорошо (сохраняет не все настройки, надо перезапускать вручную). Как запустить пульсу от нескольких юзеров — не знаю. Мне кажется, что проще избавиться от пульсы вообще.
  • Много игр от valve имеют проверку, запущена ли уже игра в виде lock-файла в /tmp. Очевидно, эта проверка глючит и не дает запустить игру второму пользователю. Решение — удалить lock-файл. Я уже написал в багтрекер доты.

Фото и видео

Напоследок, немного фото и видео рабочего решения:

Общий вид:
Раздвоение личности или еще раз о MultiseatX

Места отдельно:
Раздвоение личности или еще раз о MultiseatX

Раздвоение личности или еще раз о MultiseatX

Вот так мы спрятали провода, так что их совсем не видно:
Раздвоение личности или еще раз о MultiseatX

С маком для красоты:
Раздвоение личности или еще раз о MultiseatX

Видео:

Автор:

Источник


* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js