GPU page fault / device lost when zooming the map onto Jupiter (DistantSphere shader reads bindless index -1)

Lt Cal

New Member
Messages
8
Reaction score
6
Game Version v2026.10.19.5638 (Linux build), unmodded (only Core enabled), stock Sol system

Operating System Linux: Ubuntu 26.04, kernel 7.0.0-38-generic, Mesa RADV 26.0.8, AMD Radeon RX 6600 (Navi 23 / gfx1032, 8 GB)

What Happened When I zoom the map camera in on Jupiter, the game freezes for about 2 seconds and then the GPU faults and resets (VK_ERROR_DEVICE_LOST). On this machine the reset often takes the whole desktop session down with it. The same thing happens at gas giants in a modded system, so it isn't specific to Jupiter's assets.

I think I've found the cause. DistantSphereRenderer sets _material.HeightTextureId = -1 for bodies with no cubemap height map, which is every gas giant. The DistantSphere vertex shader still indexes the bindless cube array with that value, unconditionally. -1 << 6 turns the descriptor address into one far outside the bindless table, and the scalar load page-faults. It only happens while the planet is drawn as a distant sphere, the screen-size band between the sprite and the full terrain renderer, which is why it shows up while zooming toward the planet. Other drivers may tolerate the bad read, which may be why it isn't reported more widely.

What Was Expected Zooming in on a gas giant renders it normally, as it does for rocky planets.

Reproduction Steps
  1. Load a Sol save (or start a new game) in Earth orbit.
  2. Open map view and zoom out.
  3. Move the map camera to Jupiter and zoom in until its moons start to show.
  4. The game hangs for about 2 seconds, then the GPU resets.
Reproduction Rate Always (about 10 out of 10 attempts, same faulting address every time)

Additional Info
  • Video/Screenshots: none (the crash takes the display down)
  • Save File: not needed, a new game reproduces it
  • Other Notes:
Kernel log at the fault, a scalar (SQC) data load from the same bogus address every time:

amdgpu 0000:03:00.0: [gfxhub] page fault (src_id:0 ring:24 vmid:N pasid:N)
amdgpu 0000:03:00.0: in page starting at address 0x000080010001f000 from client 0x1b (UTCL2)
amdgpu 0000:03:00.0: GCVM_L2_PROTECTION_FAULT_STATUS:0x00701431
amdgpu 0000:03:00.0: Faulty UTCL2 client ID: SQC (data) (0xa)
amdgpu 0000:03:00.0: PERMISSION_FAULTS: 0x3
amdgpu 0000:03:00.0: ring gfx_0.0.0 timeout ... GPU reset begin!

Game log: vkQueueSubmit failed with error: VK_ERROR_DEVICE_LOST from Program.PostRender, followed by vkDeviceWaitIdle DEVICE_LOST in Program.Dispose.

RADV hang dump (RADV_DEBUG=hang): the fault is "VA not found", and the active pipeline is the DistantSphere vertex shader, which does this with no branch around it:
%47 = @load_ubo (%37, 0x20) // material offset 0x20: HeightTextureId, SamplerClampId
%49 = ishl.nuw %47.x, 6 // index * 64-byte descriptor
%50 = @load_global_amd (%45, %49) // bindless cube descriptor load <- faults
%55 = txl %50 ... (cube) // height sample for vertex displacement

Suggested fix, either of these:
  • Bind TextureReference.EmptyCubemap with a zero height range instead of -1. The renderer already does this for a missing Diffuse.
  • Guard the height sample in the shader with HeightTextureId >= 0.
Workaround mod (Harmony prefix on DistantSphereRenderer.Render):
C#
static readonly AccessTools.FieldRef<DistantSphereRenderer, DistantSphereMaterialData> Material =
    AccessTools.FieldRefAccess<DistantSphereRenderer, DistantSphereMaterialData>("_material");



static void BeforeRender(DistantSphereRenderer __instance)
{
    ref DistantSphereMaterialData m = ref Material(__instance);
    if (m.HeightTextureId >= 0)
        return;
    m.HeightTextureId = TextureReference.EmptyCubemap.BindlessHandle;
    m.MinHeight = 0f;
    m.MaxHeight = 0f;
}
 
Upvote 0
Back
Top