On Sat, 3 Oct 2026 02:13:15 GMT, John Hendrikx <[email protected]> wrote:

>> modules/javafx.graphics/src/main/java/javafx/scene/image/WritableImage.java 
>> line 175:
>> 
>>> 173:     public final DrawingContext getDrawingContext() {
>>> 174:         if (drawingContext == null) {
>>> 175:             drawingContext = 
>>> Toolkit.getToolkit().createDrawingContext(getWritablePlatformImage(), 
>>> this::notifyDrawingContextDirty);
>> 
>> `setPlatformImage()` L1086 can replace the platform image (as a result of 
>> `snapshot`, for instance).  this will disassociate the cached 
>> `drawingContext` from the platform image.
>
> It seems that the same happens when the user supplies their own `PixelBuffer` 
> -- snapshot just replaces the platform image, effectively orphaning the 
> storage provided by the user -- that's bad, as the user can easily hold on to 
> this and expect it to be updated.
> 
> So IMHO, `snapshot` is broken, and `setPlatformImage` should be removed for 
> two reasons:
> 
> - A user supplied buffer must be honored, and it currently is just silently 
> replaced; and this already shows up as a bug (`PixelBuffer.updateBuffer` 
> still targetting the user storage, while  
> `image.getPixelReader().getArgb(...)` reads the new snapshot provided storage
> - The GPU and CPU path currently both allocate a new massive heap object for 
> the snapshot, which basically already exists. The GPU path copies the data 
> from a direct memory allocation to this new heap buffer (even though it could 
> have just copied it to the existing one), and the CPU path renders into a new 
> heap buffer, even though it could have rendered into the existing one
> 
> Also the tiled path (when the snapshot would be larger than the maximum 
> texture size) already does in-place updates, so having the normal path do so 
> as well would make it consistent.
> 
> So, I'd like to make a real fix for this in a different PR, rather than 
> stacking this into this one. The fix would entail:
> 
> - Add `Tookit.renderToImage` method that accepts a target platform image, and 
> use that for `snapshot`
> - For the CPU/SW path, if the format matches, use the target as-is; if not 
> allocate a temp buffer, and copy -- either way, the user supplied buffer is 
> updated as expected, not silently orphaned
> - For the GPU path, it always allocates a new off-heap buffer regardless for 
> the GPU to access, but it doesn't need to also allocate a new heap buffer to 
> copy that buffer into; it can just copy it into the given target instead -- 
> same amount of work, but saves a (potentially huge) buffer allocation
> - The `loadTkImage`/`getTkImageLoader`/`Image.setPlatformImage` can all be 
> removed (all only used by snapshots)
> - After snapshotting into the existing buffer, mark it dirty
> - Stop holding on to a render target for the snapshot (currently, the GPU 
> path holds on to a buffer the size of the snapshot even after it is copied to 
> the heap, potentially holding on to several MB's of memory to avoid a 
> relatively cheap render target creation 'just in case' another snapshot is 
> made... -- if the snapshot is 20 MB, then the current GPU path allocates 
> another 20 MB as render target (and never discards i...

I've added an `@implNote` that this is a known issue, let me know if you're 
okay with that until we can resolve the bigger problem.

-------------

PR Review Comment: https://git.openjdk.org/jfx/pull/1969#discussion_r4176927445

Reply via email to