#import "template.typ": *
#show: ams-article.with(
  title: [Render: от DRM до Высокоуровневых API и Display Server'ов в Linux],
  authors: (
    (
      name: "<NAME>",
      department: [CT M3235],
      organization: [Itmo University],
      location: [Russia, St. Petersburg],
      email: "<EMAIL>",
      url: "t.me/ne1mnn"
    ),
  ),
  abstract: [
    В современном мире 2D/3D графика и вычисления на выдеокарте занимают центральное место в различных сферах -- от игровой индустрии и пользовательских интерфейсов до моделирования физических процессов и машинного обучения. Однако, эффективный рендеринг и работа на видеокарте в Linux (в т.ч. Android), особенно в условиях постоянно развивающихся технологий, представляет собой сложную задачу, требующую глубокого понимания различных уровней абстракции – от драйверов и DRM (Direct Render Manager) до Display Server'ов и высокоуровневых API.
    
    В рамках моего доклада, я собираюсь обсудить ключевые проблемы и решения, связанные с рендерингом 2D и 3D графики в Linux. Основное внимание будет уделено изучению работы DRM как фундаментального элемента для эффективного взаимодействия между аппаратной и программной частями системы. Рассмотрим архитектуру и интерфейсы Display Server'ы, таких как X11, Wayland, Surface Flinger, в контексте современных графических требований, и какие возможности они открывают для разработчиков и пользователей.
    
    Кроме того, будет подробно рассмотренно взаимодействие этих компонентов с высокоуровневыми графическими API, такими как OpenGL и Vulkan, и как они способствуют повышению производительности и качества визуализации на различных уровнях абстракции.
    
    В моем докладе представлен комплексный анализ архитектуры и компонентов, с акцентом на их взаимосвязь и важность для создания эффективной графической экосистемы. Это позволит слушателям не только глубже понять технические аспекты рендеринга в Linux, но и оценить потенциал и перспективы данной области, а так же важность понимания ее устройства.
  ],
)

#outline(title: [Содержание], depth: 2, indent: true)

#pagebreak()
= Общие понятия, уровень аппаратного обеспечения
Графический процессор (GPU) является ключевым компонентом современных вычислительных систем, отвечая за обработку графической информации. Он выделяется своей способностью к параллельной обработке данных, благодаря чему находит применение не только в графических вычислениях, но и в области высокопроизводительных вычислений.

== Архитектура паралельных вычислений SIMD (GPU - SIMD)
*SIMD (Single Instruction, Multiple Data)* – это модель параллельных вычислений, используемая в компьютерной архитектуре. В этой модели одна и та же операция (инструкция) применяется параллельно к множеству элементов данных. Это позволяет достигать значительного ускорения вычислений за счет одновременной обработки нескольких данных одной инструкцией. Основная идея SIMD состоит в том, что множество операций, выполняемых над различными данными, могут быть инициированы одной командой, вместо того чтобы выполнять каждую операцию отдельно. Это особенно эффективно в задачах, где одинаковые операции нужно повторить для большого массива данных, например, при обработке изображений, звука или при выполнении научных расчетов.

*GPU как реализация SIMD*: Графические процессоры (GPU) представляют собой яркий пример архитектуры SIMD в действии. 
#align(center)[#image("images/fermi.png", width: 280pt)]

В контексте GPU, SIMD позволяет одновременно выполнять одну и ту же инструкцию на большом количестве пикселей или вершин, что является стандартной задачей в графическом рендеринге. На примере архитектуры, представленной выше, у нас есть множество мультипроцессоров, у каждого есть кэш второго уровня. Видеокарта может одновременно использовать все имеющиеся мультироцессоры, выполняя на каждом разные инструкции. Непосредственно подход SIMD реализуется внутри данных потоковых мультипроцессоров. Смотря на картинку выше, нетрудно описать реализацию, которая состоит в том, что на одном столбце можно выполнить какую-то одну операцию над различными данными, как и было сказано ранее. 

== Общая архитектура современных видеокарт
Современные видеокарты обладают сложной структурой, которая включает следующие компоненты:

+ Память: Видеокарты оснащены собственной памятью (чаще всего типа GDDR), которая используется для хранения текстур, буферов кадров и других графических данных. Быстродействие и объем памяти играют ключевую роль в производительности GPU.

+ Вычислительные Блоки: Состоят из множества маленьких, но мощных процессоров, обрабатывающих данные параллельно. Они способны выполнять различные операции, от простых математических вычислений до сложной обработки текстур.

+ Кеши: Как и в CPU, в GPU присутствуют кеши для ускорения доступа к данным. Они уменьшают задержку при доступе к часто используемым данным и повышают общую производительность.

== Связь GPU и CPU
Все приложения исполняются на центральных процессорах, но для некоторых вычислений и отображения изображений на физические устройства они использую видеокарты, таким образом необходим механизм для связи CPU и GPU. Для этого на физическом уровне существует системная шина шину, пример современной шины - PCI Express (PCIe). PCIe обеспечивает высокоскоростной канал для передачи данных между процессором и видеокартой, что критично для высокопроизводительных графических и вычислительных приложений. Современные стандарты PCIe позволяют передавать данные с очень высокой скоростью, что важно для задач, требующих интенсивного обмена данными между CPU и GPU.

== Программирование видеокарт
В конкретных приложениях видеокарты выполняют самые различные задачи и вычисления, например - физический просчет траектории полета огромного количества частиц, машинное обучение, вычисление реалистичного освещения больших 3D сцен, растеризация изображений. Для каждой задачи необходимы различные программы для видеокарт. Программирование GPU включает в себя несколько ключевых аспектов:
+ MMIO (Memory-Mapped I/O): Техника, позволяющая программам обращаться к устройствам, таким как GPU, используя стандартные операции чтения и записи в память. Это упрощает коммуникацию между CPU и GPU.
+ DMA (Direct Memory Access): Механизм, позволяющий переносить данные между памятью и GPU без непосредственного участия CPU, что существенно увеличивает скорость передачи данных и снижает нагрузку на процессор.
+ Шейдерные Программы: Программы, запускаемые непосредственно на GPU для обработки графики. Шейдеры могут быть написаны на специализированных языках, таких как GLSL (для OpenGL) или HLSL (для DirectX и Vulkan), и позволяют детально контролировать процесс рендеринга, создавая сложные визуальные эффекты и реалистичные изображения.

#pagebreak()
= Низкий уровень
== Прошлый взгляд на работу с видеокартой 
В классических Unix-системах, таких как X Window System, используемая ранее в Linux, процесс рендеринга был организован через сервер X (например, XFree86). Это был привилегированный пользовательский процесс, который отображал видеопамять в виртуальное адресное пространство пользователя. Сервер X действовал как посредник между приложениями и аппаратным обеспечением, обрабатывая графические запросы от клиентов и направляя их к видеоадаптеру.

*Архитектура и Рендеринг*: В этой архитектуре, сервер X взаимодействовал напрямую с аппаратным обеспечением для рендеринга изображений. Он управлял видеопамятью и обеспечивал основные графические операции, такие как рисование окон и управление вводом. Такой подход имел значительные недостатки: он был неэффективен с точки зрения производительности, особенно в условиях современных графических требований, и представлял ограничения в масштабируемости и безопасности.

#align(center)[#image("./images/Access_to_video_card_without_DRM.svg", width: 300pt)]

== KMS и DRI - DRM Linux Kernel Module
Современные требования к графической обработке и неэффективность старой архитектуры привели к разработке нового подхода, в основе которого лежит модуль ядра Linux - DRM (Direct Rendering Manager).

*DRM: Ключевые Компоненты и Архитектура*
+ KMS (Kernel Mode Setting): Эта функция DRM позволяет ядру управлять настройками видеоадаптера, такими как разрешение экрана и глубина цвета, обеспечивая повышенную производительность и безопасность.
+ DRI (Direct Rendering Infrastructure): DRI обеспечивает прямое взаимодействие между приложениями и аппаратным обеспечением графики, минуя сервер X. Это позволяет приложениям напрямую использовать ресурсы GPU, улучшая производительность и уменьшая задержки.

#align(center)[#image("./images/Access_to_video_card_with_DRM.svg")]

*Архитектура DRM*: DRM состоит из ядра и драйверов устройств, обеспечивающих интерфейс между аппаратным обеспечением и высокоуровневыми графическими стеками. Он управляет доступом к графическим ресурсам, обеспечивая эффективное распределение и изоляцию ресурсов между различными приложениями.

Модуль ядра Linux DRM включает в себя бесплатные драйверы с открытым исходным кодом для поддержки оборудования трех основных производителей графических процессоров для настольных компьютеров (AMD, NVIDIA и IntelЫ), а также растущего числа мобильных графических процессоров и систем на кристалле (SoC). Качество каждого драйвера сильно варьируется в зависимости от степени сотрудничества со стороны производителя и других факторов.

#pagebreak()
= Кроссплатформенная Абстрактные API для работы с видеокартой
Кроссплатформенные графические API, такие как OpenGL, Vulkan и CUDA, представляют собой абстрактные интерфейсы, позволяющие разработчикам создавать графические приложения, которые могут работать на различных устройствах и операционных системах. Эти API служат мостом между программным обеспечением и аппаратным обеспечением, облегчая разработку графических приложений, игр, и систем виртуализации.

== Задачи Кроссплатформенных Графических API
+ Унификация Разработки: Предоставление единого интерфейса для работы с графикой на разных платформах и устройствах, уменьшая необходимость в платформоспецифическом коде.
+ Абстракция от Аппаратного Обеспечения: Разработчики могут фокусироваться на создании графики, не беспокоясь о деталях конкретного графического оборудования.
+ Эффективность и Производительность: Эти API оптимизированы для максимальной производительности, позволяя приложениям лучше использовать возможности современных GPU.

== Связь DRM с OpenGL/Vulkan
Взаимодействие подобных абстрактных графических API с драйверами на Linux происходит через DRM. DRM обеспечивает эффективное взаимодействие между аппаратным и программным обеспечением, управляя такими вещами, как доступ к видеопамяти и устройствам вывода. В своб очередь, Графические драйверы, которые обеспечивают совместимость с конкретными видеокартами, играют важную роль в процессе. Они переводят инструкции от API в команды, которые может обработать GPU. На разных платформах эти драйверы могут взаимодействовать с аппаратным обеспечением по-разному, но API, как правило, предоставляют единый интерфейс для разработчиков.

== Пример использования OpenGL и DRM на низком уровне 
Рассмотрим простейшее пользовательское приложение, которое демонстрирует процесс инициализации и настройка контекста через DRM и использование OpenGL для рендеринга (использованы пользовательская библиотеки для работы с DRM - libdrm, OpenGL в современной модульной реализации Mesa 3D):

#import "@preview/codelst:1.0.0": sourcecode

*CMake проекта*
#sourcecode(```c
cmake_minimum_required(VERSION 3.16)
project(drm-example)

set(CMAKE_C_STANDARD 11)

add_executable(drm-example main.c)

find_package (PkgConfig REQUIRED)
pkg_check_modules(DRM REQUIRED libdrm)

target_link_libraries(drm-example ${DRM_LIBRARIES} gbm EGL GLESv2)
target_include_directories(drm-example PUBLIC ${DRM_INCLUDE_DIRS})
target_compile_options(drm-example PUBLIC ${DRM_CFLAGS_OTHER})
```)

*Структуры для хранение низкоуровневых примитивов*
#sourcecode(```c
static struct {
  int fd;
  drmModeModeInfo *mode;
  uint32_t crtc_id;
  uint32_t connector_id;
} drm;

static struct {
  struct gbm_device *dev;
  struct gbm_surface *surface;
} gbm;

static struct {
  EGLDisplay display;
  EGLConfig config;
  EGLContext context;
  EGLSurface surface;
  GLuint program;
  GLint modelviewmatrix, modelviewprojectionmatrix, normalmatrix;
  GLuint vbo;
  GLuint positionsoffset, colorsoffset, normalsoffset;
} gl;

struct drm_fb {
  struct gbm_bo *bo;
  uint32_t fb_id;
};
```)

*Инициализация*
+ Получим коннектор DRM, по средствам которого будет создано соединением с модулем DRM, установка разрешения выводимого изображения, вывод буффера с зарендереным изображением (`Framebuffer`) на экран:
  #sourcecode(```c
  drmModeRes *resources;
  drmModeConnector *connector = NULL;
  drmModeEncoder *encoder = NULL;
  int i, area;

  drm.fd = open("/dev/dri/card0", O_RDWR);

  if (drm.fd < 0) {
    printf("could not open drm device\n");
    return -1;
  }

  resources = drmModeGetResources(drm.fd);
  if (!resources) {
    printf("drmModeGetResources failed: %s\n", strerror(errno));
    return -1;
  }

  /* find a connected connector: */
  for (i = 0; i < resources->count_connectors; i++) {
    connector = drmModeGetConnector(drm.fd, resources->connectors[i]);
    if (connector->connection == DRM_MODE_CONNECTED) {
      /* it's connected, let's use this! */
      break;
    }
    drmModeFreeConnector(connector);
    connector = NULL;
  }

  if (!connector) {
    /* we could be fancy and listen for hotplug events and wait for
     * a connector..
     */
    printf("no connected connector!\n");
    return -1;
  }

  /* find prefered mode or the highest resolution mode: */
  for (i = 0, area = 0; i < connector->count_modes; i++) {
    drmModeModeInfo *current_mode = &connector->modes[i];

    if (current_mode->type & DRM_MODE_TYPE_PREFERRED) {
      drm.mode = current_mode;
    }

    int current_area = current_mode->hdisplay * current_mode->vdisplay;
    if (current_area > area) {
      drm.mode = current_mode;
      area = current_area;
    }
  }

  if (!drm.mode) {
    printf("could not find mode!\n");
    return -1;
  }

  /* find encoder: */
  for (i = 0; i < resources->count_encoders; i++) {
    encoder = drmModeGetEncoder(drm.fd, resources->encoders[i]);
    if (encoder->encoder_id == connector->encoder_id) break;
    drmModeFreeEncoder(encoder);
    encoder = NULL;
  }

  if (encoder) {
    drm.crtc_id = encoder->crtc_id;
  } else {
    uint32_t crtc_id = find_crtc_for_connector(resources, connector);
    if (crtc_id == 0) {
      printf("no crtc found!\n");
      return -1;
    }

    drm.crtc_id = crtc_id;
  }

  drm.connector_id = connector->connector_id;

  return 0;
  ```)

+ Инициализация поверхности, на которую будет выводиться изображение:
  #sourcecode(```c
  gbm.dev = gbm_create_device(drm.fd);

  gbm.surface = gbm_surface_create(gbm.dev, drm.mode->hdisplay,
                                   drm.mode->vdisplay, GBM_FORMAT_XRGB8888,
                                   GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING);
  if (!gbm.surface) {
    printf("failed to create gbm surface\n");
    return -1;
  }

  return 0;
  ```)

+ Инициализация контекста OpenGL, привязанная к поверхности, созданной раннее
  #sourcecode(```c
  EGLint major, minor, n;
  GLuint vertex_shader, fragment_shader;
  GLint ret;

  static const EGLint context_attribs[] = {EGL_CONTEXT_CLIENT_VERSION, 2,
                                           EGL_NONE};

  static const EGLint config_attribs[] =
      {
          EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
          EGL_BLUE_SIZE, 8,
          EGL_GREEN_SIZE, 8,
          EGL_RED_SIZE, 8,
          EGL_DEPTH_SIZE, 8,
          EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
          EGL_NONE
      };

  PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT =
      (void *)eglGetProcAddress("eglGetPlatformDisplayEXT");
  assert(eglGetPlatformDisplayEXT != NULL);

  gl.display = eglGetPlatformDisplayEXT(EGL_PLATFORM_GBM_KHR, gbm.dev, NULL);

  if (!eglInitialize(gl.display, &major, &minor)) {
    printf("failed to initialize\n");
    return -1;
  }

  printf("Using display %p with EGL version %d.%d\n", gl.display, major, minor);

  printf("EGL Version \"%s\"\n", eglQueryString(gl.display, EGL_VERSION));
  printf("EGL Vendor \"%s\"\n", eglQueryString(gl.display, EGL_VENDOR));
  printf("EGL Extensions \"%s\"\n", eglQueryString(gl.display, EGL_EXTENSIONS));

  if (!eglBindAPI(EGL_OPENGL_ES_API)) {
    printf("failed to bind api EGL_OPENGL_ES_API\n");
    return -1;
  }

  if (!eglChooseConfig(gl.display, config_attribs, &gl.config, 1, &n) ||
      n != 1) {
    printf("failed to choose config: %d\n", n);
    return -1;
  }

  gl.context =
      eglCreateContext(gl.display, gl.config, EGL_NO_CONTEXT, context_attribs);
  if (gl.context == NULL) {
    printf("failed to create context\n");
    return -1;
  }

  gl.surface = eglCreateWindowSurface(gl.display, gl.config, gbm.surface, NULL);
  if (gl.surface == EGL_NO_SURFACE) {
    printf("failed to create egl surface\n");
    return -1;
  }

  /* connect the context to the surface */
  eglMakeCurrent(gl.display, gl.surface, gl.surface, gl.context);

  printf("GL Extensions: \"%s\"\n", glGetString(GL_EXTENSIONS));

  return 0;
  ```)

+ Создаем буффер для рендера изображения:
  #sourcecode(```c
  static struct drm_fb *drm_fb_get_from_bo(struct gbm_bo *bo) {
    struct drm_fb *fb = gbm_bo_get_user_data(bo);
    uint32_t width, height, stride, handle;
    int ret;
  
    if (fb) return fb;
  
    fb = calloc(1, sizeof *fb);
    fb->bo = bo;
  
    width = gbm_bo_get_width(bo);
    height = gbm_bo_get_height(bo);
    stride = gbm_bo_get_stride(bo);
    handle = gbm_bo_get_handle(bo).u32;
  
    ret = drmModeAddFB(drm.fd, width, height, 24, 32, stride, handle, &fb->fb_id);
    if (ret) {
      printf("failed to create fb: %s\n", strerror(errno));
      free(fb);
      return NULL;
    }
  
    gbm_bo_set_user_data(bo, fb, drm_fb_destroy_callback);
  
    return fb;
  }
  
  bo = gbm_surface_lock_front_buffer(gbm.surface);
  fb = drm_fb_get_from_bo(bo);
  ```)

+ Изменяем размер созданного буффера, на размер соответсвующий поверхности полученного ранее коннектора:
  #sourcecode(```c
  /* set mode: */
  ret = drmModeSetCrtc(drm.fd, drm.crtc_id, fb->fb_id, 0, 0, &drm.connector_id, 1, drm.mode);
  if (ret) {
    printf("failed to set mode: %s\n", strerror(errno));
    return ret;
  }
  ```)

*Ц<NAME>*
Цикл рендера -- основной цикл приложения, в котором происходит вызов системных функций, шейдерных программ и тд. В цикле мы:
+ Инициируем рендер изображения в текущий буффер:
  #sourcecode(```c
  static void draw(uint32_t i) {
    /* clear current buffer with blue color */
    glClear(GL_COLOR_BUFFER_BIT);
    glClearColor(0.2f, 0.3f, 0.5f, 1.0f);

    /* other render stuff */
  }
  
  draw(i++);
  ```)
+ Выводим отрендеренный буффер на экран:
  #sourcecode(```c
  eglSwapBuffers(gl.display, gl.surface);
  ```)
+ Ставим активируем второй буффер для следующей итерации рендера (используется простейшая двойная буфферизация):
  #sourcecode(```c
  /* get new active buffer */
  next_bo = gbm_surface_lock_front_buffer(gbm.surface);
  fb = drm_fb_get_from_bo(next_bo);

  /* release last buffer to render on again: */
  gbm_surface_release_buffer(gbm.surface, bo);
  bo = next_bo;
  ```)
+ Инициируем физическое отображение активного буффера через коннектор:
  #sourcecode(```c
  static void page_flip_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec, void *data) {
    int *waiting_for_flip = data;
    *waiting_for_flip = 0;
  }
  
  ret = drmModePageFlip(drm.fd, drm.crtc_id, fb->fb_id,
                          DRM_MODE_PAGE_FLIP_EVENT, &waiting_for_flip);
  if (ret) {
    printf("failed to queue page flip: %s\n", strerror(errno));
    return -1;
  }

  while (waiting_for_flip) {
    ret = select(drm.fd + 1, &fds, NULL, NULL, NULL);
    if (ret < 0) {
      printf("select err: %s\n", strerror(errno));
      return ret;
    } else if (ret == 0) {
      printf("select timeout!\n");
      return -1;
    } else if (FD_ISSET(0, &fds)) {
      printf("user interrupted!\n");
      break;
    }

    drmEventContext evctx = {
      .version = DRM_EVENT_CONTEXT_VERSION,
      .page_flip_handler = page_flip_handler,
    };
    drmHandleEvent(drm.fd, &evctx);
  }
  ```)

  Таким образом мы ознакомились с базовым процессом рендера на Linux, используя для инициализации системы низкоуровневое API (`drm`), а для рендера высокооуровневое (`OpenGL`). Так же важно заметить, что наше приложение работает без дополнительных тяжеловесных абстракций в виде `Display Server`'а (о которых речь пойдет далее).

== Real world пример
Для более подробного ознакомления с процессом работы и возможностями выскооуровневых графических API можно ознакомится с еще одним примером -- созданная мной #link("https://github.com/sabitov-kirill/sculpto")[кросс-платформенная система рендера реалистичных 3D сцен], #link("https://github.com/sabitov-kirill/sculpto/blob/main/docs/images/sculpto_images.pdf")[архитектура проекта и примеры работы].

#align(center)[
  #image("./images/pathtracer_spheres.png", width: 300pt)
  #image("./images/normal_mapping_and_bloom_on.png", width: 300pt)
  #image("./images/render_pass_funal.png", width: 250pt)
]

#pagebreak()
= Абстракция в виде Display Server'а
*Display Server* — это компонент программного обеспечения, который управляет выводом графики на экран и взаимодействует с устройствами ввода, такими как клавиатура и мышь. Он играет роль посредника между приложениями и аппаратным обеспечением компьютера, обрабатывая графические запросы от приложений и преобразуя их в изображения на экране.

Основным отличием Display Server'ов от высокоуровневых графических API (OpenGL, Vulkan) явялется то, что они имеют разные аспекты графической архитектуры в компьютерных системах, каждый из которых выполняет уникальные функции.

*Функциональное Назначение*:
+ Display Server'ы: Они управляют выводом графики на экран и взаимодействием с устройствами ввода. Display Server'ы отвечают за управление окнами, обработку событий ввода от клавиатуры и мыши, а также за отрисовку графического интерфейса пользователя.
+ Графические API (OpenGL, Vulkan): Эти API предоставляют набор инструментов для непосредственного рендеринга графики, включая создание трехмерных сцен, обработку текстур, освещения и теней. Они не занимаются управлением оконами или вводом от пользователей, а сконцентрированы на рендеринге.

*Задачи, решение которых предоставляют Display Server'ы*:
+ Управление Окнами: Display Server'ы упрощают процесс создания и управления окнами, которые служат поверхностями для рендеринга. Они обрабатывают создание, перемещение, изменение размера и рендеринг окон, а также управление фокусом и стеком окон.
+ Обработка Ввода: Они получают и обрабатывают события ввода от клавиатуры, мыши и других устройств ввода, передавая эти события соответствующим приложениям.
+ Композитинг: Некоторые Display Server'ы, особенно в современных системах, выполняют композитинг окон, что позволяет создавать эффекты прозрачности, анимации и другие визуальные эффекты на уровне пользовательского интерфейса.
+ Интеграция с Системой: Display Server'ы обеспечивают важную интеграцию с другими частями системы, такими как системы безопасности, сетевые протоколы (для удаленного доступа к графическому интерфейсу) и многое другое.
+ Мультипользовательская Среда: В некоторых случаях, Display Server'ы позволяют поддерживать мультипользовательские сессии и удаленный доступ к графическим интерфейсам.

Так же стоит упомянуть, что Display Server'ы так же используют низкоуровневый API DRM, для выполнения приведеных выше задач. При использовании высокоуровневых API (OpenGL, Vulkan) с Display Server'ом второй является лишь прослойкой для организации процессы рендера, как и было сказано выше.

== Desktop X11 и Wayland
=== Архитектура и Особенности X Window System (X)

*Архитектура*
- Центральная Роль X Server: В традиционной архитектуре X Window System, X Server играет центральную роль, управляя всеми операциями отображения и ввода.
- Комплексность и Модульность: X охватывает широкий спектр функций, от управления ресурсами PCI до управления отображением и прямого рендеринга. Со временем, множество функций было вынесено из X Server в клиентские библиотеки и драйверы ядра.

*Особенности*
- Отсутствие Стандартизации: В X есть некоторые ограничения, такие как сложность реализации современных функций, например, композиции и управления вводом.
- Модульность. Со временем, функции X Windows System, такие как рендеринг шрифтов (Freetype и Fontconfig), управление памятью и непостредственный рендеринг (Direct Rendering Infrastructure), Display Management (XRandR), были перенесены из X Server в отдельные библиотеки и модули ядра, что привело к более модульной и гибкой архитектуре.

=== Архитектура и Особенности Wayland

*Архитектура*
- Сервер и Протокол Wayland является как новым протоколом дисплейного сервера, так и его реализацией. Wayland построен на компонентах, уже существующих в экосистеме Linux, может использовать графические приложения (клиенты), созданные для X Windows System.
- Упрощенная Архитектура: В отличие от X, Wayland упрощает многие процессы, предоставляя клиентам возможность управления своими окнами и содержимым.

*Особенности*
- Прямой Контроль и Рендеринг: Приложения в Wayland могут выделять собственные буферы и напрямую рендерить содержимое окон, используя аппаратное ускорение или качественные программные реализации.
- Упрощение Управления Окнами и Композиции: Управление окнами и композиция полностью осуществляются сервером, что снижает сложность и улучшает производительность за счет уменьшения переключений контекста.
- Фокус на Клиентских Приложениях: Wayland оставляет процесс рендеринга на стороне клиента, в то время как управление памятью и буферами осуществляется через системные интерфейсы.

#align(center)[
  #stack(dir: ltr,
    image("./images/x-architecture.png", height: 200pt),
    image("./images/wayland-architecture.png", height: 200pt)  
  )
  _Сравнение пайплайна обработки событий X Windows System и Wayland.
  Видно, что X Window System использует более сложную и многоуровневую архитектуру для обработки событий ввода, что может привести к большей задержке и увеличению сложности в обработке событий._
]

Таким образом *X Window System* является более старой и сложной системой с высокой степенью модульности и интеграции различных компонентов. Подходит для более сложных и многофункциональных систем. *Wayland* в свою очередь является более современный и упрощенный подход, сосредоточенный на улучшении производительности и упрощении архитектуры. Предоставляет клиентам больше контроля над рендерингом и управлением окнами. Wayland предлагает более современное и упрощенное решение для современных графических систем.

== Mobile Android Surface Flinger

Для мобильных устройств на системе Android (основанной на Linux) средствами компании Google разработан собственный Display Server -- Surface Flinger, оптимизированных для карманных устройств.

= Заключение
Мы рассмотрели ключевые аспекты и эволюцию системы рендеринга в Linux, начиная от низкоуровневых компонентов, таких как Direct Rendering Manager (DRM), до высокоуровневых графических API и Display Server'ов. 

Повторение ключевых особенностей:
1. *DRM и Его Роль*: DRM оказался важным звеном в цепочке рендеринга, обеспечивая эффективное взаимодействие между аппаратным обеспечением и программными компонентами системы. Эволюция DRM и его интеграция с графическими API, такими как OpenGL и Vulkan, позволила повысить производительность и эффективность графических операций в Linux.
2. *Высокоуровневые API*: OpenGL и Vulkan представляют собой ключевые инструменты для создания сложной графики и игр. Их развитие и адаптация к современным требованиям позволили разработчикам максимально использовать возможности современных GPU.
3. *Развитие Display Server'ов*: Мы обсудили эволюцию от X Window System к Wayland, подчеркнув, как изменения в архитектуре Display Server'ов отражают потребности современных графических систем. Wayland, предлагая более прямой и эффективный способ обработки графических данных и ввода пользователя, демонстрирует тенденции к упрощению и повышению производительности.
4. *Изменения в X Window System*: Вынесение различных модулей из X Server в отдельные библиотеки и компоненты способствовало упрощению системы, повышению ее модульности и улучшению взаимодействия с другими компонентами Linux-экосистемы.

В заключение, рассмотрение архитектуры и компонентов системы рендеринга в Linux демонстрирует ее динамичное развитие и адаптацию к меняющимся требованиям в области графических вычислений. Эти изменения не только повысили эффективность и производительность, но и открыли новые горизонты для разработчиков и пользователей системы.

#pagebreak()
= Ссылки
+ #link("https://dri.freedesktop.org/docs/drm/gpu/")[freedesctop.org]: GPU Driver Developer's Guide
+ <NAME>.: Linux Graphics Drivers: an Introduction
+ #link("https://en.wikipedia.org/wiki/Direct_Rendering_Manager")[wikipedia.org]: Direct Rendering Manager
+ #link("freedesctop.org")[freedesctop.org]: Direct Rendering Manager (DRM)
+ #link("https://wiki.archlinux.org/title/kernel_mode_setting")[ArchLinux Wiki]: Kernel mode setting
+ #link("https://unix.stackexchange.com/questions/733336/what-is-opengls-relationship-with-the-drm", "Informal topic about relationship between OpenGL and DRM")
