Half-Life: Alyx performance analysis (or: why low graphic settings produce a sharper image)

Petros Douvantzis
12 min readJun 6, 2020

--

I have been a happy PSVR user for more than 1 year and due to Alyx, I got the Valve Index. Alyx and the Index live in the PC space and playing with it reminded me of the difference between console and PC gaming in terms of tweaking and out of the box experience.

Alyx was built to work with a variety of VR headsets and different setups in terms of computing power. It comes as no surprise that it has various graphic options to tweak, on top of those provided by Steam VR such as “render resolution” and “motion smoothing”. If you’re like me, you’ll understand why I spent my first 2 weeks with the headset playing with the settings instead of enjoying the actual game.

So, here are my findings which will can hopefully help you get a higher resolution picture from the game. I run Alyx on my PC, having a GTX1080, and on my Razer Blade Advanced 2019 model, having an RTX2080 Max-Q. I will also get into some details in the end of the article about the issues I faced when running VR from a laptop.

If you’re interested just in the tips, you can skip to the TLDR paragraph.

Steam VR render scale

Before diving into Alyx’s dynamic resolution implementation, we need to first look at how Steam VR handles resolution. When a game renders a frame, it isn’t sent straight to the headset. It’s handed over to Steam VR’s compositor, which applies lens correction and renders it to the headset’s native resolution. So, the game’s resolution can be different than the headset’s.

Steam VR settings

In Steam VR you can set the “render resolution” per eye. Valve index has a per-eye resolution of 1440×1600. Setting the render resolution to 100% results in 2016×2440.

The reason it’s bigger than the headset’s native resolution is because it takes into account that lens correction will stretch out the center of the game’s rendered frame and it will need more pixels to sample from.

Steam VR has a per-game resolution multiplier that when multiplied with the render resolution, produces the resolution that the game will render to. Let me give you an example.

If you use 120% for the “render resolution”and 200% for the per-game multiplier, the final resolution scale will be: 120% x 200% = 240 % , producing a render resolution of 3122×3780. Note that the percentage refers to the total amount of pixels and not the per axis increase. So, 200% will not result in a horizontal resolution of 2 x 2016 = 4032 , but in

The total amount of pixels (taking into account both the horizontal and vertical resolution increase) will be double, though.

Alyx dynamic resolution

Alyx, on the other hand, uses a dynamic resolution scheme, where Steam VR’s resolution is only used as a reference. You can check out a really interesting analysis of the game’s algorithm by Alex Vlachos , but I’ll explain the gist of it bellow.

Alyx uses 8 different fidelity levels (not to be confused with fidelity levels found in the game’s graphics settings menu), which result in higher or smaller render resolutions and MSAA x4. In my case, where I set the global steam VR scale to 118% (2188 x 2432), the levels are:

Resolutions per fidelity level. Steam resolution is 2188 x 2432.

Level 3 defaults to the Steam VR resolution. The other resolutions are calculated according to each fidelity level’s scale. For example, level 8 results to 3094 x 3439 which has double the amount of pixels than fidelity level 3.

The game tries to choose the higher fidelity level possible, as long as no frame is dropped. If you run your headset at 90Hz, the GPU has a 11,1ms window to render the frame. Alyx, will try to render it in 0,9*11,1 = 10 ms as it leaves some time for the VR compositor to do the final render and also allows for some headroom. This means that if you get into a GPU intensive scene, Alyx will probably drop the fidelity level. On the other hand, looking at the sky, will probably reach level 8.

The algorithm chooses a higher fidelity level for less complex scenes , such as looking towards the sky

You can visualize the fidelity level used, by launching the game with -console -vconsole:

, pressing the tilde(~) key to open the console, typing vr_perf_hud 1 and hitting enter. There is a way to disable the automatic fidelity level algorithm and force your own. To disable it, type: vr_fidelity_level_auto 0 and to force fidelity level 8, type: vr_fidelity_level 8 .

I played with the fidelity levels while gazing at City 17 from the balcony at the beginning of the game. The following gifs cycle between level 0, 3, 6, 8:

Gif cycling different fidelity levels. Notice how the GPU time graph increases with the level.

Due to gif compression, the difference may not be that apparent. To see the difference better, you can view the in-game screenshots on a computer monitor: 0, 3, 6, 8. Notice that the higher the fidelity level, the larger the screenshot size. This is because Alyx is handing a larger buffer to Steam VR’s compositor as fidelity level increases.

Level 8 resulted in super clear and detailed textures. I could easily make out the individual leaves of the trees at the street level and the railings of the balcony at the first floor were rendered beautifully. The geometry of the buildings far away was solid without shimmering. Level 3 on the other hand, was quite more blurry. Level 6 was a good compromise. Unfortunately, the game mostly played around level 3 with the out of the box settings.

Alyx does not give you a direct way (besides using the console) of controlling the fidelity level from the graphics options, but you can control it in an indirect way: using higher graphic presets, can result in a lower fidelity level. This is far from intuitive, but since you are stressing your GPU more at higher quality settings, the algorithm will have to drop the resolution to manage and hit those 10 ms.

I noticed that in some reviews where they fiddle with the graphics options and conclude that Alyx plays well in Ultra settings even in lower-end GPUs, they don’t realize that they’re getting a blurrier image. For example, in this comparison they attribute the bluriness of ULTRA settings to different Anti-Aliasing and not to the lower fidelity level chosen by the algorithm.

Graphics options

Alyx has some graphics options under the “performance” menu, which can alter the quality and the effect detail level. There are some ready to use presets that vary from “low fidelity” to “high fidelity”. Even though the word “fidelity” is used, it’s not related to the “fidelity level” that controls the game’s resolution.

Here are 2 screenshots with low and ultra settings. The fidelity level has manually been forced to 6, so that we remove that from the equation:

“low” settings on the left, “ultra” settings on the right

If you’re struggling to see the difference, it’s because in this particular scene there is virtually no difference. If you zoom-in you can see in the “ultra” screenshot, that the characters have an ambient shadow in their feet. This is controlled by the “character” setting. The performance implications though from “low” to “ultra” are vast.

“High” settings with some tweaks

The “textures” setting remains at “high” regardless of the preset you use. It has almost no performance cost, unless you run low on GPU memory. The settings that can greatly affect performance are “characters”, “fog” and “shadow”. You can see exactly how they affect the image in this really good guide (that I previously mentioned). The “shadows” setting affects the resolution of the dynamic shadows. “Character” setting does not seem to affect the character detail, but it enables something like ambient occlusion and creates a soft shadow on the character’s feet making them look more grounded.

In order to measure the performance cost of these 3 settings, I set all of them to “low” and measured GPU time with fidelity level locked to 3. I changed each setting to “medium” and “high” and measured the increase in GPU time.

GPU time increase (in ms) per graphic setting

The way to read the table is for example, that an increase in “character” level from “low” to “medium” costs 0,7 ms.

If you want to gain performance, set all of them to low.

For a slightly better visual result set:

  • “shadows” to “medium” or “high”
  • “fog” to “medium”

MSAA

Alyx uses MSAA x4 for all fidelity levels (at least in my system). You can change (or even disable) the MSAA level, by writing in the console: vr_msaa 0.

Many gamers think that MSAA is mostly blurring the geometry edges, but that would be an oversimplification. Its effect is crucial to the visual quality in VR, image stability and geometry detail as the following screenshot shows:

MSAA level comparison (check out the tree branches)

MSAA x4 effectively quadruples the geometry coverage. Geometry that is driven by alpha textures such as wires and tree branches (that probably use “alpha to coverage” and rely on MSAA to work correctly) have a huge improvement with MSAA enabled.

I also noticed that disabling MSAA produces a slightly brightened image. I believe that Alyx expects MSAA to be enabled before tone-mapping the final image.

What about the performance cost you may ask? Here’s a really interesting table:

GPU time for different MSAA values and fidelity levels

It’s certainly not cheap. But if you consider that using MSAA x4 is similar to rendering geometry from a buffer of 2700x3000 to one of 5400x6000, it’s acceptable. Fragment shaders still run at the initial resolution. So, even though you gain more “geometry” resolution, you don’t get sharper textures.

You may be tempted to disable it though. Looking at the table, you can see that “fid. level 6, MSAA x2” has similar performance to “fil. level 8, MSAA x0”. Check out the visual comparison:

fidelity level VS MSAA level

I think the choice between the two is obvious.

“Fid. level 6, MSAA x4” is slightly faster than “Fid. level 8, MSAA x2”. Here’s a comparison:

The difference in this case is much smaller.

Here are all the screenshots. I recommend looking at them at a 100% scale in a monitor.

Motion smoothing

Steam VR has the option of motion smoothing enabled by default. This can be useful when a game can’t deliver a frame in time. Motion smoothing takes into account the previous frames and creates a synthetic one. If enabled, it prepares a synthetic frame even if you never drop a frame, so that it’s ready if needed. This process however can increase the game’s render times by 2ms.

Not than unlike motion smoothing, reprojection is always running to correct the image, based on the headset’s latest orientation (not position). The performance cost of this operation is negligible. Reprojection will render a frame even if the game drops one, however it will not compensate for translation in the way “motion smoothing” does. For example, if you use locomotion, motion smoothing can make it look smooth even if the game drops frames. Timewarp can’t. Note that you won’t get motion sickness with motion smoothing disabled even if the game drops frames. You’ll just experience a bit of judder in moving objects. Reprojection, on the other hand, reduces motion sickness.

Since Alyx is already varying the resolution to avoid dropping a frame, you don’t actually need “motion smoothing” enabled at the same time. So, disable it and enjoy the higher fidelity level that Alyx will choose due to the extra GPU power available to it.

If your GPU can’t reach the headset’s refresh rate, even with all the proposed optimizations applied, you can enable “forced motion smoothing” which results in halving the game’s refresh rate. In our example, Alyx will render at 45 Hz, which needs a render time of 22ms. The game’s algorithm though will still try to hit 10ms and probably choose a low fidelity level, which will result in a blurry picture. In this case, you can take the situation into your own hands and force a fidelity level that you like, as long as it has a render time of less than 19ms. If you enter a demanding area though and it takes more than 19ms to render the frame, the frame rate will drop to 90/3=30Hz.

It would be a great improvement if the auto fidelity algorithm targeted half the frame rate when “forced motion smoothing” was enabled.

Laptop optimization (aka: why nvidia Optimus sucks)

Even though my Razer Blade’s RTX2080 Max Q performs similarly to my desktop’s GTX1080, the VR performance was quite bad. Fortunately, I found the reasons that caused it.

At first, I had to use Razer’s game mode, which resulted in robust performance without frame spikes. I usually don’t prefer it over balanced mode, due to the higher fan noise, but it’s mandatory for stable VR performance.

In case you are using Afterburner to lock the GPU frequency, don’t. It causes frame drops in VR.

The primary reason Alyx performed bad in my laptop though, was the spectator window. Most gaming laptops use nvidia’s Optimus technology, which uses the nvidia discrete GPU for rendering and then copies the result to the integrated GPU so that it’s displayed in the monitor’s laptop. In the following screenshots, you can see the Intel integrated GPU (GPU 0), being utilized by “Desktop Window Manager” so that the VR view is rendered in the laptop’s screen:

integrated GPU utilization when VR View is enabled in the laptop’s screen

In the next screenshot, I had the VR view disabled at first. The red line shows the time when I enabled the VR View. Notice that Intel’s GPU utilization increases and as a side-effect the CPU usage increases too, stealing CPU power from the game. This translates to increased render times in VR and thus frame drops.

CPU and GPU utilization increase when VR View gets enabled in laptop’s screen

One solution is to lower the spectator’s window resolution or even minimize it. To do that, run Alyx with -window -w 512 -h 512 . You can even disable the window entirely by running Alyx with -nowindow.

Another solution is to connect an external monitor via HDMI (or whatever output is directly connected to your discrete GPU) and set it as your main monitor. In this case, the spectator window will not cause any performance issues.

VR View & Spectator view cost in desktop systems

The previous paragraph showed that Alyx’s spectator window has a huge performance impact on laptops with nvidia Optimus technology. How about desktops systems though(or laptops when an external monitor is used)?

Hiding Alyx’s spectator window had no measurable performance difference in a desktop systems. Steam’s VR View did!

Steam’s ’VR View did increase GPU time as you can see in the following gif:

GPU time when steam’s VR View is shown or hidden

When Steam’s VR view was visible, the GPU time graph exhibited some spikes. They increased the GPU time by 1,0 to 1,5 ms. This applies to other games as well.

TLDR

Here’s what you need to do to get a sharper image (higher fidelity level) in Alyx:

  • Disable Steam VR’s “motion smoothing”
  • Set the headset’s refresh rate to 80Hz or 90Hz instead of 120Hz. The lower the refresh rate, the longer the GPU time window and thus the higher the fidelity level (resolution) the game will choose.
  • Set Steam VR’s render resolution to 100%. Higher values are not needed for Alyx.
  • Change the graphic options as follows: “characters” to “low”, “fog” to “low” or “medium”, “shadow” to “medium” or “high”
  • Minimize the spectator window if you’re using a laptop and close Steam’s VR View window (if open).

To check out the frame times while in VR, or even from the desktop, check out fpsVR.

--

--