Running Android games on Windows 10/11 using QEMU+Hyper-V+virglrenderer+Bliss OS

GuanZhang
10 min readDec 25, 2022

[Please scroll to the bottom of the story to see edit revisions]

If you are trying to play Android games on a PC running Windows 10/11, your best bet is to install some Android Emulator (not Android Studio from Google although technically you can but performance won’t be great).

Sure there is WSA on Windows 11 but from what I heard performance is not great. There is also Google Play Games but apparently it only supports x86 games (this article focuses on ARM games).

I am going to show you an alternative — roll your own Android Emulator using QEMU :D

If you prefer to watch a video guide of me doing the demo and where the article is spoken courtesy of Medium, you can catch it on YouTube here (Note I have started revising the story on Medium so what you see on YouTube will be slightly different. Always refer to Medium for the most up-to-date version of this guide, although in the future I may update the video if there is a demand for it).

You’ll need a system that meets the following requirements:

  • 64-bit Windows 10/11 with Hyper-V enabled
  • Powerful enough to run a Virtual Machine with 4 vCPUs and 4GB RAM (ideally your system can run 8 threads and has 8GB+ RAM)
  • Discrete GPU although an integrated GPU may work
  • Enough disk space to download and compile QEMU and host the Android VM and related files (around 40GB)

Most traditional Android Emulators do not work with Hyper-V enabled, so make sure you are okay with this. You can always turn it off once you are done with testing. Refer to this article on how to enable it.

Now before we get started be warned that some technical expertise is required because we’ll be building QEMU from source and also installing Bliss OS (Android OS) in a virtual environment. It is actually not that difficult so if you follow the instructions carefully you should be able to do it.

First you’ll need to get MSYS2 which is the platform we’ll be using to build QEMU. The latest installer as of this writing can be found here.

After it is installed, if you checked the box to run MSYS2 now, it will fire up a UCRT64 terminal by default. Run the following command to update MSYS2:

$ pacman -Syu

Proceed with the installation/update and after everything is done, the terminal will close. Re-open the UCRT64 terminal and continue updating the rest of the packages. You’ll also need to install a bunch of prerequisite packages in order to build QEMU:

$ pacman -Syu
$ pacman -S make mingw-w64-ucrt-x86_64-diffutils \
mingw-w64-ucrt-x86_64-gcc mingw-w64-ucrt-x86_64-glib2 \
mingw-w64-ucrt-x86_64-libslirp mingw-w64-ucrt-x86_64-make \
mingw-w64-ucrt-x86_64-pixman mingw-w64-ucrt-x86_64-pkgconf \
mingw-w64-ucrt-x86_64-SDL2 mingw-w64-ucrt-x86_64-virglrenderer \
ninja patch python

Now you have an environment that is ready to build QEMU. First make a working directory (I personally like to call it “code” since we’ll be compiling source code but you can call it whatever you want):

$ mkdir code

Go into this directory and download the latest version of QEMU (as of this writing it is 7.2.0)

$ cd code
$ wget https://download.qemu.org/qemu-7.2.0.tar.xz

Extract the tarball:

$ tar xvf qemu-7.2.0.tar.xz

You will get the following error after extracting the tarball but it can be safely ignored:

tar: qemu-7.2.0/roms/edk2/EmulatorPkg/Unix/Host/X11IncludeHack: Cannot create symlink to ‘/opt/X11/include’: No such file or directory
tar: Exiting with failure status due to previous errors

CD into the directory and download the patch to allow building of virglrenderer support for QEMU on Windows:

$ cd qemu-7.2.0
$ wget https://raw.githubusercontent.com/kjliew/qemu-3dfx/master/virgil3d/0001-Virgil3D-with-SDL2-OpenGL.patch
$ patch -p0 -i 0001-Virgil3D-with-SDL2-OpenGL.patch

Now you’re ready to configure the patched QEMU:

$ ./configure --target-list=x86_64-softmmu --prefix=/ucrt64 --enable-whpx \
--disable-hax --disable-tcg --enable-virglrenderer --enable-sdl \
--enable-slirp --disable-capstone --disable-tools --disable-guest-agent \
--disable-gtk

You will get the following error but it can be safely ignored:

Running postconf script 'C:/msys64/ucrt64/bin/python3.exe C:/msys64/home/androidemu/code/qemu-7.2.0/s
cripts/symlink-install-tree.py'
--- stdout ---

--- stderr ---
error making symbolic link C:/msys64/ucrt64/share/trace-events-all
Traceback (most recent call last):
File "C:\msys64\home\androidemu\code\qemu-7.2.0\scripts\symlink-install-tree.py", line 33, in <modu
le>
raise e
File "C:\msys64\home\androidemu\code\qemu-7.2.0\scripts\symlink-install-tree.py", line 29, in <modu
le>
os.symlink(source, bundle_dest)
OSError: [WinError 1314] A required privilege is not held by the client: 'C:/msys64/home/androidemu/c
ode/qemu-7.2.0/build/trace/trace-events-all' -> 'qemu-bundle/msys64/ucrt64/share/trace-events-all'

And we are ready to build:

$ make -j4

Go for a coffee break as it may take some time :-)

After the code is compiled, install/copy all the QEMU related binaries and libraries over to a new folder so it becomes portable and you can run it outside of the MSYS2 environment.

$ make DESTDIR=~/qemu-virgl install
$ cd ~/qemu-virgl/msys64/ucrt64/
$ cp $(ldd qemu-system-x86_64.exe | grep -i /ucrt64/ | awk '{print $3}') .

Now we will setup the virtual environment that will be run by QEMU.

First, you will need to create a virtual disk image to install the Android OS into, by running the following commands:

$ pacman -S mingw-w64-ucrt-x86_64-qemu-image-util
$ cd ~/qemu-virgl
$ qemu-img.exe create -f qcow2 bliss-15.img 20G

The image file may ultimately grow up to 20GB as you install Android apps, so please make sure you have enough space in your drive. You can adjust the size to whatever you want but 20G is a good starting point which gives you enough space for the Android OS and also to install a few games for testing.

We will need to generate a UEFI firmware that QEMU can use on Windows:

$ cat msys64/ucrt64/share/edk2-i386-vars.fd \
msys64/ucrt64/share/edk2-x86_64-code.fd > edk2-x86_64.fd

You can now either stay in the MSYS2 environment or just run everything from Windows PowerShell. In this example we will run it from the PowerShell.

Start by copying the qemu-virgl directory to a separate location. You can find your MSYS2 home directory on Windows Explorer via the path C:\msys64\home\<username> so just copy/move the contents of C:\msys64\home\<username>\qemu-virgl to a separate location, say C:\qemu-virgl.

You’ll need to download an Android OS ISO to install into a virtual machine to be run on QEMU. For this article we will be using Bliss OS 15.8.2 (Bliss-v15.8.2-x86_64-UNOFFICIAL-gapps-20221214.iso). Normally Bliss OS test builds are available here, however there are some issues with the newer builds, so we’re going to be using a slightly older version available from my unofficial mirror. Once the issues are fixed in newer versions of Bliss OS I will update the article. This version of Bliss OS runs Android 12.

Now it is time to start up the virtual machine booting off the Android ISO. Make sure that both the ISO and the UEFI firmware are in C:\qemu-virgl or specify the correct location in the command below:

C:\qemu-virgl> msys64\ucrt64\qemu-system-x86_64 -bios edk2-x86_64.fd `
-accel whpx,kernel-irqchip=off -smp 4 -m 4096 `
-display sdl,gl=on,show-cursor=on -device virtio-vga-gl,xres=1280,yres=720 `
-net nic,model=virtio-net-pci -net user,hostfwd=tcp::5555-:5555 `
-machine vmport=off -usb -device usb-tablet -device usb-kbd `
-machine q35 -drive file=bliss-15.img,if=virtio `
-cdrom Bliss-v15.8.2-x86_64-UNOFFICIAL-gapps-20221214.iso

I didn’t specify any -cpu options, because that is hardware (CPU) specific, so if for whatever reason QEMU does not start or performs poorly, you may try different options and see what works best. For my Intel i7–3740QM CPU for instance, -cpu Westmere works fine as well as -cpu kvm64. You can find out available options by running -cpu ?.

Note there is a bug with using -cpu max when whpx (Hyper-V) is being used as the accelerator.

Once the VM is started and boots off the ISO, you will be presented with this screen. Scroll down and choose “Installation”.

You will need to create 2 partitions. First one is for EFI (boot), the second one is where the bulk of Android (data) will be stored.

Select “Create/Modify partitions”, choose “Yes” to use GPT. Select “New”, press <Enter> for “First Sector”, “+512M” for “Size”, <Enter> for “Hex code”, “EFI” for “partition name”.

Now using the down arrow key scroll down to “19.5 GiB free space” and hit <Enter> (with [ New ] highlighted) to create another partition. Press <Enter> for “First Sector”, <Enter> again for “Size”, <Enter> again for “Hex code”, “Android” for “partition name”. It should now look something like this:

Using the arrow keys, choose “Write”, type “yes” then “Quit”.

Now use the down arrow key to scroll down to “vda2” then press <Enter>.

Select “ext4” as the filesystem to format.

Select “Yes” to install EFI GRUB2.

Choose “Yes” to format.

For this question it doesn’t really matter what you choose, since future releases of Bliss OS removed this option altogether.

After the installation is complete you can close the QEMU window and run the following command to boot your newly installed Android OS off the virtual disk directly:

C:\qemu-virgl> msys64\ucrt64\qemu-system-x86_64 -bios edk2-x86_64.fd `
-accel whpx,kernel-irqchip=off -smp 4 -m 4096 `
-display sdl,gl=on,show-cursor=on -device virtio-vga-gl,xres=1280,yres=720 `
-net nic,model=virtio-net-pci -net user,hostfwd=tcp::5555-:5555 `
-machine vmport=off -usb -device usb-tablet -device usb-kbd `
-machine q35 -drive file=bliss-15.img,if=virtio `
-audiodev dsound,id=snd0 -device AC97,audiodev=snd0

The first time you boot after installation by default the Android setup wizard will start. You can skip it entirely by hitting “E” to edit the boot options and adding SETUPWIZARD=0 at the end and then hitting F10 to boot (you don’t need to do this for subsequent boots).

If for whatever reason you want to boot off the ISO with your disk image mounted, you can use the following options to start QEMU:

-drive file=bliss-15.img,if=none,id=disk1 -device ide-hd,drive=disk1,bootindex=2 -drive file=Bliss-v15.8.2-x86_64-UNOFFICIAL-gapps-20221214.iso,if=none,media=cdrom,id=drive-cd1 -device ahci,id=achi0 -device ide-cd,bus=achi0.0,drive=drive-cd1,bootindex=1

Basically replace the original option -drive file=bliss-15.img,if=virtio with the one above.

After all the hard work, we are now ready to play some games! The following are two ARM games you can install into Android for testing:

Both require ARM translation which is provided by libhoudini.

Download the Android SDK Platform Tools for Windows and extract the ZIP file, then go into command prompt and CD into that directory. You can now use the adb command to install APKs directly into Android.

> .\adb kill-server
> .\adb devices
* daemon not running; starting now at tcp:5037
* daemon started successfully
List of devices attached
emulator-5554 device

> .\adb install <game.apk>

Note the linked APK for Arknights is an XAPK and cannot be installed using adb directly. You can either push the file to Android first using adb and then use an installer such as SAI or just download using Google Play Store, Aurora or other app stores such as QooApp.

Here are some screenshots of games running on our “Android Emulator”:

Arknights (armeabi-v7a)
Gundam U.C. ENGAGE (arm64-v8a)

Obviously not all games will work — some detect root/developer options/Android Emulator and will simply crash but in general this setup is functional.

There is currently a known issue with playing videos in YouTube, Nikke as well as Gundam U.C. ENGAGE — you will notice some strange artifacts such as the following:

To work around the issue, you can edit the boot options:

At the boot prompt, hit “E” to edit.

Add FFMPEG_CODEC=1 at the end and hit F10 to boot.

Lastly some games do not function well with “clicks”, so we’ll need to make Bliss OS emulate taps with clicks. Go into Settings > Blissify > Miscellaneous and enable “Force mouse click as touch” and you’re all set.

I think this is a good starting point to allow us to develop a full-fledged Open Source Android Emulator for Windows (and potentially Mac and Linux as well).

As a reference, there are similar existing Open Source projects like PlayCover for Mac and Waydroid for Linux. Most recently I also learnt about TrinityEmulator which sounds like a pretty cool project as well.

Thanks to Discord users Xtr, QuackDoc, Senjosei and HMTheBoy154.

In the future I will be working on some automated scripts for installation as well as performance tuning and benchmarks, so please stay tuned!

If you have any questions and/or suggestions, the AndroidEmu community has a Discord server as well as a Subreddit, so you can usually find me there.

Edit (12/30/22): clangarm64 repository has been added to MSYS2 so it is necessary to run pacman -Syu twice otherwise you may run into an error saying the database file does not exist. Added notes about errors after extracting the QEMU tarball and running ./configure which can be safely ignored (Thanks u/graphixillusion!). Added instructions on how to skip Android setup wizard.

Edit (2/2/23): For those who have the issue where the QEMU window immediately closes after running, it is most likely that your GPU is not supported, however there is a workaround. Install Chrome then go to C:\Program Files\Google\Chrome\Application\109.0.5414.120 (or whatever version you have) and copy the following files to where the qemu-system-x86_64.exe binary is, run it and everything should work:

d3dcompiler_47.dll
libEGL.dll
libGLESv2.dll

--

--

GuanZhang

Want to help build an Open Source Android Emulator (Win/Mac/Linux)? Join the AndroidEmu Discord and let's talk! https://discord.gg/mRpT4Qq