Implement GPU backend detection for Blender compatibility
- Added functionality to detect GPU backends (HIP and NVIDIA) during runner registration, enhancing compatibility for Blender versions below 4.x. - Introduced a new method, DetectAndStoreGPUBackends, to download the latest Blender and run a detection script, storing the results for future rendering decisions. - Updated rendering logic to force CPU rendering when HIP is detected on systems with Blender < 4.x, ensuring stability and compatibility. - Enhanced the Context structure to include flags for GPU detection status, improving error handling and rendering decisions based on GPU availability.
This commit is contained in:
@@ -6,6 +6,7 @@ import (
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"jiggablend/internal/runner/api"
|
||||
"jiggablend/internal/runner/workspace"
|
||||
@@ -85,3 +86,42 @@ func (m *Manager) GetBinaryForJob(version string) (string, error) {
|
||||
return m.GetBinaryPath(version)
|
||||
}
|
||||
|
||||
// TarballEnv returns a copy of baseEnv with LD_LIBRARY_PATH set so that a
|
||||
// tarball Blender installation can find its bundled libs (e.g. lib/python3.x).
|
||||
// If blenderBinary is the system "blender" or has no path component, baseEnv is
|
||||
// returned unchanged.
|
||||
func TarballEnv(blenderBinary string, baseEnv []string) []string {
|
||||
if blenderBinary == "" || blenderBinary == "blender" {
|
||||
return baseEnv
|
||||
}
|
||||
if !strings.Contains(blenderBinary, string(os.PathSeparator)) {
|
||||
return baseEnv
|
||||
}
|
||||
blenderDir := filepath.Dir(blenderBinary)
|
||||
libDir := filepath.Join(blenderDir, "lib")
|
||||
ldLib := libDir
|
||||
for _, e := range baseEnv {
|
||||
if strings.HasPrefix(e, "LD_LIBRARY_PATH=") {
|
||||
existing := strings.TrimPrefix(e, "LD_LIBRARY_PATH=")
|
||||
if existing != "" {
|
||||
ldLib = libDir + ":" + existing
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
out := make([]string, 0, len(baseEnv)+1)
|
||||
done := false
|
||||
for _, e := range baseEnv {
|
||||
if strings.HasPrefix(e, "LD_LIBRARY_PATH=") {
|
||||
out = append(out, "LD_LIBRARY_PATH="+ldLib)
|
||||
done = true
|
||||
continue
|
||||
}
|
||||
out = append(out, e)
|
||||
}
|
||||
if !done {
|
||||
out = append(out, "LD_LIBRARY_PATH="+ldLib)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
|
||||
45
internal/runner/blender/detect.go
Normal file
45
internal/runner/blender/detect.go
Normal file
@@ -0,0 +1,45 @@
|
||||
// Package blender: GPU backend detection for HIP vs NVIDIA.
|
||||
package blender
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"jiggablend/pkg/scripts"
|
||||
)
|
||||
|
||||
// DetectGPUBackends runs a minimal Blender script to detect whether HIP (AMD) and/or
|
||||
// NVIDIA (CUDA/OptiX) devices are available. Use this to decide whether to force CPU
|
||||
// for Blender < 4.x (only force when HIP is present, since HIP has no official support pre-4).
|
||||
func DetectGPUBackends(blenderBinary, scriptDir string) (hasHIP, hasNVIDIA bool, err error) {
|
||||
scriptPath := filepath.Join(scriptDir, "detect_gpu_backends.py")
|
||||
if err := os.WriteFile(scriptPath, []byte(scripts.DetectGPUBackends), 0644); err != nil {
|
||||
return false, false, fmt.Errorf("write detection script: %w", err)
|
||||
}
|
||||
defer os.Remove(scriptPath)
|
||||
|
||||
env := TarballEnv(blenderBinary, os.Environ())
|
||||
cmd := exec.Command(blenderBinary, "-b", "--python", scriptPath)
|
||||
cmd.Env = env
|
||||
cmd.Dir = scriptDir
|
||||
out, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
return false, false, fmt.Errorf("run blender detection: %w (output: %s)", err, string(out))
|
||||
}
|
||||
|
||||
scanner := bufio.NewScanner(strings.NewReader(string(out)))
|
||||
for scanner.Scan() {
|
||||
line := strings.TrimSpace(scanner.Text())
|
||||
switch line {
|
||||
case "HAS_HIP":
|
||||
hasHIP = true
|
||||
case "HAS_NVIDIA":
|
||||
hasNVIDIA = true
|
||||
}
|
||||
}
|
||||
return hasHIP, hasNVIDIA, scanner.Err()
|
||||
}
|
||||
Reference in New Issue
Block a user