Cycles: Set quality parameter for OIDN

OpenImageDenoise API exposes two modes, high quality and balanced.
This currently only has effect on Nvidia devices, on which it
provides a noticeable performance improvement without visible
difference in quality. This change sets quality to balanced for
the viewport, and high quality for final frame rendering, as
it's what makes the most sense.

Ref #115045

Co-authored-by: Werner, Stefan <stefan.werner@intel.com>
Pull Request: #115265
This commit is contained in:
Nikita Sirgienko 2024-02-06 20:46:48 +01:00
parent e38f360ddb
commit 280b5c89ae
8 changed files with 63 additions and 10 deletions

@ -479,6 +479,7 @@ void BlenderSync::sync_integrator(BL::ViewLayer &b_view_layer, bool background)
integrator->set_use_denoise_pass_albedo(denoise_params.use_pass_albedo);
integrator->set_use_denoise_pass_normal(denoise_params.use_pass_normal);
integrator->set_denoiser_prefilter(denoise_params.prefilter);
integrator->set_denoiser_quality(denoise_params.quality);
}
/* UPDATE_NONE as we don't want to tag the integrator as modified (this was done by the
@ -974,6 +975,9 @@ DenoiseParams BlenderSync::get_denoise_params(BL::Scene &b_scene,
denoising.use_gpu = get_boolean(cscene, "denoising_use_gpu");
denoising.prefilter = (DenoiserPrefilter)get_enum(
cscene, "denoising_prefilter", DENOISER_PREFILTER_NUM, DENOISER_PREFILTER_NONE);
/* This currently only affects NVIDIA and the difference in quality is too small to justify
* exposing a setting to the user. */
denoising.quality = DENOISER_QUALITY_HIGH;
input_passes = (DenoiserInput)get_enum(
cscene, "denoising_input_passes", DENOISER_INPUT_NUM, DENOISER_INPUT_RGB_ALBEDO_NORMAL);
@ -993,6 +997,9 @@ DenoiseParams BlenderSync::get_denoise_params(BL::Scene &b_scene,
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);
/* This currently only affects NVIDIA and the difference in quality is too small to justify
* exposing a setting to the user. */
denoising.quality = DENOISER_QUALITY_BALANCED;
denoising.start_sample = get_int(cscene, "preview_denoising_start_sample");
input_passes = (DenoiserInput)get_enum(

@ -48,12 +48,25 @@ const NodeEnum *DenoiseParams::get_prefilter_enum()
return &prefilter_enum;
}
const NodeEnum *DenoiseParams::get_quality_enum()
{
static NodeEnum quality_enum;
if (quality_enum.empty()) {
quality_enum.insert("high", DENOISER_QUALITY_HIGH);
quality_enum.insert("balanced", DENOISER_QUALITY_BALANCED);
}
return &quality_enum;
}
NODE_DEFINE(DenoiseParams)
{
NodeType *type = NodeType::add("denoise_params", create);
const NodeEnum *type_enum = get_type_enum();
const NodeEnum *prefilter_enum = get_prefilter_enum();
const NodeEnum *quality_enum = get_quality_enum();
SOCKET_BOOLEAN(use, "Use", false);
@ -67,6 +80,7 @@ NODE_DEFINE(DenoiseParams)
SOCKET_BOOLEAN(temporally_stable, "Temporally Stable", false);
SOCKET_ENUM(prefilter, "Prefilter", *prefilter_enum, DENOISER_PREFILTER_FAST);
SOCKET_ENUM(quality, "Quality", *quality_enum, DENOISER_QUALITY_HIGH);
return type;
}

@ -40,6 +40,12 @@ enum DenoiserPrefilter {
DENOISER_PREFILTER_NUM,
};
enum DenoiserQuality {
DENOISER_QUALITY_HIGH = 1,
DENOISER_QUALITY_BALANCED = 2,
DENOISER_QUALITY_NUM,
};
/* NOTE: Is not a real scene node. Using Node API for ease of (de)serialization.
* The default values here do not really matter as they are always initialized from the
* Integrator node. */
@ -69,20 +75,13 @@ class DenoiseParams : public Node {
bool use_gpu = true;
DenoiserPrefilter prefilter = DENOISER_PREFILTER_FAST;
DenoiserQuality quality = DENOISER_QUALITY_HIGH;
static const NodeEnum *get_type_enum();
static const NodeEnum *get_prefilter_enum();
static const NodeEnum *get_quality_enum();
DenoiseParams();
bool modified(const DenoiseParams &other) const
{
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 && use_gpu == other.use_gpu &&
prefilter == other.prefilter);
}
};
CCL_NAMESPACE_END

@ -164,6 +164,18 @@ class OIDNDenoiseContext {
oidn_filter.setProgressMonitorFunction(oidn_progress_monitor_function, denoiser_);
oidn_filter.set("hdr", true);
oidn_filter.set("srgb", false);
# if OIDN_VERSION_MAJOR >= 2
switch (denoise_params_.quality) {
case DENOISER_QUALITY_BALANCED:
oidn_filter.set("quality", OIDN_QUALITY_BALANCED);
break;
case DENOISER_QUALITY_HIGH:
default:
oidn_filter.set("quality", OIDN_QUALITY_HIGH);
}
# endif
if (denoise_params_.prefilter == DENOISER_PREFILTER_NONE ||
denoise_params_.prefilter == DENOISER_PREFILTER_ACCURATE)
{

@ -139,7 +139,8 @@ bool OIDNDenoiserGPU::denoise_create_if_needed(DenoiseContext &context)
{
const bool recreate_denoiser = (oidn_device_ == nullptr) || (oidn_filter_ == nullptr) ||
(use_pass_albedo_ != context.use_pass_albedo) ||
(use_pass_normal_ != context.use_pass_normal);
(use_pass_normal_ != context.use_pass_normal) ||
(quality_ != params_.quality);
if (!recreate_denoiser) {
return true;
}
@ -206,6 +207,18 @@ bool OIDNDenoiserGPU::denoise_create_if_needed(DenoiseContext &context)
oidnSetFilterInt(oidn_filter_, "cleanAux", true);
}
# if OIDN_VERSION_MAJOR >= 2
switch (params_.quality) {
case DENOISER_QUALITY_BALANCED:
oidnSetFilterInt(oidn_filter_, "quality", OIDN_QUALITY_BALANCED);
break;
case DENOISER_QUALITY_HIGH:
default:
oidnSetFilterInt(oidn_filter_, "quality", OIDN_QUALITY_HIGH);
}
quality_ = params_.quality;
# endif
if (context.use_pass_albedo) {
albedo_filter_ = create_filter();
if (albedo_filter_ == nullptr) {

@ -61,6 +61,7 @@ class OIDNDenoiserGPU : public DenoiserGPU {
bool use_pass_albedo_ = false;
bool use_pass_normal_ = false;
DenoiserQuality quality_ = DENOISER_QUALITY_HIGH;
int max_mem_ = 3000;
};

@ -136,6 +136,10 @@ NODE_DEFINE(Integrator)
denoiser_prefilter_enum.insert("fast", DENOISER_PREFILTER_FAST);
denoiser_prefilter_enum.insert("accurate", DENOISER_PREFILTER_ACCURATE);
static NodeEnum denoiser_quality_enum;
denoiser_quality_enum.insert("high", DENOISER_QUALITY_HIGH);
denoiser_quality_enum.insert("balanced", DENOISER_QUALITY_BALANCED);
/* Default to accurate denoising with OpenImageDenoise. For interactive viewport
* it's best use OptiX and disable the normal pass since it does not always have
* the desired effect for that denoiser. */
@ -149,6 +153,7 @@ NODE_DEFINE(Integrator)
denoiser_prefilter_enum,
DENOISER_PREFILTER_ACCURATE);
SOCKET_BOOLEAN(denoise_use_gpu, "Denoise on GPU", true);
SOCKET_ENUM(denoiser_quality, "Denoiser Quality", denoiser_quality_enum, DENOISER_QUALITY_HIGH);
return type;
}
@ -402,6 +407,7 @@ DenoiseParams Integrator::get_denoise_params() const
denoise_params.use_pass_normal = use_denoise_pass_normal;
denoise_params.prefilter = denoiser_prefilter;
denoise_params.quality = denoiser_quality;
return denoise_params;
}

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