# CUDA Slicer: GPU-Accelerated Slicing & Polygon Offsetting Library [![Python Version](https://img.shields.io/badge/python-3.8%20%7C%203.9%20%7C%203.10%20%7C%203.11%20%7C%203.12-blue)](https://pypi.org/) [![CUDA](https://img.shields.io/badge/CUDA-11.x%20%7C%2012.x-green.svg)](https://developer.nvidia.com/cuda-toolkit) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) A high-performance C/C++ and CUDA library with native Python bindings for **Linux & Windows** providing GPU-accelerated 2D/3D polygon offsetting, Jump Flooding Signed Distance Fields (JFA / SDF), and slicing for 3D printing, CAM, and computational geometry. --- ## 🚀 Benchmark Summary (3DBenchy, 239 Layers @ 0.20 mm) Tested on **NVIDIA RTX A4500 Laptop GPU (16 GB VRAM)** vs **12th Gen Intel Core i7 CPU**: | Pipeline | Total Time (Mesh $\to$ Offset Contours) | Slicing / Offsetting Rate | Speedup vs PrusaSlicer | | :--- | :---: | :---: | :---: | | **100% GPU Direct Mesh Slicing (0.10 mm Pitch)** | **74.4 ms** | **3,212 layers/sec** | **57.47x Faster** | | **100% GPU Direct Mesh Slicing (0.05 mm Pitch)** | **190.9 ms** | **1,252 layers/sec** | **22.55x Faster** | | **Hybrid CPU Slicing + GPU JFA (0.05 mm Pitch)** | 739.4 ms | 323 layers/sec | 5.82x Faster | | **PrusaSlicer CLI Headless (CPU Baseline)** | 4,305.7 ms | 55 layers/sec | 1.00x (Baseline) | > ⚡ **Key Optimizations Applied:** > - **Stage 6 (Marching Squares Vectorization):** Reduced from **72.5 ms down to 35.4 ms (2.05x faster / 6,751 layer/s)** via zero-allocation discrete edge-table addressing, thread-local buffer reuse, and on-the-fly collinear point decimation (>95% vertex reduction). > - **Stage 5 (D2H Transfer):** Reduced from **136.3 ms down to 4.5 ms (30x–48x faster)** via GPU 32-bit bit-packing + page-locked pinned host DMA (`cudaMallocHost`). > - **Stage 3 (GPU JFA Distance Field):** Reduced from **118.9 ms down to 52.8 ms (2.25x faster)** via perimeter-band limited steps and integer arithmetic. --- ## 🐍 Python Package Integration ### 1. Installation #### A. Install from Source (Linux & Windows) Make sure you have NVIDIA CUDA Toolkit (11.5+ or 12.x) and a C++ compiler (GCC on Linux, MSVC 2019/2022 on Windows) installed: ```bash # Clone the repository cd cudaslicer # Install directly with pip pip install . ``` #### B. Build Wheel (.whl) ```bash python -m pip install --upgrade build wheel python -m build --wheel # The wheel will be generated in dist/ # e.g., dist/cudaslicer-1.0.0-cp310-cp310-linux_x86_64.whl # or dist/cudaslicer-1.0.0-cp310-cp310-win_amd64.whl ``` --- ### 2. Python API Quickstart #### A. Backend Selection & GPU Capability Check ```python import cudaslicer # 1. Check if a CUDA GPU is present if cudaslicer.has_cuda(): print("CUDA GPU is active!") else: print("Running in multi-threaded CPU compatibility mode.") # 2. Control compute backend globally ('auto', 'cuda', 'cpu') cudaslicer.set_backend("auto") # Auto: use CUDA if available, fallback to CPU ``` #### B. Offsetting 2D Polygon Contours (Single Layer or Multi-Layer) ```python import numpy as np import cudaslicer # Define a polygon (e.g. 50x50 mm square) poly = np.array([ [10.0, 10.0], [60.0, 10.0], [60.0, 60.0], [10.0, 60.0] ], dtype=np.float32) # Generate 2 inward perimeters (at -0.5*w and -1.5*w) and infill mask (at -2.0*w) # pitch_mm defaults to 0.10 mm, backend defaults to 'auto' layer = cudaslicer.offset_polygons( layers=[poly], perimeters_count=2, layer_width=0.45, pitch_mm=0.10, backend="auto" # 'auto', 'cuda', or 'cpu' ) # Unpack directly perimeters, infill_mask = layer print(f"Outer Perimeter 1 (-0.225mm): {len(perimeters[0])} loop(s)") print(f"Inner Perimeter 2 (-0.675mm): {len(perimeters[1])} loop(s)") print(f"Infill Region Mask (-0.900mm): shape {infill_mask.shape}, {infill_mask.sum()} px") ``` #### C. Offsetting 2D / 3D Occupancy Masks Directly ```python import numpy as np import cudaslicer # Create a 2D binary grid (e.g., 200 x 200 pixels) mask = np.zeros((200, 200), dtype=np.uint8) mask[40:160, 40:160] = 1 # Compute Euclidean perimeters and infill mask perimeters, infill_mask = cudaslicer.offset_masks( masks=mask, perimeters_count=2, layer_width=0.45, pitch_mm=0.10, backend="auto" ) print("Perimeters shape:", perimeters.shape) # (2, 200, 200) print("Infill mask shape:", infill_mask.shape) # (200, 200) ``` #### D. End-to-End Mesh Slicing with Custom First Layer Height ```python import trimesh import cudaslicer mesh = trimesh.load("benchy.stl") # 100% GPU Slicing & Perimeter Offsetting layers = cudaslicer.slice_mesh( mesh_or_triangles=mesh, layer_height=0.20, first_layer_height=0.25, # custom first layer height perimeters_count=2, layer_width=0.45, pitch_mm=0.10 # default 0.10 ) print(f"Sliced {len(layers)} layers in GPU VRAM!") layer_0 = layers[0] # First layer at Z = 0.25 mm perims, infill_mask = layer_0 print(f"Layer 0 (Z = {layer_0.z} mm): {len(perims)} perimeters, infill mask: {infill_mask.shape}") ``` --- ## 🛠️ Building Standalone C/C++ Libraries (Windows & Linux) ### Linux Build (`libcudaslicer_offset.so` & `.a`) ```bash mkdir -p build && cd build cmake .. -DCMAKE_BUILD_TYPE=Release cmake --build . -j$(nproc) ``` Outputs: - Shared Library: `build/lib/libcudaslicer_offset.so` - Static Library: `build/lib/libcudaslicer_offset.a` - C Benchmark CLI: `build/bin/gpu_slicer_c_bench` ### Windows Build (`cudaslicer_offset.dll` & `.lib`) Open **x64 Native Tools Command Prompt for VS 2022** and run: ```cmd mkdir build cd build cmake .. -G "Visual Studio 17 2022" -A x64 -DCMAKE_BUILD_TYPE=Release cmake --build . --config Release ``` Outputs: - DLL: `build/lib/Release/cudaslicer_offset.dll` - Import Lib: `build/lib/Release/cudaslicer_offset.lib` - Benchmark: `build/bin/Release/gpu_slicer_c_bench.exe` --- ## ⚙️ Cross-Platform C API Reference (`include/gpu_offset.h`) The public header provides a portable C API with `__declspec(dllexport)` / `__declspec(dllimport)` on Windows and default symbol visibility on Linux: ```c #include "gpu_offset.h" // 1. Initialize GPU gpu_offset_init(0); // 2. Configure slicing & offsetting parameters GpuOffsetConfig config = { .pitch_mm = 0.10f, // default 0.10 mm .pad_mm = 1.5f, .perimeters_count = 2, // 2 perimeter passes .layer_width = 0.45f, // 0.45 mm extrusion width .first_layer_height = 0.25f, // 0.25 mm first layer height .export_infill_mask = 1, // generate 2D binary infill mask .use_gpu_rasterizer = 1 }; // 3. 100% Direct GPU Mesh Slicing & Offsetting GpuLayerResult* results = NULL; size_t num_layers = 0; GpuOffsetStats stats = {0}; gpu_offset_slice_mesh_and_offset( triangles, num_triangles, min_x, min_y, min_z, max_x, max_y, max_z, 0.20f, 0.25f, &config, &results, &num_layers, &stats ); // Access perimeters and infill mask for (size_t l = 0; l < num_layers; ++l) { float z = results[l].z_height; size_t num_perims = results[l].num_perimeters; // 2 GpuContour* infill_cnts = results[l].infill.contours; uint8_t* infill_mask = results[l].infill.mask; } // 4. Cleanup gpu_offset_free_results(results, num_layers); gpu_offset_cleanup(); ``` --- ## 🔄 Automated CI/CD (GitHub Actions) - Building Linux Python wheels (`manylinux_2_35_x86_64`) across Python 3.9, 3.10, 3.11, 3.12. - Building Windows x64 Python wheels (`win_amd64`) across Python 3.9, 3.10, 3.11, 3.12. - Building standalone Linux `.so` and Windows `.dll` binaries as downloadable CI artifacts. --- ## 📄 License MIT License. Free for commercial and research use.