Skip to content

Instantly share code, notes, and snippets.

@maluoi
Last active April 7, 2026 17:21
Show Gist options
  • Select an option

  • Save maluoi/4ea99fc6a4b32b69369a7e12acdf203b to your computer and use it in GitHub Desktop.

Select an option

Save maluoi/4ea99fc6a4b32b69369a7e12acdf203b to your computer and use it in GitHub Desktop.
Scaling resolution dynamically in a StereoKit app based on GPU timing
//////////////////////
// Dynamic Performance Scaling
static float perfGpuSmoothed = 0;
static float perfCurrentScale = 0;
/// <summary>Dynamically adjusts Renderer.ViewportScaling based on GPU
/// performance relative to the display's refresh rate budget. Call this
/// each frame to maintain smooth performance.</summary>
/// <param name="targetUtilization">Fraction of the GPU frame budget to
/// target, default 0.85 (85%).</param>
/// <param name="minScale">Minimum viewport scale, default 0.5.</param>
/// <param name="maxScale">Maximum viewport scale, default 1.0.</param>
/// <param name="smoothing">EMA smoothing factor for GPU time, lower is
/// smoother. Default 0.05.</param>
/// <param name="deadZone">Ratio dead zone where no adjustment is made,
/// default 0.05 (5%).</param>
/// <param name="adjustRateUp">How fast the scale increases when under
/// budget, default 0.02 (2% per frame).</param>
/// <param name="adjustRateDown">How fast the scale decreases when over
/// budget, default 0.1 (10% per frame).</param>
static void AutoScalePerformance(
float targetUtilization = 0.9f,
float minScale = 0.5f,
float maxScale = 1.0f,
float smoothing = 0.05f,
float deadZone = 0.05f,
float adjustRateUp = 0.02f,
float adjustRateDown = 0.8f)
{
float gpuUs = Time.PerfGPUus;
if (gpuUs <= 0 || Device.DisplayRefreshRate <= 0) return;
// Initialize from current state on first call
if (perfCurrentScale <= 0)
perfCurrentScale = Renderer.ViewportScaling;
float budgetUs = 1_000_000f / Device.DisplayRefreshRate;
float targetUs = budgetUs * targetUtilization;
// Smooth GPU time with exponential moving average
perfGpuSmoothed = perfGpuSmoothed <= 0
? gpuUs
: perfGpuSmoothed + (gpuUs - perfGpuSmoothed) * smoothing;
// If we're close to our target, don't adjust
float ratio = targetUs / perfGpuSmoothed;
if (Math.Abs(ratio - 1.0f) < deadZone) return;
// Calculate the ideal scale and move toward it gradually,
// scaling down faster than up to avoid dropped frames.
float idealScale = Math.Clamp(perfCurrentScale * ratio, minScale, maxScale);
float rate = idealScale < perfCurrentScale
? adjustRateDown
: adjustRateUp;
perfCurrentScale += (idealScale - perfCurrentScale) * rate;
perfCurrentScale = Math.Clamp(perfCurrentScale, minScale, maxScale);
Renderer.ViewportScaling = perfCurrentScale;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment