13 Java 2D
This chapter provides information and guidance for troubleshooting some of the most common issues that might be found in the Java 2D API.
This chapter contains the following sections:
For a summary of Java 2D properties, see Java 2D Properties.
Generic Performance Issues
There could be many causes for poor rendering performance. The following topics identify the cause for your applications poor rendering performance and suggests some approaches to improve performance of software-only rendering.
This topic contains the following subsections:
Hardware-Accelerated Rendering Primitives
In order to better understand what could be causing performance problems, take a look at what hardware acceleration means.
In general, hardware-accelerated rendering could be divided into two categories.
-
Hardware-accelerated rendering to an "accelerated" destination. Examples of rendering destinations that can be hardware-accelerated are
VolatileImage, screen andBufferStrategy. If a destination is accelerated, then rendering goes to a surface may be performed by video hardware. So, if you issue adrawRectcall, Java 2D redirects this call to the underlying native API (such as GDI, DirectDraw, Direct3D or OpenGL, or X11), which performs the operation using hardware. -
Caching images in accelerated memory (video memory or pixmaps) so that they can be copied very fast to another accelerated surface. These images are known as managed images.
Ideally, all operations performed on an accelerated surface are hardware-accelerated. In this case, the application takes full advantage of what is offered by the platform.
Unfortunately in many cases the default pipelines are not able to use the hardware for rendering. This can happen due to the pipeline limitations, or the underlying native API. For example, most X servers do not support rendering antialiased primitives, or alpha compositing.
One cause of performance issues is when operations performed are not hardware-accelerated. Even in cases when a destination surface is accelerated, some primitives may not be.
It is important to know how to detect the cases when hardware acceleration is not being used. Knowing this may help in improving performance.
Primitive Tracing to Detect and Avoid Non-Accelerated Rendering
To detect a non-accelerated rendering, you can use Java 2D primitive tracing.
Run your application with -Dsun.java2d.trace=count. When the application exits, a list of primitives and their counts is printed to the console.
Any time you see a MaskBlit or any of the General* primitives, it typically means that some of your rendering is going through software loops. Here is the output from performing drawImage on a translucent BufferedImage to a VolatileImage on Linux:
sun.java2d.loops.Blit$GeneralMaskBlit::Blit(IntArgb, SrcOverNoEa, "Integer BGR Pixmap")sun.java2d.loops.MaskBlit::MaskBlit(IntArgb, SrcOver, IntBgr)
Note:
Most of this tracing was taken on Linux; you may see some differences depending on your platform and configuration.Causes of Poor Rendering Performance
Some of the possible causes of poor rendering performance and possible alternatives are described as follows:
Improve Performance of Software-only Rendering
If your application relies on software-only rendering (by only rendering to a BufferedImage, or changing the default pipeline to an unaccelerated one), or even if it does mixed rendering, then the following are certain approaches to improving performance:
-
Image types or operations with optimized support:
Due to overall platform size constraints, Java 2D has a limited number of optimized routines for converting from one image format to another. In situations where an optimized direct loop can not be found, Java 2D will do the conversion through an intermediate image format (
IntArgb). This results in performance degradation.Java 2D primitive tracing can be used for detecting such situations.
For each
drawImagecall there will be two primitives: the first one converting the image from the source format to an intermediateIntArgbformat and the second one converting from intermediateIntArgbto the destination format.Here are two ways to avoid such situations:
-
Use a different image format if possible.
-
Convert your image to an intermediate image of one of the better-supported formats, such as
INT_RGBorINT_ARGB. In this way the conversion from the custom image format will happen only once instead of on every copy.
-
-
Transparency vs translucency:
Consider using 1-bit transparent (
BITMASK) images for your sprites as opposed to images with full translucency (such asINT_ARGB) if possible.Processing images with full alpha is more CPU-intensive.
You can get a 1-bit transparent image using a call to GraphicsConfiguration.createCompatibleImage(w,h, Transparency.BITMASK).
Text-Related Issues
This section describes possible issues and crashes that are related to text rendering and describes tips to overcome such issues.
This section contains the following subsections:
Tracing Font Loading
Setting the -Dsun.java2d.debugfonts=true property generates
information about the fonts loaded by Java 2D. You can see what fonts Java 2D finds, infer which
ones it uses, and see information about fonts that it rejects. This property generates output
similar to the following:
INFO: Registered file C:\WINDOWS\Fonts\WINGDING.TTF as font ** TrueType Font: Family=Wingdings
Name=Wingdings style=0 fileName=C:\WINDOWS\Fonts\WINGDING.TTF rank=2
Aug 16, 2006 10:59:06 PM sun.font.FontManager initialiseDeferredFont
INFO: Opening deferred font file SYMBOL.TTF
Aug 16, 2006 10:59:06 PM sun.font.FontManager addToFontList
INFO: Add to Family Symbol, Font Symbol rank=2
Aug 16, 2006 10:59:06 PM sun.font.FontManager registerFontFile
INFO: Registered file C:\WINDOWS\Fonts\SYMBOL.TTF as font ** TrueType Font: Family=Symbol
Name=Symbol style=0 fileName=C:\WINDOWS\Fonts\SYMBOL.TTF rank=2
Aug 16, 2006 10:59:06 PM sun.font.FontManager findFont2D
INFO: Search for font: Dialog
Aug 16, 2006 10:59:06 PM sun.font.FontManager initialiseDeferredFont
INFO: Opening deferred font file ARIALBD.TTF
Aug 16, 2006 10:59:06 PM sun.font.FontManager addToFontList
INFO: Add to Family Arial, Font Arial Bold rank=2
Aug 16, 2006 10:59:06 PM sun.font.FontManager registerFontFile
INFO: Registered file C:\WINDOWS\Fonts\ARIALBD.TTF as font ** TrueType Font: Family=Arial
Name=Arial Bold style=1 fileName=C:\WINDOWS\Fonts\ARIALBD.TTF rank=2
Aug 16, 2006 10:59:06 PM sun.font.FontManager initialiseDeferredFont
INFO: Opening deferred font file WINGDING.TTF
Aug 16, 2006 10:59:06 PM sun.font.FontManager initialiseDeferredFont
INFO: Opening deferred font file SYMBOL.TTF
Aug 16, 2006 10:59:06 PM sun.font.FontManager findFont2D
INFO: Search for font: Dialog
Aug 16, 2006 10:59:06 PM sun.font.FontManager initialiseDeferredFont
INFO: Opening deferred font file ARIAL.TTF
Aug 16, 2006 10:59:06 PM sun.font.FontManager addToFontList
INFO: Add to Family Arial, Font Arial rank=2
Aug 16, 2006 10:59:06 PM sun.font.FontManager registerFontFile
INFO: Registered file C:\WINDOWS\Fonts\ARIAL.TTF as font ** TrueType Font: Family=Arial
Name=Arial style=0 fileName=C:\WINDOWS\Fonts\ARIAL.TTF rank=2
Aug 16, 2006 10:59:06 PM sun.font.FontManager initialiseDeferredFont
INFO: Opening deferred font file WINGDING.TTF
Aug 16, 2006 10:59:06 PM sun.font.FontManager initialiseDeferredFont
INFO: Opening deferred font file SYMBOL.TTF
Differences in Text Appearance
Differences in text appearance in Java applications compared to native applications can be due to different font rasterizers being used. Java applications typically use the operating system's font rasterizer, the same one that native applications use. However, Java applications may use FreeType, a software library to render fonts, which has been installed or included in an operating system. For example, FreeType may be used on Windows for grayscale text or on macOS for Type 1 fonts that aren't supported by the macOS font rasterizer. However, note that Windows has multiple font rasterizers. Consequently, text rendering can vary between native applications. In addition, all platforms have some degree of configurability in platform rasterization which can lead to small differences in text appearance.
Other sources of difference include:
- Whether subpixel positioning is in use as this affects the precise positioning of glyphs; see java.awt.RenderingHints.KEY_FRACTIONALMETRICS.
- On Linux, Swing might choose different anti-aliasing settings.
There are several likely reasons for this behavior:
- Antialiasing over a remote X11 connection is not enabled by default for performance reasons.
-
CJK fonts that use embedded bitmaps may render using the bitmaps instead of subpixel text.
-
Some variants of unsupported desktops do not report their font smoothing settings properly. For example, KDE is unsupported but should generally work; however, some problem seems to prevent JDK from picking up the setting.
The size of the font in the Java language is always expressed with 72 dpi. A native OS can use a different screen dpi, and therefore an adjustment must be made. Matching Java font size can be calculated as Toolkit.getScreenResolution() divided by 72 multiplied by the size of the native font.
In all native Swing look-and-feel, such as the Windows look-and-feel or the GTK look-and-feel for the Linux operating system, Swing components perform this adjustment automatically.
On operating systems other than Windows, the general recommendation is to use
TrueType fonts instead of Type1 fonts. The easiest way to figure out the type of font is
to look at the file extension: extensions pfa and pfb
indicate Type1 fonts, and ttf, ttc, and
tte represent TrueType fonts.
Font Metrics
If you find that text bounds are different from what you expect, then ensure that you are using the appropriate way to calculate them. For example, the height obtained from a FontMetrics is not specific to a particular piece of text, and the stringWidth indicates logical advance, which is not the same thing as wide. For more details, see the Font and Text questions in the Java 2D FAQ.