This chapter provides information and guidance for troubleshooting some of the most common issues that might be found in the Java 2D API, included in the following sections:
See Appendix A, Java 2D Properties for a summary of Java 2D properties.
See also the Java 2D FAQ.
Java 2D uses a set of pipelines, which can be roughly defined as different ways of rendering the primitives. These pipelines are as follows:
X11 pipeline, which is the default for Solaris OS and Linux
OpenGL pipeline, which is an alternative on Solaris OS and Linux, as well as Windows
DirectDraw/GDI pipeline, which is the default on Windows
Direct3D pipeline, which is an alternative on Windows
By choosing a different pipeline, or manipulating the properties of a pipeline, you might be able to determine the cause of the problem, and often find a workaround.
The following procedure can help you troubleshoot Java 2D issues:
Determine the default pipeline used in your configuration.
Either change the pipeline to another one, or modify the properties of the default pipeline.
If the problem disappears, you have found a workaround.
If the problem persists, try changing another property or pipeline.
This section describes how to change the Java 2D pipelines and their properties for each operating system: UNIX (Solaris OS and Linux), and Windows.
For the default X11 pipeline on Solaris OS and Linux, the following information is provided:
Properties related to the use of X11 pixmaps
Disabling the use of pixmaps by the X11 pipeline
Disabling/forcing the use of shared memory pixmaps by the X11 pipeline
Use of Shared Memory Extension by the X11 pipeline
Increasing the amount of shared memory available to X server and Java 2D
Disabling the use of Shared Memory Extension by the X11 pipeline
Solaris OS on SPARC: use of DGA in certain configurations
Detecting if the DGA extension is used for rendering to the screen
Typical issues caused by the use of DGA
Controlling the use of DGA by Java 2D
Solaris OS on SPARC: changing the default visual used by Java 2D
For the default DirectDraw/GDI pipeline on Windows, the following information is provided:
Disabling the use of DirectDraw
Forcing the use of DirectDraw pipeline
Disabling the built-in punting mechanism
Disabling the use of DirectDraw blit operations
For the alternative Direct3D pipeline on Windows, the following information is provided:
Disabling the Direct3D pipeline
Forcing the use of the Direct3D pipeline
Diagnosing rendering problems with the Direct3D pipeline
This section also provides information on using the OpenGL pipeline as an alternative pipeline on Solaris OS, Linux, and Windows.
On Unix platforms the default pipeline is the X11 pipeline. This pipeline uses the X protocol for rendering to the screen or to certain types of offscreen images, such as VolatileImages, or “compatible” images (images that are created with the GraphicsConfiguration.createCompatibleImage() method). Such types of images can be put into X11 pixmaps for improved performance, especially in the case of the Remote X server.
In addition, in certain cases Java 2D uses X server extensions, for example, the MIT X shared memory extension, or Direct Graphics Access extension, Double-buffer extension for double-buffering when using the BufferStrategy API.
An additional pipeline, the OpenGL pipeline, might offer greater performance in some configurations.
Java 2D by default uses X11 pixmaps for storing or caching certain types of offscreen images. Only the following types of images can be stored in pixmaps:
Opaque images, in which case ColorModel.getTransparency() returns Transparency.OPAQUE
1-bit transparent images (also known as sprites, Transparency.BITMASK)
The advantage of using pixmaps for storing images is that they can be put into the framebuffer's Video memory at the driver's discretion, which improves the speed at which these pixmaps can be copied to the screen or another pixmap.
The use of pixmaps typically results in better performance. However, in certain cases, the opposite is true. Such cases typically involve the use of operations which cannot be performed using the X protocol, such as antialiasing, alpha compositing, and transforms that are more complex than simple translation transforms.
For these operations the X11 pipeline must do the rendering using the built-in software renderer. In most cases this includes reading the contents of the pixmap to a system memory (over the network in the case of remote X server), performing the rendering, and then sending the pixels back to the pixmap. Such operations could result in extremely poor performance, especially if the X server is remote.
To disable the use of pixmaps by Java2D, pass the following property to the Java VM: -Dsun.java2d.pmoffscreen=false.
To minimize the effect of such operations requiring reading of pixels from a pixmap on overall performance, the X11 pipeline uses shared memory pixmaps for storing images which are often read from. Note that the shared memory pixmaps can only be used in the case of a local X server.
The advantage of using shared memory pixmaps is that the pipeline can get direct access to the pixels in the pipeline bypassing the X11 protocol, which results in better performance.
By default an image is stored in a normal X server pixmap, but it can be later moved to a shared memory pixmap if the pipeline detects excessive reading from such an image. The image can be moved back to a server pixmap if it is copied from often enough.
The pipeline allows two ways of controlling the use of shared memory pixmaps: either disablng them, or forcing all images to be always stored in shared memory pixmaps.
To disable shared memory pixmaps, set the J2D_PIXMAPS environment variable to server. This is the default in remote X server case.
To force all pixmaps to be created in shared memory, set J2D_PIXMAPS to shared.
First try forcing the shared memory pixmaps, as it is often improves performance. However, with certain video board/driver configurations it may be necessary to disable the shared memory pixmaps to avoid rendering artifacts or crashes.
The Java 2D X11 pipeline uses by default the MIT Shared Memory Extension (MIT SHM). This extension allows a faster exchange of data between the client (the Java application) and the X server, and this can significantly improve the performance of Java applications.
On Solaris OS releases 8 and earlier it was sometimes necessary to increase the amount of shared memory available to the system (and to X server in particular) as the default was too low, resulting in poor rendering performance. Increasing the amount of shared memory and shared memory segments can result in better performance.
To change the default settings on Solaris OS, edit the /etc/system file, changing the shmsys:shminfo_* settings, as in the following example. Note that this is not needed on Solaris 9 OS and newer.
set shmsys:shminfo_shmmax=10000000 set shmsys:shminfo_shmni=200 set shmsys:shminfo_shminfo=150
On Linux this setting can be configured by editing the /proc/sys/kernel/shm* files.
In case of problems (such as crashes, or rendering artifacts) with older X servers and Shared Memory Extension, it is useful to be able to disable the extension. To disable the use of MIT SHM, set the J2D_USE_MITSHM environment variable to false.
On SPARC hardware, if the framebuffer supports Sun's DGA (Direct Graphics Access) X server extension, and Java 2D has a corresponding module for accessing the framebuffer, DGA will be used for rendering to the screen.
All offscreen images will reside in Java heap memory, and Java 2D's software-only rendering pipeline is used for rendering to them. This is different from a typical UNIX configuration, where X11 pixmaps are used for offscreen images.
To detect if the DGA extension is used for rendering ot the screen, run any Java application which does some rendering or displays a GUI, and check if a /tmp/wg* file was created when the application started. Exit the application and verify that the file has been deleted. If this is the case, then on this system Java 2D is using DGA.
Since DGA allows direct access to the framebuffer's video memory, the typical problems include corruption outside of window bounds, complete system, and X server lock-ups.
If it is determined that DGA is being used, the first thing to try is to disable it. This can be done by setting the NO_J2D_DGA environment variable to true. This forces the default UNIX path to use only X11 for rendering to the screen, and pixmaps for accelerating offscreen images.
In some cases it could be beneficial to enable the use of pixmaps, while also using DGA for rendering to the screen. To force the use of pixmaps for accelerating offscreen images, set the following property when starting the application: -Dsun.java2d.pmoffscreen=true.
On certain video boards on the SPARC platform, more than one visual can be available from the X server. By default Java 2D tries to select the best visual, where “best” is typically a higher-bit depth visual. For example, on some Solaris OS releases the default X11 visual is 8-bit PseudoColor, although 24-bit visual is also available. In such cases Java 2D will select a 24-bit TrueColor visual as the default for Java windows.
While it is possible to create a Java top-level window with a GraphicsConfiguration object corresponding to a different visual, in some cases it is necessary to make Java use a different default visual instead. This can be done by setting the FORCEDEFVIS environment variable. It can be set to true to force the use of the default X server visual (even if it is not the best one), or it can be set to a hexadecimal number corresponding to the visual ID as reported by tools like xdpyinfo.
To determine your X server default visual, execute the xdpyinfo command and look at the default visual id field.
The default pipeline on the Windows platform is a mixture of the DirectDraw pipeline and the GDI pipeline, where some operations are performed with the DirectDraw pipeline and others with the GDI pipeline. DirectDraw and GDI APIs are used for rendering to accelerated offscreen and onscreen surfaces.
Starting with the Java SE 6 release, when the application enters full-screen mode, the new Direct3D pipeline can be used, if the drivers satisfy the requirements. Possible issues with the Direct3D pipeline include rendering artifacts, crashes, and performance-related problems.
An additional pipeline, the OpenGL pipeline, might offer greater performance in some configurations.
When DirectDraw is disabled, all operations are performed with GDI. Provide the following flag to disable the use of DirectDraw: -Dsun.java2d.noddraw=true. In this case all offscreen images will be created in the Java heap, and rendered to with the default software pipeline. All onscreen rendering, as well as copies of offscreen images to the screen will be performed using GDI.
In case the pipeline was disabled by default for some reason, it can be enabled by providing the -Dsun.java2d.noddraw=false flag to the VM.
However, typically there was a reason why it was disabled in the first place, so it is better not to force it.
In general, the DirectDraw pipeline attempts to place the offscreen surfaces in the framebuffer's video memory, which provides fast copies from these surfaces to the screen or other accelerated surfaces, as well as hardware accelerated rendering of certain graphics operations.
However, if the pipeline cannot perform an operation using the DirectDraw API (operations using, for example, alpha compositing, or transforms, or antialiasing), the rendering is performed using the software pipeline. In some cases this means that the pixels of the destination surface, which resides in VRAM, need to be read into system memory, which is a very expensive operation.
To limit the impact of unaccelerated rendering to VRAM-based surfaces, there exists a punting mechanism, which moves the surface which is detected to be often read from to the system memory. If the surface is found to be copied from often enough, it may be promoted back to the video memory.
On certain video boards/drivers combinations the system-memory based DirectDraw surfaces are known to cause rendering artifacts and other issues. The DirectDraw pipeline provides a way to disable the punting mechanism so that the system memory surfaces are not used.
To defeat the built-in surface punting mechanism provide the following flag to the Java VM: -Dsun.java2d.ddforcevram=true. Note that this can result in performance degradation, as the software loops may be reading pixels from VRAM on each operation. In this case you may consider disabling the DirectDraw pipeline (see above).
In a blit operation (Bit Block Transfer), two bitmap patterns are combined. This operation basically corresponds to a call to the Graphics.drawImage() API.
In some cases it is possible to avoid rendering problems by disabling the DirectDraw blit operations. GDI blits will be used instead. Note that this might result in bad performance. Consider disabling the DirectDraw pipeline instead.
To disable the use of DirectDraw blit operations, pass the parameter -Dsun.java2d.ddblit=false to the Java VM.
Starting with the Java SE 6 release, the Direct3D pipeline uses the Direct3D API for rendering. This pipeline is enabled in full-screen mode by default, if the drivers support the required features and the level of rendering quality.
With both the Java SE 5 and later releases, it is possible to enable the Direct3D pipeline or to force its use, as described in the subsections below.
Consider enabling the Direct3D pipeline for your application if it makes heavy use of rendering operations such as alpha compositing, antialiasing, and transforms.
However, use caution when deciding to enable this pipeline in your application. For example, some built-in video chipsets (which are used in most notebooks) do not perform well using Direct3D, even if they satisfy the quality requirements for Java 2D pipelines.
Some older video boards/drivers combinations are known to cause issues (both rendering and performance) with the Direct3D pipeline. To disable the pipeline in such cases, with Java SE 5 and later releases, pass the parameter -Dsun.java2d.d3d=false to the Java VM, or set the J2D_D3D environment variable to false.
With Java SE 5 and later releases, to enable the Direct3D pipeline in both windowed and full-screen mode, use the parameter -Dsun.java2d.d3d=true, or set the J2D_D3D environment variable to true. Note that the pipeline is enabled only if the drivers support minimum required features.
With the Java SE 6 release, some rendering issues (like missing pixels, garbled rendering) can be diagnosed by forcing different Direct3D rasterizers. Set the J2D_D3D_RASTERIZER environment variable to one of the following: ref, rgb, hal, or tnl.
Refer to Direct3D documentation for a description of these rasterizers. By default the best rasterizer is chosen based on its advertised capabilities. In particular, the ref rasterizer forces the use of the reference Direct3D rasterizer from Microsoft. If a rendering problem is not reproducible with this rasterizer, then it is very likely to be a video driver bug.
The rgb rasterizer is available only if the Direct3D SDK is installed. This SDK can be obtained from Microsoft Game Technologies Center.
For performance or quality problems with text rendering with the Direct3D pipeline, you can force the use of ARGB texture instead of the default Alpha texture for the Direct3D pipeline's glyph cache. To do this, set the J2D_D3D_NOALPHATEXTURE environment variable to true.
The OpenGL pipeline was first made available in the J2SE 5.0 release on Solaris OS, Linux, and Windows. This alternate pipeline uses the hardware-accelerated, cross-platform OpenGL API when rendering to VolatileImages, to backbuffers created with BufferStrategy API, and to the screen.
This pipeline can offer great performance advantages over the default (X11 or GDI/DirectDraw) pipelines for certain applications. Consider enabling the pipeline for your application if it makes heavy use of rendering operations like alpha compositing, antialiasing, and transforms.
For a complete list of Java 2D operations that are accelerated by the OpenGL pipeline, refer to the article Behind the Graphics2D: The OpenGL-based Pipeline.
The OpenGL pipeline is currently disabled by default. To attempt to enable the OpenGL pipeline, provide the following option to the JVM:
To receive verbose console output about whether the OpenGL pipeline is initialized successfully for a particular screen, set the option to True (note the uppercase “T”):
The OpenGL pipeline will not be enabled if the hardware or drivers do not meet the minimum requirements. If for some reason one of the following requirements is not met, Java 2D will fall back and use the default pipeline (X11 on Solaris/Linux, GDI/DirectDraw on Windows), which means your application will continue to work correctly, but without the OpenGL acceleration.
The minimum requirements for Solaris OS and Linux are the following:
Hardware accelerated OpenGL/GLX libraries installed and configured properly
OpenGL version 1.2 or higher
GLX version 1.3 or higher
At least one TrueColor visual with an available depth buffer
The minimum requirements for Windows OS are the following:
Hardware accelerated drivers supporting the extensions WGL_ARB_pbuffer, WGL_ARB_render_texture, and WGL_ARB_pixel_format
OpenGL version 1.2 or higher
At least one pixel format with an available depth buffer
Since the OpenGL pipeline relies heavily on the OpenGL API and the underlying graphics hardware and drivers, it is very important to ensure that you have the latest graphics drivers installed on your machine. Drivers can be downloaded from your graphics card manufacturer's web site, as shown in the following table.
As mentioned above, the OpenGL pipeline might not be enabled on certain machines for various reasons. For example, the drivers might not be properly installed and might report an insufficient version number. Alternatively, your machine might have an older graphics card that does not support the appropriate OpenGL version or extensions.
In the Java SE 6 and later releases, you can get detailed information about the startup procedures of the OpenGL-based Java 2D pipeline by using the J2D_TRACE_LEVEL environment variable as follows.
# set J2D_TRACE_LEVEL=4 # java -Dsun.java2d.opengl=True YourApp
On Solaris OS and Linux:
# export J2D_TRACE_LEVEL=4 # java -Dsun.java2d.opengl=True YourApp
The output will be different depending on your platform and the installed graphics hardware, but it can give you some insight into the reasons why the OpenGL pipeline is not being successfully enabled for your configuration. Note that this output is especially useful when filing bug reports intended for the Java 2D team at Sun, as discussed below.
Since the OpenGL pipeline relies so heavily on the underlying graphics hardware and drivers, it might sometimes be difficult to determine whether rendering or performance issues are being caused by Java 2D or by the OpenGL drivers.
One feature new to the OpenGL pipeline in the Java SE 6 release is the use of the GL_EXT_framebuffer_object extension, which provides better performance for rendering and reduced VRAM consumption when using VolatileImages. This “FBO“ codepath is enabled by default when the OpenGL pipeline is enabled, but only if your graphics hardware and driver support this OpenGL extension. This extension is generally available on Nvidia GeForce/Quadro FX series and newer, and on ATI Radeon 9500 and newer. If you suspect that the “FBO” codepath is causing problems in your application, you can disable it by setting the following system property:
Setting this property will cause Java 2D to fall back on the older “pbuffer-based” codepath.
If you find that a certain Java 2D operation causes different visual results with the OpenGL pipeline enabled than without, it probably indicates a graphics driver bug. Similarly, if the performance of Java 2D rendering is significantly worse with the OpenGL pipeline enabled than without, it is most likely caused by a driver or hardware problem.
In either case, file a detailed bug report through the normal bug reporting channels (see Chapter 8, Submitting Bug Reports). When filing bug reports, be as detailed as possible, and always include the following information:
Operating system (for example, Ubuntu Linux 6.06, Windows XP SP2)
Name of graphics hardware manufacturer and device (for example, Nvidia GeForce? 2 MX 440)
Exact driver version (for example, ATI Catalyst 6.8, Nvidia 91.33)
Output when J2D_TRACE_LEVEL=4 is specified on the command line (as described in previous section)
If on Solaris OS or Linux, the output of the glxinfo command
This section contains the following subsections:
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 which can be hardware-accelerated are VolatileImage, screen, and BufferStrategy. If a destination is accelerated, rendering which goes to such surface may be performed by video hardware. So if you issue a drawRect call, 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. Such images are known as “managed images.”
Ideally, all operations performed to an accelerated surface are hardware-accelerated. In this case the application takes the full advantage that 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.
To detect a non-accelerated rendering, you can use Java 2D primitive tracing.
Java 2D has built-in primitive tracing. See the description of the trace property at System Properties for Java 2D Technology.
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)
Here are some of the common non-accelerated primitives in the default pipelines, and their signatures in the tracing output. Note that most of this tracing was taken on Linux; you may see some differences depending on your platform and configuration.
Translucent images (Images with ColorModel.getTranslucency() returns Translucency.TRANSLUCENT), or with AlphaCompositing. Sample primitive tracing output:
sun.java2d.loops.Blit$GeneralMaskBlit::Blit(IntArgb,SrcOverNoEa, "Integer BGR Pixmap")sun.java2d.loops.MaskBlit::MaskBlit(IntArgb, SrcOver, IntBgr)
Use of antialiasing (by setting the antialiasing hint). Sample primitive tracing output:
sun.java2d.loops.MaskFill::MaskFill(AnyColor, Src, IntBgr)
Rendering antialiased text (setting the text antialising hint). Sample output can be one of the following:
sun.java2d.loops.DrawGlyphListAA::DrawGlyphListAA(OpaqueColor, SrcNoEa, AnyInt)
sun.java2d.loops.DrawGlyphListLCD::DrawGlyphListLCD(AnyColor, SrcNoEa, IntBgr)
Alpha compositing, either by rendering with translucent Color (a Color with alpha value which is not 0xff), or by setting a non-default AlphaCompositing mode with Graphics2D.setComposite():
sun.java2d.loops.Blit$GeneralMaskBlit::Blit(IntArgb, SrcOver, IntRgb)sun.java2d.loops.MaskBlit::MaskBlit(IntArgb, SrcOver, IntRgb)
Non-trivial transforms (if the transform is more than only translation). Rendering a transformed opaque image to a VolatileImage:
sun.java2d.loops.TransformHelper::TransformHelper(IntBgr, SrcNoEa, IntArgbPre)
Rendering a rotated line:
sun.java2d.loops.DrawPath::DrawPath(AnyColor, SrcNoEa, AnyInt)
Run your application with the tracing and make sure you do not use unaccelerated primitives unless they are needed.
Some of the possible causes of poor rendering performance are described in the following subsections:
A situation when only part of the primitives rendered by an application could be accelerated by the particular pipeline when rendering to an accelerated surface can cause thrashing, because the pipelines will be constantly trying to adjust for better rendering performance but with possibly little success.
If it is known beforehand that most of the rendering primitives will not be accelerated, it could be better to either render to a BufferedImage and then copy it to the back-buffer or the screen, or switch to a non-hardware accelerated pipeline using one of the flags discussed above.
Note, however, that this approach may limit your application's ability to take advantage of future improvements in Java 2D's use of hardware acceleration.
For example, if your application is often used in remote X server cases, but it heavily uses antialiasing, alpha compositing, and so forth, the performance can be severely degraded. To avoid this, disable the use of Pixmaps by setting the -Dsun.java2d.pmoffscreen=false property either by passing it to the Java runtime, or by setting it programmatically using the System.setProperty() API. Note that this property must be set prior to any GUI-related operations because it is read only once.
It is preferable to use the simplest primitive possible to achieve the desired visual effect.
For example, use Graphics.drawLine()instead of new Line2D().draw(). The result looks the same. However, the second operation is much more computationally-intensive because it is rendered as a generic shape, which is typically much more expensive to render. Shapes show up in different ways in the primitive tracing, depending on antialiasing settings and the specific pipeline, but most likely they will show up as many *FillSpans or DrawPath primitives.
Another example of complicated attributes is GradientPaint. Although it may be hardware accelerated by some of the non-default pipelines (such as OpenGL), it is not hardware accelerated by the default pipelines. Therefore, you can restrict the use of GradientPaint if it causes performance problems.
Rendering to a BufferedImage almost always uses software loops.
An exception is that on some SPARC systems the VIS instruction set may be used for accelerating certain imaging operations. Refer to web site for the VIS Instruction Set.
To ensure that the rendering has the opportunity of being hardware accelerated, choose a BufferStrategy or a VolatileImage object as the rendering destination.
Java 2D attempts to accelerate certain types of images. Contents of images may be cached in video memory for faster copying to accelerated destinations such as VolatileImages. These mechanisms can be unknowingly defeated by the application, for example, in the following cases:
If an application gets access to BufferedImage pixels by using the getRaster().getDataBuffer() API, Java 2D will not be able to guarantee that the data in the cache is up to date, so it will disable any acceleration attempts of such image.
There are two ways to avoid this problem:
If possible, do not call getDataBuffer(). Instead, work with WriteableRaster, which can be obtained with the BufferedImage.getRaster() method.
If you do need to modify the pixels directly, you can manually cache your image in video memory by maintaining the cached copy of your image in a VolatileImage, and updating the cached data when the original image is touched.
If an application renders to an image every time before copying it to an accelerated surface (VolatileImage, BufferStrategy), the image cannot take advantage of being cached in accelerated memory. This is because the cached copy has to be updated every time the original image is updated, and therefore only the default system-memory based surface is used, and this means no acceleration.
If the application uses many images, it may exhaust the available accelerated memory. If this is indeed the cause of performance issues for your application, you might need to handle the resources.
The following API can be used to request the amount of available accelerated memory: GraphicsDevice.getAvailableAcceleratedMemory().
In addition, the following API can be used to determine if your image is being accelerated: Image.getCapabilities().
If you determined that your application is exhausting the resources, you can handle the problem in the following ways:
Do not hold images you no longer need. For example, if your game advanced to the next level, release all images from the previous levels. You can also release accelerated resources associated with an image by using the Image.flush() API.
Use the acceleration priority API Image.getAccelerationPriority() and setAccelerationPriority() to specify the acceleration priority for your images. It is a good idea to make sure that at least your back-buffer is accelerated, so create it first, and with acceleration priority of 1 (default). You can also prohibit certain images from being accelerated if needed by setting the acceleration priority to 0.0.
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, there are certain approaches to improving performance:
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 drawImage call there will be two primitives: the first one converting the image from the source format to an intermediate IntArgb format and the second one converting from intermediate IntArgb to 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_RGB or INT_ARGB. In this way the conversion from the custom image format will happen only once instead of on every copy.
Consider using 1-bit transparent (BITMASK) images for your sprites as opposed to images with full translucency (such as INT_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).
This section describes some issues that can be related to text rendering, included in the following subsections:
If an application crashes during text rendering, first check the fatal error log file. See Appendix B, Fatal Error Log for detailed information about this error log file. If the crash occurred in fontmanager.dll or if fontmanager is present in the stack, then the crash occurred in the font processing code. Here is an example of typical native stack frames (excerpt from the full log file).
Stack: [0x008a0000,0x008f0000), sp=0x008ef52c, free space=317k Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code) C [ntdll.dll+0x1888f] C [ntdll.dll+0x18238] C [ntdll.dll+0x11c76] C [MSVCR71.dll+0x16b3] C [MSVCR71.dll+0x16db] C [fontmanager.dll+0x21f9a] C [fontmanager.dll+0x22876] C [fontmanager.dll+0x1de40] C [fontmanager.dll+0x1da94] C [fontmanager.dll+0x48abb] j sun.font.FileFont.getGlyphImage(JI)J+0 j sun.font.FileFontStrike.getGlyphImagePtrs([I[JI)V+92 j sun.font.GlyphList.mapChars(Lsun/java2d/loops/FontInfo;I)Z+37 j sun.font.GlyphList.setFromString(Lsun/java2d/loops/FontInfo;Ljava/lang/String;FF)Z+71 j sun.java2d.pipe.GlyphListPipe.drawString(Lsun/java2d/SunGraphics2D;Ljava/lang/String;DD)V+148 j sun.java2d.SunGraphics2D.drawString(Ljava/lang/String;II)V+60 j FontCrasher.tryFont(Ljava/lang/String;)V+138 j FontCrasher.main([Ljava/lang/String;)V+20 v ~StubRoutines::call_stub
In this case, a particular font is probably the problem. If so, then removing this font from the system will likely resolve the problem.
To identify the font file, execute the application with -Dsun.java2d.debugfonts=true. The font that is mentioned last is usually the one that is causing problems. Here is an example of typical output.
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
Note - In some cases the font that is last mentioned might be in fact innocent. Font names are printed when they are first used and subsequent uses are not shown.
To verify that this particular font is causing the problem, you can temporarily remove it from your system. You can easily find the file name associated with this particular family name from the above output.
Another verification approach is to use the Font2DTest tool (demo/jfc/Font2DTest) to test fonts that you suspect. You can specify a particular font size, style, and rasterization mode. If the process of viewing a particular font with Font2DTest causes the JDK to crash, then it is very likely that it is the font that is causing the problems.
If you found a font causing the JDK to crash, it is very important to report this problem, including the particular font and the operating system, at bugs.sun.com. See Chapter 8, Submitting Bug Reports for more information about reporting bugs.
Java has its own font rasterizer, and you can expect some small differences between the appearance of text in a Java application and in a native application.
One of the most typical sources of these differences is that the antialiasing settings can be different. In particular, a Swing application sometimes ignores the Linux desktop font antialiasing settings.
There are several likely reasons for this behavior:
Over remote X11 antialiasing is not enabled by default for performance reasons. For information about how to force antialiasing, see the Font and Test questions in the Java 2D FAQ.
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 best way to ensure that the configuration is what you expect is to run Font2DTest, explicitly select the font used by the native application, and set other parameters as appropriate. Here is a sample screen from the Font2DTest tool.
Hint: you can input your own string by choosing “user text” in the drop-down menu labelled “Text to use.”
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 needs to 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 feels, such as the Windows look and feel or the GTK look and feel (for Solaris OS and Linux), Swing components perform this adjustment automatically1, but if you are running Font2DTest, the text display area will always use 72 dpi.
On operating systems other than Windows, the general recommendation is to use TrueType fonts instead of Type1 fonts. The easiest way to discover 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.
If you find that text bounds are different from what you expect, 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 “width.” For more details, refer to the Font and Text questions in the Java 2D FAQ.
This section describes some issues that can arise with Java 2D printing and suggests causes and solutions.
See also the Printing questions in the Java 2D FAQ.
Cause: The JRE uses Windows printer drivers and they might have problems.
Solution: Upgrade the Windows printer driver for the printer that is being used.
Cause: Some jobs fail to properly spool to the printer.
Solution: In the printer driver properties, disable Advanced Printing Options.
Cause: Applications might cause the JRE to probe all printers, including those that are disconnected.
Solution: Look for disconnected or unreachable network printers and remove them from the list of printers.
Cause: The cause is one of the following:
The lpc utility is not in the /usr/sbin directory.
The lpstat utility is not in the /usr/sbin directory.
Solution: Install lpc and lpstat in the standard location, as mentioned above.