[java] Java rendering speed

Started by
18 comments, last by Absolution 19 years, 6 months ago
A few friends and I have been working on a java raycasting engine similar to wolf3d. Although java has gotten exceptionally fast at 2D image blitting and effects, its still rather lacking in terms of per-pixel direct buffer access, which our rendering engine needs. There's simply too many layers between the program and image data. So far the fastest way we've found to render a scene is using a MemoryImageSource so that we can use a simple packed int RGB format array for rendering. This has gotten some pretty decent results, but we still want to squeeze as much speed out as possible. The game/engine is very similar to the one developed by david brackeen at http://www.brackeen.com/home/scared/ Even with the MemoryImageSource method, there's still alot to be desired. The array is in packed RGB int format, which means that for the image to be rendered, it has to be copied, converted to the target pixel format, and finally displayed. Does anyone know a faster way to render and still have direct (well, as direct as possible) access to the image data?
"I never let schooling interfere with my education" - Mark Twain
Advertisement
Try using a Doom style BSP renderer rather than Wolf3D raycasting. It's much more computationally efficent, and gives you non-orthoganal walls. You can simplify it by using flat levels like Wolf3D.

Skizz
Thats planned in the future. The raycasting that we have now is pretty efficient however, and from profiling we've determined its now whats slowing the engine down. Its the rendering of the walls and floors thats really taking the cake.
"I never let schooling interfere with my education" - Mark Twain
Quote:Original post by Rocket05
Although java has gotten exceptionally fast at 2D image blitting and effects, its still rather lacking in terms of per-pixel direct buffer access, which our rendering engine needs.


I used to do something similar 6 years ago when I was writing software 3D engines in Java. Although it's fun to do these things at first, frankly I don't see why you'd bother trying to "squeeze performance" out since you're barking up the wrong tree: nowadays in java you should generally be using OpenGL.

Anyway, from memory it is possible to go pretty damn fast right now. There are several tricks to do along the way (just like with any graphical pipeline...). The most important are to take advantage of Java's managed images (can't remember the current name - volatile, managed, etc - don't care; it's about to be renamed anyway!) which go into VRAM where possible and stay there if you code carefully. The difference between software blitting and hardware blitting + page-flipping is considerable!

There's plenty of tutorial matter around on that subject, so if you don't already know the ins and outs of hw-accelerated images you just need to google. Be careful to seek out and understand the various conditions that will force your image out of VRAM; at first glance, these may make pixelrendering seem impossible, but mostly you just have to think more carefully about what you're doing and how.

Beyond that, I'm afraid I don't remember most of the tricks (it's been a long time), but one I DO remember is that JVM's have historically been poor at converting between colour modes, and that carefully matching your Image formats etc to the current desktop screen mode can make a big difference (simply because of the time incurred in behind-the-scenes colour-conversion between different RGBA / ARGB / 555 / 8888 / etc).

It used to be a right PITA to get your JVM rendering purely in the correct appropriate mode. Nowadays you can explicitly create images in particular modes, but you might also want to check out the ColorModel classes and interrogate your JVM and see how that differs from what your desktop / display driver is actually doing.
BufferedImage
MemoryImageSource is about as good as it gets, assuming you've done it correctly. You wan't to use a single MemoryImageSource instead of creating a new one every frame, wich I'm sure you know more about than me. You can also try getting the data buffer from the raster: "((DataBufferInt) image.getRaster().getDataBuffer()).getData();", but I doubt it's any faster.

The hardware blitting that redmilamber mentioned has some major limitations wich makes it irrelivant for your case. Basicly you can only draw static images. Would be great if you did a tiling 2d game, but is less usefull in most other cases.
Actually, write your own implementation of MemoryImageSource - it's not hard - strip it down, on some very simple blitting (2D bilinear filtering of a texture) I got a 3x speed increase. You implementation should be about 20 lines long if I remember correctly.

Oh and method calls are bad news :)
-- Jonathan
I tried the BufferedImage.getRaster().getDataBuffer().getData() (long trace ;)) method, and it seems to be working almost twice as fast. Only had to change about 10 lines of code to get it working, because the resulting int array is exactly like the one I was using from MemoryImageSource. I think this can be sped up even more by using a BufferedImage created using GraphicsConfiguration so that the colormodel will match that of the desktop, however this will take longer to implement and test (right now im just creating a new BufferedImage(), standard INT_RGB color model).

I'm also thinking with hardware acceleration, it might possibly be faster to load the textures into video memory, and scale blit columns at a time as they're needed? I really have no idea if this would be faster. This would also take a lot of work to change the code to work this way, does anyone know the answer to this one before we try it?

Sprite blitting might also benefit from hardware acceleration, but the biggest problem is dealing with the depth buffer while blitting. Possibly, still needs to be tested.

Of course this is all assuming that hardware blitting supports scaling, and on hardware without hardware support, the software pure java method might be faster.

btw thx for all your help so far people ;)

oh yeah, the reason that we dont just use an OpenGL or java3d binding is that we're trying to target the broadest range of computers possible, not just gaming computers, and we're trying to make the game fast enough to run even on (today's) low end machines, i.e. about 700mhz with a generic video card (what most of our school computers have, where software 3d is faster than opengl).
"I never let schooling interfere with my education" - Mark Twain
Check this link.

To clarify; Your problem with rendering speed has NOTHING to do with java. By performing rendering operations one pixel at a time you may as well be using the win api and windows gdi ie its going to be SLOW. To modify the pixels of an image the image must reside in main memory which is ALOT slower than vram (obviously).

Quote:Original post by Rocket05
I tried the BufferedImage.getRaster().getDataBuffer().getData() (long trace ;)) method, and it seems to be working almost twice as fast.


This is fast but it doesn't work on 1.1 vms. (No BufferedImage)

Quote:I'm also thinking with hardware acceleration, it might possibly be faster to load the textures into video memory, and scale blit columns at a time as they're needed? I really have no idea if this would be faster.


Again, to access pixel data from a managed image you have to fetch from vram then blit to main memory. PixelGrabber/getDataBuffer will most likely disallow the texture from being cached anyway. Main memory to main memory is the way to go.

Quote:Sprite blitting might also benefit from hardware acceleration, but the biggest problem is dealing with the depth buffer while blitting.


Again, think about were the data resides.

Quote:oh yeah, the reason that we dont just use an OpenGL or java3d binding is that we're trying to target the broadest range of computers possible, not just gaming computers, and we're trying to make the game fast enough to run even on (today's) low end machines, i.e. about 700mhz with a generic video card (what most of our school computers have, where software 3d is faster than opengl).


Then you definitly want AWT/MemoryImageSource. You can always check the java version and load a rendering class that uses BufferImage/getDataBuffer() for users that can use it.

Or do everyone a favor and redirect your users to the sun site to download a current JRE.
That definetly provided some much needed insight, thanks.

So I guess things can't get much faster... unless we use native methods, but we're hoping not to use those unless we really have to.
"I never let schooling interfere with my education" - Mark Twain

This topic is closed to new replies.

Advertisement