diff options
author | Sergey Sharybin <sergey@blender.org> | 2021-09-21 18:03:22 +0300 |
---|---|---|
committer | Sergey Sharybin <sergey@blender.org> | 2021-10-05 17:19:14 +0300 |
commit | 6e268a749fee16b442bcb3fba6cb6e08850d8389 (patch) | |
tree | effa2244461bc000856218ec44b8990305aac91c /intern/cycles/render | |
parent | 758f3f7456ac1e31f411c4ac1b19760ad6e5539c (diff) |
Fix adaptive sampling artifacts on tile boundaries
Implement an overscan support for tiles, so that adaptive sampling can
rely on the pixels neighbourhood.
Differential Revision: https://developer.blender.org/D12599
Diffstat (limited to 'intern/cycles/render')
-rw-r--r-- | intern/cycles/render/buffers.cpp | 37 | ||||
-rw-r--r-- | intern/cycles/render/buffers.h | 9 | ||||
-rw-r--r-- | intern/cycles/render/session.cpp | 8 | ||||
-rw-r--r-- | intern/cycles/render/tile.cpp | 70 | ||||
-rw-r--r-- | intern/cycles/render/tile.h | 6 |
5 files changed, 106 insertions, 24 deletions
diff --git a/intern/cycles/render/buffers.cpp b/intern/cycles/render/buffers.cpp index 3682b55049a..00b4284c22b 100644 --- a/intern/cycles/render/buffers.cpp +++ b/intern/cycles/render/buffers.cpp @@ -97,6 +97,11 @@ NODE_DEFINE(BufferParams) SOCKET_INT(width, "Width", 0); SOCKET_INT(height, "Height", 0); + SOCKET_INT(window_x, "Window X", 0); + SOCKET_INT(window_y, "Window Y", 0); + SOCKET_INT(window_width, "Window Width", 0); + SOCKET_INT(window_height, "Window Height", 0); + SOCKET_INT(full_x, "Full X", 0); SOCKET_INT(full_y, "Full Y", 0); SOCKET_INT(full_width, "Full Width", 0); @@ -233,13 +238,31 @@ void BufferParams::update_offset_stride() bool BufferParams::modified(const BufferParams &other) const { - if (!(width == other.width && height == other.height && full_x == other.full_x && - full_y == other.full_y && full_width == other.full_width && - full_height == other.full_height && offset == other.offset && stride == other.stride && - pass_stride == other.pass_stride && layer == other.layer && view == other.view && - exposure == other.exposure && - use_approximate_shadow_catcher == other.use_approximate_shadow_catcher && - use_transparent_background == other.use_transparent_background)) { + if (width != other.width || height != other.height) { + return true; + } + + if (full_x != other.full_x || full_y != other.full_y || full_width != other.full_width || + full_height != other.full_height) { + return true; + } + + if (window_x != other.window_x || window_y != other.window_y || + window_width != other.window_width || window_height != other.window_height) { + return true; + } + + if (offset != other.offset || stride != other.stride || pass_stride != other.pass_stride) { + return true; + } + + if (layer != other.layer || view != other.view) { + return false; + } + + if (exposure != other.exposure || + use_approximate_shadow_catcher != other.use_approximate_shadow_catcher || + use_transparent_background != other.use_transparent_background) { return true; } diff --git a/intern/cycles/render/buffers.h b/intern/cycles/render/buffers.h index 184ac7197af..3cf826f14d6 100644 --- a/intern/cycles/render/buffers.h +++ b/intern/cycles/render/buffers.h @@ -82,6 +82,15 @@ class BufferParams : public Node { int width = 0; int height = 0; + /* Windows defines which part of the buffers is visible. The part outside of the window is + * considered an "overscan". + * + * Window X and Y are relative to the position of the buffer in the full buffer. */ + int window_x = 0; + int window_y = 0; + int window_width = 0; + int window_height = 0; + /* Offset into and width/height of the full buffer. */ int full_x = 0; int full_y = 0; diff --git a/intern/cycles/render/session.cpp b/intern/cycles/render/session.cpp index 4f93c3a9054..8d2d950f661 100644 --- a/intern/cycles/render/session.cpp +++ b/intern/cycles/render/session.cpp @@ -286,12 +286,20 @@ RenderWork Session::run_update_for_next_iteration() BufferParams tile_params = buffer_params_; const Tile &tile = tile_manager_.get_current_tile(); + tile_params.width = tile.width; tile_params.height = tile.height; + + tile_params.window_x = tile.window_x; + tile_params.window_y = tile.window_y; + tile_params.window_width = tile.window_width; + tile_params.window_height = tile.window_height; + tile_params.full_x = tile.x + buffer_params_.full_x; tile_params.full_y = tile.y + buffer_params_.full_y; tile_params.full_width = buffer_params_.full_width; tile_params.full_height = buffer_params_.full_height; + tile_params.update_offset_stride(); path_trace_->reset(buffer_params_, tile_params); diff --git a/intern/cycles/render/tile.cpp b/intern/cycles/render/tile.cpp index 7e53a9d0911..75c1f78982d 100644 --- a/intern/cycles/render/tile.cpp +++ b/intern/cycles/render/tile.cpp @@ -372,8 +372,17 @@ void TileManager::update(const BufferParams ¶ms, const Scene *scene) configure_image_spec_from_buffer(&write_state_.image_spec, buffer_params_, tile_size_); const DenoiseParams denoise_params = scene->integrator->get_denoise_params(); + const AdaptiveSampling adaptive_sampling = scene->integrator->get_adaptive_sampling(); + node_to_image_spec_atttributes( &write_state_.image_spec, &denoise_params, ATTR_DENOISE_SOCKET_PREFIX); + + if (adaptive_sampling.use) { + overscan_ = 4; + } + else { + overscan_ = 0; + } } bool TileManager::done() @@ -399,19 +408,29 @@ Tile TileManager::get_tile_for_index(int index) const /* TODO(sergey): Consider using hilbert spiral, or. maybe, even configurable. Not sure this * brings a lot of value since this is only applicable to BIG tiles. */ - const int tile_y = index / tile_state_.num_tiles_x; - const int tile_x = index - tile_y * tile_state_.num_tiles_x; + const int tile_index_y = index / tile_state_.num_tiles_x; + const int tile_index_x = index - tile_index_y * tile_state_.num_tiles_x; + + const int tile_x = tile_index_x * tile_size_.x; + const int tile_y = tile_index_y * tile_size_.y; Tile tile; - tile.x = tile_x * tile_size_.x; - tile.y = tile_y * tile_size_.y; - tile.width = tile_size_.x; - tile.height = tile_size_.y; + tile.x = tile_x - overscan_; + tile.y = tile_y - overscan_; + tile.width = tile_size_.x + 2 * overscan_; + tile.height = tile_size_.y + 2 * overscan_; + tile.x = max(tile.x, 0); + tile.y = max(tile.y, 0); tile.width = min(tile.width, buffer_params_.width - tile.x); tile.height = min(tile.height, buffer_params_.height - tile.y); + tile.window_x = tile_x - tile.x; + tile.window_y = tile_y - tile.y; + tile.window_width = min(tile_size_.x, buffer_params_.width - (tile.x + tile.window_x)); + tile.window_height = min(tile_size_.y, buffer_params_.height - (tile.y + tile.window_y)); + return tile; } @@ -483,11 +502,22 @@ bool TileManager::write_tile(const RenderBuffers &tile_buffers) DCHECK_EQ(tile_buffers.params.pass_stride, buffer_params_.pass_stride); + vector<float> pixel_storage; + const BufferParams &tile_params = tile_buffers.params; - const float *pixels = tile_buffers.buffer.data(); - const int tile_x = tile_params.full_x - buffer_params_.full_x; - const int tile_y = tile_params.full_y - buffer_params_.full_y; + const int tile_x = tile_params.full_x - buffer_params_.full_x + tile_params.window_x; + const int tile_y = tile_params.full_y - buffer_params_.full_y + tile_params.window_y; + + const int64_t pass_stride = tile_params.pass_stride; + const int64_t tile_row_stride = tile_params.width * pass_stride; + + const int64_t xstride = pass_stride * sizeof(float); + const int64_t ystride = xstride * tile_params.width; + const int64_t zstride = ystride * tile_params.height; + + const float *pixels = tile_buffers.buffer.data() + tile_params.window_x * pass_stride + + tile_params.window_y * tile_row_stride; VLOG(3) << "Write tile at " << tile_x << ", " << tile_y; @@ -499,13 +529,16 @@ bool TileManager::write_tile(const RenderBuffers &tile_buffers) * The only thing we have to ensure is that the tile_x and tile_y are a multiple of the * image tile size, which happens in compute_render_tile_size. */ if (!write_state_.tile_out->write_tiles(tile_x, - tile_x + tile_params.width, + tile_x + tile_params.window_width, tile_y, - tile_y + tile_params.height, + tile_y + tile_params.window_height, 0, 1, TypeDesc::FLOAT, - pixels)) { + pixels, + xstride, + ystride, + zstride)) { LOG(ERROR) << "Error writing tile " << write_state_.tile_out->geterror(); return false; } @@ -531,12 +564,15 @@ void TileManager::finish_write_tiles() ++tile_index) { const Tile tile = get_tile_for_index(tile_index); - VLOG(3) << "Write dummy tile at " << tile.x << ", " << tile.y; + const int tile_x = tile.x + tile.window_x; + const int tile_y = tile.y + tile.window_y; + + VLOG(3) << "Write dummy tile at " << tile_x << ", " << tile_y; - write_state_.tile_out->write_tiles(tile.x, - tile.x + tile.width, - tile.y, - tile.y + tile.height, + write_state_.tile_out->write_tiles(tile_x, + tile_x + tile.window_width, + tile_y, + tile_y + tile.window_height, 0, 1, TypeDesc::FLOAT, diff --git a/intern/cycles/render/tile.h b/intern/cycles/render/tile.h index 08eaa4034f0..a13afaea64e 100644 --- a/intern/cycles/render/tile.h +++ b/intern/cycles/render/tile.h @@ -35,6 +35,9 @@ class Tile { int x = 0, y = 0; int width = 0, height = 0; + int window_x = 0, window_y = 0; + int window_width = 0, window_height = 0; + Tile() { } @@ -128,6 +131,9 @@ class TileManager { int2 tile_size_ = make_int2(0, 0); + /* Number of extra pixels around the actual tile to render. */ + int overscan_ = 0; + BufferParams buffer_params_; /* Tile scheduling state. */ |