This post summarizes the changes that were made in Substance 5 to address the performance issues raised by the users. As mentioned before (part 1 and part 2), Substance 5 is 2.5-3.5 times faster than Substance 4.3 on various static and dynamic scenarios. Many thanks go to Dmitri Trembovetski from Java2D team for his help and tips.
- Use multi-stop gradients (LinearGradientPaint) with REPEAT cycle method (as mentioned in the comments on Romain’s blog entry).
- Rendering translucent texts is slow and does not use the new native font rasterizer in 6u10. Solution – instead of installing a translucent composite, interpolate the text foreground color and the background fill color based on your alpha value, and use full opacity text rendering.
- BufferedImage.setRGB and BufferedImage.getRGB are really slow. A custom BufferedImageOp might be more difficult to learn, but is much more performant if done correctly.
- Set RenderingHints.KEY_ANTIALIASING to OFF before calling any Graphics.fill operation that results in aliased fill in any case. This is especially relevant for Graphics.fillRect that gets integer parameters. Java2D is not smart enough (yet) to choose the non-antialiased path when the end result is non-antialiased.
- Intermediate non-cached BufferedImages are slow. Whenever possible, either draw directly on the Graphics context, or collect the final result into one BufferedImage that goes into the cache, even if the cache key is more complex.
- Filling with translucent color or filling under translucent composite is very expensive. In fact, the single largest performance gain (20% of the final result) in Substance 5 was removing watermarks from most core skins.
- Use AffineTransform for rotating painting instead of doing it manually. As with BufferedImageOp, it takes some time to understand how to do it (and i’m still terrible at it), but the performance is much better.
- Use EnumSet and EnumMap whenever possible. This is not Java2D-specific, and the tip goes to Joshua Bloch. These are quite faster than Hash* counterparts.
- Do not do multiplt rendering of the same surfaces. This is especially relevant for tables thatcan have potentially thousands of visible cells on the screen. Try to draw background fills and gradients once per table.
- Last, and not specific to Java2D – profile every scenario, question every method and every line of code.
More tips on Java2D performance right here.
Update: hitting “Submit” too fast, i forgot another Swing-specific optimization. Since everything UI-relates has to run on EDT, you can use non-synchronized non-thread safe code and collections. This comes in quite handy coupled with caching images and additional otherwise guarded blocks.
The biggest pain point of Substance users, as expressed in the comments on the announcement of release 4.3, is the performance. While this might have been less noticeable for smaller UIs, the users of Substance NetBeans module were especially vocal about the performance issue. As i have already said before, you made your statement very clear, and performance improvements were placed as the top priority for the next release (code named Substance 5).
Following the extensive correspondence with Java2D team (thanks, Dmitri), i have created a new java.net project named LightBeam. LightBeam has a collection of static and dynamic scenarios that are targetting different core Swing components and different interaction scenarios. The static scenarios create a number of components and then render the main frame onto an offscreen buffer. The dynamic scenarios run a number of typical interaction scenarios that involve changing the components or models.
Here is the spreadsheet with the performance improvements on static scenarios. The numbers are milliseconds it takes to render a frame with a number of matching components (buttons, sliders etc) to an offscreen buffer (the smaller, the better).

An average improvement from version 4.3 is by factor of 3.5. As you can see, slider rendering was especially slow in version 4.3. Another important number to notice is the heap memory consumption – it has not grown at all as compared with version 4.3.
And here is the spreadsheet with the performance improvements on static scenarios. The numbers are milliseconds it takes to run a specific scenario and repaint the contents (the smaller, the better).

An average performance improvement from version 4.3 is by factor of 2.5. As before, sliders were especially slow in version 4.3. Note that there is one scenario where the additional visuals provided by Substance prove to be still too costly – in dynamically selecting table rows. This would, obviously, have to be addressed before the final release.
Project LightBeam is targeted at look-and-feel developers that wish to test the performance of their libraries. The SVN repository contains a number of sample scripts that were used in creating the above spreadsheets. It will be extensively used throughout the development of Substance to make sure that there are no performance regressions from this moment forward.
The latest development drop of Substance 5 should be very stable. You’re more than welcome to try it out and report any exceptions, errors or visual inconsistencies on the project forums, mailing lists or in a direct mail. Also, if you’re using NetBeans 6.1, please consider trying out the latest drop of Substance module. It should be noticeably faster, but if you’re experiencing any slowdowns, just right-click on the title bar and select “Show cache stats”. In the new dialog, click “Copy to clipboard” and attach the results to a forum / mailing list posting.
Update – the numbers above are for software unaccelerated rendering. No work has been done yet to analyze and improve the performance on d3d-accelerated pipeline.
One of Substance users has switched from version 3.3 to the 4.* line, and is now missing his favorite Streetlights skin. Indeed, it has been removed about a year ago in version 4.0. This specific skin was never marked as officially supported, and the reason was simple – the old theming layer was not powerful enough to support a skin that mixes dark and bright colors.
It is difficult to design a pleasant skin that combines dark colors for overall controls and bright colors for active controls (selected, rolled over, pressed, armed). It is more difficult to implement such a skin in a programmatic way, and even more so to properly support animations. With usual bright colors you only need to animate the background fill while the foreground color stays the same (usually black). The dark-bright switch requires animating both foreground and background colors. Also, there are many corner cases that reveal themselves only with this specific combination. For example, using the same bright colors for both inner fill and outer border of a selected button results in a very fuzzy appearance. It is much better to use dark colors for painting borders of brightly-filled buttons.
As i have already mentioned, the new version of Substance (currently under development) as much more powerful theming layer. Now it is possible to bring Streelights back to life, this time with much better and consistent visuals. Here is a thumbnail of the test application running under Streetlights (click to see full size):

You’re more than welcome to read the code behind the Streetlights skin. It is available as part of the Extras pack.
Looking at the comments on the announcement of release 4.3 of Substance look-and-feel, the three major pain points for the users are: performance, performance and performance. You made your statement very clear, and performance improvements were placed as the top priority for the next release (code named Substance 5).
Those of you who visit the Java2D forum on java.net might have seen the discussion between myself and Dmitri Trembovetski, one of Sun’s engineers working on Java2D team. Dmitri has been kind enough to analyze the tracing metrics of Substance, providing very valuable tips on improving the rendering performance. I have been quite busy for the last two weeks working on nothing but the performance area in Substance 5, and i’m very pleased to share the initial results with you.
Substance distribution includes a test application that uses all core Swing controls, checking quite a few scenarios (toolbars embedded in toolbars would be such an example from a real bug report submitted by a user). The distribution also includes a performance suite that selects a few representative tabs in this application (buttons, toggle buttons, check boxes, radio buttons, comboboxes, sliders, table with different renderers; application menu bar, tool bar and tabs are always present). In order to measure the performance, this test frame is rendered to an offscreen image, allowing the look-and-feel to cache all the relevant images (first 10 iterations) and then timing the subsequent iterations.
Here are the results for Substance 4.3 (latest stable release) as compared with native Windows look-and-feel, Nimbus and Plastic3D from JGoodies on a dual-core Vista machine running b22 of 6u10:
- Plastic3D – 34ms with 10.527 KB used heap space
- Windows – 56ms with 10.290 KB used heap space
- Nimbus – 66ms with 25.796 KB used heap space
- Substance – 194ms with 23.353 KB used heap space
As you can see, Substance 4.3 is almost three times slower than Nimbus and 3.5 times slower than Windows look-and-feel.
And these are the results under the latest development drop of Substance 5:
- Plastic3D – 34ms with 10.527 KB used heap space
- Substance – 52ms with 18.549 KB used heap space
- Windows – 56ms with 10.290 KB used heap space
- Nimbus – 66ms with 25.796 KB used heap space
As you can see, version 5.0 is 3.7 times faster than version 4.3, even edging out Windows and Nimbus. It also uses less memory than before (by about 20%) and starts around twice faster. The same range of numbers is observed on a single-CPU Windows XP and Ubuntu 8.04 (running the same b22 of 6u10). The numbers above are for the Autumn skin. Similar improvements are recorded for other core Substance skins, such as Business Black Steel (from 220ms to 73ms), Creme (207ms to 62ms) and Nebula (222ms to 73ms), staying around 3 to 3.7 faster than the previous release.
The next entry will talk more about the specific optimizations that contributed to the performance improvements. You are more than welcome to take the latest dev drop and test it on your applications. There are some minor color inconsistencies on colorized combo boxes, but other than that it should be quite stable and fast.
Note that this is very much work in progress. While all of the current measurements are taken on the software pipeline (still more places left to be optimized), and there is a lot of work to be done for hardware-accelerated pipelines (D3D). The performance suite will be used throughout the development of this version to make sure that there is no performance regression. It will also serve to create guidelines for designing fast custom skins for Substance. Stay tuned for more.