Add hardware compatibility flags for CPU rendering and HIPRT control
- Introduced `--force-cpu-rendering` and `--disable-hiprt` flags to the runner command, allowing users to enforce CPU rendering and disable HIPRT acceleration. - Updated the runner initialization and context structures to accommodate the new flags, enhancing flexibility in rendering configurations. - Modified the rendering logic to respect these flags, improving compatibility and user control over rendering behavior in Blender.
This commit is contained in:
@@ -154,6 +154,9 @@ bin/jiggablend runner --api-key <your-api-key>
|
|||||||
# With custom options
|
# With custom options
|
||||||
bin/jiggablend runner --manager http://localhost:8080 --name my-runner --api-key <key> --log-file runner.log
|
bin/jiggablend runner --manager http://localhost:8080 --name my-runner --api-key <key> --log-file runner.log
|
||||||
|
|
||||||
|
# Hardware compatibility flags (force CPU + disable HIPRT)
|
||||||
|
bin/jiggablend runner --api-key <key> --force-cpu-rendering --disable-hiprt
|
||||||
|
|
||||||
# Using environment variables
|
# Using environment variables
|
||||||
JIGGABLEND_MANAGER=http://localhost:8080 JIGGABLEND_API_KEY=<key> bin/jiggablend runner
|
JIGGABLEND_MANAGER=http://localhost:8080 JIGGABLEND_API_KEY=<key> bin/jiggablend runner
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -37,6 +37,8 @@ func init() {
|
|||||||
runnerCmd.Flags().String("log-level", "info", "Log level (debug, info, warn, error)")
|
runnerCmd.Flags().String("log-level", "info", "Log level (debug, info, warn, error)")
|
||||||
runnerCmd.Flags().BoolP("verbose", "v", false, "Enable verbose logging (same as --log-level=debug)")
|
runnerCmd.Flags().BoolP("verbose", "v", false, "Enable verbose logging (same as --log-level=debug)")
|
||||||
runnerCmd.Flags().Duration("poll-interval", 5*time.Second, "Job polling interval")
|
runnerCmd.Flags().Duration("poll-interval", 5*time.Second, "Job polling interval")
|
||||||
|
runnerCmd.Flags().Bool("force-cpu-rendering", false, "Force CPU rendering for all jobs (disables GPU rendering)")
|
||||||
|
runnerCmd.Flags().Bool("disable-hiprt", false, "Disable HIPRT acceleration in Blender Cycles")
|
||||||
|
|
||||||
// Bind flags to viper with JIGGABLEND_ prefix
|
// Bind flags to viper with JIGGABLEND_ prefix
|
||||||
runnerViper.SetEnvPrefix("JIGGABLEND")
|
runnerViper.SetEnvPrefix("JIGGABLEND")
|
||||||
@@ -51,6 +53,8 @@ func init() {
|
|||||||
runnerViper.BindPFlag("log_level", runnerCmd.Flags().Lookup("log-level"))
|
runnerViper.BindPFlag("log_level", runnerCmd.Flags().Lookup("log-level"))
|
||||||
runnerViper.BindPFlag("verbose", runnerCmd.Flags().Lookup("verbose"))
|
runnerViper.BindPFlag("verbose", runnerCmd.Flags().Lookup("verbose"))
|
||||||
runnerViper.BindPFlag("poll_interval", runnerCmd.Flags().Lookup("poll-interval"))
|
runnerViper.BindPFlag("poll_interval", runnerCmd.Flags().Lookup("poll-interval"))
|
||||||
|
runnerViper.BindPFlag("force_cpu_rendering", runnerCmd.Flags().Lookup("force-cpu-rendering"))
|
||||||
|
runnerViper.BindPFlag("disable_hiprt", runnerCmd.Flags().Lookup("disable-hiprt"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func runRunner(cmd *cobra.Command, args []string) {
|
func runRunner(cmd *cobra.Command, args []string) {
|
||||||
@@ -63,6 +67,8 @@ func runRunner(cmd *cobra.Command, args []string) {
|
|||||||
logLevel := runnerViper.GetString("log_level")
|
logLevel := runnerViper.GetString("log_level")
|
||||||
verbose := runnerViper.GetBool("verbose")
|
verbose := runnerViper.GetBool("verbose")
|
||||||
pollInterval := runnerViper.GetDuration("poll_interval")
|
pollInterval := runnerViper.GetDuration("poll_interval")
|
||||||
|
forceCPURendering := runnerViper.GetBool("force_cpu_rendering")
|
||||||
|
disableHIPRT := runnerViper.GetBool("disable_hiprt")
|
||||||
|
|
||||||
var r *runner.Runner
|
var r *runner.Runner
|
||||||
|
|
||||||
@@ -118,7 +124,7 @@ func runRunner(cmd *cobra.Command, args []string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create runner
|
// Create runner
|
||||||
r = runner.New(managerURL, name, hostname)
|
r = runner.New(managerURL, name, hostname, forceCPURendering, disableHIPRT)
|
||||||
|
|
||||||
// Check for required tools early to fail fast
|
// Check for required tools early to fail fast
|
||||||
if err := r.CheckRequiredTools(); err != nil {
|
if err := r.CheckRequiredTools(); err != nil {
|
||||||
|
|||||||
@@ -54,10 +54,15 @@ type Runner struct {
|
|||||||
hasNVIDIA bool
|
hasNVIDIA bool
|
||||||
gpuBackendProbed bool
|
gpuBackendProbed bool
|
||||||
gpuDetectionFailed bool
|
gpuDetectionFailed bool
|
||||||
|
|
||||||
|
// forceCPURendering forces CPU rendering for all jobs regardless of metadata/backend detection.
|
||||||
|
forceCPURendering bool
|
||||||
|
// disableHIPRT disables HIPRT acceleration when configuring Cycles HIP devices.
|
||||||
|
disableHIPRT bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// New creates a new runner.
|
// New creates a new runner.
|
||||||
func New(managerURL, name, hostname string) *Runner {
|
func New(managerURL, name, hostname string, forceCPURendering, disableHIPRT bool) *Runner {
|
||||||
manager := api.NewManagerClient(managerURL)
|
manager := api.NewManagerClient(managerURL)
|
||||||
|
|
||||||
r := &Runner{
|
r := &Runner{
|
||||||
@@ -67,6 +72,9 @@ func New(managerURL, name, hostname string) *Runner {
|
|||||||
processes: executils.NewProcessTracker(),
|
processes: executils.NewProcessTracker(),
|
||||||
stopChan: make(chan struct{}),
|
stopChan: make(chan struct{}),
|
||||||
processors: make(map[string]tasks.Processor),
|
processors: make(map[string]tasks.Processor),
|
||||||
|
|
||||||
|
forceCPURendering: forceCPURendering,
|
||||||
|
disableHIPRT: disableHIPRT,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate fingerprint
|
// Generate fingerprint
|
||||||
@@ -307,6 +315,8 @@ func (r *Runner) executeJob(job *api.NextJobResponse) (err error) {
|
|||||||
r.IsGPULockedOut(),
|
r.IsGPULockedOut(),
|
||||||
r.HasHIP(),
|
r.HasHIP(),
|
||||||
r.GPUDetectionFailed(),
|
r.GPUDetectionFailed(),
|
||||||
|
r.forceCPURendering,
|
||||||
|
r.disableHIPRT,
|
||||||
func() { r.SetGPULockedOut(true) },
|
func() { r.SetGPULockedOut(true) },
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -49,6 +49,10 @@ type Context struct {
|
|||||||
GPUDetectionFailed bool
|
GPUDetectionFailed bool
|
||||||
// OnGPUError is called when a GPU error line is seen in render logs; typically sets runner GPU lockout.
|
// OnGPUError is called when a GPU error line is seen in render logs; typically sets runner GPU lockout.
|
||||||
OnGPUError func()
|
OnGPUError func()
|
||||||
|
// ForceCPURendering is a runner-level override that forces CPU rendering for all jobs.
|
||||||
|
ForceCPURendering bool
|
||||||
|
// DisableHIPRT is a runner-level override that disables HIPRT acceleration in Blender.
|
||||||
|
DisableHIPRT bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// ErrJobCancelled indicates the manager-side job was cancelled during execution.
|
// ErrJobCancelled indicates the manager-side job was cancelled during execution.
|
||||||
@@ -73,6 +77,8 @@ func NewContext(
|
|||||||
gpuLockedOut bool,
|
gpuLockedOut bool,
|
||||||
hasHIP bool,
|
hasHIP bool,
|
||||||
gpuDetectionFailed bool,
|
gpuDetectionFailed bool,
|
||||||
|
forceCPURendering bool,
|
||||||
|
disableHIPRT bool,
|
||||||
onGPUError func(),
|
onGPUError func(),
|
||||||
) *Context {
|
) *Context {
|
||||||
if frameEnd < frameStart {
|
if frameEnd < frameStart {
|
||||||
@@ -97,6 +103,8 @@ func NewContext(
|
|||||||
GPULockedOut: gpuLockedOut,
|
GPULockedOut: gpuLockedOut,
|
||||||
HasHIP: hasHIP,
|
HasHIP: hasHIP,
|
||||||
GPUDetectionFailed: gpuDetectionFailed,
|
GPUDetectionFailed: gpuDetectionFailed,
|
||||||
|
ForceCPURendering: forceCPURendering,
|
||||||
|
DisableHIPRT: disableHIPRT,
|
||||||
OnGPUError: onGPUError,
|
OnGPUError: onGPUError,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -182,6 +190,9 @@ func (c *Context) ShouldEnableExecution() bool {
|
|||||||
// (runner GPU lockout, GPU detection failed at startup for any version, metadata force_cpu,
|
// (runner GPU lockout, GPU detection failed at startup for any version, metadata force_cpu,
|
||||||
// or Blender < 4.x when the runner has HIP).
|
// or Blender < 4.x when the runner has HIP).
|
||||||
func (c *Context) ShouldForceCPU() bool {
|
func (c *Context) ShouldForceCPU() bool {
|
||||||
|
if c.ForceCPURendering {
|
||||||
|
return true
|
||||||
|
}
|
||||||
if c.GPULockedOut {
|
if c.GPULockedOut {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,8 +27,8 @@ func NewRenderProcessor() *RenderProcessor {
|
|||||||
|
|
||||||
// gpuErrorSubstrings are log line substrings that indicate a GPU backend error (matched case-insensitively); any match triggers full GPU lockout.
|
// gpuErrorSubstrings are log line substrings that indicate a GPU backend error (matched case-insensitively); any match triggers full GPU lockout.
|
||||||
var gpuErrorSubstrings = []string{
|
var gpuErrorSubstrings = []string{
|
||||||
"illegal address in hip", // HIP (AMD) e.g. "Illegal address in HIP" or "Illegal address in hip"
|
"illegal address in hip", // HIP (AMD) e.g. "Illegal address in HIP" or "Illegal address in hip"
|
||||||
"hiperror", // hipError* codes
|
"hiperror", // hipError* codes
|
||||||
"hip error",
|
"hip error",
|
||||||
"cuda error",
|
"cuda error",
|
||||||
"cuerror",
|
"cuerror",
|
||||||
@@ -107,7 +107,9 @@ func (p *RenderProcessor) Process(ctx *Context) error {
|
|||||||
v := ctx.GetBlenderVersion()
|
v := ctx.GetBlenderVersion()
|
||||||
major := parseBlenderMajor(v)
|
major := parseBlenderMajor(v)
|
||||||
isPre4 := v != "" && major >= 0 && major < 4
|
isPre4 := v != "" && major >= 0 && major < 4
|
||||||
if ctx.GPUDetectionFailed {
|
if ctx.ForceCPURendering {
|
||||||
|
ctx.Info("Runner compatibility flag is enabled: forcing CPU rendering for this job")
|
||||||
|
} else if ctx.GPUDetectionFailed {
|
||||||
ctx.Info("GPU backend detection failed at startup—we could not determine whether this machine has HIP (AMD) or NVIDIA GPUs, so rendering will use CPU to avoid compatibility issues")
|
ctx.Info("GPU backend detection failed at startup—we could not determine whether this machine has HIP (AMD) or NVIDIA GPUs, so rendering will use CPU to avoid compatibility issues")
|
||||||
} else if isPre4 && ctx.HasHIP {
|
} else if isPre4 && ctx.HasHIP {
|
||||||
ctx.Info("Blender < 4.x has no official HIP support: using CPU rendering only")
|
ctx.Info("Blender < 4.x has no official HIP support: using CPU rendering only")
|
||||||
@@ -193,6 +195,7 @@ func (p *RenderProcessor) createRenderScript(ctx *Context, renderFormat string)
|
|||||||
settingsMap = make(map[string]interface{})
|
settingsMap = make(map[string]interface{})
|
||||||
}
|
}
|
||||||
settingsMap["force_cpu"] = ctx.ShouldForceCPU()
|
settingsMap["force_cpu"] = ctx.ShouldForceCPU()
|
||||||
|
settingsMap["disable_hiprt"] = ctx.DisableHIPRT
|
||||||
settingsJSON, err := json.Marshal(settingsMap)
|
settingsJSON, err := json.Marshal(settingsMap)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
if err := os.WriteFile(renderSettingsFilePath, settingsJSON, 0644); err != nil {
|
if err := os.WriteFile(renderSettingsFilePath, settingsJSON, 0644); err != nil {
|
||||||
|
|||||||
@@ -175,9 +175,13 @@ if render_settings_override:
|
|||||||
if current_engine == 'CYCLES':
|
if current_engine == 'CYCLES':
|
||||||
# Check if CPU rendering is forced
|
# Check if CPU rendering is forced
|
||||||
force_cpu = False
|
force_cpu = False
|
||||||
|
disable_hiprt = False
|
||||||
if render_settings_override and render_settings_override.get('force_cpu'):
|
if render_settings_override and render_settings_override.get('force_cpu'):
|
||||||
force_cpu = render_settings_override.get('force_cpu', False)
|
force_cpu = render_settings_override.get('force_cpu', False)
|
||||||
print("Force CPU rendering is enabled - skipping GPU detection")
|
print("Force CPU rendering is enabled - skipping GPU detection")
|
||||||
|
if render_settings_override and render_settings_override.get('disable_hiprt'):
|
||||||
|
disable_hiprt = render_settings_override.get('disable_hiprt', False)
|
||||||
|
print("Disable HIPRT flag is enabled")
|
||||||
|
|
||||||
# Ensure Cycles addon is enabled
|
# Ensure Cycles addon is enabled
|
||||||
try:
|
try:
|
||||||
@@ -321,7 +325,16 @@ if current_engine == 'CYCLES':
|
|||||||
try:
|
try:
|
||||||
if best_device_type == 'HIP':
|
if best_device_type == 'HIP':
|
||||||
# HIPRT (HIP Ray Tracing) for AMD GPUs
|
# HIPRT (HIP Ray Tracing) for AMD GPUs
|
||||||
if hasattr(cycles_prefs, 'use_hiprt'):
|
if disable_hiprt:
|
||||||
|
if hasattr(cycles_prefs, 'use_hiprt'):
|
||||||
|
cycles_prefs.use_hiprt = False
|
||||||
|
print(f" Disabled HIPRT (HIP Ray Tracing) via runner compatibility flag")
|
||||||
|
elif hasattr(scene.cycles, 'use_hiprt'):
|
||||||
|
scene.cycles.use_hiprt = False
|
||||||
|
print(f" Disabled HIPRT (HIP Ray Tracing) via runner compatibility flag")
|
||||||
|
else:
|
||||||
|
print(f" HIPRT toggle not available on this Blender version")
|
||||||
|
elif hasattr(cycles_prefs, 'use_hiprt'):
|
||||||
cycles_prefs.use_hiprt = True
|
cycles_prefs.use_hiprt = True
|
||||||
print(f" Enabled HIPRT (HIP Ray Tracing) for faster rendering")
|
print(f" Enabled HIPRT (HIP Ray Tracing) for faster rendering")
|
||||||
elif hasattr(scene.cycles, 'use_hiprt'):
|
elif hasattr(scene.cycles, 'use_hiprt'):
|
||||||
|
|||||||
Reference in New Issue
Block a user