Ground fog kept when looking down (texel writes made before the renderer starts are no longer dropped) #638

Merged
hckrman101 merged 1 commit from fog-early-texels into main 2026-11-08 15:37:03 +00:00
hckrman101 commented 2026-11-08 15:19:33 +00:00 (Migrated from github.com)

The ground fog vanishes while the camera looks down a little (and stays that way while the camera holds still), and comes back when the camera passes level or looks straight down. Only windowed starts are affected; headless runs never show it.

Cause. During boot the game fills a few textures with nvnTextureWriteTexels. In a windowed start the window's thread starts the renderer after the game has begun, so rx_nvn_write_texels has no renderer yet and falls through to the WebGPU stand-in, which on Linux (and in builds without wgpu-native) does nothing. Those textures keep zeros in their storage. (Headless starts the renderer first, which is why it never reproduces there.)

One of them is OoT's 4x4 white placeholder texture. At some camera angles the game skips the fog layer's depth pass and binds that placeholder as t3 of the ground fog composite in its place. The composite reads t3 as a depth limit: 1.0 means "no limit" and the half-resolution fog clouds are applied; 0 masks them out everywhere. With the placeholder left at 0, the ground fog disappears.

Evidence from frame dumps:

  • the fog cloud buffer is drawn the same in both states; only the composite output loses it;
  • the composite's sampled placeholder texture: mean 0 0 0 0 before, 1 1 1 1 with this change;
  • the placeholder's guest memory is 0x00 in windowed runs and 0xFF headless.

Change (host/rx_backend.c). WriteTexels calls made before the renderer starts are kept, like the texture and sampler registrations already are: each keeps a copy of its data (the exact byte span from the region, strides and format) and is given to the renderer in order when it starts. In a windowed start the log now shows rx: 123 texture and sampler calls made before the renderer started (33 texel writes), given to it, so 33 boot texel writes were being dropped before.

Tested (Linux, windowed, live stick input):

  • Before: a short right-stick-down tap, then the camera held still: ground fog gone for 2+ seconds, and again on a second tap.
  • After: level, two down taps, then up past level to the sky: fog present at every angle.
  • The game boots and plays normally. Headless never takes this path.
  • Lichii at a similar pitch keeps the ground fog wisps where unfixed Hookshot shows none.

Not covered:

  • ReadTexels before the renderer starts still goes to the stand-in; nothing seemed to rely on it.
  • The other early texel writes now reach the renderer too; I didn't survey which textures they are, but nothing looked different.
  • Looking up, the sky turns bright white; that is the same with and without this change, and may be a separate issue.

Before / after (Kokiri Forest, windowed). Top: without this change, camera level (fog) and then looking down a little (ground fog gone). Bottom: with it, level and looking down (ground fog kept).

fog before and after

The ground fog vanishes while the camera looks down a little (and stays that way while the camera holds still), and comes back when the camera passes level or looks straight down. Only windowed starts are affected; headless runs never show it. **Cause.** During boot the game fills a few textures with `nvnTextureWriteTexels`. In a windowed start the window's thread starts the renderer after the game has begun, so `rx_nvn_write_texels` has no renderer yet and falls through to the WebGPU stand-in, which on Linux (and in builds without wgpu-native) does nothing. Those textures keep zeros in their storage. (Headless starts the renderer first, which is why it never reproduces there.) One of them is OoT's 4x4 white placeholder texture. At some camera angles the game skips the fog layer's depth pass and binds that placeholder as t3 of the ground fog composite in its place. The composite reads t3 as a depth limit: 1.0 means "no limit" and the half-resolution fog clouds are applied; 0 masks them out everywhere. With the placeholder left at 0, the ground fog disappears. Evidence from frame dumps: - the fog cloud buffer is drawn the same in both states; only the composite output loses it; - the composite's sampled placeholder texture: mean 0 0 0 0 before, 1 1 1 1 with this change; - the placeholder's guest memory is 0x00 in windowed runs and 0xFF headless. **Change** (`host/rx_backend.c`). WriteTexels calls made before the renderer starts are kept, like the texture and sampler registrations already are: each keeps a copy of its data (the exact byte span from the region, strides and format) and is given to the renderer in order when it starts. In a windowed start the log now shows `rx: 123 texture and sampler calls made before the renderer started (33 texel writes), given to it`, so 33 boot texel writes were being dropped before. **Tested** (Linux, windowed, live stick input): - Before: a short right-stick-down tap, then the camera held still: ground fog gone for 2+ seconds, and again on a second tap. - After: level, two down taps, then up past level to the sky: fog present at every angle. - The game boots and plays normally. Headless never takes this path. - Lichii at a similar pitch keeps the ground fog wisps where unfixed Hookshot shows none. **Not covered:** - `ReadTexels` before the renderer starts still goes to the stand-in; nothing seemed to rely on it. - The other early texel writes now reach the renderer too; I didn't survey which textures they are, but nothing looked different. - Looking up, the sky turns bright white; that is the same with and without this change, and may be a separate issue. **Before / after** (Kokiri Forest, windowed). Top: without this change, camera level (fog) and then looking down a little (ground fog gone). Bottom: with it, level and looking down (ground fog kept). ![fog before and after](https://raw.githubusercontent.com/hckrman101/Hookshot/pr-images/fog-638.png)
Commenting is not possible because the repository is archived.
No description provided.