Hey, I’ve been looking into Virtual Shadow Map performance settings, specifically MaxPhysicalPages and ResolutionLODBiasDirectional. From what I understand, both have a significant impact on visual quality and performance.
After seeing the Witcher 4 demo, I’m very curious about what an optimal setup for these parameters might look like. If possible, I’d love to know how the Witcher 4 demo is handling Virtual Shadow Maps in this regard, or if there are any insights you can share about their configuration or general approach
[Attachment Removed]
Hi Max,
You are correct that MaxPhysicalPages and ResolutionLODBiasDirectional have a significant impact on game performance. However, since these settings are heavily dependent on your scene, it doesn’t make much sense to give you the exact numbers for the Witcher demo. Instead, let me give you a general overview of how to tweak these settings for your title, and we can discuss any follow-ups later.
MaxPhysicalPages: The maximum number of physical shadow pages available in the VSM physical page pool for the frame. It sets the capacity of the pool where actual shadow texels are stored and reused. This value is set during VSM initialization from a console variable and used to size several textures and buffers:
- FVirtualShadowMapArray::Initialize computes UniformParameters.MaxPhysicalPages from CVarMaxPhysicalPages and the physical pool dimensions, and then resizes the physical pool via the cache manager. If size or configuration flags change, the pool is recreated, and cached pages are dropped.
- Drives how many threads/workgroups are dispatched in several VSM management passes, meaning it directly impacts GPU work:
- UpdatePhysicalPageAddresses, UpdatePhysicalPages, SelectPagesToInitialize, SelectPagesToMerge, SelectPagesForHZB, etc., all dispatch a workload based on GetMaxPhysicalPages;
- Feeds the per-frame lists of LRU/AVAILABLE/EMPTY/REQUESTED pages, and clearing/initialization logic.
Practical impact:
- Higher MaxPhysicalPages increases the total physical memory footprint of the VSM pool and HZB metadata, and increases the amount of per-page compute performed every frame (more counters, more passes iterate over pages).
- Too low a value causes frequent page contention and thrashing (pages constantly evicted/allocated), causing more re-rendering of shadow pages and stalls; too high a value costs VRAM and compute time to manage a bigger pool, and may rebuild the pool (dropping cache) when you change it.
ResolutionLODBiasDirectional: A resolution bias applied to directional light clipmap level selection, effectively making directional shadow clipmaps render at higher or lower resolutions. Negative bias “zooms in” (higher resolution; more pages), positive bias “zooms out” (lower resolution; fewer pages).
- It’s stored in ProjectionData and consumed for tracing a directional light source:
- TraceDirectional computes the dither scale and ray sampling, partly based on ProjectionData.ResolutionLodBias (VirtualShadowMapProjectionDirectional.ush; it uses ProjectionData.TexelDitherScale and ResolutionLodBias to scale per-light dithering and page/clipmap sampling).
- There’s a compute path that can push extra resolution bias to projection data at runtime:
- ApplyResolutionLODBias in VirtualShadowMapThrottle.usf, which loads/stores VSM_PSD_OFFSET_RESOLUTION_LOD_BIAS in ProjectionData (shows how the engine can throttle/adjust bias dynamically when needed).
Practical impact:
- More negative ResolutionLODBiasDirectional (e.g., -1.0) increases directional shadow resolution (more shadow detail, more pages mapped/requested, higher cost).
- More positive bias (e.g., 1.0) reduces resolution (fewer pages; cheaper; more aliasing).
- Separate moving bias lets you use a cheaper resolution when the sun/light is considered moving (to avoid expensive re-render), transitioning smoothly back to the non-moving bias based on r.Shadow.Scene.LightActiveFrameCount
[Attachment Removed]