Mobile Multi-View: GPU culling runs on the primary view only, so geometry outside the left eye frustum is missing from the right eye

Summary

On a standalone Quest 3 build, geometry disappears near the outer edge of the right eye while it stays visible in the left one. Landscape tiles and instanced meshes (trees) go separately, each through its own culling path, and each comes back when that path is switched off at runtime.

The engine is an installed 5.7.4, CL 51494982. The project renders with Vulkan, Mobile HDR off, vr.MobileMultiView=1, r.Mobile.SupportGPUScene=1, OpenXR (OculusXR and OculusVR plugins disabled). The device log reports bInstancedStereoEnabled = 0 and bMobileMultiViewNative = 1.

Two paths are involved, both traced in the installed engine sources:

  1. Landscape tile culling. FLandscapeCulling::DispatchCulling (Runtime/Landscape/Private/LandscapeCulling.cpp:665-699) uploads ViewToClip and TranslatedWorldToClip per view, and LandscapeCulling.usf tests each 4x4 quad tile against that single frustum with BoxCullFrustum. In single pass stereo only the primary view computes visibility and mesh draw commands (Runtime/Renderer/Private/SceneVisibility.cpp:4427, with the secondary view receiving copies at :2340-2352), and the tile draw arguments are fetched for the view that built the commands (MeshDrawCommands.cpp:772-776 into LandscapeCulling.cpp:829-856). The multi view draw then writes the left eye tile list into both layers.

  2. GPU instance culling. FSceneView::IsInstancedStereoPass requires bIsInstancedStereoEnabled (Runtime/Engine/Private/SceneView.cpp:2494-2497), which native multi view does not set, so the mobile base pass builds the instance culling context with the primary view alone and never reaches the Stereo mode that adds the second view (Runtime/Renderer/Private/MobileShadingRenderer.cpp:421-429). Only that Stereo mode keeps an instance visible when either view sees it (Shaders/Private/InstanceCulling/BuildInstanceDrawCommands.usf:299-305).

Because each Quest eye has a wider outer than inner FOV, the band along the outer edge of the right eye is outside the left frustum, which is exactly where the geometry is missing.

What Type of Bug are you experiencing?

Rendering (Graphics / Niagara)

Steps to Reproduce

  1. Package a Development Android build of a scene with a Landscape (section size 63 quads, so tile culling is active) and an instanced forest, then run it on a Quest 3.
  2. Look towards the outer (right) edge of the right eye and close the left eye. Ground tiles and trees are missing there while both are present in the left eye.
  3. With the game running, send landscape.EnableGPUCulling 0 over adb (adb shell "am broadcast -a android.intent.action.RUN -e cmd 'landscape.EnableGPUCulling 0'"). The ground tiles come back. Returning the value to 1 makes them disappear again.
  4. With ground culling off, send r.CullInstances 0. The trees come back, and return to 1 makes them disappear again.

Expected Result

Under Mobile Multi-View, culling keeps anything visible to either eye, as the instanced stereo Stereo path already does.

Observed Result

Culling decides on the primary view, and the multi view draw sends that decision to both eyes, so the right eye loses the band its own frustum covers.

Affects Versions

5.7

Platform(s)

OpenXR

Upload an image

Additional Notes

Quest 3, Android 14, OpenXR, Vulkan, Mobile Multi-View native, instanced stereo reported off. Installed UE 5.7.4, CL 51494982. Related: UE-314601 (marked Fixed, Target Fix 5.7, Fix Commit 46646528) describes the same symptom for the packaged VR Template; both paths above still cull on one view in 5.7.4.