So I've been working on a simple real-time raytracer using purely Java and now that I have most stuff working correctly from diffuse lighting and specular highlights to ray reflections and refractions I started wondering if I could make a minimalistic adventure game using this fresh engine of mine. Only thing preventing me from doing that is the poor performance in higher than 512x512 resolutions.
So I decided to read up a bit about multithreading in Java because I've never before needed more than one thread for my projects so I had no previous experience about that subject. So after that I tried various ways of implementing multithreaded rendering and finally got to a point where 4 threads render their given portion of the screen individually and pass it to the buffered image's pixel data which represents the screen. And I'm quite okay with that, the only real problem now is syncing the rendering with updating the whole image and I've tried numerous ways to do that but can't come up with anything good, it's always flickering or has some noise or is blocky because stuff is being rendered all the time even when refreshing the screen.
Here's my project's source code in github, the rendering is done in Engine.java: https://github.com/Harha/JRay
I've tried to look for answers regarding this via google and from stackoverflow directly with no luck, noone seems to really have done something like this publicly in the past or then I'm just bad at searching for things. Anyways, I'm out of ideas and wondered if someone here could come up with some sensible answer which could be used to sync all the rendering threads with the main thread that's updating the bitmap.
Thanks in advance, I by no means want to be spoonfed but as I said, I really am out of ideas for this...
Edit: Here's my fixed run loop.
/*
* Main run method.
* Handles the update and render methods.
*/
public void run() {
for (int i = 0; i < THREAD_COUNT; i++) {
updateDelta(i);
lastFPS[i] = getTime();
}
requestFocus();
while (running) {
updateDelta(0);
update(delta[0]);
runRenderThreads();
try {
e.awaitTermination(10, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
render();
}
stop();
}
It waits for 10 milliseconds for render threads to finish their given task, if that time is exceeded then it just renders the image to the buffer in render() and starts over and doesn't care if tasks pile up.
Ray tracing is actually a prime example for multi-threading because of the easy task distribution and the big performance requirement so this has definitely been done before.
I recommend that you use double buffering. That is, you don't paint directly on the screen but on an invisible buffer and assign the same amount of pixels to each thread there. You wait until each thread is done and then swap the visible with the invisible buffer and begin with the new image. If you still get flickering, try vertical synchronization.
Pseudo-Code
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class Raytracer
{
final static int THREADS = 4;
public static void main(String[] args) throws InterruptedException
{
ExecutorService renderPool = Executors.newFixedThreadPool(THREADS);
while(true)
{
for(int i=0;i<THREADS;i++)
{
renderPool.execute(createRenderThread(i));
}
if(renderPool.awaitTermination(1,TimeUnit.MINUTES))
{
// delay here in case you want to artifically limit the frame rate
// v-sync if necessary here
swapBuffers(); // should be available from your graphics library, e.g. open GL
}
}
}
private static Runnable createRenderThread(final int i)
{
return new Runnable()
{
@Override public void run()
{
for(int x=..;x<..;x++)
for(int y=..;y<..;y++)
render(x,y);
// do something ...
}
};
}
}