From 8f00d8b0c8e50947ddf15c31d1f8ce4eade882b9 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Thu, 27 Feb 2025 15:12:54 +0100 Subject: [PATCH] Fix: Cycles hardware RT is only supported if all multi devices have it Pull Request: https://projects.blender.org/blender/blender/pulls/135179 --- intern/cycles/blender/addon/properties.py | 35 ++++++++++++++-------- intern/cycles/blender/device.cpp | 7 ----- intern/cycles/device/multi/device.cpp | 36 +++++++++++++++++++++-- 3 files changed, 56 insertions(+), 22 deletions(-) diff --git a/intern/cycles/blender/addon/properties.py b/intern/cycles/blender/addon/properties.py index 64428eddc5d..7369fce9c90 100644 --- a/intern/cycles/blender/addon/properties.py +++ b/intern/cycles/blender/addon/properties.py @@ -1835,16 +1835,26 @@ class CyclesPreferences(bpy.types.AddonPreferences): self._draw_devices(row, compute_device_type, devices) import _cycles - has_peer_memory = 0 - has_rt_api_support = {'METAL': False, 'HIP': False, 'ONEAPI': False} + has_peer_memory = False + has_enabled_hardware_rt = False + has_disabled_hardware_rt = False for device in self.get_device_list(compute_device_type): - if device[3] and self.find_existing_device_entry(device).use: - has_peer_memory += 1 - if device[4] and self.find_existing_device_entry(device).use: - device_type = device[1] - has_rt_api_support[device_type] = True + if not self.find_existing_device_entry(device).use: + continue + if device[1] != compute_device_type: + continue - if has_peer_memory > 1: + if device[3]: + has_peer_memory = True + if device[4]: + has_enabled_hardware_rt = True + else: + has_disabled_hardware_rt = True + + # Any device without RT support will disable it for all. + has_hardware_rt = has_enabled_hardware_rt and not has_disabled_hardware_rt + + if has_peer_memory: row = layout.row() row.use_property_split = True row.prop(self, "peer_memory") @@ -1857,18 +1867,19 @@ class CyclesPreferences(bpy.types.AddonPreferences): col = layout.column() col.use_property_split = True col.prop(self, "kernel_optimization_level") - if has_rt_api_support['METAL']: - col.prop(self, "metalrt") + row = col.row() + row.active = has_hardware_rt + row.prop(self, "metalrt") if compute_device_type == 'HIP': import platform row = layout.row() - row.active = has_rt_api_support['HIP'] + row.active = has_hardware_rt row.prop(self, "use_hiprt") elif compute_device_type == 'ONEAPI' and _cycles.with_embree_gpu: row = layout.row() - row.active = has_rt_api_support['ONEAPI'] + row.active = has_hardware_rt row.prop(self, "use_oneapirt") def draw(self, context): diff --git a/intern/cycles/blender/device.cpp b/intern/cycles/blender/device.cpp index 8242ab5f362..9cb70805be2 100644 --- a/intern/cycles/blender/device.cpp +++ b/intern/cycles/blender/device.cpp @@ -63,13 +63,6 @@ static void adjust_device_info(DeviceInfo &device, PointerRNA cpreferences, bool adjust_device_info_from_preferences(device, cpreferences); for (DeviceInfo &info : device.multi_devices) { adjust_device_info_from_preferences(info, cpreferences); - - /* There is an accumulative logic here, because Multi-devices are supported only for - * the same backend + CPU in Blender right now, and both oneAPI and Metal have a - * global boolean backend setting for enabling/disabling Hardware Ray Tracing, - * so all sub-devices in the multi-device should enable (or disable) Hardware Ray Tracing - * simultaneously (and CPU device is expected to ignore `use_hardware_raytracing` setting). */ - device.use_hardware_raytracing |= info.use_hardware_raytracing; } if (preview) { diff --git a/intern/cycles/device/multi/device.cpp b/intern/cycles/device/multi/device.cpp index d1489524289..758812e4fac 100644 --- a/intern/cycles/device/multi/device.cpp +++ b/intern/cycles/device/multi/device.cpp @@ -31,10 +31,12 @@ class MultiDevice : public Device { device_ptr unique_key = 1; vector> peer_islands; - MultiDevice(const DeviceInfo &info, Stats &stats, Profiler &profiler, bool headless) - : Device(info, stats, profiler, headless) + MultiDevice(const DeviceInfo &info_, Stats &stats, Profiler &profiler, bool headless) + : Device(info_, stats, profiler, headless) { - for (const DeviceInfo &subinfo : info.multi_devices) { + verify_hardware_raytracing(); + + for (const DeviceInfo &subinfo : this->info.multi_devices) { /* Always add CPU devices at the back since GPU devices can change * host memory pointers, which CPU uses as device pointer. */ SubDevice *sub; @@ -78,6 +80,34 @@ class MultiDevice : public Device { } } + void verify_hardware_raytracing() + { + /* Determine if we can use hardware ray-tracing. It is only supported if all selected + * GPU devices support it. Both the backends and scene update code do not support mixed + * BVH2 and hardware raytracing. The CPU device will ignore this setting. */ + bool have_disabled_hardware_rt = false; + bool have_enabled_hardware_rt = false; + + for (const DeviceInfo &subinfo : info.multi_devices) { + if (subinfo.type != DEVICE_CPU) { + if (subinfo.use_hardware_raytracing) { + have_enabled_hardware_rt = true; + } + else { + have_disabled_hardware_rt = true; + } + } + } + + info.use_hardware_raytracing = have_enabled_hardware_rt && !have_disabled_hardware_rt; + + for (DeviceInfo &subinfo : info.multi_devices) { + if (subinfo.type != DEVICE_CPU) { + subinfo.use_hardware_raytracing = info.use_hardware_raytracing; + } + } + } + const string &error_message() override { error_msg.clear();