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:
authorPatrick Mours <pmours@nvidia.com>2020-02-11 18:30:01 +0300
committerPatrick Mours <pmours@nvidia.com>2020-02-11 20:03:43 +0300
commit38589de10c098cfe32ac7716f4d7844abf959753 (patch)
treed28b007bdc75e4eefd1d7ded5115655c50a72140 /intern/cycles/render
parent35490c3ead03d472dbcba36c85d428e81b442520 (diff)
Cycles: Add support for denoising in the viewport
The OptiX denoiser can be a great help when rendering in the viewport, since it is really fast and needs few samples to produce convincing results. This patch therefore adds support for using any Cycles denoiser in the viewport also (but only the OptiX one is selectable because the NLM one is too slow to be usable currently). It also adds support for denoising on a different device than rendering (so one can e.g. render with the CPU but denoise with OptiX). Reviewed By: #cycles, brecht Differential Revision: https://developer.blender.org/D6554
Diffstat (limited to 'intern/cycles/render')
-rw-r--r--intern/cycles/render/buffers.cpp2
-rw-r--r--intern/cycles/render/session.cpp246
-rw-r--r--intern/cycles/render/session.h11
-rw-r--r--intern/cycles/render/tile.cpp131
-rw-r--r--intern/cycles/render/tile.h10
5 files changed, 292 insertions, 108 deletions
diff --git a/intern/cycles/render/buffers.cpp b/intern/cycles/render/buffers.cpp
index b08b6c84c1d..41e1b73fdac 100644
--- a/intern/cycles/render/buffers.cpp
+++ b/intern/cycles/render/buffers.cpp
@@ -146,7 +146,7 @@ void RenderBuffers::reset(BufferParams &params_)
params = params_;
/* re-allocate buffer */
- buffer.alloc(params.width * params.height * params.get_passes_size());
+ buffer.alloc(params.width * params.get_passes_size(), params.height);
buffer.zero_to_device();
}
diff --git a/intern/cycles/render/session.cpp b/intern/cycles/render/session.cpp
index dac7fbac806..160b77d5f14 100644
--- a/intern/cycles/render/session.cpp
+++ b/intern/cycles/render/session.cpp
@@ -183,7 +183,8 @@ bool Session::draw_gpu(BufferParams &buffer_params, DeviceDrawParams &draw_param
if (gpu_draw_ready) {
/* then verify the buffers have the expected size, so we don't
* draw previous results in a resized window */
- if (!buffer_params.modified(display->params)) {
+ if (buffer_params.width == display->params.width &&
+ buffer_params.height == display->params.height) {
/* for CUDA we need to do tone-mapping still, since we can
* only access GL buffers from the main thread. */
if (gpu_need_display_buffer_update) {
@@ -211,6 +212,7 @@ void Session::run_gpu()
reset_time = time_dt();
last_update_time = time_dt();
+ last_display_time = last_update_time;
progress.set_render_start_time();
@@ -291,12 +293,21 @@ void Session::run_gpu()
* reset and draw in between */
thread_scoped_lock buffers_lock(buffers_mutex);
+ /* avoid excessive denoising in viewport after reaching a certain amount of samples */
+ bool need_denoise = tile_manager.schedule_denoising || tile_manager.state.sample < 20 ||
+ (time_dt() - last_display_time) >= params.progressive_update_timeout;
+
/* update status and timing */
update_status_time();
/* render */
render();
+ /* denoise */
+ if (need_denoise) {
+ denoise();
+ }
+
device->task_wait();
if (!device->error_message().empty())
@@ -305,7 +316,7 @@ void Session::run_gpu()
/* update status and timing */
update_status_time();
- gpu_need_display_buffer_update = true;
+ gpu_need_display_buffer_update = need_denoise || !params.run_denoising;
gpu_draw_ready = true;
progress.set_update();
@@ -359,7 +370,8 @@ bool Session::draw_cpu(BufferParams &buffer_params, DeviceDrawParams &draw_param
if (display->draw_ready()) {
/* then verify the buffers have the expected size, so we don't
* draw previous results in a resized window */
- if (!buffer_params.modified(display->params)) {
+ if (buffer_params.width == display->params.width &&
+ buffer_params.height == display->params.height) {
display->draw(device, draw_params);
if (display_outdated && (time_dt() - reset_time) > params.text_timeout)
@@ -372,7 +384,7 @@ bool Session::draw_cpu(BufferParams &buffer_params, DeviceDrawParams &draw_param
return false;
}
-bool Session::acquire_tile(Device *tile_device, RenderTile &rtile)
+bool Session::acquire_tile(Device *tile_device, RenderTile &rtile, RenderTile::Task task)
{
if (progress.get_cancel()) {
if (params.progressive_refine == false) {
@@ -387,8 +399,14 @@ bool Session::acquire_tile(Device *tile_device, RenderTile &rtile)
Tile *tile;
int device_num = device->device_number(tile_device);
- if (!tile_manager.next_tile(tile, device_num))
+ while (!tile_manager.next_tile(tile, device_num, task == RenderTile::DENOISE)) {
+ /* Wait for denoising tiles to become available */
+ if (task == RenderTile::DENOISE && !progress.get_cancel() && tile_manager.has_tiles()) {
+ denoising_cond.wait(tile_lock);
+ continue;
+ }
return false;
+ }
/* fill render tile */
rtile.x = tile_manager.state.buffer.full_x + tile->x;
@@ -399,7 +417,7 @@ bool Session::acquire_tile(Device *tile_device, RenderTile &rtile)
rtile.num_samples = tile_manager.state.num_samples;
rtile.resolution = tile_manager.state.resolution_divider;
rtile.tile_index = tile->index;
- rtile.task = (tile->state == Tile::DENOISE) ? RenderTile::DENOISE : RenderTile::PATH_TRACE;
+ rtile.task = task;
tile_lock.unlock();
@@ -413,6 +431,9 @@ bool Session::acquire_tile(Device *tile_device, RenderTile &rtile)
device->map_tile(tile_device, rtile);
+ /* Reset copy state, since buffer contents change after the tile was acquired */
+ buffers->map_neighbor_copied = false;
+
return true;
}
@@ -429,6 +450,8 @@ bool Session::acquire_tile(Device *tile_device, RenderTile &rtile)
tile->buffers->reset(buffer_params);
}
+ tile->buffers->map_neighbor_copied = false;
+
tile->buffers->params.get_offset_stride(rtile.offset, rtile.stride);
rtile.buffer = tile->buffers->buffer.device_pointer;
@@ -484,45 +507,75 @@ void Session::release_tile(RenderTile &rtile)
}
update_status_time();
+
+ /* Notify denoising thread that a tile was finished. */
+ denoising_cond.notify_all();
}
void Session::map_neighbor_tiles(RenderTile *tiles, Device *tile_device)
{
thread_scoped_lock tile_lock(tile_mutex);
- int center_idx = tiles[4].tile_index;
- assert(tile_manager.state.tiles[center_idx].state == Tile::DENOISE);
- BufferParams buffer_params = tile_manager.params;
- int4 image_region = make_int4(buffer_params.full_x,
- buffer_params.full_y,
- buffer_params.full_x + buffer_params.width,
- buffer_params.full_y + buffer_params.height);
-
- for (int dy = -1, i = 0; dy <= 1; dy++) {
- for (int dx = -1; dx <= 1; dx++, i++) {
- int px = tiles[4].x + dx * params.tile_size.x;
- int py = tiles[4].y + dy * params.tile_size.y;
- if (px >= image_region.x && py >= image_region.y && px < image_region.z &&
- py < image_region.w) {
- int tile_index = center_idx + dy * tile_manager.state.tile_stride + dx;
- Tile *tile = &tile_manager.state.tiles[tile_index];
- assert(tile->buffers);
-
- tiles[i].buffer = tile->buffers->buffer.device_pointer;
- tiles[i].x = tile_manager.state.buffer.full_x + tile->x;
- tiles[i].y = tile_manager.state.buffer.full_y + tile->y;
- tiles[i].w = tile->w;
- tiles[i].h = tile->h;
- tiles[i].buffers = tile->buffers;
-
- tile->buffers->params.get_offset_stride(tiles[i].offset, tiles[i].stride);
- }
- else {
- tiles[i].buffer = (device_ptr)NULL;
- tiles[i].buffers = NULL;
- tiles[i].x = clamp(px, image_region.x, image_region.z);
- tiles[i].y = clamp(py, image_region.y, image_region.w);
- tiles[i].w = tiles[i].h = 0;
+ const int4 image_region = make_int4(
+ tile_manager.state.buffer.full_x,
+ tile_manager.state.buffer.full_y,
+ tile_manager.state.buffer.full_x + tile_manager.state.buffer.width,
+ tile_manager.state.buffer.full_y + tile_manager.state.buffer.height);
+
+ if (!tile_manager.schedule_denoising) {
+ /* Fix up tile slices with overlap. */
+ if (tile_manager.slice_overlap != 0) {
+ int y = max(tiles[4].y - tile_manager.slice_overlap, image_region.y);
+ tiles[4].h = min(tiles[4].y + tiles[4].h + tile_manager.slice_overlap, image_region.w) - y;
+ tiles[4].y = y;
+ }
+
+ /* Tiles are not being denoised individually, which means the entire image is processed. */
+ tiles[3].x = tiles[4].x;
+ tiles[1].y = tiles[4].y;
+ tiles[5].x = tiles[4].x + tiles[4].w;
+ tiles[7].y = tiles[4].y + tiles[4].h;
+ }
+ else {
+ int center_idx = tiles[4].tile_index;
+ assert(tile_manager.state.tiles[center_idx].state == Tile::DENOISE);
+
+ for (int dy = -1, i = 0; dy <= 1; dy++) {
+ for (int dx = -1; dx <= 1; dx++, i++) {
+ int nindex = tile_manager.get_neighbor_index(center_idx, i);
+ if (nindex >= 0) {
+ Tile *tile = &tile_manager.state.tiles[nindex];
+
+ tiles[i].x = image_region.x + tile->x;
+ tiles[i].y = image_region.y + tile->y;
+ tiles[i].w = tile->w;
+ tiles[i].h = tile->h;
+
+ if (buffers) {
+ tile_manager.state.buffer.get_offset_stride(tiles[i].offset, tiles[i].stride);
+
+ tiles[i].buffer = buffers->buffer.device_pointer;
+ tiles[i].buffers = buffers;
+ }
+ else {
+ assert(tile->buffers);
+ tile->buffers->params.get_offset_stride(tiles[i].offset, tiles[i].stride);
+
+ tiles[i].buffer = tile->buffers->buffer.device_pointer;
+ tiles[i].buffers = tile->buffers;
+ }
+ }
+ else {
+ int px = tiles[4].x + dx * params.tile_size.x;
+ int py = tiles[4].y + dy * params.tile_size.y;
+
+ tiles[i].x = clamp(px, image_region.x, image_region.z);
+ tiles[i].y = clamp(py, image_region.y, image_region.w);
+ tiles[i].w = tiles[i].h = 0;
+
+ tiles[i].buffer = (device_ptr)NULL;
+ tiles[i].buffers = NULL;
+ }
}
}
}
@@ -545,6 +598,7 @@ void Session::run_cpu()
bool tiles_written = false;
last_update_time = time_dt();
+ last_display_time = last_update_time;
{
/* reset once to start */
@@ -620,11 +674,6 @@ void Session::run_cpu()
}
if (!no_tiles) {
- /* buffers mutex is locked entirely while rendering each
- * sample, and released/reacquired on each iteration to allow
- * reset and draw in between */
- thread_scoped_lock buffers_lock(buffers_mutex);
-
/* update scene */
scoped_timer update_timer;
if (update_scene()) {
@@ -638,17 +687,31 @@ void Session::run_cpu()
if (progress.get_cancel())
break;
+ /* buffers mutex is locked entirely while rendering each
+ * sample, and released/reacquired on each iteration to allow
+ * reset and draw in between */
+ thread_scoped_lock buffers_lock(buffers_mutex);
+
+ /* avoid excessive denoising in viewport after reaching a certain amount of samples */
+ bool need_denoise = tile_manager.schedule_denoising || tile_manager.state.sample < 20 ||
+ (time_dt() - last_display_time) >= params.progressive_update_timeout;
+
/* update status and timing */
update_status_time();
/* render */
render();
+ /* denoise */
+ if (need_denoise) {
+ denoise();
+ }
+
/* update status and timing */
update_status_time();
if (!params.background)
- need_copy_to_display_buffer = true;
+ need_copy_to_display_buffer = need_denoise || !params.run_denoising;
if (!device->error_message().empty())
progress.set_error(device->error_message());
@@ -869,6 +932,20 @@ void Session::set_pause(bool pause_)
pause_cond.notify_all();
}
+void Session::set_denoising(bool denoising, bool optix_denoising)
+{
+ /* Lock buffers so no denoising operation is triggered while the settings are changed here. */
+ thread_scoped_lock buffers_lock(buffers_mutex);
+
+ params.run_denoising = denoising;
+ params.full_denoising = !optix_denoising;
+ params.optix_denoising = optix_denoising;
+
+ // TODO(pmours): Query the required overlap value for denoising from the device?
+ tile_manager.slice_overlap = denoising && !params.background ? 64 : 0;
+ tile_manager.schedule_denoising = denoising && !buffers;
+}
+
void Session::wait()
{
if (session_thread) {
@@ -1016,33 +1093,74 @@ void Session::render()
/* Add path trace task. */
DeviceTask task(DeviceTask::RENDER);
- task.acquire_tile = function_bind(&Session::acquire_tile, this, _1, _2);
+ task.acquire_tile = function_bind(&Session::acquire_tile, this, _1, _2, RenderTile::PATH_TRACE);
task.release_tile = function_bind(&Session::release_tile, this, _1);
- task.map_neighbor_tiles = function_bind(&Session::map_neighbor_tiles, this, _1, _2);
- task.unmap_neighbor_tiles = function_bind(&Session::unmap_neighbor_tiles, this, _1, _2);
task.get_cancel = function_bind(&Progress::get_cancel, &this->progress);
task.update_tile_sample = function_bind(&Session::update_tile_sample, this, _1);
task.update_progress_sample = function_bind(&Progress::add_samples, &this->progress, _1, _2);
task.need_finish_queue = params.progressive_refine;
task.integrator_branched = scene->integrator->method == Integrator::BRANCHED_PATH;
- task.requested_tile_size = params.tile_size;
- task.passes_size = tile_manager.params.get_passes_size();
- if (params.run_denoising) {
- task.denoising = params.denoising;
-
- assert(!scene->film->need_update);
- task.pass_stride = scene->film->pass_stride;
- task.target_pass_stride = task.pass_stride;
- task.pass_denoising_data = scene->film->denoising_data_offset;
- task.pass_denoising_clean = scene->film->denoising_clean_offset;
-
- task.denoising_from_render = true;
- task.denoising_do_filter = params.full_denoising;
- task.denoising_use_optix = params.optix_denoising;
- task.denoising_write_passes = params.write_denoising_passes;
+ device->task_add(task);
+}
+
+void Session::denoise()
+{
+ if (!params.run_denoising) {
+ return;
+ }
+
+ /* It can happen that denoising was already enabled, but the scene still needs an update. */
+ if (scene->film->need_update || !scene->film->denoising_data_offset) {
+ return;
}
+ /* Add separate denoising task. */
+ DeviceTask task(DeviceTask::DENOISE);
+
+ if (tile_manager.schedule_denoising) {
+ /* Run denoising on each tile. */
+ task.acquire_tile = function_bind(&Session::acquire_tile, this, _1, _2, RenderTile::DENOISE);
+ task.release_tile = function_bind(&Session::release_tile, this, _1);
+ task.update_tile_sample = function_bind(&Session::update_tile_sample, this, _1);
+ task.update_progress_sample = function_bind(&Progress::add_samples, &this->progress, _1, _2);
+ }
+ else {
+ assert(buffers);
+
+ /* Wait for rendering to finish. */
+ device->task_wait();
+
+ /* Run denoising on the whole image at once. */
+ task.type = DeviceTask::DENOISE_BUFFER;
+ task.x = tile_manager.state.buffer.full_x;
+ task.y = tile_manager.state.buffer.full_y;
+ task.w = tile_manager.state.buffer.width;
+ task.h = tile_manager.state.buffer.height;
+ task.buffer = buffers->buffer.device_pointer;
+ task.sample = tile_manager.state.sample;
+ task.num_samples = tile_manager.state.num_samples;
+ tile_manager.state.buffer.get_offset_stride(task.offset, task.stride);
+ task.buffers = buffers;
+ }
+
+ task.get_cancel = function_bind(&Progress::get_cancel, &this->progress);
+ task.need_finish_queue = params.progressive_refine;
+ task.map_neighbor_tiles = function_bind(&Session::map_neighbor_tiles, this, _1, _2);
+ task.unmap_neighbor_tiles = function_bind(&Session::unmap_neighbor_tiles, this, _1, _2);
+
+ task.denoising = params.denoising;
+
+ task.pass_stride = scene->film->pass_stride;
+ task.target_pass_stride = task.pass_stride;
+ task.pass_denoising_data = scene->film->denoising_data_offset;
+ task.pass_denoising_clean = scene->film->denoising_clean_offset;
+
+ task.denoising_from_render = true;
+ task.denoising_do_filter = params.full_denoising;
+ task.denoising_use_optix = params.optix_denoising;
+ task.denoising_write_passes = params.write_denoising_passes;
+
device->task_add(task);
}
@@ -1067,6 +1185,8 @@ void Session::copy_to_display_buffer(int sample)
/* set display to new size */
display->draw_set(task.w, task.h);
+
+ last_display_time = time_dt();
}
display_outdated = false;
diff --git a/intern/cycles/render/session.h b/intern/cycles/render/session.h
index ec465601541..3ef2b70879a 100644
--- a/intern/cycles/render/session.h
+++ b/intern/cycles/render/session.h
@@ -154,6 +154,7 @@ class Session {
void reset(BufferParams &params, int samples);
void set_samples(int samples);
void set_pause(bool pause);
+ void set_denoising(bool denoising, bool optix_denoising);
bool update_scene();
bool load_kernels(bool lock_scene = true);
@@ -178,8 +179,10 @@ class Session {
void update_status_time(bool show_pause = false, bool show_done = false);
- void copy_to_display_buffer(int sample);
void render();
+ void denoise();
+ void copy_to_display_buffer(int sample);
+
void reset_(BufferParams &params, int samples);
void run_cpu();
@@ -190,7 +193,7 @@ class Session {
bool draw_gpu(BufferParams &params, DeviceDrawParams &draw_params);
void reset_gpu(BufferParams &params, int samples);
- bool acquire_tile(Device *tile_device, RenderTile &tile);
+ bool acquire_tile(Device *tile_device, RenderTile &tile, RenderTile::Task task);
void update_tile_sample(RenderTile &tile);
void release_tile(RenderTile &tile);
@@ -213,14 +216,16 @@ class Session {
thread_mutex tile_mutex;
thread_mutex buffers_mutex;
thread_mutex display_mutex;
+ thread_condition_variable denoising_cond;
bool kernels_loaded;
DeviceRequestedFeatures loaded_kernel_features;
double reset_time;
+ double last_update_time;
+ double last_display_time;
/* progressive refine */
- double last_update_time;
bool update_progressive_refine(bool cancel);
DeviceRequestedFeatures get_requested_device_features();
diff --git a/intern/cycles/render/tile.cpp b/intern/cycles/render/tile.cpp
index 9ef0c695667..4ddfd56cd01 100644
--- a/intern/cycles/render/tile.cpp
+++ b/intern/cycles/render/tile.cpp
@@ -101,6 +101,7 @@ TileManager::TileManager(bool progressive_,
tile_order = tile_order_;
start_resolution = start_resolution_;
pixel_size = pixel_size_;
+ slice_overlap = 0;
num_samples = num_samples_;
num_devices = num_devices_;
preserve_tile_device = preserve_tile_device_;
@@ -201,8 +202,7 @@ int TileManager::gen_tiles(bool sliced)
int image_h = max(1, params.height / resolution);
int2 center = make_int2(image_w / 2, image_h / 2);
- int num_logical_devices = preserve_tile_device ? num_devices : 1;
- int num = min(image_h, num_logical_devices);
+ int num = preserve_tile_device || sliced ? min(image_h, num_devices) : 1;
int slice_num = sliced ? num : 1;
int tile_w = (tile_size.x >= image_w) ? 1 : divide_up(image_w, tile_size.x);
@@ -216,7 +216,7 @@ int TileManager::gen_tiles(bool sliced)
tile_list = state.render_tiles.begin();
if (tile_order == TILE_HILBERT_SPIRAL) {
- assert(!sliced);
+ assert(!sliced && slice_overlap == 0);
int tile_h = (tile_size.y >= image_h) ? 1 : divide_up(image_h, tile_size.y);
state.tiles.resize(tile_w * tile_h);
@@ -319,6 +319,12 @@ int TileManager::gen_tiles(bool sliced)
int slice_h = (slice == slice_num - 1) ? image_h - slice * (image_h / slice_num) :
image_h / slice_num;
+ if (slice_overlap != 0) {
+ int slice_y_offset = max(slice_y - slice_overlap, 0);
+ slice_h = min(slice_y + slice_h + slice_overlap, image_h) - slice_y_offset;
+ slice_y = slice_y_offset;
+ }
+
int tile_h = (tile_size.y >= slice_h) ? 1 : divide_up(slice_h, tile_size.y);
int tiles_per_device = divide_up(tile_w * tile_h, num);
@@ -363,6 +369,7 @@ void TileManager::gen_render_tiles()
{
/* Regenerate just the render tiles for progressive render. */
foreach (Tile &tile, state.tiles) {
+ tile.state = Tile::RENDER;
state.render_tiles[tile.device].push_back(tile.index);
}
}
@@ -386,17 +393,29 @@ void TileManager::set_tiles()
int TileManager::get_neighbor_index(int index, int neighbor)
{
- static const int dx[] = {-1, 0, 1, -1, 1, -1, 0, 1, 0}, dy[] = {-1, -1, -1, 0, 0, 1, 1, 1, 0};
+ /* Neighbor indices:
+ * 0 1 2
+ * 3 4 5
+ * 6 7 8
+ */
+ static const int dx[] = {-1, 0, 1, -1, 0, 1, -1, 0, 1};
+ static const int dy[] = {-1, -1, -1, 0, 0, 0, 1, 1, 1};
int resolution = state.resolution_divider;
int image_w = max(1, params.width / resolution);
int image_h = max(1, params.height / resolution);
+
+ int num = min(image_h, num_devices);
+ int slice_num = !background ? num : 1;
+ int slice_h = image_h / slice_num;
+
int tile_w = (tile_size.x >= image_w) ? 1 : divide_up(image_w, tile_size.x);
- int tile_h = (tile_size.y >= image_h) ? 1 : divide_up(image_h, tile_size.y);
+ int tile_h = (tile_size.y >= slice_h) ? 1 : divide_up(slice_h, tile_size.y);
- int nx = state.tiles[index].x / tile_size.x + dx[neighbor],
- ny = state.tiles[index].y / tile_size.y + dy[neighbor];
- if (nx < 0 || ny < 0 || nx >= tile_w || ny >= tile_h)
+ /* Tiles in the state tile list are always indexed from left to right, top to bottom. */
+ int nx = (index % tile_w) + dx[neighbor];
+ int ny = (index / tile_w) + dy[neighbor];
+ if (nx < 0 || ny < 0 || nx >= tile_w || ny >= tile_h * slice_num)
return -1;
return ny * state.tile_stride + nx;
@@ -426,15 +445,11 @@ bool TileManager::finish_tile(int index, bool &delete_tile)
{
delete_tile = false;
- if (progressive) {
- return true;
- }
-
switch (state.tiles[index].state) {
case Tile::RENDER: {
if (!schedule_denoising) {
state.tiles[index].state = Tile::DONE;
- delete_tile = true;
+ delete_tile = !progressive;
return true;
}
state.tiles[index].state = Tile::RENDERED;
@@ -457,15 +472,18 @@ bool TileManager::finish_tile(int index, bool &delete_tile)
int nindex = get_neighbor_index(index, neighbor);
if (check_neighbor_state(nindex, Tile::DENOISED)) {
state.tiles[nindex].state = Tile::DONE;
- /* It can happen that the tile just finished denoising and already can be freed here.
- * However, in that case it still has to be written before deleting, so we can't delete
- * it yet. */
- if (neighbor == 8) {
- delete_tile = true;
- }
- else {
- delete state.tiles[nindex].buffers;
- state.tiles[nindex].buffers = NULL;
+ /* Do not delete finished tiles in progressive mode. */
+ if (!progressive) {
+ /* It can happen that the tile just finished denoising and already can be freed here.
+ * However, in that case it still has to be written before deleting, so we can't delete
+ * it yet. */
+ if (neighbor == 4) {
+ delete_tile = true;
+ }
+ else {
+ delete state.tiles[nindex].buffers;
+ state.tiles[nindex].buffers = NULL;
+ }
}
}
}
@@ -477,27 +495,56 @@ bool TileManager::finish_tile(int index, bool &delete_tile)
}
}
-bool TileManager::next_tile(Tile *&tile, int device)
+bool TileManager::next_tile(Tile *&tile, int device, bool denoising)
{
- int logical_device = preserve_tile_device ? device : 0;
+ /* Preserve device if requested, unless this is a separate denoising device that just wants to
+ * grab any available tile. */
+ const bool preserve_device = preserve_tile_device && device < num_devices;
+
+ int tile_index = -1;
+ int logical_device = preserve_device ? device : 0;
+
+ if (denoising) {
+ while (logical_device < state.denoising_tiles.size()) {
+ if (state.denoising_tiles[logical_device].empty()) {
+ if (preserve_device) {
+ return false;
+ }
+ else {
+ logical_device++;
+ continue;
+ }
+ }
- if (logical_device >= state.render_tiles.size())
- return false;
+ tile_index = state.denoising_tiles[logical_device].front();
+ state.denoising_tiles[logical_device].pop_front();
+ break;
+ }
+ }
+ else {
+ while (logical_device < state.render_tiles.size()) {
+ if (state.render_tiles[logical_device].empty()) {
+ if (preserve_device) {
+ return false;
+ }
+ else {
+ logical_device++;
+ continue;
+ }
+ }
- if (!state.denoising_tiles[logical_device].empty()) {
- int idx = state.denoising_tiles[logical_device].front();
- state.denoising_tiles[logical_device].pop_front();
- tile = &state.tiles[idx];
- return true;
+ tile_index = state.render_tiles[logical_device].front();
+ state.render_tiles[logical_device].pop_front();
+ break;
+ }
}
- if (state.render_tiles[logical_device].empty())
- return false;
+ if (tile_index >= 0) {
+ tile = &state.tiles[tile_index];
+ return true;
+ }
- int idx = state.render_tiles[logical_device].front();
- state.render_tiles[logical_device].pop_front();
- tile = &state.tiles[idx];
- return true;
+ return false;
}
bool TileManager::done()
@@ -508,6 +555,16 @@ bool TileManager::done()
(state.sample + state.num_samples >= end_sample);
}
+bool TileManager::has_tiles()
+{
+ foreach (Tile &tile, state.tiles) {
+ if (tile.state != Tile::DONE) {
+ return true;
+ }
+ }
+ return false;
+}
+
bool TileManager::next()
{
if (done())
diff --git a/intern/cycles/render/tile.h b/intern/cycles/render/tile.h
index 017c1af0ead..14c693683c4 100644
--- a/intern/cycles/render/tile.h
+++ b/intern/cycles/render/tile.h
@@ -89,6 +89,7 @@ class TileManager {
} state;
int num_samples;
+ int slice_overlap;
TileManager(bool progressive,
int num_samples,
@@ -105,15 +106,19 @@ class TileManager {
void reset(BufferParams &params, int num_samples);
void set_samples(int num_samples);
bool next();
- bool next_tile(Tile *&tile, int device = 0);
+ bool next_tile(Tile *&tile, int device, bool denoising);
bool finish_tile(int index, bool &delete_tile);
bool done();
+ bool has_tiles();
void set_tile_order(TileOrder tile_order_)
{
tile_order = tile_order_;
}
+ int get_neighbor_index(int index, int neighbor);
+ bool check_neighbor_state(int index, Tile::State state);
+
/* ** Sample range rendering. ** */
/* Start sample in the range. */
@@ -160,9 +165,6 @@ class TileManager {
/* Generate tile list, return number of tiles. */
int gen_tiles(bool sliced);
void gen_render_tiles();
-
- int get_neighbor_index(int index, int neighbor);
- bool check_neighbor_state(int index, Tile::State state);
};
CCL_NAMESPACE_END