diff --git a/intern/cycles/blender/addon/properties.py b/intern/cycles/blender/addon/properties.py index 75b44215536..71bc1f71100 100644 --- a/intern/cycles/blender/addon/properties.py +++ b/intern/cycles/blender/addon/properties.py @@ -1472,11 +1472,16 @@ class CyclesPreferences(bpy.types.AddonPreferences): default=False, ) - use_metalrt: BoolProperty( - name="MetalRT (Experimental)", + metalrt: EnumProperty( + name="MetalRT", description="MetalRT for ray tracing uses less memory for scenes which use curves extensively, and can give better " - "performance in specific cases. However this support is experimental and some scenes may render incorrectly", - default=False, + "performance in specific cases.", + default='AUTO', + items=( + ('OFF', "Off", "Disable MetalRT (uses BVH2 layout for intersection queries)"), + ('ON', "On", "Enable MetalRT for intersection queries"), + ('AUTO', "Auto", "Automatically pick the fastest intersection method"), + ), ) use_hiprt: BoolProperty( @@ -1711,7 +1716,7 @@ class CyclesPreferences(bpy.types.AddonPreferences): if is_arm64: col.prop(self, "kernel_optimization_level") if has_rt_api_support: - col.prop(self, "use_metalrt") + col.prop(self, "metalrt") if compute_device_type == 'HIP': has_cuda, has_optix, has_hip, has_metal, has_oneapi, has_hiprt = _cycles.get_device_types() diff --git a/intern/cycles/blender/device.cpp b/intern/cycles/blender/device.cpp index d5f5d4931ff..18c4026bffe 100644 --- a/intern/cycles/blender/device.cpp +++ b/intern/cycles/blender/device.cpp @@ -39,8 +39,17 @@ void static adjust_device_info_from_preferences(DeviceInfo &info, PointerRNA cpr info.has_peer_memory = false; } - if (info.type == DEVICE_METAL && !get_boolean(cpreferences, "use_metalrt")) { - info.use_hardware_raytracing = false; + if (info.type == DEVICE_METAL) { + MetalRTSetting use_metalrt = (MetalRTSetting)get_enum( + cpreferences, "metalrt", METALRT_NUM_SETTINGS, METALRT_AUTO); + + info.use_hardware_raytracing = info.use_metalrt_by_default; + if (use_metalrt == METALRT_OFF) { + info.use_hardware_raytracing = false; + } + else if (use_metalrt == METALRT_ON) { + info.use_hardware_raytracing = true; + } } if (info.type == DEVICE_ONEAPI && !get_boolean(cpreferences, "use_oneapirt")) { diff --git a/intern/cycles/device/device.h b/intern/cycles/device/device.h index 2eaa8164761..b499058ce1a 100644 --- a/intern/cycles/device/device.h +++ b/intern/cycles/device/device.h @@ -67,6 +67,14 @@ enum KernelOptimizationLevel { KERNEL_OPTIMIZATION_NUM_LEVELS }; +enum MetalRTSetting { + METALRT_OFF = 0, + METALRT_ON = 1, + METALRT_AUTO = 2, + + METALRT_NUM_SETTINGS +}; + class DeviceInfo { public: DeviceType type; @@ -83,6 +91,7 @@ class DeviceInfo { bool has_peer_memory; /* GPU has P2P access to memory of another GPU. */ bool has_gpu_queue; /* Device supports GPU queue. */ bool use_hardware_raytracing; /* Use hardware instructions to accelerate ray tracing. */ + bool use_metalrt_by_default; /* Use MetalRT by default. */ KernelOptimizationLevel kernel_optimization_level; /* Optimization level applied to path tracing * kernels (Metal only). */ DenoiserTypeMask denoisers; /* Supported denoiser types. */ @@ -106,6 +115,7 @@ class DeviceInfo { has_peer_memory = false; has_gpu_queue = false; use_hardware_raytracing = false; + use_metalrt_by_default = false; denoisers = DENOISER_NONE; } diff --git a/intern/cycles/device/metal/device_impl.mm b/intern/cycles/device/metal/device_impl.mm index e774818e282..bf409ed4d33 100644 --- a/intern/cycles/device/metal/device_impl.mm +++ b/intern/cycles/device/metal/device_impl.mm @@ -164,9 +164,14 @@ MetalDevice::MetalDevice(const DeviceInfo &info, Stats &stats, Profiler &profile texture_bindings_3d = [mtlDevice newBufferWithLength:8192 options:default_storage_mode]; stats.mem_alloc(buffer_bindings_1d.allocatedSize + texture_bindings_2d.allocatedSize + texture_bindings_3d.allocatedSize); - /* command queue for path-tracing work on the GPU */ + + /* Command queue for path-tracing work on the GPU. In a situation where multiple + * MetalDeviceQueues are spawned from one MetalDevice, they share the same MTLCommandQueue. + * This is thread safe and just as performant as each having their own instance. It also + * adheres to best practices of maximizing the lifetime of each MTLCommandQueue. */ mtlComputeCommandQueue = [mtlDevice newCommandQueue]; - /* command queue for non-tracing work on the GPU */ + + /* Command queue for non-tracing work on the GPU. */ mtlGeneralCommandQueue = [mtlDevice newCommandQueue]; /* Acceleration structure arg encoder, if needed */