SDL icon indicating copy to clipboard operation
SDL copied to clipboard

[Feature Request] Add 4k support for UWP on xbox

Open tunip3 opened this issue 2 years ago • 8 comments

UWP on Xbox will always return a windows size of 1080p regardless of display res. However, you are still able to create a 4k swapchain will output at this resolution. You can instead get the display res from the HDMI device information on Xbox to get the actual display res. It would be nice to see SDL implement this for proper 4k support on UWP. I have tried a quick and dirty implementation of this by manually overriding the window size as 4k however this produces a zoomed in image even though the swapchain says that it is set to 4k. I think somewhere in the chain SDL is still only producing an output that is only 1080p

You can find more about 4k on UWP here: https://walbourn.github.io/directx-and-uwp-on-xbox-one/

Below I have added the functions that retroarch uses to get the output res on its UWP port as an example.

int uwp_get_height(void)
	{
		/* This function must be performed within UI thread,
       * otherwise it will cause a crash in specific cases
		 * https://github.com/libretro/RetroArch/issues/13491 */
		float surface_scale    = 0;
		int ret                = -1;
		volatile bool finished = false;
		Windows::ApplicationModel::Core::CoreApplication::MainView->CoreWindow->Dispatcher->RunAsync(
			CoreDispatcherPriority::Normal,
			ref new Windows::UI::Core::DispatchedHandler([&surface_scale, &ret, &finished]()
				{
					if (is_running_on_xbox())
					{
						const Windows::Graphics::Display::Core::HdmiDisplayInformation^ hdi = Windows::Graphics::Display::Core::HdmiDisplayInformation::GetForCurrentView();
						if (hdi)
							ret = Windows::Graphics::Display::Core::HdmiDisplayInformation::GetForCurrentView()->GetCurrentDisplayMode()->ResolutionHeightInRawPixels;
					}

					if (ret == -1)
               {
                  const LONG32 resolution_scale = static_cast<LONG32>(Windows::Graphics::Display::DisplayInformation::GetForCurrentView()->ResolutionScale);
                  surface_scale                 = static_cast<float>(resolution_scale) / 100.0f;
                  ret                           = static_cast<LONG32>(
                        CoreWindow::GetForCurrentThread()->Bounds.Height 
                        * surface_scale);
               }
					finished = true;
				}));
		Windows::UI::Core::CoreWindow^ corewindow = Windows::UI::Core::CoreWindow::GetForCurrentThread();
		while (!finished)
		{
			if (corewindow)
				corewindow->Dispatcher->ProcessEvents(Windows::UI::Core::CoreProcessEventsOption::ProcessAllIfPresent);
		}
		return ret;
	}
int uwp_get_width(void)
	{
		/* This function must be performed within UI thread,
       * otherwise it will cause a crash in specific cases
		 * https://github.com/libretro/RetroArch/issues/13491 */
		float surface_scale    = 0;
		int returnValue        = -1;
		volatile bool finished = false;
		Windows::ApplicationModel::Core::CoreApplication::MainView->CoreWindow->Dispatcher->RunAsync(
			CoreDispatcherPriority::Normal,
			ref new Windows::UI::Core::DispatchedHandler([&surface_scale, &returnValue, &finished]()
				{
					if (is_running_on_xbox())
					{
						const Windows::Graphics::Display::Core::HdmiDisplayInformation^ hdi = Windows::Graphics::Display::Core::HdmiDisplayInformation::GetForCurrentView();
						if (hdi)
							returnValue = Windows::Graphics::Display::Core::HdmiDisplayInformation::GetForCurrentView()->GetCurrentDisplayMode()->ResolutionWidthInRawPixels;
					}

					if(returnValue == -1)
               {
                  const LONG32 resolution_scale = static_cast<LONG32>(Windows::Graphics::Display::DisplayInformation::GetForCurrentView()->ResolutionScale);
                  surface_scale = static_cast<float>(resolution_scale) / 100.0f;
                  returnValue   = static_cast<LONG32>(
                        CoreWindow::GetForCurrentThread()->Bounds.Width 
                        * surface_scale);
               }
					finished = true;
				}));
		Windows::UI::Core::CoreWindow^ corewindow = Windows::UI::Core::CoreWindow::GetForCurrentThread();
		while (!finished)
		{
			if (corewindow)
				corewindow->Dispatcher->ProcessEvents(Windows::UI::Core::CoreProcessEventsOption::ProcessAllIfPresent);
		}
		
		return returnValue;
	}

tunip3 avatar Dec 05 '22 19:12 tunip3

Feel free to submit a PR for this!

slouken avatar Dec 05 '22 19:12 slouken

Feel free to submit a PR for this!

I can open a pr but unfortunately it will have to be in an uncomplete state as like I have mentioned I was unable to find a way to prevent the image from being zoomed into as somewhere along the chain the resolution must be set to 1080p

tunip3 avatar Dec 05 '22 20:12 tunip3

The most reliable way to do this is to use GetGamingDeviceModelInformation per a more recent blog post.

walbourn avatar Dec 05 '22 22:12 walbourn

The most reliable way to do this is to use GetGamingDeviceModelInformation per a more recent blog post.

Thanks!

slouken avatar Dec 05 '22 22:12 slouken

The most reliable way to do this is to use GetGamingDeviceModelInformation per a more recent blog post.

Yes, however the benefit of using the resolution from the HDMI device information is that you can avoid rendering at a higher resolution than needed.

tunip3 avatar Dec 05 '22 22:12 tunip3

For Xbox games just create the swapchain at the 4K or 1440p size regardless of the current setting of the TV. The hardware scalar takes care of the rest. The only reason you need use GGDMI is to deal with:

(a) Xbox One original h/w scalar can't handle anything larger than 1080p (b) The pixel throughput for 4K requires an Xbox One X or Xbox Series X to get a good framerate.

walbourn avatar Dec 05 '22 22:12 walbourn

@walbourn do you know if UWP titles can support higher refresh rates than 60hz?

tunip3 avatar Dec 05 '22 23:12 tunip3

Most advanced graphics features (HDR, 120Hz, etc.) require access to the Microsoft GDK with Xbox extensions.

walbourn avatar Dec 05 '22 23:12 walbourn