Skip to content

GGGS shader: discard by per-band NoData (not v<=0) + Nearest data sampling (#122)#133

Merged
rolker merged 12 commits into
jazzyfrom
feature/issue-122
Jun 28, 2026
Merged

GGGS shader: discard by per-band NoData (not v<=0) + Nearest data sampling (#122)#133
rolker merged 12 commits into
jazzyfrom
feature/issue-122

Conversation

@rolker

@rolker rolker commented Jun 28, 2026

Copy link
Copy Markdown
Owner

Summary

The GGGS raster fragment shader discarded every sample with v <= 0.0 and auto-ranged
over the rest — correct for depth band 1 (mosaicker floors returns to >= 1, reserves 0
for NoData), but wrong for the other bands the #108 picker now exposes (uncertainty,
quality, signed offsets): valid zero/negative samples were silently discarded and the
colormap range computed only over positives.

This makes the shader honor the band's actual NoData value instead of a hardcoded
sign test. The CPU side already re-queried per-band NoData (GggsTile::loadPixels); this
closes the gap on the GPU side.

Closes #122.

Changes

  • Shader (gggs_tile_layer.cpp): added u_has_nodata (int) + u_nodata (float)
    uniforms; replaced if(v <= 0.0) discard; with if(u_has_nodata != 0 && v == u_nodata) discard;. Uniforms set per-tile inside the render loop (NoData can differ per
    tile/band); u_min/u_max stay layer-global (shared colormap range). Removed the stale
    [camp#108] LIMITATION comment that pointed here.
  • Nearest sampling (gggs_tile.cpp): the R32F data texture min/mag filter switched
    Linear → Nearest. For real survey data viewed for quality assessment, faithful
    cell-accurate values matter more than smoothness — interpolation fabricates values not in
    the data (and produced a bright one-texel halo around NoData regions, since interpolated
    boundary texels never equal the sentinel). The colormap LUT texture stays Linear (it's
    a color ramp, not data). On-screen blit smoothing (SmoothPixmapTransform) for data
    layers is a separate, operator-selectable follow-up: Operator-selectable interpolation for data layers (Nearest default; A/B on real data) #132.
  • Float-consistent NoData compare (gggs_tile.cpp): the CPU range exclusion now
    compares in float to match the shader's float discard.

Tests

./ui_ws/test.sh camp124 tests, 0 failures, 4 skipped (the skips are offscreen-GL
render tests that SKIP-not-FAIL where no GL is available):

  • test_gggs_tile.cppNegativeValidSamplesNonZeroNoData (Float32 tile, NoData=9999,
    samples [-3, 0, -1.5, 9999]): range covers the negatives, NoData excluded. Runs.
  • test_gggs_render.cppNoDataDiscardHonorsUniform: asserts a valid 0.0 region renders
    opaque (only the new code does; the old v<=0 discards it) and the NoData block renders
    transparent. Designed to fail if the discard is reverted to v<=0. GL-gated (SKIPs
    in-container; a GL host confirms fail-on-revert).

Review

Driven via /run-issue; 3 rounds of pre-push review-code (Round 1 caught that the render
test didn't discriminate the fix). Final: approved, 0 must-fix, 0 suggestions.

Follow-up


Authored-By: Claude Code Agent
Model: Claude Opus 4.8 (1M context)

Claude Code Agent and others added 12 commits June 28, 2026 15:41
Replace shader's hardcoded v<=0.0 discard with per-tile NoData uniform
The GGGS fragment shader discarded every sample with v<=0.0, a convention
valid only for the depth/sidescan band 1 (the mosaicker floors real returns
to >=1 and reserves 0 for NoData). After #108 enabled arbitrary band
selection, bands with legitimately zero or negative valid samples
(uncertainty, quality, signed offsets) were mis-rendered: valid <=0 samples
were silently discarded and the colormap range was computed over the positive
subset only.

Add u_has_nodata (int, for GLSL 1.20 portability) and u_nodata (float)
uniforms; replace the discard with 'if(u_has_nodata != 0 && v == u_nodata)
discard'. The uniforms are set per-tile inside the render loop (after
texture->bind(0)) from tile->hasNoData()/tile->noData(); tiles without NoData
discard nothing.

Asymmetry note: u_min/u_max stay layer-global (set once outside the loop from
data_min_/data_max_) because the colormap range is shared across tiles, while
the NoData uniform is per-tile because NoData can differ per tile/band. This
asymmetry is intentional.

Remove the stale [camp#108] LIMITATION comment that referenced this follow-up.

Tests: add a Float32 GggsTile range test (negative valid samples + non-zero
NoData) that RUNS, and an offscreen render test pinning the discard path that
SKIPS when offscreen GL is unavailable.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings June 28, 2026 17:15

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@rolker rolker merged commit 6598471 into jazzy Jun 28, 2026
1 check failed
@rolker rolker deleted the feature/issue-122 branch June 28, 2026 17:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

GGGS shader v<=0 discard mis-ranges signed/uncertainty bands selectable since #108

2 participants