How to Optimize TRELLIS.2 Performance with CUDA Kernels and FlexGEMM
TRELLIS.2 achieves high-performance sparse voxel processing by combining custom CUDA kernels for rasterization and spatial hashing with the FlexGEMM library's GPU-accelerated sparse matrix multiplication primitives.
Optimizing 3D neural reconstruction pipelines requires careful tuning of both geometric processing and sparse convolution operations. The microsoft/TRELLIS.2 repository implements a hybrid architecture that leverages hand-optimized CUDA kernels for voxel grid generation while delegating matrix-heavy computations to FlexGEMM's specialized sparse kernels. Understanding how these components interact allows you to maximize throughput on modern NVIDIA GPUs.
Understanding TRELLIS.2's CUDA Architecture
Voxel Rasterization Kernels
The core geometric workload in TRELLIS.2 converts triangle meshes into sparse voxel grids using the rasterization engine in o-voxel/src/rasterize/rasterize.cu. These kernels exploit shared memory and warp-level primitives to maintain high occupancy during voxelization. The implementation processes triangle meshes in parallel batches, with each thread handling voxel coverage tests and atomic operations to populate the sparse grid.
Spatial Hashing and Indexing
Once voxels are generated, fast lookup becomes critical. The repository implements hash-based storage in o-voxel/src/hash/hash.cu, which accelerates spatial queries during both encoding and decoding phases. For memory-efficient storage and cache-friendly access patterns, TRELLIS.2 employs space-filling curve encodings located in o-voxel/src/serialize/z_order.cu and o-voxel/src/serialize/hilbert.cu. These utilities pack 3D coordinates into compact 32-bit representations that minimize memory bandwidth during grid traversal.
Integrating FlexGEMM for Sparse Operations
Configuring FlexGEMM Parameters
The Python interface in trellis2/modules/sparse/conv/conv_flex_gemm.py wraps FlexGEMM operators such as sparse_submanifold_conv3d and grid_sample_3d. To optimize performance, you can tune two critical parameters:
algorithm: Set viaflex_gemm.ops.spconv.set_algorithm()or passed directly to convolution calls. Use"auto"to let the library select the best kernel for the current sparsity pattern, or specify"spconv"or"grid_sample"for deterministic behavior.hashmap_ratio: Configure withflex_gemm.ops.spconv.set_hashmap_ratio(). Higher values (e.g., 1.5) improve collision handling in sparse convolutions at the cost of increased memory consumption.
Sparse Convolution Workflows
FlexGEMM handles the computational bottleneck in sparse 3D convolutions that process voxel features. Unlike dense operations that waste cycles on empty space, the library's kernels skip zero-valued voxels using the coordinate indices generated by the CUDA rasterization stage. This tight integration between the o-voxel CUDA backend and FlexGEMM frontend ensures that data stays on the GPU between voxelization and neural processing steps.
Performance Optimization Strategies
Kernel Launch Configuration
Tune the CUDA block size in o-voxel/src/rasterize/rasterize.cu to match your GPU's Streaming Multiprocessor (SM) count. For most NVIDIA architectures, blocks of 128-256 threads provide optimal occupancy. You can programmatically query the ideal configuration using cudaOccupancyMaxPotentialBlockSize before launching the mesh_to_flexible_dual_grid conversion.
Memory Layout and Bandwidth
Store voxel coordinates in the packed 32-bit format produced by the Z-order and Hilbert curve utilities to reduce memory bandwidth by up to 50% compared to raw float32 coordinates. Ensure tensors align to 256-byte boundaries for optimal memory coalescing when transferring data between the voxel grid and FlexGEMM operations.
FlexGEMM Algorithm Tuning
Experiment with the FLEX_GEMM_ALGO environment variable or runtime parameters in conv_flex_gemm.py. For highly sparse scenes (fewer than 1% occupancy), the "spconv" algorithm typically outperforms "grid_sample", while the reverse holds for moderately dense volumes. Set hashmap_ratio between 1.2 and 2.0 depending on your scene complexity—higher ratios prevent hash collisions that stall the GPU during feature aggregation.
Batch Processing
Group multiple meshes into a single batch before calling o_voxel.convert.mesh_to_flexible_dual_grid() to amortize kernel launch overhead. The rasterization kernels in rasterize.cu process batches more efficiently than sequential single-mesh conversions because they can maintain warps full of active threads across the entire batch.
Implementation Examples
The following examples demonstrate the complete optimization workflow, from mesh voxelization through FlexGEMM-accelerated sparse convolution.
Example 1: Basic Voxelization and Conversion Pipeline
import torch
import o_voxel
from flex_gemm.ops.spconv import sparse_submanifold_conv3d
# Load mesh data (verts: Nx3, faces: Mx3)
verts, faces = load_obj('example.obj')
# Step 1: Convert mesh to sparse voxel grid using optimized CUDA kernels
voxel_idx, dual_vert, intersect = o_voxel.convert.mesh_to_flexible_dual_grid(
verts, faces,
voxel_size=0.01
)
# Step 2: Prepare features and weights for FlexGEMM processing
features = torch.randn(voxel_idx.shape[0], 64, device='cuda')
weight = torch.randn(64, 128, 3, 3, 3, device='cuda')
# Step 3: Apply sparse submanifold convolution
out = sparse_submanifold_conv3d(
features,
voxel_idx,
weight,
algorithm='auto',
hashmap_ratio=1.5
)
# Step 4: Reconstruct mesh if needed
verts_rec, faces_rec = o_voxel.convert.flexible_dual_grid_to_mesh(
voxel_idx, dual_vert, intersect
)
Example 2: Tuning Rasterization with Custom Block Sizes
import torch
import o_voxel
# Configure GPU for deterministic behavior
torch.backends.cuda.matmul.allow_tf32 = False
torch.cuda.set_device(0)
# Load geometry
verts, faces = load_obj('complex_scene.obj')
# Override default kernel launch parameters from rasterize.cu
# Higher block sizes (256) improve throughput for large meshes
voxel_idx, dual_vert, intersect = o_voxel.convert.mesh_to_flexible_dual_grid(
verts,
faces,
voxel_size=0.005,
block_size=256 # Matches optimized occupancy in rasterize.cu
)
Example 3: End-to-End Optimized Pipeline
import torch
import o_voxel
import flex_gemm.ops.spconv as spconv
def render_optimized_mesh(mesh_path):
verts, faces = load_obj(mesh_path)
# Voxelize with optimal memory layout
vox_idx, vox_vert, intersect = o_voxel.convert.mesh_to_flexible_dual_grid(
verts, faces,
voxel_size=0.01
)
# Feature extraction with FlexGEMM
feats = torch.randn(vox_idx.shape[0], 32, device='cuda')
weight = torch.randn(32, 64, 3, 3, 3, device='cuda')
conv_out = spconv.sparse_submanifold_conv3d(
feats,
vox_idx,
weight,
algorithm='auto',
hashmap_ratio=1.2 # Balanced for medium-density scenes
)
# Reconstruct with dual grid conversion
new_verts, new_faces = o_voxel.convert.flexible_dual_grid_to_mesh(
vox_idx, vox_vert, intersect
)
return new_verts, new_faces, conv_out
Summary
- Custom CUDA kernels in
o-voxel/src/rasterize/rasterize.cuando-voxel/src/hash/hash.cuhandle geometric conversion and spatial indexing with warp-level optimization. - Space-filling curves (
z_order.cu,hilbert.cu) compact 3D coordinates to minimize memory bandwidth during grid operations. - FlexGEMM integration through
trellis2/modules/sparse/conv/conv_flex_gemm.pyaccelerates sparse convolutions via tunable algorithms and hashmap ratios. - Performance tuning requires aligning block sizes to GPU architectures, batching mesh processing, and selecting FlexGEMM algorithms based on scene sparsity.
Frequently Asked Questions
How does TRELLIS.2 handle memory efficiency in sparse voxel grids?
TRELLIS.2 implements hash-based storage in o-voxel/src/hash/hash.cu combined with space-filling curve encodings from z_order.cu and hilbert.cu. These components pack 3D coordinates into 32-bit integers that consume less memory than float32 tuples while maintaining cache-friendly access patterns during spatial lookups.
What is the optimal hashmap_ratio for FlexGEMM operations in TRELLIS.2?
The optimal hashmap_ratio depends on your scene density. For sparse scenes with scattered voxels, use ratios between 1.2 and 1.5 to prevent hash collisions. Denser volumes benefit from ratios up to 2.0, though this increases GPU memory consumption. Configure this parameter in conv_flex_gemm.py or via flex_gemm.ops.spconv.set_hashmap_ratio().
Can I modify the CUDA kernel block sizes in the rasterization stage?
Yes. While the default configurations in o-voxel/src/rasterize/rasterize.cu target 128-256 threads for general GPU compatibility, you can override these at the Python API level using the block_size parameter in mesh_to_flexible_dual_grid(). Use cudaOccupancyMaxPotentialBlockSize profiling to determine the ideal configuration for your specific GPU architecture.
How do I install FlexGEMM for TRELLIS.2 optimization?
Run the setup script with the --flexgemm flag to install FlexGEMM as a submodule and ensure CUDA toolchain compatibility. The installation process compiles the sparse convolution kernels against your system's CUDA version, enabling the optimized paths in trellis2/modules/sparse/conv/conv_flex_gemm.py.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →