Skip to content

Exorcising AWT

Ben Fry edited this page Aug 16, 2020 · 3 revisions

In 4.x, we'd like to disconnect code that touches AWT from anything that doesn't absolutely require it. There are two reasons behind this:

  1. More modern renderer implementations (JOGL's NEWT, LWJGL, etc) hang when AWT is invoked
  2. AWT code is fairly anachronistic in general

To handle the first point, we've added --disable-awt as a way to prevent any AWT code from running. This was done for alpha 2 so that @codeanticode could try things with GL. However that's not yet complete, since we'll still need non-AWT ways to get display count, width, height, pixel density. The refactor was about moving all that AWT cruft out of the main classes so that we have little or no AWT in the main processing.core package.

JOGL and JavaFX also have their own more efficient ways of handling image objects, our use of AWT in those was just a crutch to get things working quickly; this would provide a pathway for others to build out that improved image support.

Additional notes from https://github.com/processing/processing4/issues/80:

The idea is that we get the AWT-specific code out of the main classes, and then the usage of AWT is determined independently by individual renderers… i.e. for now, JavaFX and JOGL just need to create PImageAWT objects instead of PImage if they want to do saving or have access to the AWT code.

However, this way, in the future, when someone wants to/has time to excise AWT from JOGL or JavaFX, that can be done as an independent thing. It's also then clearer in the JFX/GL code bases where AWT is being used, rather than introducing a surprise when a user calls save(). Does that make sense?

AWT has some weird performance bottlenecks that are avoided by more modern approaches for JavaFX, JOGL (i.e. NEWT or whatever it's called now), and LWJGL. So in an ideal world, those renderers would never touch/initalize AWT. In the real world, I've not had time to maintain all those renderers independently, so we're still relying on AWT for some things around the edges (like image i/o).

In a similar fashion, loadImage() is part of the renderer/surface level… So a better option for me at the moment might be to move saving images into ShimAWT, but I need to take a closer look… For now, the band-aid of using new PImageAWT in JavaFX and JOGL to replace new PImage, and on save() rewrapping the PImage as a PImageAWT if it's not one already should do.

Future Directions

There's a possible world in which there is no processing.core.awt and instead we're using nothing but JavaFX and LWJGL. So the abstraction level that we're looking for is per renderer (AWT/Java2D, JavaFX, JOGL, LWJGL, etc) where each renderer is essentially a PGraphics implementation and a PSurface implementation.

Loading/Saving images

The exact path forward isn't quite clear, since there are several considerations:

  • Lots of JavaFX and GL code (outside Processing) just use BufferedImage anyway.
  • Invoking certain parts of AWT don't necessarily freeze things up; there are two factors for incompatibility:
    1. Whether the code is safe to be headless
    2. Where rendering is happening (starting Java on the "first thread" on macOS and that sort of thing)
  • We have out old load/save options for TGA (with RLE) and TIFF (uncompressed but fast) which we could remove, but:
    • We'd lose TGA (TIFF is supported by ImageIO)
    • ImageIO performance is dreadful
    • Who knows what else relies on our implementations in specific ways (i.e. the multithreaded image saving or anything else)

Related:

At the moment (alpha 2), the load/save code is in ShimAWT, but that doesn't feel great.

Clone this wiki locally