La carrera armamentista de DirectX: por qué los controladores a veces superan al silicio

¿Te fue útil?

Actualizaste la GPU. La hoja de especificaciones prometía la luna. Luego tu gráfico de tiempos por frame parece un sismógrafo,
la CPU consume un núcleo por completo y la tarjeta “más rápida” rinde como si hiciera trabajo caritativo para el silicio del año pasado.
Si alguna vez viste una nueva versión de controlador arreglar mágicamente un juego que asumiste estaba “limitado por la GPU”,
has visto la verdad incómoda: en el mundo de DirectX, el controlador suele ser el producto de rendimiento.

Esto no es una conspiración de los fabricantes; es arquitectura. DirectX es un contrato con lagunas, y el controlador es
el abogado, el juez y a veces la persona que mueve los muebles en silencio para que tu aplicación deje de tropezar.
Hablemos de cómo los controladores pueden superar al silicio, qué significa eso para sistemas de producción reales (sí, los juegos cuentan),
y cómo diagnosticar cuellos de botella sin recurrir al culto de “actualiza los controladores lol”.

Controladores vs silicio: de dónde viene realmente el rendimiento

Las GPUs son brutalmente rápidas en el trabajo para el que están diseñadas. También son brutalmente exigentes respecto a cómo se les alimenta.
La diferencia entre “la GPU está al 40% de uso” y “la GPU está saturada” a menudo no son transistores. Son
la entrega de comandos, la compilación de shaders, la planificación, la gestión de residencia y mil pequeñas decisiones
sobre transiciones de estado y sincronización.

En la práctica, tu tiempo por frame es la suma de:

  • Trabajo en la CPU: construcción de listas de comandos, culling, física, animación y el coste de hablar con el controlador/runtime.
  • Trabajo del controlador/runtime: traducir llamadas de la API a paquetes de hardware, validar, cachear, gestionar memoria y estado.
  • Trabajo en la GPU: ejecutar shaders, etapas de función fija, rasterización, núcleos RT, motores de copia, etc.
  • Presentación y pacing: composición, vsync, comportamiento del modo flip y la planificación del OS alrededor de ello.

Las GPUs modernas pueden estar inactivas porque la CPU no pudo enviar trabajo lo bastante rápido, o porque el controlador no pudo
traducirlo eficientemente, o porque la GPU espera la residencia de memoria, o porque el compositor del SO decidió que tu ventana es
“especial” hoy. Los controladores son el pegamento, y el pegamento puede ser la parte más rápida de tu sistema o la que se vuelve pegajosa bajo presión.

Cuando la gente dice “los controladores a veces superan al silicio”, se refieren a esto: una actualización del controlador puede desbloquear
un rendimiento que el hardware ya tenía, porque el controlador es quien elige la generación de código, el batching, la planificación y la caché.
Dos versiones diferentes del controlador pueden hacer que la misma GPU se comporte como dos productos distintos.

Qué promete realmente DirectX (y qué no)

DirectX no es “una capa delgada sobre el hardware”. Es una promesa de compatibilidad con un conjunto de abstracciones.
Esas abstracciones cambian con el tiempo—Direct3D 9 vs 11 vs 12 son básicamente religiones diferentes—y cada cambio
altera quién asume qué costes.

Direct3D 11: el controlador hacía mucho trabajo invisible

D3D11 hizo productivos a los desarrolladores permitiéndoles ser algo irresponsables. Podías spamear llamadas de dibujo,
cambiar estado constantemente y confiar en que el controlador gestionaría riesgos, reordenaría trabajo y parchearía decisiones.
Eso no era gratis. El controlador a menudo hacía un trabajo pesado por draw en la CPU, y ese overhead podía dominar el tiempo por frame.

Los proveedores se hicieron muy buenos optimizando controladores D3D11 porque tenían que serlo. Si tu controlador no podía “tragar”
un título real de D3D11, tu GPU parecía lenta en benchmarks que vendían GPUs. El controlador se convirtió en un arma competitiva,
y el arma más despiadada es la que los usuarios no ven.

Direct3D 12: obtienes poder, pero también la factura

D3D12 es una API de bajo nivel. Se espera que la aplicación gestione más explícitamente: estados de recursos, sincronización,
montones de descriptores, PSOs y a menudo la estrategia de compilación de shaders. En teoría, menos overhead del controlador.
En realidad, más oportunidades para crear cargas patológicas y luego culpar “al controlador”.

El controlador todavía importa masivamente en D3D12 porque:

  • La compilación de shaders, el cache y la generación de código del controlador aún pueden diferir por proveedor y versión.
  • La residencia de memoria y el paging siguen siendo mediadas por WDDM y las políticas del controlador.
  • La planificación sigue sujeta a reglas del SO + controlador (colas de hardware, prioridades, granularidad de preempción).
  • El comportamiento de la biblioteca de pipeline y la caché de PSO puede decidir si tu “primera ejecución” es un festival de stutter.

DirectX es un blanco móvil, y el “blanco” es tu juego/aplicación publicada

El detalle operativo más importante: los controladores se publican continuamente. Tu hardware se envía una vez.
Eso significa que la “especificación de rendimiento” de una GPU para una carga DirectX es en realidad función de:
hardware + versión del controlador + compilación del OS + compilación del juego + ajustes + overlays + compositores en segundo plano.
Enhorabuena, tu benchmark ahora es un sistema distribuido.

Cómo ganan los controladores: las palancas de rendimiento que no ves

Si quieres un modelo mental: el silicio proporciona potencial, los controladores deciden si lo cobras.
Aquí están las palancas principales donde los controladores rutinariamente mueven rendimiento suficiente como para vencer a las diferencias de hardware.

1) Compiladores de shaders: los reyes silenciosos

HLSL se compila a DXIL (o a bytecode antiguo), y luego el controlador compila de nuevo a ISA para la GPU.
Esa última etapa es donde vive gran parte de la “magia del controlador”: programación de instrucciones, asignación de registros,
decisiones de ocupación de wave, transformaciones matemáticas y especialización basada en peculiaridades del hardware.

Una actualización del controlador puede cambiar el codegen lo suficiente como para:

  • Aumentar la ocupación (menos registros) y mejorar el rendimiento en cargas sensibles al ancho de banda.
  • Reducir stalls mejorando la programación de instrucciones alrededor de la latencia de fetch de texturas.
  • Corregir malas compilaciones o problemas de precisión que forzaban rutas de fallback más lentas.
  • Ajustar comportamiento de operaciones de subgrupo/wave que afectan el coste por divergencia.

Los compiladores de shaders son también donde ocurre el “se volvió más rápido en este proveedor”, porque el compilador de cada proveedor
tiene heurísticas y madurez distintas. No es hacer trampa; es ingeniería. Pero es ingeniería que cambia el producto después de comprarlo.

2) Manejo y caché de Pipeline State Object (PSO)

Los PSO de D3D12 están pensados para crearse por adelantado. Si creas PSOs en tiempo de ejecución a mitad de frame, mereces el stutter
que obtienes. Pero la realidad es desordenada: pipelines de contenido, mods, permutaciones dinámicas y cambios en servicios en vivo.
El controlador puede ayudar cacheando PSOs compilados efectivamente, o perjudicar invalidando cachés entre actualizaciones.

En Windows, también existen cachés en disco y cachés por aplicación. Cuando una actualización de controlador los reinicia, tu “primera ejecución”
se convierte en un festival de compilación. La segunda ejecución se ve bien y todos discuten en foros sobre placebo.

3) Envío y batching de comandos

Incluso con D3D12, hay overhead alrededor del envío de listas de comandos, primitivas de sincronización y gestión de colas.
Los controladores pueden optimizar cómo bufferizan y envían trabajo al kernel, y cómo coalescen envíos pequeños.

D3D11 es más dramático: el controlador a veces reordena, agrupa y deduplica cambios de estado. Un controlador que
se vuelve más inteligente sobre “este cambio de estado no hace nada” puede acelerar un título sin tocar el juego.

4) Residencia de memoria, paging y el “acantilado de VRAM”

La gestión de memoria gráfica en Windows es un problema de tres cuerpos: intención de la app, política del controlador, política del OS.
Cuando tu working set cabe en VRAM, la vida es buena. Cuando no, caes de un acantilado hacia paging,
stalls y “¿por qué mi 1% low es tan malo?”.

Los controladores influyen en decisiones de residencia, heurísticas de expulsión y cuán agresivo es el prefetch.
Dos versiones de controlador pueden comportarse distinto bajo presión: una thrashéa, otra degrada suavemente.
Si persigues stutter, asume que estás cerca de un límite de residencia hasta que se pruebe lo contrario.

5) Planificación y preempción: WDDM no es tu amigo, es tu casero

Las políticas de planificación de WDDM determinan cómo los contextos comparten la GPU. Los juegos compiten con navegadores,
reproducción de vídeo, overlays de captura, paneles RGB y el compositor del SO. El controlador participa en esa planificación.

Una actualización del controlador puede ajustar la granularidad de preempción, prioridades de cola o el comportamiento temporal alrededor del present.
Eso puede cambiar de forma significativa el pacing incluso si el FPS medio se mantiene igual.

6) Modos de present, pacing de frames y la “suavidad” como propiedad de ingeniería

El usuario no experimenta “FPS medio”. Experimenta tiempos por frame y pacing.
El modo de present (modelo flip vs blit), vsync, VRR y el comportamiento del compositor deciden si tu presupuesto de 16.6ms
es estable o una ruleta.

Los controladores pueden:

  • Mejorar heurísticas de pacing para ciertos patrones de present.
  • Cambiar cómo interactúan con el compositor en modo sin bordes vs pantalla completa exclusiva.
  • Corregir errores de temporización que causan microstutter en tasas de refresco específicas.

7) Workarounds: el arte poco glamuroso de entregar

La base de datos de perfiles de aplicaciones y workarounds del controlador es enorme. Algunos son conmutadores oficiales,
otros son silenciosos. Estos workarounds pueden desactivar rutas rápidas defectuosas, forzar diferentes opciones de compilación de shaders
o ajustar la gestión de recursos para títulos específicos.

Por eso a veces ves un juego nuevo “rendir mejor en el proveedor X” después de un driver day-one: no es que el silicio aprendiera trucos de la noche a la mañana.
El controlador aprendió cómo sobrevivir al comportamiento de ese juego.

Broma #1: Los controladores son como el café: todos dicen que pueden funcionar sin ellos y luego los ves intentarlo.

Hechos e historia: la carrera armamentista en 10 cicatrices

  • Era D3D9: “reemplazos de shader” eran comunes: los controladores a veces intercambiaban patrones de código shader por equivalentes más rápidos cuando los reconocían.
  • D3D10 introdujo un reinicio importante: endureció el modelo de la API y rompió mucho del comportamiento “ingenioso” de los controladores de D3D9.
  • D3D11 popularizó el renderizado multihilo… hasta cierto punto: existían contextos diferidos, pero muchos motores aún pegaban con bloqueos del controlador y cuellos de botella en CPU.
  • Mantle influyó en D3D12: la industria tomó la pista de que el overhead del controlador mataba escenas con muchas draw calls.
  • La evolución de WDDM cambió el rendimiento: WDDM 1.x vs 2.x trajo dinámicas diferentes de gestión de memoria y planificación para GPUs modernas.
  • Shader Model 6 avanzó hacia DXIL: la canalización de compilación se estandarizó más, pero el backend del controlador aún decide la ISA final.
  • El modelo flip de present se volvió norma: Windows moderno prefiere el modelo flip por eficiencia; cambia latencia y pacing respecto a rutas blit antiguas.
  • La adopción de DXR expuso brechas de madurez en controladores: el rendimiento temprano en ray tracing a menudo variaba mucho con actualizaciones de controladores porque la pila era nueva y las rutas rápidas evolucionaban.
  • Resizable BAR importó más en algunas cargas DX: habilitar acceso CPU a rangos mayores de VRAM cambió patrones de transferencia y redujo overhead en ciertos escenarios.
  • Los “drivers day-one” se convirtieron en expectativa del mercado: no porque el marketing lo pidiera, sino porque workarounds y ajuste de caché de shaders forman parte de la preparación de lanzamiento.

Modos de fallo comunes: cuando el controlador se convierte en el cuello de botella

Si gestionas sistemas de producción, aprendes a odiar colas invisibles. Los controladores gráficos son básicamente colas invisibles con un ventilador adjunto.
Estos son los modos de fallo que aparecen en despliegues reales de DirectX.

Overhead de CPU del controlador (especialmente D3D11)

Síntomas: un núcleo de CPU pegado, GPU infrautilizada, FPS limitado por el “render thread”, escalado con CPUs más rápidas más que con GPUs más rápidas.
Las causas raíz incluyen cambios de estado habladores, draw calls excesivos, actualizaciones de recursos ineficientes o serialización del controlador por bloqueos.

Stutter por compilación de shaders (DX12, y también DX11 si se hace mal)

Síntomas: picos enormes al encontrar un efecto por primera vez, “la primera partida es horrible”, la segunda ejecución está bien, los picos coinciden con materiales nuevos.
Causa raíz: compilar shaders/PSOs a demanda, invalidaciones de caché o caché de shaders del controlador deshabilitado/borrado.

Thrash de residencia en VRAM

Síntomas: stalls periódicos, caídas súbitas al girar la cámara, gran variación con texturas de alta resolución, peor en modo sin bordes con otras apps abiertas.
Causa raíz: el working set excede la VRAM o la fragmentación causa expulsiones; paging a memoria del sistema por parte del driver/OS.

Problemas de present/composición

Síntomas: “el FPS es alto pero se siente mal”, latencia de entrada inconsistente, stutter solo en sin bordes, problemas al activar HDR/VRR.
Causas raíz: cambios de ruta de compositor, modos de refresco desajustados, overlays enganchando present o bugs del controlador en modos de present específicos.

Regresiones del controlador y “arreglos” que mueven el problema

Síntomas: un juego mejora, otro empeora, o tu carga estable se vuelve inestable tras una actualización.
Causa raíz: cambios heurísticos, cambios en cachés o workarounds que habilitan/deshabilitan rutas rápidas.

Guion rápido de diagnóstico (primero/segundo/tercero)

Esta es la lista de comprobación que uso cuando alguien dice “el rendimiento DX es raro” y quiero señal en 15 minutos.
El objetivo es identificar cuál cola está hambrienta: CPU, controlador, GPU, residencia de memoria o present.

Primero: decide si estás limitado por CPU/controlador o por GPU

  • Observa el uso por núcleo de la CPU y la utilización de los motores de la GPU.
  • Si la utilización de la GPU es baja pero un núcleo de CPU está caliente, sospecha overhead del controlador o cuello de botella del hilo de render.
  • Si la GPU está alrededor del 95–100% y la CPU es moderada, probablemente estás limitado por la GPU (entonces enfócate en shaders, ancho de banda y ajustes).

Segundo: identifica la clase de stutter (compilación, residencia, present)

  • Stutter en efectos la primera vez: compilación de shader/PSO.
  • Stutter al girar la cámara o entrar en nuevas áreas: streaming/residencia.
  • Stutter con tiempo de GPU estable pero present irregular: pacing/compositor/overlays.

Tercero: haz bisect de variables agresivamente

  • Alterna fullscreen vs sin bordes.
  • Desactiva overlays (captura, chat, monitorización).
  • Prueba una versión de controlador conocida y estable (no “la más reciente”, sino estable).
  • Borra cachés de shader solo cuando reproduzcas intencionadamente el comportamiento de “primera ejecución”.

La regla de decisión: si no puedes nombrar la cola que está causando el cuello de botella, no estás diagnosticando aún—estás narrando.

Tareas prácticas con comandos: medir, decidir, repetir

Estas tareas están diseñadas para sistemas Windows, pero uso un shell tipo bash (Git Bash, MSYS2, WSL llamando utilidades de Windows).
Los comandos son realistas. La idea es disciplina: captura evidencia, interprétala y decide qué hacer después.

Tarea 1: Confirmar modelo de GPU y versión del controlador

cr0x@server:~$ powershell.exe -NoProfile -Command "Get-CimInstance Win32_VideoController | Select-Object Name,DriverVersion,DriverDate | Format-Table -Auto"
Name                          DriverVersion      DriverDate
----                          -------------      ----------
NVIDIA GeForce RTX 4070       31.0.15.5212       11/28/2024 12:00:00 AM

Qué significa: Ya tienes la verdad de base para triage de regresiones y reportes de bugs al proveedor.
Decisión: Si el rendimiento cambió recientemente, fija la última versión buena conocida y planifica un bisect (no adivines).

Tarea 2: Comprobar build de Windows e indicios de versión de WDDM

cr0x@server:~$ powershell.exe -NoProfile -Command "Get-ComputerInfo | Select-Object WindowsProductName,WindowsVersion,OsBuildNumber | Format-List"
WindowsProductName : Windows 11 Pro
WindowsVersion     : 23H2
OsBuildNumber      : 22631

Qué significa: Las builds del OS pueden cambiar el comportamiento del compositor, la planificación y las peculiaridades de la pila gráfica.
Decisión: Si un problema aparece después de una actualización de Windows, reprodúcelo en una máquina de control o revierte para confirmar antes de culpar a la GPU.

Tarea 3: Capturar rápidamente la utilización de motores de la GPU

cr0x@server:~$ powershell.exe -NoProfile -Command "Get-Counter '\GPU Engine(*)\Utilization Percentage' -SampleInterval 1 -MaxSamples 3 | Select-Object -ExpandProperty CounterSamples | Select-Object InstanceName,CookedValue | Sort-Object CookedValue -Descending | Select-Object -First 10 | Format-Table -Auto"
InstanceName                                        CookedValue
------------                                        ----------
pid_1234_luid_0x00000000_0x0000_engtype_3D             92.3412
pid_1234_luid_0x00000000_0x0000_engtype_Copy            4.1201
pid_5678_luid_0x00000000_0x0000_engtype_VideoDecode     1.0033

Qué significa: Alta utilización 3D sugiere límite en GPU; 3D baja con CPU alta sugiere límite en envío/controlador.
Decisión: Si 3D está bajo, deja de tocar ajustes gráficos y empieza a perfilar overhead de CPU/controlador.

Tarea 4: Comprobar CPU por proceso e identificar saturación mono-hilo

cr0x@server:~$ powershell.exe -NoProfile -Command "Get-Process | Sort-Object CPU -Descending | Select-Object -First 8 Name,Id,CPU,Threads | Format-Table -Auto"
Name        Id    CPU   Threads
----        --    ---   -------
GameClient  1234  987.4  62
Discord     4321  112.6  45
chrome      8888   71.9  83

Qué significa: Alto tiempo de CPU y muchos hilos no prueban render multihilo; a menudo enmascaran un hilo de render caliente.
Decisión: Si el FPS es bajo y un núcleo está pegado en el Administrador de Tareas, trátalo como límite CPU/controlador hasta que el tiempo de GPU demuestre lo contrario.

Tarea 5: Inspeccionar errores relacionados con DXGI y driver en los logs del Visor de Eventos

cr0x@server:~$ powershell.exe -NoProfile -Command "Get-WinEvent -LogName System -MaxEvents 50 | Where-Object {$_.ProviderName -match 'Display|dxgkrnl'} | Select-Object TimeCreated,Id,ProviderName,Message | Format-Table -Wrap"
TimeCreated           Id ProviderName Message
-----------           -- ------------ -------
1/12/2026 9:41:02 PM 4101 Display     Display driver nvlddmkm stopped responding and has successfully recovered.

Qué significa: Los TDRs y resets del controlador a menudo se hacen pasar por “stutter aleatorio” o “hitching extraño”.
Decisión: Si ves 4101 o advertencias de dxgkrnl, deja de optimizar y empieza a estabilizar: relojes, temperaturas, energía y la integridad del controlador primero.

Tarea 6: Comprobar el estado de composición de DWM y la configuración de refresco

cr0x@server:~$ powershell.exe -NoProfile -Command "Get-Process dwm | Select-Object Name,Id,CPU,StartTime | Format-List"
Name      : dwm
Id        : 1024
CPU       : 58.12
StartTime : 1/12/2026 7:03:11 PM

Qué significa: Si la CPU de DWM sube durante el juego en modo sin bordes, la composición/overlays pueden estar interfiriendo.
Decisión: Prueba pantalla completa exclusiva o desactiva overlays; si eso arregla el pacing, tienes un problema de ruta de present, no de shaders.

Tarea 7: Identificar overlays y hooks de captura como sospechosos principales

cr0x@server:~$ powershell.exe -NoProfile -Command "Get-Process | Where-Object {$_.Name -match 'GameBar|Xbox|RTSS|obs|Discord|Steam|nvcontainer'} | Select-Object Name,Id | Format-Table -Auto"
Name         Id
----         --
GameBar      7777
Discord      4321
Steam        2468
nvcontainer  1357

Qué significa: Los overlays pueden enganchar Present, añadir trabajo a la GPU o cambiar el comportamiento del flip.
Decisión: Para el diagnóstico, ejecuta en limpio: desactiva overlays uno a uno y mide cambios en el pacing de frames.

Tarea 8: Comprobar actividad de disco y presión en la ubicación de la caché de shaders

cr0x@server:~$ powershell.exe -NoProfile -Command "Get-Counter '\PhysicalDisk(_Total)\Disk Bytes/sec' -SampleInterval 1 -MaxSamples 3 | Select-Object -ExpandProperty CounterSamples | Select-Object CookedValue"
CookedValue
-----------
124928512
98234368
110231552

Qué significa: Grandes ráfagas de disco durante el juego a menudo correlacionan con escrituras de caché de shaders o streaming de activos.
Decisión: Si el stutter coincide con picos de disco, separa la compilación de shaders (efecto de primera ejecución) del streaming (área nueva) repitiendo la misma escena.

Tarea 9: Confirmar estado del pagefile (el paging puede amplificar problemas de residencia)

cr0x@server:~$ powershell.exe -NoProfile -Command "Get-CimInstance Win32_PageFileSetting | Select-Object Name,InitialSize,MaximumSize | Format-Table -Auto"
Name               InitialSize MaximumSize
----               ----------- -----------
C:\pagefile.sys    16384       32768

Qué significa: Pagefiles demasiado pequeños pueden causar comportamiento de presión de memoria agresivo que parece inestabilidad de GPU.
Decisión: Si estás cerca de los límites de RAM mientras juegas/creas contenido, usa tamaño gestionado por el sistema o un tamaño fijo sensato; no “desactives el pagefile por rendimiento”.

Tarea 10: Comprobar presión de memoria rápidamente

cr0x@server:~$ powershell.exe -NoProfile -Command "Get-Counter '\Memory\Available MBytes' -SampleInterval 1 -MaxSamples 3 | Select-Object -ExpandProperty CounterSamples | Select-Object CookedValue"
CookedValue
-----------
812
790
765

Qué significa: Poca RAM disponible aumenta la probabilidad de stutter por paging y contención de streaming de activos.
Decisión: Si la RAM disponible baja por debajo de ~1–2GB durante el juego, cierra aplicaciones en segundo plano antes de culpar a la GPU.

Tarea 11: Validar que el juego está usando realmente DX12 (o DX11)

cr0x@server:~$ powershell.exe -NoProfile -Command "Get-Process GameClient | Select-Object -ExpandProperty Modules | Where-Object {$_.ModuleName -match 'd3d12|d3d11|dxgi'} | Select-Object ModuleName,FileName | Format-Table -Auto"
ModuleName FileName
---------- --------
dxgi.dll   C:\Windows\System32\dxgi.dll
d3d12.dll  C:\Windows\System32\d3d12.dll

Qué significa: Te sorprendería cuántas veces se prueba “rendimiento DX12” mientras la app silenciosamente cae a DX11.
Decisión: Si se carga la API equivocada, arregla opciones de lanzamiento/configuración primero; no interpretes números de rendimiento hasta confirmar la ruta de la API.

Tarea 12: Comprobar plan de energía y comportamiento de frecuencia de CPU

cr0x@server:~$ powercfg.exe /getactivescheme
Power Scheme GUID: 381b4222-f694-41f0-9685-ff5bb260df2e  (Balanced)

Qué significa: Ahorro de energía agresivo puede aumentar la latencia y empeorar el pacing en escenarios limitados por CPU/controlador.
Decisión: Para diagnóstico, usa un plan de alto rendimiento en equipos de escritorio, luego valida el impacto antes de mantenerlo (los portátiles son diferentes).

Tarea 13: Detectar presión de memoria GPU vía herramientas del proveedor (ejemplo NVIDIA)

cr0x@server:~$ nvidia-smi --query-gpu=name,driver_version,utilization.gpu,memory.used,memory.total --format=csv
name, driver_version, utilization.gpu [%], memory.used [MiB], memory.total [MiB]
NVIDIA GeForce RTX 4070, 552.12, 91 %, 11342 MiB, 12282 MiB

Qué significa: Memoria usada cerca del total sugiere que coqueteas con expulsiones y paging (especialmente a 4K + texturas altas).
Decisión: Si la memoria está >90% y ves stutter, reduce calidad de texturas o resolución primero; no persigas “ajustes del controlador” todavía.

Tarea 14: Capturar un trazo ETW rápido para planificación GPU/present (configuración)

cr0x@server:~$ wpr.exe -start GPU -filemode
WPR: Started recording with profile GPU.

Qué significa: Estás grabando un trazo ETW que luego puede inspeccionarse en WPA para ver retrasos de present, colas de GPU y envío en CPU.
Decisión: Si no puedes identificar el cuello de botella con contadores, toma un trazo. Adivinar es más lento que medir.

Tarea 15: Detener el trazo y guardarlo

cr0x@server:~$ wpr.exe -stop C:\temp\gpu-trace.etl
WPR: Trace successfully saved to C:\temp\gpu-trace.etl

Qué significa: Ahora tienes un archivo que muestra dónde fue el tiempo: CPU, GPU, present, DWM, colas del controlador.
Decisión: Usa WPA para confirmar: ¿estás bloqueado en present, esperando la GPU o limitado por tiempo de CPU en llamadas al controlador?

Tarea 16: Comprobación básica de red (sí, importa para reportes de “stutter”)

cr0x@server:~$ ping -n 10 1.1.1.1
Pinging 1.1.1.1 with 32 bytes of data:
Reply from 1.1.1.1: bytes=32 time=15ms TTL=58
Reply from 1.1.1.1: bytes=32 time=16ms TTL=58
Reply from 1.1.1.1: bytes=32 time=120ms TTL=58
Reply from 1.1.1.1: bytes=32 time=16ms TTL=58

Ping statistics for 1.1.1.1:
    Packets: Sent = 10, Received = 10, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
    Minimum = 15ms, Maximum = 120ms, Average = 26ms

Qué significa: Los jugadores reportan “stutter” que en realidad es jitter de red causando hitching en animaciones/streaming en títulos online.
Decisión: Si los gráficos de tiempos por frame no muestran baches pero la experiencia de usuario sí, comprueba la variación de red antes de reescribir tu renderer.

Tres microhistorias desde la realidad corporativa

Microhistoria 1: El incidente causado por una suposición equivocada

Un estudio lanzó una actualización DX12 para un juego en vivo. La lista de cambios parecía limpia: menos draw calls, mejor batching,
barreras más explícitas y un buen paso de preconstrucción de PSO durante las pantallas de carga. El equipo asumió que si el juego
funcionaba bien en sus máquinas internas, funcionaría bien en las máquinas de los clientes con “GPUs similares”.

En la semana de lanzamiento, llegaron tickets de soporte: congelamientos aleatorios de 2–3 segundos en la primera partida, a veces seguidos de un crash.
El congelamiento no se reproducía consistentemente en la oficina. Cuando se reproducía, alguien encogía de hombros y culpaba “a Windows”.
Mientras tanto, el canal de incidentes se llenó de jugadores compartiendo soluciones como “juega un partido contra bots primero” y “no alt-tabees”.

La suposición equivocada fue sutil: asumieron que el caching de shaders y PSO se comportaba igual entre versiones de controladores y builds de Windows.
En un subconjunto de sistemas de clientes, la caché de shaders del controlador estaba efectivamente fría cada ejecución debido a una configuración de perfil y a
una herramienta de limpieza de disco que borraba directorios de caché. Su paso de “preconstruir PSOs durante la carga” compilaba algunos pero no todas las permutaciones.
Las faltantes se compilaban a demanda durante el primer tiroteo, justo cuando el juego también hacía streaming de texturas.

La solución no fue “decir a los jugadores que actualicen controladores”, aunque eso redujo el radio del problema. La solución real fue ingeniería:
añadir una ruta de warmup de shaders/PSO determinista que cubriera permutaciones comunes, persistir una caché de PSO gestionada por la aplicación
y añadir telemetría para eventos de compilación correlacionados con picos de frame. También actualizaron el runbook de incidentes para preguntar
“¿es esto una invalidación de caché?” antes de culpar al renderer.

Microhistoria 2: La optimización que se volvió en contra

Una app corporativa de visualización (piensa CAD + renderizado en tiempo real) tuvo un cuello de botella en CPU con D3D11. El hilo de render estaba caliente,
y el equipo hizo lo que hacen los equipos bajo deadline: empujaron más trabajo a hilos worker usando contextos diferidos.
La idea era paralelizar el registro de comandos, reducir tiempo en el controlador en el hilo principal y mantener la GPU ocupada.

En pruebas sintéticas, el FPS medio mejoró. El equipo celebró. Luego los usuarios empezaron a reportar “hitches aleatorios” al rotar ensamblajes grandes.
El hitching era peor en CPUs de gama alta, que siempre es una excelente forma de empezar una reunión.

El contragolpe vino del comportamiento del controlador y los costes de sincronización. La ruta de contextos diferidos aumentó la cantidad de
merging de listas de comandos por frame e introdujo contenido en actualizaciones de recursos que no estaban diseñadas para paralelismo.
El controlador también alcanzó bloqueos internos con mayor frecuencia porque la app creó una tormenta de listas de comandos pequeñas, cada una con cambios de estado
que el controlador antes podía deduplicar en un flujo mono-hilo.

Eventualmente revertieron el cambio en los peores casos e implementaron una solución más aburrida: reducir cambios de estado, agrupar draw calls
por material y cachear agresivamente objetos de estado inmutables. También limitaron contextos diferidos a cargas de trabajo específicas donde ayudaban consistentemente.
La lección no fue “los hilos son malos”. Fue “el overhead del controlador no es una función pura del número de núcleos de CPU”.

Microhistoria 3: La práctica aburrida pero correcta que salvó el día

Un pequeño equipo de operaciones soportaba una flota de kioscos Windows que ejecutaban una experiencia interactiva basada en DirectX. El hardware era idéntico
por orden de compra, pero el mundo real tenía otros planes: las actualizaciones de Windows sucedían, los controladores de GPU derivaban y un proveedor lanzó una nueva
utilidad overlay que “útilmente” monitorizaba rendimiento.

Tenían una práctica que nadie quería pagar hasta que importó: una imagen dorada con versiones de controladores fijadas,
un build de OS conocido y una ventana de mantenimiento mensual donde los cambios se escenificaban, probaban y desplegaban gradualmente.
Era aburrido. También fue la diferencia entre “una flota estable” y “una pesadilla de soporte”.

Un mes, una nueva versión de controlador mejoró el rendimiento en un benchmark de juegos popular, y la dirección pidió por qué no se actualizaban los kioscos de inmediato.
El equipo de ops se resistió. Lo escenificaron primero. En staging encontraron un problema de temporización del modo present en el panel 60Hz específico del kiosco que causaba microstutter—sin pérdida de FPS, solo una sensación miserable.

Retuvieron la actualización, presentaron un ticket al proveedor con una reproducción mínima (más trazos ETW) y desplegaron los kioscos con la versión fijada.
El día lo salvó una práctica de la que nadie se jacta en conferencias: despliegue controlado, métricas base y el coraje de decir “todavía no”.

Broma #2: Una actualización de controlador es un boleto de lotería cuyo premio es “tu app funciona como el martes pasado”.

Errores comunes: síntomas → causa raíz → solución

Esta sección existe para evitar que pierdas una semana. Estos son reincidentes que he visto en juegos, visualización y aplicaciones empresariales que usan DirectX como compositor UI.

1) Síntoma: baja utilización de GPU, FPS bajo

  • Causa raíz: cuello de botella de envío CPU/controlador (demasiados draws, cambios de estado o overhead D3D11).
  • Solución: Reducir draw calls; agrupar por material; evitar cambios de estado redundantes; pasar a D3D12 solo si realmente puedes gestionar los costes explícitos.

2) Síntoma: los 1% lows son terribles, los promedios están bien

  • Causa raíz: stutter por compilación de shaders, creación de PSO a mitad de frame o thrash de residencia VRAM.
  • Solución: Precompilar/warmear PSOs; persistir bibliotecas de PSO; asegurar que la caché de shaders esté habilitada; bajar texturas si la VRAM está cerca del lleno.

3) Síntoma: la ventana sin bordes stutterea; pantalla completa exclusiva es suave

  • Causa raíz: ruta de composición/overlays/interacción con DWM.
  • Solución: Desactivar overlays; probar diferentes modos de present; preferir el modelo flip; considerar pantalla completa exclusiva para apps sensibles a latencia.

4) Síntoma: el stutter aparece después de actualizar el controlador, luego desaparece tras “algún tiempo”

  • Causa raíz: cachés de shaders invalidadas; la recompilación ocurre gradualmente conforme se encuentran contenidos.
  • Solución: Proveer warmup de shaders en la app; evitar interpretar el rendimiento de “primera ejecución” como estado estacionario; documentar comportamiento de caché para soporte.

5) Síntoma: congelamientos aleatorios, a veces con un evento de reset del controlador

  • Causa raíz: TDR disparado por hang de GPU, relojes inestables/undervolt o bug del controlador activado por una ruta shader específica.
  • Solución: Volver a relojes de stock; reducir undervolts agresivos; capturar ETW + volcados; si es reproducible, minimizar shader y presentar un bug al proveedor.

6) Síntoma: rendimiento varía mucho entre proveedores para el mismo contenido DX12

  • Causa raíz: backends de compilador y heurísticas diferentes; puntos óptimos distintos para tamaño de wave, presión de registros y patrones de barrera.
  • Solución: Usar profiling agnóstico al proveedor (PIX + herramientas del proveedor); evitar comportamiento indefinido; probar variantes de shader donde sea necesario.

7) Síntoma: “actualicé la GPU pero no hay mejora”

  • Causa raíz: cuello de botella CPU/controlador, problemas de enlace PCIe, restricciones de plan de energía o la app está capada por present/vsync.
  • Solución: Validar caps de present/vsync; comprobar saturación de núcleos CPU; confirmar velocidad del enlace PCIe en herramientas del proveedor; probar modo uncapped para diagnóstico.

8) Síntoma: microstutter sin picos obvios de CPU/GPU

  • Causa raíz: pacing de frames e irregularidades en la cola de present (a menudo compositor/VRR/desajuste de refresco).
  • Solución: Cambiar modo de present (exclusivo vs sin bordes); alinear ajustes de refresco; reducir clientes GPU en segundo plano; trazar present con ETW.

Listas de verificación / plan paso a paso

Checklist A: Higiene de reproducibilidad (deja de autoengañarte)

  1. Fija la versión exacta del controlador y el build del OS para la prueba.
  2. Desactiva overlays y herramientas de captura para ejecuciones base.
  3. Registra ajustes: resolución, vsync/VRR, modo de ventana, upscalers.
  4. Ejecuta la misma escena tres veces: inicio en frío, ejecución caliente, ejecución caliente otra vez.
  5. Registra estadísticas de tiempos por frame (promedio, 1% low) y nota dónde ocurren los stutters.

Checklist B: Decide qué subsistema es culpable

  1. Si la utilización de GPU es baja y un núcleo de CPU está caliente: enfócate en overhead de envío/controlador.
  2. Si la utilización de GPU es alta: enfócate en coste de shaders, ancho de banda y ajustes.
  3. Si el stutter ocurre en efectos de primera vez: enfócate en compilación/creación de PSO.
  4. Si el stutter ocurre en áreas nuevas: enfócate en streaming y residencia.
  5. Si el stutter depende del modo (sin bordes vs pantalla completa): enfócate en present/compositor.

Checklist C: Triage de regresiones (cómo dejar de discutir en Slack)

  1. Reproduce en dos máquinas: una control, una afectada.
  2. Bisecta versiones de controlador (última buena → primera mala) si es posible.
  3. Captura trazos ETW en ambas y compara comportamiento de present + colas GPU.
  4. Verifica comportamiento de la caché de shaders (¿se reinicia? ¿escribe en disco?).
  5. Si la regresión es específica de proveedor, reduce a una prueba mínima y repórtala correctamente.

Checklist D: Guía para lanzamiento (qué hacer antes de publicar)

  1. Implementar prebuild de PSO y una caché gestionada por la aplicación para permutaciones comunes.
  2. Proveer una opción de “shader warmup” o hacerlo automáticamente en momentos no interactivos.
  3. Rastrear eventos de compilación y retrasos de present en telemetría (con cumplimiento de privacidad y opt-in).
  4. Probar en múltiples versiones de controladores, incluyendo versiones “estables populares” más antiguas.
  5. Documentar overlays conocidos problemáticos y ofrecer guías al usuario que no los culpabilicen.

Preguntas frecuentes (FAQ)

1) ¿Cómo puede una actualización de controlador hacer que mi GPU sea más rápida sin cambiar hardware?

Porque el controlador controla el codegen del backend de shaders, el caching, el batching, la política de residencia de memoria y las interacciones de planificación.
Si el controlador reduce overhead de CPU o genera mejor ISA para shaders calientes, obtienes mejoras reales en el mismo silicio.

2) ¿DX12 siempre es más rápido que DX11?

No. DX12 reduce ciertos overheads del controlador, pero traslada responsabilidad a la aplicación. Si el motor crea PSOs a mitad de frame,
maneja mal barreras o inunda el sistema con envíos pequeños, DX12 puede ser más lento o provocar más stutter.

3) ¿Por qué obtengo stutter solo en la primera partida o la primera carga?

Normalmente compilación de shaders o creación de PSO a demanda, además de cachés frías. Las actualizaciones de controlador también pueden invalidar cachés.
La solución es precompilación/warmup y caching persistente, no solo “más FPS”.

4) ¿Cuál es la diferencia entre “limitado por GPU” y “limitado por controlador”?

Limitado por GPU significa que la GPU está ocupada ejecutando trabajo y el tiempo por frame sigue el tiempo de GPU. Limitado por controlador significa que la CPU/controlador
no puede enviar o preparar trabajo lo bastante rápido, así que la GPU espera. Baja utilización de GPU con un hilo de render caliente es la pista clásica.

5) ¿De verdad importan tanto los overlays?

Sí. Muchos overlays enganchan Present, añaden trabajo de composición o introducen sincronización. También pueden cambiar el modo de present o interferir con VRR.
Para el diagnóstico, desactívalos. Para el despliegue, asume que los usuarios los ejecutarán y haz tu ruta de present robusta.

6) ¿Por qué cambia la “suavidad” aunque el FPS medio no cambie?

El pacing de frames trata sobre la varianza, no la media. El comportamiento de la cola de present, la temporización del compositor y la planificación pueden hacer que los frames lleguen de forma irregular.
Los controladores pueden cambiar esto con actualizaciones porque modifican heurísticas de temporización y sincronización.

7) ¿Debo decir a los usuarios que siempre instalen el último controlador?

Para consumidores, “último” suele estar bien, pero en entornos gestionados quieres “conocido bueno”. Fija una versión validada, escenifica actualizaciones y despliega gradualmente.
Trata los controladores como cualquier otra dependencia con riesgo de regresión.

8) ¿Pueden los controladores incluir optimizaciones y workarounds por juego?

Absolutamente. Eso es común y a menudo necesario. El intercambio es imprevisibilidad: heurísticas ajustadas para un título pueden afectar a otro.
Por eso el triage de regresiones necesita fijado de versiones y trazos reproducibles.

9) ¿Cuál es la forma más rápida de encontrar el cuello de botella?

Correlaciona picos de tiempo por frame con tiempo de envío en la CPU, tiempo de ejecución en la GPU o retraso de present. Si los contadores no bastan,
toma un trazo ETW (WPR/WPA) y mira colas GPU y eventos Present.

10) ¿Es “hacer trampa” cuando los controladores optimizan para patrones específicos?

No inherentemente. Se vuelve problema cuando las optimizaciones dependen de comportamiento indefinido o rompen la corrección. Como ingeniero,
deberías preferir rutas explícitas y conforme a la especificación para no quedar a merced de heurísticas por versión.

Un principio operativo que vale la pena conservar

Idea parafraseada, atribuida a Gene Kim: mejora el flujo y acorta los bucles de retroalimentación; cambios pequeños y medibles superan a las conjeturas heroicas.
Eso aplica a regresiones de controladores y trabajo de rendimiento tanto como a interrupciones.

Conclusión: próximos pasos que realmente mueven la aguja

La carrera armamentista de DirectX no es solo proveedores peleando con silicio. Son proveedores publicando compiladores, planificadores, cachés
y workarounds a alta frecuencia. El controlador es una superficie de rendimiento, y puede absolutamente hacer que la GPU de ayer
se vea mejor que la de hoy si la pila de software es más amigable.

Próximos pasos prácticos:

  1. Deja de diagnosticar con corazonadas. Confirma la ruta de la API, versión del controlador, build del OS y modo de present antes de comparar nada.
  2. Clasifica la cola culpable. CPU/controlador vs GPU vs residencia vs present. Luego optimiza lo correcto.
  3. Haz la compilación aburrida. Preconstruye PSOs, warmea shaders y persiste cachés para que la “primera ejecución” no sea una pesadilla.
  4. Trata los controladores como dependencias. Fija, escenifica, despliega y mantén una ruta conocida buena.
  5. Usa trazos cuando los contadores mienten. ETW es la jugada adulta cuando el pacing de frames se vuelve raro.

Si haces esos cinco, pasarás menos tiempo discutiendo sobre qué GPU es “mejor” y más tiempo entregando un renderer que se comporte
como un sistema profesional: medible, depurable y predeciblemente rápido.

← Anterior
Proxmox vs VMware ESXi: ¿qué hipervisor deberías usar en 2026?
Siguiente →
ZFS usando NVMe como L2ARC: cuando ARC no es suficiente

Deja un comentario