This is an automated email from the ASF dual-hosted git repository. asf-gitbox-commits pushed a commit to branch geoapi-4.0 in repository https://gitbox.apache.org/repos/asf/sis.git
commit f6e6c072f0606b89675cde7bc2cf4bad1e51a4f1 Author: Martin Desruisseaux <[email protected]> AuthorDate: Mon Aug 10 12:41:22 2026 +0200 Add a "todo" note about the use of `prefetch` in context of artificially tiled image. Minor edition as a side-effect of the review of the situation regarding prefetch. --- .../org/apache/sis/image/BandedSampleConverter.java | 6 +++--- .../main/org/apache/sis/image/ComputedImage.java | 4 ++-- .../main/org/apache/sis/image/ImageOverlay.java | 2 +- .../org/apache/sis/image/MultiSourcePrefetch.java | 5 +++-- .../main/org/apache/sis/image/PlanarImage.java | 2 ++ .../main/org/apache/sis/image/PrefetchedImage.java | 4 ++-- .../org/apache/sis/image/SourceAlignedImage.java | 2 +- .../image/internal/shared/BatchComputedImage.java | 21 +++++++++++++++++++-- .../sis/storage/tiling/ArtificiallyTiledImage.java | 13 ++++++++++--- .../storage/tiling/TiledGridCoverageResource.java | 2 +- 10 files changed, 44 insertions(+), 17 deletions(-) diff --git a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/BandedSampleConverter.java b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/BandedSampleConverter.java index 9cf90055f5..8a4270ad36 100644 --- a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/BandedSampleConverter.java +++ b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/BandedSampleConverter.java @@ -454,10 +454,10 @@ class BandedSampleConverter extends WritableComputedImage { @Override public void setData(final Raster data) { final Rectangle bounds = data.getBounds(); - final WritableRenderedImage target = (WritableRenderedImage) getSource(); + final var target = (WritableRenderedImage) getSource(); ImageUtilities.clipBounds(target, bounds); if (!bounds.isEmpty()) { - final TileOpExecutor executor = new TileOpExecutor(target, bounds) { + final var executor = new TileOpExecutor(target, bounds) { @Override protected void writeTo(final WritableRaster target) throws TransformException { final Rectangle aoi = target.getBounds().intersection(bounds); Transferer.create(data, target, aoi).compute(inverses); @@ -506,7 +506,7 @@ class BandedSampleConverter extends WritableComputedImage { @Override public boolean equals(final Object object) { if (equalsBase(object)) { - final BandedSampleConverter other = (BandedSampleConverter) object; + final var other = (BandedSampleConverter) object; return Arrays .equals(converters, other.converters) && Objects.equals(colorModel, other.colorModel) && Arrays .equals(sampleResolutions, other.sampleResolutions); diff --git a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/ComputedImage.java b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/ComputedImage.java index 7d6ec91caa..986e9b6e98 100644 --- a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/ComputedImage.java +++ b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/ComputedImage.java @@ -593,9 +593,9 @@ public abstract class ComputedImage extends PlanarImage implements Disposable { } /** - * Notifies this image that tiles will be computed soon in the given region. + * Notifies this image that tiles will be computed soon for the given tile indices. * This method is invoked by {@link ImageProcessor#prefetch(RenderedImage, Rectangle)} - * before to request (potentially in multi-threads) all tiles in the area of interest. + * before to request (potentially in multi-threads) tiles at the specified indices. * If the returned {@code Disposable} is non-null, {@code ImageProcessor} guarantees * that the {@link Disposable#dispose()} method will be invoked after the prefetch * operation completed, successfully or not. diff --git a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/ImageOverlay.java b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/ImageOverlay.java index 3c7253e944..29b718e84e 100644 --- a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/ImageOverlay.java +++ b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/ImageOverlay.java @@ -399,7 +399,7 @@ final class ImageOverlay extends MultiSourceImage { */ @Override protected Raster computeTile(final int tileX, final int tileY, WritableRaster target) { - final Rectangle aoi = new Rectangle( + final var aoi = new Rectangle( ImageUtilities.tileToPixelX(this, tileX), ImageUtilities.tileToPixelY(this, tileY), getTileWidth(), diff --git a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/MultiSourcePrefetch.java b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/MultiSourcePrefetch.java index 7f1452b754..d0aa7605bf 100644 --- a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/MultiSourcePrefetch.java +++ b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/MultiSourcePrefetch.java @@ -29,7 +29,7 @@ import org.apache.sis.image.internal.shared.ImageUtilities; /** * A helper class for forwarding a {@code prefetch(…)} operation to multiple sources. * This implementation assumes that all sources share the same pixel coordinates space. - * However the tile matrix does not need to be the same. + * However, the tile matrix does not need to be the same. * * @author Martin Desruisseaux (Geomatys) */ @@ -102,12 +102,13 @@ final class MultiSourcePrefetch implements Disposable { * @param parallel whether parallelism is allowed. * @return a handler for disposing resources after prefetch, or {@code null} if none. */ + @SuppressWarnings("UseSpecificCatch") final Disposable run(boolean parallel) { switch (count) { case 0: return null; case 1: parallel = false; } - @SuppressWarnings({"unchecked","rawtypes"}) + @SuppressWarnings({"unchecked", "rawtypes"}) final var workers = (Future<Disposable>[]) (parallel ? new Future[count] : null); cleaners = new Disposable[count]; for (int i=0; i<count; i++) { diff --git a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/PlanarImage.java b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/PlanarImage.java index 4cadfc431d..8c32509269 100644 --- a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/PlanarImage.java +++ b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/PlanarImage.java @@ -25,6 +25,7 @@ import java.awt.image.Raster; import java.awt.image.WritableRaster; import java.awt.image.WritableRenderedImage; import java.awt.image.RenderedImage; +import java.awt.image.ImagingOpException; import java.util.Objects; import java.util.Vector; import java.util.function.DoubleUnaryOperator; @@ -633,6 +634,7 @@ public abstract class PlanarImage implements RenderedImage { * @param tiles indices of the tiles which will be prefetched. * @return handler on which to invoke {@code dispose()} after the prefetch operation * completed (successfully or not), or {@code null} if none. + * @throws ImagingOpException if an error occurred while preparing tile computation. */ Disposable prefetch(Rectangle tiles) { return null; diff --git a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/PrefetchedImage.java b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/PrefetchedImage.java index ee5ac4274e..b8b05b7b10 100644 --- a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/PrefetchedImage.java +++ b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/PrefetchedImage.java @@ -35,7 +35,7 @@ import org.apache.sis.util.resources.Errors; /** - * An image which delegate all tile requests to another image except for some tiles that are fetched in advance. + * An image which delegates all tile requests to another image except for some tiles that are fetched in advance. * This image has the same coordinate systems as the source image. * * @author Martin Desruisseaux (Geomatys) @@ -108,7 +108,7 @@ final class PrefetchedImage extends PlanarImage implements TileErrorHandler.Exec return; } } - final Worker worker = new Worker(source, areaOfInterest); + final var worker = new Worker(source, areaOfInterest); final Rectangle ti = worker.getTileIndices(); minTileX = ti.x; minTileY = ti.y; diff --git a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/SourceAlignedImage.java b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/SourceAlignedImage.java index 96c778b03d..21265e35e1 100644 --- a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/SourceAlignedImage.java +++ b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/SourceAlignedImage.java @@ -199,7 +199,7 @@ abstract class SourceAlignedImage extends ComputedImage { /** * Notifies the source image that tiles will be computed soon in the given region. * If the source image is an instance of {@link PlanarImage}, then this method - * forwards the notification to it. Otherwise default implementation does nothing. + * forwards the notification to it. Otherwise, the default implementation does nothing. */ @Override protected Disposable prefetch(final Rectangle tiles) { diff --git a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/internal/shared/BatchComputedImage.java b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/internal/shared/BatchComputedImage.java index 07aa6ae592..8b24a29c5c 100644 --- a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/internal/shared/BatchComputedImage.java +++ b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/image/internal/shared/BatchComputedImage.java @@ -38,6 +38,9 @@ import org.apache.sis.util.resources.Errors; * Implementations should manage their own cache for avoiding to compute the same tiles many times. * The caching mechanism inherited from {@link ComputedImage} is less useful here. * + * @todo Consider moving as a public class in {@link org.apache.sis.image.internal} + * for leveraging {@code MultiSourcePrefetch}. + * * @author Martin Desruisseaux (Geomatys) */ public abstract class BatchComputedImage extends ComputedImage { @@ -76,6 +79,13 @@ public abstract class BatchComputedImage extends ComputedImage { this.tiles = tiles; } + /** + * Tests whether this set of tiles contains the given set. + */ + final boolean contains(final Rectangle other) { + return new Rectangle(x, y, width, height).contains(other); + } + /** Discards this set of tiles. */ @Override public void dispose() { remove(this); @@ -179,7 +189,14 @@ public abstract class BatchComputedImage extends ComputedImage { * @throws ImagingOpException if an error occurred while preparing tile computation. */ @Override - protected Disposable prefetch(final Rectangle region) { + public Disposable prefetch(final Rectangle region) { + synchronized (this) { + for (Rasters r = prefetched; r != null; r = r.next) { + if (r.contains(region)) { + return null; // Already prefetched. + } + } + } final Raster[] tiles; try { tiles = computeTiles(region); @@ -188,7 +205,7 @@ public abstract class BatchComputedImage extends ComputedImage { } catch (Exception e) { throw (ImagingOpException) new ImagingOpException(e.getMessage()).initCause(e); } - final Rasters r = new Rasters(region, tiles); + final var r = new Rasters(region, tiles); synchronized (this) { r.next = prefetched; prefetched = r; diff --git a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/tiling/ArtificiallyTiledImage.java b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/tiling/ArtificiallyTiledImage.java index ba659a2afb..1f6ad12f91 100644 --- a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/tiling/ArtificiallyTiledImage.java +++ b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/tiling/ArtificiallyTiledImage.java @@ -152,11 +152,13 @@ final class ArtificiallyTiledImage extends BatchComputedImage { int minTileY = Integer.MAX_VALUE; int maxTileX = Integer.MIN_VALUE; int maxTileY = Integer.MIN_VALUE; + final int tilex0 = tiles.x; // Tile index of the raster at index 0 in the returned array. + final int tileY0 = tiles.y; final int numXTiles = tiles.width; final var rasters = new Raster[Math.multiplyExact(numXTiles, tiles.height)]; for (int i = 0; i < rasters.length; i++) { - final int x = tiles.x + i % numXTiles; - final int y = tiles.y + i / numXTiles; + final int x = tilex0 + i % numXTiles; + final int y = tileY0 + i / numXTiles; if ((rasters[i] = cache.get(new Point(x, y))) == null) { if (x < minTileX) minTileX = x; if (x > maxTileX) maxTileX = x; @@ -195,6 +197,11 @@ final class ArtificiallyTiledImage extends BatchComputedImage { * Then, the requested extent is converted to the coverage grid coordinate system. * Because this is also expected to be an identity operation or at most a translation, * the rounding more is set to `NEAREST` instead of `ENCLOSING`. + * + * TODO: we use `RasterLoadingStrategy.AT_GET_TILE_TIME` because we don't know if we are going + * to use all requested tiles (because the cache in this class may make some reading unnecessary). + * We should do something more advanced, with a mask (potentially made of many rectangles) of the + * tiles that we really need to read. */ final GridGeometry request = domain.relocate(extent.reshape(low, high, true)); final GridCoverage coverage = source.readAtGetTileTime(request, requestedBands); @@ -207,7 +214,7 @@ final class ArtificiallyTiledImage extends BatchComputedImage { for (int y = minTileY; y <= maxTileY; y++) { for (int x = minTileX; x <= maxTileX; x++) { // No integer arithmetic can overflow in this loop. - final int i = (y - tiles.y) * numXTiles + (x - tiles.x); + final int i = (y - tileY0) * numXTiles + (x - tilex0); if (rasters[i] == null) { rasters[i] = cache.computeIfAbsent(new Point(x, y), (key) -> { final int tileWidth = sampleModel.getWidth(); diff --git a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/tiling/TiledGridCoverageResource.java b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/tiling/TiledGridCoverageResource.java index 7d9655bd5a..c5be80aebe 100644 --- a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/tiling/TiledGridCoverageResource.java +++ b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/tiling/TiledGridCoverageResource.java @@ -872,7 +872,7 @@ check: if (dataType.isInteger()) { if (virtualSize / stride > ImageLayout.MAX_TILE_SIZE) { // Tile is too large, even after subsampling. if (i == xDimension || i == yDimension) { - applyArtificialTiling |= !loadAtReadTime; + applyArtificialTiling = !loadAtReadTime; } } virtualTileSize[i] = virtualSize;
