Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
66 commits
Select commit Hold shift + click to select a range
e6f5258
Started on batch API query methods
Waqar-ukaea Oct 30, 2025
4334524
Added a batch_ray_fire miniapp for extra testing
Waqar-ukaea Oct 30, 2025
1dbc734
Added test_cases for batch_ray_fire
Waqar-ukaea Nov 4, 2025
b388e66
Implemented batch_point_in_volume()
Waqar-ukaea Nov 5, 2025
c9af01e
Added a batch_point in volume miniapp for extra testing
Waqar-ukaea Nov 5, 2025
1025013
Added stress test for batch_ray_fire which calls over a batch of 10M …
Waqar-ukaea Nov 5, 2025
0daa265
Added a catch2 microbenchmark to the large number of rays stress test
Waqar-ukaea Nov 6, 2025
f7a49ba
Rebased changes from #170
Waqar-ukaea Nov 7, 2025
742b1f0
Overloading ray_fire/point_in_volume for batch calls
Waqar-ukaea Nov 10, 2025
8cdab31
Added method descriptions for the two overloads
Waqar-ukaea Nov 10, 2025
081abc1
Refactor batch based point_in_volume tests
Waqar-ukaea Nov 11, 2025
e9af504
Dropped dir mask in batch PIV calls + made dirs optional
Waqar-ukaea Nov 12, 2025
0f0811c
Added a new ray-benchmark tool to compare embree vs gprt ray throughput
Waqar-ukaea Nov 12, 2025
50d0e07
Removed performance benchmarking in unit tests
Waqar-ukaea Nov 12, 2025
a2092ec
Removed the leftover extra call to rebuild SBT
Waqar-ukaea Nov 18, 2025
eb5d3e9
Update AABB population program to properly distribute threads
Waqar-ukaea Nov 19, 2025
00bc00e
Move timer to exclude memory transfer around raygen launch
Waqar-ukaea Nov 19, 2025
59f59d3
Ensured timer still setup for Embree ray benchamrking
Waqar-ukaea Nov 19, 2025
8ac2744
Add default stubs for GPU specific ray tracing methods. Cleanup embre…
Waqar-ukaea Nov 25, 2025
7bc2ec7
Refactor raygen launching functions to make use of PushConstants for …
Waqar-ukaea Nov 25, 2025
605e573
Added methods for pre-packing rays and performing ray_fire on those rays
Waqar-ukaea Nov 25, 2025
5e140f9
Update ray_benchmark tool to make use of ray pre-packing and ray_fire…
Waqar-ukaea Nov 25, 2025
e7bdeaa
Added include guard to header with shared types between slang and C++
Waqar-ukaea Nov 27, 2025
71e4d4f
Fixed ambiguity with mixing GPRT math types (double3) and linalg
Waqar-ukaea Nov 27, 2025
d412746
Refactored internal and public facing rayhit buffers to shared POD
Waqar-ukaea Nov 27, 2025
be5ea23
Refactored ray-benchmark miniapp to write into XDG's rayhit buffers d…
Waqar-ukaea Nov 27, 2025
59c97c2
Refactored ray_benchmark miniapp to make use of new xdg::Timer objects
Waqar-ukaea Nov 28, 2025
3c84151
Switch constant DILATION_FACTOR to be inline const so it compiles wit…
Waqar-ukaea Dec 3, 2025
bbc9562
Ensure embree path is making use of all CPU threads available
Waqar-ukaea Dec 3, 2025
2364b04
Extended random ray generation to get random origins too
Waqar-ukaea Dec 3, 2025
498a10d
Added in source-radius for GPRT but fails to compile
Waqar-ukaea Dec 3, 2025
67002b1
No idea why but apparently I need the xdg->prepare_volume_for_raytrac…
Waqar-ukaea Dec 4, 2025
5cf0169
Moved some header definitions around to make it possible to compile w…
Waqar-ukaea Dec 5, 2025
dc9b55a
Added a python script to drive multiple ray-benchmarks
Waqar-ukaea Dec 5, 2025
cb38689
Updated GPRT render tool to make use of upstream API changes for GUI …
Waqar-ukaea Jan 13, 2026
6494af3
Updated batch query tests to make use of TEMPLATE_TEST_CASE pattern
Waqar-ukaea Jan 13, 2026
69742fa
Set default RayHit buffer size to be 1m rays
Waqar-ukaea Jan 14, 2026
553e0b9
Attempting to implement a callback based method for populating intern…
Waqar-ukaea Jan 19, 2026
f0f7389
Removed the now redundant pack_external_rays() code path
Waqar-ukaea Jan 19, 2026
ce80cdd
Made DeviceRayHitBuffers more opaque to abstract away from GPRT speci…
Waqar-ukaea Jan 19, 2026
201d069
Updated some comments
Waqar-ukaea Jan 19, 2026
7c25fda
Renamed ray_fire_packed() to ray_fire_prepared()
Waqar-ukaea Jan 19, 2026
2d78b02
Added the required CMake linking to GPRT for ray_benchmark miniapp
Waqar-ukaea Jan 19, 2026
5704d88
Adding the ability to trace against multiple volumes for prepared rays
Waqar-ukaea Jan 21, 2026
b920f9c
Added the ability to trace against multiple volumes within same rayge…
Waqar-ukaea Jan 23, 2026
055eca8
Abstracted some methods from ray_benchmark into functions for use in …
Waqar-ukaea Jan 26, 2026
c6c71fa
Added test for filling ray buffers directly + ray_fire_prepared code …
Waqar-ukaea Jan 28, 2026
e758e69
Merge pull request #13 from Waqar-ukaea/ray-population-callback
Waqar-ukaea Jan 28, 2026
5f21bd2
Merging ray population from remote
Waqar-ukaea Jan 28, 2026
6aabf14
Removed header causing compilation error + gated test for direct buff…
Waqar-ukaea Jan 29, 2026
9192c19
Fixed redundant include causing libmesh only build to fail
Waqar-ukaea Jan 30, 2026
5f930ad
Core API changes to allow batch queries with XDG
Waqar-ukaea Jan 30, 2026
53d9632
Added tests for batch query API with GPRT
Waqar-ukaea Jan 30, 2026
663dad5
Added wiring for point_in_volume_prepared()
Waqar-ukaea Jan 30, 2026
3e41d89
Added test for point_in_volume_prepared() codepath
Waqar-ukaea Jan 30, 2026
cb2976e
Added point_in_volume_prepared()
Waqar-ukaea Jan 30, 2026
abd0ce2
Added tests for point_in_volume_prepared()
Waqar-ukaea Jan 30, 2026
d229e4f
Fixed wrong function signature call and redefinition of helper functi…
Waqar-ukaea Jan 30, 2026
d88e7fc
Remove stale GPRT specific code from xdg.cpp
Waqar-ukaea Jan 30, 2026
bf001ab
Updated direct_buffer_access test to also test multi-volume
Waqar-ukaea Feb 3, 2026
dd3bda0
Cleaned up some function names and added some warnings for no rays pa…
Waqar-ukaea Feb 3, 2026
c0d180f
Fixed multi-volume tests
Waqar-ukaea Feb 3, 2026
8218938
Added Device side MeshID to sense mapping to handle reverse sense for…
Waqar-ukaea Feb 3, 2026
422a386
Cleanup unused variables in shared host/device side structs
Waqar-ukaea Feb 3, 2026
9eaaae1
Implemented batch based versions of ray_fire() and point_in_volume() …
Waqar-ukaea Feb 3, 2026
3fdf69a
Forgot to add initialise meshid_to_sense_buffer and destruction
Waqar-ukaea Feb 4, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions include/xdg/gprt/ray.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#ifndef _XDG_GPRT_RAY_H
#define _XDG_GPRT_RAY_H

#include "gprt.h"
#include "../shared_enums.h"

/*
* Double-precision ray and hit structures used by the GPRT backend.
*
* These types are not inherently GPRT-specific, but we keep them here for now
* since GPRT is the only GPU backend. If another GPU backend is added, these
* can be reused. Unifying them with the CPU/Embree types is possible, but may
* not be worth the added complexity at this stage.
*/

namespace xdg {

struct dblRay
{
double3 origin;
double3 direction;
int volume_mesh_id; // MeshID of the volume this ray will be traced against
uint enabled; // Flag to indicate if the ray is active
int32_t* exclude_primitives; // Optional for excluding primitives
int32_t exclude_count; // Number of excluded primitives
};


struct dblHit
{
double distance;
int surf_id;
int primitive_id;
PointInVolume piv; // Point in volume check result (0 for outside, 1 for inside)
};

}


#endif
88 changes: 64 additions & 24 deletions include/xdg/gprt/ray_tracer.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,15 @@

#include "xdg/constants.h"
#include "xdg/mesh_manager_interface.h"
#include "xdg/primitive_ref.h"
#include "xdg/geometry_data.h"
#include "xdg/ray_tracing_interface.h"
#include "xdg/ray.h"
#include "xdg/error.h"
#include "gprt/gprt.h"

#include "shared_structs.h"

extern GPRTProgram dbl_deviceCode;
namespace xdg {

// Ray generation types corresponding to different queries for GPRT
enum class RayGenType {
RAY_FIRE,
POINT_IN_VOLUME,
Expand All @@ -26,17 +24,16 @@ enum class RayGenType {
};

struct gprtRayHit {
size_t capacity = 1; // Max number of rays allocated
size_t size = 0; // Current number of active rays
DeviceRayHitBuffers view; // external facing POD for rayhit buffers
size_t size = 0; // Current number of active rays

GPRTBufferOf<dblRay> ray = nullptr;
GPRTBufferOf<dblHit> hit = nullptr;
dblRay* devRayAddr = nullptr;
dblHit* devHitAddr = nullptr;

bool is_valid() const { return capacity > 0 && ray && hit && devRayAddr && devHitAddr; }
bool is_valid() const {
return view.capacity > 0 && ray && hit && view.rayDevPtr && view.hitDevPtr;
}
};

class GPRTRayTracer : public RayTracer {
public:
GPRTRayTracer();
Expand Down Expand Up @@ -79,19 +76,38 @@ class GPRTRayTracer : public RayTracer {
};

bool point_in_volume(TreeID scene,
const Position& point,
const Direction* direction = nullptr,
const std::vector<MeshID>* exclude_primitives = nullptr) const override;
const Position& point,
const Direction* direction = nullptr,
const std::vector<MeshID>* exclude_primitives = nullptr) const override;

void point_in_volume(TreeID tree,
const Position* points,
const size_t num_points,
uint8_t* results,
const Direction* directions = nullptr,
std::vector<MeshID>* exclude_primitives = nullptr) override;

std::pair<double, MeshID> ray_fire(TreeID scene,
const Position& origin,
const Direction& direction,
const double dist_limit = INFTY,
HitOrientation orientation = HitOrientation::EXITING,
std::vector<MeshID>* const exclude_primitives = nullptr) override;
const Position& origin,
const Direction& direction,
const double dist_limit = INFTY,
HitOrientation orientation = HitOrientation::EXITING,
std::vector<MeshID>* const exclude_primitives = nullptr) override;
void ray_fire(TreeID tree,
const Position* origins,
const Direction* directions,
const size_t num_rays,
double* hitDistances,
MeshID* surfaceIDs,
const double dist_limit = INFTY,
HitOrientation orientation = HitOrientation::EXITING,
std::vector<MeshID>* const exclude_primitives = nullptr) override;

std::pair<double, MeshID> closest(TreeID scene,
const Position& origin) override {};
const Position& origin) override {
fatal_error("Closest queries are not currently supported with GPRT ray tracer");
return {INFTY, ID_NONE};
};

bool occluded(TreeID scene,
const Position& origin,
Expand All @@ -100,9 +116,16 @@ class GPRTRayTracer : public RayTracer {
fatal_error("Occlusion queries are not currently supported with GPRT ray tracer");
return false;
}


void check_rayhit_buffer_capacity(const size_t N) override;

// Return GPRT context to attatch "external" shaders to same context (required since GPRT doesn't support VK_EXTERNAL_MEMORY_EXTENSION yet)
GPRTContext context()
{
return context_;
}

private:
void check_ray_buffer_capacity(size_t N);

// GPRT objects
GPRTContext context_;
Expand Down Expand Up @@ -133,7 +156,25 @@ class GPRTRayTracer : public RayTracer {

// Internal GPRT Mappings
std::unordered_map<SurfaceTreeID, GPRTAccel> surface_volume_tree_to_accel_map; // Map from XDG::TreeID to GPRTAccel for volume TLAS
std::vector<GPRTAccel> blas_handles_; // Store BLAS handles so that they can be explicitly referenced in destructor
std::unordered_map<SurfaceTreeID, MeshID> surface_tree_to_volume_map_;
std::vector<SurfaceAccelerationStructure> tlas_handles_; // Host side storage of TLAS device addresses
GPRTBufferOf<SurfaceAccelerationStructure> tlas_handle_buffer_; // Device buffer for TLAS addresses
std::vector<int> meshid_to_sense_; // Host-side MeshID -> sense map
GPRTBufferOf<int> meshid_to_sense_buffer_ {nullptr}; // Device buffer for MeshID -> sense map
bool initialized_ {false}; // flag to indicate if init() has been called

void update_tlas_table_(); // Update the TLAS table (MeshID -> SurfaceAccelerationStructure) buffer on the device
void update_meshid_to_sense_(); // Update the MeshID -> sense (+1/-1) buffer on the device

// Helper to upload data to device buffer, resizing buffer as needed
template <typename T>
void upload_device_buffer_(GPRTBufferOf<T>& buf, const std::vector<T>& host_data)
{
gprtBufferResize<T>(context_, buf, host_data.size(), false);
gprtBufferMap(buf);
std::copy(host_data.begin(), host_data.end(), gprtBufferGetHostPointer(buf));
gprtBufferUnmap(buf);
}

// Global Tree IDs
GPRTAccel global_surface_accel_ {nullptr};
Expand All @@ -142,5 +183,4 @@ class GPRTRayTracer : public RayTracer {
};

} // namespace xdg

#endif // include guard
#endif // include guard
41 changes: 12 additions & 29 deletions include/xdg/gprt/shared_structs.h
Original file line number Diff line number Diff line change
@@ -1,32 +1,15 @@
#ifndef XDG_GPRT_SHARED_STRUCTS_H
#define XDG_GPRT_SHARED_STRUCTS_H

#include "gprt.h"
#include "../shared_enums.h"
#include "ray.h"

struct GPRTPrimitiveRef
{
int id; // ID of the primitive
int sense;
};

struct dblRay
{
double3 origin;
double3 direction;
double tMin; // Minimum distance for ray intersection
double tMax; // Maximum distance for ray intersection
int32_t* exclude_primitives; // Optional for excluding primitives
int32_t exclude_count; // Number of excluded primitives
xdg::HitOrientation hitOrientation;
int volume_tree; // TreeID of the volume being queried
SurfaceAccelerationStructure volume_accel; // The volume accel
};

struct dblHit
{
double distance;
int surf_id;
int primitive_id;
xdg::PointInVolume piv; // Point in volume check result (0 for outside, 1 for inside)
};

/* variables for double precision triangle mesh geometry */
struct DPTriangleGeomData {
Expand All @@ -35,20 +18,17 @@ struct DPTriangleGeomData {
uint3 *index; // index buffer
double3 *normals; // normals buffer
int surf_id;
int2 vols;
int forward_vol;
int reverse_vol;
dblRay *ray; // double precision rays
int* meshid_to_sense; // MeshID -> sense (+1 forward, -1 reverse)
xdg::dblRay *ray; // double precision rays
xdg::HitOrientation hitOrientation;
int forward_tree; // TreeID of the forward volume
int reverse_tree; // TreeID of the reverse volume
GPRTPrimitiveRef* primitive_refs;
int num_faces; // Number of faces in the geometry
};

struct dblRayGenData {
dblRay *ray;
dblHit *hit;
xdg::dblRay *ray;
xdg::dblHit *hit;
SurfaceAccelerationStructure* meshid_to_accel_address; // MeshID->TLAS address table to recover volume to trace against
};

/* A small structure of constants that can change every frame without rebuilding the
Expand All @@ -57,4 +37,7 @@ struct dblRayGenData {
struct dblRayFirePushConstants {
double tMax;
double tMin;
xdg::HitOrientation hitOrientation;
};

#endif
99 changes: 96 additions & 3 deletions include/xdg/ray_tracing_interface.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,46 @@
#include <memory>
#include <vector>
#include <unordered_map>
#include <functional>

#include "xdg/error.h"
#include "xdg/constants.h"
#include "xdg/embree_interface.h"
#include "xdg/mesh_manager_interface.h"
#include "xdg/primitive_ref.h"
#include "xdg/geometry_data.h"


namespace xdg
{

struct dblHit; // forward declaration for dblHit

/**
* @brief Device ray/hit buffer descriptor
*
* This structure provides access to device-allocated ray and hit buffers
* in a backend-agnostic way. The buffers contain XDG's standard ray and hit
* data structures (dblRay and dblHit), regardless of which compute backend
* is being used.
*
* Key design principle:
* - Device pointers are opaque (void*)
* - The data layout is always the XDG types dblRay and dblHit
* - Downstream code can write to these buffers (hopefully) using any compute API
*
* For type-safe access in downstream code:
* - Cast rayDevPtr to (dblRay*) when using C++ or kernels
* - Cast hitDevPtr to (dblHit*) when reading hit results
*/
struct DeviceRayHitBuffers {
void* rayDevPtr;
void* hitDevPtr;
size_t capacity; // Number of rays the buffer can hold
size_t rayStride; // Bytes between ray elements - sizeof(dblRay)
size_t hitStride; // Bytes between hit elements - sizeof(dblHit)
};

class RayTracer {
public:
// Constructors/Destructors
Expand Down Expand Up @@ -73,12 +103,41 @@ class RayTracer {
*/
virtual void create_global_element_tree() = 0;

// Query Methods
/**
* @brief Check whether a point lies in a specified volume
*
* This method performs a check to see whether a given point is inside a volume provided.
* It computes this by firing a ray from the point and checking whether or not the ray is Entering or Exiting
* the volume boundary. If no direction is provided, a default direction will be used.
* Note - zero length direction vectors are not explicitly checked for internally and should be avoided to avoid causing undefined behavior.
*
* @param[in] tree The TreeID of the volume we are querying against
* @param[in] point The point to be queried
* @param[in] direction (optional) direction to launch a ray in a specified direction - must be non-zero length
* @param[in] exclude_primitives (optional) vector of surface element MeshIDs to exclude from intersection tests
* @return Boolean result of point in volume check
*/
virtual bool point_in_volume(TreeID tree,
const Position& point,
const Direction* direction = nullptr,
const std::vector<MeshID>* exclude_primitives = nullptr) const = 0;


/**
* @brief Fire a ray against a given volume and return the first hit
*
* This method fires a ray from a given origin in a specified direction against the surfaces of a volume.
* It returns the distance to the closest hit and the MeshID of the surface hit. The user can specify
* a distance limit and whether Entering/Exiting hits should be rejected.
* Note - zero length direction vectors are not explicitly checked for internally and should be avoided to avoid causing undefined behavior.
*
* @param[in] tree The TreeID of the volume we are querying against
* @param[in] origin An array of Position objects representing the starting points of the rays
* @param[in] direction (optional) Direction object to launch a ray in a specified direction
* @param[in] dist_limit (optional) maximum distance to consider for intersections
* @param[in] orientation (optional) flag to consider whether Entering/Exiting hits should be rejected. Defaults to EXITING
* @param[in] exclude_primitives (optional) vector of surface element MeshIDs to exclude from intersection tests
* @return A pair containing the distance to the closest hit and the MeshID of the surface hit
*/
virtual std::pair<double, MeshID> ray_fire(TreeID tree,
const Position& origin,
const Direction& direction,
Expand Down Expand Up @@ -123,6 +182,40 @@ class RayTracer {
int num_registered_surface_trees() const { return surface_trees_.size(); };
int num_registered_element_trees() const { return element_trees_.size(); };


// GPU Ray Tracing Support

virtual void point_in_volume(TreeID tree,
const Position* points,
const size_t num_points,
uint8_t* results,
const Direction* directions = nullptr,
std::vector<MeshID>* exclude_primitives = nullptr)
{
fatal_error("GPU ray tracing not supported with this RayTracer backend");
}

virtual void ray_fire(TreeID tree,
const Position* origins,
const Direction* directions,
const size_t num_rays,
double* hitDistances,
MeshID* surfaceIDs,
const double dist_limit = INFTY,
HitOrientation orientation = HitOrientation::EXITING,
std::vector<MeshID>* const exclude_primitives = nullptr)
{
fatal_error("GPU ray tracing not supported with this RayTracer backend");
}

/**
* @brief Check whether the current ray buffer capacity is sufficient for the number of rays requested
* @param[in] num_rays The number of rays to be processed
*/
virtual void check_rayhit_buffer_capacity(const size_t num_rays) {
fatal_error("GPU ray tracing not supported with this RayTracer backend");
}

protected:
// Common functions across RayTracers
const double bounding_box_bump(const std::shared_ptr<MeshManager> mesh_manager, MeshID volume_id); // return a bump value based on the size of a bounding box (minimum 1e-3). Should this be a part of mesh_manager?
Expand Down Expand Up @@ -150,4 +243,4 @@ class RayTracer {
} // namespace xdg


#endif // include guard
#endif // include guard
Loading
Loading