portableRT is a C++ library that enables your application to perform ray tracing using all available hardware through a single API. On CPUs, it uses Embree. On GPUs, the user can choose between a general GPGPU approach, ideal for older or compute-focused GPUs without dedicated ray tracing units, or make use of the hardware-accelerated ray tracing units (when available)
This first version is extremely simple and focuses solely on intersecting a ray with a triangle using all the available backends. It currently works with all the available GPUs Ray tracing cores.
Device Type | Recommended Backend |
---|---|
NVIDIA GPUs with RT cores | OPTIX |
AMD GPUs with Ray Accelerators | HIP_ROCM |
Intel GPUs with Ray Tracing Units (RTUs) | EMBREE_SYCL |
x86_64 CPUs (Intel/AMD) | EMBREE_CPU |
Non-x86 CPUs (e.g. ARM, RISC-V) | CPU_SCALAR |
GPUs without dedicated ray tracing units (any) | SYCL |
git clone https://github.com/101001000/portableRT.git
cd portableRT
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build
-
Download OptiX 7.5.0 and extract it.
-
Configure CMake:
-DUSE_OPTIX=ON -DOptiX_ROOT=/path/to/OptiX-SDK-7.5.0-linux64-x86_64
-
Install HIP with ROCm (tested with ROCm 5.4.3).
-
Configure CMake:
-DUSE_HIP=ON -DHIP_ROOT=/path/to/rocm
-
Grab the SYCL‑enabled build: embree‑4.4.0.sycl.x86_64.linux.tar.gz.
You can reuse the same install for the CPU back‑end. -
Configure CMake:
-DUSE_EMBREE_SYCL=ON -Dembree_DIR=/path/to/embree-sycl/
-
Download the CPU build (with or without SYCL): embree‑4.4.0.x86_64.linux.tar.gz.
-
Configure CMake:
-DUSE_EMBREE_CPU=ON -Dembree_DIR=/path/to/embree/
Don’t forget
• Sourceembree_vars.sh
before using any Embree back‑end.
• For SYCL targets (Embree SYCL, generic SYCL), compile with DPC++ 6.0.1 or newer — e.g. intel/llvm v6.0.1.
#include <portableRT/portableRT.h>
#include <array>
#include <iostream>
int main() {
std::array<float, 9> tri = {-1,-1,0, 1,-1,0, 0,1,0};
portableRT::Ray hit{{0,0,-1}, {0,0,1}};
portableRT::Ray miss{{-2,0,-1}, {0,0,1}};
// Compute hit with any CPU
bool hit_cpu = portableRT::intersect_tri<portableRT::Backend::CPU>(tri, hit);
bool miss_cpu = portableRT::intersect_tri<portableRT::Backend::CPU>(tri, miss);
// Compute hit with NVidia RTX GPU RT cores
bool hit_optix = portableRT::intersect_tri<portableRT::Backend::OPTIX>(tri, hit);
bool miss_optix = portableRT::intersect_tri<portableRT::Backend::OPTIX>(tri, miss);
// Compute hit with AMD Radeon Rays GPU RT units
bool hit_hip = portableRT::intersect_tri<portableRT::Backend::HIP_ROCM>(tri, hit);
bool miss_hip = portableRT::intersect_tri<portableRT::Backend::HIP_ROCM>(tri, miss);
// Compute hit with Intel GPU Ray Tracing Units
bool hit_embreesycl = portableRT::intersect_tri<portableRT::Backend::EMBREE_SYCL>(tri, hit);
bool miss_embreesycl = portableRT::intersect_tri<portableRT::Backend::EMBREE_SYCL>(tri, miss);
// Compute hit with vectorized CPUs
bool hit_embreecpu = portableRT::intersect_tri<portableRT::Backend::EMBREE_CPU>(tri, hit);
bool miss_embreecpu = portableRT::intersect_tri<portableRT::Backend::EMBREE_CPU>(tri, miss);
// Compute hit with any parallel device (any GPU/CPU/FPGA)
bool hit_sycl = portableRT::intersect_tri<portableRT::Backend::SYCL>(tri, hit);
bool miss_sycl = portableRT::intersect_tri<portableRT::Backend::SYCL>(tri, miss);
}