No has conocido realmente los “gráficos” hasta que no has visto un cursor arrastrarse por la pantalla como si estuviera subiendo un sofá cuesta arriba.
En el mundo anterior a NVIDIA, el cuello de botella no era algún bug exótico de shaders. Eras tú, una CPU, un bus de memoria y un bloque de RAM
que, por casualidad, estaba mapeado a la pantalla.
Esta fue la era en la que un “subsistema gráfico” podía significar: un controlador CRT, una paleta, una disposición por bitplanes que mejor no malinterpretes,
y un controlador que a veces hacía más arte improvisado que renderizado. Si administras sistemas de producción hoy, reconocerás los patrones:
límites de ancho de banda ocultos, métricas engañosas y “optimizaciones” que trasladan el problema de un cuello de botella a otro.
Qué significaba “gráficos” antes de las GPU
Hoy “gráficos” implica una tubería: shaders, texturas, buffers de comandos, VRAM y una pila de controladores que es media kernel, media magia negra.
Antes de que NVIDIA convirtiera “GPU” en palabra de uso común, “gráficos” era principalmente conseguir píxeles en un frame buffer lo suficientemente rápido como para que los humanos
no notaran que estabas simulando el movimiento.
La mayoría de los sistemas vivían en uno de tres mundos:
-
Modo texto que fingía ser gráficos. Celdas de caracteres, una ROM de fuentes y quizá algunos caracteres de bloque para la “UI.”
Barato, fiable y rápido porque movía bytes, no píxeles. -
Mapas de bits 2D con aceleración mínima. Un frame buffer en VRAM; dibujar significaba copiar rectángulos, dibujar líneas
y rellenar regiones. Si tenías un blitter, vivías bien. -
3D como un impuesto para especialistas. Workstations con tarjetas adicionales caras o canalizaciones propietarias. En PCs de consumidor,
“3D” a menudo significaba renderizado por software: matemáticas ingeniosas, trucos de punto fijo y resignación.
El hilo común: mover memoria. “Renderizar” no era un debate filosófico. Era “¿cuántos bytes puedo mover por frame?”
y “¿cuántas veces toco cada píxel?”
Si quieres el modelo mental central, es este: los gráficos previos a las GPU son E/S.
Tu pantalla es un dispositivo de memoria que se lee continuamente. Tu trabajo es actualizar esa memoria sin tropezar con el bus, la caché de la CPU
o el timing de refresco del display.
Hechos concretos y contexto histórico
Algunos puntos cortos y relevantes que importan porque explican por qué el software se escribió como se escribió:
APIs, formatos de archivo, toolkits de UI y la folclore del rendimiento no surgieron de la nada.
-
VGA de IBM (1987) estandarizó 640×480 con 16 colores y un modo 256 colores de 320×200.
Ese modo 320×200×8bpp se convirtió en el lienzo por defecto para juegos porque era un punto dulce para velocidad y uso de memoria. -
“Modo 13h” (320×200, 256 colores) en DOS mapeaba la VRAM linealmente.
El direccionamiento lineal permitía a la CPU escribir píxeles con aritmética de punteros simple—sin gimnasia planar. -
Los modos planares eran comunes y dolorosos.
En modos VGA de 16 colores, los píxeles vivían a través de bitplanes. Una sola escritura de píxel podía significar leer-modificar-escribir en varios planos.
Eso moldeó todo, desde motores de sprites hasta por qué ciertas fuentes tenían ese aspecto. -
Las VESA BIOS Extensions (VBE) hicieron posibles resoluciones más altas en DOS.
No era “plug and play”; era “si tienes suerte y el firmware de tu tarjeta se porta bien.” -
La aceleración 2D temprana trataba rectángulos, no triángulos.
BitBLT (bit block transfer), dibujo de líneas por hardware y cursores por hardware importaban más que cualquier cosa “3D.” -
El bus era destino: ISA vs VLB vs PCI.
El ancho de banda y la latencia de ISA limitaban las escrituras al frame buffer; VLB y PCI hicieron práctico el gráfico de mayor rendimiento alimentando la VRAM más rápido. -
Las paletas de color eran una característica de rendimiento.
El color indexado de 8 bits significaba que un buffer de pantalla completo podía ser ~64 KB (320×200) o ~300 KB (640×480), lo bastante pequeño para la época.
El «palette cycling» permitía “animación” sin tocar la mayoría de los píxeles. -
Los aceleradores 3D inicialmente vivieron como ayudantes de función fija.
Las primeras tarjetas 3D de consumo aceleraban mapeo de texturas y preparación de triángulos; la CPU seguía haciendo mucho, especialmente la lógica del juego y las transformaciones. -
El doble buffering no era “gratuito.”
Tener dos frame buffers completos significaba duplicar el uso de VRAM y aumentar el ancho de banda de copia. Muchos sistemas usaban rectángulos sucios en su lugar.
La tubería antigua: de la CPU al fósforo
1) El frame buffer no era una metáfora
Una pila de controladores GPU moderna encola trabajo; la GPU lo toma y escribe en VRAM con enorme paralelismo interno.
En el mundo antiguo, la CPU era el renderizador. Si querías que un píxel se encendiera, escribías en la dirección que representaba ese píxel.
El controlador de pantalla escaneaba la VRAM continuamente y generaba la señal de vídeo.
Ese arreglo creó una verdad simple pero implacable: el rendimiento gráfico era rendimiento de memoria.
No solo “RAM rápida,” sino dónde vivía la RAM y cuánto costaba alcanzarla.
VRAM detrás de un bus lento es como un bucket S3 accesado por un módem dial-up: técnicamente correcto, prácticamente cruel.
2) Qué significaba “aceleración”
La aceleración previa a las GPU usualmente significaba un chip que podía:
- copiar un rectángulo de una zona de VRAM a otra (BitBLT)
- rellenar un rectángulo con un color sólido
- dibujar líneas
- soportar un cursor por hardware (para que el ratón no hiciera tearing ni lag)
Esto era enorme. Si puedes copiar rectángulos en hardware, puedes desplazar ventanas, mover sprites y redibujar elementos de UI
sin devorar la CPU. Es la misma razón por la que los sistemas modernos adoran DMA: los motores de copia liberan compute para trabajo real.
3) Por qué la gente obsesionaba con los formatos de píxel
Los formatos de píxel no eran estéticos; eran supervivencia. Si eliges 8bpp indexado, reduces huella de memoria y ancho de banda.
Si eliges 16bpp (a menudo 5-6-5 RGB), aumentas el ancho de banda pero simplificas sombreado y evitas trucos de paleta. Si eliges 24bpp,
le pides al bus que haga cardio.
Y los formatos no siempre eran lineales. Disposiciones planares, frame buffers bancados (donde cambias qué segmento de VRAM es visible en una dirección),
y restricciones de alineación significaban que un “simple bucle sobre píxeles” ingenuo podía ser catastróficamente lento.
4) Tearing y la tiranía del refresco
El controlador de display lee la VRAM a un ritmo fijo. Si escribes en VRAM mientras está escaneando, puedes ver frames medio actualizados:
tearing. La solución “correcta” es sincronización—esperar el blank vertical o usar page flipping. La solución cara es copiar.
La solución barata es “no redibujar demasiado y esperar que nadie lo note.”
Los sistemas que acertaban se sentían mágicamente fluidos. Los que no, parecían como si tus ojos estuvieran depurando.
Broma #1: En aquellos días, “renderizado en tiempo real” significaba “renderizar a tiempo para la siguiente reunión.” A veces ambas cosas ocurrían.
A dónde se iba el tiempo: cuellos de botella que podías sentir
Ancho de banda: el presupuesto silencioso
Si quieres una regla práctica para gráficos a la antigua, calcula tu presupuesto bruto de escritura.
Una pantalla 640×480 a 8bpp son ~300 KB. A 60 fps eso es ~18 MB/s solo para escribir un frame completo—ignorando lecturas,
ignorando overdraw, ignorando blits, ignorando todo lo demás que la CPU y el bus estén haciendo.
En papel eso suena modesto hoy. En contexto, frecuentemente era la máquina entera.
Buses antiguos, caches y controladores de memoria podían convertir esos “18 MB/s” en una fantasía cuando añades contención y estados de espera.
Por eso la redibujo parcial (rectángulos sucios) no era una micro-optimización; era la diferencia entre usable e insultante.
Latencia: por qué un solo píxel podía ser caro
La VRAM detrás de un bus puede tener patrones de acceso feos. Las escrituras secuenciales podrían estar bien; las escrituras dispersas de píxeles pueden ser una pesadilla.
Esto se ve en motores de sprites por software: agrupan, alinean, prefieren spans. Hacen cualquier cosa para convertir escrituras aleatorias en lineales.
Overdraw: pintar el mismo píxel varias veces
En un renderizador por software, cada vez que tocas un píxel pagas. Si tu toolkit de UI repinta toda la ventana por un cursor parpadeante,
no tienes un “bug de UI.” Tienes un problema de throughput. Lo mismo en juegos: si dibujas fondo, luego sprites, luego UI,
el mismo píxel puede escribirse tres veces.
El instinto correcto en esa era era: minimizar toques. Pintar una vez. Cachear agresivamente. Recortar sin piedad.
A veces la mejor técnica de renderizado era “no hacerlo.”
Ciclos de CPU: matemática vs memoria
Los viejos debates de renderizado (“usar punto fijo,” “precalcular tablas,” “evitar divisiones”) no eran académicos.
Las CPUs eran lo suficientemente lentas como para que las matemáticas pudieran dominar. Pero a menudo ocurría lo contrario: la CPU podía calcular más rápido de lo que podía escribir
al frame buffer. Ahí ves trucos como dibujar en un buffer en memoria del sistema y copiar en bloques más grandes.
Parece derrochador—hasta que recuerdas que existen caches y los buses no perdonan.
Controladores: la capa delgada entre tú y el dolor
Si estabas en DOS, llamabas al BIOS o tocabas registros directamente. Si estabas en los primeros Windows o X11,
confiabas en un modelo de controladores que podría haber sido escrito por un proveedor cuyo KPI principal era “arranca la mayoría de las veces.”
Si estabas en estaciones de trabajo (SGI, Sun, HP), a menudo tenías mejor integración—a precio de estación de trabajo.
En términos operativos: la fiabilidad de tus gráficos era un problema de cadena de suministro.
Tu “corrección de renderizado” dependía de firmware, timings de bus y peculiaridades de chipset.
El ángulo de fiabilidad: gráficos como dependencia operativa
La gente olvida cuán críticamente operativos eran los “gráficos” en entornos corporativos:
pisos de trading, estaciones CAD, imagen médica, sistemas kiosk, centros de llamadas. Si la UI iba con lag, el negocio iba con lag.
Si la pantalla se apagaba tras suspend/resume, el help desk adquiría un nuevo pasatiempo.
Una pila gráfica pre-GPU es una parábola de SRE: acantilados de rendimiento, fallos parciales, límites no obvios
e interacciones complicadas entre hardware y software. No “la ajustas una vez.” La mantienes estable.
Una cita, porque aplica a todas las eras de sistemas y cada pantalla que alguna vez tartamudeó:
La esperanza no es una estrategia.
—idea parafraseada común en operaciones; trátala como recordatorio, no como cita.
Tres mini-historias corporativas desde las trincheras
Mini-historia 1: El incidente causado por una suposición equivocada (profundidad de color como “solo un ajuste”)
Un dashboard logístico interno se desplegó en unos cientos de thin clients y escritorios reacondicionados.
Era mayormente 2D: gráficos, tablas y un widget de mapa. El despliegue fue bien en el piloto—máquinas más nuevas, gráficos PCI decentes,
abundante RAM. Luego llegó al almacén.
El síntoma era extrañamente humano: los trabajadores se quejaban de que la UI “se sentía pegajosa.” Los movimientos del ratón se retrasaban, el desplazamiento tenía lag,
y después de unos minutos la app “se ponía al día” a saltos. No se colgaba. Simplemente envejecía en su sitio.
Soporte intentó lo habitual: reinstalar, reiniciar, cambiar ratones, culpar a la red. Nada consistente.
La suposición equivocada fue pensar que cambiar de 16 bits a 32 bits de color era una mejora cosmética inofensiva.
La nueva compilación por defecto usaba 32bpp porque se veía más limpia en monitores modernos y evitaba banding en gradientes.
En las máquinas antiguas, las escrituras al frame buffer se doblaron, y el controlador retrocedió de rutas aceleradas 2D a una ruta lenta por software
para algunas operaciones en 32bpp.
La guinda: la app redibujaba grandes regiones en cada tick de timer—aceptable en 16bpp en el hardware del piloto, desastroso en 32bpp en restos de la era ISA.
Podías ver el uso de CPU mantenerse moderado mientras el bus se asfixiaba; el hilo de UI no estaba al máximo, estaba bloqueado en escrituras lentas y llamadas al controlador.
La solución no fue heroica. Bloquearon la flota a 16bpp en esos endpoints, parchearon la app para reducir las regiones de redibujado,
y añadieron una comprobación de inicio que rechazaba habilitar “gradientes bonitos” a menos que un pequeño benchmark pasara.
La lección: las “opciones” son parte del contrato de rendimiento. Trátalas como un cambio de esquema.
Mini-historia 2: La optimización que salió mal (doble buffering por todas partes)
Un equipo de producto de kioscos quería animaciones más suaves: sin tearing, sin parpadeo. Hicieron lo que dice todo post de blog:
implementar doble buffering. Renderizar en un buffer fuera de pantalla, luego blitear a la pantalla. Limpio. Predecible. Moderno.
Lo enviaron, orgullosos del nuevo pulido.
Dos semanas después, llegaron los reportes desde campo: stalls aleatorios, frames negros ocasionales y una deriva lenta hacia el lag tras varias horas.
Los dispositivos tenían RAM modesta y gráficos integrados compartiendo ancho de banda con la CPU. Los kioscos también hacían trabajo en segundo plano:
logging local, subidas ocasionales y decodificación de imágenes.
El doble buffering convirtió pequeñas actualizaciones incrementales en copias de frame completas. El código viejo usaba rectángulos sucios;
redibujaba solo lo que cambiaba. El código nuevo siempre renderizaba la escena completa (incluso el fondo estático) en el back buffer
y luego copiaba todo al front. El ancho de banda se disparó. La presión de caché aumentó. Y cuando la memoria se apretó,
el paging empezó a roer por los bordes.
Peor aún: su llamada de “blit a pantalla” no siempre usaba aceleración por hardware en algunos chipsets. En laboratorio era rápido;
en campo a veces caía a una ruta más lenta, especialmente en ciertas profundidades de color. La optimización era correcta en teoría,
y errónea en despliegue.
Revirtieron el doble buffering universal e implementaron un híbrido:
doble buffer solo para la región animada, mantener rectángulos sucios para el resto, y añadir un watchdog que detecte cuando los blits
se vuelven más lentos y degrade la animación con gracia. También fijaron el uso de memoria para evitar swap.
La lección: un frame más suave no vale nada si no puedes sostenerlo. No optimices la estética sin medir el bus.
Mini-historia 3: La práctica aburrida pero correcta que salvó el día (captura de baseline + rollback)
Un departamento financiero utilizó una aplicación X11 legacy en thin clients Linux durante años. No era bonita, pero era estable.
El equipo responsable de endpoints tenía un hábito que parecía absurdamente conservador: antes de cualquier actualización de controlador, capturaban un baseline
de IDs de hardware, módulos del kernel, logs de Xorg y métricas básicas de rendimiento 2D. Luego lo almacenaban con la solicitud de cambio.
Un proveedor empujó una “actualización de seguridad” que incluía una renovación de la pila gráfica. Tras el despliegue a un subconjunto, usuarios reportaron que mover ventanas
dejaba estelas y el redibujado de texto iba con lag. No todos—solo ciertos modelos. El help desk empezó a recopilar capturas. Ingenieros empezaron a adivinar.
Ahí es donde se muere el tiempo.
El equipo de endpoints comparó los nuevos logs contra su baseline. Vieron de inmediato que la aceleración estaba deshabilitada en las unidades afectadas:
el módulo del controlador cambió, pero esos clientes tenían una revisión de PCI ID ligeramente diferente. La nueva pila los trató como no soportados y cayó
a un driver framebuffer genérico.
Porque tenían baselines, no necesitaron una war room. Revirtieron el paquete gráfico para esos modelos, fijaron versiones,
y abrieron un ticket al proveedor con evidencia precisa: mismatch de módulo, ruta de fallback y pasos reproducibles.
La lección: la instrumentación aburrida vence a la depuración heroica. Los baselines no son papeleo; son viajes en el tiempo.
Broma #2: Nada eleva la moral del equipo como descubrir que tu “regresión de rendimiento” en realidad es “apagara mos la aceleración.” Es como arreglar una fuga volviendo a abrir el agua.
Tareas prácticas: comandos, salidas y qué significa la salida
Estas tareas asumen que estás diagnosticando una ruta gráfica algo legacy en Linux: framebuffer, X11 o DRM/KMS básico.
Incluso si no ejecutas hardware retro, las mismas comprobaciones exponen los modos de fallo clásicos: drivers de fallback, aceleración deshabilitada,
saturación de ancho de banda y tormentas de redibujado.
Task 1: Identificar la GPU / controlador gráfico
cr0x@server:~$ lspci -nn | egrep -i 'vga|3d|display'
00:02.0 VGA compatible controller [0300]: Intel Corporation 82865G Integrated Graphics Controller [8086:2572] (rev 02)
Significado: Ya no estás adivinando; tienes vendor y device IDs.
Decisión: Busca qué driver debería enlazar (i915, nouveau, mga, etc.). Si ves un controlador integrado antiguo,
asume ancho de banda de memoria compartida y rutas de aceleración frágiles.
Task 2: Ver qué driver del kernel realmente se enlazó al dispositivo
cr0x@server:~$ lspci -k -s 00:02.0
00:02.0 VGA compatible controller: Intel Corporation 82865G Integrated Graphics Controller (rev 02)
Subsystem: Dell Device 0163
Kernel driver in use: i915
Kernel modules: i915
Significado: “Kernel driver in use” es la verdad. “Kernel modules” es lo que podría usarse.
Decisión: Si dice vesafb o fbdev cuando esperas un driver DRM nativo, probablemente estás en una ruta lenta.
Task 3: Confirmar estado DRM/KMS y detectar fallback a simpledrm
cr0x@server:~$ dmesg | egrep -i 'drm|fb0|simpledrm|vesafb' | tail -n 12
[ 1.234567] simpledrm: framebuffer at 0xe0000000, 0x300000 bytes
[ 1.234890] simpledrm: format=a8r8g8b8, mode=1024x768x32, linelength=4096
[ 2.101010] [drm] Initialized i915 1.6.0 20201103 for 0000:00:02.0 on minor 0
Significado: El arranque temprano puede iniciar con simpledrm y luego cambiar a un driver real. Eso es normal.
Decisión: Si nunca ves inicializar el driver real, estás atascado en framebuffer genérico. Espera pobre rendimiento 2D.
Task 4: Revisar Xorg por aceleración deshabilitada
cr0x@server:~$ grep -E "(EE|WW|Accel|glamor|uxa|sna)" /var/log/Xorg.0.log | tail -n 20
[ 22.123] (II) modeset(0): glamor X acceleration enabled on Mesa DRI Intel(R) 865G
[ 22.125] (WW) modeset(0): Disabling glamor because of old hardware
[ 22.126] (II) modeset(0): Using shadow framebuffer
Significado: “shadow framebuffer” es código para “software hará copias extra.”
Decisión: En hardware antiguo esto puede ser inevitable; entonces reduce redibujado y profundidad de píxel. En hardware más nuevo, es una mala configuración.
Task 5: Comprobar qué renderer OpenGL tienes (hardware vs software)
cr0x@server:~$ glxinfo -B | egrep 'OpenGL vendor|OpenGL renderer|OpenGL version'
OpenGL vendor string: Mesa
OpenGL renderer string: llvmpipe (LLVM 15.0.7, 256 bits)
OpenGL version string: 4.5 (Compatibility Profile) Mesa 23.0.4
Significado: llvmpipe significa renderizado por software. Tu CPU es ahora la GPU.
Decisión: Si esperabas aceleración por hardware, deja de afinar la app y arregla la pila de controladores. Si aceptas renderizado por software,
limita resolución/efectos y presupuesta CPU en consecuencia.
Task 6: Ver si el rendering directo está habilitado
cr0x@server:~$ glxinfo | grep -i "direct rendering"
direct rendering: Yes
Significado: “Yes” sugiere que DRI funciona, pero no garantiza rendimiento (aún podría ser software).
Decisión: Combínalo con el string del renderer. Si direct rendering es “No,” espera severa lentitud y tearing.
Task 7: Confirmar el modo actual (resolución + refresco)
cr0x@server:~$ xrandr --current
Screen 0: minimum 320 x 200, current 1024 x 768, maximum 8192 x 8192
VGA-1 connected primary 1024x768+0+0 (normal left inverted right x axis y axis) 0mm x 0mm
1024x768 60.00*+
800x600 60.32
640x480 59.94
Significado: Tienes 1024×768@60. Ese es el presupuesto bruto de píxeles que debes redibujar.
Decisión: Si el rendimiento es malo, baja resolución o profundidad de color primero. Es la palanca más rápida con mayor efecto.
Task 8: Revisar si el kernel reporta colgados o resets de GPU
cr0x@server:~$ dmesg | egrep -i 'hang|reset|gpu|ring|fault' | tail -n 20
[ 912.332100] i915 0000:00:02.0: GPU HANG: ecode 9:1:0x85dffffb, in Xorg [1234]
[ 913.001234] i915 0000:00:02.0: Resetting chip for hang on rcs0
Significado: No estás tratando con “lento”; estás tratando con inestabilidad que causa stalls.
Decisión: Reduce funciones de aceleración, prueba un driver más viejo/nuevo, o cambia la carga de trabajo (desactiva compositing).
No lo tapes con sleeps desde la app.
Task 9: Medir saturación de CPU y cambios de contexto durante lag de UI
cr0x@server:~$ vmstat 1 5
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
2 0 0 512000 42000 320000 0 0 1 2 180 300 25 10 65 0 0
5 1 0 98000 41000 250000 0 0 0 120 900 3200 65 20 10 5 0
4 2 20480 12000 20000 120000 20 40 10 600 1200 5000 70 15 5 10 0
Significado: Aumentos en r, bajo id y si/so no nulo indica contención y swapping.
Decisión: Si arranca el swap, arregla la presión de memoria primero (bajar resolución, desactivar compositing, reducir caches o añadir RAM).
El swapping convierte “gráficos” en “sistemas distribuidos,” y no de manera divertida.
Task 10: Identificar presión de ancho de banda de memoria (proxy rápido vía perf)
cr0x@server:~$ sudo perf stat -a -e cycles,instructions,cache-misses,context-switches -d -- sleep 5
Performance counter stats for 'system wide':
12,345,678,901 cycles
6,789,012,345 instructions # 0.55 insn per cycle
234,567,890 cache-misses
12,345 context-switches
5.001234567 seconds time elapsed
Significado: IPC bajo más fallos de caché altos durante el stutter es consistente con renderizado limitado por memoria o rutas de copia intensivas.
Decisión: Reduce toques de píxel (rectángulos sucios), reduce la profundidad de color y evita blends por píxel que forzan lecturas.
Task 11: Comprobar el estado del compositor (un impuesto oculto frecuente)
cr0x@server:~$ ps -ef | egrep -i 'picom|compton|mutter|kwin_x11' | grep -v grep
cr0x 1888 1 5 10:01 ? 00:02:11 picom --config /home/cr0x/.config/picom.conf
Significado: Un compositor puede convertir simples copias 2D en texturas mezcladas y buffering extra.
Decisión: En GPUs débiles/antiguas o renderizado por software, desactiva el compositing. Si lo necesitas, ajústalo (vsync off/on, sombras off).
Task 12: Capturar un benchmark ligero de renderizado X11 (sanity check)
cr0x@server:~$ x11perf -copywinwin500 | head -n 20
x11perf: description: local server
x11perf: drawing to window 500x500
CopyWinWin500 200 reps @ 4.50 msec ( 444.4/sec): Copy 500x500 from window to window
Significado: Esto aproxima qué tan rápido el sistema puede copiar un rectángulo moderado—exactamente lo que hacen las UIs 2D a la antigua.
Decisión: Compara entre máquinas o antes/después de cambios. Si es un orden de magnitud más lento tras una actualización, sospecha fallback de driver.
Task 13: Comprobar detalles del dispositivo framebuffer (cuando realmente estás en fbdev)
cr0x@server:~$ cat /sys/class/graphics/fb0/virtual_size
1024,768
Significado: Confirma el tamaño virtual del framebuffer; útil cuando las apps asumen un modo pero el kernel eligió otro.
Decisión: Si esto no coincide con tu modo esperado, arregla KMS mode setting o la configuración de Xorg antes de tocar la app.
Task 14: Revisar la lista de módulos del kernel por framebuffers en conflicto
cr0x@server:~$ lsmod | egrep 'i915|nouveau|radeon|amdgpu|vesafb|simpledrm|fbdev' | head
i915 3121152 3
drm_kms_helper 315392 1 i915
drm 622592 4 drm_kms_helper,i915
simpledrm 20480 1
Significado: Varios drivers de framebuffer pueden coexistir, pero conflictos pueden fijarte a un driver genérico.
Decisión: Si vesafb está cargado junto a un DRM real y ves problemas, añade blacklist al genérico con cautela y prueba.
Task 15: Detectar “tormentas de redibujo” desde una app (alto tráfico X11)
cr0x@server:~$ xrestop -b | head -n 12
res-base win pix GC col fnt pmap other total PID Login Name
36 12 820 18 12 2 0 45 945 2444 cr0x legacy-dashboard
22 8 120 10 6 1 0 18 177 1888 cr0x picom
Significado: El crecimiento de pixmaps y recursos puede indicar buffering offscreen excesivo o fugas que degradan el rendimiento con el tiempo.
Decisión: Si los pixmaps de una app suben indefinidamente, trátalo como fuga de memoria; política de reinicio o parche está justificada.
Task 16: Ver IO de disco y presión de journaling (porque ocurre swapping y logging)
cr0x@server:~$ iostat -xz 1 3
avg-cpu: %user %nice %system %iowait %steal %idle
35.21 0.00 12.10 9.88 0.00 42.81
Device r/s w/s rkB/s wkB/s avgrq-sz avgqu-sz await %util
sda 2.00 45.00 64.00 980.00 45.16 0.90 19.50 92.00
Significado: Alto %util y await indica que el disco está ocupado; si la UI va con lag, podrías estar haciendo paging o saturado por logs.
Decisión: Corta la fuga de IO: reduce verbosidad de logging, mueve logs, añade RAM o arregla el disco. Los gráficos no existen aislados.
Guía rápida de diagnóstico
Cuando un sistema “se siente lento,” la forma más rápida de perder tiempo es discutir sobre sensaciones.
Ejecuta lo siguiente en orden y usualmente identificarás la clase de cuello de botella en 10 minutos.
Primero: confirma que no estás en un driver de fallback
- Ejecuta
lspci -ky verifica que el driver del kernel esperado esté en uso. - Revisa
dmesgporsimpledrm/vesafbsolamente, sin inicialización de un driver DRM adecuado. - Comprueba
glxinfo -By mira si estás enllvmpipe.
Si estás en fallback: detente. Arregla eso primero. Todo lo demás es maquillaje en un framebuffer.
Segundo: aisla si estás limitado por CPU, memoria o IO
vmstat 1mientras reproduces el lag: busca altous/sy(CPU), altosi/so(swap), altowa(IO wait).iostat -xz 1si aparece swap o IO wait.perf statcomo señal rápida de fallos de caché e IPC pobre bajo carga.
Decisión: Si estás haciendo swap o IO-bound, arregla memoria/disco primero. Si la CPU está al máximo, reduce carga de renderizado por software o habilita aceleración.
Si los fallos de caché se disparan, reduce toques de píxel y copias.
Tercero: reduce el presupuesto de píxeles sin piedad
- Baja resolución (
xrandr), y prueba de nuevo. - Reduce profundidad de color si es posible (stacks legacy todavía lo permiten; los modernos menos).
- Desactiva compositing y “efectos suaves”.
Decisión: Si el rendimiento mejora de inmediato, tu cuello de botella es ancho de banda/copia, no la “lógica de la aplicación.”
Cuarto: valida los patrones de redibujado
- Usa
x11perfpara una comprobación rápida de operaciones 2D. - Observa crecimiento de recursos con
xrestoppara detectar fugas o buffering excesivo.
Decisión: Si la app genera tormentas de redibujo, arregla la invalidación y el clipping en la app en lugar de perseguir flags del driver.
Errores comunes (síntoma → causa raíz → solución)
1) El ratón se mueve pero las ventanas “se pegan” al arrastrar
Síntoma: El cursor sigue respondiendo; arrastrar ventanas deja estelas; el redibujado ocurre en bloques.
Causa raíz: El overlay de cursor por hardware funciona, pero la aceleración 2D está deshabilitada; las actualizaciones son copias por software vía shadow framebuffer.
Solución: Confirma el binding del driver; desactiva el compositor; reduce profundidad de color/resolución; asegura el driver correcto de Xorg (modesetting vs vendor).
2) Suave en laboratorio, lento en campo
Síntoma: Mismo software; sitios distintos; solo algunas máquinas andan a paso de tortuga.
Causa raíz: Revisiones de dispositivo o firmware diferentes; el driver cae a fallback en PCI IDs específicos; o menos memoria provoca swap.
Solución: Inventario de hardware IDs; compara logs de Xorg; fija versiones de driver conocidas por modelo; exige un mínimo de RAM.
3) “Mejoras visuales” causan stutter sin alta CPU
Síntoma: La UI tartamudea; CPU no está al máximo; usuarios reportan sensación “pegajosa.”
Causa raíz: Saturación de bus/VRAM; mayor bpp y blending alfa incrementaron tráfico de memoria; hilos bloqueados en llamadas al driver.
Solución: Reduce bpp/efectos; recorta regiones de redibujado; reemplaza blends por píxel con assets precompuestos; adopta rectángulos sucios.
4) Frames negros o parpadeo aleatorio tras habilitar doble buffering
Síntoma: Blanqueos periódicos, especialmente bajo carga; a veces solo en ciertos monitores.
Causa raíz: Blits de frame completo fallan en timing de refresco; page flipping no soportado de forma fiable; presión de VRAM causa fallos de asignación.
Solución: Buffering híbrido: bufferiza solo regiones animadas; usa vsync/page-flip solo cuando esté soportado; reduce resolución; limita tasa de frames.
5) El rendimiento degrada con las horas
Síntoma: Arranca bien; gradualmente va con lag; reiniciar “lo arregla.”
Causa raíz: Fuga de recursos (pixmaps, superficies offscreen), creep de swap, crecimiento de IO de logs, o ballooning de caché del compositor.
Solución: Rastrear recursos (xrestop), memoria (vmstat), disco (iostat); implementar política de reinicio; parchear fugas.
6) Tearing visible en animaciones y desplazamiento
Síntoma: Líneas horizontales de tear durante movimiento.
Causa raíz: Sin vsync/page flipping; escrituras directas al front buffer; compositor deshabilitado o mal configurado.
Solución: Habilita vsync donde esté soportado; usa compositing en hardware capaz; o reduce movimiento/coste de refresco si el hardware no puede seguir.
7) “Habilitamos aceleración” pero todo empeoró
Síntoma: Mayor uso de CPU, menor responsividad tras cambiar drivers.
Causa raíz: La ruta de aceleración activa fallbacks costosos (ej., operaciones no soportadas fuerzan readbacks); mismatch entre Mesa/driver.
Solución: Valida el renderer real (glxinfo -B); prueba método de aceleración alternativo (UXA/SNA/glamor según stack);
mantén versiones consistentes; prefiere menos características antes que características buggeadas.
Listas de verificación / plan paso a paso
Paso a paso: estabilizar un entorno gráfico legacy
-
Inventario de hardware. Captura
lspci -nny guárdalo con el perfil de la máquina.
Por qué: Revisiones diferentes se comportan distinto; no puedes gestionar lo que no nombras. -
Bloquea drivers conocidos por clase de hardware.
Por qué: Las pilas gráficas pueden tener regresiones. Trátalas como kernels: despliegue en etapas y fijado de versiones. -
Baseline de rendimiento. Registra
x11perf -copywinwin500, resolución, estado del compositor.
Por qué: Cuando alguien dice “se siente más lento,” puedes responder con números. -
Establece un modo por defecto sensato. Elige una resolución y refresco que el hardware sostenga.
Por qué: La ganancia de rendimiento más barata son menos píxeles. -
Decide sobre compositing explícitamente. O lo desactivas o lo configuras; no lo dejes “pasar por defecto.”
Por qué: Los compositores añaden buffering y blending, que es exactamente donde los sistemas antiguos mueren. -
Presupuesta memoria. Asegura que el sistema no haga swap bajo carga normal.
Por qué: El swap convierte pequeños stutters en segundos de silencio. -
Controla patrones de redibujado en las apps. Prefiere rectángulos sucios; evita repintados completos de ventana por timers.
Por qué: Las escrituras al framebuffer son tu “llamada API” más cara. -
Prueba con assets de peor caso. Fuentes más grandes, pantallas más cargadas, máxima densidad de datos.
Por qué: Si apenas pasa en condiciones ideales, fallará en producción. -
Define modos de degradación. Menos animaciones, reducir alfa, volver a renderizado más simple si cae el rendimiento.
Por qué: Una UI estable “menos bonita” vence a una UI bonita que se bloquea. -
Mantén capacidad de rollback. Guarda paquetes y configs de último conocido bueno.
Por qué: Cuando los gráficos se rompen, a menudo necesitas recuperar sin una UI local funcional.
Checklist: validación previa al cambio (actualización de driver, refresco OS, nueva UI)
- Confirma binding del driver del kernel (
lspci -k). - Comprueba la ruta del renderer (
glxinfo -B). - Registra modo actual (
xrandr --current). - Ejecuta un benchmark 2D rápido (subconjunto de
x11perf). - Confirma elección y configuración del compositor (
ps -ef). - Verifica que no haya colgados de GPU en logs tras estrés (
dmesg). - Comprueba margen de memoria bajo carga (
vmstat). - Verifica que el disco no esté saturado (
iostat), especialmente en thin clients con flash barato.
Checklist: respuesta de emergencia cuando la UI es inútil
- Cambia a una resolución más baja vía shell remota cuando sea posible.
- Desactiva compositing y reinicia la sesión.
- Revierte paquetes de la pila gráfica a la baseline.
- Si estás atascado en fbdev, arranca con parámetros de kernel conocidos buenos y confirma carga de módulos.
- Reduce la carga de redibujado de la app: desactiva animaciones, baja frecuencia de actualización, simplifica visuales.
Preguntas frecuentes
1) ¿Qué hacía realmente una “tarjeta gráfica” antes de las GPUs?
A menudo: scanear un frame buffer al monitor, gestionar una paleta y quizá acelerar operaciones 2D como copias y rellenos de rectángulos.
La CPU seguía dibujando la mayoría de las cosas, especialmente lo que no era una simple transferencia de bloques.
2) ¿Por qué 320×200 fue tan común en los juegos antiguos de PC?
Porque era rápido y simple. Cabía bien en memoria, se mapeaba linealmente en el famoso modo de 256 colores, y no exigía mucho ancho de banda.
Los juegos podían actualizar una porción decente de la pantalla sin caer en un precipicio de rendimiento.
3) ¿Qué es un “blitter” y por qué debería importarme?
Un blitter es hardware dedicado a mover bloques de píxeles (BitBLT) y a veces a realizar operaciones raster simples.
Importaba porque la UI y los juegos 2D están dominados por “copiar este rectángulo,” no por “calcular este triángulo.”
En términos operativos, es un motor DMA para píxeles.
4) ¿El renderizado por software siempre fue lento?
No siempre. A menudo era sorprendentemente competitivo porque la CPU podía ser decente en matemáticas, y los programadores ingeniosos minimizaban escrituras de memoria.
Pero era frágil: una pasada extra sobre el frame buffer, un blend más, o mayor profundidad de color podía colapsar el rendimiento.
5) ¿Por qué los cambios en profundidad de color causaban desastres?
Porque el ancho de banda y el almacenamiento escalan con bytes por píxel. Pasar de 16bpp a 32bpp dobla el tráfico del frame buffer.
En buses antiguos y gráficos integrados, eso no es un “pequeño” cambio; puede ser todo el presupuesto.
6) ¿Cómo evitaban el parpadeo sin compositores modernos?
Rectángulos sucios, orden cuidadoso de dibujos, sincronizar actualizaciones con el blank vertical cuando era posible y a veces page flipping
si el hardware soportaba múltiples buffers. También diseñaban UIs que no redibujaban constantemente—porque no podían.
7) ¿Cuál es el equivalente moderno de un “cuello de botella de framebuffer”?
Cualquier momento en que estés dominado por copias de memoria y ancho de banda: compositing por software, escritorios remotos que empujan actualizaciones de pantalla completas,
o aplicaciones que fuerzan readbacks de GPU. Las etiquetas cambiaron; la física no.
8) Si mi sistema muestra llvmpipe, ¿siempre es malo?
Depende de la carga. Para dashboards estáticos o 2D ligero puede ser aceptable. Para compositing pesado, vídeo o 3D, suele ser un problema.
La movediza práctica es tratar llvmpipe como una señal de capacidad: estás usando CPU para hacer gráficos.
9) ¿Cuál es la palanca de ajuste de mayor influencia en sistemas gráficos antiguos?
Reduce píxeles tocados por segundo. Eso generalmente significa menor resolución, menos repintados de ventana completos, menos blends y menos compositing.
Si debes optimizar, optimiza la estrategia de redibujado antes de micro-optimizar matemáticas.
10) ¿Por qué los problemas gráficos legacy se sienten “aleatorios”?
Porque a menudo se sientan en la intersección de revisiones de hardware, peculiaridades de firmware y fallbacks de drivers.
Dos máquinas que parecen idénticas en compras pueden comportarse distinto ante un driver.
Por eso los baselines y los IDs de hardware importan.
Conclusión: pasos prácticos siguientes
Antes de NVIDIA y la era GPU, “gráficos” era un presupuesto que podías contar: bytes por píxel, píxeles por frame, frames por segundo,
y el bus que debía llevarlo todo. La cultura de ingeniería que surgió de ese periodo—rectángulos sucios, trucos de paleta,
buffering cuidadoso y sospecha de mejoras visuales “gratis”—no era nostalgia. Era lo que funcionaba bajo restricciones duras.
Si operas o modernizas algo que todavía huele a esa era (kioscos embebidos, thin clients, HMIs industriales,
escritorios remotos, apps legacy X11), haz tres cosas esta semana:
- Prueba la ruta de renderizado. Confirma el driver real y el renderer en uso; destierra fallbacks silenciosos.
- Baseline y fija. Captura logs y benchmarks simples, y fija una pila gráfica conocida buena por clase de hardware.
- Reduce redibujado. Reduce toques de píxeles: resolución, profundidad de color, compositing y estrategia de repintado.
El mundo pre-GPU no era más amable. Era simplemente más honesto: podías ver el cuello de botella con tus ojos.
Trata esa honestidad como una ventaja de diagnóstico y mantendrás incluso gráficos legacy lo bastante estables para que el negocio funcione.