HMD Eyebuffer resolution is tied to mirror window resolution in error prone way in SteamVr integration

In the UE4 SteamVR integration, HMD resolution is set with r.screenpercentage. This is baselined off of the mirror window’s resolution, and this seems error prone.

At startup, the UE4 SteamVR integration will pick a screenpercentage based on the results of OpenVR’s GetRecommendedRenderTargetSize call.

	// determine our ideal screen percentage
	uint32 RecommendedWidth, RecommendedHeight;
	VRSystem->GetRecommendedRenderTargetSize(&RecommendedWidth, &RecommendedHeight);
	RecommendedWidth *= 2;

	int32 ScreenX, ScreenY;
	uint32 ScreenWidth, ScreenHeight;
	GetWindowBounds(&ScreenX, &ScreenY, &ScreenWidth, &ScreenHeight);

	float WidthPercentage = ((float)RecommendedWidth / (float)ScreenWidth) * 100.0f;
	float HeightPercentage = ((float)RecommendedHeight / (float)ScreenHeight) * 100.0f;

	float ScreenPercentage = FMath::Max(WidthPercentage, HeightPercentage);

	//@todo steamvr: move out of here
	static IConsoleVariable* CScrPercVar = IConsoleManager::Get().FindConsoleVariable(TEXT("r.ScreenPercentage"));

	if (FMath::RoundToInt(CScrPercVar->GetFloat()) != FMath::RoundToInt(ScreenPercentage))

This seems fine, but the problem is if the mirror window ever changes afterwards, the screenpercentage begins being baselined off of the wrong resolution (some games have resizable mirrors).

It seems like for VR, r.screenpercentage itself should be baselined off of either the native HMD resolution or the result of GetRecommendedRenderTargetSize directly, and not be tied back to the resolution of the mirror window in any way, since it is just a detached mirror, unrelated at all to the HMD resolution. This has thrown off several developers.

I was confused by this:

void FSteamVRHMD::GetWindowBounds(int32* X, int32* Y, uint32* Width, uint32* Height)
// (vr::IVRExtendedDisplay*)vr::VRExtendedDisplay();
if (vr::IVRExtendedDisplay *VRExtDisplay = VRExtendedDisplayFn())
	VRExtDisplay->GetWindowBounds(X, Y, Width, Height);
	*X = 0;
	*Y = 0;
	*Width = WindowMirrorBoundsWidth;
	*Height = WindowMirrorBoundsHeight;

Now that I look more at the code, it seems WindowMirrorBoundsWidth and WindowMirrorBoundsHeight aren’t really based on the mirror window and instead are hardcoded to the Vive resolution, so the concern above might not be warranted.

I don’t know if hardcoding the resolution might cause other bugs for e.g. DK2, which has a different base resolution.

Hi, I’ve looked into it more. It is still wrong: while GetRecommendedRenderTargetSize is called with hardcoded values for the vive screen, the actual buffer is allocated as a multiple of the mirror.

So by default with the 720p mirror window you get a multiplier intended for 1200p, but applied to 720p. Ends up very blurry.

And if you change the mirror reolution, the eye buffer resolution changes too, which it shouldn’t.

Also, the WindowMirrorBoundsWidth and height variables are settable by ini file, so you could in theory set them to 1280x720 and get the right multiplier, but GetRecommendedRenderTargetSize is getting called with them a few lines before the ini is loaded and the values are read.

Here’s steps to reproduce:

Launch a default project in VR. Query r.ScreenPercentage-- it will be 140 by default, which is the correct multiplier for the vive screen if baseline off of the vive screen resolution. Instead things are baseline off of the 720p mirror window and it will be blurry.

If you now run ‘r.SetRes 2160x1200’ on the console, things will be much clearer: that’s the Vive’s screen resolution, and combined with the 140 ScreenPercentage it gives the correct eyebuffer size.

There is no way for devs to know to do this without reading a lot of code, and if one of their users is on a 1080p or 720p monitor the Smirror window will be limited and it will end up affecting the HMD res (I just tested this as well, set desktop res to 720, launch game, run ‘r.SetRes 2160x1200’, and your window is limited to 720p and the HMD view, based on that window size, is blurry; run with a 1440p desktop, the mirror fits, and the HMD view is clear).

I am experiencing the same problem and have not found a proper workaround yet. The VR resolution being tied to the preview screen resolution is really a problematic bug. To get it right a fix in the Steam VR integration code is needed, isn’t it? Is there a reason why you set the bug report to resolved?

My current workaround is to run console command ‘r.SetRes 2160x1200’ on startup. On my 1080p monitor this leads to a somewhat acceptable rendering output, although not perfect.

If there’s a better workaround I’d love to hear about it :slight_smile:

PS: My previous workaround was to issue a fullscreen command, same result on 1080p monitor but on 4k monitors this lead to inacceptable performance.

Appears fixed in 4.13 and 4.14 btw