214 lines
6.9 KiB
Python
214 lines
6.9 KiB
Python
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
# Copyright (C) 2025 ComfyUI-GeometryPack Contributors
|
|
|
|
"""
|
|
CuMesh Installation - GPU-accelerated mesh processing library.
|
|
|
|
Tries to install cumesh via:
|
|
1. Pre-built wheel from cumesh-wheels repository
|
|
2. Source compilation from JeffreyXiang/CuMesh
|
|
|
|
Requires CUDA and PyTorch. Gracefully skips if not available.
|
|
"""
|
|
|
|
import os
|
|
import sys
|
|
import shutil
|
|
import tempfile
|
|
import subprocess
|
|
from pathlib import Path
|
|
|
|
|
|
# Known wheel configurations
|
|
WHEEL_REPO_BASE = "https://github.com/PozzettiAndrea/cumesh-wheels/releases/download"
|
|
SOURCE_REPO = "https://github.com/JeffreyXiang/CuMesh.git"
|
|
|
|
|
|
def _check_cuda_available():
|
|
"""Check if CUDA is available via PyTorch."""
|
|
try:
|
|
import torch
|
|
if torch.cuda.is_available():
|
|
return True, torch.version.cuda, torch.__version__
|
|
else:
|
|
return False, None, torch.__version__
|
|
except ImportError:
|
|
return False, None, None
|
|
|
|
|
|
def _get_python_version():
|
|
"""Get Python version string for wheel filename."""
|
|
return f"{sys.version_info.major}{sys.version_info.minor}"
|
|
|
|
|
|
def _verify_cumesh_import():
|
|
"""Try to import cumesh and verify it works."""
|
|
try:
|
|
import cumesh
|
|
# Try to instantiate the main class
|
|
_ = cumesh.CuMesh
|
|
return True
|
|
except Exception:
|
|
return False
|
|
|
|
|
|
def _install_wheel(cuda_version, torch_version, python_version):
|
|
"""Try to install cumesh from pre-built wheel."""
|
|
# Format versions for wheel URL
|
|
# CUDA: "12.8" -> "128", Torch: "2.8.0" -> "280"
|
|
cuda_short = cuda_version.replace(".", "")[:3] if cuda_version else None
|
|
torch_short = torch_version.split("+")[0].replace(".", "")[:3] if torch_version else None
|
|
|
|
if not cuda_short or not torch_short:
|
|
print("[CuMesh] Cannot determine CUDA/PyTorch versions for wheel selection")
|
|
return False
|
|
|
|
# Construct wheel URL
|
|
wheel_tag = f"cu{cuda_short}-torch{torch_short}"
|
|
wheel_name = f"cumesh-0.0.1-cp{python_version}-cp{python_version}-linux_x86_64.whl"
|
|
wheel_url = f"{WHEEL_REPO_BASE}/{wheel_tag}/{wheel_name}"
|
|
|
|
print(f"[CuMesh] Trying wheel: {wheel_tag}/{wheel_name}")
|
|
|
|
try:
|
|
result = subprocess.run(
|
|
[sys.executable, "-m", "pip", "install", wheel_url],
|
|
capture_output=True,
|
|
text=True,
|
|
timeout=300
|
|
)
|
|
|
|
if result.returncode == 0:
|
|
print(f"[CuMesh] Wheel installed successfully!")
|
|
return True
|
|
else:
|
|
print(f"[CuMesh] Wheel installation failed (may not exist for this configuration)")
|
|
if "404" in result.stderr or "not found" in result.stderr.lower():
|
|
print(f"[CuMesh] Wheel not available for {wheel_tag}")
|
|
return False
|
|
|
|
except subprocess.TimeoutExpired:
|
|
print("[CuMesh] Wheel download timed out")
|
|
return False
|
|
except Exception as e:
|
|
print(f"[CuMesh] Wheel installation error: {e}")
|
|
return False
|
|
|
|
|
|
def _install_from_source():
|
|
"""Try to install cumesh from source."""
|
|
print("[CuMesh] Attempting source compilation...")
|
|
print("[CuMesh] This may take several minutes...")
|
|
|
|
# Create temporary directory for clone
|
|
temp_dir = tempfile.mkdtemp(prefix="cumesh_build_")
|
|
clone_path = Path(temp_dir) / "CuMesh"
|
|
|
|
try:
|
|
# Clone repository
|
|
print(f"[CuMesh] Cloning {SOURCE_REPO}...")
|
|
result = subprocess.run(
|
|
["git", "clone", "--recursive", SOURCE_REPO, str(clone_path)],
|
|
capture_output=True,
|
|
text=True,
|
|
timeout=300
|
|
)
|
|
|
|
if result.returncode != 0:
|
|
print(f"[CuMesh] Git clone failed: {result.stderr}")
|
|
return False
|
|
|
|
# Install with pip
|
|
print("[CuMesh] Building and installing (this may take a while)...")
|
|
result = subprocess.run(
|
|
[sys.executable, "-m", "pip", "install", ".", "--no-build-isolation"],
|
|
cwd=str(clone_path),
|
|
capture_output=True,
|
|
text=True,
|
|
timeout=1200 # 20 minutes for compilation
|
|
)
|
|
|
|
if result.returncode == 0:
|
|
print("[CuMesh] Source build completed successfully!")
|
|
return True
|
|
else:
|
|
print(f"[CuMesh] Source build failed:")
|
|
print(result.stderr[-2000:] if len(result.stderr) > 2000 else result.stderr)
|
|
return False
|
|
|
|
except subprocess.TimeoutExpired:
|
|
print("[CuMesh] Source build timed out (>20 minutes)")
|
|
return False
|
|
except FileNotFoundError:
|
|
print("[CuMesh] Git not found - cannot clone repository")
|
|
return False
|
|
except Exception as e:
|
|
print(f"[CuMesh] Source build error: {e}")
|
|
return False
|
|
finally:
|
|
# Clean up temp directory
|
|
try:
|
|
shutil.rmtree(temp_dir)
|
|
except Exception:
|
|
pass
|
|
|
|
|
|
def install_cumesh():
|
|
"""
|
|
Install CuMesh library for GPU-accelerated mesh processing.
|
|
|
|
Returns:
|
|
bool: True if installed successfully or already available,
|
|
False if installation failed (graceful failure).
|
|
"""
|
|
print("\n" + "="*60)
|
|
print("ComfyUI-GeometryPack: CuMesh Installation (Optional)")
|
|
print("="*60 + "\n")
|
|
|
|
# Check if already installed
|
|
if _verify_cumesh_import():
|
|
print("[CuMesh] Already installed and working!")
|
|
return True
|
|
|
|
# Check CUDA availability
|
|
cuda_available, cuda_version, torch_version = _check_cuda_available()
|
|
|
|
if not cuda_available:
|
|
print("[CuMesh] CUDA not available - skipping cumesh installation")
|
|
print("[CuMesh] This is fine! The 'cumesh' UV unwrap method will be disabled,")
|
|
print("[CuMesh] but other UV unwrap methods (xatlas, libigl, blender) will work.")
|
|
return True # Graceful skip, not a failure
|
|
|
|
print(f"[CuMesh] CUDA {cuda_version} detected with PyTorch {torch_version}")
|
|
|
|
python_version = _get_python_version()
|
|
print(f"[CuMesh] Python version: {sys.version_info.major}.{sys.version_info.minor}")
|
|
|
|
# Try wheel first
|
|
print("\n[CuMesh] Step 1: Trying pre-built wheel...")
|
|
if _install_wheel(cuda_version, torch_version, python_version):
|
|
if _verify_cumesh_import():
|
|
print("[CuMesh] Installation verified!")
|
|
return True
|
|
else:
|
|
print("[CuMesh] Wheel installed but import failed, trying source...")
|
|
|
|
# Fallback to source
|
|
print("\n[CuMesh] Step 2: Trying source compilation...")
|
|
if _install_from_source():
|
|
if _verify_cumesh_import():
|
|
print("[CuMesh] Installation verified!")
|
|
return True
|
|
else:
|
|
print("[CuMesh] Source build completed but import failed")
|
|
|
|
# Both failed
|
|
print("\n" + "-"*60)
|
|
print("[CuMesh] WARNING: CuMesh installation failed")
|
|
print("[CuMesh] The 'cumesh' UV unwrap method will not be available.")
|
|
print("[CuMesh] Other UV unwrap methods (xatlas, libigl, blender) will still work.")
|
|
print("-"*60)
|
|
|
|
# Return True for graceful failure - don't break the whole install
|
|
return True
|