Your GitHub program runs correctly for me. It generates the "parallel-rendering.png" output image, which has no artifacts.
I would suggest running your program without parallelism, to see if that makes a difference. Otherwise, I guess you could log every pixel and the value that was calculated for it.
This won't solve your problem but you can write this shorter like this:
if let Ok(mut buffer) = image_buffer_lock_result {
// conduct gamma correction over the pixel
buffer.put_pixel(*x, *y, Rgb(Util::gamma_correction(&pixel_color, self.samples_per_pixel)));
}
As a note on that. Yes that's probably the reason for the black pixels. But on the other hand doing this synchronization is probably not a good idea in the first place. It's probably better to use map and collect instead of for_each and then write the buffer from a single thread. This way you don't let the threads compete with each other.
Not sure if that's true though. Probably depends a bit on how many threads you have and how long the ray tracing takes compared to do the writes into the buffer.
Or maybe you can par_iter_mut directly over the buffer.
Instead of iterating over just (x,y) coordinates in a shared buffer, you should use an iterator that gives you &mut Rgb for every pixel, and iterate that in parallel. This way every reference will be guaranteed to be separate, and you will not need any locking of the image buffer.
You don't need to change the struct definition, but instead take the lock once outside the iterator. You can then use RgbImage::par_enumerate_pixels_mut to make your iterator instead of manually indexing into the image.
Something like this (untested):
pub fn trace(&self, cam: &Camera, world: &World, bar: &ProgressBar ,max_depth: u32) {
let locked_buf = self.image_buffer.write().unwrap();
locked_buf
.par_enumerate_pixels_mut()
.progress_with(bar.clone())
.for_each(|(x, y, px_out)| {
let mut pixel_color = Color::new(0.0, 0.0, 0.0);
// calculate pixel color for (x, y) here ...
*px_out = Rgb(Util::gamma_correction(&pixel_color, self.samples_per_pixel));
}
});
}