The results are surprising - realtime raytracing of simple scenes might be possible with Java on current computers. The preview doesn't look like much, but textures won't cause a big slowdown, and the two spheres have mirror surfaces, so the core features of raytracing, reflection and refraction seem to be doable. Lightsources and shadows will cause a slowdown though. For this scene, I'd estimate 30% slowdown for each additional light source. I'll find that out soon. In the demo the balls circle around the center of the checkerboard plane, so there shouldn't be any caching messing with my timings since each frame is different from the former.

Using one thread on a 2.5 GHz core i5 I get about 30FPS with my current code and three scene elements (two reflective) and 800x600 pixels.

I hope I can optimize the tracer itself some more, and when using all (virtual) cores of the CPU there might be a speedup of 3 or more in reach, which is looking promising.

I hope to get a little graphics demo out of this, wanted to do something like that since a while

Textures took a while, but I now have textures and two worker threads in place to parallelize the rendering process. Didn't result in such a big speedup, and the thread synchronisation was quite tricky, but it works.

I've put a demo up - I'm curious to hear if and how well this works on other systems. It does a few ugly hacks in the graphics code, and I feel uncertain if this will work well on other systems ...

It's an executable jar file, a double click should run it if you have Java 7 installed.

Also I'm curious how high/low the FPS will go on other PCs. I'm getting something like 30 FPS in average, but the movement isn't all smooth because some frames take notably longer to render than others. I have not yet found out why. Initially I thought it would skip frames or double-show buffered frames, but the double buffering seems to be alright. It's indeed the calculation time itself that can go up by 30% for some frames.

Anyways, looks promising and I want to add some light and color effects now to work into the direction of a graphics demo.

Edit: Resizing the window can annoy the rendering code to the point when it stops rendering. If you want to reproduce the bug, you have a 99% chance that resizing will work

Nor will it work with LWJGL, until the devs fix it. So even if I did purchase Mountain Lion, I would need to switch back and forth between JREs in order to run Java 7 apps, Chrome applets and any LWJGL apps.

So basically Java 7 will cost me $30, a long download on my slow wifi, a lot of trouble, and of course all the little problems that tend to come with upgrading your operating system. Not worth it to run a Java 2D application which has no real reason to target JRE7 in the first place.

The whole thing is a pain in the ass. And all of this for string switch?

Why did you need any synchronization? It should be possible to do the ray tracing for each pixel in parallel without any synchronization at all. Shouldn't each pixel only depend on its own ray?

Synchronization was maybe a bit misleading. The problem is that the display thread needs to wait till all rendering threads have finished, and then switch the buffer and display the frame while the rendering threads work on the next frame.

Each pixel is independent. Just the threads must keep some order so that the parts come together in the right frame.

I'm not sure if I did it right, but I tried to compile it with "Java 6 binary level", and I hope this will execute with Java 6, too:

It's also got a bugfix for the mentioned thread synchronization. It might be a tad faster than before. Tomorrow I'll try to work some more on it. Do the current AMD and Intel CPUs have two real FPUs, or even more?

Intel has one per physical core, older AMDs had that too. Newer AMDs (Bulldozer) have one per module (which includes 2 integer clusters), but that one can be used by both clusters and switches pretty fast. On my Core i7 (4 cores, 8 threads), i get 57fps with a cpu load of 25% (i.e. 2 of the 8 possible threads are at 100%).

Thanks! And thanks again for testing on a Mac. It's good to know that it works there, too.

The stuttering will stay until I try to smooth out the display of frames. At the moment each frame is displayed once it it is ready, and the rendering code for some reason has a notable jitter in the rendering times.

With some luck I could solve the deadlock though. it seems all three threads could run into a "wait()" call, and waited for a notify to continue, which never came because all threads were waiting ... I need a clear head and some sleep to look into this again.

I guess my graphics tricks don't like that. Can you run it from a console window, and see if there is a ClassCastException or ArrayIndexOutOfBounds exception thrown? I had to reach deep into the raster classes to get Java2D working as a framebuffer for me.

I assume it ran into a deadlock. Till today I didn't know that multiple notify() calls can cause only one wait() to wake up if they happen at exactly the same time (and it happened ...)

I once more changed the threading concept. I hope it now works without deadlocks. It starts 8 rendering worker threads and one program thread, and is capped at 60 FPS for those with real powerful machines. I can't test the capping though, I don't reach that much FPS with my hardware

3 mirror balls, one infinite plane and a sky sphere, give me ~30 FPS. I'm somewhat certain that I can't achieve big speedups anymore, but I'll see what I can do with it. It's a nice toy for sure

@Roquen: I've got one volatile variable which is increased by the worker threads to count how many workers are done yet. Now that you mention it, I must say that I'm not quite sure what happens with the frame buffer, which is written to by all worker threads.

@alesky: Thanks

@ra4king: Wow, that is some gaming equipment you have there! Raytracing is a simple concept, but vector math ... well you know how to use OpenGL, so I assume have already learned most it

I assume it ran into a deadlock. Till today I didn't know that multiple notify() calls can cause only one wait() to wake up if they happen at exactly the same time (and it happened ...)...@Roquen: I've got one volatile variable which is increased by the worker threads to count how many workers are done yet. Now that you mention it, I must say that I'm not quite sure what happens with the frame buffer, which is written to by all worker threads.

A volatile variable is probably not a good idea. Increment is a get and set operation which is not thread safe. How about AtomicInteger?

Given that threading is hard, and prone to issues, how about using some of the concurrency utils built in to the JDK? You could use an ExecutorService to manage the worker threads, and have your render thread wait on each Future.get() in turn.

I guess my graphics tricks don't like that. Can you run it from a console window, and see if there is a ClassCastException or ArrayIndexOutOfBounds exception thrown? I had to reach deep into the raster classes to get Java2D working as a framebuffer for me.

What does that mean exactly? Are you working directly with an int[] of pixels? Where are you getting them from - a BufferedImage? If so, you could also build an image from your array rather than trying to get the array from the image - this code might help (PixelData is just a wrapper to an int[] and dimensions, etc.)

A volatile variable is probably not a good idea. Increment is a get and set operation which is not thread safe. How about AtomicInteger?

Maybe I was wrong again. I thought an x++ is an atomic operation in Java. I didn't look into the new concurrency classes yet (I've been working with Java 1.4 tooo long ...), but I heard they are useful. AtomicInteger is new to me, but seems to be what I should have used there.

What does that mean exactly? Are you working directly with an int[] of pixels? Where are you getting them from - a BufferedImage?

BufferedImage -> WriteableRaster -> DataBuffer -> int []

I've been surprised that it was actually accessible. But I must admit my last try to dig into the graphics internals was done with Java 1.2, and my memory says that the structures were not so easily accessible back then.

If so, you could also build an image from your array rather than trying to get the array from the image - this code might help)

That's about what I have been doing, just that they build an BufferedImage from the data, while I wanted to write into the buffer of an already existing BufferedImage. But thanks, it's good to know that the method is used, and that it's not as hacky as I had assumed

At least it opened a lot of options for me, since I was/am used to working with frame buffer devices and I can now use a lot of tricks that I was used from my older projects. Writing all pixels in a loop gave me 144 FPS on my PC, using one thread. That seemed to have plenty of reserves for application code, and was much faster than my former tries to display graphics with Java2D, which were more like giving 15-20 FPS. My bigger game projects don't need it right now, but it's good to know that once can use Java this way nowadays

The only question that really puzzles me is why drawing operations including alpha blending are so slow for volatile images on some graphics adapters. On my PC drawing semi-transparent buffered images to a volatile image resulted in like 400 FPS and on my laptop about 20 FPS. This is too much difference to be easily understood by my poor brain

I've been surprised that it was actually accessible. But I must admit my last try to dig into the graphics internals was done with Java 1.2, and my memory says that the structures were not so easily accessible back then.

Nothing (relevant) has changed as far as I can see. You just need to be careful where you're getting the BufferedImage from and what format it's in. Any TYPE_INT_* should give you an int[] though, so might not be the cause of Julien's issue. It's not hacky either - it's what BufferedImages were designed for! The code I pointed to is mine btw - feel free to use anything from that class without worrying about the license.

Slight bit of pedantry, but I'd say the title of this thread isn't entirely accurate - if you're doing all the raytracing through direct array manipulation it's not really in Java2D.

The deadlock in r3 was caused by something else. I don't think someone has given feedback to the r4 yet (the one with the volatile int for the workers done count). But just to be safe, I've changed that to an AtomicInteger:

There was also a bug in r4 that disabled the 60FPS cap. I still couldn't test it, but in r5 it's at least enabled.

Regarding the buffered images, maybe I just didn't know the right was when I tried it first. Well, at least I know it now and I'm happy that it works

And yes, I've taken care to create a BufferedImage of TYPE_INT_RGB, in the hope that those will always get an IntDataBuffer. Maybe Julien just ran into an immediate deadlock, I dunno. If the r5 works, I'll blame my buggy threading.

I'd say do it like this:1. Start X threads when the program starts.2. When you want to render, signal the threads to start in some way.3. Then each thread gets and increases an AtomicInteger to get a pixel index. Each thread then processes for example 1000 pixels or so, basically something like this in a loop:

The point of using the PIXEL_PER_BATCH variable is to reduce the amount of synchronization so that you don't have to synchronize per pixel. However, we still want to have a pretty big number of subtasks since each subtask can take a very different amount of time depending on what geometry it hits.

The deadlock in r3 was caused by something else. I don't think someone has given feedback to the r4 yet (the one with the volatile int for the workers done count). But just to be safe, I've changed that to an AtomicInteger

When using volatile variables, you have a guarantee that the value you read is from the main memory, instead of from the processor cache. This does not mean you can increment it reliably from more than one thread, as an increment is basically:

1 2 3 4 5 6

volatileintcounter;

{intn = counter;counter = n + 1;}

You can see how the read and the write are two instructions, so multiple threads can and up interleaving these instructions, causing lost increments.

Just using AtomicInteger doesn't solve it, as it's just a volatile integer underneath. You must use

counter.incrementAndGet()

or

counter.getAndIncrement()

as they have the required functionality (compare-and-swap) to guarantee increments from multiple threads.

Hi, appreciate more people! Σ ♥ = ¾Learn how to award medals... and work your way up the social rankings!

Just to say, since posting earlier I've given this a go (r5). Good work! I get a steady 30fps with OpenJDK 1.6 on Ubuntu 12.04 - Intel® Core™ i5 CPU M 430 @ 2.27GHz × 4 Top gives me this running at ~300% CPU (100% per virtual core).

java-gaming.org is not responsible for the content posted by its members, including references to external websites,
and other references that may or may not have a relation with our primarily
gaming and game production oriented community.
inquiries and complaints can be sent via email to the info‑account of the
company managing the website of java‑gaming.org