Sign in to follow this  

[java] Java rendering speed

This topic is 4836 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

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?

Share this post


Link to post
Share on other sites
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

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
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.

Share this post


Link to post
Share on other sites
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 :)

Share this post


Link to post
Share on other sites
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).

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Quote:

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.


It only makes it irrelevant if you don't bother to try take advantage of it. I said you had to be cunning; I've seen plenty of situations where developers WERE cunning, and managed to get not quite the best of both worlds, but certainly noticeable performance improvements.

Also, c.f. Chet's article:

"Developers that care about top performance for these types of images may want to look into using VolatileImages instead. These images store the data in accelerated memory (when possible) and thus rendering to and from that image may be accelerated automatically. The downside is that these images require a bit more care and feeding, due to "surface loss" issues that arise with current video memory architectures and operating systems. Note that not all types of rendering to these images is accelerated, either, but simple types of rendering like lines and rectangular fills and copiescan usually be accelerated, depending on the platform configuration."

...so, with a bit of refactoring of your rendering, and a bit of cunning, and a tiny bit of effort to handle surface loss, you can make at least *some* use of hardware.

For instance, I've seen people often think of ways to replace per-pixel effects with pixel-tile effects. As one example, if VNC's authors had taken AP's approach and given up, then it would never have worked: instead, they decomposed their rendering into hextiles.

For the game engine, you should be able to work out some patterns of pixels that are often used and blit them - or even use the primitives (like line-drawing) directly onto a VolatileImage. etc.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Quote:
Original post by Rocket05
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 appreciate your predicament, and the fact that your school has a lot of computers with a particular configuration, but bear in mind also that most people with sub-1Ghz PC's IME seem to have 3d cards in there, usually a cheap ATI RagePro-based chip (they were very common in mass produced home user and corporate PC's for a long time in the P-2 and P-3 days), or a TNT2, or a Matrox G200 derivative. All of these are much faster than CPU rendering until you buy a CPU circa 2.5 Ghz, IIRC.

They're crappy, but worth using if you can.

redmilamber

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Quote:
Original post by nonnus29
To modify the pixels of an image the image must reside in main memory which is ALOT slower than vram (obviously).


No, only if you use certain image types. It is possible to modify images in VRAM, but java has only limited support for doing so.

Basically, you are stressing the efficiency of the AGP bus when you do so - but note that the AGP bus has a lot of bandwidth to spare on upload to the card, and latency is good (though not excellent).

So, it's worth trying. Obviously, it's best to blit to VRAM if you can, since this is effectively batching bus data, i.e. making using of the fact that AGP bandwidth is a heck of a lot better than AGP latency.

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.[/quote]

What ?!?!? He said that they have low hardware, NOT low JRE's.

If in doubt, you should be using a managed BufferedImage for everything, since they are accelerated if they can be, and there's generally no penalty if not.

Share this post


Link to post
Share on other sites
My bad, I misread that part.

Quote:
For instance, I've seen people often think of ways to replace per-pixel effects with pixel-tile effects. As one example, if VNC's authors had taken AP's approach and given up, then it would never have worked: instead, they decomposed their rendering into hextiles.


Whats the VNC of which you speak?

On windows, even for managed images DirectDraw is used (until java 5 final when opengl will be use?) so even 2d tile blitting isn't THAT fast especially now that newer cards have poorer support for 2d blitting than the old cards.

But most likely attempting to optimize your technique for certain hardware/paths can make the finished product nonportable. So... yes, managed BufferedImages for software rendering, I'll go along with that.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Quote:
Original post by nonnus29
Whats the VNC of which you speak?


The original free remote-desktop program, which has versions available for most OS's and even a java version, so you can fullscreen to any other computer from your own one as if you were sitting there.

Obviously, sending 1024x768 (or more!) 24 bpp even over a LAN 20 times a second (minimum not to get really annoyed) is not easy. So, VNC used a lot of tricks to compress data based on domain-specific knowledge (e.g. most windowing systems use windows etc).

Share this post


Link to post
Share on other sites
well considering its a wolf3d like raycasting engine, i think it might be possible to use hardware blitting to generate most of the scene (the walls) because the patterns are consistent (the textures are static). This would mean that the engine would have to make 320 blits of one pixel wide columns of pixels from textures onto the screen, with a scaled height. This sounds like its worth a try, although floor and ceiling's are going to be different because the pattern isn't exactly consistent, they still need to be done per-pixel.

Thanks for all your help on this issue, its given me plenty of new ideas to try. When the game is finished i'll try to come back here and write either a forum post or an article on what i've learned in trying all these techniques.

Share this post


Link to post
Share on other sites
java sucks so hard in per-pixel stuff it simply isnt funny anymore.

you definitly want to do your effects in ram and then pump them over your agp bus in one go. SDL does it in a fraction of the time java did, and believe me ive tried.

exploiting hardware might be a good idea indeed tho. blitting scaled collumns of your textures should be possible in your situation, and i think thatd give a huge speedboost.

Share this post


Link to post
Share on other sites
It's basically all been covered, but it depends on the version of java you are running. MemoryImageSource for 1.1, and BufferedImage for others. I've been writing a software 1.1 engine in my spare time. I've tried just about every trick, but MemoryImageSource is the fastest for what I was doing. I tried writing my own, but it didn't speed up my application.

http://www.freestandingentertainment.com/chance/test3

Share this post


Link to post
Share on other sites

This topic is 4836 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this