[Bf-blender-cvs] [b80b7ce0490] cycles-x: Cycles X: Reduce memory usage of OIDN denoiser

Sergey Sharybin noreply at git.blender.org
Fri Jul 9 11:31:36 CEST 2021


Commit: b80b7ce049086cdfe4a4436b2d765b8fef06755a
Author: Sergey Sharybin
Date:   Thu Jul 8 16:28:45 2021 +0200
Branches: cycles-x
https://developer.blender.org/rBb80b7ce049086cdfe4a4436b2d765b8fef06755a

Cycles X: Reduce memory usage of OIDN denoiser

The idea is to perform denoising in the render buffer's
denoised pass without allocating temporary color.

This optimization covers all scenarios of when OIDN is used:
single- and multi- device rendering.

This also fixes certain artifacts caused by previous memory
optimizations which lead to a feedback loops.

Differential Revision: https://developer.blender.org/D11852

===================================================================

M	intern/cycles/integrator/denoiser_oidn.cpp

===================================================================

diff --git a/intern/cycles/integrator/denoiser_oidn.cpp b/intern/cycles/integrator/denoiser_oidn.cpp
index e4de4f8b3c1..45a326aef91 100644
--- a/intern/cycles/integrator/denoiser_oidn.cpp
+++ b/intern/cycles/integrator/denoiser_oidn.cpp
@@ -104,6 +104,7 @@ bool OIDNDenoiser::load_kernels(Progress *progress)
 }
 
 #ifdef WITH_OPENIMAGEDENOISE
+
 class OIDNPass {
  public:
   OIDNPass() = default;
@@ -119,6 +120,12 @@ class OIDNPass {
 
     const PassInfo pass_info = Pass::get_info(type);
     use_compositing = pass_info.use_compositing;
+    use_denoising_albedo = pass_info.use_denoising_albedo;
+  }
+
+  inline operator bool() const
+  {
+    return name[0] != '\0';
   }
 
   /* Name of an image which will be passed to the OIDN library.
@@ -128,6 +135,8 @@ class OIDNPass {
 
   PassType type = PASS_NONE;
   PassMode mode = PassMode::NOISY;
+  bool use_compositing = false;
+  bool use_denoising_albedo = true;
 
   /* Offset of beginning of this pass in the render buffers. */
   int offset = -1;
@@ -141,15 +150,8 @@ class OIDNPass {
    * outside of generic pass handling. */
   bool need_scale = false;
 
-  bool use_compositing = false;
-
   /* For the scaled passes, the data which holds values of scaled pixels. */
   array<float> scaled_buffer;
-
-  /* For the in-place usable passes denotes whether the data is prepared to be used as-is.
-   * For example, for compositing passes this means that the compositing result has been read,
-   * and for scaling passes means that scaling has been performed. */
-  bool is_inplace_ready = false;
 };
 
 class OIDNDenoiseContext {
@@ -176,36 +178,43 @@ class OIDNDenoiseContext {
 
     if (denoise_params_.use_pass_normal) {
       oidn_normal_pass_ = OIDNPass(buffer_params_, "normal", PASS_DENOISING_NORMAL);
-      set_pass(oidn_normal_pass_);
     }
   }
 
-  void denoise(const PassType pass_type)
+  bool need_denoising() const
+  {
+    if (buffer_params_.width == 0 && buffer_params_.height == 0) {
+      return false;
+    }
+
+    return true;
+  }
+
+  /* Make the guiding passes available by a sequential denoising of various passes. */
+  void read_guiding_passes()
+  {
+    read_guiding_pass(oidn_albedo_pass_);
+    read_guiding_pass(oidn_normal_pass_);
+  }
+
+  void denoise_pass(const PassType pass_type)
   {
-    /* Add input color image. */
     OIDNPass oidn_color_pass(buffer_params_, "color", pass_type);
     if (oidn_color_pass.offset == PASS_UNUSED) {
       return;
     }
-    set_pass(oidn_color_pass);
-
-    if (denoise_params_.use_pass_albedo) {
-      const PassInfo pass_info = Pass::get_info(pass_type);
-      if (!pass_info.use_denoising_albedo) {
-        set_fake_albedo_pass();
-      }
-      else {
-        set_pass(oidn_albedo_pass_);
-      }
-    }
 
-    /* Add output pass. */
     OIDNPass oidn_output_pass(buffer_params_, "output", pass_type, PassMode::DENOISED);
     if (oidn_color_pass.offset == PASS_UNUSED) {
       LOG(DFATAL) << "Missing denoised pass " << pass_type_as_string(pass_type);
       return;
     }
-    set_pass_referenced(oidn_output_pass);
+
+    OIDNPass oidn_color_access_pass = read_input_pass(oidn_color_pass, oidn_output_pass);
+
+    set_input_pass(oidn_color_access_pass);
+    set_guiding_passes(oidn_color_pass);
+    set_output_pass(oidn_output_pass);
 
     /* Execute filter. */
     oidn_filter_->commit();
@@ -215,34 +224,57 @@ class OIDNDenoiseContext {
   }
 
  protected:
-  /* Set OIDN image to reference pixels from the given render buffer pass.
-   * No transform to the pixels is done, no additional memory is used. */
-  void set_pass_referenced(const OIDNPass &oidn_pass)
+  /* Make pixels of a guiding pass available by the denoiser. */
+  void read_guiding_pass(OIDNPass &oidn_pass)
   {
-    const int64_t x = buffer_params_.full_x;
-    const int64_t y = buffer_params_.full_y;
-    const int64_t width = buffer_params_.width;
-    const int64_t height = buffer_params_.height;
-    const int64_t offset = buffer_params_.offset;
-    const int64_t stride = buffer_params_.stride;
-    const int64_t pass_stride = buffer_params_.pass_stride;
+    if (!oidn_pass) {
+      return;
+    }
 
-    const int64_t pixel_index = offset + x + y * stride;
-    const int64_t buffer_offset = pixel_index * pass_stride;
+    DCHECK(!oidn_pass.use_compositing);
+
+    if (!is_pass_scale_needed(oidn_pass)) {
+      /* Pass data is available as-is from the render buffers. */
+      return;
+    }
+
+    if (allow_inplace_modification_) {
+      scale_pass_in_render_buffers(oidn_pass);
+      return;
+    }
+
+    read_pass_pixels_into_buffer(oidn_pass);
+  }
+
+  /* Special reader of the ionput pass.
+   * To save memory it will read pixels into the output, and let the denoiser to perform an
+   * in-place operation. */
+  OIDNPass read_input_pass(OIDNPass &oidn_input_pass, const OIDNPass &oidn_output_pass)
+  {
+    const bool use_compositing = oidn_input_pass.use_compositing;
+
+    /* Simple case: no compositing is involved, no scaling is needed.
+     * The pass pixels will be referenced as-is, without extra processing. */
+    if (!use_compositing && !is_pass_scale_needed(oidn_input_pass)) {
+      return oidn_input_pass;
+    }
 
     float *buffer_data = render_buffers_->buffer.data();
+    float *pass_data = buffer_data + oidn_output_pass.offset;
 
-    oidn_filter_->setImage(oidn_pass.name,
-                           buffer_data + buffer_offset + oidn_pass.offset,
-                           oidn::Format::Float3,
-                           width,
-                           height,
-                           0,
-                           pass_stride * sizeof(float),
-                           stride * pass_stride * sizeof(float));
+    PassAccessor::Destination destination(pass_data, 3);
+    destination.pixel_stride = buffer_params_.pass_stride;
+
+    read_pass_pixels(oidn_input_pass, destination);
+
+    OIDNPass oidn_input_pass_at_output = oidn_input_pass;
+    oidn_input_pass_at_output.offset = oidn_output_pass.offset;
+
+    return oidn_input_pass_at_output;
   }
 
-  void read_pass_pixels(OIDNPass &oidn_pass, const PassAccessor::Destination &destination)
+  /* Read pass pixels using PassAccessor into the given destination. */
+  void read_pass_pixels(const OIDNPass &oidn_pass, const PassAccessor::Destination &destination)
   {
     PassAccessor::PassAccessInfo pass_access_info;
     pass_access_info.type = oidn_pass.type;
@@ -263,28 +295,9 @@ class OIDNDenoiseContext {
     pass_accessor.get_render_tile_pixels(render_buffers_, buffer_params_, destination);
   }
 
-  void read_pass_pixels_inplace_if_needed(OIDNPass &oidn_pass)
+  /* Read pass pixels using PassAccessor into a temporary buffer which is owned by the pass.. */
+  void read_pass_pixels_into_buffer(OIDNPass &oidn_pass)
   {
-    if (oidn_pass.is_inplace_ready) {
-      return;
-    }
-    oidn_pass.is_inplace_ready = true;
-
-    float *buffer_data = render_buffers_->buffer.data();
-    float *pass_data = buffer_data + oidn_pass.offset;
-
-    PassAccessor::Destination destination(pass_data, 3);
-    destination.pixel_stride = buffer_params_.pass_stride;
-
-    read_pass_pixels(oidn_pass, destination);
-  }
-
-  void read_pass_pixels_into_buffer_if_needed(OIDNPass &oidn_pass)
-  {
-    if (!oidn_pass.scaled_buffer.empty()) {
-      return;
-    }
-
     VLOG(3) << "Allocating temporary buffer for pass " << oidn_pass.name << " ("
             << pass_type_as_string(oidn_pass.type) << ")";
 
@@ -299,10 +312,35 @@ class OIDNDenoiseContext {
     read_pass_pixels(oidn_pass, destination);
   }
 
-  void set_pass_scaled(OIDNPass &oidn_pass)
+  /* Set OIDN image to reference pixels from the given render buffer pass.
+   * No transform to the pixels is done, no additional memory is used. */
+  void set_pass_referenced(const OIDNPass &oidn_pass)
   {
-    read_pass_pixels_into_buffer_if_needed(oidn_pass);
+    const int64_t x = buffer_params_.full_x;
+    const int64_t y = buffer_params_.full_y;
+    const int64_t width = buffer_params_.width;
+    const int64_t height = buffer_params_.height;
+    const int64_t offset = buffer_params_.offset;
+    const int64_t stride = buffer_params_.stride;
+    const int64_t pass_stride = buffer_params_.pass_stride;
+
+    const int64_t pixel_index = offset + x + y * stride;
+    const int64_t buffer_offset = pixel_index * pass_stride;
+
+    float *buffer_data = render_buffers_->buffer.data();
+
+    oidn_filter_->setImage(oidn_pass.name,
+                           buffer_data + buffer_offset + oidn_pass.offset,
+                           oidn::Format::Float3,
+                           width,
+                           height,
+                           0,
+                           pass_stride * sizeof(float),
+                           stride * pass_stride * sizeof(float));
+  }
 
+  void set_pass_from_buffer(OIDNPass &oidn_pass)
+  {
     const int64_t width = buffer_params_.width;
     const int64_t height = buffer_params_.height;
 
@@ -318,27 +356,34 @@ class OIDNDenoiseContext {
 
   void set_pass(OIDNPass &oidn_pass)
   {
-    const bool use_compositing = oidn_pass.use_compositing;
-
-    /* Simple case: no compositing is involved, no scaling o9s needed. Reference the pass from the
-     * render buffers without extra compute. */
-    if (!use_compositing && !is_pass_scale_needed(oidn_pass)) {
+    if (oidn_pass.scaled_buffer.empty()) {
       set_pass_referenced(oidn_pass);
-      return;
     }
+    else {
+      set_pass_from_buffer(oidn_pass);
+    }
+  }
 
-    if (allow_inplace_modification_) {
-      set_pass_referenced(oidn_pass);
-      if (use_compositing) {
-        read_pass_pixels_inplace_if_needed(oidn_pass);
+  void set_input_pass(OIDNPass &oidn_pass)
+  {
+    set_pass_referenced(oidn_pass);
+  }
+
+  void set_guiding_passes(OIDNPass &oidn_pass)
+  {
+    if (oidn_albedo_pass_) {
+      if (oidn_pass.use_denoising_albedo) {
+        set_pass(oidn_albedo_pass_);
       }
       else {
-        scale_pass_inplace_if_needed(oidn_pass);
+        set_fake_albedo_pass();
       }
-      return;
     }
+  }
 
-    set_pass_scaled(oidn_pass);
+  void set_output_pass(OIDNPass &oidn_pass)
+  {
+    set_pass_referenced(oidn_pass);
   }
 
   vo

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list