Enhance device management and model handling in SnapForm
- Updated frame extraction logic to allow for single frame extraction. - Integrated model readiness checks for BEN2 and DA3 models in relevant operators. - Added directory name attribute to model specifications for better organization. - Improved device selection logic for production and debug tasks. - Refactored preferences to expose device settings and ensure they reflect available hardware. - Enhanced runtime device detection and management, including support for CUDA and MPS. - Updated tests to cover new device management features and model directory handling. - Removed deprecated download model tests to streamline codebase.
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import json
|
||||
import os
|
||||
import platform
|
||||
import secrets
|
||||
import shutil
|
||||
import socket
|
||||
@@ -15,7 +16,12 @@ from urllib.request import ProxyHandler, Request, build_opener
|
||||
|
||||
import bpy
|
||||
|
||||
from .models import BEN2_MODEL, get_downloadable_model, selected_model_key
|
||||
from .models import (
|
||||
BEN2_MODEL,
|
||||
get_downloadable_model,
|
||||
model_directory_name,
|
||||
selected_model_key,
|
||||
)
|
||||
|
||||
|
||||
DA3_COMMIT = "3d835ec1a5802d64a8b8b15f817a1ab54809bfe4"
|
||||
@@ -107,7 +113,16 @@ def models_directory():
|
||||
|
||||
|
||||
def model_directory(model_key):
|
||||
return models_directory() / model_key.lower()
|
||||
root = models_directory()
|
||||
directory = root / model_directory_name(model_key)
|
||||
legacy_directory = root / model_key.lower()
|
||||
if (
|
||||
not directory.is_dir()
|
||||
and legacy_directory.is_dir()
|
||||
and legacy_directory != directory
|
||||
):
|
||||
legacy_directory.rename(directory)
|
||||
return directory
|
||||
|
||||
|
||||
def model_ready(model_key):
|
||||
@@ -117,6 +132,61 @@ def model_ready(model_key):
|
||||
)
|
||||
|
||||
|
||||
def runtime_devices():
|
||||
"""Devices detected by the installed Runtime, or None when unknown."""
|
||||
ready_path = runtime_directory() / "snapform_ready.json"
|
||||
if not ready_path.is_file():
|
||||
return None
|
||||
try:
|
||||
payload = json.loads(ready_path.read_text(encoding="utf-8"))
|
||||
except (json.JSONDecodeError, OSError):
|
||||
return None
|
||||
devices = payload.get("devices")
|
||||
if not isinstance(devices, list) or not devices:
|
||||
return None
|
||||
return [str(name).lower() for name in devices]
|
||||
|
||||
|
||||
def machine_devices():
|
||||
"""Devices the machine can run, fastest first; used before Runtime install."""
|
||||
devices = ["cpu"]
|
||||
if shutil.which("nvidia-smi"):
|
||||
devices.insert(0, "cuda")
|
||||
elif sys.platform == "darwin" and platform.machine().lower() in {
|
||||
"arm64",
|
||||
"aarch64",
|
||||
}:
|
||||
devices.insert(0, "mps")
|
||||
return devices
|
||||
|
||||
|
||||
def supported_devices():
|
||||
"""Inference devices available on this machine, fastest first."""
|
||||
return runtime_devices() or machine_devices()
|
||||
|
||||
|
||||
DEVICE_LABELS = {
|
||||
"cuda": ("CUDA", "NVIDIA CUDA"),
|
||||
"mps": ("MPS", "Apple Metal (MPS)"),
|
||||
"cpu": ("CPU", "CPU"),
|
||||
}
|
||||
|
||||
|
||||
def device_enum_items(_owner, _context):
|
||||
"""Blender EnumProperty items listing only devices supported on this machine."""
|
||||
return [
|
||||
(name.upper(), *DEVICE_LABELS[name], index)
|
||||
for index, name in enumerate(supported_devices())
|
||||
]
|
||||
|
||||
|
||||
def production_device():
|
||||
"""Device configured for production tasks, falling back to Auto."""
|
||||
addon_preferences = preferences()
|
||||
configured = getattr(addon_preferences, "device", "")
|
||||
return configured or "AUTO"
|
||||
|
||||
|
||||
def jobs_directory():
|
||||
path = storage_root() / "jobs"
|
||||
path.mkdir(parents=True, exist_ok=True)
|
||||
@@ -153,13 +223,7 @@ def new_job_paths(job_type):
|
||||
|
||||
|
||||
def uv_executable():
|
||||
addon_preferences = preferences()
|
||||
configured = getattr(addon_preferences, "uv_executable", "uv")
|
||||
resolved = shutil.which(configured)
|
||||
if resolved:
|
||||
return resolved
|
||||
if Path(configured).is_file():
|
||||
return str(Path(configured))
|
||||
"""Return the bundled uv path inside the shared storage."""
|
||||
return str(uv_cache_path())
|
||||
|
||||
|
||||
@@ -171,9 +235,7 @@ def uv_cache_path():
|
||||
|
||||
def install_runtime_command(status_path):
|
||||
executable = uv_executable()
|
||||
addon_preferences = preferences()
|
||||
backend = getattr(addon_preferences, "torch_backend", "CU128")
|
||||
pypi_index = getattr(addon_preferences, "pypi_index_url", "") or ""
|
||||
backend = "cu128" if "cuda" in machine_devices() else "cpu"
|
||||
script = Path(__file__).with_name("bootstrap_runtime.py")
|
||||
command = [
|
||||
sys.executable,
|
||||
@@ -185,7 +247,7 @@ def install_runtime_command(status_path):
|
||||
"--models-dir",
|
||||
str(models_directory()),
|
||||
"--backend",
|
||||
backend.lower(),
|
||||
backend,
|
||||
"--da3-commit",
|
||||
DA3_COMMIT,
|
||||
"--ben2-commit",
|
||||
@@ -193,8 +255,6 @@ def install_runtime_command(status_path):
|
||||
"--status",
|
||||
str(status_path),
|
||||
]
|
||||
if pypi_index:
|
||||
command.extend(["--pypi-index", pypi_index])
|
||||
return command
|
||||
|
||||
|
||||
@@ -640,6 +700,7 @@ def remove_background_request(
|
||||
model_key,
|
||||
video_frames=None,
|
||||
start_frame=1,
|
||||
device=None,
|
||||
):
|
||||
return HostJobRequest(
|
||||
{
|
||||
@@ -650,7 +711,7 @@ def remove_background_request(
|
||||
"model_dir": str(model_directory(model_key)),
|
||||
"output_dir": str(result_directory),
|
||||
"status": str(status_path),
|
||||
"device": settings.device.lower(),
|
||||
"device": (device or settings.device).lower(),
|
||||
"video_frames": (
|
||||
settings.video_frames
|
||||
if video_frames is None
|
||||
@@ -701,6 +762,7 @@ def reconstruct_request(
|
||||
use_ray_pose=None,
|
||||
remove_background=False,
|
||||
start_frame=1,
|
||||
device=None,
|
||||
):
|
||||
snapform_selected_key = model_key or selected_model_key(settings, export_format)
|
||||
snapform_selected_process_res = (
|
||||
@@ -732,7 +794,7 @@ def reconstruct_request(
|
||||
"gs_views_interval": settings.gs_views_interval,
|
||||
"video_frames": settings.video_frames,
|
||||
"start_frame": start_frame,
|
||||
"device": settings.device.lower(),
|
||||
"device": (device or settings.device).lower(),
|
||||
"use_ray_pose": 1 if snapform_selected_ray_pose else 0,
|
||||
"ref_view_strategy": settings.ref_view_strategy,
|
||||
"remove_background_model_dir": "",
|
||||
|
||||
Reference in New Issue
Block a user