diff options
author | William Leeson <leesonw> | 2021-10-26 09:30:15 +0300 |
---|---|---|
committer | William Leeson <william@blender.org> | 2021-10-26 17:11:27 +0300 |
commit | 366262bef5426fa98e75c96a1562dd16001fba26 (patch) | |
tree | 80a4fd4c204d1e48bc25dd42bf93c6923e5959c4 /intern/cycles/integrator | |
parent | 4094868f7301ed06e6fd0710d1e9193796eb857d (diff) |
Distance Scrambling for for Cycles X - Sobol version
Cycles:Distance Scrambling for Cycles Sobol Sampler
This option implements micro jittering an is based on the INRIA
research paper [[ https://hal.inria.fr/hal-01325702/document | on micro jittering ]]
and work by Lukas Stockner for implementing the scrambling distance.
It works by controlling the correlation between pixels by either using
a user supplied value or an adaptive algorithm to limit the maximum
deviation of the sample values between pixels.
This is a follow up of https://developer.blender.org/D12316
The PMJ version can be found here: https://developer.blender.org/D12511
Reviewed By: leesonw
Differential Revision: https://developer.blender.org/D12318
Diffstat (limited to 'intern/cycles/integrator')
-rw-r--r-- | intern/cycles/integrator/path_trace_work_gpu.cpp | 5 | ||||
-rw-r--r-- | intern/cycles/integrator/tile.cpp | 58 | ||||
-rw-r--r-- | intern/cycles/integrator/tile.h | 3 | ||||
-rw-r--r-- | intern/cycles/integrator/work_tile_scheduler.cpp | 9 | ||||
-rw-r--r-- | intern/cycles/integrator/work_tile_scheduler.h | 8 |
5 files changed, 68 insertions, 15 deletions
diff --git a/intern/cycles/integrator/path_trace_work_gpu.cpp b/intern/cycles/integrator/path_trace_work_gpu.cpp index b7dc4e5d181..251bec0dc8f 100644 --- a/intern/cycles/integrator/path_trace_work_gpu.cpp +++ b/intern/cycles/integrator/path_trace_work_gpu.cpp @@ -258,7 +258,10 @@ void PathTraceWorkGPU::render_samples(RenderStatistics &statistics, * schedules work in halves of available number of paths. */ work_tile_scheduler_.set_max_num_path_states(max_num_paths_ / 8); - work_tile_scheduler_.reset(effective_buffer_params_, start_sample, samples_num); + work_tile_scheduler_.reset(effective_buffer_params_, + start_sample, + samples_num, + device_scene_->data.integrator.scrambling_distance); enqueue_reset(); diff --git a/intern/cycles/integrator/tile.cpp b/intern/cycles/integrator/tile.cpp index 7ea73451d80..b49e1b27b83 100644 --- a/intern/cycles/integrator/tile.cpp +++ b/intern/cycles/integrator/tile.cpp @@ -48,7 +48,8 @@ ccl_device_inline uint round_up_to_power_of_two(uint x) TileSize tile_calculate_best_size(const int2 &image_size, const int num_samples, - const int max_num_path_states) + const int max_num_path_states, + const float scrambling_distance) { if (max_num_path_states == 1) { /* Simple case: avoid any calculation, which could cause rounding issues. */ @@ -71,17 +72,54 @@ TileSize tile_calculate_best_size(const int2 &image_size, * - Keep values a power of two, for more integer fit into the maximum number of paths. */ TileSize tile_size; - - /* Calculate tile size as if it is the most possible one to fit an entire range of samples. - * The idea here is to keep tiles as small as possible, and keep device occupied by scheduling - * multiple tiles with the same coordinates rendering different samples. */ const int num_path_states_per_sample = max_num_path_states / num_samples; - if (num_path_states_per_sample != 0) { - tile_size.width = round_down_to_power_of_two(lround(sqrt(num_path_states_per_sample))); - tile_size.height = tile_size.width; + if (scrambling_distance < 0.9f) { + /* Prefer large tiles for scrambling distance. */ + if (image_size.x * image_size.y <= num_path_states_per_sample) { + tile_size.width = image_size.x; + tile_size.height = image_size.y; + } + else { + /* Pick the option with the biggest tile size */ + int heightOption = num_path_states_per_sample / image_size.x; + int widthOption = num_path_states_per_sample / image_size.y; + // Check if these options are possible + if ((heightOption > 0) || (widthOption > 0)) { + int area1 = image_size.x * heightOption; + int area2 = widthOption * image_size.y; + /* The option with the biggest pixel area */ + if (area1 >= area2) { + tile_size.width = image_size.x; + tile_size.height = heightOption; + } + else { + tile_size.width = widthOption; + tile_size.height = image_size.y; + } + } + else { // Large tiles are not an option so use square tiles + if (num_path_states_per_sample != 0) { + tile_size.width = round_down_to_power_of_two(lround(sqrt(num_path_states_per_sample))); + tile_size.height = tile_size.width; + } + else { + tile_size.width = tile_size.height = 1; + } + } + } } else { - tile_size.width = tile_size.height = 1; + /* Calculate tile size as if it is the most possible one to fit an entire range of samples. + * The idea here is to keep tiles as small as possible, and keep device occupied by scheduling + * multiple tiles with the same coordinates rendering different samples. */ + + if (num_path_states_per_sample != 0) { + tile_size.width = round_down_to_power_of_two(lround(sqrt(num_path_states_per_sample))); + tile_size.height = tile_size.width; + } + else { + tile_size.width = tile_size.height = 1; + } } if (num_samples == 1) { @@ -93,7 +131,7 @@ TileSize tile_calculate_best_size(const int2 &image_size, tile_size.num_samples = min(round_up_to_power_of_two(lround(sqrt(num_samples / 2))), static_cast<uint>(num_samples)); - const int tile_area = tile_size.width / tile_size.height; + const int tile_area = tile_size.width * tile_size.height; tile_size.num_samples = min(tile_size.num_samples, max_num_path_states / tile_area); } diff --git a/intern/cycles/integrator/tile.h b/intern/cycles/integrator/tile.h index 879c68b875c..61f7d736115 100644 --- a/intern/cycles/integrator/tile.h +++ b/intern/cycles/integrator/tile.h @@ -51,6 +51,7 @@ std::ostream &operator<<(std::ostream &os, const TileSize &tile_size); * possible, and have as many threads active for every tile as possible. */ TileSize tile_calculate_best_size(const int2 &image_size, const int num_samples, - const int max_num_path_states); + const int max_num_path_states, + const float scrambling_distance); CCL_NAMESPACE_END diff --git a/intern/cycles/integrator/work_tile_scheduler.cpp b/intern/cycles/integrator/work_tile_scheduler.cpp index c874dffde91..2d1ac07db7f 100644 --- a/intern/cycles/integrator/work_tile_scheduler.cpp +++ b/intern/cycles/integrator/work_tile_scheduler.cpp @@ -33,13 +33,17 @@ void WorkTileScheduler::set_max_num_path_states(int max_num_path_states) max_num_path_states_ = max_num_path_states; } -void WorkTileScheduler::reset(const BufferParams &buffer_params, int sample_start, int samples_num) +void WorkTileScheduler::reset(const BufferParams &buffer_params, + int sample_start, + int samples_num, + float scrambling_distance) { /* Image buffer parameters. */ image_full_offset_px_.x = buffer_params.full_x; image_full_offset_px_.y = buffer_params.full_y; image_size_px_ = make_int2(buffer_params.width, buffer_params.height); + scrambling_distance_ = scrambling_distance; offset_ = buffer_params.offset; stride_ = buffer_params.stride; @@ -54,7 +58,8 @@ void WorkTileScheduler::reset(const BufferParams &buffer_params, int sample_star void WorkTileScheduler::reset_scheduler_state() { - tile_size_ = tile_calculate_best_size(image_size_px_, samples_num_, max_num_path_states_); + tile_size_ = tile_calculate_best_size( + image_size_px_, samples_num_, max_num_path_states_, scrambling_distance_); VLOG(3) << "Will schedule tiles of size " << tile_size_; diff --git a/intern/cycles/integrator/work_tile_scheduler.h b/intern/cycles/integrator/work_tile_scheduler.h index 155bba5cb68..d9fa7e84431 100644 --- a/intern/cycles/integrator/work_tile_scheduler.h +++ b/intern/cycles/integrator/work_tile_scheduler.h @@ -38,7 +38,10 @@ class WorkTileScheduler { void set_max_num_path_states(int max_num_path_states); /* Scheduling will happen for pixels within a big tile denotes by its parameters. */ - void reset(const BufferParams &buffer_params, int sample_start, int samples_num); + void reset(const BufferParams &buffer_params, + int sample_start, + int samples_num, + float scrambling_distance); /* Get work for a device. * Returns true if there is still work to be done and initialize the work tile to all @@ -68,6 +71,9 @@ class WorkTileScheduler { * Will be passed over to the KernelWorkTile. */ int offset_, stride_; + /* Scrambling Distance requires adapted tile size */ + float scrambling_distance_; + /* Start sample of index and number of samples which are to be rendered. * The scheduler will cover samples range of [start, start + num] over the entire image * (splitting into a smaller work tiles). */ |