# Escritorio virtual de Windows 10 (y II)

*Vamos a ver algunos consejos para optimizar la máquina virtual creada en el* [*artículo anterior*](/escritorio-virtual-de-windows-10-parte-1)*.* *Este artículo pertenece a una serie donde se explica como instalar Windows 10 en una máquina virtual asignándole una de las GPU del equipo de forma exclusiva, para obtener un rendimiento gráfico similar al que tendría en una máquina real.* *Si te has perdido algún artículo anterior de esta historia, el primero lo tienes* [*aquí*](/iommu-primer-asalto).

---

Una vez apagada la máquina virtual, si seleccionamos en el menú el icono con una exclamación —con el texto de ayuda **Mostrar detalles del hardware virtual**— podemos ver la configuración definitiva y ajustarla.

![Hardware de la máquina virtual tras la instalación](https://cdn.hashnode.com/res/hashnode/image/upload/v1637026439223/kYgQjJMfS.png align="center")

Podemos quitar las unidades CDROM o, en todo caso, dejar solo una por lo que pueda surgir. También se puede quitar el dispositivo tipo **Serial** y añadir uno de tipo **Tableta**. La tableta nos permite evitar problemas con el posicionamiento del puntero y usar el ratón con la pantalla de la máquina virtual sin antes tener que hacer clic.

Si hemos dejado una unidad CDROM, podemos cambiar su **Bus de disco** a **SCSI**. Eso nos permite eliminar también los dispositivos **Controller IDE**.

# Rendimiento del almacenamiento

En las **Opciones de Rendimiento** del **SCSI Disco** se puede indicar el **Modo caché** como **none** y el **Modo E/S** como **native**.

El primero evita que el anfitrión consuma memora cacheando las operaciones de E/S de la máquina virtual. Esto también lo hace el sistema operativo de la máquina virtual, por lo que no tiene sentido hacerlo dos veces. Quizás fuera útil si pensáramos lanzar varias máquinas virtuales que accedan al mismo tiempo a los mismos dispositivos de almacenamiento.

El segundo activa el uso de [llamadas al sistema nativas de Linux para la E/S asíncrona](https://blog.cloudflare.com/io_submit-the-epoll-alternative-youve-never-heard-about/) al archivo con el contenido del disco duro virtual. El valor por defecto usa hilos y operaciones síncronas.

La combinación de estas dos opciones debería ofrecernos mejor rendimiento que las opciones por defecto.

Dentro de la máquina virtual, en el intérprete de comandos de Windows, es interesante ejecutar este comando:

```powershell
fsutil behavior query DisableDeleteNotify
```

Si devuelve 0, nos indica que cuando un bloque del almacenamiento deja de usarse, Windows envía al dispositivo el comando TRIM para indicarle que ha quedado libre.

Si estamos utilizando una imagen de disco en formato **raw**, esto no tendrá ningún efecto. Pero con **qcow2** el archivo reducirá su tamaño, al necesitar menos espacio para almacenar la imagen. Si empleamos un volumen lógico LVM sobre un dispositivo SSD, como es mi caso, el comando TRIM se propagará hasta el SSD, evitando la degradación del rendimiento del dispositivo.

Si hiciera falta, para activarlo hay que ejecutar:

```powershell
fsutil behavior set DisableDeleteNotify 0
```

# Rendimiento de la interfaz de red

La tarjeta de red de la máquina virtual es el dispositivo con el nombre **NIC &lt;MAC&gt;**. Por lo general se trata de una emulación de una tarjeta Intel e1000 o una [Realtek RTL8139](https://es.wikipedia.org/wiki/Realtek). Se puede obtener mejor rendimiento cambiando el **Modelo de dispositivo** a **virtio**, que es una interfaz de red paravirtualizada, como la que usamos con el disco duro virtual. Lo único es que es necesario iniciar la máquina virtual e instalar los controladores de la carpeta `NetKVM` de la ISO de controladores VirtIO.

Por defecto la interfaz de red de la máquina virtual está conectada a una red virtual llamada "default", en la que también está el equipo anfitrión. En esta red la máquina virtual recibe una IP privada y su acceso a Internet se realiza a través del anfitrión utilizando [NAT](https://es.wikipedia.org/wiki/Traducci%C3%B3n_de_direcciones_de_red).

Todo esto se puede simplificar mucho cambiando **Fuente de red** a **Dispositivo anfitrión &lt;interfaz&gt;: macvtap** y **Modo de fuente** a **Puente**. Usando [macvtap](https://virt.kernelnewbies.org/MacVTap) la máquina virtual pasa a algo así como a compartir la la tarjeta de red "&lt;interfaz&gt;" del equipo anfitrión. La red le asignará a la máquina virtual una IP como si fuera una máquina real y de esta forma puede conectarse al resto de equipos de la red y a Internet sin usar al anfitrión como intermediario.

En mi caso, al utilizar *macvtap* en Ubuntu 16.04, la interfaz de red funcionaba en el primer arranque pero nunca en posteriores. Se debía a un conflicto con *NetworkManager*, que decidía por su cuenta bajar la interfaz *macvtap* anfitrión. Se resuelve editando el archivo `/etc/NetworkManager/NetworkManager.conf` para añadir lo siguiente:

```ini
[keyfile]  
unmanaged-devices=interface-name:macvtap0
```

para que *NetworkManager* no intente gestionar esa interfaz. En Ubuntu 18.04, por el momento no he tenido ningún problema similar, de modo que no parece que haga falta este truco.

# Vídeo QXL

En el dispositivo **Video Cirrus** se puede cambiar el modelo a **QXL**. El modelo **Video Cirrus** emula una tarjeta gráfica VGA del fabricante Cirrus Logic. Mientras que QXL es un dispositivo de vídeo paravirtualizado, por lo que ofrece mejor rendimiento. Además, mientras que con la emulación VGA estamos limitados a una resolución 800x600, con QXL tenemos automáticamente 1024x768. Será necesario iniciar la máquina virtual e instalar los controladores de la carpeta `qxldod` de la ISO de controladores VirtIO.

# Asignación de memoria RAM

En la configuración de memoria podemos configurar cuánta memoria pensará la máquina virtual que tiene —la **Asignación máxima**— y cuanta memoria del anfitrión puede realmente usar como máximo —la **Asignación actual**—.

Por ejemplo, mi máquina virtual supone que tiene 8GB de RAM, pero el sistema anfitrión nunca le asignará más de 4 GB de memoria.

![Configuración de la asignación de memoria](https://cdn.hashnode.com/res/hashnode/image/upload/v1637026439233/wjJfsFSO55.png align="center")

Desde el punto de vista del sistema operativo, la máquina virtual es un proceso más. Cuando se inicia, pide al sistema operativo la cantidad de memoria indicada en **Asignación máxima** como memoria RAM para la máquina. El sistema operativo le reserva el espacio de direcciones pero realmente solo le asigna la memoria según va a accediendo a ella. Es decir, que la memoria se asigna a la máquina virtual a demanda.

Si miramos el hardware detectado por nuestro sistema operativo, seguramente observaremos un dispositivo desconocido que se corresponde con el dispositivo balón de memoria —en inglés, *balloon device*—. Para que funcione adecuadamente es necesario instalar en la máquina virtual el controlador `balloon` de la ISO de controladores VirtIO.

Con el controlador del balón de memoria instalado, cuando el sistema operativo arranca, dicho controlador reserva una porción de la memoria de la máquina para que nunca pueda usarse. ¿Cuánta memoria reserva?. La necesaria para que el sistema nunca pueda utilizar más memoria que la cantidad indicada en **Asignación actual**.

Es decir, que la máquina virtual piensa que la memoria instalada es **Asignación máxima**, pero nunca podrá emplear más de **Asignación actual** de la memoria del sistema anfitrión.

La cantidad indicada en "Asignación actual" se puede cambiar en tiempo de ejecución desde el anfitrión mediante el comando `virsh`:

```sh
sudo virsh setmem <máquina_virtual> 2G --live
```

Si el nuevo valor es mayor, el balón se encogerá para que el sistema de la máquina virtual pueda consumir más memoria. Obviamente, nunca podremos asignar un valor superior a **Asignación actual**.

Por el contrario, si el nuevo valor es menor, el balón crecerá y devolverá la memoria adicional que reserve al sistema anfitrión, haciendo que haya menos memoria para la máquina virtual.

Si no nos interesa este comportamiento, basta con que no instalemos el controlador del balón de memoria. O que pongamos en **Asignación máxima** y en **Asignación actual** la misma cantidad. Sin embargo, hay que tener presente que durante el arranque, Windows pone a ceros toda la memoria de la máquina, haciendo que el sistema anfitrión tenga que asignarle efectivamente la memoria indicada en "Asignación máxima". El controlador del balón de memoria nos permite obligar después a Windows a devolver buena parte de la memoria, hasta lo indicado en **Asignación actual**.

# Espacio de intercambio en la máquina virtual

En algunos foros se sugiere desactivar el espacio de intercambio —o *swap*—  en el sistema operativo de la máquina virtual. La justificación es que el sistema anfitrión ya tiene su espacio de intercambio donde pueda intercambiar cualquier porción de la memoria, incluida la asignada a las máquinas virtuales.

Pero lo cierto es que nadie mejor que el sistema operativo de la máquina virtual para saber qué partes intercambiar primero, por lo que es mejor que tenga su propio espacio de intercambio.

Al reducir la cantidad de memoria disponible con el *balloon device*, obligamos al sistema operativo de la máquina virtual a decidir qué partes de la memoria son menos importantes respecto al rendimiento, para liberarlas o intercambiarlas primero.

# Kernal SamePage Merging (KSM)

En algunos foros se recomienda activar [KSM](https://en.wikipedia.org/wiki/Kernel_same-page_merging) en el sistema Linux anfitrión. KSM es una tecnología creada originalmente para intentar maximizar el número de máquinas virtuales en un mismo equipo. Básicamente, consiste en un hilo del núcleo que recorre la memoria buscando regiones con el mismo contenido. Cuando las encuentra, ahorra memoria liberando los duplicados y quedándose solo con una copia.

Por tanto, parece una tecnología interesante para evitar que las máquinas virtuales con Windows acaparen demasiada memoria cuando la llenan de ceros durante el arranque. De hecho [Red Hat hizo un experimento](https://kernelnewbies.org/Linux_2_6_32#Kernel_Samepage_Merging_.28memory_deduplication.29) donde pudo lanzar hasta 52 Windows con 1 GB en un servidor con solamente 16 GB.

Sin embargo, hay que tener presente que recorrer la memoria de esta manera no es gratis. KSM sacrifica tiempo de CPU para maximizar el número de máquinas virtuales. Por eso yo no he activado y probado KSM, hasta el momento.

# Afinidad de los procesadores

Las CPU de la máquina virtual se implementan como hilos de ejecución en el anfitrión. Para mejorar el rendimiento se puede vincular cada uno de esos hilos a una CPU real, evitando que migren de CPU a criterio del sistema, lo que dificulta aprovechar adecuadamente las memorias caché.

Lamentablemente, para configurar esta funcionalidad no podemos usar la interfaz gráfica de usuario de *virt-manager*. Tenemos que ejecutar:

```sh
sudo virsh edit <máquina_virtual>
```

desde la línea de comandos y modificar el XML —que describe la máquina virtual—  a mano para añadir antes de la etiqueta `<os>` lo siguiente:

```xml
<cputune>  
  <vcpupin vcpu='0' cpuset='0'/>  
  <vcpupin vcpu='1' cpuset='1'/>  
  <vcpupin vcpu='2' cpuset='2'/>  
  <vcpupin vcpu='3' cpuset='3'/>  
</cputune>
```

***ADVERTENCIA:*** *Ojo con olvidar el comando* `sudo`. *Si nos olvidamos de* `sudo` al ejecutar `virsh`, el comando puede fallar con el error `error: Domain not found` por no encontrar la máquina virtual o acabaremos editando una máquina virtual diferente a la que hemos configurado en virt-manager.

En mi sistema las CPU de la 0 a la 3 corresponde con los núcleos del primero al cuarto. Mientras que las CPU de la 4 a la 7 son hilos de esos mismos núcleos. Como hemos configurado la máquina virtual con 4 núcleos de 1 hilo, vinculamos cada uno de esos 4 núcleos virtuales con uno de los 4 núcleos de la CPU real.

La topología de las CPU reales de nuestro sistema se puede conocer mirando `/proc/cpuinfo` en el sistema anfitrión.

# Huge Pages

Además, se puede indicar que el proceso de la máquina virtual use páginas de memoria de gran tamaño o [*huge pages*](https://www.kernel.org/doc/Documentation/vm/hugetlbpage.txt). El tamaño de página típico son 4 KB, pero algunas CPU permiten tamaños superiores —en la familia x86 se admiten páginas de 4 kB, 2 MB y 1 GB, según el modelo de CPU— lo que evita consultar algunos niveles de más en la tabla de página, durante la traducción de las direcciones virtuales y permite consumir menos entradas de la [TLB](https://es.wikipedia.org/wiki/Translation_Lookaside_Buffer).

Para activar su uso, primero hay que editar el XML de la máquina virtual:

```sh
sudo virsh edit <máquina_virtual>
```

y añadir lo siguiente antes de la etiqueta `<os>`:

```xml
<memoryBacking>  
  <hugepages/>  
</memoryBacking>
```

Las *huge pages* pueden no estar disponibles cuando se necesitan debido a la fragmentación de la memoria. Por eso, si se quieren emplear, hay que configurar el sistema para reservar la cantidad necesaria durante el arranque:

```sh
echo "vm.nr_hugepages=2048" | sudo tee /etc/sysctl.d/hugepages.conf
```

Donde 2048 páginas de 2 MB son 4096 MB, suficiente para una máquina virtual de 4 GB. Sin embargo, hay que tener presente que la memoria reservada no puede ser usada con otro propósito ni puede ser intercambiada. Como mi sistema solo tiene 16 GB, yo he optado por no activar el uso de *huge pages*. Obviamente, tendría sentido activarlo si dispusiera de mucha más memoria.

# Asignar a la máquina virtual la GPU

Llegados a este punto, antes de continuar, lo primero que deberíamos hacer es [crear un punto de restauración](https://support.microsoft.com/es-es/help/4027538) en Windows. Así, si las cosas se ponen muy mal, no tendremos que volver a empezar desde cero.

Volvemos a la configuración de la máquina virtual, hacemos clic en **\+ Agregar hardware** y seleccionamos **Dispositivo PCI anfitrión**. Hay que escoger la tarjeta gráfica que queremos asignar. En mi caso es el dispositivo que dice **0000:01:00:0 NVIDIA Corporation GM206 \[Geforce GTX 950\]**.

![Añadir la tarjeta gráfica como dispositivo PCI del anfitrión](https://cdn.hashnode.com/res/hashnode/image/upload/v1637026439242/7gyYIvf997.png align="center")

Lo mismo se hace con el dispositivo justo debajo —el `0000:01:00:1`— que es la salida de audio digital de la tarjeta gráfica a través del conector HDMI. A fin de cuentas, ambos dispositivos están en la misma tarjeta y no es conveniente asignar uno a la máquina virtual y el otro no.

Yo también hice lo mismo con el dispositivo **0000:05:00:0 ASMedia Technology Inc. ASM1042 SuperSpeed USB Host Controller** para tener puertos USB donde conectar directamente un teclado, un ratón, un *gamepad* o un *pendrive*; si hiciera falta.

En principio para una tarjeta gráfica AMD esto sería todo. Al iniciar la máquina virtual ya no debería inicializarse en el monitor virtual en *virt-manager*. En su lugar debemos ver el arranque en el monitor físico conectado a la tarjeta gráfica. Una vez haya arrancado Windows, vamos a la web de fabricante de la GPU, bajamos los controladores para el dispositivo y los instalamos. Es preferible seleccionar el controlador adecuado nosotros mismos antes que utilizar la autodetección, ya que esto último puede dar problemas.

Sin embargo, [con Windows 10 algunos usuarios informan de que pueden ser necesarios algunos trucos adicionales](https://ubuntuforums.org/showthread.php?t=2289210). En mi caso intenté una actualización de Windows 8.1 a Windows 10 que no se completaba, si no editaba el XML de la máquina virtual

```sh
sudo virsh edit <máquina_virtual>
```

para eliminar toda la etiqueta `<hyperv>` en `<features>` y añadir lo siguiente:

```xml
<kvm>  
  <hidden state='on'/>  
</kvm>
```

De hecho mi etiqueta `<features>` es así:

```xml
<features>  
  <acpi/>  
  <apic/>  
  <pae/>  
  <kvm>  
    <hidden state='on'/>  
  </kvm>  
</features>
```

Cuando se tiene una GPU de NVIDIA hace falta cambiar lo mismo, independientemente de la versión de Windows, para que funcione. También se recomienda buscar la etiqueta `<timer name=’hypervclock’ ... >` dentro de `<clock>` y dejarla de esta manera...

```xml
<timer name='hypervclock' present='no'>
```

...o borrarla.

Con estos cambios el arranque debe ocurrir como hemos descrito anteriormente. Después solo tendremos que buscar el controlador adecuado e instalarlo.

# Activar el uso de Message Signaled Interrupts (MSI)

[MSI](https://en.wikipedia.org/wiki/Message_Signaled_Interrupts) es una alternativa al mecanismo tradicional de señalar las interrupciones mediante líneas dedicadas, que puede proporcionar una pequeña mejora de rendimiento.

Para activar su uso con nuestra tarjeta gráfica, básicamente tenemos que:

1. Comprobar en el **Administrador de dispositivos** que la tarjeta soporta MSI. Lo más probable es que sí.
    
2. Ejecutar `regedit` en Windows, localizar la clave de registro del dispositivo y añadir allí la configuración que activa el uso de MSI para el dispositivo.
    

Todos los detalles del proceso están perfectamente descritos en el primer mensaje de [este hilo](https://forums.guru3d.com/threads/windows-line-based-vs-message-signaled-based-interrupts.378044/) en un foro.

# Detalles finales

Si todo ha ido bien, ya tenemos una máquina virtual con una GPU real. Como ya no estamos usando el visor de *virt-manager*, quizás haga falta conectar temporalmente un teclado y un ratón a los puertos USB reales que le hemos asignado.

## Teclado y ratón compartido

Eso de tener dos teclados no es muy práctico a largo plazo, por lo que utilizo [*Synergy*](https://symless.com/synergy) para compartir el teclado y el ratón del anfitrión con la máquina virtual. También permite compartir el portapapeles entre ambos sistemas.

En `conf/synergy.conf` dentro de mí [repositorio](https://github.com/jesustorresdev/virtual-desktop) hay un ejemplo de mi configuración de *Synergy*. *Synergy* hace que al llegar al borde derecho de mi monitor en el sistema anfitrión, este aparezca por la izquierda en el monitor de la máquina virtual.

Este comportamiento a veces da problemas con juegos o con herramientas de edición 3D. Para esos casos he configurado la combinación de teclas <kbd>Alt+W</kbd> para que al pulsarla se confine el ratón al escritorio del sistema en el que esté en ese momento. Así el ratón y la entrada de teclado no puede cambiar de un sistema a otro por error.

*Synergy* usa la red para conectar servidor y cliente, pero al usar *macvtap*, anfitrión y máquina virtual no pueden. Por eso he añadido a la máquina virtual una nueva red virtual privada que solo la conecta con el anfitrión. Es a través de esa red aislada por la que conecta el cliente con el servidor de *Synergy*.

## Monitor compartido

En mi caso no tengo un monitor para cada sistema. Tengo dos para ambos. La gráfica integrada se conecta a ellos mediante salidas DVI, mientras que la gráfica asignada a la máquina virtual utiliza las salidas HDMI. Cambiando la entrada que me interesa en cada monitor, puedo elegir si quiero ver el escritorio de la máquina virtual o del anfitrión.

Tengo en mente un proyecto para poder hacer eso empleando combinaciones de teclas, evitando usar los incómodos controles de los monitores. Sin embargo, ya veremos si algún día me pongo a ello 😉.

## Sonido

El sonido es seguramente el aspecto con el que menos satisfecho estoy. Después de probar muchas alternativas, creo que las mejores opciones son:

* **Conectar directamente una tarjeta de sonido o unos auriculares** en un puerto USB asignado a la máquina virtual por *PCI Passthrough*. Sin duda es así como se consigue la mejor calidad de sonido. También sirve la salida de audio HDMI de la tarjeta gráfica asignada. Se puede escuchar por los altavoces del monitor —si los tiene— o conectar algunos por la salida de audio que los monitores suelen traer. Si no queremos tener dos parejas de altavoces, una para cada sistema, ni estar conectando y desconectado cables según nos interese, podemos comprar un mezclador barato para combinar ambas salidas de audio y tener solo unos altavoces conectados.
    
* **Usar una tarjeta de sonido virtual de red**, como la del proyecto [duncanthrax/scream](https://github.com/duncanthrax/scream). La idea de la tarjeta virtual de red es instalar en Windows un controlador de dispositivo de tarjeta de sonido que realmente envíe el audio por red a otro equipo para su reproducción. En ese sentido, el proyecto *scream* proporciona tanto los controladores para Windows como el servidor para Linux. El resultado es bastante bueno, prácticamente sin distorsiones ni latencia.
    
* **Añadir un dispositivo de sonido emulado a la máquina virtual** y que *QEMU* haga el resto. Esta es la solución típica. Necesita muchos ajustes y al final el resultado no es muy satisfactorio. Pero voy a explicar como lo he configurado yo.
    

Primero hay que añadir un dispositivo de sonido a la máquina virtual. En mi caso, tras varias pruebas, he dejado el modelo ICH9, que es bastante moderno y funciona perfectamente.

Luego hay que indicar a *QEMU* como reproducir en el anfitrión el sonido del dispositivo emulado. Simplemente, editamos el XML de la máquina virtual:

```sh
sudo virsh edit <máquina_virtual>
```

y añadimos lo siguiente al final:

```xml
<qemu:commandline>  
  <qemu:env name='QEMU_AUDIO_DRV' value='pa'/>  
  <qemu:env name='QEMU_PA_SERVER' value='127.0.0.1'/>  
  <qemu:env name='QEMU_PA_SAMPLES' value='1024'/>  
</qemu:commandline>
```

Esto hace que *QEMU* use el servidor *pulseaudio* del anfitrión para reproducir el sonido, al igual que el resto de aplicaciones de Linux.

El valor de `QEMU_PA_SAMPLES` permite controlar el tamaño del buffer de muestras. Con valores muy altos, se consigue una calidad similar a la que se obtiene con *Scream*, al menos durante los primeros minutos. Sin embargo, el retardo es excesivo, haciendo imposible ver un vídeo. Con 1024 el retardo es inapreciable, pero la calidad del sonido no es tan alta.

Por defecto *pulseaudio* no acepta conexiones de red por TCP. Para resolverlo hay que editar `/etc/pulse/default.pa` y descomentar la línea del módulo `module-native-protocol-tcp` y que quede así:

```plaintext
load-module module-native-protocol-tcp auth-ip-acl=127.0.0.1
```

Por defecto, si tenemos activado el monitor virtual VNC, *Libvirt* ignorará lo indicado en `QEMU_AUDIO_DRV` para redirigir todo el sonido por VNC, tanto si el cliente VNC sabe reproducir el audio como si no es de esta manera. Es necesario editar `/etc/libvirt/qemu.conf` y asegurarnos que la siguiente línea está descomentada y aparece de esta forma:

```plaintext
vnc_allow_host_audio = 1
```

para que *Libvirt* haga siempre lo indicado por `QEMU_AUDIO_DRV`.

Por último, hay que indicar a Windows que la frecuencia de muestreo por defecto del dispositivo de audio es 44100 Hz, que es la frecuencia de muestreo por defecto en Linux. El valor por defecto en Windows es 48000 Hz. Si la frecuencia de muestreo en Windows y en Linux no coincide, oiremos los sonidos distorsionados. Los pasos son:

![Configuración de la frecuencia de muestreo en Windows 10](https://cdn.hashnode.com/res/hashnode/image/upload/v1637026439248/0wbRdmc_hg.png align="center")

1. En la máquina virtual hay que buscar el icono del altavoz en la bandeja del sistema, hacer clic con el botón derecho del ratón y seleccionar **Abrir Configuración de sonido**.
    
2. Hacer clic en **Panel de control de sonido**.
    
3. En **Reproducción** seleccionar **Altavoces (High Definition Audio Device)** y luego hacer clic en propiedades.
    
4. Hacer clic en la pestaña **Opciones avanzadas**.
    
5. Hacer clic en la lista de selección y escoger **16 bits, 44100 Hz (Calidad de CD)**.
    
6. Aplicar y salir.
    

Y ya solo queda reproducir algo para ver como suena. En mi caso el sonido va acompañado a ratos de unos clics. Dependiendo de para qué vayamos a usar la máquina virtual, es posible que nos interese probar otra solución de las comentadas.

## Evitar el reinicio de Xorg

En el [artículo anterior](https://jesustorres.es/escritorio-virtual-de-windows-10-parte-1#heading-liberar-la-grafica) vimos que si cambiamos la tarjeta gráfica usada por nuestro escritorio en Linux mediante el comando `prime-select`, estamos obligados a salir de la sesión y reiniciar el gestor de pantalla; para posteriormente volver a iniciar sesión en el escritorio y lanzar la máquina virtual, de manera que esta pueda usar la tarjeta gráfica liberada.

Como esto puede resultar bastante tedioso si estamos cambiamos de tarjeta gráfica con frecuencia, podemos optar por ejecutar el escritorio en el sistema Linux siempre en la tarjeta gráfica integrada. De modo que la otra tarjeta gráfica estará disponible, por lo general, para ejecutar la máquina virtual.

En caso de querer aprovechar la tarjeta gráfica no discreta con algún programa del escritorio Linux —por ejemplo, un juego o alguna otra aplicación que se beneficie de utilizar un hardware gráfico más potente, cuando no la está utilizando la máquina virtual— podemos utilizar el comando `primusrun`:

```sh
primusrun <comando>
```

O, en caso de querer desactivar VSync, lo utilizaríamos así:

```sh
vblank_mode=0 primusrun <comando>
```

También se puede usar [nvidia-xrun](https://github.com/Witko/nvidia-xrun), un script que similar a `primusrun`, pero que es específico para tarjetas gráficas de NVIDIA y que suele ofrecer mejor rendimiento.

## VFIO-Tools

Una alternativa muy interesante a mis scripts es [VFIO-Tools](https://github.com/PassthroughPOST/VFIO-Tools). Básicamente, se trata de una solución más modular, que facilita mucho crear scripts de hook personalizados que se ejecuten cuando la máquina virtual se inicia o detiene.

Algunos de los scripts que trae de serie hacen cosas como: configurar las *huge pages* —por lo que es importante desactivarlo si no nos interesa esta funcionalidad— ajustar la prioridad de los hilos que la máquina virtual usa para simular las CPU virtuales —lo que puede mejorar los tiempos de respuesta— y conmutar la entrada del monitor para que muestre la máquina virtual automáticamente cuando esta se inicia.
