Skip to content

geotiff: gds chunked gpu path bool-band reject + LERC masked_fill (#1896)#1900

Merged
brendancol merged 2 commits into
mainfrom
issue-1896
May 15, 2026
Merged

geotiff: gds chunked gpu path bool-band reject + LERC masked_fill (#1896)#1900
brendancol merged 2 commits into
mainfrom
issue-1896

Conversation

@brendancol
Copy link
Copy Markdown
Contributor

Summary

Two parity gaps between the GDS chunked GPU read path and the eager GPU path in xrspatial/geotiff/_backends/gpu.py.

  1. _read_geotiff_gpu_chunked_gds validated band with a numeric range check only. Since isinstance(True, int) is True, band=True passed True < n_bands_out and silently picked band 1. Match the eager path (geotiff: non-VRT read paths accept band=True / band=False #1786) and the dask path by rejecting bool/np.bool_ first.
  2. _decode_window_gpu_direct called gpu_decode_tiles_from_file and gpu_decode_tiles without forwarding masked_fill. On a LERC file with a per-pixel valid mask, that left invalid pixels at LERC's zero fill instead of the nodata sentinel. Resolve masked_fill once for compression == COMPRESSION_LERC (same as the eager path) and thread it through both kernels.

Closes #1896.

Test plan

  • test_gds_chunked_band_{true,false,np_bool}_rejected raises ValueError.
  • test_gds_chunked_band_int_still_works -- band=1 selects band 1.
  • test_gds_chunked_lerc_mask_matches_eager -- NaN nodata + per-pixel mask, chunked output equals eager output, NaN at masked positions.
  • test_gds_chunked_lerc_mask_sentinel_nodata -- same with -9999 sentinel.

Refs #1813, #1895, #1786.

Mirror two parity gaps from the eager GPU path into the GDS chunked
GPU read path:

- Reject band=True/np.bool_(True) up front in
  _read_geotiff_gpu_chunked_gds before the numeric range check.
  Without it, isinstance(True, int) causes True < n_bands_out
  to silently select band 1.
- Resolve masked_fill once for LERC files and forward it through
  _decode_window_gpu_direct to both gpu_decode_tiles_from_file
  and gpu_decode_tiles. Without it, LERC files with a per-pixel
  valid mask read back at LERC's zero fill instead of the nodata
  sentinel on the chunked path.
Pin the two regressions the fix in 54ab604 closes:

- _read_geotiff_gpu_chunked_gds rejects band=True,
  band=False, and band=np.bool_(True) while still accepting a
  plain int band.
- _decode_window_gpu_direct forwards masked_fill so a LERC file
  with a per-pixel valid mask round-trips through the chunked path
  with the same NaN-on-invalid-pixel behaviour as the eager GPU path
  (both for NaN and sentinel nodata).
Copilot AI review requested due to automatic review settings May 15, 2026 05:04
@github-actions github-actions Bot added the performance PR touches performance-sensitive code label May 15, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR closes parity gaps in the GeoTIFF GPU backend’s GDS chunked read path so it matches the eager GPU path behavior for (1) invalid band inputs and (2) LERC valid-mask handling.

Changes:

  • Reject band when it is bool / np.bool_ in _read_geotiff_gpu_chunked_gds (matching other backends).
  • Resolve and forward LERC masked_fill through _decode_window_gpu_direct into both GPU tile decode entry points.
  • Add regression tests covering bool-band rejection and LERC mask parity between eager and GDS chunked paths.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
xrspatial/geotiff/_backends/gpu.py Threads masked_fill into GDS chunk decode and adds explicit bool/np.bool_ rejection for band.
xrspatial/geotiff/tests/test_gds_chunked_gpu_parity_1896.py New regression tests for bool-band rejection and LERC masked-fill parity (eager vs GDS chunked).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +163 to +171
lerc = pytest.importorskip("lerc")

from xrspatial.geotiff._compression import LERC_AVAILABLE # noqa: E402


_lerc_gpu_only = pytest.mark.skipif(
not (_HAS_GPU and LERC_AVAILABLE),
reason="cupy + CUDA + lerc required",
)
@brendancol brendancol merged commit c331d02 into main May 15, 2026
16 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

performance PR touches performance-sensitive code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

geotiff: GDS chunked GPU path missing bool-band rejection and LERC masked_fill

2 participants