[Bf-blender-cvs] [58011ab628c] cycles-x: Cycles-X: Fix incorrect performance calculation at certain navigation resolutions

Alaska noreply at git.blender.org
Fri Sep 3 13:40:28 CEST 2021


Commit: 58011ab628c0c1dec32e825a1aafa9dec70c3f8c
Author: Alaska
Date:   Fri Sep 3 13:23:03 2021 +0200
Branches: cycles-x
https://developer.blender.org/rB58011ab628c0c1dec32e825a1aafa9dec70c3f8c

Cycles-X: Fix incorrect performance calculation at certain navigation resolutions

During viewport navigation the algorithm that calculates the resolution divider assumes that the at every resolution division the sample count will be 4. This is not true for cases where the resolution division is equal to `2 * pixel_size` and `pixel_size`. In those cases the sample count is 1. As a result the algorithm assumes `2 * pixel_size` and `pixel_size` are too expensive in a lot of cases and thus doesn't use it.

This patch addresses this issue by informing the algorithm of changes in sample counts between resolution divisions meaning it can more properly gauge the performance of various resolution divisions. As a result the algorithm is more likely to pick the correct resolution divider when performance of the scene is in the range that `2 * pixel_size` and `pixel_size` are viable options all while keeping the performance target at 30fps like before.

Along with this patch the sample count while the resolution divider is equal to `2 * pixel_size` has been increased from 1 sample per pixel to 2 samples per pixel. Without an increase to this value there are some negative side effects. I have chosen the value of 2 and not 4 because this values means at a resolution divider of `2 * pixel_size` the rendering is still cheaper than a resolution divider of `pixel_size`.

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

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

M	intern/cycles/integrator/render_scheduler.cpp
M	intern/cycles/integrator/render_scheduler.h

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

diff --git a/intern/cycles/integrator/render_scheduler.cpp b/intern/cycles/integrator/render_scheduler.cpp
index 059d2df922e..e39c10fa603 100644
--- a/intern/cycles/integrator/render_scheduler.cpp
+++ b/intern/cycles/integrator/render_scheduler.cpp
@@ -748,25 +748,32 @@ int RenderScheduler::get_num_samples_to_path_trace() const
 
 int RenderScheduler::get_num_samples_during_navigation(int resolution_divider) const
 {
-  /* Specvial trick for the fast navigation: schedule multiple samples during fast navigation
+  /* Special trick for fast navigation: schedule multiple samples during fast navigation
    * (which will prefer to use lower resolution to keep up with refresh rate). This gives more
-   * usable visual feedback for artists. There are couple of tricks though. */
+   * usable visual feedback for artists. There are a couple of tricks though. */
 
   if (is_denoise_active_during_update()) {
-    /* When resolution divider is the previous to the final resolution schedule single sample.
-     * This is so that rendering on lower resolution does not exceed time what it takes to render
-     * first sample at the full resolution. */
+    /* When denoising is used during navigation prefer using a higher resolution with less samples
+     * (scheduling less samples here will make it so the resolution_divider calculation will use a
+     * lower value for the divider). This is because both OpenImageDenoiser and OptiX denoiser
+     * give visually better results on a higher resolution image with less samples. */
     return 1;
   }
 
-  if (resolution_divider <= pixel_size_ * 2) {
-    /* When denoising is used during navigation prefer using higher resolution and less samples
-     * (scheduling less samples here will make it so resolutiondivider calculation will use lower
-     * value for the divider). This is because both OpenImageDenoiser and OptiX denoiser gives
-     * visually better results on higher resolution image with less samples. */
+  if (resolution_divider <= pixel_size_) {
+    /* When resolution divider is at or below pixel size, schedule one sample. This doesn't effect
+     * the sample count at this resolution division, but instead assists in the calculation of
+     * the resolution divider. */
     return 1;
   }
 
+  if (resolution_divider == pixel_size_ * 2) {
+    /* When resolution divider is the previous step to the final resolution, schedule two samples.
+     * This is so that rendering on lower resolution does not exceed time that it takes to render
+     * first sample at the full resolution. */
+    return 2;
+  }
+
   /* Always render 4 samples, even if scene is configured for less.
    * The idea here is to have enough information on the screen. Resolution divider of 2 allows us
    * to have 4 time extra samples, so verall worst case timing is the same as the final resolution
@@ -929,14 +936,10 @@ void RenderScheduler::update_start_resolution_divider()
     return;
   }
 
-  const int num_samples_during_navigation = get_num_samples_during_navigation(
-      default_start_resolution_divider_);
-
   const double desired_update_interval_in_seconds =
       guess_viewport_navigation_update_interval_in_seconds();
 
-  const double actual_time_per_update = first_render_time_.path_trace_per_sample *
-                                            num_samples_during_navigation +
+  const double actual_time_per_update = first_render_time_.path_trace_per_sample +
                                         first_render_time_.denoise_time +
                                         first_render_time_.display_update_time;
 
@@ -946,16 +949,12 @@ void RenderScheduler::update_start_resolution_divider()
   const int resolution_divider_for_update = calculate_resolution_divider_for_time(
       desired_update_interval_in_seconds * 1.4, actual_time_per_update);
 
-  /* Never higher resolution that the pixel size allows to (which is possible if the scene is
-   * simple and compute device is fast). */
-  const int new_resolution_divider = max(resolution_divider_for_update, pixel_size_);
-
   /* TODO(sergey): Need to add hysteresis to avoid resolution divider bouncing around when actual
    * render time is somewhere on a boundary between two resolutions. */
 
-  /* Don't let resolution to go below the desired one: better be slower than provide a fully
-   * unreadable viewport render. */
-  start_resolution_divider_ = min(new_resolution_divider, default_start_resolution_divider_);
+  /* Never increase resolution to higher than the pixel size (which is possible if the scene is
+   * simple and compute device is fast). */
+  start_resolution_divider_ = max(resolution_divider_for_update, pixel_size_);
 
   VLOG(3) << "Calculated resolution divider is " << start_resolution_divider_;
 }
@@ -1038,14 +1037,23 @@ void RenderScheduler::check_time_limit_reached()
  * Utility functions.
  */
 
-int calculate_resolution_divider_for_time(double desired_time, double actual_time)
+int RenderScheduler::calculate_resolution_divider_for_time(double desired_time, double actual_time)
 {
   /* TODO(sergey): There should a non-iterative analytical formula here. */
 
   int resolution_divider = 1;
-  while (actual_time > desired_time) {
+
+  /* This algorithm iterates through resolution dividers until a divider is found that achieves
+   * the desired render time. A limit of default_start_resolution_divider_ is put in place as the
+   * maximum resolution divider to avoid an unreadable viewport due to a low resolution.
+   * pre_resolution_division_samples and post_resolution_division_samples are used in this
+   * calculation to better predict the performance impact of changing resolution divisions as
+   * the sample count can also change between resolution divisions. */
+  while (actual_time > desired_time && resolution_divider < default_start_resolution_divider_) {
+    int pre_resolution_division_samples = get_num_samples_during_navigation(resolution_divider);
     resolution_divider = resolution_divider * 2;
-    actual_time /= 4.0;
+    int post_resolution_division_samples = get_num_samples_during_navigation(resolution_divider);
+    actual_time /= 4.0 * pre_resolution_division_samples / post_resolution_division_samples;
   }
 
   return resolution_divider;
diff --git a/intern/cycles/integrator/render_scheduler.h b/intern/cycles/integrator/render_scheduler.h
index bbe2c8424f2..a2d92877f08 100644
--- a/intern/cycles/integrator/render_scheduler.h
+++ b/intern/cycles/integrator/render_scheduler.h
@@ -407,14 +407,13 @@ class RenderScheduler {
 
   /* Initial resolution divider which will be used on render scheduler reset. */
   int start_resolution_divider_ = 0;
-};
-
-/* Calculate smallest resolution divider which will bring down actual rendering time below the
- * desired one. This call assumes linear dependency of render time from number of pixel (quadratic
- * dependency from the resolution divider): resolution divider of 2 beings render time down by a
- * factor of 4. */
-int calculate_resolution_divider_for_time(double desired_time, double actual_time);
 
+  /* Calculate smallest resolution divider which will bring down actual rendering time below the
+   * desired one. This call assumes linear dependency of render time from number of pixels
+   * (quadratic dependency from the resolution divider): resolution divider of 2 brings render time
+   * down by a factor of 4. */
+  int calculate_resolution_divider_for_time(double desired_time, double actual_time);
+};
 int calculate_resolution_divider_for_resolution(int width, int height, int resolution);
 
 int calculate_resolution_for_divider(int width, int height, int resolution_divider);



More information about the Bf-blender-cvs mailing list