Friday, March 29, 2013

Java Image Acceleration

This is something that took me a long time to figure out. But that might help you if your seeing java performance issues when rendering sprites or other images.


Speeding up image rendering


While working on a game that was using sprite sheets with a background color instead of transparent PNGs. I found that my rendering code was slowing down significantly especially in fullscreen mode. I did some research and found out that Java images have to be hardware accelerated and won't be if the raster is modified directly. Something I had assumed would happen automagically. The problem arises from modifying an Images raster on the CPU and not automatically reallocating it on the GPU.


Check Image Capabilities


There is a check to see if a given image is hardware accelerated. It's in ImageCapabilities which you can get for any java.awt.Image for a given GraphicsConfiguration which is different per GraphicsDevice. There is also setAccelerationPriority method but I don't believe you would want to rely on it for games as much. You should definitely give it a test especially if you don't want to convert all images over to using VolatileImage's which can loose their handle to video memory in certain circumstances akin to DirectX's hardware reset that usually happens in windows when Alt+Tabbing between a fullscreen exclusive application and another windowed application.

Creating Accelerated VoltaileImage's

I've relied on the GraphicsConfiguration function for creating these VolatileImage's. createCompatibleVolatileImage or on the java.awt.Toolkit function with the same name. There are a couple of overloaded methods that you can use to successfully create accelerated images. Combine this and the check in the ImageCapabilities to make sure you've created an image that is going to be accelerated.

Transparency

This is yet another tricky spot, I always make sure to set the following -D or system property flags for explicitly turning on either opengl or directx rendering. The flags I use are

// either

System.setProperty("sun.java2d.opengl", "True");
// or
System.setProperty("sun.java2d.d3d", "True");
System.setProperty("sun.java2d.ddforcevram", "True");
// and

System.setProperty("sun.java2d.transaccel", "True");

The capital T in True actually tells java2d to output to the console whether the accelerated rendering system was enabled this sometimes can be installation and system configuration dependant. I've had issues on some systems with both OpenGL and DirectX where they should be working but for some yet unknown reason they don't. I've also had issues with a WindowsXP hardware acceleration setting on the desktop causing sometimes reverse effects to java applications, when I figure this out I'll let you know. You'll get a message like this "OpenGL pipeline enabled for default config on screen 0" in your console or "Direct3D pipeline enabled on screen 0"

You can also optionally add logging to java2d to debug long rendering operations using:

System.setProperty("sun.java2d.trace", "timestamp,log,count");

*Warning* opengl driver support is kind of iffy on some NVIDIA cards on Windows, not sure what exactly the issue is but I have had reports of slow rendering with SLI cards. You'll have to experiment and offer a way of switching the flags that are turned on in order to get better performance. Additionally on a laptop I've had issues initializing DirectX I need to investigate more on that.


Test Code




Monday, March 25, 2013

Green Algae: Updates

Thought I'd do an update on the latest changes I've been making to my Green Algae project. It's one of those side projects that sometimes can be more enticing than the more serious projects. I feel it's good to have something on the side that is not under the gun or a time crunch it gives you freedom to work on it when your moved. Of course it's always easier to work on a project that is making progress. Spend too much time trying to move the code to the next step and you'll end up stagnating it. It's a funk you don't want to find yourself in, so either move on to something a little bit less challenging or that you've done before or risk spending way to much time on a road block.

Anyways just a little rambling thoughts to get your brain going. So without further adieu I'll lay out my current changes.

  • Changed tree image perspective to side view.
  • Modified map generation ever so slightly
    • Created worker threads during map generation
    • Was working on using a perlin noise generated map texture but stalled that for a little while to focus on gameplay
    • Reduced generation time from a couple minutes to around 10-15 seconds using the LMAX Disruptor Library, I was going to go with a ConcurrentLinkedQueue but I found the Disruptor a while back and had been meaning to attempt to pulverise things with it.
      • The slow down was due to drawing to a bufferedimage to create the minimap during map generation causing  major blocking to occur during generation
      • I had to tune the disruptor to a 4 core machine with an integrated graphics chip and no DirectX pipeline in the swing rendering.
      • I'm using only two EventHandler instances with a ring buffer of size 1024 
      • Haven't counted the number of draw calls which I further reduced by not drawing things that had already been drawn which actually increased the correctness of the minimap with respect to foliage now noticably showing.
  • Attempting to add bridge building, almost there just need to properly place bridge sections
  • Fixed issues with dragging logs from chopped down trees.
    • Turns out my grid partitioning scheme was to blame because the logs were not moving partitions when being dragged so drag one outside of it's partition and you wouldn't be able to drag it again, this works almost perfectly now, still some issues with duplicates being created when placing in piles.
  • Fixed collision volumes for trees and player to allow the correct overlapping. 
    • Changed from using radial colliders to box/rectangular colliders, the box/rectangular volume for the tree is now only at the base of the tree allowing the player to walk behind the tree
    • The players box/rectangular volume is now at the feet allowing for  the player to walk in front of  trees and other objects. Additional collision volumes will be necessary at some point to handle combat and other types of hit detections so a CompositeVolume using the composite design pattern will be necessary at some point.
  • Fixed render order with foliage (which are just trees right now).
    • They are now properly sorted, however the character does not display in front of them when it's supposed. I actually started using a TreeSet for the render sorting with a custom comparator, my Drawable interface which extends Comparator only sorts using layers and id values which id values are in order of instantiation which was not always coinciding with the correct order.


There are definitely more improvements to be made with regard to map generation and render order as in making sure moving objects are removed and added to the sorted Drawable collection, that should be pretty easy after changing the abstract Drawables compareTo method to use coordinates rather than simply layer and id.

I'll eventually get around to detailing a little bit more of the way the collision detection and space partitioning works, it's functional currently not feature complete but the abstraction is there for new strategies to be added.

I welcome questions for those interested in how any of the features work up to this point. Enjoy the screenies!