Select devices and use several GPUs
Choose the CUDA device for each RayD backend, replicate a Torch scene across GPUs, and run one process per GPU.
RayD runs every query on one NVIDIA GPU. This guide shows how each backend picks that GPU and the three ways to use more than one.
Pick the device#
The Dr.Jit backend follows Dr.Jit's current-thread CUDA device. Select it before you create meshes, scenes, or arrays:
import rayd.drjit as rd
print(rd.device_count()) # visible CUDA devices
rd.set_device(0) # initialize_optix=True also creates the OptiX context
print(rd.current_device())Do not reuse scenes or OptiX resources across a device switch in the same process.
Replicate one Torch scene across GPUs#
Scene(devices=[0, 1]) builds a full copy of the scene on each device. Each query splits its batch of rays across the copies and returns results and gradients on the first device. Per-ray results are bitwise identical to a single-device run; accumulated grids match up to float32 summation order.
scene = rt.Scene(devices=[0, 1])
scene.add_mesh(rt.Mesh(vertices, faces))
scene.build()
hit = scene.intersect(ray) # ray tensors on cuda:0; result on cuda:0MultiDeviceOptions tunes the split:
| Field | Default | Effect |
|---|---|---|
weights | equal | share of the batch per device, as a ratio |
operation_weights | None | weights for one operation family ("intersect") or exact shape ("trace_reflections:4") |
require_peer_access | True | reject devices without CUDA peer access |
require_homogeneous_devices | True | reject a mix of GPU models |
warm_up | True | pre-link OptiX pipelines on every device during build() |
chunk_rays, tape_memory_budget_bytes, offload | None | run the batch in chunks to bound memory |
pipeline, pipeline_chunks_per_device | True, 4 | overlap copies and compute |
min_rays_per_device, min_lanes_per_device | 262144 | below this size, run on the first device only |
opts = rt.MultiDeviceOptions(weights=[0.6, 0.4])
scene = rt.Scene(devices=[0, 1], options=opts)To measure the split instead of guessing it, call scene.calibrate_devices() after build(). It times a probe (intersect by default, trace_reflections with max_bounces set) on each device and stores the fastest split for that operation. Read it with scene.device_weights_for("intersect"). A scene with fewer than two devices raises RuntimeError.
Splitting pays off for compute-heavy work and large accumulations. Cheap queries with wide results can be slower on two GPUs, because the rays and results cross the interconnect.
Note
add_instance is not available on a multi-device scene. Diffraction accumulation splits its Monte Carlo sample window, not a ray batch.
One process per GPU#
The Dr.Jit backend has no in-process multi-device mode. Run one process per GPU and pin each one with CUDA_VISIBLE_DEVICES. The same recipe works for Torch and across nodes, for example with torchrun.
- Give every process its own
OPTIX_CACHE_PATHso that concurrent processes do not share one OptiX disk cache. - To split a Monte Carlo accumulation such as
accum_dfr_direct, give each rank a disjoint window of the sample space withlane_offsetandlane_count, then sum the grids (for example withall_reduce). The sum equals the single-run grid up to summation order.
The RayD repository has runnable recipes under examples/torch/distributed.