- 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.
128 lines
3.8 KiB
Go
128 lines
3.8 KiB
Go
// Package blender handles Blender binary management and execution.
|
|
package blender
|
|
|
|
import (
|
|
"fmt"
|
|
"log"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"jiggablend/internal/runner/api"
|
|
"jiggablend/internal/runner/workspace"
|
|
)
|
|
|
|
// Manager handles Blender binary downloads and management.
|
|
type Manager struct {
|
|
manager *api.ManagerClient
|
|
workspaceDir string
|
|
}
|
|
|
|
// NewManager creates a new Blender manager.
|
|
func NewManager(managerClient *api.ManagerClient, workspaceDir string) *Manager {
|
|
return &Manager{
|
|
manager: managerClient,
|
|
workspaceDir: workspaceDir,
|
|
}
|
|
}
|
|
|
|
// GetBinaryPath returns the path to the Blender binary for a specific version.
|
|
// Downloads from manager and extracts if not already present.
|
|
func (m *Manager) GetBinaryPath(version string) (string, error) {
|
|
blenderDir := filepath.Join(m.workspaceDir, "blender-versions")
|
|
if err := os.MkdirAll(blenderDir, 0755); err != nil {
|
|
return "", fmt.Errorf("failed to create blender directory: %w", err)
|
|
}
|
|
|
|
// Check if already installed - look for version folder first
|
|
versionDir := filepath.Join(blenderDir, version)
|
|
binaryPath := filepath.Join(versionDir, "blender")
|
|
|
|
// Check if version folder exists and contains the binary
|
|
if versionInfo, err := os.Stat(versionDir); err == nil && versionInfo.IsDir() {
|
|
// Version folder exists, check if binary is present
|
|
if binaryInfo, err := os.Stat(binaryPath); err == nil {
|
|
// Verify it's actually a file (not a directory)
|
|
if !binaryInfo.IsDir() {
|
|
log.Printf("Found existing Blender %s installation at %s", version, binaryPath)
|
|
return binaryPath, nil
|
|
}
|
|
}
|
|
// Version folder exists but binary is missing - might be incomplete installation
|
|
log.Printf("Version folder %s exists but binary not found, will re-download", versionDir)
|
|
}
|
|
|
|
// Download from manager
|
|
log.Printf("Downloading Blender %s from manager", version)
|
|
|
|
reader, err := m.manager.DownloadBlender(version)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
defer reader.Close()
|
|
|
|
// Manager serves pre-decompressed .tar files - extract directly
|
|
log.Printf("Extracting Blender %s...", version)
|
|
if err := workspace.ExtractTarStripPrefix(reader, versionDir); err != nil {
|
|
return "", fmt.Errorf("failed to extract blender: %w", err)
|
|
}
|
|
|
|
// Verify binary exists
|
|
if _, err := os.Stat(binaryPath); err != nil {
|
|
return "", fmt.Errorf("blender binary not found after extraction")
|
|
}
|
|
|
|
log.Printf("Blender %s installed at %s", version, binaryPath)
|
|
return binaryPath, nil
|
|
}
|
|
|
|
// GetBinaryForJob returns the Blender binary path for a job.
|
|
// Uses the version from metadata or falls back to system blender.
|
|
func (m *Manager) GetBinaryForJob(version string) (string, error) {
|
|
if version == "" {
|
|
return "blender", nil // System blender
|
|
}
|
|
|
|
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
|
|
}
|
|
|