[ANN] RayMakie, the new PBRT based rendering backend!

We’ve been working on a new 100% Julia backend for GPU accelerated raytracing for Makie to replace RPRMakie!
Its physically based ray tracing (pbrt) and is pretty much a Julia port of the amazing pbrt-v4 ray tracer.
I also added an experimental rasterizer, which also runs on the GPU via KernelAbstractions - which could pave a way to have a 100% Julia GPU graphics API, which has the potential to rival OpenGL in the future (still pretty hypothetical, we will need to see how it matches performance and how well it works across platforms).
I just want to say, that I’m really happy with how the GPU stack has matured and how it has become possible to write this while reaching performance which is in the same regime as established ray tracers!
Read all the details in https://makie.org/website/blogposts/raytracing/.

Terrain with volumetric clouds Black hole with gravitational lensing
Protein structure from ProtPlot Protein structure (gold, DoF)
CMS particle detector (Geant4.jl) CMS detector full view
Oil palm (PlantGeom.jl) Stanford bunny cloud (NanoVDB)
BOMEX cumulus clouds Christmas tree (GLTF)
90 Likes

Really cool. My favourite is the gold ball dropping in water, looks gorgeous.

I hope there will be more demo’s at Julia4PDEs 2026 workshop at Vrije Universiteit Amsterdam!

6 Likes

Would it be possible to take advantage of RT-core-like hardware via Vulcan.jl in this context, in principle?

2 Likes

Awesome work!! Congratulations!

I saw that the post mentions NVIDIA and AMD GPU. What about Metal? Do we have support? If not, is there anything I can do to help supporting it?

2 Likes

This looks incredible. I’m very excited to find reasons to use it!

I have tried Metal many times while Simon was developing this and it never worked quite right. Not sure about the current state, last I tried was two weeks ago or so. Either the code would not compile at all, because Metal is a bit stricter than the other backends with requiring Float32 types. And when it compiled and returned an image, there was a weird issue that I assume is because of some race condition, maybe related to atomics? The visual effect was that objects looked more or less transparent because in each sample, they’d sometimes be hit by rays and sometimes not. This would even happen after I removed all random number generation from the kernels, so rays should have been completely deterministic across samples. I was not able to debug this yet, I dug in to a point where I could see nondeterministic behavior in the queue sizes but not where it ultimately stemmed from. Simon recommended to try and build up a simpler example of the problem than starting with the full tracer but I didn’t have time for that.

To test, you have to pass Metal.MtlArray as the backend type to the integrator.

2 Likes

Yeah, I hope we figure out Metal support soon!
I do bet a bit on claude code, which is pretty good at debugging these kind of problems when it is allowed to execute Julia code.
Usually its enough to dev all the involved packages and set it on one of the example scenes with a low resolution and sample count and tell it to fix all errors it encounters. It may also be required to guide it to towards creating MWEs until it has isolated the problems for harder problems (e.g. like the atomic operation bug).
Btw, the API has changed, so now one needs to pass device=Metal.MetalBackend().

4 Likes

In theory, yes!
In practice quite a lot would be required to get julia to compile to SPIR-V and have the RT core extensions available.
I do hope that the GPU infrastructure matures in that direction and I do think we have most of the puzzle pieces together for this (we do already compile to SPIR-V e.g. in OpenCL.jl).

2 Likes

Note that OpenCL is a different SPIR-V dialect than GLSL/Vulkan with stricter semantics regarding control flow etc., which complicates things a bit (there are already issues with the OpenCL dialect not supporting the way Julia throws exceptions for example). There has recently been some work on supporting GLSL SPIR-V in the LLVM backend, which might help, but I believe SPIRV.jl even decided to skip LLVM entirely

1 Like

Also, before the API changed, I was able get things alright. I remember I had to unroll the for loops in the kernels, otherwise all was messy and most of the times black. We will need to start again and see. I should have the MWE around, somewhere.

1 Like

Ideally, the same KernelAbstractions code would work for all backends, but there seem to be many differences left to account for..

Yeah, I tried it here but I could not make it even compile using Metal.jl

Never mind, it was not a compilation problem but my inability to install the correct packages and run the example :sweat_smile:

So you managed to render something with Metal with the current state of the package?

No! It turns out I could not even make the packages run. I thought it was compilation issues but it was not. I am still trying.

I finally managed to correctly instantiate the packages and tried to run the black hole example. The result was:

julia> Unhandled Task ERROR: InvalidIRError: compiling MethodInstance for Hikari.gpu_vp_finalize_film_kernel!(::KernelAbstractions.CompilerMetadata{KernelAbstractions.NDIteration.DynamicSize, KernelAbstractions.NDIteration.DynamicCheck, Nothing, CartesianIndices{1, Tuple{Base.OneTo{Int64}}}, KernelAbstractions.NDIteration.NDRange{1, KernelAbstractions.NDIteration.DynamicSize, KernelAbstractions.NDIteration.DynamicSize, CartesianIndices{1, Tuple{Base.OneTo{Int64}}}, CartesianIndices{1, Tuple{Base.OneTo{Int64}}}}}, ::MtlDeviceMatrix{ColorTypes.RGB{Float32}, 1}, ::MtlDeviceVector{Float32, 1}, ::MtlDeviceVector{Float32, 1}, ::Int32, ::Int32) resulted in invalid LLVM IR
Reason: unsupported use of double value

Does a sphere count? :slight_smile:

4 Likes

Try to start easy, maybe with some basic examples from Raycore.jl first.

Edit: and probably the branch sd/multitype-vec which is the one used for the complicated demos.

1 Like

I’m sorry, accidentally I clicked on “Flag this post”. I cannot find how to remove it :slight_smile: