Skip to content

Interpolated texture tile sizes can truncate and cause water/lava jitter #1119

Description

@banteg

Linked Shipwright report: HarbourMasters/Shipwright#6666

I investigated the Shipwright water/lava texture animation jitter locally and the repro points at LUS-side tile-size derivation rather than frame pacing or skipped interpolation.

In the Fire Temple lava case, the interpolation replay cycle stayed regular (0 -> 1 -> 2 -> 0 ...), but one replay phase derived a different rendered texture window size from the interpolated tile coordinates.

Bad phase example:

replay=1
tile0=(0.000,6.333,124.000,130.333)
renderSize0=(32, 31)
texSize0=(32, 31)

Adjacent phases for the same lava surface stayed 32x32:

replay=0 tile0=(0.000,6.000,124.000,130.000) renderSize0=(32, 32)
replay=2 tile0=(0.000,6.667,124.000,130.667) renderSize0=(32, 32)

So the visual jitter appears to come from alternating between a 32x32 and 32x31 texture window. The intended height is still 32 texels, but the current conversion effectively truncates (lrt - ult + 4) / 4 after interpolation. With interpolated float values like 6.333 and 130.333, precision can land just below 32.0, and the cast becomes 31.

The conversions I found are in src/fast/interpreter.cpp, in the code paths that derive rendered/imported tile dimensions from uls/ult/lrs/lrt, including:

  • ImportTextureRgba16
  • ImportTextureRgba32
  • ImportTextureCi4
  • ImportTextureCi8
  • GfxSpTri1

A minimal local fix that made the lava case stable was to round the derived texel count instead of truncating it:

static uint32_t GetTileSizeFromCoordinates(float low, float high) {
    float size = (high - low + 4.0f) / 4.0f;
    if (size <= 0.0f) {
        return 0;
    }
    return static_cast<uint32_t>(lroundf(size));
}

Then use that helper instead of directly casting (high - low + 4) / 4 to uint32_t/int32_t in those tile-size calculations.

I tested this locally in Shipwright; the lava scene stopped visibly alternating between good and bad texture phases. The local soh target built successfully after the change. I did not need to change interpolation scheduling or texture cache behavior for this specific symptom.

Additional Shipwright-side diagnostic comment: HarbourMasters/Shipwright#6666 (comment)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions