|
| 1 | +name: GPU Test |
| 2 | + |
| 3 | +# GPU tests are triggered by adding the "GPU CI" label to a PR |
| 4 | +# This prevents expensive GPU runners from running on every commit |
| 5 | +on: |
| 6 | + pull_request: |
| 7 | + types: [labeled] |
| 8 | + |
| 9 | +jobs: |
| 10 | + gpu-test: |
| 11 | + name: GPU Test ${{ matrix.python-version }} |
| 12 | + # Only run when the "GPU CI" label is added |
| 13 | + if: github.event.label.name == 'GPU CI' |
| 14 | + |
| 15 | + # Use the GPU runner group - you need to create this in your org settings |
| 16 | + # Go to: Organization Settings > Actions > Runner groups > Create new runner group |
| 17 | + # Select "NVIDIA GPU-Optimized Image for Linux" when creating the runner |
| 18 | + runs-on: |
| 19 | + group: gpu-runners |
| 20 | + labels: linux-gpu |
| 21 | + |
| 22 | + strategy: |
| 23 | + fail-fast: false |
| 24 | + matrix: |
| 25 | + python-version: ["3.12", "3.13"] |
| 26 | + |
| 27 | + steps: |
| 28 | + - name: Checkout source |
| 29 | + uses: actions/checkout@v4 |
| 30 | + with: |
| 31 | + fetch-depth: 0 |
| 32 | + |
| 33 | + - name: Install Python ${{ matrix.python-version }} |
| 34 | + uses: actions/setup-python@v5 |
| 35 | + with: |
| 36 | + python-version: ${{ matrix.python-version }} |
| 37 | + |
| 38 | + - name: Verify GPU |
| 39 | + run: | |
| 40 | + echo "=== NVIDIA GPU Info ===" |
| 41 | + nvidia-smi |
| 42 | + echo "" |
| 43 | + echo "=== Driver version check ===" |
| 44 | + echo "OptiX 7.7 requires driver 530.41+" |
| 45 | + echo "OptiX 8.0 requires driver 535+" |
| 46 | + echo "OptiX 9.1 requires driver 590+" |
| 47 | +
|
| 48 | + - name: Install CUDA Toolkit |
| 49 | + uses: Jimver/cuda-toolkit@v0.2.21 |
| 50 | + id: cuda-toolkit |
| 51 | + with: |
| 52 | + cuda: '12.6.3' |
| 53 | + method: 'network' |
| 54 | + # Only install toolkit components, not drivers (runner already has drivers) |
| 55 | + sub-packages: '["nvcc", "cudart-dev", "nvrtc-dev", "thrust"]' |
| 56 | + |
| 57 | + - name: Verify CUDA installation |
| 58 | + run: | |
| 59 | + echo "=== CUDA Version ===" |
| 60 | + nvcc --version |
| 61 | + echo "CUDA_PATH=${CUDA_PATH:-not set}" |
| 62 | + echo "CUDA installed to: ${{ steps.cuda-toolkit.outputs.CUDA_PATH }}" |
| 63 | +
|
| 64 | + - name: Install build dependencies |
| 65 | + run: | |
| 66 | + sudo apt-get update |
| 67 | + sudo apt-get install -y cmake |
| 68 | +
|
| 69 | + - name: Install OptiX SDK headers |
| 70 | + run: | |
| 71 | + # Clone NVIDIA's public OptiX headers repository |
| 72 | + # This contains the minimal headers needed to build OptiX applications |
| 73 | + # See: https://github.com/NVIDIA/optix-dev |
| 74 | + OPTIX_DIR="/opt/optix" |
| 75 | + sudo mkdir -p ${OPTIX_DIR} |
| 76 | + sudo chown -R $(whoami) ${OPTIX_DIR} |
| 77 | +
|
| 78 | + echo "=== Cloning OptiX SDK headers from NVIDIA/optix-dev ===" |
| 79 | + # Use OptiX 7.7 for broader driver compatibility (requires driver 530.41+) |
| 80 | + # OptiX 9.x requires R590+ drivers which may not be available on all runners |
| 81 | + git clone --depth 1 --branch v7.7.0 --verbose https://github.com/NVIDIA/optix-dev.git ${OPTIX_DIR} |
| 82 | +
|
| 83 | + # Debug: show what was cloned |
| 84 | + echo "=== Contents of ${OPTIX_DIR} ===" |
| 85 | + ls -la ${OPTIX_DIR} |
| 86 | + echo "=== Contents of ${OPTIX_DIR}/include (if exists) ===" |
| 87 | + ls -la ${OPTIX_DIR}/include/ 2>/dev/null || echo "include directory not found" |
| 88 | +
|
| 89 | + # Verify the headers are present |
| 90 | + if [ -f "${OPTIX_DIR}/include/optix.h" ]; then |
| 91 | + echo "OptiX headers installed successfully at: ${OPTIX_DIR}" |
| 92 | + echo "OptiX_INSTALL_DIR=${OPTIX_DIR}" >> $GITHUB_ENV |
| 93 | + else |
| 94 | + echo "ERROR: OptiX headers not found after clone" |
| 95 | + echo "Attempting alternative: checking if files are in subdirectory..." |
| 96 | + find ${OPTIX_DIR} -name "optix.h" 2>/dev/null || echo "optix.h not found anywhere" |
| 97 | + exit 1 |
| 98 | + fi |
| 99 | +
|
| 100 | + - name: Compile PTX for target GPU |
| 101 | + run: | |
| 102 | + # Detect GPU compute capability |
| 103 | + GPU_ARCH=$(nvidia-smi --query-gpu=compute_cap --format=csv,noheader | head -1 | tr -d '.') |
| 104 | + echo "Detected GPU compute capability: sm_${GPU_ARCH}" |
| 105 | +
|
| 106 | + # Compile kernel.cu to PTX for the target architecture |
| 107 | + echo "=== Compiling kernel.cu to PTX ===" |
| 108 | + nvcc -ptx \ |
| 109 | + -arch=sm_${GPU_ARCH} \ |
| 110 | + -I${OptiX_INSTALL_DIR}/include \ |
| 111 | + -I cuda \ |
| 112 | + --use_fast_math \ |
| 113 | + -o rtxpy/kernel.ptx \ |
| 114 | + cuda/kernel.cu |
| 115 | +
|
| 116 | + echo "=== PTX compiled successfully ===" |
| 117 | + head -15 rtxpy/kernel.ptx |
| 118 | +
|
| 119 | + - name: Install otk-pyoptix from source |
| 120 | + run: | |
| 121 | + echo "Using OptiX from: ${OptiX_INSTALL_DIR}" |
| 122 | +
|
| 123 | + # Clone and install otk-pyoptix |
| 124 | + git clone --depth 1 https://github.com/NVIDIA/otk-pyoptix.git /tmp/otk-pyoptix |
| 125 | + cd /tmp/otk-pyoptix/optix |
| 126 | +
|
| 127 | + # Install with OptiX path set |
| 128 | + pip install . |
| 129 | +
|
| 130 | + - name: Install rtxpy with CUDA dependencies |
| 131 | + run: | |
| 132 | + python -m pip install -U pip |
| 133 | + python -m pip install -ve .[tests,cuda12] |
| 134 | + python -m pip list |
| 135 | +
|
| 136 | + - name: Run GPU tests |
| 137 | + run: | |
| 138 | + python -m pytest -v rtxpy/tests |
| 139 | +
|
| 140 | + - name: Test basic ray tracing |
| 141 | + run: | |
| 142 | + python -c " |
| 143 | + from rtxpy import RTX |
| 144 | + import numpy as np |
| 145 | +
|
| 146 | + # Simple triangle mesh test |
| 147 | + verts = np.float32([0,0,0, 1,0,0, 0,1,0, 1,1,0]) |
| 148 | + triangles = np.int32([0,1,2, 2,1,3]) |
| 149 | + rays = np.float32([0.33,0.33,100, 0,0,0, -1,1000]) |
| 150 | + hits = np.float32([0,0,0,0]) |
| 151 | +
|
| 152 | + optix = RTX() |
| 153 | + res = optix.build(0, verts, triangles) |
| 154 | + assert res == 0, f'Build failed with {res}' |
| 155 | +
|
| 156 | + res = optix.trace(rays, hits, 1) |
| 157 | + assert res == 0, f'Trace failed with {res}' |
| 158 | +
|
| 159 | + print(f'Hit result: t={hits[0]}, normal=({hits[1]}, {hits[2]}, {hits[3]})') |
| 160 | + assert hits[0] > 0, 'Expected a hit' |
| 161 | + print('GPU ray tracing test PASSED!') |
| 162 | + " |
0 commit comments