LINUX.ORG.RU

История изменений

Исправление geekless, (текущая версия) :

Ага, спасибо. Еще у меня есть просьба оценить нижеизложенное.

Я пытаюсь продумать механизм взаимодействия клиента с дисплеем таким образом, чтобы:

  • Рендеринг осуществлялся с максимальной производительностью при выводе на локальной машине.
  • Клиенту не нужно было заботиться о том, локальный дисплей или нет: если дисплей удаленный, команды рендеринга просто прозрачно для клиента форвардятся на удаленную машину.
  • Клиент мог пережить динамическое переконфигурирование дисплея: подключение и отключение мониторов, gpu, перезапуск драйверов и т.п., т.е. ситуации потери контекста рендеринга.

Для этого нам нужен промежуточный API, абстрагированный как от кишок реализации дисплея, так и от конкретного рисующего API. В рамках изложения условно назовём этот промежуточный API — XNext. Вот мои соображения:

В качестве примеров рисующего API я рассматриваю следующие: OpenGL и некий аналог XRender (обернутый в cairo). Можно умозрительно заменить XRender на Direct2D, например. В общем, это какое-то API, которое более понятно для типичного прикладного программиста, чем навороченный OGL.

Клиент обменивается не критичными к производительности данными с дисплейным сервером через сокет. XNext предоставляет следующие сущности клиенту:

Экраны (Screens). Это абстрактные сущности, служащие местом отображения данных. Каждый экран содержит один или несколкьо вьюпортов.

Вьюпорты (Viewports). Это области на экране, которые сопоставлены устройствам отображения графики, т.е. мониторам. Если у нас мультимониторная конфигурация с общим рабоим столом, у нас как раз будет несколько вьюпортов на одном экране.

Устройства (Devices). Это, собственно, GPU. С каждым экраном связано устройство. API позволяет приложению узнать: «если хочешь выводить графику на вот этот экран, используй вот такое устройство». Кроме того, могут быть устройства, не связанные с какими-либо экранами (предназначены только для вычислений, без показа результата на экране).

Вся эта конфигурация может меняться динамически. Вьюпорты могут менять расположение, появляться и исчезать. Устройство вместе с экраном может полностью «отвалиться», т.е. быть выключенным «на горячую» или просто пропасть в результате программного сбоя. Клиенту нужно быть к этому готовым.

Полотна (Canvases). Полотно — это хэндл для рендеринга графики на устройстве. Полотно привязано к устройству. Если устройство исчезает, полотно становится невалидным. Полотно имеет размеры (ширина и высота в пикселях) и, вероятно, еще какие-то аттрибуты. (Не уверен, относится ли формат хранения пикселей к полотну или к контексту рисования в нём.)

Полотно служит для следующего:

  • На полотне можно инициализировать контекст рисующего API и писать туда графику. На полотне также можно инициализировать контекст рисующего API и читать оттуда графику. При этом ввод и вывод полностью развязаны: например, один клиент может рисовать в полотно при помощи OpenGL, а другой использовать эти данные при помощи XRender. Таким образом, полотно служит абстракцией от способа рисования. Через 10 лет у нас для риcования могут использоваться совершенно новые API, но точкой их стыковки друг с другом будет служить всё так же полотно.
  • Клиент может послать полотну уведомление о изменении содержимого, и оно придёт всем клиентам, кто подписан на данное уведомление. (Аналог расширения DAMAGE в X11.) Основное предназначение этой фичи — возможность посылать в композитор уведомления о том, что следует обновить отображение.

Для инициализации рисующего API используется механизм, схожий с DRI2. То есть: клиент запрашивает у сервера имя библиотеки для рисования, загружает эту библиотеку, авторизуется у ядреного драйвера через обмен cookie и затем получает у сервера контекст рисования для полотна. После этого библиотека, в которой реализовано рисующее API, взаимодействует непосредственно с ядром, без необходимости обмениваться данными по сокету.

Если сервер находится на удаленной машине, он возвращает пустую строку вместо имени библиотеки. После этого клиент делает следующее: подгружает (стандартную, девайсо-независимую) библиотеку, которая предоставляет тот же самый API. Данная библиоткека прозрачно для клиента перенаправляет команды рисования через сокет на сервер. На сервере осуществляется вызор реальных функций рисования.

Итак, что получается. Для того, чтобы что-нибудь нарисовать, клиент после запуска делает делает следующее:

  • Получает ID устройства.
  • Запрашивает для данного устройства имя библиотеки, реализующей API рисования.
  • Загружает эту библиотеку в своё адресное пространство. Если сервер вернул пустое имя библиотеки, то загружает некоторую «стандартную» библиотеку.
  • Создаёт на устройстве полотно.
  • В рисующей библиотеке вызывает функцию для создания контекста на этом полотне.
  • Рисует в созданном контексте при помощи стандартного рисующего API.

Клиенту следует быть готовым, что контекст и полотно в любой момент могут стать невалидными. В этом случае он может заново получить ID устройства и переинициализировать библиотеку, полотно и контекст. (Сервер может иметь любые скрытые механизмы управления выводом графики. Например, отключить клиента от локального GPU и подключить удаленное GPU. Если клиент готов к динамической переконфигурации графического стека, он это переживёт.)

// Тут еще можно написать много буков о том, как это всё взаимодействует с оконной подсистемой и композитором, но наверное пока хватит.

Исходная версия geekless, :

Ага, спасибо. Еще у меня есть просьба оценить нижеизложенное.

Я пытаюсь продумать механизм взаимодействия клиента с дисплеем таким образом, чтобы:

  • Рендеринг осуществлялся с максимальной производительностью при выводе на локальной машине.
  • Клиенту не нужно было заботиться о том, локальный дисплей или нет: если дисплей удаленный, команды рендеринга просто прозрачно для клиента форвардятся на удаленную машину.
  • Клиент мог пережить динамическое переконфигурирование дисплея: подключение и отключение мониторов, gpu, перезапуск драйверов и т.п., т.е. ситуации потери контекста рендеринга.

Для этого нам нужен промежуточный API, абстрагированный как от кишок реализации дисплея, так и от конкретного рисующего API. В рамках изложения условно назовём этот промежуточный API — XNext. Вот мои соображения:

В качестве примеров рисующего API я рассматриваю следующие: OpenGL и некий аналог XRender (обернутый в cairo). Можно умозрительно заменить XRender на Direct2D, например. В общем, это какое-то API, которое более понятно для типичного прикладного программиста, чем навороченный OGL.

Клиент обменивается не критичными к производительности данными с дисплейным сервером через сокет. XNext предоставляет следующие сущности клиенту:

Экраны (Screens). Это абстрактные сущности, служащие местом отображения данных. Каждый экран содержит один или несколкьо вьюпортов.

Вьюпорты (Viewports). Это области на экране, которые сопоставлены устройствам отображения графики, т.е. мониторам. Если у нас мультимониторная конфигурация с общим рабоим столом, у нас как раз будет несколько вьюпортов на одном экране.

Устройства (Devices). Это, собственно, GPU. С каждым экраном связано устройство. API позволяет приложению узнать: «если хочешь выводить графику на вот этот экран, используй вот такое устройство». Кроме того, могут быть устройства, не связанные с какими-либо экранами (предназначены только для вычислений, без показа результата на экране).

Вся эта конфигурация может меняться динамически. Вьюпорты могут менять расположение, появляться и исчезать. Устройство вместе с экраном может полностью «отвалиться», т.е. быть выключенным «на горячую» или просто пропасть в результате программного сбоя. Клиенту нужно быть к этому готовым.

Полотна (Canvases). Полотно — это хэндл для рендеринга графики на устройстве. Полотно привязано к устройству. Если устройство исчезает, полотно становится невалидным. Полотно имеет размеры (ширина и высота в пикселях) и, вероятно, еще какие-то аттрибуты. (Не уверен, относится ли формат хранения пикселей к полотну или к контексту рисования в нём.)

Полотно служит для следующего:

  • На полотне можно инициализировать контекст рисующего API и писать туда графику. На полотне также можно инициализировать контекст рисующего API и читать оттуда графику. При этом ввод и вывод полностью развязаны: например, один клиент может рисовать в полотно при помощи OpenGL, а другой использовать эти данные при помощи XRender. Таким образом, полотно служит абстракцией от способа рисования. Через 10 лет у нас для риcования могут использоваться совершенно новые API, но точкой их стыковки друг с другом будет служить всё так же полотно.
  • Клиент может послать полотну уведомление о изменении содержимого, и оно придёт всем клиентам, кто подписан на данное уведомление. (Аналог расширения DAMAGE в X11.) Основное предназначение этой фичи — возможность посылать в композитор уведомления о том, что следует обновить отображение.

Для инициализации рисующего API используется механизм, схожий с DRI2. То есть: клиент запрашивает у сервера имя библиотеки для рисования, загружает эту библиотеку, авторизуется у ядреного драйвера через обмен cookie и затем получает у сервера контекст рисования для полотна. После этого библиотека, в которой реализовано рисующее API, взаимодействует непосредственно с ядром, без необходимости обмениваться данными по сокету.

Если сервер находится на удаленной машине, он возвращает пустую строку вместо имени библиотеки. После этого клиент делает следующее: подгружает (стандартную, девайсо-независимую) библиотеку, которая предоставляет тот же самый API. Данная библиоткека прозрачно для клиента перенаправляет команды рисования через сокет на сервер. На сервере осуществляется вызор реальных функций рисования.

Итак, что получается. Для того, чтобы что-нибудь нарисовать, клиент после запуска делает делает следующее:

  • Получает ID устройства.
  • Запрашивает для данного устройства имя библиотеки, реализующей API рисования.
  • Загружает эту библиотеку в своё адресное пространство. Если сервер вернул пустое имя библиотеки, то загружает некоторую «стандартную» библиотеку.
  • Создаёт на устройстве полотно.
  • В рисующей библиотеке вызывает функцию для создания контекста на этом полотне.
  • Рисует в созданном контексте при помощи стандартного рисующего API.

Клиенту следует быть готовым, что контекст и полотно в любой момоент могут стать невалидными. В этом случае он может заново получить ID устройства и переинициализировать библиотеку, полотно и контекст. (Сервер может иметь любые скрытые механизмы управления выводом графики. Например, отключить клиента от локального GPU и подключить удаленное GPU. Если клиент готов к динамической переконфигурации графического стека, он это переживёт.)

// Тут еще можно написать много буков о том, как это всё взаимодействует с оконной подсистемой и композитором, но наверное пока хватит.