Live data from Hacker News

Writing a small ray tracer in Rust and Zig

nelari.us

11–20 of 98 posts

Re: Writing a small ray tracer in Rust and Zig

#11
post #7

> I wrapped my objects in atomic reference counters, and wrapped my pixel buffer in a mutex Rust people, is there a way to tell the compiler that each thread gets its own elements? Do you really have to either (unnecessarily) add a lock or reach for unsafe?

Yes, there's `chunks_mut` [0] in the standard library that separate the slice to multiple non-overlapped chunks.

[0]: https://doc.rust-lang.org/std/primitive.slice.html#method.ch...

Re: Writing a small ray tracer in Rust and Zig

#12
post #7

> I wrapped my objects in atomic reference counters, and wrapped my pixel buffer in a mutex Rust people, is there a way to tell the compiler that each thread gets its own elements? Do you really have to either (unnecessarily) add a lock or reach for unsafe?

Yes. Instead of having a single slice of pixels, split it into n slices, one for each thread.

Re: Writing a small ray tracer in Rust and Zig

#13
post #7

> I wrapped my objects in atomic reference counters, and wrapped my pixel buffer in a mutex Rust people, is there a way to tell the compiler that each thread gets its own elements? Do you really have to either (unnecessarily) add a lock or reach for unsafe?

> Rust people, is there a way to tell the compiler that each thread gets its own elements?

That's what `local_pixels` does in the post. Where things get trickier is when you want to share write access to a single shared buffer in a non-overlapping way (e.g. `buffer` in the post.) To do this you need to either resort to unsafe, or to prove to the compiler that the writes aren't overlapping. One way to do the latter this is to get a slice (which Vec is convertable into), and then split up that slice (which the standard library has plenty of methods for: https://doc.rust-lang.org/std/slice/index.html ), and then give each thread those non-overlapping slices.

Re: Writing a small ray tracer in Rust and Zig

#14
post #7

> I wrapped my objects in atomic reference counters, and wrapped my pixel buffer in a mutex Rust people, is there a way to tell the compiler that each thread gets its own elements? Do you really have to either (unnecessarily) add a lock or reach for unsafe?

If you want to use completely safe Rust, you could probably get the Vec as a `&mut [u32]`, then use `.split_at()` on the slice to chop up the buffer into multiple contiguous sub-pieces for each thread. Collect up those pieces behind a struct for easier usage. It would cost you an extra pointer + length for each subpiece, but that's the price for guaranteeing that no thread reaches outside the contiguous intervals assigned to it.

EDIT: As mentioned by a sibling, `chunks_mut` is probably closer to what you want in this instance. If you have to get chunks of various sizes -- for instance, if the number of threads doesn't evenly divide the buffer into nice uniform tiles -- you'd need to drop down to the `split_at` level anyway.

Re: Writing a small ray tracer in Rust and Zig

#15
post #7

> I wrapped my objects in atomic reference counters, and wrapped my pixel buffer in a mutex Rust people, is there a way to tell the compiler that each thread gets its own elements? Do you really have to either (unnecessarily) add a lock or reach for unsafe?

It's a library, so only half an answer to your question, but there's a fantastic library called rayon[1] created by one of the core contributors the the Rust language itself, Niko Matsakis. It lets you use Rust's iterator API to do extremely easy parallelism:

  list.iter().map()
becomes:

  list.par_iter().map()
Seeing as in the original example code, the final copies into the minifb have to be sequential due to the lock anyway, all the usage of synchronization primitives and in fact the whole loop could be replaced with something like:

  let rendered = buffers.par_iter().map().collect();  
  for buffer in rendered.iter() {  
    // The copy from the article  
  }
I've not written much Rust in a while, so maybe the state of the art is different now, but there are a lot of ways to avoid having to reach specifically for synchronization primitives.

Re: Writing a small ray tracer in Rust and Zig

#17
post #7

> I wrapped my objects in atomic reference counters, and wrapped my pixel buffer in a mutex Rust people, is there a way to tell the compiler that each thread gets its own elements? Do you really have to either (unnecessarily) add a lock or reach for unsafe?

I wonder if there’s a way to borrow noncontiguous slices.

https://blog.rom1v.com/2019/04/implementing-tile-encoding-in...

Re: Writing a small ray tracer in Rust and Zig

#18

> But rendering in separate threads turned out to be (unsurprisingly) harder than the way I would do it in C++...It was a bit frustrating to figure out how to accomplish this. Googling yielded a few stack overflow posts with similar questions, and were answered by people basically saying use my crate! Based on some discussion in r/rust ( https://www.reddit.com/r/rust/comments/c7t5za/writing_a_smal... ) I went ahead a…

I still don't understand why Rayon is not part of the Rust standard library.

Rust was created to have easy and safe multithreading on the CPU, and Rayon is the clear winner in this space, for me it feels like something that should be part of Rust.

Re: Writing a small ray tracer in Rust and Zig

#19
post #7

> I wrapped my objects in atomic reference counters, and wrapped my pixel buffer in a mutex Rust people, is there a way to tell the compiler that each thread gets its own elements? Do you really have to either (unnecessarily) add a lock or reach for unsafe?

I wonder if there’s a way to borrow noncontiguous slices.

Yes, the standard library has many methods for splitting up a single mutable slice into multiple non-overlapping mutable slices. There's split_at_mut() which just splits at an index, or split_mut() which splits using a predicate, or chunks() which gives you an iterator over non-overlapping subslices of a given length, and more.

Re: Writing a small ray tracer in Rust and Zig

#20

> But rendering in separate threads turned out to be (unsurprisingly) harder than the way I would do it in C++...It was a bit frustrating to figure out how to accomplish this. Googling yielded a few stack overflow posts with similar questions, and were answered by people basically saying use my crate! Based on some discussion in r/rust ( https://www.reddit.com/r/rust/comments/c7t5za/writing_a_smal... ) I went ahead a…

I still don't understand why Rayon is not part of the Rust standard library. Rust was created to have easy and safe multithreading on the CPU, and Rayon is the clear winner in this space, for me it feels like something that should be part of Rust.

The Rust stdlib is specifically intended to be as lightweight as possible (while still providing those idiomatic abstractions that might be needed throughout the ecosystem, e.g. std.future) in order to avoid the Python "dead batteries" problem.

What the Rust ecosystem is still lacking is a quasi-standard "Rust Platform" of best-practice library components where the community can freely deprecate something when a clearly better replacement comes along. There are a few "community" websites that try to provide guidance wrt. some parts of the Rust ecosystem, but nothing that feels even close to official or consensus-driven.

Post reply on HN