Run Sunshine + Moonlight on 4K TV without a 4K monitor

Hello everyone!

Since I was unable to find the answers myself, I decided to figure it out on my own and share it with all of you. Yeah, I used ChatGPT for the scripting, but there was a lot of trial and error and figuring things out on my own. Now, I might have gone a little too far, and there might be better solutions out there, but here's what I did...

Problem:
From what I can tell, the GameStream protocol relies on capturing the display output for streaming. It's not capturing raw graphics output (like a graphics benchmark can run in the background), it's just intercepting it. This means if you have a 1440p monitor and you want to stream your game to your 4K TV, you'd have to resort to such Neanderthalic methods as setting your graphics properties to output a higher-than-native resolution (and I'm not even sure if that would work as intended).

Solution:
Though the documentation for Sunshine is kind of lacking, it turns out that the interface to add applications to the Moonlight listing is just Command Prompt commands. So, I figured, why not try a solution that takes advantage of the fact I can make Windows do whatever I want?

Step 1:
From some other reddit posts regarding using Sunlight without a monitor...
Download the lddSampleDriver.zip from Releases · ge9/IddSampleDriver (github.com)
Set-it up in accordance with ge9's readmefile.
Open the "option.txt" file, and get rid of resolutions you don't want and change the 60 [fps] to something like 120, if your streaming device can support it. (e.g. 3840, 2160, 120)
Go to Windows Display Settings and set the display mode to "Show only on 1"
Whatever you do, DO NOT set this virtual display as your primary!

Step 2:
Open Notepad.
Copy and paste the following PowerShell script in there:

Add-Type @"
  using System;
  using System.Text;
  using System.Collections.Generic;
  using System.Runtime.InteropServices;
  public class Windows {
    [DllImport("user32.dll", EntryPoint = "GetWindowText", ExactSpelling = false, CharSet = CharSet.Auto, SetLastError = true)]
    public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpWindowText, int nMaxCount);
    [DllImport("user32.dll", EntryPoint = "GetWindowTextLength", ExactSpelling = false, CharSet = CharSet.Auto, SetLastError = true)]
    public static extern int GetWindowTextLength(IntPtr hWnd);
    [DllImport("user32.dll")]
    public static extern bool EnumWindows(EnumWindowsProc lpEnumFunc, IntPtr lParam);
    public delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam);
    public static List<string> GetWindowTitles() {
      List<string> titles = new List<string>();
      EnumWindowsProc enumProc = (IntPtr hWnd, IntPtr lParam) => {
        int length = GetWindowTextLength(hWnd);
        if (length > 0) {
          StringBuilder sb = new StringBuilder(length + 1);
          GetWindowText(hWnd, sb, sb.Capacity);
          titles.Add(sb.ToString());
        }
        return true;
      };
      EnumWindows(enumProc, IntPtr.Zero);
      return titles;
    }
  }
"@

Start-Sleep -Seconds 10

while ($true) {
  $windowTitles = [Windows]::GetWindowTitles()
  if ($windowTitles -notcontains "Steam Big Picture Mode") {
    # If "Steam Big Picture Mode" is not in the list of window titles, switch back to the primary display
    DisplaySwitch.exe /internal
    break
  }
  Start-Sleep -Seconds 5
}

Save the script somewhere easy to remember like C:\Scripts, and name it something like "WaitforBigPic.ps1"

Step 3:
Open Sunshine's GUI and navigate to the Apps section (https://localhost:47990/apps)
Edit the default "Steam Big Picture"
Under the "Detached Commands" section, in this order:
- DisplaySwitch.exe /external
- steam steam://open/bigpicture
Under the "Command" section:
- powershell -File "C:\Scripts\WaitforBigPic.ps1" (example file location)

Now, when you launch Steam Big Picture from Moonlight, Windows will set your primary display to the virtual 4K monitor, and when you close Big Picture Mode, it will revert back to your actual monitor!

The only thing I wish was that ge9 would have added support for HDR in his virtual display driver... If anyone knows a thing or two about driver development, especially using Microsoft's Indirect Display Driver using the IddCx class extension driver, please drop me a DM!

I hope this helps