El Direct Rendering Manager ( DRM ) es un subsistema del núcleo Linux responsable de la interfaz con las GPU de las tarjetas de vídeo modernas . DRM expone una API que los programas del espacio de usuario pueden utilizar para enviar comandos y datos a la GPU y realizar operaciones como configurar el ajuste del modo de la pantalla. DRM se desarrolló primero como el componente del espacio del núcleo 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 usar la API DRM para ordenar a la GPU que realice renderizado 3D y decodificación de video acelerados por hardware , así como computación GPGPU .
El núcleo Linux ya tenía una API llamada fbdev , utilizada para gestionar el framebuffer de un adaptador gráfico , [2] pero no podía utilizarse para manejar las necesidades del hardware de vídeo basado en GPU acelerado en 3D moderno . Estos dispositivos suelen requerir la configuración y gestión de una cola de comandos en su propia memoria para enviar comandos a la GPU y también requieren la gestión de buffers y espacio libre dentro de esa memoria. [3] Inicialmente, los programas de espacio de usuario (como el servidor X ) gestionaban directamente estos recursos, pero normalmente actuaban como si fueran los únicos con acceso a ellos. Cuando dos o más programas intentaban controlar el mismo hardware al mismo tiempo, y configuraban sus recursos cada uno a su manera, la mayoría de las veces terminaban catastróficamente. [3]
El Direct Rendering Manager fue creado para permitir que varios 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 al DRM, que actúa como árbitro y se encarga de evitar posibles conflictos.
El alcance de DRM se ha ampliado a lo largo de los años para cubrir más funciones que antes manejaban los programas de espacio de usuario, como la gestión del framebuffer y la configuración del modo , los objetos de uso compartido de memoria y la 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 un ordenador (una GPU discreta y otra integrada) generó nuevos problemas, como la conmutación de GPU , que también debían resolverse en la capa DRM. Para poder adaptarse a la tecnología Nvidia Optimus , se proporcionó a DRM capacidades de descarga de GPU, llamadas PRIME. [7]
El Direct Rendering Manager reside en el espacio del núcleo , por lo que los programas del espacio de usuario deben usar llamadas del sistema del núcleo para solicitar sus servicios. Sin embargo, DRM no define sus propias llamadas del sistema personalizadas. En su lugar, 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 conoce como un dispositivo DRM , y se crea un archivo de dispositivo (donde X es un número secuencial) para interactuar con él. [8] [9] Los programas del espacio de usuario que desean comunicarse con la GPU deben abrir este archivo y usar llamadas ioctl para comunicarse con DRM. Diferentes ioctl corresponden a diferentes funciones de la API DRM ./dev/dri/cardX
Se creó una biblioteca llamada libdrm para facilitar la interfaz de los programas de 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 de ayuda. [10] El uso de libdrm no solo evita exponer la interfaz del núcleo 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 de usuario un conjunto mínimo de ioctl con funcionalidad común independiente del hardware. [8] Un controlador DRM, por otro lado, implementa la parte dependiente del hardware de la API, específica para el tipo de GPU que admite; debe proporcionar la implementación de los ioctl restantes no cubiertos por el núcleo DRM, pero también puede extender la API, ofreciendo ioctl adicionales con funcionalidad extra solo disponible en dicho hardware. [8] Cuando un controlador DRM específico proporciona una API mejorada, la biblioteca libdrm del espacio de usuario también se extiende mediante una biblioteca adicional libdrm- driver que puede ser utilizada por el espacio de usuario para interactuar con los ioctl 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 de contenedor correspondientes. Además, los controladores exportan interfaces específicas del dispositivo para que las utilicen los controladores de espacio de usuario y las aplicaciones que reconocen el dispositivo 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 vallas, administración de memoria y administración de salida.
Existen varias operaciones (ioctls) en la API de DRM que, ya sea por motivos de seguridad o por cuestiones de concurrencia, deben estar restringidas para que las utilice un único proceso de espacio de usuario por dispositivo. [8] Para implementar esta restricción, DRM limita dichas ioctls para que solo las invoque el proceso considerado el "maestro" de un dispositivo DRM, normalmente denominado DRM-Master . Solo uno de todos los procesos que tienen abierto el nodo del dispositivo tendrá su identificador de archivo marcado como maestro, específicamente el primero que llame a la ioctl SET_MASTER . Cualquier intento de utilizar una de estas ioctls restringidas sin ser el DRM-Master devolverá un error. Un proceso también puede renunciar a su función de maestro (y dejar que otro proceso la adquiera) llamando a la 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 de 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 que finaliza 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 denominada DRM-Auth . Básicamente es un método de autenticación contra el dispositivo DRM, con el fin de demostrarle que el proceso tiene la aprobación del DRM-Master para obtener dichos privilegios. El procedimiento consiste en: [12] : 13
Debido al aumento del tamaño de la memoria de vídeo 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 los búferes fuera de pantalla con el administrador de composición . Estos requisitos llevaron al desarrollo de nuevos métodos para administrar los búferes gráficos dentro del núcleo. El Administrador de ejecución de gráficos (GEM) surgió como uno de estos métodos. [6]
GEM proporciona una API con primitivas explícitas de gestión de memoria . [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 de espacio de usuario y no necesitan ser recargados cada vez que el programa recupera el control de la GPU. Cuando un programa de espacio de usuario necesita un trozo de memoria de video (para almacenar un framebuffer , una textura o cualquier otro dato requerido por la GPU [15] ), solicita la asignación al controlador DRM utilizando 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 de usuario para hacer referencia a la memoria asignada en las próximas operaciones. [6] [14] La API GEM también proporciona operaciones para rellenar el buffer y liberarlo cuando ya no se necesita. La memoria de los controladores GEM no publicados se recupera cuando el proceso del espacio de usuario cierra el descriptor de archivo del dispositivo DRM (intencionalmente o porque finaliza). [16]
GEM también permite que dos o más procesos de espacio de usuario que utilicen 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 únicos para un proceso pero repetibles en otros procesos, por lo tanto, 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 un, y solo un, objeto GEM creado dentro del mismo dispositivo DRM por el mismo controlador DRM, mediante el uso de un entero único de 32 bits . GEM proporciona una operación flink para obtener un nombre GEM a partir de un identificador 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 proceso receptor puede utilizar el nombre GEM para obtener un identificador GEM local que apunte al objeto GEM original.
Desafortunadamente, el uso de nombres GEM para compartir buffers no es seguro. [12] : 16 [17] [18] Un proceso de terceros malintencionado que acceda al mismo dispositivo DRM podría intentar adivinar el nombre GEM de un buffer 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 memoria de vídeo, es gestionar la sincronización de memoria entre la GPU y la CPU. Las arquitecturas de memoria actuales son muy complejas y suelen implicar varios niveles de cachés para la memoria del sistema y, a veces, también para la memoria de vídeo. Por tanto, los gestores de memoria de vídeo también deberían gestionar la coherencia de la caché para garantizar que los datos compartidos entre la CPU y la GPU sean coherentes. [20] Esto significa que, a menudo, los aspectos internos de la gestión de memoria de vídeo dependen en gran medida de los detalles de hardware de la GPU y de la arquitectura de memoria y, por 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 decidieron exponer a los programas de espacio de usuario la API GEM, pero internamente implementaron un administrador de memoria diferente que se adapta mejor a su hardware y arquitectura de memoria particulares. [23]
La API GEM también proporciona ioctls para controlar el flujo de ejecución (buffers de comandos), pero son específicos de Intel y se utilizan 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 ioctl específicos de administració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 una GPU podría acceder, 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 Graphics Address Remapping Table (GART). [5] TTM también debería 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 gráficas del espacio de usuario generalmente trabajan con grandes cantidades de datos de video. Otro asunto importante era mantener la consistencia entre las diferentes memorias y cachés involucrados.
El concepto principal de TTM son los "objetos de búfer", regiones de la memoria de vídeo que en algún momento deben ser direccionables por la GPU. [5] Cuando una aplicación gráfica del espacio de usuario desea acceder a un determinado objeto de búfer (normalmente para llenarlo de contenido), TTM puede requerir su reubicación en un tipo de memoria direccionable por la CPU. Otras reubicaciones (u operaciones de mapeo GART) pueden ocurrir cuando la GPU necesita acceder 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 gestionar cualquier dato relacionado y problemas de coherencia de caché. [5]
Otro concepto importante de TTM son las cercas . Las cercas son esencialmente un mecanismo para gestionar la concurrencia entre la CPU y la GPU. [24] Una cerca rastrea cuándo 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 una VRAM dedicada, de una manera adecuada, y proporcionar todas las características imaginables en un administrador de memoria para su uso con cualquier tipo de hardware, condujo a una solución excesivamente compleja con una API mucho más grande 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, su API fue preferida sobre la de 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, al tiempo que exponían sus objetos de búfer como objetos GEM y, por lo tanto, admitían la API GEM. [23] Algunos ejemplos de controladores actuales que utilizan TTM como un 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 de uso compartido de búfer DMA (a menudo abreviada como DMA-BUF) es una API interna del núcleo Linux diseñada para proporcionar un mecanismo genérico para compartir búferes 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 búferes a través de DMA-BUF para lograr una copia cero de los datos de una transmisión 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 la descarga de GPU que utiliza DMA-BUF para compartir los framebuffers resultantes entre los controladores DRM de la GPU discreta y la integrada. [27] : 13 Una característica importante de DMA-BUF es que un buffer 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 ioctls se reutilizaron más tarde como una forma de corregir la inseguridad inherente de compartir búfer 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 del descriptor de archivo recibido. [12] : 16 Este método lo utiliza DRI3 para compartir búferes entre el cliente y el servidor X [29] y también Wayland .
Para funcionar correctamente, una tarjeta de video o un adaptador gráfico 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 de visualización conectada . Esta operación se denomina configuración de modo [30] y generalmente requiere acceso sin procesar al hardware gráfico , es decir, la capacidad de escribir en ciertos registros del controlador de pantalla de la tarjeta de video . [31] [32] Se debe realizar una operación de configuración de modo antes de comenzar a usar el búfer de cuadros , y también cuando una aplicación o el usuario requieren cambiar el modo.
En los primeros tiempos, 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 de tipo Unix, el servidor X era 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 vídeo. [33] Este enfoque, más tarde denominado configuración de modo de espacio de usuario o UMS, [34] [35] plantea varios problemas. [36] [30] No sólo rompe el aislamiento que los sistemas operativos deberían proporcionar entre los programas y el hardware, lo que plantea problemas de estabilidad y seguridad, sino que también podría dejar el hardware gráfico en un estado inconsistente si dos o más programas de espacio de usuario intentan realizar la configuración de modo al mismo tiempo. Para evitar estos conflictos, el servidor X se convirtió en la práctica en el único programa de espacio 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 configurar el modo apropiado y para gestionar cualquier otra operación que implicara la configuración de modo. Inicialmente, la configuración del modo se realizaba exclusivamente durante el proceso de inicio del servidor X, pero más tarde el servidor X adquirió la capacidad de hacerlo mientras se ejecutaba. [37] La extensión XFree86-VidModeExtension se introdujo en XFree86 3.1.2 para permitir que cualquier cliente X solicitara cambios en la línea de modelo (resolución) al servidor X. [38] [39] La extensión VidMode fue reemplazada más tarde por la extensión XRandR más genérica .
Sin embargo, este no era el único código que realizaba la configuración de modo en un sistema Linux . Durante el proceso de arranque del sistema, el núcleo 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 de framebuffer del núcleo 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) manejaban 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 volvía a X. [41] Este proceso causaba un molesto parpadeo en la transición y también podía fallar, lo que provocaba 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 trasladó a un único lugar dentro del núcleo, específicamente al módulo DRM existente. [36] [37] [44] [42] [43] De esta forma, cada proceso (incluido el servidor X) debería poder ordenar al núcleo que realice operaciones de configuración de modo, y el núcleo garantizaría que las operaciones concurrentes no generen un estado inconsistente. La nueva API del núcleo y el código agregado al módulo DRM para realizar estas operaciones de configuración de modo se denominaron Kernel Mode-Setting (KMS). [30]
La configuración del modo del núcleo ofrece varios beneficios. El más inmediato es, por supuesto, la eliminación del código de configuración de modo duplicado, tanto del núcleo (consola Linux, fbdev) como del espacio de usuario (controladores DDX de X Server). 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 una gestió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 núcleo, también se puede utilizar al comienzo del proceso de arranque, lo que evita el parpadeo debido a los cambios de modo en estas primeras etapas.
El hecho de que KMS sea parte del núcleo le permite utilizar recursos que solo están disponibles en el espacio del núcleo, como las interrupciones . [45] Por ejemplo, la recuperación del modo después de un proceso de suspensión/reanudación se simplifica mucho al ser administrada por el propio núcleo, y de paso mejora la seguridad (ya no hay más herramientas de espacio de usuario que requieran permisos de root). El núcleo también permite la conexión en caliente de nuevos dispositivos de visualización fácilmente, lo que resuelve un problema de larga data. [45] La configuración del modo también está estrechamente relacionada con la gestión de memoria (ya que los framebuffers son básicamente buffers de memoria), por lo que se recomienda encarecidamente una integración estrecha con el administrador de memoria gráfica. Esa es la razón principal por la que el código de configuración del modo del núcleo se incorporó a DRM y no como un subsistema separado. [44]
Para evitar romper la compatibilidad con versiones anteriores de la API de DRM, se proporciona Kernel Mode-Setting como una característica adicional del controlador de ciertos controladores de DRM. [46] Cualquier controlador de DRM puede elegir proporcionar el indicador DRIVER_MODESET cuando se registra con el núcleo de DRM para indicar que admite la API de KMS. [8] Aquellos controladores que implementan Kernel Mode-Setting a menudo se denominan controladores KMS como una forma de diferenciarlos de los controladores de 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 desea exponerla o implementarla) implementan sin embargo la API de KMS sin el resto de la API de DRM, lo que permite que los servidores de visualización (como Wayland ) se ejecuten 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 la línea de salida de pantalla 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 pertenecientes a la API de KMS, específicamente a las operaciones de configuración de modo y cambio de página . [33] [52] Esta API de 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 de modo atómico es asegurar un cambio correcto de modo en configuraciones complejas con múltiples restricciones, evitando pasos intermedios que podrían llevar a un estado de video inconsistente o inválido; [52] también evita estados de video riesgosos cuando un proceso de configuración de modo fallido debe deshacer ("rollback"). [53] : 9 La configuración de modo atómico permite saber de antemano si cierta configuración de modo específica es apropiada, al proporcionar 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 son proporcionadas por el mismo nuevo ioctl 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 principal, 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 cortes. [53] : 9,14 [52] Este requisito es especialmente relevante para los controladores de pantalla móviles e integrados, que tienden a usar 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 los mismos objetos (CRTCs, 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 hacer una configuración de modo (principalmente propiedades de CRTCs, codificadores y conectores) o un cambio de página (generalmente propiedades de planos). El ioctl es el mismo para ambos casos, la diferencia es la lista de propiedades que se pasan con cada uno. [54]
En la API DRM original, el dispositivo DRM se utiliza tanto para operaciones privilegiadas (configuración de modo, otros controles de visualización) como para operaciones 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 en la que solo 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. El propietario del dispositivo DRM ("DRM Master") debe otorgar permiso a otras aplicaciones de espacio de usuario que quieran renderizar o realizar cálculos GPGPU mediante el uso de una interfaz de autenticación especial. [56] Luego, las aplicaciones autenticadas pueden renderizar 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 a otros programas de espacio de usuario se les pueda conceder el uso del dispositivo, incluso en casos que no involucran ninguna visualización de gráficos como los cálculos GPGPU. [55] [56]/dev/dri/cardX
El concepto de "nodos de renderizado" 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 separados (o "nodos") para cada una. [9] Para cada GPU encontrada, su controlador DRM correspondiente (si admite la función de nodos de renderizado) crea un archivo de dispositivo , llamado nodo de renderizado , además del nodo primario . [56] [9] Los clientes que usan un modelo de renderizado directo y las aplicaciones que desean aprovechar las facilidades informáticas de una GPU pueden hacerlo sin requerir privilegios adicionales simplemente abriendo cualquier nodo de renderizado existente y enviando operaciones de GPU utilizando el subconjunto limitado de la API DRM compatible con esos nodos, siempre que tengan permisos del sistema de archivos para abrir el archivo de 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 rechazan explícitamente la operación flink de GEM para evitar compartir búferes mediante nombres globales de GEM inseguros; solo se pueden usar descriptores de archivos PRIME (DMA-BUF) para compartir búferes 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 cada vez mayor de integradores de GPU móviles y sistemas en chip (SoC). La calidad de cada controlador varía mucho, dependiendo del grado de cooperación por parte del fabricante y otros factores.
También hay una serie de controladores para hardware antiguo y obsoleto que se detallan en la siguiente tabla con fines históricos.
El Direct Rendering Manager se desarrolla dentro del núcleo 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, con otros mantenedores que se encargan de controladores específicos. [127] Como es habitual en el desarrollo del núcleo de Linux, los submantenedores y colaboradores 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 ser incluidos en la línea principal a Linus Torvalds cada vez que se va a lanzar una nueva versión de Linux. Torvalds, como mantenedor principal de todo el núcleo, tiene la última palabra sobre si un parche es adecuado o no para su inclusión en el núcleo.
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 dentro del 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 bajo el directorio de dispositivos de caracteres . [130] Durante los años siguientes, el número de tarjetas de video 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 expandió durante la serie 2.4.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 DRM/personalidad , se realizó durante la segunda mitad de 2004, [11] [132] y se fusionó en la versión del kernel 2.6.11. [133] Esta división permitió que varios controladores DRM para varios dispositivos funcionaran simultáneamente, abriendo el camino al soporte para 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 núcleo había sido reconocida durante años, [134] [135] pero los fabricantes de tarjetas gráficas habían argumentado que la única forma de hacer la configuración del modo era utilizar las rutinas proporcionadas por ellos mismos y contenidas en el BIOS de vídeo de cada tarjeta gráfica. Dicho código tenía que ser ejecutado utilizando el modo real x86 , lo que impedía que fuera invocado por un núcleo que se ejecutase en modo protegido . [44] La situación cambió cuando Luc Verhaegen y otros desarrolladores encontraron una forma de hacer la configuración del modo de forma nativa en lugar de hacerlo desde el BIOS, [136] [44] demostrando que era posible hacerlo utilizando el código normal del núcleo y sentando las bases para lo que se convertiría en Kernel Mode Setting . 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 de 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 núcleo para manejar los framebuffers. [139]
En octubre de 2008, el kernel Linux 2.6.27 trajo consigo una importante reorganización del código fuente , antes de algunos cambios significativos que se avecinaban. El árbol del código fuente de DRM se trasladó a su propio directorio de origen /drivers/gpu/drm/
y los diferentes controladores se trasladaron a sus propios subdirectorios. Los encabezados también se trasladaron 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 gestor 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 la inclusión de TTM en el kernel principal 2.6.25 en noviembre de 2007, [5] y de nuevo en mayo de 2008, pero se descartó 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 publicada en diciembre de 2008. [141] Mientras tanto, TTM tuvo que esperar hasta septiembre de 2009 para ser finalmente fusionado con Linux 2.6.31 como requisito del nuevo controlador Radeon KMS DRM. [142]
Con la gestión de memoria en su lugar para manejar objetos de búfer, los desarrolladores de DRM finalmente pudieron agregar al núcleo la API ya terminada y el código para hacer la configuración de modo . Esta API expandida es lo que se llama Kernel Mode-setting (KMS) y los controladores que la implementan a menudo se conocen como 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 de espacio de usuario X.Org para tarjetas gráficas Intel también fue el primero en usar las nuevas API GEM y KMS. [146] El soporte de KMS para el controlador DRM de Radeon se agregó a la versión Linux 2.6.31 de septiembre de 2009. [147] [148] [149] El nuevo controlador KMS de Radeon utilizó el administrador de memoria TTM pero expuso interfaces y ioctl compatibles con GEM en lugar de TTM. [23]
Desde 2006, el proyecto Nouveau ha estado desarrollando un controlador DRM de software libre para GPU NVIDIA fuera del núcleo oficial de Linux. En 2010, el código fuente de Nouveau se fusionó con Linux 2.6.33 como un 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, utilizaba TTM como su administrador de memoria. [150]
La nueva API de KMS (incluida la API de 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 asincrónicas en Linux 2.6.33 [151] [152] —solo para el controlador i915, radeon y nouveau lo agregaron más tarde durante el lanzamiento de 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, los llamados búferes tontos (una forma no acelerada e independiente del hardware de manejar búferes simples adecuados para su uso como búferes de cuadros) se agregaron a la API de KMS. [155] [156] El objetivo era reducir la complejidad de aplicaciones como Plymouth que no necesitan usar 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 ganó un nuevo tipo principal de objetos, llamados planes . Los planes se desarrollaron para representar superposiciones de hardware compatibles con el motor scanout. [159] [160] El soporte de planes 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 de objeto genérico , un método para agregar valores genéricos a cualquier objeto KMS. Las propiedades son especialmente útiles para establecer un comportamiento o características especiales para objetos como CRTC y planes.
En 2010, Dave Airlie desarrolló una prueba de concepto temprana para proporcionar descarga de GPU entre controladores DRM. [7] [164] Como Airlie estaba tratando de imitar la tecnología NVIDIA Optimus , decidió llamarla "PRIME". [7] Airlie reanudó su trabajo en PRIME a fines de 2011, pero basándose en el nuevo mecanismo de uso compartido de búfer DMA-BUF introducido por el kernel de Linux 3.3. [165] La infraestructura básica de 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 tarde, durante la versión Linux 3.5, varios controladores DRM implementaron soporte PRIME, incluidos i915 para tarjetas Intel, radeon para tarjetas AMD y nouveau para tarjetas NVIDIA. [171] [172]
En los últimos años, la API de DRM se ha expandido de forma incremental con características nuevas y mejoradas. En 2013, como parte de GSoC , David Herrmann desarrolló la característica de nodos de renderizado múltiples . [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 habilitada de forma predeterminada desde Linux 3.17. [77] En 2014, Matt Roper (Intel) desarrolló el concepto de planos universales (o planos unificados ) por el cual los framebuffers ( planos primarios ), superposiciones ( planos secundarios ) y cursores ( planos de cursor ) se tratan como un solo tipo de objeto con una API unificada. [178] La compatibilidad con planos universales proporciona una API de DRM más consistente con menos ioctls más genéricos . [33] Para mantener la compatibilidad con versiones anteriores de la API , el núcleo DRM expone la característica como una capacidad adicional que puede proporcionar un controlador DRM. El soporte de 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 de 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 modo se propuso por primera vez a principios de 2012. [182] Ville Syrjälä (Intel) se hizo cargo de 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] Más tarde, en 2013, ambas características propuestas se reunieron en una sola utilizando un solo ioctl para ambas tareas. [185] Dado que era un requisito, la característica tuvo que esperar a que se fusionara el soporte de los planos universales a mediados de 2014. [181] Durante la segunda mitad de 2014, el código atómico fue mejorado en gran medida por Daniel Vetter (Intel) y otros desarrolladores de DRM [186] : 18 para facilitar la transición de los controladores KMS existentes al nuevo marco atómico. [187] Todo este trabajo se fusionó finalmente 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 kernel Direct Rendering Manager fue desarrollado inicialmente para ser utilizado con la nueva Infraestructura de Renderizado Directo del servidor de visualización XFree86 4.0, posteriormente heredada por su sucesor, el Servidor X.Org . Por lo tanto, los principales usuarios de DRM eran los clientes DRI que se vinculan a la implementación OpenGL acelerada por hardware que se encuentra en la biblioteca Mesa 3D , así como al propio Servidor X. Hoy en día, DRM también es utilizado por varios compositores Wayland , incluido el compositor de referencia Weston . kmscon es una implementación de consola virtual que se ejecuta en el espacio de usuario utilizando las instalaciones KMS de DRM. [196]
En 2015, la versión 358.09 (beta) del controlador propietario Nvidia GeForce recibió soporte para la interfaz de configuración de modo DRM implementada como un nuevo blob de kernel llamado nvidia-modeset.ko
. Este nuevo componente del controlador funciona junto con el nvidia.ko
módulo de kernel para programar el motor de visualización (es decir, el controlador de visualización) de la GPU. [197]
GEM se ocupa básicamente de los 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 a los contenidos de datos de flink.
gem-flink no proporciona ningún espacio de nombres privado a las aplicaciones y servidores. En su lugar, solo se proporciona un espacio de nombres global por nodo DRM. Las aplicaciones autenticadas maliciosas pueden atacar a otros clientes mediante la "adivinación de nombres" por fuerza bruta de los búferes de gemas
Muchas GPU modernas de gama alta vienen con sus propios administradores de memoria. Incluso incluyen varias cachés diferentes que deben sincronizarse durante el acceso. [...] . Por lo tanto, la gestión de memoria en las GPU depende en gran medida del controlador y del hardware.
Las tarjetas gráficas se programan de numerosas maneras, pero la mayor parte de la inicialización y la configuración del modo se realiza a través de E/S asignada a la memoria. Se trata simplemente de un conjunto de registros a los que la CPU puede acceder a través de su espacio de direcciones de memoria estándar. Los registros de este espacio de direcciones se dividen en rangos que se ocupan de varias 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 lo restauraba cuando volvía al modo de texto. El cambio rápido de usuario se lograba con un interruptor VT, por lo que al cambiar de servidor X del primer usuario parpadeaba una vez para pasar al modo de texto y luego parpadeaba inmediatamente de nuevo para pasar a la sesión del segundo usuario.
Una limitación más sutil es que el controlador no podía manejar interrupciones, por lo que no había compatibilidad con monitores enchufables.
El controlador DRM/KMS funciona completamente ahora, aunque todavía sin DMA. Ah, y está escrito en Rust, aunque está lleno principalmente de bloques inseguros.
Lo bueno es que, como tenemos un controlador DRM/KMS "normal" (y la ayuda de @[email protected]), podemos hacer cosas como... ¡ejecutar Wayland! Weston en un iPod Nano 5G.
utiliza un chip de pantalla integrado en el chip de administración Hi1710 y utiliza el núcleo IP del SM750
Creo que la mejor solución a este problema es que el núcleo proporcione un único controlador de dispositivo 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 la extracción de hardware del espacio de usuario mientras se carga un controlador de dispositivo basado en el núcleo.
hay 17 controladores que admiten la configuración de modo atómico fusionados con el subsistema DRM.