El Direct Rendering Manager ( DRM ) es un subsistema del kernel de Linux responsable de interactuar con las GPU de las tarjetas de video modernas . DRM expone una API que los programas de espacio de usuario pueden usar para enviar comandos y datos a la GPU y realizar operaciones como configurar el modo de pantalla. DRM se desarrolló por primera vez como el componente de espacio del kernel de la infraestructura de renderizado directo del servidor X , [1] pero desde entonces ha sido utilizado por otras alternativas de pila gráfica como Wayland y aplicaciones y bibliotecas independientes como SDL2 y Kodi .
Los programas de espacio de usuario pueden utilizar la API DRM para ordenar a la GPU que realice renderizado 3D y decodificación de vídeo acelerados por hardware , así como computación GPGPU .
El kernel de Linux ya tenía una API llamada fbdev , utilizada para administrar el framebuffer de un adaptador de gráficos , [2] pero no podía usarse para manejar las necesidades del moderno hardware de video basado en GPU con aceleración 3D. Estos dispositivos generalmente requieren configurar y administrar una cola de comandos en su propia memoria para enviar comandos a la GPU y también requieren administración de buffers y espacio libre dentro de esa memoria. [3] Inicialmente, los programas de espacio de usuario (como el Servidor X ) administraban directamente estos recursos, pero generalmente actuaban como si fueran los únicos con acceso a ellos. Cuando dos o más programas intentaron controlar el mismo hardware al mismo tiempo, y configurar sus recursos cada uno a su manera, la mayoría de las veces terminaron catastróficamente. [3]
El Direct Rendering Manager fue creado para permitir que múltiples programas utilicen recursos de hardware de video de manera cooperativa. [4] El DRM obtiene acceso exclusivo a la GPU y es responsable de inicializar y mantener la cola de comandos, la memoria y cualquier otro recurso de hardware. Los programas que desean utilizar la GPU envían solicitudes a DRM, que actúa como árbitro y se ocupa de evitar posibles conflictos.
El alcance de DRM se ha ampliado a lo largo de los años para cubrir más funciones que anteriormente manejaban los programas de espacio de usuario, como la gestión de framebuffer y la configuración de modo , objetos de memoria compartida y sincronización de memoria. [5] [6] Algunas de estas expansiones recibieron nombres específicos, como Graphics Execution Manager (GEM) o kernel mode-setting (KMS), y la terminología prevalece cuando se alude específicamente a la funcionalidad que proporcionan. Pero en realidad son partes de todo el subsistema DRM del núcleo.
La tendencia a incluir dos GPU en una computadora (una GPU discreta y otra integrada) generó nuevos problemas, como el cambio de GPU , que también debían resolverse en la capa DRM. Para igualar la tecnología Nvidia Optimus , DRM recibió capacidades de descarga de GPU, llamadas PRIME. [7]
El Direct Rendering Manager reside en el espacio del kernel , por lo que los programas del espacio de usuario deben utilizar llamadas al sistema del kernel para solicitar sus servicios. Sin embargo, DRM no define sus propias llamadas al sistema personalizadas. En cambio, sigue el principio de Unix de " todo es un archivo " para exponer las GPU a través del espacio de nombres del sistema de archivos, utilizando archivos de dispositivo bajo la /dev
jerarquía. Cada GPU detectada por DRM se denomina dispositivo DRM y se crea un archivo de dispositivo (donde X es un número secuencial) para interactuar con él. [8] [9] Los programas de espacio de usuario que quieran comunicarse con la GPU deben abrir este archivo y usar llamadas ioctl para comunicarse con DRM. Diferentes ioctls corresponden a diferentes funciones de la API DRM ./dev/dri/cardX
Se creó una biblioteca llamada libdrm para facilitar la interfaz de los programas del espacio de usuario con el subsistema DRM. Esta biblioteca es simplemente un contenedor que proporciona una función escrita en C para cada ioctl de la API DRM, así como constantes, estructuras y otros elementos auxiliares. [10] El uso de libdrm no sólo evita exponer la interfaz del kernel directamente a las aplicaciones, sino que presenta las ventajas habituales de reutilizar y compartir código entre programas.
DRM consta de dos partes: un "núcleo DRM" genérico y uno específico ("controlador DRM") para cada tipo de hardware compatible. [11] El núcleo DRM proporciona el marco básico donde se pueden registrar diferentes controladores DRM y también proporciona al espacio del usuario un conjunto mínimo de ioctls con funcionalidad común independiente del hardware. [8] Un controlador DRM, por otro lado, implementa la parte de la API que depende del hardware, específica del tipo de GPU que admite; debería proporcionar la implementación de los ioctl restantes no cubiertos por el núcleo DRM, pero también puede ampliar la API, ofreciendo ioctl adicionales con funcionalidad adicional solo disponible en dicho hardware. [8] Cuando un controlador DRM específico proporciona una API mejorada, el libdrm del espacio de usuario también se amplía con una biblioteca adicional libdrm- driver que puede ser utilizada por el espacio del usuario para interactuar con los ioctls adicionales.
El núcleo DRM exporta varias interfaces a aplicaciones de espacio de usuario, generalmente destinadas a ser utilizadas a través de libdrm
las funciones contenedoras correspondientes. Además, los controladores exportan interfaces específicas de dispositivos para que las utilicen controladores de espacio de usuario y aplicaciones compatibles con dispositivos a través de archivos ioctls y sysfs . Las interfaces externas incluyen: mapeo de memoria, administración de contexto, operaciones DMA , administración de AGP , control de vblank , administración de barreras, administración de memoria y administración de salida.
Hay varias operaciones (ioctls) en la API DRM que, por motivos de seguridad o por cuestiones de concurrencia, deben restringirse para ser utilizadas por un único proceso de espacio de usuario por dispositivo. [8] Para implementar esta restricción, DRM limita dichos ioctls para que solo sean invocados por el proceso considerado "maestro" de un dispositivo DRM, generalmente llamado DRM-Master . Solo uno de todos los procesos que tienen el nodo del dispositivo abierto tendrá su identificador de archivo marcado como maestro, específicamente el primero que llama a SET_MASTER ioctl. Cualquier intento de utilizar uno de estos ioctl restringidos sin ser el DRM-Master devolverá un error. Un proceso también puede renunciar a su rol maestro (y dejar que otro proceso lo adquiera) llamando al ioctl DROP_MASTER ./dev/dri/cardX
El Servidor X —o cualquier otro servidor de visualización— es comúnmente el proceso que adquiere el estado DRM-Master en cada dispositivo DRM que administra, generalmente cuando abre el nodo del dispositivo correspondiente durante su inicio, y mantiene estos privilegios durante toda la sesión gráfica hasta termina o muere.
Para los procesos restantes del espacio de usuario, existe otra forma de obtener el privilegio de invocar algunas operaciones restringidas en el dispositivo DRM llamada DRM-Auth . Básicamente es un método de autenticación contra el dispositivo DRM, con el fin de demostrarle que el proceso cuenta con la aprobación del DRM-Master para obtener dichos privilegios. El procedimiento consta de: [12] : 13
Debido al tamaño cada vez mayor de la memoria de video y la creciente complejidad de las API de gráficos como OpenGL , la estrategia de reinicializar el estado de la tarjeta gráfica en cada cambio de contexto era demasiado costosa en términos de rendimiento. Además, los escritorios Linux modernos necesitaban una forma óptima de compartir buffers fuera de la pantalla con el administrador de composición . Estos requisitos llevaron al desarrollo de nuevos métodos para gestionar los buffers de gráficos dentro del kernel. El Graphics Execution Manager (GEM) surgió como uno de estos métodos. [6]
GEM proporciona una API con primitivas de gestión de memoria explícitas . [6] A través de GEM, un programa de espacio de usuario puede crear, manejar y destruir objetos de memoria que viven en la memoria de video de la GPU. Estos objetos, llamados "objetos GEM", [14] son persistentes desde la perspectiva del programa del espacio de usuario y no necesitan recargarse cada vez que el programa recupera el control de la GPU. Cuando un programa de espacio de usuario necesita una porción de memoria de video (para almacenar un framebuffer , textura o cualquier otro dato requerido por la GPU [15] ), solicita la asignación al controlador DRM usando la API GEM. El controlador DRM realiza un seguimiento de la memoria de video utilizada y puede cumplir con la solicitud si hay memoria libre disponible, devolviendo un "identificador" al espacio del usuario para consultar aún más la memoria asignada en operaciones futuras. [6] [14] GEM API también proporciona operaciones para llenar el búfer y liberarlo cuando ya no sea necesario. La memoria de los identificadores GEM no publicados se recupera cuando el proceso del espacio de usuario cierra el descriptor de archivo del dispositivo DRM , intencionalmente o porque finaliza. [dieciséis]
GEM también permite que dos o más procesos de espacio de usuario que utilizan el mismo dispositivo DRM (por lo tanto, el mismo controlador DRM) compartan un objeto GEM. [16] Los identificadores GEM son enteros locales de 32 bits exclusivos de un proceso pero repetibles en otros procesos, por lo que no son adecuados para compartir. Lo que se necesita es un espacio de nombres global, y GEM proporciona uno mediante el uso de identificadores globales llamados nombres GEM . Un nombre GEM se refiere a uno, y solo uno, objeto GEM creado dentro del mismo dispositivo DRM por el mismo controlador DRM, utilizando un entero único de 32 bits . GEM proporciona una operación flink para obtener un nombre de GEM de un identificador de GEM. [16] [12] : 16 El proceso puede luego pasar este nombre GEM (entero de 32 bits) a otro proceso utilizando cualquier mecanismo IPC disponible. [12] : 15 El nombre GEM puede ser utilizado por el proceso destinatario para obtener un identificador GEM local que apunte al objeto GEM original.
Lamentablemente, el uso de nombres GEM para compartir buffers no es seguro. [12] : 16 [17] [18] Un proceso malicioso de terceros que acceda al mismo dispositivo DRM podría intentar adivinar el nombre GEM de un búfer compartido por otros dos procesos, simplemente sondeando números enteros de 32 bits. [19] [18] Una vez que se encuentra un nombre GEM, se puede acceder a su contenido y modificarlo, violando la confidencialidad e integridad de la información del buffer. Este inconveniente se superó más tarde con la introducción del soporte DMA-BUF en DRM, ya que DMA-BUF representa buffers en el espacio de usuario como descriptores de archivos, que pueden compartirse de forma segura .
Otra tarea importante para cualquier sistema de gestión de memoria de vídeo, además de gestionar el espacio de la memoria de vídeo, es gestionar la sincronización de la memoria entre la GPU y la CPU. Las arquitecturas de memoria actuales son muy complejas y normalmente implican varios niveles de cachés para la memoria del sistema y, a veces, también para la memoria de vídeo. Por lo tanto, los administradores de memoria de video también deben manejar la coherencia de la caché para garantizar que los datos compartidos entre la CPU y la GPU sean consistentes. [20] Esto significa que a menudo los componentes internos de administración de la memoria de video dependen en gran medida de los detalles del hardware de la GPU y la arquitectura de la memoria y, por lo tanto, son específicos del controlador. [21]
GEM fue desarrollado inicialmente por ingenieros de Intel para proporcionar un administrador de memoria de video para su controlador i915. [20] La familia Intel GMA 9xx son GPU integradas con una arquitectura de memoria uniforme (UMA), donde la GPU y la CPU comparten la memoria física y no hay una VRAM dedicada. [22] GEM define "dominios de memoria" para la sincronización de memoria, y si bien estos dominios de memoria son independientes de la GPU, [6] están diseñados específicamente con una arquitectura de memoria UMA en mente, lo que los hace menos adecuados para otras arquitecturas de memoria como aquellas con una VRAM separada. Por esta razón, otros controladores DRM han decidido exponer la API GEM a programas de espacio de usuario, pero internamente implementaron un administrador de memoria diferente, más adecuado para su hardware y arquitectura de memoria particulares. [23]
La API GEM también proporciona ioctls para controlar el flujo de ejecución (búferes de comandos), pero son específicos de Intel y se pueden usar con GPU Intel i915 y posteriores. [6] Ningún otro controlador DRM ha intentado implementar ninguna parte de la API GEM más allá de los ioctls específicos de gestión de memoria.
Translation Table Maps (TTM) es el nombre del administrador de memoria genérico para GPU que se desarrolló antes de GEM. [5] [14] Fue diseñado específicamente para administrar los diferentes tipos de memoria a los que puede acceder una GPU, incluida la RAM de video dedicada (comúnmente instalada en la tarjeta de video) y la memoria del sistema accesible a través de una unidad de administración de memoria de E/S llamada Gráficos. Tabla de reasignación de direcciones (GART). [5] TTM también debe manejar las porciones de la RAM de video que no son direccionables directamente por la CPU y hacerlo con el mejor rendimiento posible, considerando que las aplicaciones de gráficos en el espacio de usuario generalmente funcionan con grandes cantidades de datos de video. Otro asunto importante fue mantener la coherencia entre las diferentes memorias y cachés involucrados.
El concepto principal de TTM son los "objetos de búfer", regiones de la memoria de video que en algún momento deben ser direccionables por la GPU. [5] Cuando una aplicación de gráficos de espacio de usuario desea acceder a un determinado objeto de búfer (generalmente para llenarlo con contenido), TTM puede requerir reubicarlo en un tipo de memoria direccionable por la CPU. Podrían ocurrir más reubicaciones (u operaciones de mapeo GART) cuando la GPU necesita acceso a un objeto de búfer pero aún no está en el espacio de direcciones de la GPU. Cada una de estas operaciones de reubicación debe manejar cualquier problema de coherencia de caché y datos relacionados. [5]
Otro concepto importante de TTM son las vallas . Las barreras son esencialmente un mecanismo para gestionar la concurrencia entre la CPU y la GPU. [24] Una valla rastrea cuando la GPU ya no utiliza un objeto de búfer, generalmente para notificar a cualquier proceso del espacio de usuario con acceso a él. [5]
El hecho de que TTM intentara gestionar todo tipo de arquitecturas de memoria, incluidas aquellas con y sin VRAM dedicada, de manera adecuada, y proporcionar todas las funciones imaginables en un administrador de memoria para su uso con cualquier tipo de hardware, llevó a un proceso demasiado complejo. solución con una API mucho mayor de lo necesario. [24] [14] Algunos desarrolladores de DRM pensaron que no encajaría bien con ningún controlador específico, especialmente la API. Cuando GEM surgió como un administrador de memoria más simple, se prefirió su API a la TTM. Pero algunos desarrolladores de controladores consideraron que el enfoque adoptado por TTM era más adecuado para tarjetas de video discretas con memoria de video dedicada e IOMMU, por lo que decidieron usar TTM internamente, mientras exponían sus objetos de búfer como objetos GEM y, por lo tanto, admitían la API GEM. [23] Ejemplos de controladores actuales que utilizan TTM como administrador de memoria interna pero que proporcionan una API GEM son el controlador radeon para tarjetas de video AMD y el controlador nouveau para tarjetas de video NVIDIA.
La API DMA Buffer Sharing (a menudo abreviada como DMA-BUF) es una API interna del kernel de Linux diseñada para proporcionar un mecanismo genérico para compartir buffers DMA entre múltiples dispositivos, posiblemente administrados por diferentes tipos de controladores de dispositivos. [25] [26] Por ejemplo, un dispositivo Video4Linux y un dispositivo adaptador de gráficos podrían compartir buffers a través de DMA-BUF para lograr una copia cero de los datos de una secuencia de video producida por el primero y consumida por el segundo. Cualquier controlador de dispositivo Linux puede implementar esta API como exportador, como usuario (consumidor) o ambos.
Esta característica se aprovechó por primera vez en DRM para implementar PRIME, una solución para descarga de GPU que utiliza DMA-BUF para compartir los framebuffers resultantes entre los controladores DRM de la GPU discreta e integrada. [27] : 13 Una característica importante de DMA-BUF es que un búfer compartido se presenta al espacio del usuario como un descriptor de archivo . [14] [12] : 17 Para el desarrollo de PRIME se agregaron dos nuevos ioctls a la API DRM, uno para convertir un identificador GEM local en un descriptor de archivo DMA-BUF y otro para la operación exactamente opuesta.
Estos dos nuevos ioctl se reutilizaron posteriormente como una forma de solucionar la inseguridad inherente al uso compartido del buffer de GEM. [12] : 17 A diferencia de los nombres GEM, los descriptores de archivos no se pueden adivinar (no son un espacio de nombres global) y los sistemas operativos Unix proporcionan una forma segura de pasarlos a través de un socket de dominio Unix utilizando la semántica SCM_RIGHTS. [14] [28] : 11 Un proceso que desea compartir un objeto GEM con otro proceso puede convertir su identificador GEM local en un descriptor de archivo DMA-BUF y pasarlo al destinatario, que a su vez puede obtener su propio identificador GEM de el descriptor del archivo recibido. [12] : 16 Este método lo utiliza DRI3 para compartir buffers entre el cliente y el servidor X [29] y también Wayland .
Para funcionar correctamente, una tarjeta de video o un adaptador de gráficos debe configurar un modo (una combinación de resolución de pantalla , profundidad de color y frecuencia de actualización ) que esté dentro del rango de valores admitidos por ella misma y la pantalla adjunta . Esta operación se llama configuración de modo , [30] y generalmente requiere acceso sin formato al hardware de gráficos, es decir, la capacidad de escribir en ciertos registros del controlador de visualización de la tarjeta de video . [31] [32] Se debe realizar una operación de configuración de modo antes de comenzar a utilizar el framebuffer , y también cuando una aplicación o el usuario requieran cambiar el modo.
Al principio, los programas de espacio de usuario que querían utilizar el framebuffer gráfico también eran responsables de proporcionar las operaciones de configuración de modo [3] y, por lo tanto, necesitaban ejecutarse con acceso privilegiado al hardware de vídeo. En los sistemas operativos tipo Unix, el servidor X fue el ejemplo más destacado, y su implementación de configuración de modo residía en el controlador DDX para cada tipo específico de tarjeta de video. [33] Este enfoque, más tarde denominado Configuración de modo del espacio de usuario o UMS, [34] [35] plantea varios problemas. [36] [30] No solo rompe el aislamiento que los sistemas operativos deberían proporcionar entre los programas y el hardware, generando preocupaciones tanto de estabilidad como de seguridad, sino que también podría dejar el hardware de gráficos en un estado inconsistente si dos o más programas de espacio de usuario intentan hacer el modo de configuración al mismo tiempo. Para evitar estos conflictos, el Servidor X se convirtió en la práctica en el único programa espacial de usuario que realizaba operaciones de configuración de modo; el resto de los programas de espacio de usuario dependían del servidor X para establecer el modo apropiado y para manejar cualquier otra operación que involucrara la configuración del modo. Inicialmente, la configuración del modo se realizaba exclusivamente durante el proceso de inicio del Servidor X, pero luego el Servidor X obtuvo la capacidad de hacerlo mientras se ejecuta. [37] La extensión XFree86-VidModeExtension se introdujo en XFree86 3.1.2 para permitir que cualquier cliente X solicite cambios en el modelo (resolución) al servidor X. [38] [39] La extensión VidMode fue reemplazada posteriormente por la extensión XRandR, más genérica .
Sin embargo, este no fue el único código que configura el modo en un sistema Linux . Durante el proceso de inicio del sistema, el kernel de Linux debe establecer un modo de texto mínimo para la consola virtual (basado en los modos estándar definidos por las extensiones VESA BIOS ). [40] Además, el controlador framebuffer del kernel de Linux contenía código de configuración de modo para configurar dispositivos framebuffer. [2] Para evitar conflictos de configuración de modo, el servidor XFree86 (y más tarde el servidor X.Org) manejó el caso en el que el usuario cambiaba del entorno gráfico a una consola virtual de texto guardando su estado de configuración de modo y restaurándolo cuando el usuario volvió a cambiar a X. [41] Este proceso causó un parpadeo molesto en la transición y también puede fallar, lo que lleva a una pantalla de salida corrupta o inutilizable. [42]
El enfoque de configuración del modo de espacio de usuario también causó otros problemas: [43] [42]
Para solucionar estos problemas, el código de configuración de modo se movió a un solo lugar dentro del kernel, específicamente al módulo DRM existente. [36] [37] [44] [42] [43] Entonces, cada proceso, incluido el servidor X, debería poder ordenar al kernel que realice operaciones de configuración de modo, y el kernel garantizaría que las operaciones concurrentes no lo hagan. resulta en un estado inconsistente. La nueva API del kernel y el código agregado al módulo DRM para realizar estas operaciones de configuración de modo se llamaron Kernel Mode-Setting (KMS). [30]
La configuración del modo kernel proporciona varios beneficios. El más inmediato es, por supuesto, la eliminación del código de configuración de modo duplicado, tanto del kernel (consola Linux, fbdev) como del espacio del usuario (controladores DDX del servidor X). KMS también facilita la escritura de sistemas gráficos alternativos, que ahora no necesitan implementar su propio código de configuración de modo. [42] [43] Al proporcionar administración de modo centralizada, KMS resuelve los problemas de parpadeo al cambiar entre la consola y X, y también entre diferentes instancias de X (cambio rápido de usuario). [41] [44] Dado que está disponible en el kernel, también se puede utilizar al comienzo del proceso de arranque, ahorrando parpadeos debido a cambios de modo en estas primeras etapas.
El hecho de que KMS sea parte del kernel le permite utilizar recursos que sólo están disponibles en el espacio del kernel, como las interrupciones . [45] Por ejemplo, el modo de recuperación después de un proceso de suspensión/reanudación se simplifica mucho al ser administrado por el propio kernel y, de paso, mejora la seguridad (no más herramientas de espacio de usuario que requieren permisos de root). El kernel también permite la conexión en caliente de nuevos dispositivos de visualización fácilmente, resolviendo un problema de larga data. [45] La configuración de modo también está estrechamente relacionada con la gestión de la memoria, ya que los framebuffers son básicamente buffers de memoria, por lo que se recomienda encarecidamente una estrecha integración con el administrador de memoria de gráficos. Esa es la razón principal por la que el código de configuración del modo del kernel se incorporó a DRM y no como un subsistema separado. [44]
Para evitar romper la compatibilidad con versiones anteriores de la API DRM, la configuración del modo kernel se proporciona como una característica adicional del controlador de ciertos controladores DRM. [46] Cualquier controlador DRM puede optar por proporcionar el indicador DRIVER_MODESET cuando se registra con el núcleo DRM para indicar que admite la API KMS. [8] Aquellos controladores que implementan la configuración del modo Kernel a menudo se denominan controladores KMS como una forma de diferenciarlos de los controladores DRM heredados, sin KMS.
KMS se ha adoptado hasta tal punto que ciertos controladores que carecen de aceleración 3D (o para los cuales el proveedor de hardware no quiere exponerla o implementarla) implementan la API KMS sin el resto de la API DRM, lo que permite servidores de visualización (como Wayland ) para correr con facilidad. [47] [48]
KMS modela y administra los dispositivos de salida como una serie de bloques de hardware abstractos que se encuentran comúnmente en el canal de salida de un controlador de pantalla . Estos bloques son: [49]
En los últimos años, ha habido un esfuerzo continuo para brindar atomicidad a algunas operaciones regulares relacionadas con la API de KMS, específicamente a las operaciones de configuración de modo y cambio de página . [33] [52] Esta API KMS mejorada es lo que se llama visualización atómica (anteriormente conocida como configuración de modo atómico y cambio de página atómico o nuclear ).
El propósito de la configuración del modo atómico es garantizar un cambio de modo correcto en configuraciones complejas con múltiples restricciones, evitando pasos intermedios que podrían conducir a un estado de video inconsistente o no válido; [52] también evita estados de vídeo riesgosos cuando es necesario deshacer ("revertir") un proceso fallido de configuración de modo. [53] : 9 La configuración del modo atómico permite saber de antemano si cierta configuración de modo específica es apropiada, proporcionando capacidades de prueba de modo. [52] Cuando se prueba un modo atómico y se confirma su validez, se puede aplicar con una única operación de confirmación indivisible (atómica) . Tanto las operaciones de prueba como las de confirmación las proporciona el mismo ioctl nuevo con diferentes indicadores.
Por otro lado , el cambio de página atómico permite actualizar múltiples planos en la misma salida (por ejemplo, el plano primario, el plano del cursor y tal vez algunas superposiciones o planos secundarios), todos sincronizados dentro del mismo intervalo VBLANK , lo que garantiza una visualización adecuada sin desgarros. [53] : 9,14 [52] Este requisito es especialmente relevante para los controladores de pantalla móviles e integrados, que tienden a utilizar múltiples planos/superposiciones para ahorrar energía.
La nueva API atómica se basa en la antigua API KMS. Utiliza el mismo modelo y objetos (CRTC, codificadores, conectores, planos, ...), pero con un número cada vez mayor de propiedades de objetos que se pueden modificar. [52] El procedimiento atómico se basa en cambiar las propiedades relevantes para construir el estado que queremos probar o confirmar. Las propiedades que queremos modificar dependen de si queremos realizar una configuración de modo (principalmente propiedades de CRTC, codificadores y conectores) o pasar página (generalmente propiedades de planos). El ioctl es el mismo para ambos casos, la diferencia es la lista de propiedades pasadas con cada uno. [54]
En la API DRM original, el dispositivo DRM se utiliza para operaciones tanto privilegiadas (configuración de modo, otros controles de visualización) como no privilegiadas (renderizado, cálculo GPGPU ). [9] Por razones de seguridad, abrir el archivo del dispositivo DRM asociado requiere privilegios especiales "equivalentes a privilegios de root". [55] Esto conduce a una arquitectura donde sólo algunos programas de espacio de usuario confiables (el servidor X, un compositor gráfico, ...) tienen acceso completo a la API DRM, incluidas las partes privilegiadas como la API modeset. Otras aplicaciones de espacio de usuario que quieran renderizar o realizar cálculos GPGPU deben ser autorizadas por el propietario del dispositivo DRM ("DRM Master") mediante el uso de una interfaz de autenticación especial. [56] Luego, las aplicaciones autenticadas pueden representar o realizar cálculos utilizando una versión restringida de la API DRM sin operaciones privilegiadas. Este diseño impone una restricción severa: siempre debe haber un servidor de gráficos en ejecución (el servidor X, un compositor Wayland, ...) que actúe como DRM-Master de un dispositivo DRM para que otros programas de espacio de usuario puedan tener el uso del dispositivo, incluso en casos que no impliquen ninguna visualización de gráficos como cálculos GPGPU. [55] [56]/dev/dri/cardX
El concepto de "nodos de representación" intenta resolver estos escenarios dividiendo la API del espacio de usuario DRM en dos interfaces (una privilegiada y otra no privilegiada) y utilizando archivos de dispositivo (o "nodos") separados para cada una. [9] Para cada GPU encontrada, su controlador DRM correspondiente (si admite la función de nodos de procesamiento) crea un archivo de dispositivo , llamado nodo de procesamiento , además del nodo principal . [56] [9] Los clientes que utilizan un modelo de renderizado directo y las aplicaciones que desean aprovechar las funciones informáticas de una GPU, pueden hacerlo sin requerir privilegios adicionales simplemente abriendo cualquier nodo de renderizado existente y enviando operaciones de GPU usando el subconjunto limitado. de la API DRM admitida por esos nodos, siempre que tengan permisos del sistema de archivos para abrir el archivo del dispositivo. Los servidores de visualización, compositores y cualquier otro programa que requiera la API modeset o cualquier otra operación privilegiada deben abrir el nodo primario estándar que otorga acceso a la API DRM completa y usarlo como de costumbre. Los nodos de renderizado no permiten explícitamente la operación flink de GEM para evitar que se comparta el búfer utilizando nombres globales de GEM inseguros; Sólo se pueden utilizar descriptores de archivos PRIME (DMA-BUF) para compartir buffers con otro cliente, incluido el servidor de gráficos. [9] [56]/dev/dri/renderDX
/dev/dri/cardX
El subsistema DRM de Linux incluye controladores gratuitos y de código abierto para soportar hardware de los 3 principales fabricantes de GPU para computadoras de escritorio (AMD, NVIDIA e Intel), así como de un número creciente de GPU y sistemas en un chip (SoC) móviles. integradores. La calidad de cada conductor varía mucho, dependiendo del grado de cooperación del fabricante y otros asuntos.
También hay una serie de controladores para hardware antiguo y obsoleto que se detallan en la siguiente tabla con fines históricos.
Direct Rendering Manager se desarrolla dentro del kernel de Linux y su código fuente reside en el /drivers/gpu/drm
directorio del código fuente de Linux. El mantenedor del subsistema es Dave Airlie, y otros mantenedores se encargan de controladores específicos. [127] Como es habitual en el desarrollo del kernel de Linux, los submantenedores y contribuyentes de DRM envían sus parches con nuevas características y correcciones de errores al mantenedor principal de DRM, que los integra en su propio repositorio de Linux . El mantenedor de DRM, a su vez, envía todos estos parches que están listos para incorporarse a Linus Torvalds cada vez que se lanza una nueva versión de Linux. Torvalds, como principal mantenedor de todo el kernel, tiene la última palabra sobre si un parche es adecuado o no para su inclusión en el kernel.
Por razones históricas, el código fuente de la biblioteca libdrm se mantiene bajo el paraguas del proyecto Mesa . [128]
En 1999, mientras desarrollaba DRI para XFree86 , Precision Insight creó la primera versión de DRM para las tarjetas de video 3dfx , como un parche del kernel de Linux incluido en el código fuente de Mesa . [129] Más tarde ese año, el código DRM se incluyó en el kernel de Linux 2.3.18 en el directorio de dispositivos de caracteres . [130] Durante los años siguientes, el número de tarjetas de vídeo compatibles creció. Cuando se lanzó Linux 2.4.0 en enero de 2001, ya había soporte para Creative Labs GMX 2000, Intel i810, Matrox G200/G400 y ATI Rage 128, además de las tarjetas 3dfx Voodoo3, [131] y esa lista se amplió durante la versión 2.4. Serie x, con controladores para tarjetas ATI Radeon , algunas tarjetas de video SiS e Intel 830M y GPU integradas posteriores./drivers/char/drm/
La división de DRM en dos componentes, núcleo DRM y controlador DRM, llamada división núcleo/personalidad DRM , se realizó durante la segunda mitad de 2004, [11] [132] y se fusionó en la versión 2.6.11 del kernel. [133] Esta división permitió que múltiples controladores DRM para múltiples dispositivos funcionaran simultáneamente, abriendo el camino a la compatibilidad con múltiples GPU.
La idea de poner todo el código de configuración del modo de vídeo en un solo lugar dentro del kernel había sido reconocida durante años, [134] [135] pero los fabricantes de tarjetas gráficas habían argumentado que la única forma de configurar el modo era utilizar las rutinas proporcionados por ellos mismos y contenidos en el Video BIOS de cada tarjeta gráfica. Dicho código tenía que ejecutarse utilizando el modo real x86 , lo que impedía que fuera invocado por un kernel que se ejecutaba en modo protegido . [44] La situación cambió cuando Luc Verhaegen y otros desarrolladores encontraron una manera de realizar la configuración del modo de forma nativa en lugar de hacerlo mediante BIOS, [136] [44] mostrando que era posible hacerlo utilizando el código del kernel normal y sentando las bases. para lo que se convertiría en Configuración del Modo Kernel . En mayo de 2007, Jesse Barnes ( Intel ) publicó la primera propuesta para una API de configuración de modo DRM y una implementación nativa funcional de configuración de modo para GPU Intel dentro del controlador DRM i915. [42] En diciembre de 2007, Jerome Glisse comenzó a agregar el código de configuración de modo nativo para tarjetas ATI al controlador DRM radeon. [137] [138] El trabajo tanto en la API como en los controladores continuó durante 2008, pero se retrasó por la necesidad de un administrador de memoria también en el espacio del kernel para manejar los framebuffers. [139]
En octubre de 2008, el kernel de Linux 2.6.27 trajo una importante reorganización del código fuente , antes de que se produjeran algunos cambios importantes. El árbol del código fuente de DRM se movió a su propio directorio fuente /drivers/gpu/drm/
y los diferentes controladores se movieron a sus propios subdirectorios. Los encabezados también se movieron a un nuevo /include/drm
directorio. [140]
La creciente complejidad de la gestión de la memoria de vídeo dio lugar a varios enfoques para resolver este problema. El primer intento fue el administrador de memoria Translation Table Maps (TTM), desarrollado por Thomas Hellstrom ( Tungsten Graphics ) en colaboración con Emma Anholt (Intel) y Dave Airlie ( Red Hat ). [5] Se propuso incluir TTM en el núcleo principal 2.6.25 en noviembre de 2007, [5] y nuevamente en mayo de 2008, pero se abandonó en favor de un nuevo enfoque llamado Graphics Execution Manager (GEM). [24] GEM fue desarrollado por primera vez por Keith Packard y Emma Anholt de Intel como una solución más sencilla para la gestión de memoria para su controlador i915. [6] GEM fue bien recibido y se fusionó con la versión 2.6.28 del kernel de Linux lanzada en diciembre de 2008. [141] Mientras tanto, TTM tuvo que esperar hasta septiembre de 2009 para finalmente fusionarse con Linux 2.6.31 como requisito de la nueva Radeon. Controlador KMS DRM. [142]
Con la administración de memoria implementada para manejar objetos de búfer, los desarrolladores de DRM finalmente pudieron agregar al kernel la API ya terminada y el código para configurar el modo de ejecución . Esta API ampliada es lo que se llama configuración del modo kernel (KMS) y los controladores que la implementan a menudo se denominan controladores KMS . En marzo de 2009, KMS se fusionó con la versión 2.6.29 del kernel de Linux, [30] [143] junto con el soporte de KMS para el controlador i915. [144] La API de KMS ha estado expuesta a programas de espacio de usuario desde libdrm 2.4.3. [145] El controlador DDX X.Org del espacio de usuario para tarjetas gráficas Intel también fue el primero en utilizar las nuevas API GEM y KMS. [146] La compatibilidad con KMS para el controlador Radeon DRM se agregó a la versión Linux 2.6.31 de septiembre de 2009. [147] [148] [149] El nuevo controlador Radeon KMS utilizó el administrador de memoria TTM pero en su lugar expuso interfaces e ioctl compatibles con GEM. de los TTM. [23]
Desde 2006, el proyecto nouveau había estado desarrollando un controlador DRM de software gratuito para las GPU NVIDIA fuera del kernel oficial de Linux. En 2010, el código fuente nouveau se fusionó con Linux 2.6.33 como controlador experimental. [58] [59] En el momento de la fusión, el controlador ya se había convertido a KMS y detrás de la API GEM usaba TTM como administrador de memoria. [150]
La nueva API KMS, incluida la API GEM, fue un gran hito en el desarrollo de DRM, pero no impidió que la API se mejorara en los años siguientes. KMS obtuvo soporte para cambios de página junto con notificaciones VBLANK asíncronas en Linux 2.6.33 [151] [152] ; solo para el controlador i915, radeon y nouveau lo agregaron más tarde durante la versión Linux 2.6.38. [153] La nueva interfaz de cambio de página se agregó a libdrm 2.4.17. [154] A principios de 2011, durante el ciclo de lanzamiento de Linux 2.6.39, se agregaron a la API de KMS los llamados buffers tontos , una forma no acelerada e independiente del hardware de manejar buffers simples adecuados para su uso como framebuffers. [155] [156] El objetivo era reducir la complejidad de aplicaciones como Plymouth que no necesitan utilizar operaciones aceleradas especiales proporcionadas por ioctls específicos del controlador. [157] La característica fue expuesta por libdrm desde la versión 2.4.25 en adelante. [158] Más tarde ese año también adquirió un nuevo tipo principal de objetos, llamados aviones . Los planos se desarrollaron para representar superposiciones de hardware compatibles con el motor de exploración. [159] [160] El soporte plano se fusionó en Linux 3.3. [161] y libdrm 2.4.30. Otro concepto agregado a la API, durante los lanzamientos de Linux 3.5 [162] y libdrm 2.4.36 [163] , fueron las propiedades genéricas de objetos , un método para agregar valores genéricos a cualquier objeto KMS. Las propiedades son especialmente útiles para establecer comportamientos o características especiales para objetos como CRTC y aviones.
Dave Airlie desarrolló una primera prueba de concepto para proporcionar descarga de GPU entre controladores DRM en 2010. [7] [164] Dado que Airlie estaba tratando de imitar la tecnología NVIDIA Optimus , decidió llamarla "PRIME". [7] Airlie reanudó su trabajo en PRIME a finales de 2011, pero basándose en el nuevo mecanismo de intercambio de búfer DMA-BUF introducido por el kernel de Linux 3.3. [165] La infraestructura básica DMA-BUF PRIME se terminó en marzo de 2012 [166] y se fusionó con la versión Linux 3.4, [167] [168] [169] así como con libdrm 2.4.34. [170] Más adelante, durante el lanzamiento de Linux 3.5, varios controladores DRM implementaron soporte PRIME, incluido i915 para tarjetas Intel, radeon para tarjetas AMD y nouveau para tarjetas NVIDIA. [171] [172]
En los últimos años, la API DRM se ha ampliado progresivamente con funciones nuevas y mejoradas. En 2013, como parte de GSoC , David Herrmann desarrolló la función de múltiples nodos de renderizado . [55] Su código se agregó a la versión 3.12 del kernel de Linux como una característica experimental [173] [174] compatible con los controladores i915, [175] radeon [176] y nouveau [177] , y habilitado de forma predeterminada desde Linux 3.17. [77] En 2014, Matt Roper (Intel) desarrolló el concepto de planos universales (o planos unificados ) mediante el cual los framebuffers ( planos primarios ), las superposiciones ( planos secundarios ) y los cursores ( planos de cursor ) se tratan como un solo tipo de objeto con una API unificada. [178] El soporte de planos universales proporciona una API DRM más consistente con menos ioctls más genéricos . [33] Para mantener la API compatible con versiones anteriores , el núcleo DRM expone la función como una capacidad adicional que puede proporcionar un controlador DRM. La compatibilidad con el plano universal debutó en Linux 3.15 [179] y libdrm 2.4.55. [180] Varios controladores, como el Intel i915, [181] ya lo han implementado.
La mejora más reciente de la API DRM es la API de configuración de modo atómico , que aporta atomicidad a las operaciones de configuración de modo y cambio de página en un dispositivo DRM. La idea de una API atómica para la configuración de modos se propuso por primera vez a principios de 2012. [182] Ville Syrjälä (Intel) asumió la tarea de diseñar e implementar dicha API atómica. [183] Basándose en su trabajo, Rob Clark ( Texas Instruments ) adoptó un enfoque similar con el objetivo de implementar cambios de página atómicos. [184] Posteriormente, en 2013, ambas funciones propuestas se reunieron en una sola utilizando un solo ioctl para ambas tareas. [185] Dado que era un requisito, la función tuvo que esperar a que se fusionara el soporte de aviones universales a mediados de 2014. [181] Durante la segunda mitad de 2014, Daniel Vetter (Intel) y otros desarrolladores de DRM mejoraron enormemente el código atómico [186] : 18 para facilitar la transición de los controladores KMS existentes al nuevo marco atómico. [187] Todo este trabajo finalmente se fusionó en las versiones Linux 3.19 [188] y Linux 4.0 [189] [190] [191] , y se habilitó de forma predeterminada desde Linux 4.2. [192] libdrm expuso la nueva API atómica desde la versión 2.4.62. [193] Ya se han convertido varios controladores a la nueva API atómica. [194] Para 2018, se habían agregado al kernel de Linux diez nuevos controladores DRM basados en este nuevo modelo atómico. [195]
El subsistema del núcleo Direct Rendering Manager se desarrolló inicialmente para usarse con la nueva infraestructura de renderizado directo del servidor de visualización XFree86 4.0, heredado más tarde por su sucesor, el servidor X.Org . Por lo tanto, los principales usuarios de DRM fueron los clientes DRI que se vinculan a la implementación OpenGL acelerada por hardware que se encuentra en la biblioteca Mesa 3D , así como el propio X Server. Hoy en día, varios compositores de Wayland también utilizan DRM , incluido el compositor de referencia Weston . kmscon es una implementación de consola virtual que se ejecuta en el espacio del usuario utilizando las instalaciones de DRM KMS. [196]
En 2015, la versión 358.09 (beta) del controlador propietario Nvidia GeForce recibió soporte para la interfaz de configuración del modo DRM implementada como un nuevo blob del kernel llamado nvidia-modeset.ko
. Este nuevo componente del controlador funciona junto con el nvidia.ko
módulo del kernel para programar el motor de visualización (es decir, el controlador de visualización) de la GPU. [197]
GEM esencialmente trata con objetos de búfer de gráficos (que pueden contener texturas, búferes de renderizado, sombreadores o todo tipo de otros objetos de estado y datos utilizados por la gpu)
GEM flink tiene muchos problemas. Los nombres de flink son globales, lo que permite que cualquier persona con acceso al dispositivo acceda al contenido de los datos de flink.
gem-flink no proporciona espacios de nombres privados para aplicaciones y servidores. En cambio, sólo se proporciona un espacio de nombres global por nodo DRM. Las aplicaciones maliciosas autenticadas pueden atacar a otros clientes mediante la "adivinación de nombres" por fuerza bruta de los buffers de gemas.
Muchas GPU modernas de alta gama vienen con sus propios administradores de memoria. Incluso incluyen varios cachés diferentes que deben sincronizarse durante el acceso. [...] . Por lo tanto, la gestión de la memoria en las GPU depende en gran medida de los controladores y del hardware.
Las tarjetas gráficas se programan de numerosas maneras, pero la mayor parte de la inicialización y configuración de modo se realiza a través de IO asignada en memoria. Este es solo un conjunto de registros accesibles a la CPU a través de su espacio de direcciones de memoria estándar. Los registros en este espacio de direcciones se dividen en rangos que se ocupan de diversas características de la tarjeta gráfica, como la configuración del modo, el control de salida o la configuración del reloj.
Históricamente, el servidor X era responsable de guardar el estado de salida cuando se iniciaba y luego restaurarlo cuando volvía al modo de texto. El cambio rápido de usuario se logró con un conmutador VT, por lo que al alejarse del servidor X del primer usuario parpadearía una vez para ir al modo de texto y luego parpadearía nuevamente inmediatamente para ir a la sesión del segundo usuario.
Una limitación más sutil es que el controlador no podía manejar las interrupciones, por lo que no había soporte para monitores de conexión en caliente.
El controlador DRM/KMS funciona completamente ahora, aunque todavía sin DMA. Ah, y está escrito en Rust, aunque en su mayoría está lleno de bloques inseguros y sin procesar.
Lo bueno es que, dado que tenemos un controlador DRM/KMS "normal" (y ayuda de @[email protected]), podemos hacer cosas como... ¡ejecutar Wayland! Weston en un iPod Nano 5G.
utiliza un chip de visualización integrado en el chip de gestión Hi1710 y utiliza el núcleo IP del SM750
Creo que la mejor solución a este problema es que el kernel proporcione un controlador de dispositivo único y completo para cada pieza de hardware de vídeo. Esto significa que los controladores conflictivos como fbdev y DRM deben fusionarse en un sistema cooperativo. También significa que se debe evitar extraer hardware del espacio del usuario mientras se carga un controlador de dispositivo basado en kernel.
En este momento hay 17 controladores que admiten la configuración de modo atómico fusionados en el subsistema DRM.