OpenGL + 3D Rendering work great with iommu if you have VT-d support on your motherboard + processor. First look up your hardware to see if it supports VT-d. If it does, do the following:
Edit the file /etc/default/grub as root (use sudo), adding the following to the line beginning GRUB_CMDLINE_LINUX_DEFAULT:
For Intel, intel_iommu=on iommu=pt. for AMD, amd_iommu=on. Eg.:
sudo nano /etc/default/grub

After saving and closing, type grep CMDLINE_LINUX_DEFAULT /etc/default/grub in your terminal. If you did everything right, you will see the line you edited with the new code. Eg.:
$ grep CMDLINE_LINUX_DEFAULT /etc/default/grub
GRUB_CMDLINE_LINUX_DEFAULT="intel_iommu=on iommu=pt"
Then, run sudo update-grub to apply the changes and reboot.
(update-grub is a shortcut on Debian-derived distros for the command grub2-mkconfig -o /boot/grub/grub.cfg)
Some observations on this:
- It should be noted that this is a "weak" passthrough (shared) mode, that does not take over the entire device. "True" passthrough completely removes the device from control of the host. That requires a
vfio-pci=vendId:devId stub either in grub or /etc/modprobe.d (and a rebuild of initramfs). For more information on passthrough, this is a good place to start: https://wiki.archlinux.org/title/PCI_passthrough_via_OVMF
- There's even more elaborate ways of sharing your graphics, each vendor has their own version. For example, Intel-GVT-g for intel iGDs: https://wiki.archlinux.org/title/Intel_GVT-g
Here's my xml for the devices in question:
Display Spice - note: with passthrough you cannot enable a remote server:
<graphics type="spice">
<listen type="none"/>
<image compression="off"/>
<gl enable="yes"/>
</graphics>

Video Virtio (change from QXL):
<video>
<model type="virtio" heads="1" primary="yes">
<acceleration accel3d="yes"/>
</model>
<address type="pci" domain="0x0000" bus="0x00" slot="0x01" function="0x0"/>
</video>

Unrelated, I'm using a zvol block device on Ubuntu's ZFS installer config. It's an option available in the Ubuntu Desktop version only:

zvols are really cool because you can switch between using them for kvm-qemu and [systemd-container][5] (linux only, obviously) - plus snapshot and send / receive them.
But since zvols mimic a regular disk, they demonstrate that you could use a dedicated disk for your VM if you have room to install one, as well.
Once you make the zvol, give it a gpt partition structure using fdisk/sgdisk/{g}parted etc. just like you would any other disk. Once I created the gpt partition, I used the Windows ISO to do the actual partitioning.
btrfs has something similar which should be better supported by systemd-nspawn, but I am not sure if you can operate them like a block device in qemu.
Last tip: I needed to copy some files from the host to the VM. You can't really mount a folder from Linux --> Windows, but I could mount the partition (#3) Windows created on the zvol in the host as a regular NTFS partition.
So while the VM was off, I mounted partition 3 on /mnt, copied the folder I needed, umount /mnt the partition and start the VM back up.
Sometimes it's a little tricky to figure out what to do in that situation, so I thought I'd throw that in. People in guides I've read have also recommended setting up Samba sharing if you need something more frequent, or I also remote to Windows VMs using OpenSSH-Server and PSRemoting, as well, so there's lots of options (Windows even has SSHFS now, if you check out Chocolatey).