Article Content

This is a very wordy post about how I made my desktop work seamlessly as both a workstation, and as a game console. Not much cloud stuff today, folks. The particularly cool/unique bit being that I have managed to achieve a deterministic dual-boot between two instances of Windows, where I can hibernate one instance, boot into the other, and be free from fear of NTFS corruption and other nastiness, by bullying Windows Boot Manager into submission in my EFI partition(s). If you're just interested in that bit, skip to here.


A car is probably the most expensive asset you will buy that decreases in value.

Your desktop machine is probably the second most expensive asset you will buy that decreases in value.

And yet I think the latter of those is the more concerning one.

Generally, people buy a car, and that's that. They may one day retire that car and replace it with a new one, but people (outside of enthusiasts) generally don't buy two cars for the sake of it, or for different purposes.

But compute? That's a different story. You might buy yourself a desktop PC for your study. Then you might buy yourself an Xbox so you can play video games at your couch. But then, oh no, the PS5 has exclusives. So you buy that, too. So does the Switch, so you buy that as well (in fairness, the Switch is the only case where its games will likely never come to PC, so you can kind of justify that one). All of the above depreciate, and all of the above will need to be replaced. It's wasteful, it's expensive, and it's inefficient.

But basically the only difference between all of these devices is software! Your desktop PC has all the hardware to do everything that these other devices can. So why do we never take advantage of that?

This is the rabbit hole I found myself going down around Christmas last year. I spent days over the holidays tinkering and tweaking, almost losing hope on several occasions. But β€” spoiler alert β€” for the past month or so, I've been relishing in the joys of my Renaissance Machine; the workstation to end all workstations, and the gaming console to end all gaming consoles. Sort of.

But to get there... I had the joys of wrestling Windows. That's the titular element of this post, because it was what made me want to bash my own cranium in, but there's plenty more to discuss before that point. So let's get hacking.

The Objective

So, first of all, the problem statement:

I want to write code, run containers, design graphics, produce videos β€” whatever multitude of disciplines took my fancy that week β€” and stick a pin in it, play some video games for a bit, then come back to exactly where I left off the day later.

Fundamentally, this isn't hard. Sticking a pin in exactly where you were is easily achievable by hibernating your machine. Then go play your PS5 or something. I use Windows (with WSL, I'm not an animal) for my day-to-day operations, and Windows entirely supports this workflow.

But what if you wanted to play games on the same machine you just hibernated?

That's a much harder question to answer.

There's two distinct parts to this:

  1. How do you get Windows to feel like a game console?
  2. How do you get Windows to feel like a game console without it interrupting your workstation workloads?

So, let's address those.

How do you get Windows to feel like a game console?

First of all, what defines "feeling like a game console"?

  1. I should be able to play video games, using my desktop's compute, from another room of the house. This is the crucial bit, because one of my primary motivators was the fact that I hate playing video games in the study. I work here. I don't want to be in this room when I'm doing something recreational.
  2. The UI needs to be fully controller-friendly β€” I don't want to have to use a keyboard and mouse at my couch on the other side of the house.
  3. I need ultra-low latency and decent bandwidth between the client and my desktop.
  4. Ideally, I can wake and shut the machine down remotely, such that I never have to physically interact with it, or even enter the study.

Effectively, my desktop is abstracted away in every meaningful sense. I'd go as far as to say that I should have to consciously remember that I'm not playing on a game console.

Now, let me address the elephant in the room. You're probably asking, "why are you using Windows in the first place?!"

Good question.

Because yeah, even if I wanted to stick to Windows as my "Workstation OS", there's nothing stopping me from dual-booting that alongside a Linux installation, to serve as my "Gaming OS". This was precisely my thinking initially, so I had a rummage online, and I quickly found that the widespread consensus for achieving what I want is to use a Fedora-based distro called Bazzite.

Now, it is true, Linux has come a long way in terms of video game support and playability. Bazzite plays right into this; it's literally designed as a game console OS. It comes with Steam and Sunshine pre-installed, for example. Hopefully you know what Steam is πŸ˜†, but Sunshine's really the star of the show here.

Sunshine lets you stream your video games to Moonlight. The former goes on your host, the latter goes on your client. I have genuinely no ill to speak of either of these. They configurably, yet seamlessly and simply handle everything from:

  • Audio and video, obviously
    • But also, more nuanced things such as switching your PC's audio devices to the stream or to your defaults, dependent upon whether a Moonlight client is connected
  • Controller input for various platforms
  • Even things like haptics

That already solves requirement 1, and requirement 2 as well, because Bazzite loads straight into Steam Big Picture on startup, which is controller-friendly, and from there, it's whatever support your games have (most do support controllers).

Requirement 3 is a bit of physical work, but I already have Cat6 cables connecting the study up to a switch in the loft, out of which is another Cat6 into each room β€” including the room in which I have my Moonlight client installed. So that was easily done.

Finally, requirement 4. Wake-on-LAN (WoL). I've historically found this to be very janky and... far from a perfect science. But basically anything like "Energy Efficient Ethernet", or "Green Ethernet" in your BIOS/OS device management settings; switch them off. You basically just don't want the power to the NIC to be cut off on shut down, so it can respond to magic packets. I eventually got it working, but I'd be lying if I said I could give you a consistent, repeatable guide...

It wasn't all sunshine and rainbows

Sorry... you'll have to excuse the pun. It was good though, c'mon.

Bazzite came with two critical problems.

  1. Not a deal-breaker, but not far off: Linux... doesn't really have great support for virtual displays. This was quite a strict requirement for me. I have four monitors (I know, shut up), all of which are ultrawide, in different orientations. I can't use any of them as a 16:9 4K 120Hz display, which is what my TV can render. Maybe there are ways to hack around it, but from an energy efficiency standpoint, I really don't want what's streamed to my TV to just be a mirror of what's being physically displayed on a screen in the study. I'm not physically there, so it should be headless. There's a fantastic Virtual Display Driver for Windows by MikeTheTech, but nothing so promising for Linux. I spent about half a day faffing with edid files and xrandr, before I eventually came to the conclusion that the only way people get around this is to use a dummy plug β€” basically a fake display output to trick the GPU into rendering a virtual display. But of course... I have four monitors. I also only have four outputs on my GPU. Returning to requirement 4 β€” I don't want to have to physically enter the study. For this, I would need to switch one of my real outputs out for a dummy plug, all the time (okay, I could probably use some kind of splitter with a toggle, but this starts to look incredibly overengineered). Yes, first-world problems, I know. But this definitely made returning to Windows seem a little more appealing...
  2. The real deal-breaker was the latency. If I physically sat at the desk to play video games, it was undetectable. And to be honest, I couldn't feel the latency in most games. It was when I picked up Celeste β€” which is a fairly hard, precision-demanding platformer β€” that I could physically feel the lag. It might've been ~15ms, maybe not even that, but there was this slight delay between moving my thumbstick and seeing Madeline move that, repeatedly, made me die dozens of times on a level I normally ace. I'm not sure if this is added latency due to DXVK or something, but I tried the same setup on Windows, and it was far smoother. That was kind of the nail in the coffin.

And so... back to single-boot.

Replicating the ease of Bazzite in Windows

Surprisingly, this wasn't super difficult. I basically just replicated what I had in Bazzite (manually installing things as necessary this time), set Sunshine to open on startup, and configured a virtual display which Sunshine would stream β€” but the secret sauce was an app called GameConsoleMode (GCM). This handles various bits to get the whole desktop-gaming-console setup working smoothly, including:

  • Replacing the Windows UI with a console-like, controller-friendly interface
  • Booting straight into a launcher of your choice, including Steam Big Picture, for example, like Bazzite does
  • Various extensions, including for DisplayFusion, so you can switch between monitor profiles when it starts
    • I have a profile that disables all of my physical displays, leaving only the virtual one enabled, when in GCM
  • And various other bits.

It worked very smoothly, but to get to that point, I had to use Windows Autologon (which I wasn't overly happy with), and to get past the UAC prompt that would show on every startup (to load GCM), I had to run it as a task on startup, with administrative permissions, using Task Scheduler. Given that this is also the OS I use as a workstation, I wasn't overly comfortable with some of this.

The usability of it was the nail in the coffin here, though. Though technically I could hibernate my machine, it wouldn't boot back into GCM from hibernation, and even if it did, it really bugged me that my workstation was now effectively console-first, workstation-second. Since DisplayFusion disabled my physical monitors (and GCM forced the profile, so I couldn't use a hotkey to back out of it), I had to go to the other side of the house, load my Moonlight stream, and close GCM from the stream, which would then re-enable my physical monitors. It... worked, but it felt horribly hacky and... crucially, not quite like a console, and not quite like a workstation either.

Which brought me on to the second of our distinct problems above.

How do you get Windows to feel like a game console without it interrupting your workstation workloads?

So, we now know exactly how to make Windows feel like a game console. Once in that interface, it really did feel smooth, seamless, and totally comfortable to play. But my workstation was really suffering. I was sure, and I'm still sure now, that there are ways to make a single installation of Windows behave in exactly the way I want; to have two isolated profiles within a single installation, where I can flick seamlessly between gaming and workstation. Using a VM would be my best off-the-cuff idea β€” but that of course comes with some performance implications. No matter how you spin it, wanting to hibernate my machine made any possible solution just feel a little bit... wrong. I mean, sure, I could leave my workloads open in background while I play a game, but it feels dirty, and ultimately, it does take a hit on your game's performance. It's never going to be perfect.

So, I considered something that made my stomach sink.

Dual-booting two instances of Windows.

You can do this without paying for another Windows license, because it uses the hardware signature, which is obviously going to be the same for your second install.

...This was horrible. Primarily because Windows is notorious for treating NVRAM and EFI partitions as its personal playground. But eventually β€” eventually β€” I got it working, seemingly deterministically.

Disclaimer: If you're going to follow along with the below, that's fine, I don't think there's any conceivable way you could hard-brick your machine, but you will almost definitely soft-brick it at some point. Make sure you have some Windows installation media handy, that you're comfortable mounting/navigating EFI partitions, taking backups of them, using bcdboot to reinstate broken boot entries, and that you're mentally prepared for seeing a lot of blue screens. I take no responsibility for Windows-induced crying as a result of following the below.

To get this working, we kind of need two broad axioms:

  1. No matter what happens, the bootloader at the top of our boot order always == our custom bootloader (e.g., rEFInd, GRUB β€” I went with the former β€” just not Windows Boot Manager)
  2. S5 (Shutdown) and S4 (Hibernate) power states always == cold-boot, regardless of the state of that OS; so our bootloader menu is opened.

As long as these are true, it should work deterministically.

To get there, we need a few other things to be true:

  1. Each Windows instance must be installed on a separate SSD, with its own EFI partition. Each instance of Windows must boot from the EFI partition on its own SSD. As such, we create a situation in which neither installation has any idea that the other exists. Basically, both SSDs are completely decoupled, with each one having everything to do with its own Windows installation, and nothing to do with the other Windows installation. There are two reasons we need this:
    • a. If both Windows installations are setup to use the same EFI partition, Windows will "helpfully" use Windows Boot Manager's selection menu to enable you to choose between the two... maybe. Under its own conditions. One of those being that if one Windows instance is hibernated, you will be forced into booting that one. Something I learned the hard way: If you don't physically disconnect your SSD with an existing Windows installation when you install your second from Windows installation media, it'll use the existing EFI partition. You can fix this by remapping your boot entries for each Windows installation with bcdboot, though.
    • b. We want to be able to offline the other disk with diskpart β€” effectively barring it from mounting the disk. So, if Windows copy A is installed on SSD A and Windows copy B is installed on SSD B, then Windows copy A needs to not mount SSD B, and vice-versa. This is critical, because mounting a hibernated filesystem from a different OS is how you corrupt it (yes, even though NTFS is built to work as a shared partition).
  2. With our boot entries now totally separate, we need a bootloader that isn't Windows. I went with rEFInd, and it's worked very well, but you can use GRUB. In sum, you want to download rEFInd, assign your EFI partition a letter with diskpart, and copy your rEFInd files over (delete any files not for your architecture though; e.g., aa64 if you're on x64; almost definitely you will be) to \EFI\refind on your EFI partition. UEFI will detect rEFInd's .efi file so you can boot into it. You can find a proper guide online, but specifically for this case, do this for the EFI partition on both SSDs.
  3. In each Windows installation (for now you'll probably have to manually rearrange your boot order to point to the correct OS in BIOS), use bcdedit to point your Windows Boot Manager entry to \EFI\Boot\refind_x64.efi on your disk's EFI partition. You can just assign it a drive letter and update the boot entry to point to that; bcdedit will figure out what GPT partition GUID that translates to iirc.

So, this all works marvelously well... for all of about five minutes, until Windows goes and rearranges your boot order. So, even if you've pointed Windows' own boot manager to rEFInd, it'll still rearrange the order to point to something else that isn't rEFInd.

Remember how I said earlier that Windows treats EFI partitions as its personal playground? Yeah.

Fortunately, we've already constrained its ability to mess around a little bit, by offlining the opposite Windows installation's disk. This means it won't attempt to do anything with the EFI partition from which it did not boot. However, we now most likely have three main EFIs on each of our two EFI partitions:

  • \EFI\Microsoft\Boot\bootmgfw.efi β€” this is the actual Windows bootloader πŸ‘Ώ β€” Windows theoretically shouldn't point to this, because it should instead look for rEFInd (as we specified earlier), but that's not a guarantee
  • \EFI\refind\refind_x64.efi β€” this is the rEFInd bootloader πŸ˜‡
  • \EFI\Boot\bootx64.efi β€” this is actually also a Windows bootloader in disguise (πŸ‘ΏπŸ‘Ώ), but it's also considered the "backup" bootloader in the eyes of the UEFI spec. Windows sometimes sticks this at the top of the boot order instead, which just... boots Windows.

So, we've still got... 1.5 problems there?

So we need to do 1.5 clever things to get around them:

  1. Delete everything in your \EFI\Boot folder. Yes, I mean that. Maybe make sure you've got a backup first. Copy the contents of your \EFI\refind folder into \EFI\Boot, then rename \EFI\Boot\refind_x64.efi to \EFI\Boot\bootx64.efi. Voila. Cue you thought it was Windows, but it was me, rEFInd!
  2. Just to make absolutely sure Windows doesn't try pushing bootmgfw.efi to the top of the boot order, let's rename it. Don't replace it, we still need it to actually boot Windows, unfortunately. I renamed mine to bootmgfw-disabled.efi. Then, in your refind.conf β€” there's one under \EFI\Boot, and one under \EFI\refind β€” create a menuentry for each of your Windows installations (in my case, "Gaming" and "Workstation"), and point them to the correct partition (you will need the GUID now, because rEFInd isn't aware of Windows drive letters) and path on that partition, so they're each pointing to the corresponding SSD's bootmgfw-disabled.efi.
    • This is a bit annoying β€” FAT32 doesn't allow symlinks, so you will have to adjust this config file twice for each SSD; once for your \EFI\refind version of rEFInd, and once for your \EFI\Boot version of rEFInd. To be fair, you could probably do away with \EFI\refind entirely, but that'd mean pointing your Windows Boot Manager to the UEFI backup bootloader, which... just doesn't feel right.

Windows now has absolutely no idea how to boot itself. If it tries to open its Boot Manager, it loads rEFInd. It can't find bootmgfw.efi, because it no longer exists, so it falls back to \EFI\Boot\bootx64.efi, which is actually just rEFInd. The only entity that knows there's actually two Windows installations is rEFInd (because it reads all EFI partitions, and you've manually specified your menuentry items anyway), and it's also the only entity that knows how to boot either installation of Windows.

Our two axioms have now been achieved. Every time your PC goes into hibernation or shutdown, it will bring up rEFInd on next boot β€” regardless of whether or not each installation of Windows is hibernated.

All I had to do from there was update my refind.conf files to default to "Gaming" windows, with a timeout of 10s, and now I can:

  1. Hibernate Workstation windows
  2. Switch on the Xbox upstairs (I installed the Moonlight UWP app on my Xbox Series X, which can decode at up to 4K@120Hz β€” you can also use a Raspberry Pi or something, but afaik they can only do up to 4K@60Hz); open Moonlight; send a magic packet to the host
  3. The PC wakes, rEFInd is loaded, It waits 10 seconds before loading into Gaming windows.
  4. Gaming windows boots up GCM, Sunshine, and Steam Big Picture, and starts streaming
  5. I open the stream, play video games for a bit, shut it down, go to sleep, whatever...
  6. The next day, I enter the study, switch my PC on, it loads rEFInd, I manually select Workstation windows...
  7. And whaddya know, I'm back to exactly where I left off. hiberfil.sys kept completely intact, no filesystem corruption, because as far as Workstation windows is aware... nothing happened since you last hibernated the machine.

Glorious.

Going forward

This is fantastic. It's gotten me back into actually playing video games, while also making me more productive during the day. It's saved me the Β£23/month I was going to be spending on Game Pass Ultimate, and in general, it has made me a very satisfied nerd/mad scientist.

Next steps?

Maybe I'll get all cloud-y with it (oh, c'mon, you knew I couldn't write a post that didn't mention the cloud at all). This all works very smoothly and stably on my local network, but what about if I effectively make my own cloud gaming setup? Perhaps I could register my machine with Tailscale, go to a friend's house, connect from there, and play co-op. Maybe a Tailscale connection to my Raspberry Pi on the same network as the desktop; then I can send a POST request to an API endpoint, which in turn sends a magic packet to wake it up, and away we go.

A GIF of Okabe Rintarou, the protagonist of the anime Steins;Gate, doing mad scientist poses.

Do I think it will hold up?

No.

Windows will definitely throw a strop at some point β€” most likely on a major update. But tbh, what we've built here is genuinely stable, and far more deterministic than Windows boots itself. Whatever breaks, you can kind of blame Microsoft πŸ˜†

As long as you're comfortable with a big blue screen one day, with your installation media and your bcdboot commands at the ready, the (hopefully) many months before that point will absolutely make it all worth it.