On Wed, 2 Apr 2025 20:12:48 GMT, Nikita Gubarkov <ngubar...@openjdk.org> wrote:
> > is it possible for pixelStride to be smaller than maxBandOff? > > Surprisingly, yes! Band offsets are arbitrary, even for > `PixelInterleavedSampleModel`, the only restriction is that `maxBandOff - > minBandOff <= pixelStride` But isn't it essentially the same thing? It just shifts the "pixelStride" window in one direction or another. > Both could be correct and there doesn't seem to be any other info, which > could allow us to determine this unambiguously. This "real starting pixel > offset" is implicitly assumed, when working with [known types in native > code](https://github.com/openjdk/jdk/blob/209e72d311234c8279289172dab2cbb255e4fed9/src/java.desktop/share/classes/sun/awt/image/BufImgSurfaceData.java#L319), > but is explicitly stored nowhere. It depends on where and when the ColorModel/SampleModel/Raster were created. If the raster was created by our code and we can determine the starting offsets, and if we can confirm that the gaps are safe to read, then we could set some flags. These flags could be recognized by the pipelines to enable fast-path optimizations. Just one example: private static BufferedImage makeCustom3BYTE_BGR() { ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB); int[] nBits = {8, 8, 8}; int[] bOffs = {2, 1, 0}; ColorModel colorModel = new ComponentColorModel(cs, nBits, false, false, Transparency.OPAQUE, DataBuffer.TYPE_BYTE); PixelInterleavedSampleModel sm = new PixelInterleavedSampleModel(DataBuffer.TYPE_BYTE, 2, 1, 400, 4000, bOffs); WritableRaster raster = Raster.createWritableRaster(sm, null); System.out.println("raster.getDataBuffer().getSize() = " + raster.getDataBuffer().getSize()); return new BufferedImage(colorModel, raster, true, null); } BufferedImage bi = new BufferedImage(3000, 3000, TYPE_INT_ARGB); BufferedImage src = makeCustom3BYTE_BGR(); Graphics2D g2d = bi.createGraphics(); g2d.setTransform(new AffineTransform()); g2d.drawImage(src, 0, 0, null); g2d.dispose(); The size of the image is "403", meaning it does not include the gap after the last pixel data. Now, if we attempt to blit this into various pipelines, we may encounter different slow/fast paths: - CMM code will bail out since such formats are not supported. - OGL/Metal code [supports](https://github.com/openjdk/jdk/blob/b01026abaab0b65f9ec0920d66a8ff1fa868d351/src/java.desktop/share/native/common/java2d/opengl/OGLBlitLoops.c#L409C40-L409C51) gaps in scanlines but does not support gaps between pixels. As a result, the slow path will be used via an intermediate ARGB_PRE surface. - Native loops will also bail out, falling back to the most [generic java implementation](https://github.com/openjdk/jdk/blob/b01026abaab0b65f9ec0920d66a8ff1fa868d351/src/java.desktop/share/classes/sun/java2d/loops/CustomComponent.java#L144). In this particular case, we can probably optimize the handling, but how should we deal with similar random rasters we might encounter? getDataElements/setDataElements is the only solution similar to OpaqueCopyArgbToAny? >But what if our last pixel also contains padding, which is not resident? Then >we would have to repeat the [same >procedure](https://github.com/openjdk/jdk/blob/130b0cdaa6604da47a893e5425547acf3d5253f4/src/java.desktop/share/classes/java/awt/image/ComponentSampleModel.java#L247) > with finding the last used component and so on. Yes, that is how it is usually implemented. When creating a surface, image, or raster, validation is performed, and specific flags are set(like pixel data format + all offsets). Then, in the pipeline, a blit operation can be registered for such an image with the given flag and a known destination. This blit operation will know how to handle pixel data properly while skipping any gaps. >But the problem with this is that there is no such info in SurfaceDataRasInfo, >which could allow us figure out, which components are really used and which >bytes are just padding. Moreover, SurfaceDataRasInfo doesn't even have a total >size field, so we can't even clamp our copy range to some boundary. It seems that, as of now, we simply don't have generic native loops that support pixel gaps. However, for known formats, there are many specialized loops, and that information is stored not in SurfaceDataRasInfo but in various macro-based [loops](https://github.com/openjdk/jdk/blob/b01026abaab0b65f9ec0920d66a8ff1fa868d351/src/java.desktop/share/native/libawt/java2d/loops/IntRgb.h#L38). ------------- PR Review Comment: https://git.openjdk.org/jdk/pull/24111#discussion_r2026221415