Cycles: Allow to disable OIDN on GPU on per-scene basis. #117874

Merged
Brecht Van Lommel merged 2 commits from Sirgienko/blender:ui_oidn_allow_gpu_checkbox into main 2024-02-06 17:46:30 +01:00
8 changed files with 59 additions and 4 deletions

View File

@ -352,6 +352,11 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
items=enum_denoising_input_passes,
default='RGB_ALBEDO_NORMAL',
)
denoising_use_gpu: BoolProperty(
name="Denoise on GPU",
description="Perform denoising on GPU devices, if available. This is significantly faster than on CPU, but requires additional GPU memory. When large scenes need more GPU memory, this option can be disabled",
default=True,
)
use_preview_denoising: BoolProperty(
name="Use Viewport Denoising",
@ -382,6 +387,11 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
min=0, max=(1 << 24),
default=1,
)
preview_denoising_use_gpu: BoolProperty(
name="Denoise Preview on GPU",
description="Perform denoising on GPU devices, if available. This is significantly faster than on CPU, but requires additional GPU memory. When large scenes need more GPU memory, this option can be disabled",
default=True,
)
samples: IntProperty(
name="Samples",
@ -1591,6 +1601,22 @@ class CyclesPreferences(bpy.types.AddonPreferences):
def has_active_device(self):
return self.get_num_gpu_devices() > 0
def has_oidn_gpu_devices(self):
import _cycles
compute_device_type = context.preferences.addons[__package__].preferences.get_compute_device_type()
# We need non-CPU devices, used for rendering and supporting OIDN GPU denoising
for device in _cycles.available_devices(compute_device_type):
device_type = device[1]
if device_type == 'CPU':
continue
has_device_oidn_support = device[5]
if has_device_oidn_support and self.find_existing_device_entry(device).use:
return True
return False
def _draw_devices(self, layout, device_type, devices):
box = layout.box()

View File

@ -123,7 +123,6 @@ def use_optix(context):
return (get_device_type(context) == 'OPTIX' and cscene.device == 'GPU' and backend_has_active_gpu(context))
def use_oneapi(context):
cscene = context.scene.cycles
@ -156,6 +155,9 @@ def get_effective_preview_denoiser(context):
return 'OIDN'
def has_oidn_gpu_devices(context):
return context.preferences.addons[__package__].preferences.has_oidn_gpu_devices()
def use_mnee(context):
# The MNEE kernel doesn't compile on macOS < 13.
@ -236,6 +238,11 @@ class CYCLES_RENDER_PT_sampling_viewport_denoise(CyclesButtonsPanel, Panel):
col.prop(cscene, "preview_denoising_start_sample", text="Start Sample")
if effective_preview_denoiser == 'OPENIMAGEDENOISE':
row = col.row()
row.active = not use_cpu(context) and has_oidn_gpu_devices(context)
row.prop(cscene, "preview_denoising_use_gpu", text="Use GPU")
class CYCLES_RENDER_PT_sampling_render(CyclesButtonsPanel, Panel):
bl_label = "Render"

"OpenImageDenoise on GPU" is not exactly fully fitting in default panel width, likely worth to change the default value in order to fit the string fully, or use more short one.

"OpenImageDenoise on GPU" is not exactly fully fitting in default panel width, likely worth to change the default value in order to fit the string fully, or use more short one.
@ -295,6 +302,11 @@ class CYCLES_RENDER_PT_sampling_render_denoise(CyclesButtonsPanel, Panel):
if cscene.denoiser == 'OPENIMAGEDENOISE':
col.prop(cscene, "denoising_prefilter", text="Prefilter")
if cscene.denoiser == 'OPENIMAGEDENOISE':
row = col.row()
row.active = not use_cpu(context) and has_oidn_gpu_devices(context)
row.prop(cscene, "denoising_use_gpu", text="Use GPU")
class CYCLES_RENDER_PT_sampling_path_guiding(CyclesButtonsPanel, Panel):
bl_label = "Path Guiding"

View File

@ -417,12 +417,14 @@ static PyObject *available_devices_func(PyObject * /*self*/, PyObject *args)
for (size_t i = 0; i < devices.size(); i++) {
DeviceInfo &device = devices[i];
string type_name = Device::string_from_type(device.type);
PyObject *device_tuple = PyTuple_New(5);
PyObject *device_tuple = PyTuple_New(6);
PyTuple_SET_ITEM(device_tuple, 0, pyunicode_from_string(device.description.c_str()));
PyTuple_SET_ITEM(device_tuple, 1, pyunicode_from_string(type_name.c_str()));
PyTuple_SET_ITEM(device_tuple, 2, pyunicode_from_string(device.id.c_str()));
PyTuple_SET_ITEM(device_tuple, 3, PyBool_FromLong(device.has_peer_memory));
PyTuple_SET_ITEM(device_tuple, 4, PyBool_FromLong(device.use_hardware_raytracing));
PyTuple_SET_ITEM(
device_tuple, 5, PyBool_FromLong(device.denoisers & DENOISER_OPENIMAGEDENOISE));
Review

Duplication of the changes from #117734 - won't be needed after merging #117734 into the master.

Duplication of the changes from https://projects.blender.org/blender/blender/pulls/117734 - won't be needed after merging https://projects.blender.org/blender/blender/pulls/117734 into the master.
PyTuple_SET_ITEM(ret, i, device_tuple);
}

View File

@ -474,6 +474,7 @@ void BlenderSync::sync_integrator(BL::ViewLayer &b_view_layer, bool background)
* is that the interface and the integrator are technically out of sync. */
if (denoise_params.use) {
integrator->set_denoiser_type(denoise_params.type);
integrator->set_denoise_use_gpu(denoise_params.use_gpu);
integrator->set_denoise_start_sample(denoise_params.start_sample);
integrator->set_use_denoise_pass_albedo(denoise_params.use_pass_albedo);
integrator->set_use_denoise_pass_normal(denoise_params.use_pass_normal);
@ -970,6 +971,7 @@ DenoiseParams BlenderSync::get_denoise_params(BL::Scene &b_scene,
/* Final Render Denoising */
denoising.use = get_boolean(cscene, "use_denoising");
denoising.type = (DenoiserType)get_enum(cscene, "denoiser", DENOISER_NUM, DENOISER_NONE);
denoising.use_gpu = get_boolean(cscene, "denoising_use_gpu");
denoising.prefilter = (DenoiserPrefilter)get_enum(
cscene, "denoising_prefilter", DENOISER_PREFILTER_NUM, DENOISER_PREFILTER_NONE);
@ -988,6 +990,7 @@ DenoiseParams BlenderSync::get_denoise_params(BL::Scene &b_scene,
denoising.use = get_boolean(cscene, "use_preview_denoising");
denoising.type = (DenoiserType)get_enum(
cscene, "preview_denoiser", DENOISER_NUM, DENOISER_NONE);
denoising.use_gpu = get_boolean(cscene, "preview_denoising_use_gpu");
denoising.prefilter = (DenoiserPrefilter)get_enum(
cscene, "preview_denoising_prefilter", DENOISER_PREFILTER_NUM, DENOISER_PREFILTER_FAST);
denoising.start_sample = get_int(cscene, "preview_denoising_start_sample");

View File

@ -63,6 +63,11 @@ class DenoiseParams : public Node {
/* Configure the denoiser to use motion vectors, previous image and a temporally stable model. */
bool temporally_stable = false;
/* If true, then allow, if supported, OpenImageDenoise to use GPU device.
* If false, then OpenImageDenoise will always use CPU regardless of GPU device
* precense. */
bool use_gpu = true;
DenoiserPrefilter prefilter = DENOISER_PREFILTER_FAST;
static const NodeEnum *get_type_enum();
@ -75,7 +80,8 @@ class DenoiseParams : public Node {
return !(use == other.use && type == other.type && start_sample == other.start_sample &&
use_pass_albedo == other.use_pass_albedo &&
use_pass_normal == other.use_pass_normal &&
temporally_stable == other.temporally_stable && prefilter == other.prefilter);
temporally_stable == other.temporally_stable && use_gpu == other.use_gpu &&
prefilter == other.prefilter);
}
};

View File

@ -27,7 +27,9 @@ unique_ptr<Denoiser> Denoiser::create(Device *path_trace_device, const DenoisePa
#endif
#ifdef WITH_OPENIMAGEDENOISE
if (params.type == DENOISER_OPENIMAGEDENOISE && path_trace_device->info.type != DEVICE_CPU &&
/* If available and allowed, then we will use OpenImageDenoise on GPU, otherwise on CPU. */
if (params.type == DENOISER_OPENIMAGEDENOISE && params.use_gpu &&
path_trace_device->info.type != DEVICE_CPU &&
OIDNDenoiserGPU::is_device_supported(path_trace_device->info))
{
return make_unique<OIDNDenoiserGPU>(path_trace_device, params);

View File

@ -148,6 +148,7 @@ NODE_DEFINE(Integrator)
"Denoiser Prefilter",
denoiser_prefilter_enum,
DENOISER_PREFILTER_ACCURATE);
SOCKET_BOOLEAN(denoise_use_gpu, "Denoise on GPU", true);
return type;
}
@ -393,6 +394,8 @@ DenoiseParams Integrator::get_denoise_params() const
denoise_params.type = denoiser_type;
denoise_params.use_gpu = denoise_use_gpu;
denoise_params.start_sample = denoise_start_sample;
denoise_params.use_pass_albedo = use_denoise_pass_albedo;

View File

@ -98,6 +98,7 @@ class Integrator : public Node {
NODE_SOCKET_API(bool, use_denoise_pass_albedo);
NODE_SOCKET_API(bool, use_denoise_pass_normal);
NODE_SOCKET_API(DenoiserPrefilter, denoiser_prefilter);
NODE_SOCKET_API(bool, denoise_use_gpu);
enum : uint32_t {
AO_PASS_MODIFIED = (1 << 0),