Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Sharybin <sergey@blender.org>2021-09-21 18:03:22 +0300
committerSergey Sharybin <sergey@blender.org>2021-10-05 17:19:14 +0300
commit6e268a749fee16b442bcb3fba6cb6e08850d8389 (patch)
treeeffa2244461bc000856218ec44b8990305aac91c /intern/cycles/render
parent758f3f7456ac1e31f411c4ac1b19760ad6e5539c (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.cpp37
-rw-r--r--intern/cycles/render/buffers.h9
-rw-r--r--intern/cycles/render/session.cpp8
-rw-r--r--intern/cycles/render/tile.cpp70
-rw-r--r--intern/cycles/render/tile.h6
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 &params, 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. */