Mesa llvmpipe vs SwiftShader para Chromium en Linux
Elige entre Mesa llvmpipe con ANGLE GL y SwiftShader para Chromium en Linux: un 49% menos de CPU en una ejecución headed, CPU similar en headless y dos flags.
BotBrowser Team
Quieres la documentación estructurada de Despliegue?
Este artículo forma parte de la biblioteca editorial. Para pasos de configuración, material de referencia y actualizaciones continuas, entra en la sección de docs.
Un servidor Linux sin GPU sigue necesitando un rasterizador por software para que Chromium tenga WebGL operativo. A través de ANGLE hay dos opciones prácticas: SwiftShader y Mesa llvmpipe, a la que se llega mediante el backend OpenGL de ANGLE. En la medición de BotBrowser, una sesión headed sobre una pantalla virtual (Xvfb) ejecutó unos 25 segundos de dibujo con Canvas 2D más un shader WebGL2. SwiftShader usó aproximadamente 999% de CPU para esa carga y Mesa llvmpipe aproximadamente 513%. Eso es cerca de un 49% menos de CPU, con WebGL1, WebGL2 y el adaptador WebGPU disponibles en ambos casos.
TL;DR
- En la medición headed sobre Xvfb, SwiftShader usó cerca de 999% de CPU y Mesa llvmpipe cerca de 513%, alrededor de 49% menos, con WebGL1, WebGL2 y el adaptador WebGPU todavía disponibles.
- En el modo headless por defecto los dos backends usaron cerca de 713.5% y 713.3%, así que allí la migración aporta estabilidad de capacidades y no CPU.
- La ruta llvmpipe son dos flags,
--use-angle=gl --bot-gpu-emulation=false, tras instalarlibgl1-mesa-dri,libglx-mesa0,libegl-mesa0ylibvulkan1. --disable-gpua secas hace querequestAdapter()devuelva null y rompegetContext('webgl')ygetContext('webgl2'), y tiene prioridad sobre--use-angle=glsi ambos están presentes.- La fila de lavapipe con unos 153% pierde WebGL2 y el adaptador WebGPU en Ubuntu 22.04, así que su menor CPU no es comparable.
Contenido
- Qué muestra la medición
- Por qué SwiftShader cuesta más aquí y en qué se diferencian los tres backends
- Por qué --disable-gpu a secas elimina los adaptadores WebGL y WebGPU
- La configuración de llvmpipe con dos flags
- Diferencias de salida entre rasterizadores y reproducibilidad con semilla
- Despliegue con un host canario en una flota Linux
Qué muestra la medición
El resultado tiene un límite claro. Procede de una sola carga headed sobre pantalla virtual, en un host Ubuntu 22.04 x86_64 con un perfil de Windows 11, sumando la CPU de ps en todos los procesos de Chromium y promediando dos ejecuciones. No describe todas las cargas ni todos los hosts. En el modo headless por defecto, los dos backends consumen casi la misma CPU.
| Modo | Backend | CPU media | Qué significa |
|---|---|---|---|
| Headed sobre Xvfb | SwiftShader | ~999% | Referencia |
| Headed sobre Xvfb | Mesa llvmpipe | ~513% | Cerca de un 49% menos que la referencia |
| Headed sobre Xvfb | Mesa lavapipe | ~153% | WebGL2 desactivado, no sirve en producción |
| Headless por defecto | SwiftShader con el conjunto completo de flags unsafe | ~713.5% | Referencia |
| Headless por defecto | Mesa llvmpipe | ~713.3% | CPU casi igual, pico de memoria unos 100 MB mayor |
La fila de lavapipe es una advertencia, no una recomendación. Su CPU baja procede de una configuración que pierde WebGL2 y el adaptador WebGPU, así que el ahorro no es comparable con las otras dos filas.
Lee la tabla según el modo que uses. Si alguna parte de tu pipeline es headed, como una pantalla virtual para capturas, comprobaciones manuales o la ruta headless antigua, la ganancia de CPU es real. Si ya usas el modo headless por defecto, no esperes ahorro de CPU. El motivo para migrar ahí es tener WebGL, WebGL2 y WebGPU estables sin depender de flags --enable-unsafe-*. Para saber qué comparar entre sesiones headless y headed, consulta Consistencia de perfiles entre navegadores headless y headed, que explica cómo registrar el par compatible y clasificar las diferencias.
La misma lectura, organizada por tipo de despliegue, queda así:
| Tipo de despliegue | Expectativa de CPU | Motivo para migrar |
|---|---|---|
| Sesión headed sobre pantalla virtual | Menor con llvmpipe, en el rango medido aquí | Ahorro de CPU y un conjunto de flags más pequeño |
| Ruta headless antigua o pipelines de capturas que corren headed | Menor con llvmpipe, verifícalo con tu propia carga | Ahorro de CPU y compatibilidad futura |
| Modo headless por defecto | Casi igual que SwiftShader | WebGL y WebGPU estables sin flags unsafe |
| Despliegue congelado por ahora | Sin cambios hasta que migres | Planifica el cambio antes de la próxima actualización mayor de Chromium |
Por qué SwiftShader cuesta más aquí y en qué se diferencian los tres backends
SwiftShader es un rasterizador por CPU que implementa OpenGL ES y Vulkan en software. Cada invocación de shader se ejecuta en núcleos de CPU, que es para lo que fue creado. Es autocontenido y no necesita paquetes de Mesa del sistema, por eso es el camino en el que acaban muchas flotas Linux por defecto.
Una lectura de 999% significa que unos diez núcleos de CPU estuvieron ocupados mientras corría la carga. Multiplícalo por el número de instancias de un host y el backend de renderizado pasa a ser una parte grande del presupuesto de CPU. La medición muestra la diferencia entre los backends, pero no aísla por qué uno es más barato que otro, así que no afirma nada sobre su funcionamiento interno.
Mesa documenta llvmpipe como un rasterizador por software que usa LLVM para generar código en tiempo de ejecución y que corre en varios hilos sobre los núcleos de CPU. En un servidor sin GPU física, Mesa lo selecciona automáticamente cuando ANGLE apunta a la pila OpenGL del sistema.
ANGLE es la capa que Chromium usa para traducir las llamadas WebGL a una API gráfica nativa, y el flag --use-angle elige a qué API apunta. Esa elección decide qué rasterizador por software hace el trabajo. Existen tres caminos:
- SwiftShader mediante ANGLE es la opción de respaldo histórica. Chromium reciente la mantiene detrás de
--enable-unsafe-swiftshader, y la palabra unsafe en ese nombre es la señal de upstream de que el camino ya no es el predeterminado. - Mesa llvmpipe mediante ANGLE GL usa
--use-angle=gl. ANGLE habla con lalibGLdel sistema y Mesa la enlaza con llvmpipe cuando no hay GPU física. Los puntos de entrada WebGL1, WebGL2 y WebGPU siguen disponibles, y ningún flag de la configuración lleva la etiqueta unsafe. - Mesa lavapipe mediante ANGLE Vulkan es el rasterizador Vulkan por software. Necesita extensiones Vulkan que ANGLE espera para WebGL2, y no todas las versiones de Mesa las incluyen.
| Backend | Flags necesarios | Adaptador WebGPU | WebGL1 | WebGL2 | Compatible a futuro |
|---|---|---|---|---|---|
| Mesa llvmpipe (recomendado) | --use-angle=gl --bot-gpu-emulation=false | sí | sí | sí | sí |
| SwiftShader | --disable-gpu --enable-unsafe-swiftshader --use-gl=angle --ignore-gpu-blocklist | sí | sí | sí | obsoleto y protegido por unsafe |
| Mesa lavapipe, bare metal, Ubuntu 22.04 | --use-angle=vulkan --enable-features=Vulkan,DefaultANGLEVulkan,VulkanFromANGLE | no (null) | sí | no | sí en Ubuntu 24.04 y posteriores |
| Mesa lavapipe, Docker, cualquier distribución | igual que arriba | no (null) | no | no | no viable para producción |
--disable-gpu a secas | solo --disable-gpu | no (null) | no | no | utilizable solo con flags adicionales |
navigator.gpu como propiedad está presente en todas las filas. La columna de WebGPU indica si navigator.gpu.requestAdapter() devuelve un adaptador utilizable. Para ver cómo se expone el adaptador y qué revela, consulta Huella digital WebGPU: la próxima generación de rastreo por GPU, que cubre los detalles del adaptador y cómo controlarlos.
Conviene mirar lavapipe de cerca porque su cifra de CPU resulta tentadora. En Ubuntu 22.04, el Mesa 23.2 empaquetado no incluye todas las extensiones Vulkan que ANGLE necesita para WebGL2. WebGL1 sigue funcionando en bare metal, pero WebGL2 falla y el adaptador WebGPU es null. Dentro de Docker, la carga del ICD de Vulkan también es frágil, así que lavapipe muchas veces ni arranca y WebGL1 deja de funcionar también. Ubuntu 24.04 con Mesa 24.2 o posterior mejora el caso bare metal, mientras que el comportamiento en contenedores sigue siendo poco fiable hoy. Vuelve a revisar lavapipe cuando tus hosts usen un Mesa más reciente, y hasta entonces considéralo aún no apto para producción en la configuración probada.
Los proyectos upstream describen su propio papel con claridad. El README de ANGLE presenta a ANGLE como la capa que traduce llamadas de OpenGL ES a otros backends gráficos, como Vulkan y OpenGL de escritorio, y por eso un solo valor de --use-angle basta para mover Chromium entre los tres rasterizadores. El repositorio de SwiftShader describe una implementación de la API gráfica Vulkan basada en CPU que aporta independencia del hardware. La documentación de Mesa describe llvmpipe como parte de los drivers de software Gallium que Mesa mantiene. En conjunto explican por qué llvmpipe es una ruta de software soportada y no una vía de escape.
El flag de SwiftShader es también una cuestión de calendario. Chromium ha marcado el camino como protegido por unsafe, lo que sugiere que quizá no siga disponible, pero no hay una fecha pública de retirada. Los pipelines que dependen de él perderán WebGL si algún día se retira el flag, así que migrar pronto convierte un corte forzado en un cambio planificado.
Por qué --disable-gpu a secas elimina los adaptadores WebGL y WebGPU
Muchos tutoriales de Chromium en Linux sugieren --disable-gpu como arreglo de una línea para problemas de renderizado en servidores. En el Chromium actual, ese flag por sí solo desactiva el descubrimiento de adaptadores WebGPU y los dos contextos WebGL. navigator.gpu sigue presente, pero requestAdapter() devuelve null, y tanto getContext('webgl') como getContext('webgl2') fallan. Canvas 2D sigue funcionando, por eso el problema suele pasar desapercibido hasta que una página necesita WebGL.
Muchos despliegues de producción evitan ese fallo porque apilan flags de escape sobre --disable-gpu:
--disable-gpu
--enable-unsafe-swiftshader
--enable-unsafe-webgpu
--use-gl=angle
--ignore-gpu-blocklist
Cada flag de esa pila tiene una función distinta. --enable-unsafe-swiftshader mantiene disponible el camino de SwiftShader, --enable-unsafe-webgpu mantiene disponible el camino WebGPU por software, --use-gl=angle fuerza la conexión con ANGLE y --ignore-gpu-blocklist omite la lista de bloqueo de GPU de Chromium. Ninguno hace falta en el camino de llvmpipe.
Esta pila de cinco flags funciona en el sentido de que WebGL1, WebGL2 y el adaptador vuelven a aparecer. También ata el despliegue al camino de SwiftShader y a cuatro flags cuyos nombres contienen unsafe o ignore. Así, cada actualización de Chromium trae la duda de si alguno de esos flags ha cambiado de comportamiento.
Hay una trampa más. --disable-gpu tiene prioridad sobre --use-angle=gl tanto en modo headed como en headless. Si añades el flag de Mesa y dejas --disable-gpu, llvmpipe nunca entra en efecto y la configuración parece indicar que la migración no hizo nada.
La salida más limpia es eliminar --disable-gpu y los cuatro flags de escape, y sustituir todo el grupo por los dos flags de la sección siguiente. Quien sepa nombrar la pila de cinco flags, la pila de dos flags y el motivo por el que --disable-gpu a secas elimina el descubrimiento de adaptadores ya ha entendido toda la migración.
La configuración de llvmpipe con dos flags
Primero instala los paquetes de Mesa en espacio de usuario que permiten a ANGLE llegar a llvmpipe:
sudo apt-get update
sudo apt-get install -y \
libgl1-mesa-dri \
libglx-mesa0 \
libegl-mesa0 \
libvulkan1
Después lanza con los dos flags. En el modo headless por defecto no hace falta pantalla:
chromium-browser \
--headless \
--no-sandbox \
--user-data-dir="$(mktemp -d)" \
--bot-profile="path/to/profile.enc" \
--use-angle=gl \
--bot-gpu-emulation=false
Para una sesión headed sobre pantalla virtual, quita --headless y proporciona una pantalla:
DISPLAY=:10.0 chromium-browser \
--no-sandbox \
--user-data-dir="$(mktemp -d)" \
--bot-profile="path/to/profile.enc" \
--use-angle=gl \
--bot-gpu-emulation=false
--use-angle=gl dirige ANGLE por la pila OpenGL del sistema, y Mesa carga llvmpipe cuando no hay GPU física. --bot-gpu-emulation=false indica a BotBrowser que deje que el driver GL real dibuje la salida WebGL mientras el ruido de Canvas 2D y la capa de variación de --bot-noise-seed siguen activos. El flag es estrecho a propósito: no desactiva el perfil ni el resto de la protección de fingerprint.
--bot-gpu-emulation acepta tres valores. false es el ajuste de esta migración. true es el modo estándar por defecto. priority añade una planificación priorizada de la GPU para cargas con muchos contextos concurrentes en una instancia del navegador, funciona de forma independiente de la elección del backend GL y no hace falta cuando false entrega el trabajo de GPU al driver real.
Cuando migres un despliegue existente, elimina estos flags antes de añadir los dos nuevos. Varios entran en conflicto con --use-angle=gl, y cualquiera de ellos puede deshacer el cambio sin mostrar ningún error.
| Flag a eliminar | Motivo |
|---|---|
--disable-gpu | Desactiva el descubrimiento de adaptadores y los dos contextos WebGL, y prevalece sobre --use-angle=gl |
--enable-unsafe-swiftshader | Solo hace falta para mantener vivo SwiftShader |
--use-gl=swiftshader | Activación explícita de SwiftShader, superada por llvmpipe |
--use-gl=angle | Forma antigua sustituida por --use-angle=gl y puede entrar en conflicto con ella |
--ignore-gpu-blocklist | No hace falta, porque llvmpipe no está en la lista de bloqueo |
--enable-features=Vulkan,DefaultANGLEVulkan,VulkanFromANGLE | Fija el camino de lavapipe, que desactiva WebGL2 en bare metal con Ubuntu 22.04 |
--use-angle=vulkan | Fuerza el mismo camino de lavapipe |
--disable-vulkan-surface | Solo es relevante para el camino Vulkan |
Dentro de un contenedor, añade los mismos cuatro paquetes de Mesa a la imagen y pasa los mismos dos flags al lanzar. Ejecutar el contenedor con --shm-size=2g da a Chromium más memoria compartida y mejora la estabilidad. Recuerda que lavapipe es el backend que falla en contenedores, así que un despliegue en contenedores es un motivo más para quedarse en llvmpipe mediante ANGLE GL.
Conserva --headless, --no-sandbox si ya lo usabas, todos los flags --bot-* incluidos --bot-profile y --bot-noise-seed, y tu configuración de red y de --user-data-dir. En lanzamientos con Playwright o Puppeteer, los mismos flags van en la lista args:
const browser = await chromium.launch({
executablePath: 'path/to/botbrowser',
args: ['--use-angle=gl', '--bot-gpu-emulation=false', '--bot-profile=path/to/profile.enc'],
});
Diferencias de salida entre rasterizadores y reproducibilidad con semilla
Distintos rasterizadores por software producen una salida de píxeles distinta para el mismo shader. Después de pasar de SwiftShader a Mesa llvmpipe, los bytes exactos de readPixels o toDataURL serán diferentes. Es el comportamiento esperado de dos rasterizadores distintos, no una señal de que la migración haya fallado.
Los campos que una página lee como identidad siguen bajo control del perfil. User-Agent, plataforma y las cadenas de proveedor y renderizador sin enmascarar vienen de tu perfil y no cambian con el backend. El comportamiento de --bot-noise-seed tampoco cambia: la misma semilla reproduce la misma salida dentro del backend elegido, y una semilla distinta produce una salida distinta y estable.
De ahí salen dos reglas prácticas. Mantén capturas de referencia por backend en lugar de comparar bytes entre SwiftShader y llvmpipe. Y cuando compares antes y después de una migración, compara ejecuciones del mismo backend y con la misma semilla, para que una regresión real no quede oculta tras una diferencia esperada entre rasterizadores.
Despliegue con un host canario en una flota Linux
Valida el cambio en un host canario antes de tocar el resto de la flota. La secuencia siguiente mantiene cada paso observable:
- Instala
libgl1-mesa-dri,libglx-mesa0,libegl-mesa0ylibvulkan1en el host canario. - Sustituye la pila de flags de GPU por
--use-angle=gl --bot-gpu-emulation=falseen una instancia y reiníciala, porque los cambios de flags solo se leen al arrancar. - Confirma que los contextos WebGL1 y WebGL2 se crean y que
navigator.gpu.requestAdapter()devuelve un adaptador no null. - Abre
chrome://gpuy comprueba que las filas de WebGL, WebGL2 y WebGPU indican renderizado por software mediante ANGLE y OpenGL en lugar de desactivado. La misma página muestra la cadena activa de ANGLE y del driver, lo que confirma que se usa llvmpipe. - Mide la CPU frente a una referencia de SwiftShader equivalente, en el mismo modo headed o headless y con la misma carga.
- Repite las comprobaciones con la misma semilla y con una semilla distinta, y después extiende el cambio al resto de la flota.
La tabla siguiente relaciona los síntomas más frecuentes con su causa habitual.
| Síntoma | Causa habitual | Solución |
|---|---|---|
| Adaptador null y fallan los dos contextos WebGL | --disable-gpu a secas, o lavapipe dentro de Docker | Elimina --disable-gpu y los flags de Vulkan, deja solo los dos flags |
| WebGL1 funciona, WebGL2 y adaptador null | lavapipe en bare metal con un Mesa antiguo | Elimina los flags de Vulkan y cambia a --use-angle=gl |
libGL error: failed to load driver: swrast | Faltan los paquetes de Mesa en espacio de usuario | Instala libgl1-mesa-dri, libglx-mesa0 y libegl-mesa0 |
chrome://gpu sigue mostrando SwiftShader | Un flag lo fuerza de nuevo, como --use-gl=swiftshader | Elimina el flag y reinicia el proceso |
| La CPU no bajó | Modo headless por defecto, donde domina la carga | Es lo esperado, el valor ahí es la estabilidad y la compatibilidad futura |
| Cambió la salida de píxeles WebGL | Rasterizador distinto | Es lo esperado, reconstruye la captura de referencia para el nuevo backend |
Una comparación equivalente es lo que hace fiable la cifra de CPU. Usa el mismo host, el mismo perfil, la misma carga y el mismo modo para ambos backends. Ejecuta una carga lo bastante larga como para mantener ocupado el renderizado, por ejemplo unos 25 segundos de dibujo con Canvas 2D junto con un shader WebGL2. Suma la CPU de todos los procesos de Chromium de la instancia, repite la prueba al menos dos veces y promedia las ejecuciones para que un pico breve de carga del host no decida el resultado. Un ahorro medido en un modo no dice nada del otro modo, así que lanza la referencia en el modo que vayas a usar. Para saber cómo revisar la salida de Canvas, WebGL y WebGPU entre backends, consulta Validación de privacidad en distintos backends de renderizado, que cubre una matriz de renderizado y un orden de pruebas controlado.
Prevé el caso en que la CPU no se mueva. En el modo headless por defecto, el renderizado va a un búfer fuera de pantalla sea cual sea el backend activo, así que el trabajo de Canvas y WebGL domina y los dos backends cuestan casi lo mismo. Aun así, la migración compensa ahí como estabilidad de capacidades y un conjunto de flags más pequeño que no depende de flags unsafe.
BotBrowser documenta una ruta de backend GPU en Linux en la que --use-angle=gl con --bot-gpu-emulation=false permite que Mesa llvmpipe dibuje WebGL mientras el ruido de Canvas 2D y la reproducibilidad de --bot-noise-seed siguen activos, de modo que puedes validar la migración de dos flags en un host canario antes de cambiar el resto de la flota. BotBrowser no puede hacer que Mesa llvmpipe sea más rápido de lo que permite el host, no garantiza ahorro de CPU en el modo headless por defecto, no puede mantener idénticos los bytes de píxeles WebGL entre rasterizadores y no controla el calendario de upstream de Chromium para retirar SwiftShader. El flag --bot-gpu-emulation requiere ENT Tier 2.
Para la preparación básica del host, lee la guía de configuración de servidores headless y la guía de despliegue con Docker. Para el comportamiento de la semilla entre backends, lee reproducibilidad de la semilla de ruido. La referencia completa de flags está en la guía de despliegue del backend GPU en Linux.
Fuentes públicas
- BotBrowser Linux GPU backend selection
- Documentación de Mesa llvmpipe
- Repositorio de SwiftShader
- README de ANGLE
Conclusión práctica
Quita --disable-gpu y los cuatro flags de escape, instala los cuatro paquetes de Mesa y arranca con --use-angle=gl --bot-gpu-emulation=false en un host canario antes de tocar la flota. Después repite la misma carga de unos 25 segundos en el modo que realmente publicas, porque un ahorro headed de cerca del 49% no dice nada del headless por defecto, y mantén la comparación de semilla en dos sesiones para que las diferencias de salida entre rasterizadores sigan visibles.
Este artículo forma parte de la guía: Despliegue y versión del navegador: mapa operativo
Artículos Relacionados
Validación de privacidad en distintos backends de renderizado
DespliegueBotBrowser headless en servidores Ubuntu
Huella digitalHuella digital WebGPU: la próxima generación de rastreo por GPU
DespliegueBotBrowser Trimmed en Linux x64: rendimiento medido
DespliegueSeñales de navegador headless y con interfaz: método
Huella digitalwebgl_debug_renderer_info: qué revela tu GPU a las páginas
Lleva BotBrowser de la investigación a producción
Usa estas guías para entender el modelo y después avanzar hacia validación multiplataforma, contextos aislados y despliegue de navegador preparado para escalar.